Initial commit
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
# Sets GTest specific flags
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS GTEST_HAS_EXCEPTIONS=0)
|
||||
|
||||
# Adds GTest library
|
||||
add_subdirectory(../extern/gtest gtest)
|
||||
|
||||
# Adds test file directories
|
||||
add_subdirectory(base)
|
||||
add_subdirectory(animation)
|
||||
add_subdirectory(geometry)
|
||||
add_subdirectory(options)
|
||||
@@ -0,0 +1,2 @@
|
||||
add_subdirectory(offline)
|
||||
add_subdirectory(runtime)
|
||||
@@ -0,0 +1,127 @@
|
||||
add_executable(test_animation_builder
|
||||
animation_builder_tests.cc)
|
||||
target_link_libraries(test_animation_builder
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_animation_builder PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_animation_builder COMMAND test_animation_builder)
|
||||
|
||||
add_executable(test_animation_optimizer
|
||||
animation_optimizer_tests.cc)
|
||||
target_link_libraries(test_animation_optimizer
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_animation_optimizer PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_animation_optimizer COMMAND test_animation_optimizer)
|
||||
|
||||
add_executable(test_raw_animation_utils
|
||||
raw_animation_utils_tests.cc)
|
||||
target_link_libraries(test_raw_animation_utils
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_raw_animation_utils PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_raw_animation_utils COMMAND test_raw_animation_utils)
|
||||
|
||||
add_executable(test_additive_animation_builder
|
||||
additive_animation_builder_tests.cc)
|
||||
target_link_libraries(test_additive_animation_builder
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_additive_animation_builder PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_additive_animation_builder COMMAND test_additive_animation_builder)
|
||||
|
||||
add_executable(test_skeleton_builder
|
||||
skeleton_builder_tests.cc)
|
||||
target_link_libraries(test_skeleton_builder
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_skeleton_builder PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_skeleton_builder COMMAND test_skeleton_builder)
|
||||
|
||||
add_executable(test_raw_skeleton_archive
|
||||
raw_skeleton_archive_tests.cc)
|
||||
target_link_libraries(test_raw_skeleton_archive
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_raw_skeleton_archive PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_raw_skeleton_archive COMMAND test_raw_skeleton_archive)
|
||||
|
||||
add_executable(test_track_builder
|
||||
track_builder_tests.cc)
|
||||
target_link_libraries(test_track_builder
|
||||
ozz_animation_offline
|
||||
ozz_animation
|
||||
ozz_base
|
||||
gtest)
|
||||
set_target_properties(test_track_builder PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_track_builder COMMAND test_track_builder)
|
||||
|
||||
add_executable(test_track_optimizer
|
||||
track_optimizer_tests.cc)
|
||||
target_link_libraries(test_track_optimizer
|
||||
ozz_animation_offline
|
||||
ozz_animation
|
||||
ozz_base
|
||||
gtest)
|
||||
set_target_properties(test_track_optimizer PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_track_optimizer COMMAND test_track_optimizer)
|
||||
|
||||
add_executable(test_raw_skeleton_archive_versioning
|
||||
raw_skeleton_archive_versioning_tests.cc)
|
||||
|
||||
target_link_libraries(test_raw_skeleton_archive_versioning
|
||||
ozz_animation_offline
|
||||
ozz_options
|
||||
gtest)
|
||||
set_target_properties(test_raw_skeleton_archive_versioning PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
|
||||
add_test(NAME test_raw_skeleton_archive_versioning_le COMMAND test_raw_skeleton_archive_versioning "--file=${ozz_media_directory}/bin/versioning/raw_skeleton_v1_le.ozz" "--joints=67" "--root_name=Hips")
|
||||
add_test(NAME test_raw_skeleton_archive_versioning_be COMMAND test_raw_skeleton_archive_versioning "--file=${ozz_media_directory}/bin/versioning/raw_skeleton_v1_be.ozz" "--joints=67" "--root_name=Hips")
|
||||
|
||||
add_executable(test_raw_animation_archive
|
||||
raw_animation_archive_tests.cc)
|
||||
target_link_libraries(test_raw_animation_archive
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_raw_animation_archive PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_raw_animation_archive COMMAND test_raw_animation_archive)
|
||||
|
||||
add_executable(test_raw_animation_archive_versioning
|
||||
raw_animation_archive_versioning_tests.cc)
|
||||
target_link_libraries(test_raw_animation_archive_versioning
|
||||
ozz_animation_offline
|
||||
ozz_options
|
||||
gtest)
|
||||
set_target_properties(test_raw_animation_archive_versioning PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
|
||||
add_test(NAME test_raw_animation_archive_versioning_le COMMAND test_raw_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/raw_animation_v3_le.ozz" "--tracks=67" "--duration=.66666667" "--name=run")
|
||||
add_test(NAME test_raw_animation_archive_versioning_be COMMAND test_raw_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/raw_animation_v3_be.ozz" "--tracks=67" "--duration=.66666667" "--name=run")
|
||||
|
||||
# Previous incompatbile versions.
|
||||
add_test(NAME test_raw_animation_archive_versioning_le_older2 COMMAND test_raw_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/raw_animation_v2_le.ozz" "--tracks=0" "--duration=1" "--name=")
|
||||
add_test(NAME test_raw_animation_archive_versioning_le_older1 COMMAND test_raw_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/raw_animation_v1_le.ozz" "--tracks=0" "--duration=1" "--name=")
|
||||
|
||||
# RawTrack
|
||||
add_executable(test_raw_track_archive
|
||||
raw_track_archive_tests.cc)
|
||||
target_link_libraries(test_raw_track_archive
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_raw_track_archive PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
add_test(NAME test_raw_track_archive COMMAND test_raw_track_archive)
|
||||
|
||||
# ozz_animation_offline fuse tests
|
||||
set_source_files_properties(${PROJECT_BINARY_DIR}/src_fused/ozz_animation_offline.cc PROPERTIES GENERATED 1)
|
||||
add_executable(test_fuse_animation_offline
|
||||
animation_builder_tests.cc
|
||||
${PROJECT_BINARY_DIR}/src_fused/ozz_animation_offline.cc)
|
||||
add_dependencies(test_fuse_animation_offline BUILD_FUSE_ozz_animation_offline)
|
||||
target_link_libraries(test_fuse_animation_offline
|
||||
ozz_animation
|
||||
gtest)
|
||||
add_test(NAME test_fuse_animation_offline COMMAND test_fuse_animation_offline)
|
||||
set_target_properties(test_fuse_animation_offline PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
|
||||
add_subdirectory(fbx)
|
||||
add_subdirectory(gltf)
|
||||
add_subdirectory(tools)
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/additive_animation_builder.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
#include "ozz/base/maths/transform.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
|
||||
using ozz::animation::offline::AdditiveAnimationBuilder;
|
||||
using ozz::animation::offline::RawAnimation;
|
||||
|
||||
TEST(Error, AdditiveAnimationBuilder) {
|
||||
AdditiveAnimationBuilder builder;
|
||||
|
||||
{ // nullptr output.
|
||||
RawAnimation input;
|
||||
EXPECT_TRUE(input.Validate());
|
||||
|
||||
// Builds animation
|
||||
EXPECT_FALSE(builder(input, nullptr));
|
||||
}
|
||||
|
||||
{ // Invalid input animation.
|
||||
RawAnimation input;
|
||||
input.duration = -1.f;
|
||||
EXPECT_FALSE(input.Validate());
|
||||
|
||||
// Builds animation
|
||||
RawAnimation output;
|
||||
output.duration = -1.f;
|
||||
output.tracks.resize(1);
|
||||
EXPECT_FALSE(builder(input, &output));
|
||||
EXPECT_FLOAT_EQ(output.duration, RawAnimation().duration);
|
||||
EXPECT_EQ(output.num_tracks(), 0);
|
||||
}
|
||||
|
||||
{ // Invalid input animation with custom refpose
|
||||
RawAnimation input;
|
||||
input.duration = 1.f;
|
||||
input.tracks.resize(1);
|
||||
|
||||
// Builds animation
|
||||
RawAnimation output;
|
||||
output.duration = -1.f;
|
||||
output.tracks.resize(1);
|
||||
|
||||
ozz::span<ozz::math::Transform> empty_ref_pose_range;
|
||||
|
||||
EXPECT_FALSE(builder(input, empty_ref_pose_range, &output));
|
||||
EXPECT_FLOAT_EQ(output.duration, RawAnimation().duration);
|
||||
EXPECT_EQ(output.num_tracks(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Build, AdditiveAnimationBuilder) {
|
||||
AdditiveAnimationBuilder builder;
|
||||
|
||||
RawAnimation input;
|
||||
input.duration = 1.f;
|
||||
input.tracks.resize(3);
|
||||
|
||||
// First track is empty
|
||||
{
|
||||
// input.tracks[0]
|
||||
}
|
||||
|
||||
// 2nd track
|
||||
// 1 key at the beginning
|
||||
{
|
||||
const RawAnimation::TranslationKey key = {0.f,
|
||||
ozz::math::Float3(2.f, 3.f, 4.f)};
|
||||
input.tracks[1].translations.push_back(key);
|
||||
}
|
||||
{
|
||||
const RawAnimation::RotationKey key = {
|
||||
0.f, ozz::math::Quaternion(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
input.tracks[1].rotations.push_back(key);
|
||||
}
|
||||
{
|
||||
const RawAnimation::ScaleKey key = {0.f, ozz::math::Float3(5.f, 6.f, 7.f)};
|
||||
input.tracks[1].scales.push_back(key);
|
||||
}
|
||||
|
||||
// 3rd track
|
||||
// 2 keys after the beginning
|
||||
{
|
||||
const RawAnimation::TranslationKey key0 = {
|
||||
.5f, ozz::math::Float3(2.f, 3.f, 4.f)};
|
||||
input.tracks[2].translations.push_back(key0);
|
||||
const RawAnimation::TranslationKey key1 = {
|
||||
.7f, ozz::math::Float3(20.f, 30.f, 40.f)};
|
||||
input.tracks[2].translations.push_back(key1);
|
||||
}
|
||||
{
|
||||
const RawAnimation::RotationKey key0 = {
|
||||
.5f, ozz::math::Quaternion(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
input.tracks[2].rotations.push_back(key0);
|
||||
const RawAnimation::RotationKey key1 = {
|
||||
.7f, ozz::math::Quaternion(-.70710677f, 0.f, 0.f, .70710677f)};
|
||||
input.tracks[2].rotations.push_back(key1);
|
||||
}
|
||||
{
|
||||
const RawAnimation::ScaleKey key0 = {.5f, ozz::math::Float3(5.f, 6.f, 7.f)};
|
||||
input.tracks[2].scales.push_back(key0);
|
||||
const RawAnimation::ScaleKey key1 = {.7f,
|
||||
ozz::math::Float3(50.f, 60.f, 70.f)};
|
||||
input.tracks[2].scales.push_back(key1);
|
||||
}
|
||||
|
||||
// Builds animation with very little tolerance.
|
||||
{
|
||||
RawAnimation output;
|
||||
ASSERT_TRUE(builder(input, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 3);
|
||||
|
||||
// 1st track.
|
||||
{
|
||||
EXPECT_EQ(output.tracks[0].translations.size(), 0u);
|
||||
EXPECT_EQ(output.tracks[0].rotations.size(), 0u);
|
||||
EXPECT_EQ(output.tracks[0].scales.size(), 0u);
|
||||
}
|
||||
|
||||
// 2nd track.
|
||||
{
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[1].translations;
|
||||
EXPECT_EQ(translations.size(), 1u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT3_EQ(translations[0].value, 0.f, 0.f, 0.f);
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[1].rotations;
|
||||
EXPECT_EQ(rotations.size(), 1u);
|
||||
EXPECT_FLOAT_EQ(rotations[0].time, 0.f);
|
||||
EXPECT_QUATERNION_EQ(rotations[0].value, 0.f, 0.f, 0.f, 1.f);
|
||||
const RawAnimation::JointTrack::Scales& scales = output.tracks[1].scales;
|
||||
EXPECT_EQ(scales.size(), 1u);
|
||||
EXPECT_FLOAT_EQ(scales[0].time, 0.f);
|
||||
EXPECT_FLOAT3_EQ(scales[0].value, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
// 3rd track.
|
||||
{
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
EXPECT_EQ(translations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, .5f);
|
||||
EXPECT_FLOAT3_EQ(translations[0].value, 0.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .7f);
|
||||
EXPECT_FLOAT3_EQ(translations[1].value, 18.f, 27.f, 36.f);
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[2].rotations;
|
||||
EXPECT_EQ(rotations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(rotations[0].time, .5f);
|
||||
EXPECT_QUATERNION_EQ(rotations[0].value, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT_EQ(rotations[1].time, .7f);
|
||||
EXPECT_QUATERNION_EQ(rotations[1].value, -1.f, 0.f, 0.f, 0.f);
|
||||
const RawAnimation::JointTrack::Scales& scales = output.tracks[2].scales;
|
||||
EXPECT_EQ(scales.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(scales[0].time, .5f);
|
||||
EXPECT_FLOAT3_EQ(scales[0].value, 1.f, 1.f, 1.f);
|
||||
EXPECT_FLOAT_EQ(scales[1].time, .7f);
|
||||
EXPECT_FLOAT3_EQ(scales[1].value, 10.f, 10.f, 10.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BuildRefPose, AdditiveAnimationBuilder) {
|
||||
AdditiveAnimationBuilder builder;
|
||||
|
||||
RawAnimation input;
|
||||
input.duration = 1.f;
|
||||
input.tracks.resize(3);
|
||||
|
||||
// First track is empty
|
||||
{
|
||||
// input.tracks[0]
|
||||
}
|
||||
|
||||
// 2nd track
|
||||
// 1 key at the beginning
|
||||
{
|
||||
const RawAnimation::TranslationKey key = {0.f,
|
||||
ozz::math::Float3(2.f, 3.f, 4.f)};
|
||||
input.tracks[1].translations.push_back(key);
|
||||
}
|
||||
{
|
||||
const RawAnimation::RotationKey key = {
|
||||
0.f, ozz::math::Quaternion(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
input.tracks[1].rotations.push_back(key);
|
||||
}
|
||||
{
|
||||
const RawAnimation::ScaleKey key = {0.f, ozz::math::Float3(5.f, 6.f, 7.f)};
|
||||
input.tracks[1].scales.push_back(key);
|
||||
}
|
||||
|
||||
// 3rd track
|
||||
// 2 keys after the beginning
|
||||
{
|
||||
const RawAnimation::TranslationKey key0 = {
|
||||
.5f, ozz::math::Float3(2.f, 3.f, 4.f)};
|
||||
input.tracks[2].translations.push_back(key0);
|
||||
const RawAnimation::TranslationKey key1 = {
|
||||
.7f, ozz::math::Float3(20.f, 30.f, 40.f)};
|
||||
input.tracks[2].translations.push_back(key1);
|
||||
}
|
||||
{
|
||||
const RawAnimation::RotationKey key0 = {
|
||||
.5f, ozz::math::Quaternion(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
input.tracks[2].rotations.push_back(key0);
|
||||
const RawAnimation::RotationKey key1 = {
|
||||
.7f, ozz::math::Quaternion(-.70710677f, 0.f, 0.f, .70710677f)};
|
||||
input.tracks[2].rotations.push_back(key1);
|
||||
}
|
||||
{
|
||||
const RawAnimation::ScaleKey key0 = {.5f, ozz::math::Float3(5.f, 6.f, 7.f)};
|
||||
input.tracks[2].scales.push_back(key0);
|
||||
const RawAnimation::ScaleKey key1 = {.7f,
|
||||
ozz::math::Float3(50.f, 60.f, 70.f)};
|
||||
input.tracks[2].scales.push_back(key1);
|
||||
}
|
||||
|
||||
// Builds animation with a custom refpose & very little tolerance
|
||||
{
|
||||
ozz::math::Transform ref_pose[3];
|
||||
ref_pose[0] = ozz::math::Transform::identity();
|
||||
ref_pose[1].translation = ozz::math::Float3(1.f, 1.f, 1.f);
|
||||
ref_pose[1].rotation =
|
||||
ozz::math::Quaternion(0.f, 0.f, .70710677f, .70710677f);
|
||||
ref_pose[1].scale = ozz::math::Float3(1.f, -1.f, 2.f);
|
||||
ref_pose[2].translation = input.tracks[2].translations[0].value;
|
||||
ref_pose[2].rotation = input.tracks[2].rotations[0].value;
|
||||
ref_pose[2].scale = input.tracks[2].scales[0].value;
|
||||
|
||||
RawAnimation output;
|
||||
ASSERT_TRUE(
|
||||
builder(input, ozz::span<ozz::math::Transform>(ref_pose), &output));
|
||||
EXPECT_EQ(output.num_tracks(), 3);
|
||||
|
||||
// 1st track.
|
||||
{
|
||||
EXPECT_EQ(output.tracks[0].translations.size(), 0u);
|
||||
EXPECT_EQ(output.tracks[0].rotations.size(), 0u);
|
||||
EXPECT_EQ(output.tracks[0].scales.size(), 0u);
|
||||
}
|
||||
|
||||
// 2nd track.
|
||||
{
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[1].translations;
|
||||
EXPECT_EQ(translations.size(), 1u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT3_EQ(translations[0].value, 1.f, 2.f, 3.f);
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[1].rotations;
|
||||
EXPECT_EQ(rotations.size(), 1u);
|
||||
EXPECT_FLOAT_EQ(rotations[0].time, 0.f);
|
||||
EXPECT_QUATERNION_EQ(rotations[0].value, .5f, .5f, -.5f, .5f);
|
||||
const RawAnimation::JointTrack::Scales& scales = output.tracks[1].scales;
|
||||
EXPECT_EQ(scales.size(), 1u);
|
||||
EXPECT_FLOAT_EQ(scales[0].time, 0.f);
|
||||
EXPECT_FLOAT3_EQ(scales[0].value, 5.f, -6.f, 3.5f);
|
||||
}
|
||||
|
||||
// 3rd track.
|
||||
{
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
EXPECT_EQ(translations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, .5f);
|
||||
EXPECT_FLOAT3_EQ(translations[0].value, 0.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .7f);
|
||||
EXPECT_FLOAT3_EQ(translations[1].value, 18.f, 27.f, 36.f);
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[2].rotations;
|
||||
EXPECT_EQ(rotations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(rotations[0].time, .5f);
|
||||
EXPECT_QUATERNION_EQ(rotations[0].value, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT_EQ(rotations[1].time, .7f);
|
||||
EXPECT_QUATERNION_EQ(rotations[1].value, -1.f, 0.f, 0.f, 0.f);
|
||||
const RawAnimation::JointTrack::Scales& scales = output.tracks[2].scales;
|
||||
EXPECT_EQ(scales.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(scales[0].time, .5f);
|
||||
EXPECT_FLOAT3_EQ(scales[0].value, 1.f, 1.f, 1.f);
|
||||
EXPECT_FLOAT_EQ(scales[1].time, .7f);
|
||||
EXPECT_FLOAT3_EQ(scales[1].value, 10.f, 10.f, 10.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/animation_builder.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
|
||||
#include "ozz/animation/runtime/animation.h"
|
||||
#include "ozz/animation/runtime/sampling_job.h"
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
|
||||
using ozz::animation::Animation;
|
||||
using ozz::animation::offline::AnimationBuilder;
|
||||
using ozz::animation::offline::RawAnimation;
|
||||
|
||||
TEST(Error, AnimationBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
AnimationBuilder builder;
|
||||
|
||||
{ // Building an empty Animation fails because animation duration
|
||||
// must be >= 0.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = -1.f; // Negative duration.
|
||||
EXPECT_FALSE(raw_animation.Validate());
|
||||
|
||||
// Builds animation
|
||||
EXPECT_TRUE(!builder(raw_animation));
|
||||
}
|
||||
|
||||
{ // Building an empty Animation fails because animation duration
|
||||
// must be >= 0.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 0.f; // Invalid duration.
|
||||
EXPECT_FALSE(raw_animation.Validate());
|
||||
|
||||
// Builds animation
|
||||
EXPECT_TRUE(!builder(raw_animation));
|
||||
}
|
||||
|
||||
{ // Building an animation with too much tracks fails.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(ozz::animation::Skeleton::kMaxJoints + 1);
|
||||
EXPECT_FALSE(raw_animation.Validate());
|
||||
|
||||
// Builds animation
|
||||
EXPECT_TRUE(!builder(raw_animation));
|
||||
}
|
||||
|
||||
{ // Building default animation succeeds.
|
||||
RawAnimation raw_animation;
|
||||
EXPECT_EQ(raw_animation.duration, 1.f);
|
||||
EXPECT_TRUE(raw_animation.Validate());
|
||||
|
||||
// Builds animation
|
||||
ozz::unique_ptr<Animation> anim(builder(raw_animation));
|
||||
EXPECT_TRUE(anim);
|
||||
}
|
||||
|
||||
{ // Building an animation with max joints succeeds.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.tracks.resize(ozz::animation::Skeleton::kMaxJoints);
|
||||
EXPECT_EQ(raw_animation.num_tracks(), ozz::animation::Skeleton::kMaxJoints);
|
||||
EXPECT_TRUE(raw_animation.Validate());
|
||||
|
||||
// Builds animation
|
||||
ozz::unique_ptr<Animation> anim(builder(raw_animation));
|
||||
EXPECT_TRUE(anim);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Build, AnimationBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
AnimationBuilder builder;
|
||||
|
||||
{ // Building an Animation with unsorted keys fails.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(1);
|
||||
|
||||
// Adds 2 unordered keys
|
||||
RawAnimation::TranslationKey first_key = {.8f, ozz::math::Float3::zero()};
|
||||
raw_animation.tracks[0].translations.push_back(first_key);
|
||||
RawAnimation::TranslationKey second_key = {.2f, ozz::math::Float3::zero()};
|
||||
raw_animation.tracks[0].translations.push_back(second_key);
|
||||
|
||||
// Builds animation
|
||||
EXPECT_FALSE(builder(raw_animation));
|
||||
}
|
||||
|
||||
{ // Building an Animation with invalid key frame's time fails.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(1);
|
||||
|
||||
// Adds a key with a time greater than animation duration.
|
||||
RawAnimation::TranslationKey first_key = {2.f, ozz::math::Float3::zero()};
|
||||
raw_animation.tracks[0].translations.push_back(first_key);
|
||||
|
||||
// Builds animation
|
||||
EXPECT_FALSE(builder(raw_animation));
|
||||
}
|
||||
|
||||
{ // Building an Animation with unsorted key frame's time fails.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(2);
|
||||
|
||||
// Adds 2 unsorted keys.
|
||||
RawAnimation::TranslationKey first_key = {0.7f, ozz::math::Float3::zero()};
|
||||
raw_animation.tracks[0].translations.push_back(first_key);
|
||||
RawAnimation::TranslationKey second_key = {0.1f, ozz::math::Float3::zero()};
|
||||
raw_animation.tracks[0].translations.push_back(second_key);
|
||||
|
||||
// Builds animation
|
||||
EXPECT_FALSE(builder(raw_animation));
|
||||
}
|
||||
|
||||
{ // Building an Animation with equal key frame's time fails.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(2);
|
||||
|
||||
// Adds 2 unsorted keys.
|
||||
RawAnimation::TranslationKey key = {0.7f, ozz::math::Float3::zero()};
|
||||
raw_animation.tracks[0].translations.push_back(key);
|
||||
raw_animation.tracks[0].translations.push_back(key);
|
||||
|
||||
// Builds animation
|
||||
EXPECT_FALSE(builder(raw_animation));
|
||||
}
|
||||
|
||||
{ // Building a valid Animation with empty tracks succeeds.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 46.f;
|
||||
raw_animation.tracks.resize(46);
|
||||
|
||||
// Builds animation
|
||||
ozz::unique_ptr<Animation> anim(builder(raw_animation));
|
||||
EXPECT_TRUE(anim);
|
||||
EXPECT_EQ(anim->duration(), 46.f);
|
||||
EXPECT_EQ(anim->num_tracks(), 46);
|
||||
}
|
||||
|
||||
{ // Building a valid Animation with 1 track succeeds.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 46.f;
|
||||
raw_animation.tracks.resize(1);
|
||||
|
||||
RawAnimation::TranslationKey first_key = {0.7f, ozz::math::Float3::zero()};
|
||||
raw_animation.tracks[0].translations.push_back(first_key);
|
||||
|
||||
// Builds animation
|
||||
ozz::unique_ptr<Animation> anim(builder(raw_animation));
|
||||
EXPECT_TRUE(anim);
|
||||
EXPECT_EQ(anim->duration(), 46.f);
|
||||
EXPECT_EQ(anim->num_tracks(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Name, AnimationBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
AnimationBuilder builder;
|
||||
|
||||
{ // Building an unnamed animation.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(46);
|
||||
|
||||
// Builds animation
|
||||
ozz::unique_ptr<Animation> anim(builder(raw_animation));
|
||||
EXPECT_TRUE(anim);
|
||||
|
||||
// Should
|
||||
EXPECT_STREQ(anim->name(), "");
|
||||
}
|
||||
|
||||
{ // Building an unnamed animation.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(46);
|
||||
raw_animation.name = "46";
|
||||
|
||||
// Builds animation
|
||||
ozz::unique_ptr<Animation> anim(builder(raw_animation));
|
||||
EXPECT_TRUE(anim);
|
||||
|
||||
// Should
|
||||
EXPECT_STREQ(anim->name(), "46");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Sort, AnimationBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
AnimationBuilder builder;
|
||||
|
||||
{
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(4);
|
||||
|
||||
// Raw animation inputs.
|
||||
// 0 1
|
||||
// --------------------
|
||||
// 0 - A B |
|
||||
// 1 - C D E |
|
||||
// 2 - F G H I J
|
||||
// 3 - K L M N |
|
||||
|
||||
// Final animation.
|
||||
// 0 1
|
||||
// --------------------
|
||||
// 0 - 0 4 11
|
||||
// 1 - 1 5 8 12
|
||||
// 2 - 2 6 9 14 16
|
||||
// 3 - 3 7 10 13 15
|
||||
|
||||
RawAnimation::TranslationKey a = {0.f * raw_animation.duration,
|
||||
ozz::math::Float3(1.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[0].translations.push_back(a);
|
||||
RawAnimation::TranslationKey b = {.4f * raw_animation.duration,
|
||||
ozz::math::Float3(3.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[0].translations.push_back(b);
|
||||
|
||||
RawAnimation::TranslationKey c = {0.f * raw_animation.duration,
|
||||
ozz::math::Float3(2.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[1].translations.push_back(c);
|
||||
RawAnimation::TranslationKey d = {0.2f * raw_animation.duration,
|
||||
ozz::math::Float3(6.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[1].translations.push_back(d);
|
||||
RawAnimation::TranslationKey e = {0.4f * raw_animation.duration,
|
||||
ozz::math::Float3(8.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[1].translations.push_back(e);
|
||||
|
||||
RawAnimation::TranslationKey f = {0.f * raw_animation.duration,
|
||||
ozz::math::Float3(12.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(f);
|
||||
RawAnimation::TranslationKey g = {.2f * raw_animation.duration,
|
||||
ozz::math::Float3(11.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(g);
|
||||
RawAnimation::TranslationKey h = {.6f * raw_animation.duration,
|
||||
ozz::math::Float3(9.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(h);
|
||||
RawAnimation::TranslationKey i = {.8f * raw_animation.duration,
|
||||
ozz::math::Float3(7.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(i);
|
||||
RawAnimation::TranslationKey j = {1.f * raw_animation.duration,
|
||||
ozz::math::Float3(5.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(j);
|
||||
|
||||
RawAnimation::TranslationKey k = {0.f * raw_animation.duration,
|
||||
ozz::math::Float3(1.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[3].translations.push_back(k);
|
||||
RawAnimation::TranslationKey l = {.2f * raw_animation.duration,
|
||||
ozz::math::Float3(2.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[3].translations.push_back(l);
|
||||
RawAnimation::TranslationKey m = {.4f * raw_animation.duration,
|
||||
ozz::math::Float3(3.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[3].translations.push_back(m);
|
||||
RawAnimation::TranslationKey n = {.6f * raw_animation.duration,
|
||||
ozz::math::Float3(4.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[3].translations.push_back(n);
|
||||
|
||||
// Builds animation
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
// Duration must be maintained.
|
||||
EXPECT_EQ(animation->duration(), raw_animation.duration);
|
||||
|
||||
// Needs to sample to test the animation.
|
||||
ozz::animation::SamplingJob job;
|
||||
ozz::animation::SamplingCache cache(1);
|
||||
ozz::math::SoaTransform output[1];
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
|
||||
// Samples and compares the two animations
|
||||
{ // Samples at t = 0
|
||||
job.ratio = 0.f;
|
||||
job.Run();
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 2.f, 12.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
{ // Samples at t = .2
|
||||
job.ratio = .2f;
|
||||
job.Run();
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 2.f, 6.f, 11.f, 2.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
{ // Samples at t = .4
|
||||
job.ratio = .4f;
|
||||
job.Run();
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 3.f, 8.f, 10.f, 3.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
{ // Samples at t = .6
|
||||
job.ratio = .6f;
|
||||
job.Run();
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 3.f, 8.f, 9.f, 4.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
{ // Samples at t = .8
|
||||
job.ratio = .8f;
|
||||
job.Run();
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 3.f, 8.f, 7.f, 4.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
{ // Samples at t = 1
|
||||
job.ratio = 1.f;
|
||||
job.Run();
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 3.f, 8.f, 5.f, 4.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,672 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/animation_optimizer.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/animation/offline/animation_builder.h"
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_skeleton.h"
|
||||
#include "ozz/animation/offline/skeleton_builder.h"
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
|
||||
using ozz::animation::Skeleton;
|
||||
using ozz::animation::offline::AnimationOptimizer;
|
||||
using ozz::animation::offline::RawAnimation;
|
||||
using ozz::animation::offline::RawSkeleton;
|
||||
using ozz::animation::offline::SkeletonBuilder;
|
||||
|
||||
TEST(Error, AnimationOptimizer) {
|
||||
AnimationOptimizer optimizer;
|
||||
|
||||
{ // nullptr output.
|
||||
RawAnimation input;
|
||||
Skeleton skeleton;
|
||||
EXPECT_TRUE(input.Validate());
|
||||
|
||||
// Builds animation
|
||||
EXPECT_FALSE(optimizer(input, skeleton, nullptr));
|
||||
}
|
||||
|
||||
{ // Invalid input animation.
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
SkeletonBuilder skeleton_builder;
|
||||
ozz::unique_ptr<Skeleton> skeleton(skeleton_builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
|
||||
RawAnimation input;
|
||||
input.duration = -1.f;
|
||||
EXPECT_FALSE(input.Validate());
|
||||
|
||||
// Builds animation
|
||||
RawAnimation output;
|
||||
output.duration = -1.f;
|
||||
output.tracks.resize(1);
|
||||
EXPECT_FALSE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_FLOAT_EQ(output.duration, RawAnimation().duration);
|
||||
EXPECT_EQ(output.num_tracks(), 0);
|
||||
}
|
||||
|
||||
{ // Invalid skeleton.
|
||||
Skeleton skeleton;
|
||||
|
||||
RawAnimation input;
|
||||
input.tracks.resize(1);
|
||||
EXPECT_TRUE(input.Validate());
|
||||
|
||||
// Builds animation
|
||||
RawAnimation output;
|
||||
EXPECT_FALSE(optimizer(input, skeleton, &output));
|
||||
EXPECT_FLOAT_EQ(output.duration, RawAnimation().duration);
|
||||
EXPECT_EQ(output.num_tracks(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Name, AnimationOptimizer) {
|
||||
// Prepares a skeleton.
|
||||
RawSkeleton raw_skeleton;
|
||||
SkeletonBuilder skeleton_builder;
|
||||
ozz::unique_ptr<Skeleton> skeleton(skeleton_builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
|
||||
AnimationOptimizer optimizer;
|
||||
|
||||
RawAnimation input;
|
||||
input.name = "Test_Animation";
|
||||
input.duration = 1.f;
|
||||
|
||||
ASSERT_TRUE(input.Validate());
|
||||
|
||||
RawAnimation output;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 0);
|
||||
EXPECT_STRCASEEQ(output.name.c_str(), "Test_Animation");
|
||||
}
|
||||
|
||||
TEST(Optimize, AnimationOptimizer) {
|
||||
// Prepares a skeleton.
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
raw_skeleton.roots[0].children.resize(1);
|
||||
raw_skeleton.roots[0].children[0].children.resize(1);
|
||||
raw_skeleton.roots[0].children[0].children[0].children.resize(2);
|
||||
SkeletonBuilder skeleton_builder;
|
||||
ozz::unique_ptr<Skeleton> skeleton(skeleton_builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
|
||||
// Disable non hierarchical optimizations
|
||||
AnimationOptimizer optimizer;
|
||||
|
||||
// Disables vertex distance.
|
||||
optimizer.setting.distance = 0.f;
|
||||
|
||||
RawAnimation input;
|
||||
input.duration = 1.f;
|
||||
input.tracks.resize(5);
|
||||
|
||||
// Translations on track 0.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(4.f, 0.f, 0.f)};
|
||||
input.tracks[0].translations.push_back(key);
|
||||
}
|
||||
|
||||
// Translations on track 1.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(0.f, 0.f, 0.f)};
|
||||
input.tracks[1].translations.push_back(key);
|
||||
}
|
||||
|
||||
// Translations on track 2.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(5.f, 0.f, 0.f)};
|
||||
input.tracks[2].translations.push_back(key);
|
||||
}
|
||||
{
|
||||
RawAnimation::TranslationKey key = {.1f, ozz::math::Float3(6.f, 0.f, 0.f)};
|
||||
input.tracks[2].translations.push_back(key);
|
||||
}
|
||||
{ // Creates an variation.
|
||||
RawAnimation::TranslationKey key = {.2f, ozz::math::Float3(7.1f, 0.f, 0.f)};
|
||||
input.tracks[2].translations.push_back(key);
|
||||
}
|
||||
{
|
||||
RawAnimation::TranslationKey key = {.3f, ozz::math::Float3(8.f, 0.f, 0.f)};
|
||||
input.tracks[2].translations.push_back(key);
|
||||
}
|
||||
|
||||
// Translations on track 3.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(16.f, 0.f, 0.f)};
|
||||
input.tracks[3].translations.push_back(key);
|
||||
}
|
||||
// Translations on track 4.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(32.f, 0.f, 0.f)};
|
||||
input.tracks[4].translations.push_back(key);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(input.Validate());
|
||||
|
||||
// Small translation tolerance -> all key maintained
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .01f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 4u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .1f);
|
||||
EXPECT_FLOAT_EQ(translations[2].time, .2f);
|
||||
EXPECT_FLOAT_EQ(translations[3].time, .3f);
|
||||
}
|
||||
|
||||
// High translation tolerance -> all key interpolated
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .1f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .3f);
|
||||
}
|
||||
|
||||
// Introduces a 10x scaling upstream that amplifies error
|
||||
// Scaling on track 0
|
||||
{
|
||||
RawAnimation::ScaleKey key = {0.f, ozz::math::Float3(10.f, 0.f, 0.f)};
|
||||
input.tracks[0].scales.push_back(key);
|
||||
}
|
||||
|
||||
// High translation tolerance -> keys aren't interpolated because of scale
|
||||
// effect.
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .1f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 4u);
|
||||
}
|
||||
|
||||
// Very high tolerance
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = 1.f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
}
|
||||
|
||||
// Introduces a -10x scaling upstream that amplifies error
|
||||
// Scaling on track 0
|
||||
{ input.tracks[0].scales[0].value = ozz::math::Float3(0.f, -10.f, 0.f); }
|
||||
|
||||
// High translation tolerance -> keys aren't interpolated because of scale
|
||||
// effect.
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .1f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 4u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .1f);
|
||||
EXPECT_FLOAT_EQ(translations[2].time, .2f);
|
||||
EXPECT_FLOAT_EQ(translations[3].time, .3f);
|
||||
}
|
||||
|
||||
// Very high tolerance
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = 1.f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .3f);
|
||||
}
|
||||
|
||||
// Compenstate scale on next joint
|
||||
{
|
||||
RawAnimation::ScaleKey key = {0.f, ozz::math::Float3(.1f, 0.f, 0.f)};
|
||||
input.tracks[1].scales.push_back(key);
|
||||
}
|
||||
|
||||
// High translation tolerance -> keys ar interpolated because of scale
|
||||
// compensation.
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = 1.f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
}
|
||||
|
||||
// Remove scaling compensation
|
||||
{ input.tracks[1].scales.clear(); }
|
||||
|
||||
// Introduces a .1x scaling upstream that amplifies error
|
||||
// Scaling on track 0
|
||||
{ input.tracks[0].scales[0].value = ozz::math::Float3(0.f, 0.f, .1f); }
|
||||
|
||||
// High translation tolerance -> keys aren't interpolated because of scale
|
||||
// effect.
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .001f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 4u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .1f);
|
||||
EXPECT_FLOAT_EQ(translations[2].time, .2f);
|
||||
EXPECT_FLOAT_EQ(translations[3].time, .3f);
|
||||
}
|
||||
|
||||
// Very high translation tolerance
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .01f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .3f);
|
||||
}
|
||||
|
||||
// Remove scaling
|
||||
{ input.tracks[0].scales.clear(); }
|
||||
|
||||
// Rotations on track 0.
|
||||
{
|
||||
RawAnimation::RotationKey key = {
|
||||
0.f, ozz::math::Quaternion::FromEuler(0.f, 0.f, 0.f)};
|
||||
input.tracks[0].rotations.push_back(key);
|
||||
}
|
||||
{ // Include error
|
||||
const float angle_error = 2.5e-3f; // creates an arc of .1m at 40m.
|
||||
RawAnimation::RotationKey key = {
|
||||
.1f, ozz::math::Quaternion::FromEuler(ozz::math::kPi_4 + angle_error,
|
||||
0.f, 0.f)};
|
||||
input.tracks[0].rotations.push_back(key);
|
||||
}
|
||||
{
|
||||
RawAnimation::RotationKey key = {
|
||||
.2f, ozz::math::Quaternion::FromEuler(ozz::math::kPi_2, 0.f, 0.f)};
|
||||
input.tracks[0].rotations.push_back(key);
|
||||
}
|
||||
|
||||
// Big enough tolerance -> keys rejected
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .3f;
|
||||
optimizer.setting.distance = 40.f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[0].rotations;
|
||||
ASSERT_EQ(rotations.size(), 2u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
}
|
||||
|
||||
// Small enough tolerance -> keys rejected
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .05f;
|
||||
optimizer.setting.distance = 40.f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[0].rotations;
|
||||
ASSERT_EQ(rotations.size(), 3u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 4u);
|
||||
}
|
||||
|
||||
// Back to default
|
||||
optimizer.setting = AnimationOptimizer::Setting();
|
||||
|
||||
// Small translation tolerance -> all key maintained
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .01f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[0].rotations;
|
||||
ASSERT_EQ(rotations.size(), 3u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 4u);
|
||||
}
|
||||
|
||||
// Introduces a .1x scaling upstream that lowers error
|
||||
// Scaling on track 0
|
||||
{
|
||||
RawAnimation::ScaleKey key = {0.f, ozz::math::Float3(0.f, .1f, 0.f)};
|
||||
input.tracks[1].scales.push_back(key);
|
||||
}
|
||||
|
||||
// Small translation tolerance, but scaled down -> keys rejected
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .011f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[0].rotations;
|
||||
ASSERT_EQ(rotations.size(), 2u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
}
|
||||
|
||||
// More vertex distance -> keys are maintained (translation unaffected)
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting.tolerance = .01f;
|
||||
optimizer.setting.distance = 1.f;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[0].rotations;
|
||||
ASSERT_EQ(rotations.size(), 3u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
}
|
||||
|
||||
// Remove scaling
|
||||
{ input.tracks[2].scales.clear(); }
|
||||
}
|
||||
|
||||
TEST(OptimizeOverride, AnimationOptimizer) {
|
||||
// Prepares a skeleton.
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
raw_skeleton.roots[0].children.resize(1);
|
||||
raw_skeleton.roots[0].children[0].children.resize(1);
|
||||
raw_skeleton.roots[0].children[0].children[0].children.resize(2);
|
||||
SkeletonBuilder skeleton_builder;
|
||||
ozz::unique_ptr<Skeleton> skeleton(skeleton_builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
|
||||
// Disable non hierarchical optimizations
|
||||
AnimationOptimizer optimizer;
|
||||
const AnimationOptimizer::Setting loose_setting(1e-2f, // 1cm
|
||||
1e-3f); // 1mm
|
||||
// Disables vertex distance.
|
||||
optimizer.setting.distance = 0.f;
|
||||
|
||||
RawAnimation input;
|
||||
input.duration = 1.f;
|
||||
input.tracks.resize(5);
|
||||
|
||||
// Translations on track 0.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(.4f, 0.f, 0.f)};
|
||||
input.tracks[0].translations.push_back(key);
|
||||
}
|
||||
|
||||
// Rotations on track 0.
|
||||
{
|
||||
RawAnimation::RotationKey key = {
|
||||
0.f, ozz::math::Quaternion::FromEuler(0.f, 0.f, 0.f)};
|
||||
input.tracks[1].rotations.push_back(key);
|
||||
}
|
||||
{ // Includes an error that
|
||||
const float angle_error = 1e-3f; // creates an arc of 1mm at 1m.
|
||||
RawAnimation::RotationKey key = {
|
||||
.1f, ozz::math::Quaternion::FromEuler(ozz::math::kPi_4 + angle_error,
|
||||
0.f, 0.f)};
|
||||
input.tracks[1].rotations.push_back(key);
|
||||
}
|
||||
{
|
||||
RawAnimation::RotationKey key = {
|
||||
.2f, ozz::math::Quaternion::FromEuler(ozz::math::kPi_2, 0.f, 0.f)};
|
||||
input.tracks[1].rotations.push_back(key);
|
||||
}
|
||||
|
||||
// Translations on track 1.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(0.f, 0.f, 0.f)};
|
||||
input.tracks[1].translations.push_back(key);
|
||||
}
|
||||
|
||||
// Translations on track 2.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(.05f, 0.f, 0.f)};
|
||||
input.tracks[2].translations.push_back(key);
|
||||
}
|
||||
{
|
||||
RawAnimation::TranslationKey key = {.1f, ozz::math::Float3(.06f, 0.f, 0.f)};
|
||||
input.tracks[2].translations.push_back(key);
|
||||
}
|
||||
{ // Creates a variation.
|
||||
const float trans_err = 5e-4f;
|
||||
RawAnimation::TranslationKey key = {
|
||||
.2f, ozz::math::Float3(.07f + trans_err, 0.f, 0.f)};
|
||||
input.tracks[2].translations.push_back(key);
|
||||
}
|
||||
{
|
||||
RawAnimation::TranslationKey key = {.3f, ozz::math::Float3(.08f, 0.f, 0.f)};
|
||||
input.tracks[2].translations.push_back(key);
|
||||
}
|
||||
|
||||
// Translations on track 3.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(.16f, 0.f, 0.f)};
|
||||
input.tracks[3].translations.push_back(key);
|
||||
}
|
||||
// Translations on track 4.
|
||||
{
|
||||
RawAnimation::TranslationKey key = {0.f, ozz::math::Float3(.32f, 0.f, 0.f)};
|
||||
input.tracks[4].translations.push_back(key);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(input.Validate());
|
||||
|
||||
// Default global tolerances
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting = loose_setting;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
ASSERT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[1].rotations;
|
||||
ASSERT_EQ(rotations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(rotations[0].time, 0.f);
|
||||
EXPECT_FLOAT_EQ(rotations[1].time, .2f);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(translations[0].time, 0.f);
|
||||
EXPECT_FLOAT_EQ(translations[1].time, .3f);
|
||||
}
|
||||
|
||||
// Overriding root has no effect on its child, even with small tolerance.
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting = loose_setting;
|
||||
const AnimationOptimizer::Setting joint_override(1e-6f, 1e6f);
|
||||
optimizer.joints_setting_override[0] = joint_override;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
ASSERT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[1].rotations;
|
||||
EXPECT_EQ(rotations.size(), 2u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
EXPECT_EQ(translations.size(), 2u);
|
||||
|
||||
optimizer.joints_setting_override.clear();
|
||||
}
|
||||
|
||||
// Overriding a joint has effect on itself.
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting = loose_setting;
|
||||
const AnimationOptimizer::Setting joint_override(1e-3f, // 1mm
|
||||
1e-2f); // 1cm
|
||||
optimizer.joints_setting_override[1] = joint_override;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[1].rotations;
|
||||
EXPECT_EQ(rotations.size(), 2u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
EXPECT_EQ(translations.size(), 2u);
|
||||
|
||||
optimizer.joints_setting_override.clear();
|
||||
}
|
||||
|
||||
// Overriding leaf has effect up to the root though.
|
||||
{
|
||||
RawAnimation output;
|
||||
optimizer.setting = loose_setting;
|
||||
const AnimationOptimizer::Setting joint_override(1e-3f, // 1mm
|
||||
10.f); // 10m
|
||||
optimizer.joints_setting_override[2] = joint_override;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[1].rotations;
|
||||
ASSERT_EQ(rotations.size(), 3u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
ASSERT_EQ(translations.size(), 2u);
|
||||
|
||||
optimizer.joints_setting_override.clear();
|
||||
}
|
||||
|
||||
// Scale at root affects rotation and translation.
|
||||
{
|
||||
RawAnimation::ScaleKey key = {0.f, ozz::math::Float3(.1f, 2.f, .1f)};
|
||||
input.tracks[0].scales.push_back(key);
|
||||
|
||||
RawAnimation output;
|
||||
optimizer.setting = loose_setting;
|
||||
const AnimationOptimizer::Setting joint_override(1.e-3f, // > 1mm
|
||||
1.f); // 1m
|
||||
optimizer.joints_setting_override[1] = joint_override;
|
||||
optimizer.joints_setting_override[2] = joint_override;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[1].rotations;
|
||||
EXPECT_EQ(rotations.size(), 3u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
EXPECT_EQ(translations.size(), 3u);
|
||||
|
||||
optimizer.joints_setting_override.clear();
|
||||
input.tracks[0].scales.clear();
|
||||
}
|
||||
|
||||
// Scale at leaf doesn't affect anything but the leaf.
|
||||
{
|
||||
RawAnimation::ScaleKey key = {0.f, ozz::math::Float3(.1f, 2.f, .1f)};
|
||||
input.tracks[4].scales.push_back(key);
|
||||
|
||||
RawAnimation output;
|
||||
optimizer.setting = loose_setting;
|
||||
const AnimationOptimizer::Setting joint_override(1e-3f, // < 1mm
|
||||
.5f); // .5m
|
||||
optimizer.joints_setting_override[1] = joint_override;
|
||||
ASSERT_TRUE(optimizer(input, *skeleton, &output));
|
||||
EXPECT_EQ(output.num_tracks(), 5);
|
||||
|
||||
const RawAnimation::JointTrack::Rotations& rotations =
|
||||
output.tracks[1].rotations;
|
||||
EXPECT_EQ(rotations.size(), 2u);
|
||||
|
||||
const RawAnimation::JointTrack::Translations& translations =
|
||||
output.tracks[2].translations;
|
||||
EXPECT_EQ(translations.size(), 2u);
|
||||
|
||||
optimizer.joints_setting_override.clear();
|
||||
input.tracks[4].scales.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
if(NOT ozz_build_fbx)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Creates a file with an invalid content.
|
||||
file(WRITE "${ozz_temp_directory}/bad.fbx" "bad content")
|
||||
|
||||
# Run fbx2ozz generic failing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME fbx2ozz_version COMMAND fbx2ozz "--version")
|
||||
add_test(NAME fbx2ozz_bad_content COMMAND fbx2ozz "--file=${ozz_temp_directory}/bad.fbx" )
|
||||
set_tests_properties(fbx2ozz_bad_content PROPERTIES PASS_REGULAR_EXPRESSION "Failed to import file \"${ozz_temp_directory}/bad.fbx\".")
|
||||
|
||||
# Run fbx2ozz skeleton failing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME fbx2ozz_skel_no_skeleton COMMAND fbx2ozz "--file=${ozz_media_directory}/fbx/cube.fbx" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/fbx_should_not_exist.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}")
|
||||
set_tests_properties(fbx2ozz_skel_no_skeleton PROPERTIES PASS_REGULAR_EXPRESSION "Failed to import skeleton.")
|
||||
|
||||
# Run fbx2ozz collada failing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME fbx2ozz_skel_no_skeleton_dae COMMAND fbx2ozz "--file=${ozz_media_directory}/collada/cube.dae" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/fbx_should_not_exist.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}")
|
||||
set_tests_properties(fbx2ozz_skel_no_skeleton_dae PROPERTIES PASS_REGULAR_EXPRESSION "Failed to import skeleton.")
|
||||
|
||||
# Ensures nothing was outputted.
|
||||
add_test(NAME fbx2ozz_skel_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/fbx_should_not_exist.ozz" "${ozz_temp_directory}/fbx_should_not_exist_too.ozz")
|
||||
set_tests_properties(fbx2ozz_skel_output PROPERTIES WILL_FAIL true)
|
||||
set_tests_properties(fbx2ozz_skel_output PROPERTIES
|
||||
DEPENDS "fbx2ozz_skel_no_skeleton
|
||||
fbx2ozz_skel_no_skeleton_dae")
|
||||
|
||||
# Run fbx2ozz skeleton passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME fbx2ozz_skel_simple COMMAND fbx2ozz "--file=${ozz_media_directory}/fbx/pab/skeleton.fbx" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/fbx_skeleton.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}")
|
||||
add_test(NAME fbx2ozz_skel_simple_raw COMMAND fbx2ozz "--file=${ozz_media_directory}/fbx/pab/skeleton.fbx" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/fbx_raw_skeleton.ozz\",\"import\":{\"enable\":true,\"raw\":true}},\"animations\":[]}}")
|
||||
|
||||
# Run fbx2ozz collada skeleton passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME fbx2ozz_skel_simple_dae_astro_max COMMAND fbx2ozz "--file=${ozz_media_directory}/collada/astro_max.dae" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/astro_max_skeleton.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}")
|
||||
add_test(NAME fbx2ozz_skel_simple_dae_astro_maya COMMAND fbx2ozz "--file=${ozz_media_directory}/collada/astro_maya.dae" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/astro_maya_skeleton.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}")
|
||||
add_test(NAME fbx2ozz_skel_simple_dae_seymour COMMAND fbx2ozz "--file=${ozz_media_directory}/collada/seymour.dae" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/seymour_skeleton.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}")
|
||||
|
||||
# Run fbx2ozz animation failing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME fbx2ozz_anim_badcontent COMMAND fbx2ozz "--file=${ozz_temp_directory}/bad.fbx")
|
||||
set_tests_properties(fbx2ozz_anim_badcontent PROPERTIES DEPENDS fbx2ozz_skel_simple)
|
||||
set_tests_properties(fbx2ozz_anim_badcontent PROPERTIES PASS_REGULAR_EXPRESSION "FbxImporter initialization failed with error: Unexpected file type")
|
||||
|
||||
# Run fbx2ozz animation passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME fbx2ozz_anim_simple COMMAND fbx2ozz "--file=${ozz_media_directory}/fbx/pab/run.fbx" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/fbx_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/fbx_animation_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}")
|
||||
set_tests_properties(fbx2ozz_anim_simple PROPERTIES DEPENDS fbx2ozz_skel_simple)
|
||||
add_test(NAME fbx2ozz_anim_simple_raw COMMAND fbx2ozz "--file=${ozz_media_directory}/fbx/pab/run.fbx" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/fbx_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/fbx_animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"raw\":true}]}")
|
||||
set_tests_properties(fbx2ozz_anim_simple_raw PROPERTIES DEPENDS fbx2ozz_skel_simple)
|
||||
add_test(NAME fbx2ozz_anim_simple_from_raw COMMAND fbx2ozz "--file=${ozz_media_directory}/fbx/pab/run.fbx" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/fbx_raw_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/fbx_animation_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}")
|
||||
set_tests_properties(fbx2ozz_anim_simple_from_raw PROPERTIES DEPENDS fbx2ozz_skel_simple_raw)
|
||||
add_test(NAME fbx2ozz_anim_simple_raw_from_raw COMMAND fbx2ozz "--file=${ozz_media_directory}/fbx/pab/run.fbx" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/fbx_raw_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/fbx_animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"raw\":true}]}")
|
||||
set_tests_properties(fbx2ozz_anim_simple_raw_from_raw PROPERTIES DEPENDS fbx2ozz_skel_simple_raw)
|
||||
|
||||
# Run fbx2ozz track passing tests
|
||||
#----------------------------
|
||||
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/properties.json.cmake" "${ozz_temp_directory}/properties.json")
|
||||
|
||||
add_test(NAME fbx2ozz_anim_properties COMMAND fbx2ozz "--file=${ozz_media_directory}/fbx/properties.fbx" "--config_file=${ozz_temp_directory}/properties.json")
|
||||
set_tests_properties(fbx2ozz_anim_properties PROPERTIES DEPENDS fbx2ozz_skel_properties)
|
||||
|
||||
# Ensures all tracks were outputted.
|
||||
file(MAKE_DIRECTORY ${ozz_temp_directory}/fbx_properties_tracks_cp)
|
||||
add_test(NAME fbx2ozz_anim_properties_output COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${ozz_temp_directory}/fbx_properties_track1_animated-ozz_curve_bool.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_animated-ozz_curve_int.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_animated-ozz_curve_number.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_animated-ozz_step_bool.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_animated-ozz_step_enum.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_animated-ozz_step_int.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_animated-ozz_step_number.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_constant-ozz_bool.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_constant-ozz_enum.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_constant-ozz_int.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track1_constant-ozz_number.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track3_animated-ozz_curve_vector.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track3_constant-ozz_vector.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track3p_animated-ozz_curve_vector.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track3p_constant-ozz_vector.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track3v_animated-ozz_curve_vector.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track3v_constant-ozz_vector.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track4_animated-ozz_curve_color.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_track4_constant-ozz_color.ozz"
|
||||
"${ozz_temp_directory}/fbx_properties_tracks_cp/"
|
||||
)
|
||||
set_tests_properties(fbx2ozz_anim_properties_output PROPERTIES
|
||||
DEPENDS fbx2ozz_anim_properties
|
||||
"${ozz_media_directory}/fbx/properties.fbx"
|
||||
"${ozz_temp_directory}/fbx_propreties_skeleton.ozz")
|
||||
|
||||
# Run fbx2ozz animation collada passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME fbx2ozz_anim_simple_dae_astro_max COMMAND fbx2ozz "--file=${ozz_media_directory}/collada/astro_max.dae" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/astro_max_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/dae_animation_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}")
|
||||
set_tests_properties(fbx2ozz_anim_simple_dae_astro_max PROPERTIES DEPENDS fbx2ozz_skel_simple_dae_astro_max)
|
||||
add_test(NAME fbx2ozz_anim_simple_dae_astro_maya COMMAND fbx2ozz "--file=${ozz_media_directory}/collada/astro_maya.dae" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/astro_maya_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/dae_animation_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}")
|
||||
set_tests_properties(fbx2ozz_anim_simple_dae_astro_maya PROPERTIES DEPENDS fbx2ozz_skel_simple_dae_astro_maya)
|
||||
add_test(NAME fbx2ozz_anim_simple_dae_seymour COMMAND fbx2ozz "--file=${ozz_media_directory}/collada/seymour.dae" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/seymour_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{
|
||||
\"filename\":\"${ozz_temp_directory}/dae_animation_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}")
|
||||
set_tests_properties(fbx2ozz_anim_simple_dae_seymour PROPERTIES DEPENDS fbx2ozz_skel_simple_dae_seymour)
|
||||
|
||||
# Uses the sample playback to test other file format and special cases.
|
||||
if(TARGET sample_playback)
|
||||
|
||||
add_custom_command(
|
||||
DEPENDS $<$<AND:$<BOOL:${ozz_build_data}>,$<BOOL:${ozz_build_fbx}>>:fbx2ozz>
|
||||
"${ozz_media_directory}/collada/pab/skeleton.dae"
|
||||
"${ozz_media_directory}/collada/pab/skeleton_zup.dae"
|
||||
"${ozz_media_directory}/collada/pab/walk.dae"
|
||||
OUTPUT "${ozz_temp_directory}/pab_skeleton_dae.ozz"
|
||||
"${ozz_temp_directory}/pab_skeleton_dae_zup.ozz"
|
||||
"${ozz_temp_directory}/pab_walk_dae.ozz"
|
||||
COMMAND fbx2ozz
|
||||
"--file=${ozz_media_directory}/collada/pab/skeleton.dae"
|
||||
"--config={\"skeleton\":{\"filename\": \"${ozz_temp_directory}/pab_skeleton_dae.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}"
|
||||
COMMAND fbx2ozz
|
||||
"--file=${ozz_media_directory}/collada/pab/skeleton_zup.dae"
|
||||
"--config={\"skeleton\":{\"filename\": \"${ozz_temp_directory}/pab_skeleton_dae_zup.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}"
|
||||
COMMAND fbx2ozz
|
||||
"--file=${ozz_media_directory}/collada/pab/walk.dae"
|
||||
"--config={\"skeleton\":{\"filename\": \"${ozz_temp_directory}/pab_skeleton_dae_zup.ozz\"},\"animations\": [{\"filename\":\"${ozz_temp_directory}/pab_walk_dae.ozz\"}]}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(BUILD_DATA_FBX_TEST ALL DEPENDS
|
||||
"${ozz_temp_directory}/pab_skeleton_dae.ozz"
|
||||
"${ozz_temp_directory}/pab_skeleton_dae_zup.ozz"
|
||||
"${ozz_temp_directory}/pab_walk_dae.ozz"
|
||||
VERBATIM)
|
||||
|
||||
add_test(NAME sample_playback_dae_zup COMMAND sample_playback "--skeleton=${ozz_temp_directory}/pab_skeleton_dae_zup.ozz" "--animation=${ozz_temp_directory}/pab_walk_dae.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
|
||||
|
||||
add_test(NAME sample_playback_dae_seymour COMMAND sample_playback "--skeleton=${ozz_media_directory}/bin/seymour_skeleton.ozz" "--animation=${ozz_media_directory}/bin/seymour_animation.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
|
||||
add_test(NAME sample_playback_dae_astro_max COMMAND sample_playback "--skeleton=${ozz_media_directory}/bin/astro_max_skeleton.ozz" "--animation=${ozz_media_directory}/bin/astro_max_animation.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
|
||||
add_test(NAME sample_playback_dae_astro_maya COMMAND sample_playback "--skeleton=${ozz_media_directory}/bin/astro_maya_skeleton.ozz" "--animation=${ozz_media_directory}/bin/astro_maya_animation.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
|
||||
|
||||
add_test(NAME sample_playback_mixed_df COMMAND sample_playback "--skeleton=${ozz_temp_directory}/pab_skeleton_dae.ozz" "--animation=${ozz_media_directory}/bin/pab_walk.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
|
||||
add_test(NAME sample_playback_mixed_fd COMMAND sample_playback "--skeleton=${ozz_media_directory}/bin/pab_skeleton.ozz" "--animation=${ozz_temp_directory}/pab_walk_dae.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
|
||||
endif()
|
||||
|
||||
# ozz_animation_fbx fuse tests
|
||||
set_source_files_properties(${PROJECT_BINARY_DIR}/src_fused/ozz_animation_fbx.cc PROPERTIES GENERATED 1)
|
||||
add_executable(test_fuse_ozz_animation_fbx
|
||||
fuse_ozz_animation_fbx_tests
|
||||
${PROJECT_BINARY_DIR}/src_fused/ozz_animation_fbx.cc)
|
||||
add_dependencies(test_fuse_ozz_animation_fbx BUILD_FUSE_ozz_animation_fbx)
|
||||
target_include_directories(test_fuse_ozz_animation_fbx
|
||||
PUBLIC ${FBX_INCLUDE_DIRS})
|
||||
target_compile_options(test_fuse_ozz_animation_fbx
|
||||
PUBLIC $<$<BOOL:${W_NULL_DEREFERENCE}>:-Wno-null-dereference>
|
||||
PUBLIC $<$<BOOL:${W_PRAGMA_PACK}>:-Wno-pragma-pack>)
|
||||
target_link_libraries(test_fuse_ozz_animation_fbx
|
||||
debug ${FBX_LIBRARIES_DEBUG}
|
||||
optimized ${FBX_LIBRARIES}
|
||||
ozz_animation_offline)
|
||||
set_target_properties(test_fuse_ozz_animation_fbx PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
|
||||
add_test(NAME test_fuse_ozz_animation_fbx COMMAND test_fuse_ozz_animation_fbx)
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/fbx/fbx.h"
|
||||
|
||||
int main(int, const char**) {
|
||||
ozz::animation::offline::fbx::FbxManagerInstance instance;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"skeleton":
|
||||
{
|
||||
"filename":"${ozz_temp_directory}/fbx_propreties_skeleton.ozz"
|
||||
},
|
||||
"animations":
|
||||
[
|
||||
{
|
||||
"filename":"${ozz_temp_directory}/fbx_properties_animation_${CMAKE_CURRENT_LIST_LINE}.ozz",
|
||||
"tracks":
|
||||
[
|
||||
{
|
||||
"properties":
|
||||
[
|
||||
{
|
||||
"filename":"${ozz_temp_directory}/fbx_properties_track1_*.ozz",
|
||||
"joint_name":"*",
|
||||
"property_name":"ozz_*",
|
||||
"type":"float1"
|
||||
},
|
||||
{
|
||||
"filename":"${ozz_temp_directory}/fbx_properties_track2_*.ozz",
|
||||
"joint_name":"*",
|
||||
"property_name":"ozz_*",
|
||||
"type":"float2"
|
||||
},
|
||||
{
|
||||
"filename":"${ozz_temp_directory}/fbx_properties_track3_*.ozz",
|
||||
"joint_name":"*",
|
||||
"property_name":"ozz_*",
|
||||
"type":"float3"
|
||||
},
|
||||
{
|
||||
"filename":"${ozz_temp_directory}/fbx_properties_track3p_*.ozz",
|
||||
"joint_name":"*",
|
||||
"property_name":"ozz_*",
|
||||
"type":"point"
|
||||
},
|
||||
{
|
||||
"filename":"${ozz_temp_directory}/fbx_properties_track3v_*.ozz",
|
||||
"joint_name":"*",
|
||||
"property_name":"ozz_*",
|
||||
"type":"vector"
|
||||
},
|
||||
{
|
||||
"filename":"${ozz_temp_directory}/fbx_properties_track4_*.ozz",
|
||||
"joint_name":"*",
|
||||
"property_name":"ozz_*",
|
||||
"type":"float4"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
if(NOT ozz_build_gltf)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Creates a file with an invalid content.
|
||||
file(WRITE "${ozz_temp_directory}/bad.unk" "bad content")
|
||||
file(WRITE "${ozz_temp_directory}/bad.gltf" "bad content")
|
||||
file(WRITE "${ozz_temp_directory}/bad.glb" "bad content")
|
||||
|
||||
# Run gltf2ozz generic failing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME gltf2ozz_version COMMAND gltf2ozz "--version")
|
||||
add_test(NAME gltf2ozz_bad_content COMMAND gltf2ozz "--file=${ozz_temp_directory}/bad.unk" )
|
||||
set_tests_properties(gltf2ozz_bad_content PROPERTIES PASS_REGULAR_EXPRESSION "Failed to import file \"${ozz_temp_directory}/bad.unk\".")
|
||||
add_test(NAME gltf2ozz_bad_content_gltf COMMAND gltf2ozz "--file=${ozz_temp_directory}/bad.gltf" )
|
||||
set_tests_properties(gltf2ozz_bad_content_gltf PROPERTIES PASS_REGULAR_EXPRESSION "Failed to import file \"${ozz_temp_directory}/bad.gltf\".")
|
||||
add_test(NAME gltf2ozz_bad_content_glb COMMAND gltf2ozz "--file=${ozz_temp_directory}/bad.glb" )
|
||||
set_tests_properties(gltf2ozz_bad_content_glb PROPERTIES PASS_REGULAR_EXPRESSION "Failed to import file \"${ozz_temp_directory}/bad.glb\".")
|
||||
|
||||
# Run gltf2ozz skeleton failing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME gltf2ozz_skel_no_animation COMMAND gltf2ozz "--file=${ozz_media_directory}/gltf/khronos/triangle.gltf" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/gltf_skeleton_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"import\":{\"enable\":true}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/gltf_should_not_exist.ozz\",\"clip\":\"*\"}]}")
|
||||
set_tests_properties(gltf2ozz_skel_no_animation PROPERTIES PASS_REGULAR_EXPRESSION "No animation found.")
|
||||
|
||||
add_test(NAME gltf2ozz_skel_no_matching_animation COMMAND gltf2ozz "--file=${ozz_media_directory}/gltf/khronos/interpolation_test.gltf" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/gltf_skeleton_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"import\":{\"enable\":true}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/gltf_should_not_exist.ozz\",\"clip\":\"won_t_match\"}]}")
|
||||
set_tests_properties(gltf2ozz_skel_no_matching_animation PROPERTIES PASS_REGULAR_EXPRESSION "No matching animation found")
|
||||
|
||||
# Ensures nothing unexpected was outputted
|
||||
#-----------------------------------------
|
||||
|
||||
add_test(NAME gltf2ozz_skel_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/gltf_should_not_exist.ozz" "${ozz_temp_directory}/gltf_should_not_exist_too.ozz")
|
||||
set_tests_properties(gltf2ozz_skel_output PROPERTIES WILL_FAIL true)
|
||||
set_tests_properties(gltf2ozz_skel_output PROPERTIES
|
||||
DEPENDS "gltf2ozz_skel_no_skeleton")
|
||||
|
||||
# Run gltf2ozz skeleton passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME gltf2ozz_skel_simple COMMAND gltf2ozz "--file=${ozz_media_directory}/gltf/khronos/interpolation_test.gltf" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/gltf_interpolation_test_skeleton.ozz\",\"import\":{\"enable\":true}}}")
|
||||
|
||||
add_test(NAME gltf2ozz_skel_box_animated COMMAND gltf2ozz "--file=${ozz_media_directory}/gltf/khronos/box_animated.gltf" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/gltf_box_animated_skeleton.ozz\",\"import\":{\"enable\":true}}}")
|
||||
|
||||
add_test(NAME gltf2ozz_skel_cesium COMMAND gltf2ozz "--file=${ozz_media_directory}/gltf/khronos/cesium_man.gltf" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/gltf_cesium_man_skeleton.ozz\",\"import\":{\"enable\":true}}}")
|
||||
|
||||
# Run gltf2ozz animation passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME gltf2ozz_animation_multiple COMMAND gltf2ozz "--file=${ozz_media_directory}/gltf/khronos/interpolation_test.gltf" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/gltf_interpolation_test_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/gltf_interpolation_test_*.ozz\"}]}")
|
||||
set_tests_properties(gltf2ozz_animation_multiple PROPERTIES DEPENDS gltf2ozz_skel_simple)
|
||||
|
||||
add_test(NAME gltf2ozz_box_animation COMMAND gltf2ozz "--file=${ozz_media_directory}/gltf/khronos/box_animated.gltf" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/gltf_box_animated_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/gltf_box_animation.ozz\"}]}")
|
||||
set_tests_properties(gltf2ozz_box_animation PROPERTIES DEPENDS gltf2ozz_skel_box_animated)
|
||||
|
||||
add_test(NAME gltf2ozz_cesium_animation COMMAND gltf2ozz "--file=${ozz_media_directory}/gltf/khronos/cesium_man.gltf" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/gltf_cesium_man_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/gltf_cesium_man_animation.ozz\"}]}")
|
||||
set_tests_properties(gltf2ozz_cesium_animation PROPERTIES DEPENDS gltf2ozz_skel_cesium)
|
||||
|
||||
# Uses the sample playback to test other file format and special cases.
|
||||
if(TARGET sample_playback)
|
||||
|
||||
add_custom_command(
|
||||
DEPENDS $<$<AND:$<BOOL:${ozz_build_data}>,$<BOOL:${ozz_build_gltf}>>:gltf2ozz>
|
||||
"${ozz_media_directory}/gltf/sketchfab/ruby/scene.gltf"
|
||||
OUTPUT "${ozz_temp_directory}/gltf_ruby_skeleton.ozz"
|
||||
"${ozz_temp_directory}/gltf_ruby_animation.ozz"
|
||||
COMMAND gltf2ozz
|
||||
"--file=${ozz_media_directory}/gltf/sketchfab/ruby/scene.gltf"
|
||||
"--config={\"skeleton\":{\"filename\": \"${ozz_temp_directory}/gltf_ruby_skeleton.ozz\",\"import\":{\"enable\":true}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/gltf_ruby_animation.ozz\"}]}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(BUILD_DATA_GLTF_TEST ALL DEPENDS
|
||||
"${ozz_temp_directory}/gltf_ruby_skeleton.ozz"
|
||||
"${ozz_temp_directory}/gltf_ruby_animation.ozz"
|
||||
VERBATIM)
|
||||
|
||||
add_test(NAME sample_playback_gltf_ruby COMMAND sample_playback "--skeleton=${ozz_temp_directory}/gltf_ruby_skeleton.ozz" "--animation=${ozz_temp_directory}/gltf_ruby_animation.ozz" "--max_idle_loops=${ozz_sample_testing_loops}" $<$<BOOL:${ozz_run_tests_headless}>:--norender>)
|
||||
endif()
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
using ozz::animation::offline::RawAnimation;
|
||||
|
||||
TEST(Empty, RawAnimationSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
|
||||
RawAnimation o_animation;
|
||||
o << o_animation;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
RawAnimation i_animation;
|
||||
i >> i_animation;
|
||||
|
||||
EXPECT_FLOAT_EQ(o_animation.duration, i_animation.duration);
|
||||
EXPECT_EQ(o_animation.num_tracks(), i_animation.num_tracks());
|
||||
}
|
||||
|
||||
TEST(Filled, RawAnimationSerialize) {
|
||||
RawAnimation o_animation;
|
||||
o_animation.duration = 46.f;
|
||||
o_animation.tracks.resize(3);
|
||||
const RawAnimation::TranslationKey t_key = {
|
||||
0.f, ozz::math::Float3(46.f, 93.f, 99.f)};
|
||||
o_animation.tracks[0].translations.push_back(t_key);
|
||||
const RawAnimation::RotationKey r_key = {
|
||||
46.f, ozz::math::Quaternion(0.f, 1.f, 0.f, 0.f)};
|
||||
o_animation.tracks[1].rotations.push_back(r_key);
|
||||
const RawAnimation::ScaleKey s_key = {1.f,
|
||||
ozz::math::Float3(93.f, 46.f, 99.f)};
|
||||
o_animation.tracks[2].scales.push_back(s_key);
|
||||
|
||||
EXPECT_TRUE(o_animation.Validate());
|
||||
EXPECT_EQ(o_animation.num_tracks(), 3);
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << o_animation;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive ia(&stream);
|
||||
|
||||
RawAnimation i_animation;
|
||||
ia >> i_animation;
|
||||
|
||||
EXPECT_TRUE(i_animation.Validate());
|
||||
EXPECT_FLOAT_EQ(o_animation.duration, i_animation.duration);
|
||||
ASSERT_EQ(o_animation.num_tracks(), i_animation.num_tracks());
|
||||
|
||||
for (size_t i = 0; i < o_animation.tracks.size(); ++i) {
|
||||
const RawAnimation::JointTrack& o_track = o_animation.tracks[i];
|
||||
const RawAnimation::JointTrack& i_track = i_animation.tracks[i];
|
||||
for (size_t j = 0; j < o_track.translations.size(); ++j) {
|
||||
const RawAnimation::TranslationKey& o_key = o_track.translations[j];
|
||||
const RawAnimation::TranslationKey& i_key = i_track.translations[j];
|
||||
EXPECT_FLOAT_EQ(o_key.time, i_key.time);
|
||||
EXPECT_TRUE(Compare(o_key.value, i_key.value, 0.f));
|
||||
}
|
||||
for (size_t j = 0; j < o_track.rotations.size(); ++j) {
|
||||
const RawAnimation::RotationKey& o_key = o_track.rotations[j];
|
||||
const RawAnimation::RotationKey& i_key = i_track.rotations[j];
|
||||
EXPECT_FLOAT_EQ(o_key.time, i_key.time);
|
||||
EXPECT_TRUE(Compare(o_key.value, i_key.value, .1f));
|
||||
}
|
||||
for (size_t j = 0; j < o_track.scales.size(); ++j) {
|
||||
const RawAnimation::ScaleKey& o_key = o_track.scales[j];
|
||||
const RawAnimation::ScaleKey& i_key = i_track.scales[j];
|
||||
EXPECT_FLOAT_EQ(o_key.time, i_key.time);
|
||||
EXPECT_TRUE(Compare(o_key.value, i_key.value, 0.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlreadyInitialized, RawAnimationSerialize) {
|
||||
RawAnimation o_animation;
|
||||
o_animation.duration = 46.f;
|
||||
o_animation.tracks.resize(1);
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream);
|
||||
o << o_animation;
|
||||
|
||||
// Streams out a second time.
|
||||
o_animation.duration = 93.f;
|
||||
o_animation.tracks.resize(2);
|
||||
o << o_animation;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
RawAnimation i_animation;
|
||||
i >> i_animation;
|
||||
EXPECT_FLOAT_EQ(i_animation.duration, 46.f);
|
||||
ASSERT_EQ(i_animation.num_tracks(), 1);
|
||||
|
||||
// A second time
|
||||
i >> i_animation;
|
||||
EXPECT_FLOAT_EQ(i_animation.duration, 93.f);
|
||||
ASSERT_EQ(i_animation.num_tracks(), 2);
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
#include "ozz/base/log.h"
|
||||
#include "ozz/options/options.h"
|
||||
|
||||
OZZ_OPTIONS_DECLARE_STRING(file, "Specifies input file", "", true)
|
||||
OZZ_OPTIONS_DECLARE_INT(tracks, "Number of tracks", 0, true)
|
||||
OZZ_OPTIONS_DECLARE_FLOAT(duration, "Duration", 0.f, true)
|
||||
OZZ_OPTIONS_DECLARE_STRING(name, "Name", "", true)
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
// Parses arguments.
|
||||
testing::InitGoogleTest(&_argc, _argv);
|
||||
ozz::options::ParseResult parse_result = ozz::options::ParseCommandLine(
|
||||
_argc, _argv, "1.0",
|
||||
"Test RawAnimation archive versioning retrocompatibility");
|
||||
if (parse_result != ozz::options::kSuccess) {
|
||||
return parse_result == ozz::options::kExitSuccess ? EXIT_SUCCESS
|
||||
: EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
TEST(Versioning, RawAnimationSerialize) {
|
||||
// Open the file.
|
||||
const char* filename = OPTIONS_file;
|
||||
ozz::io::File file(filename, "rb");
|
||||
ASSERT_TRUE(file.opened());
|
||||
|
||||
// Open archive and test object tag.
|
||||
ozz::io::IArchive archive(&file);
|
||||
ASSERT_TRUE(archive.TestTag<ozz::animation::offline::RawAnimation>());
|
||||
|
||||
// Read the object.
|
||||
ozz::animation::offline::RawAnimation animation;
|
||||
archive >> animation;
|
||||
|
||||
// More testing
|
||||
EXPECT_EQ(animation.num_tracks(), OPTIONS_tracks);
|
||||
EXPECT_FLOAT_EQ(animation.duration, OPTIONS_duration);
|
||||
EXPECT_STREQ(animation.name.c_str(), OPTIONS_name.value());
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/raw_animation_utils.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
|
||||
using ozz::animation::offline::RawAnimation;
|
||||
|
||||
TEST(SamplingTrackEmpty, Utils) {
|
||||
RawAnimation::JointTrack track;
|
||||
ozz::math::Transform output;
|
||||
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, 0.f, &output));
|
||||
|
||||
EXPECT_FLOAT3_EQ(output.translation, 0.f, 0.f, 0.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(SamplingTrackInvalid, Utils) {
|
||||
// Key order
|
||||
{
|
||||
RawAnimation::JointTrack track;
|
||||
|
||||
RawAnimation::TranslationKey t0 = {.9f, ozz::math::Float3(1.f, 2.f, 4.f)};
|
||||
track.translations.push_back(t0);
|
||||
RawAnimation::TranslationKey t1 = {.1f, ozz::math::Float3(2.f, 4.f, 8.f)};
|
||||
track.translations.push_back(t1);
|
||||
|
||||
ozz::math::Transform output;
|
||||
EXPECT_FALSE(ozz::animation::offline::SampleTrack(track, 0.f, &output));
|
||||
}
|
||||
|
||||
// Negative time
|
||||
{
|
||||
RawAnimation::JointTrack track;
|
||||
|
||||
RawAnimation::TranslationKey t0 = {-1.f, ozz::math::Float3(1.f, 2.f, 4.f)};
|
||||
track.translations.push_back(t0);
|
||||
|
||||
ozz::math::Transform output;
|
||||
EXPECT_FALSE(ozz::animation::offline::SampleTrack(track, 0.f, &output));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SamplingTrack, Utils) {
|
||||
RawAnimation::JointTrack track;
|
||||
|
||||
RawAnimation::TranslationKey t0 = {.1f, ozz::math::Float3(1.f, 2.f, 4.f)};
|
||||
track.translations.push_back(t0);
|
||||
RawAnimation::TranslationKey t1 = {.9f, ozz::math::Float3(2.f, 4.f, 8.f)};
|
||||
track.translations.push_back(t1);
|
||||
|
||||
RawAnimation::RotationKey r0 = {
|
||||
0.f, ozz::math::Quaternion(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
track.rotations.push_back(r0);
|
||||
RawAnimation::RotationKey r1 = {
|
||||
// /!\ Negated (other hemisphepre) quaternion
|
||||
.5f, -ozz::math::Quaternion(0.f, .70710677f, 0.f, .70710677f)};
|
||||
track.rotations.push_back(r1);
|
||||
RawAnimation::RotationKey r2 = {
|
||||
1.f, ozz::math::Quaternion(0.f, .70710677f, 0.f, .70710677f)};
|
||||
track.rotations.push_back(r2);
|
||||
|
||||
RawAnimation::ScaleKey s0 = {.5f, ozz::math::Float3(-1.f, -2.f, -4.f)};
|
||||
track.scales.push_back(s0);
|
||||
|
||||
ozz::math::Transform output;
|
||||
|
||||
// t = -.1
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, -.1f, &output));
|
||||
EXPECT_FLOAT3_EQ(output.translation, 1.f, 2.f, 4.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, .70710677f, 0.f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
|
||||
// t = 0
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, 0.f, &output));
|
||||
EXPECT_FLOAT3_EQ(output.translation, 1.f, 2.f, 4.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, .70710677f, 0.f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
|
||||
// t = .1
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, .1f, &output));
|
||||
EXPECT_FLOAT3_EQ(output.translation, 1.f, 2.f, 4.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, .6172133f, .1543033f, 0.f, .7715167f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
|
||||
// t = .4999999
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, .4999999f, &output));
|
||||
EXPECT_FLOAT3_EQ(output.translation, 1.5f, 3.f, 6.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, 0.f, .70710677f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
|
||||
// t = .5
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, .5f, &output));
|
||||
EXPECT_FLOAT3_EQ(output.translation, 1.5f, 3.f, 6.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, 0.f, .70710677f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
|
||||
// t = .75
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, .75f, &output));
|
||||
// Fixed up based on dot with previous quaternion
|
||||
EXPECT_QUATERNION_EQ(output.rotation, 0.f, -.70710677f, 0.f, -.70710677f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
|
||||
// t= .9
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, .9f, &output));
|
||||
EXPECT_FLOAT3_EQ(output.translation, 2.f, 4.f, 8.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, 0.f, -.70710677f, 0.f, -.70710677f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
|
||||
// t= 1.
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, 1.f, &output));
|
||||
EXPECT_FLOAT3_EQ(output.translation, 2.f, 4.f, 8.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, 0.f, .70710677f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
|
||||
// t= 1.1
|
||||
ASSERT_TRUE(ozz::animation::offline::SampleTrack(track, 1.1f, &output));
|
||||
EXPECT_FLOAT3_EQ(output.translation, 2.f, 4.f, 8.f);
|
||||
EXPECT_QUATERNION_EQ(output.rotation, 0.f, .70710677f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(output.scale, -1.f, -2.f, -4.f);
|
||||
}
|
||||
|
||||
TEST(SamplingAnimation, Utils) {
|
||||
// Building an Animation with unsorted keys fails.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 2.f;
|
||||
raw_animation.tracks.resize(2);
|
||||
|
||||
RawAnimation::TranslationKey a = {.2f, ozz::math::Float3(-1.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[0].translations.push_back(a);
|
||||
|
||||
RawAnimation::TranslationKey b = {0.f, ozz::math::Float3(2.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[1].translations.push_back(b);
|
||||
RawAnimation::TranslationKey c = {0.2f, ozz::math::Float3(6.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[1].translations.push_back(c);
|
||||
RawAnimation::TranslationKey d = {0.4f, ozz::math::Float3(8.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[1].translations.push_back(d);
|
||||
|
||||
ozz::math::Transform output[2];
|
||||
|
||||
// Too small
|
||||
{
|
||||
ozz::math::Transform small[1];
|
||||
EXPECT_FALSE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, 0.f, small));
|
||||
}
|
||||
|
||||
// Invalid, cos track are longer than duration
|
||||
{
|
||||
raw_animation.duration = .1f;
|
||||
EXPECT_FALSE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, 0.f, output));
|
||||
raw_animation.duration = 2.f;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, -.1f, output));
|
||||
EXPECT_FLOAT3_EQ(output[0].translation, -1.f, 0.f, 0.f);
|
||||
EXPECT_QUATERNION_EQ(output[0].rotation, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT3_EQ(output[0].scale, 1.f, 1.f, 1.f);
|
||||
EXPECT_FLOAT3_EQ(output[1].translation, 2.f, 0.f, 0.f);
|
||||
EXPECT_QUATERNION_EQ(output[1].rotation, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT3_EQ(output[1].scale, 1.f, 1.f, 1.f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, 0.f, output));
|
||||
EXPECT_FLOAT3_EQ(output[0].translation, -1.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(output[1].translation, 2.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, .2f, output));
|
||||
EXPECT_FLOAT3_EQ(output[0].translation, -1.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(output[1].translation, 6.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, .3f, output));
|
||||
EXPECT_FLOAT3_EQ(output[0].translation, -1.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(output[1].translation, 7.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, .4f, output));
|
||||
EXPECT_FLOAT3_EQ(output[0].translation, -1.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(output[1].translation, 8.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, 2.f, output));
|
||||
EXPECT_FLOAT3_EQ(output[0].translation, -1.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(output[1].translation, 8.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
ozz::animation::offline::SampleAnimation(raw_animation, 3.f, output));
|
||||
EXPECT_FLOAT3_EQ(output[0].translation, -1.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(output[1].translation, 8.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(FixedRateSamplingTime, Utils) {
|
||||
{ // From 0
|
||||
ozz::animation::offline::FixedRateSamplingTime it(1.f, 30.f);
|
||||
EXPECT_EQ(it.num_keys(), 31u);
|
||||
|
||||
EXPECT_EQ(it.time(0), 0.f);
|
||||
EXPECT_FLOAT_EQ(it.time(1), 1.f / 30.f);
|
||||
EXPECT_FLOAT_EQ(it.time(2), 2.f / 30.f);
|
||||
EXPECT_FLOAT_EQ(it.time(29), 29.f / 30.f);
|
||||
EXPECT_EQ(it.time(30), 1.f);
|
||||
EXPECT_ASSERTION(it.time(31), "_key < num_keys");
|
||||
}
|
||||
|
||||
{ // Offset
|
||||
ozz::animation::offline::FixedRateSamplingTime it(3.f, 100.f);
|
||||
EXPECT_EQ(it.num_keys(), 301u);
|
||||
|
||||
EXPECT_EQ(it.time(0), 0.f);
|
||||
EXPECT_FLOAT_EQ(it.time(1), 1.f / 100.f);
|
||||
EXPECT_FLOAT_EQ(it.time(2), 2.f / 100.f);
|
||||
EXPECT_FLOAT_EQ(it.time(299), 299.f / 100.f);
|
||||
EXPECT_EQ(it.time(300), 3.f);
|
||||
}
|
||||
|
||||
{ // Ceil
|
||||
ozz::animation::offline::FixedRateSamplingTime it(1.001f, 30.f);
|
||||
EXPECT_EQ(it.num_keys(), 32u);
|
||||
|
||||
EXPECT_EQ(it.time(0), 0.f);
|
||||
EXPECT_FLOAT_EQ(it.time(1), 1.f / 30.f);
|
||||
EXPECT_FLOAT_EQ(it.time(2), 2.f / 30.f);
|
||||
EXPECT_FLOAT_EQ(it.time(29), 29.f / 30.f);
|
||||
EXPECT_FLOAT_EQ(it.time(30), 1.f);
|
||||
EXPECT_EQ(it.time(31), 1.001f);
|
||||
}
|
||||
|
||||
{ // Long
|
||||
ozz::animation::offline::FixedRateSamplingTime it(1000.f, 30.f);
|
||||
EXPECT_EQ(it.num_keys(), 30001u);
|
||||
|
||||
EXPECT_EQ(it.time(0), 0.f);
|
||||
EXPECT_FLOAT_EQ(it.time(1), 1.f / 30.f);
|
||||
EXPECT_FLOAT_EQ(it.time(2), 2.f / 30.f);
|
||||
EXPECT_FLOAT_EQ(it.time(29999), 29999.f / 30.f);
|
||||
EXPECT_EQ(it.time(30000), 1000.f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/raw_skeleton.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
using ozz::animation::offline::RawSkeleton;
|
||||
|
||||
TEST(Empty, RawSkeletonSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
|
||||
RawSkeleton o_skeleton;
|
||||
o << o_skeleton;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
RawSkeleton i_skeleton;
|
||||
i >> i_skeleton;
|
||||
|
||||
EXPECT_EQ(o_skeleton.num_joints(), i_skeleton.num_joints());
|
||||
}
|
||||
|
||||
TEST(Filled, RawSkeletonSerialize) {
|
||||
/* Builds output skeleton.
|
||||
4 joints
|
||||
|
||||
*
|
||||
|
|
||||
root
|
||||
/ \
|
||||
j0 j1
|
||||
|
|
||||
j2
|
||||
*/
|
||||
|
||||
RawSkeleton o_skeleton;
|
||||
o_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = o_skeleton.roots[0];
|
||||
root.name = "root";
|
||||
root.transform = ozz::math::Transform::identity();
|
||||
root.children.resize(2);
|
||||
root.children[0].name = "j0";
|
||||
root.children[0].transform = ozz::math::Transform::identity();
|
||||
root.children[0].transform.translation.x = 46.f;
|
||||
root.children[1].name = "j1";
|
||||
root.children[1].transform = ozz::math::Transform::identity();
|
||||
root.children[1].transform.scale.y = 99.f;
|
||||
root.children[0].children.resize(1);
|
||||
root.children[0].children[0].name = "j2";
|
||||
root.children[0].children[0].transform = ozz::math::Transform::identity();
|
||||
root.children[0].children[0].transform.rotation =
|
||||
ozz::math::Quaternion(0.f, 0.f, 1.f, 0.f);
|
||||
|
||||
EXPECT_TRUE(o_skeleton.Validate());
|
||||
EXPECT_EQ(o_skeleton.num_joints(), 4);
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << o_skeleton;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
RawSkeleton i_skeleton;
|
||||
i >> i_skeleton;
|
||||
|
||||
EXPECT_TRUE(i_skeleton.Validate());
|
||||
ASSERT_EQ(o_skeleton.num_joints(), i_skeleton.num_joints());
|
||||
|
||||
// Compares skeletons joint's name.
|
||||
EXPECT_STREQ(o_skeleton.roots[0].name.c_str(),
|
||||
i_skeleton.roots[0].name.c_str());
|
||||
EXPECT_STREQ(o_skeleton.roots[0].children[0].name.c_str(),
|
||||
i_skeleton.roots[0].children[0].name.c_str());
|
||||
EXPECT_STREQ(o_skeleton.roots[0].children[0].children[0].name.c_str(),
|
||||
i_skeleton.roots[0].children[0].children[0].name.c_str());
|
||||
EXPECT_STREQ(o_skeleton.roots[0].children[1].name.c_str(),
|
||||
i_skeleton.roots[0].children[1].name.c_str());
|
||||
|
||||
// Compares skeletons joint's transform.
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].transform.translation,
|
||||
i_skeleton.roots[0].transform.translation, 0.f));
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].transform.rotation,
|
||||
i_skeleton.roots[0].transform.rotation, 0.f));
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].transform.scale,
|
||||
i_skeleton.roots[0].transform.scale, 0.f));
|
||||
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].children[0].transform.translation,
|
||||
i_skeleton.roots[0].children[0].transform.translation,
|
||||
0.f));
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].children[0].transform.rotation,
|
||||
i_skeleton.roots[0].children[0].transform.rotation,
|
||||
0.f));
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].children[0].transform.scale,
|
||||
i_skeleton.roots[0].children[0].transform.scale, 0.f));
|
||||
|
||||
EXPECT_TRUE(Compare(
|
||||
o_skeleton.roots[0].children[0].children[0].transform.translation,
|
||||
i_skeleton.roots[0].children[0].children[0].transform.translation,
|
||||
0.f));
|
||||
EXPECT_TRUE(Compare(
|
||||
o_skeleton.roots[0].children[0].children[0].transform.rotation,
|
||||
i_skeleton.roots[0].children[0].children[0].transform.rotation, 0.f));
|
||||
EXPECT_TRUE(Compare(
|
||||
o_skeleton.roots[0].children[0].children[0].transform.scale,
|
||||
i_skeleton.roots[0].children[0].children[0].transform.scale, 0.f));
|
||||
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].children[1].transform.translation,
|
||||
i_skeleton.roots[0].children[1].transform.translation,
|
||||
0.f));
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].children[1].transform.rotation,
|
||||
i_skeleton.roots[0].children[1].transform.rotation,
|
||||
0.f));
|
||||
EXPECT_TRUE(Compare(o_skeleton.roots[0].children[1].transform.scale,
|
||||
i_skeleton.roots[0].children[1].transform.scale, 0.f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlreadyInitialized, RawSkeletonSerialize) {
|
||||
RawSkeleton o_skeleton;
|
||||
o_skeleton.roots.resize(1);
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream);
|
||||
o << o_skeleton;
|
||||
|
||||
// Streams out a second time.
|
||||
o_skeleton.roots.resize(2);
|
||||
o << o_skeleton;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
RawSkeleton i_skeleton;
|
||||
i >> i_skeleton;
|
||||
ASSERT_EQ(i_skeleton.num_joints(), 1);
|
||||
|
||||
// A second time
|
||||
i >> i_skeleton;
|
||||
ASSERT_EQ(i_skeleton.num_joints(), 2);
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/raw_skeleton.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
#include "ozz/base/log.h"
|
||||
#include "ozz/options/options.h"
|
||||
|
||||
OZZ_OPTIONS_DECLARE_STRING(file, "Specifies input file", "", true)
|
||||
OZZ_OPTIONS_DECLARE_INT(joints, "Number of joints", 0, true)
|
||||
OZZ_OPTIONS_DECLARE_STRING(root_name, "Name of the root joint", "", true)
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
// Parses arguments.
|
||||
testing::InitGoogleTest(&_argc, _argv);
|
||||
ozz::options::ParseResult parse_result = ozz::options::ParseCommandLine(
|
||||
_argc, _argv, "1.0",
|
||||
"Test RawSkeleton archive versioning retrocompatibility");
|
||||
if (parse_result != ozz::options::kSuccess) {
|
||||
return parse_result == ozz::options::kExitSuccess ? EXIT_SUCCESS
|
||||
: EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
TEST(Versioning, RawSkeletonSerialize) {
|
||||
// Open the file.
|
||||
const char* filename = OPTIONS_file;
|
||||
ozz::io::File file(filename, "rb");
|
||||
ASSERT_TRUE(file.opened());
|
||||
|
||||
// Open archive and test object tag.
|
||||
ozz::io::IArchive archive(&file);
|
||||
ASSERT_TRUE(archive.TestTag<ozz::animation::offline::RawSkeleton>());
|
||||
|
||||
// Read the object.
|
||||
ozz::animation::offline::RawSkeleton skeleton;
|
||||
archive >> skeleton;
|
||||
|
||||
// More testing
|
||||
EXPECT_EQ(skeleton.num_joints(), OPTIONS_joints);
|
||||
if (skeleton.num_joints()) {
|
||||
EXPECT_STREQ(skeleton.roots[0].name.c_str(), OPTIONS_root_name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/raw_track.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::animation::offline::RawFloatTrack;
|
||||
using ozz::animation::offline::RawFloat2Track;
|
||||
using ozz::animation::offline::RawFloat3Track;
|
||||
using ozz::animation::offline::RawFloat4Track;
|
||||
using ozz::animation::offline::RawQuaternionTrack;
|
||||
using ozz::animation::offline::RawTrackInterpolation;
|
||||
|
||||
TEST(Empty, RawTrackSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
|
||||
RawFloatTrack o_track;
|
||||
o << o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
RawFloatTrack i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_EQ(o_track.keyframes.size(), i_track.keyframes.size());
|
||||
EXPECT_STREQ(o_track.name.c_str(), i_track.name.c_str());
|
||||
}
|
||||
|
||||
TEST(Filled, RawAnimationSerialize) {
|
||||
RawFloatTrack o_track;
|
||||
o_track.name = "test track";
|
||||
|
||||
const RawFloatTrack::Keyframe first_key = {RawTrackInterpolation::kLinear,
|
||||
.5f, 46.f};
|
||||
o_track.keyframes.push_back(first_key);
|
||||
const RawFloatTrack::Keyframe second_key = {RawTrackInterpolation::kLinear,
|
||||
.7f, 0.f};
|
||||
o_track.keyframes.push_back(second_key);
|
||||
|
||||
EXPECT_TRUE(o_track.Validate());
|
||||
EXPECT_EQ(o_track.keyframes.size(), 2u);
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive ia(&stream);
|
||||
|
||||
RawFloatTrack i_track;
|
||||
ia >> i_track;
|
||||
|
||||
EXPECT_TRUE(i_track.Validate());
|
||||
ASSERT_EQ(o_track.keyframes.size(), i_track.keyframes.size());
|
||||
EXPECT_STREQ(o_track.name.c_str(), i_track.name.c_str());
|
||||
|
||||
for (size_t i = 0; i < o_track.keyframes.size(); ++i) {
|
||||
const RawFloatTrack::Keyframe& o_key = o_track.keyframes[i];
|
||||
const RawFloatTrack::Keyframe& i_key = i_track.keyframes[i];
|
||||
|
||||
EXPECT_EQ(o_key.interpolation, i_key.interpolation);
|
||||
EXPECT_FLOAT_EQ(o_key.ratio, i_key.ratio);
|
||||
EXPECT_EQ(o_key.value, i_key.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlreadyInitialized, RawAnimationSerialize) {
|
||||
RawFloatTrack o_track;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream);
|
||||
o_track.name = "test track";
|
||||
o << o_track;
|
||||
|
||||
// Streams out a second ratio.
|
||||
o_track.keyframes.resize(2);
|
||||
o_track.name = "test track 2";
|
||||
o << o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
RawFloatTrack i_track;
|
||||
i >> i_track;
|
||||
ASSERT_EQ(i_track.keyframes.size(), 0u);
|
||||
|
||||
// A second ratio
|
||||
i >> i_track;
|
||||
ASSERT_EQ(i_track.keyframes.size(), 2u);
|
||||
EXPECT_STREQ(o_track.name.c_str(), i_track.name.c_str());
|
||||
}
|
||||
|
||||
TEST(Float2, RawAnimationSerialize) {
|
||||
RawFloat2Track o_track;
|
||||
o_track.name = "test track";
|
||||
|
||||
const RawFloat2Track::Keyframe first_key = {
|
||||
RawTrackInterpolation::kLinear, .5f, ozz::math::Float2(46.f, 99.f)};
|
||||
o_track.keyframes.push_back(first_key);
|
||||
const RawFloat2Track::Keyframe second_key = {
|
||||
RawTrackInterpolation::kLinear, .7f, ozz::math::Float2(16.f, 93.f)};
|
||||
o_track.keyframes.push_back(second_key);
|
||||
|
||||
EXPECT_TRUE(o_track.Validate());
|
||||
EXPECT_EQ(o_track.keyframes.size(), 2u);
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive ia(&stream);
|
||||
|
||||
RawFloat2Track i_track;
|
||||
ia >> i_track;
|
||||
|
||||
EXPECT_TRUE(i_track.Validate());
|
||||
ASSERT_EQ(o_track.keyframes.size(), i_track.keyframes.size());
|
||||
EXPECT_STREQ(o_track.name.c_str(), i_track.name.c_str());
|
||||
|
||||
for (size_t i = 0; i < o_track.keyframes.size(); ++i) {
|
||||
const RawFloat2Track::Keyframe& o_key = o_track.keyframes[i];
|
||||
const RawFloat2Track::Keyframe& i_key = i_track.keyframes[i];
|
||||
|
||||
EXPECT_EQ(o_key.interpolation, i_key.interpolation);
|
||||
EXPECT_FLOAT_EQ(o_key.ratio, i_key.ratio);
|
||||
EXPECT_EQ(o_key.value, i_key.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Float3, RawAnimationSerialize) {
|
||||
RawFloat3Track o_track;
|
||||
|
||||
const RawFloat3Track::Keyframe first_key = {
|
||||
RawTrackInterpolation::kLinear, .5f, ozz::math::Float3(46.f, 99.f, 25.f)};
|
||||
o_track.keyframes.push_back(first_key);
|
||||
const RawFloat3Track::Keyframe second_key = {
|
||||
RawTrackInterpolation::kLinear, .7f, ozz::math::Float3(16.f, 93.f, 4.f)};
|
||||
o_track.keyframes.push_back(second_key);
|
||||
|
||||
EXPECT_TRUE(o_track.Validate());
|
||||
EXPECT_EQ(o_track.keyframes.size(), 2u);
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive ia(&stream);
|
||||
|
||||
RawFloat3Track i_track;
|
||||
ia >> i_track;
|
||||
|
||||
EXPECT_TRUE(i_track.Validate());
|
||||
ASSERT_EQ(o_track.keyframes.size(), i_track.keyframes.size());
|
||||
|
||||
for (size_t i = 0; i < o_track.keyframes.size(); ++i) {
|
||||
const RawFloat3Track::Keyframe& o_key = o_track.keyframes[i];
|
||||
const RawFloat3Track::Keyframe& i_key = i_track.keyframes[i];
|
||||
|
||||
EXPECT_EQ(o_key.interpolation, i_key.interpolation);
|
||||
EXPECT_FLOAT_EQ(o_key.ratio, i_key.ratio);
|
||||
EXPECT_EQ(o_key.value, i_key.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Float4, RawAnimationSerialize) {
|
||||
RawFloat4Track o_track;
|
||||
|
||||
const RawFloat4Track::Keyframe first_key = {
|
||||
RawTrackInterpolation::kLinear, .5f,
|
||||
ozz::math::Float4(46.f, 99.f, 25.f, 5.f)};
|
||||
o_track.keyframes.push_back(first_key);
|
||||
const RawFloat4Track::Keyframe second_key = {
|
||||
RawTrackInterpolation::kLinear, .7f,
|
||||
ozz::math::Float4(16.f, 93.f, 4.f, 46.f)};
|
||||
o_track.keyframes.push_back(second_key);
|
||||
|
||||
EXPECT_TRUE(o_track.Validate());
|
||||
EXPECT_EQ(o_track.keyframes.size(), 2u);
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive ia(&stream);
|
||||
|
||||
RawFloat4Track i_track;
|
||||
ia >> i_track;
|
||||
|
||||
EXPECT_TRUE(i_track.Validate());
|
||||
ASSERT_EQ(o_track.keyframes.size(), i_track.keyframes.size());
|
||||
|
||||
for (size_t i = 0; i < o_track.keyframes.size(); ++i) {
|
||||
const RawFloat4Track::Keyframe& o_key = o_track.keyframes[i];
|
||||
const RawFloat4Track::Keyframe& i_key = i_track.keyframes[i];
|
||||
|
||||
EXPECT_EQ(o_key.interpolation, i_key.interpolation);
|
||||
EXPECT_FLOAT_EQ(o_key.ratio, i_key.ratio);
|
||||
EXPECT_EQ(o_key.value, i_key.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Quaternion, RawAnimationSerialize) {
|
||||
RawQuaternionTrack o_track;
|
||||
|
||||
const RawQuaternionTrack::Keyframe first_key = {
|
||||
RawTrackInterpolation::kLinear, .5f,
|
||||
ozz::math::Quaternion(0.f, .70710677f, 0.f, .70710677f)};
|
||||
o_track.keyframes.push_back(first_key);
|
||||
const RawQuaternionTrack::Keyframe second_key = {
|
||||
RawTrackInterpolation::kLinear, .7f,
|
||||
ozz::math::Quaternion(.6172133f, .1543033f, 0.f, .7715167f)};
|
||||
o_track.keyframes.push_back(second_key);
|
||||
|
||||
EXPECT_TRUE(o_track.Validate());
|
||||
EXPECT_EQ(o_track.keyframes.size(), 2u);
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive ia(&stream);
|
||||
|
||||
RawQuaternionTrack i_track;
|
||||
ia >> i_track;
|
||||
|
||||
EXPECT_TRUE(i_track.Validate());
|
||||
ASSERT_EQ(o_track.keyframes.size(), i_track.keyframes.size());
|
||||
|
||||
for (size_t i = 0; i < o_track.keyframes.size(); ++i) {
|
||||
const RawQuaternionTrack::Keyframe& o_key = o_track.keyframes[i];
|
||||
const RawQuaternionTrack::Keyframe& i_key = i_track.keyframes[i];
|
||||
|
||||
EXPECT_EQ(o_key.interpolation, i_key.interpolation);
|
||||
EXPECT_FLOAT_EQ(o_key.ratio, i_key.ratio);
|
||||
EXPECT_EQ(o_key.value, i_key.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,709 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/raw_skeleton.h"
|
||||
#include "ozz/animation/offline/skeleton_builder.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::animation::Skeleton;
|
||||
using ozz::animation::offline::RawSkeleton;
|
||||
using ozz::animation::offline::SkeletonBuilder;
|
||||
|
||||
TEST(Error, SkeletonBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
// The default raw skeleton is valid. It has no joint.
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 0);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Tester object that ensure order (depth-first) of joints iteration.
|
||||
class RawSkeletonIterateDFTester {
|
||||
public:
|
||||
RawSkeletonIterateDFTester() : num_joint_(0) {}
|
||||
void operator()(const RawSkeleton::Joint& _current,
|
||||
const RawSkeleton::Joint* _parent) {
|
||||
switch (num_joint_) {
|
||||
case 0: {
|
||||
EXPECT_TRUE(_current.name == "root" && _parent == nullptr);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
EXPECT_TRUE(_current.name == "j0" && _parent->name == "root");
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
EXPECT_TRUE(_current.name == "j1" && _parent->name == "root");
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
EXPECT_TRUE(_current.name == "j2" && _parent->name == "j1");
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
EXPECT_TRUE(_current.name == "j3" && _parent->name == "j1");
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
EXPECT_TRUE(_current.name == "j4" && _parent->name == "root");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
EXPECT_TRUE(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
++num_joint_;
|
||||
}
|
||||
|
||||
private:
|
||||
int num_joint_;
|
||||
};
|
||||
|
||||
// Tester object that ensure order (breadth-first) of joints iteration.
|
||||
class RawSkeletonIterateBFTester {
|
||||
public:
|
||||
RawSkeletonIterateBFTester() : num_joint_(0) {}
|
||||
void operator()(const RawSkeleton::Joint& _current,
|
||||
const RawSkeleton::Joint* _parent) {
|
||||
switch (num_joint_) {
|
||||
case 0: {
|
||||
EXPECT_TRUE(_current.name == "root" && _parent == nullptr);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
EXPECT_TRUE(_current.name == "j0" && _parent->name == "root");
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
EXPECT_TRUE(_current.name == "j1" && _parent->name == "root");
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
EXPECT_TRUE(_current.name == "j4" && _parent->name == "root");
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
EXPECT_TRUE(_current.name == "j2" && _parent->name == "j1");
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
EXPECT_TRUE(_current.name == "j3" && _parent->name == "j1");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
EXPECT_TRUE(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
++num_joint_;
|
||||
}
|
||||
|
||||
private:
|
||||
int num_joint_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(Iterate, SkeletonBuilder) {
|
||||
/*
|
||||
5 joints
|
||||
|
||||
*
|
||||
|
|
||||
root
|
||||
/ | \
|
||||
j0 j1 j4
|
||||
/ \
|
||||
j2 j3
|
||||
*/
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "root";
|
||||
|
||||
root.children.resize(3);
|
||||
root.children[0].name = "j0";
|
||||
root.children[1].name = "j1";
|
||||
root.children[2].name = "j4";
|
||||
|
||||
root.children[1].children.resize(2);
|
||||
root.children[1].children[0].name = "j2";
|
||||
root.children[1].children[1].name = "j3";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 6);
|
||||
|
||||
IterateJointsDF(raw_skeleton, RawSkeletonIterateDFTester());
|
||||
IterateJointsBF(raw_skeleton, RawSkeletonIterateBFTester());
|
||||
}
|
||||
|
||||
TEST(Build, SkeletonBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
// 1 joint: the root.
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "root";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 1);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 1);
|
||||
EXPECT_EQ(skeleton->joint_parents()[0], Skeleton::kNoParent);
|
||||
}
|
||||
|
||||
/*
|
||||
2 joints
|
||||
|
||||
*
|
||||
|
|
||||
j0
|
||||
|
|
||||
j1
|
||||
*/
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "j0";
|
||||
|
||||
root.children.resize(1);
|
||||
root.children[0].name = "j1";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 2);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 2);
|
||||
for (int i = 0; i < skeleton->num_joints(); ++i) {
|
||||
const int parent_index = skeleton->joint_parents()[i];
|
||||
if (std::strcmp(skeleton->joint_names()[i], "j0") == 0) {
|
||||
EXPECT_EQ(parent_index, Skeleton::kNoParent);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j1") == 0) {
|
||||
EXPECT_TRUE(std::strcmp(skeleton->joint_names()[parent_index], "j0") ==
|
||||
0);
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
3 joints
|
||||
|
||||
*
|
||||
|
|
||||
j0
|
||||
/ \
|
||||
j1 j2
|
||||
*/
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "j0";
|
||||
|
||||
root.children.resize(2);
|
||||
root.children[0].name = "j1";
|
||||
root.children[1].name = "j2";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 3);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 3);
|
||||
for (int i = 0; i < skeleton->num_joints(); ++i) {
|
||||
const int parent_index = skeleton->joint_parents()[i];
|
||||
if (std::strcmp(skeleton->joint_names()[i], "j0") == 0) {
|
||||
EXPECT_EQ(parent_index, Skeleton::kNoParent);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j1") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j2") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
4 joints
|
||||
|
||||
*
|
||||
|
|
||||
j0
|
||||
/ \
|
||||
j1 j3
|
||||
|
|
||||
j2
|
||||
*/
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "j0";
|
||||
|
||||
root.children.resize(2);
|
||||
root.children[0].name = "j1";
|
||||
root.children[1].name = "j3";
|
||||
|
||||
root.children[0].children.resize(1);
|
||||
root.children[0].children[0].name = "j2";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 4);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 4);
|
||||
for (int i = 0; i < skeleton->num_joints(); ++i) {
|
||||
const int parent_index = skeleton->joint_parents()[i];
|
||||
if (std::strcmp(skeleton->joint_names()[i], "j0") == 0) {
|
||||
EXPECT_EQ(parent_index, Skeleton::kNoParent);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j1") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j2") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j1");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j3") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
4 joints
|
||||
|
||||
*
|
||||
|
|
||||
j0
|
||||
/ \
|
||||
j1 j2
|
||||
|
|
||||
j3
|
||||
*/
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "j0";
|
||||
|
||||
root.children.resize(2);
|
||||
root.children[0].name = "j1";
|
||||
root.children[1].name = "j2";
|
||||
|
||||
root.children[1].children.resize(1);
|
||||
root.children[1].children[0].name = "j3";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 4);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 4);
|
||||
for (int i = 0; i < skeleton->num_joints(); ++i) {
|
||||
const int parent_index = skeleton->joint_parents()[i];
|
||||
if (std::strcmp(skeleton->joint_names()[i], "j0") == 0) {
|
||||
EXPECT_EQ(parent_index, Skeleton::kNoParent);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j1") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j2") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j3") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j2");
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
5 joints
|
||||
|
||||
*
|
||||
|
|
||||
j0
|
||||
/ \
|
||||
j1 j2
|
||||
/ \
|
||||
j3 j4
|
||||
*/
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "j0";
|
||||
|
||||
root.children.resize(2);
|
||||
root.children[0].name = "j1";
|
||||
root.children[1].name = "j2";
|
||||
|
||||
root.children[1].children.resize(2);
|
||||
root.children[1].children[0].name = "j3";
|
||||
root.children[1].children[1].name = "j4";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 5);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 5);
|
||||
for (int i = 0; i < skeleton->num_joints(); ++i) {
|
||||
const int parent_index = skeleton->joint_parents()[i];
|
||||
if (std::strcmp(skeleton->joint_names()[i], "j0") == 0) {
|
||||
EXPECT_EQ(parent_index, Skeleton::kNoParent);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j1") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j2") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j3") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j2");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j4") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j2");
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
6 joints
|
||||
|
||||
*
|
||||
|
|
||||
j0
|
||||
/ \
|
||||
j1 j3
|
||||
| / \
|
||||
j2 j4 j5
|
||||
*/
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "j0";
|
||||
|
||||
root.children.resize(2);
|
||||
root.children[0].name = "j1";
|
||||
root.children[1].name = "j3";
|
||||
|
||||
root.children[0].children.resize(1);
|
||||
root.children[0].children[0].name = "j2";
|
||||
|
||||
root.children[1].children.resize(2);
|
||||
root.children[1].children[0].name = "j4";
|
||||
root.children[1].children[1].name = "j5";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 6);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 6);
|
||||
for (int i = 0; i < skeleton->num_joints(); ++i) {
|
||||
const int parent_index = skeleton->joint_parents()[i];
|
||||
if (std::strcmp(skeleton->joint_names()[i], "j0") == 0) {
|
||||
EXPECT_EQ(parent_index, Skeleton::kNoParent);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j1") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j2") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j1");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j3") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j4") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j3");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j5") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j3");
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Skeleton joins should be sorted "per parent" and maintain original
|
||||
// children joint order.
|
||||
EXPECT_EQ(skeleton->joint_parents()[0], Skeleton::kNoParent);
|
||||
EXPECT_STREQ(skeleton->joint_names()[0], "j0");
|
||||
EXPECT_EQ(skeleton->joint_parents()[1], 0);
|
||||
EXPECT_STREQ(skeleton->joint_names()[1], "j1");
|
||||
EXPECT_EQ(skeleton->joint_parents()[2], 1);
|
||||
EXPECT_STREQ(skeleton->joint_names()[2], "j2");
|
||||
EXPECT_EQ(skeleton->joint_parents()[3], 0);
|
||||
EXPECT_STREQ(skeleton->joint_names()[3], "j3");
|
||||
EXPECT_EQ(skeleton->joint_parents()[4], 3);
|
||||
EXPECT_STREQ(skeleton->joint_names()[4], "j4");
|
||||
EXPECT_EQ(skeleton->joint_parents()[5], 3);
|
||||
EXPECT_STREQ(skeleton->joint_names()[5], "j5");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(JointOrder, SkeletonBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
/*
|
||||
7 joints
|
||||
|
||||
*
|
||||
|
|
||||
j0
|
||||
/ | \
|
||||
j1 j3 j7
|
||||
| / \
|
||||
j2 j4 j5
|
||||
|
|
||||
j6
|
||||
*/
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "j0";
|
||||
|
||||
root.children.resize(3);
|
||||
root.children[0].name = "j1";
|
||||
root.children[1].name = "j3";
|
||||
root.children[2].name = "j7";
|
||||
|
||||
root.children[0].children.resize(1);
|
||||
root.children[0].children[0].name = "j2";
|
||||
|
||||
root.children[1].children.resize(2);
|
||||
root.children[1].children[0].name = "j4";
|
||||
root.children[1].children[1].name = "j5";
|
||||
|
||||
root.children[1].children[1].children.resize(1);
|
||||
root.children[1].children[1].children[0].name = "j6";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 8);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 8);
|
||||
|
||||
// Skeleton joints should be sorted "per parent" and maintain original
|
||||
// children joint order.
|
||||
EXPECT_EQ(skeleton->joint_parents()[0], Skeleton::kNoParent);
|
||||
EXPECT_STREQ(skeleton->joint_names()[0], "j0");
|
||||
EXPECT_EQ(skeleton->joint_parents()[1], 0);
|
||||
EXPECT_STREQ(skeleton->joint_names()[1], "j1");
|
||||
EXPECT_EQ(skeleton->joint_parents()[3], 0);
|
||||
EXPECT_STREQ(skeleton->joint_names()[3], "j3");
|
||||
EXPECT_EQ(skeleton->joint_parents()[7], 0);
|
||||
EXPECT_STREQ(skeleton->joint_names()[7], "j7");
|
||||
EXPECT_EQ(skeleton->joint_parents()[2], 1);
|
||||
EXPECT_STREQ(skeleton->joint_names()[2], "j2");
|
||||
EXPECT_EQ(skeleton->joint_parents()[4], 3);
|
||||
EXPECT_STREQ(skeleton->joint_names()[4], "j4");
|
||||
EXPECT_EQ(skeleton->joint_parents()[5], 3);
|
||||
EXPECT_STREQ(skeleton->joint_names()[5], "j5");
|
||||
EXPECT_EQ(skeleton->joint_parents()[6], 5);
|
||||
EXPECT_STREQ(skeleton->joint_names()[6], "j6");
|
||||
}
|
||||
|
||||
TEST(MultiRoots, SkeletonBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
/*
|
||||
6 joints (2 roots)
|
||||
*
|
||||
/ \
|
||||
j0 j2
|
||||
| | \
|
||||
j1 j3 j5
|
||||
|
|
||||
j4
|
||||
*/
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(2);
|
||||
|
||||
raw_skeleton.roots[0].name = "j0";
|
||||
raw_skeleton.roots[0].children.resize(1);
|
||||
raw_skeleton.roots[0].children[0].name = "j1";
|
||||
|
||||
raw_skeleton.roots[1].name = "j2";
|
||||
raw_skeleton.roots[1].children.resize(2);
|
||||
raw_skeleton.roots[1].children[0].name = "j3";
|
||||
raw_skeleton.roots[1].children[1].name = "j5";
|
||||
|
||||
raw_skeleton.roots[1].children[0].children.resize(1);
|
||||
raw_skeleton.roots[1].children[0].children[0].name = "j4";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 6);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 6);
|
||||
for (int i = 0; i < skeleton->num_joints(); i++) {
|
||||
const int parent_index = skeleton->joint_parents()[i];
|
||||
if (std::strcmp(skeleton->joint_names()[i], "j0") == 0) {
|
||||
EXPECT_EQ(parent_index, Skeleton::kNoParent);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j1") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j0");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j2") == 0) {
|
||||
EXPECT_EQ(parent_index, Skeleton::kNoParent);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j3") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j2");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j4") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j3");
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j5") == 0) {
|
||||
EXPECT_STREQ(skeleton->joint_names()[parent_index], "j2");
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BindPose, SkeletonBuilder) {
|
||||
using ozz::math::Float3;
|
||||
using ozz::math::Float4;
|
||||
using ozz::math::Quaternion;
|
||||
using ozz::math::Transform;
|
||||
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
/*
|
||||
3 joints
|
||||
|
||||
*
|
||||
|
|
||||
j0
|
||||
/ \
|
||||
j1 j2
|
||||
*/
|
||||
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "j0";
|
||||
root.transform = Transform::identity();
|
||||
root.transform.translation = Float3(1.f, 2.f, 3.f);
|
||||
root.transform.rotation = Quaternion(1.f, 0.f, 0.f, 0.f);
|
||||
|
||||
root.children.resize(2);
|
||||
root.children[0].name = "j1";
|
||||
root.children[0].transform = Transform::identity();
|
||||
root.children[0].transform.rotation = Quaternion(0.f, 1.f, 0.f, 0.f);
|
||||
root.children[0].transform.translation = Float3(4.f, 5.f, 6.f);
|
||||
root.children[1].name = "j2";
|
||||
root.children[1].transform = Transform::identity();
|
||||
root.children[1].transform.translation = Float3(7.f, 8.f, 9.f);
|
||||
root.children[1].transform.scale = Float3(-27.f, 46.f, 9.f);
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 3);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
|
||||
// Convert bind pose back to aos.
|
||||
ozz::math::SimdFloat4 translations[4];
|
||||
ozz::math::SimdFloat4 scales[4];
|
||||
ozz::math::SimdFloat4 rotations[4];
|
||||
const ozz::math::SoaTransform& bind_pose = skeleton->joint_bind_poses()[0];
|
||||
ozz::math::Transpose3x4(&bind_pose.translation.x, translations);
|
||||
ozz::math::Transpose4x4(&bind_pose.rotation.x, rotations);
|
||||
ozz::math::Transpose3x4(&bind_pose.scale.x, scales);
|
||||
|
||||
for (int i = 0; i < skeleton->num_joints(); ++i) {
|
||||
if (std::strcmp(skeleton->joint_names()[i], "j0") == 0) {
|
||||
EXPECT_SIMDFLOAT_EQ(translations[i], 1.f, 2.f, 3.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotations[i], 1.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scales[i], 1.f, 1.f, 1.f, 0.f);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j1") == 0) {
|
||||
EXPECT_SIMDFLOAT_EQ(translations[i], 4.f, 5.f, 6.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotations[i], 0.f, 1.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scales[i], 1.f, 1.f, 1.f, 0.f);
|
||||
} else if (std::strcmp(skeleton->joint_names()[i], "j2") == 0) {
|
||||
EXPECT_SIMDFLOAT_EQ(translations[i], 7.f, 8.f, 9.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotations[i], 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scales[i], -27.f, 46.f, 9.f, 0.f);
|
||||
} else {
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Unused joint from the SoA structure must be properly initialized
|
||||
EXPECT_SIMDFLOAT_EQ(translations[3], 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotations[3], 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scales[3], 1.f, 1.f, 1.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(MaxJoints, SkeletonBuilder) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
{ // Inside the domain.
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(Skeleton::kMaxJoints);
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), Skeleton::kMaxJoints);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
EXPECT_TRUE(skeleton);
|
||||
}
|
||||
|
||||
{ // Outside of the domain.
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(Skeleton::kMaxJoints + 1);
|
||||
|
||||
EXPECT_FALSE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), Skeleton::kMaxJoints + 1);
|
||||
|
||||
EXPECT_TRUE(!builder(raw_skeleton));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
if(NOT ozz_build_tools)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_executable(test2ozz
|
||||
test2ozz.cc)
|
||||
target_link_libraries(test2ozz
|
||||
ozz_animation_tools
|
||||
ozz_options)
|
||||
|
||||
set_target_properties(test2ozz
|
||||
PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
|
||||
# Creates content test files
|
||||
file(WRITE "${ozz_temp_directory}/bad.content" "bad content")
|
||||
file(WRITE "${ozz_temp_directory}/good.content0" "good content 0")
|
||||
file(WRITE "${ozz_temp_directory}/good.content1" "good content 1")
|
||||
file(WRITE "${ozz_temp_directory}/good.content2" "good content 2")
|
||||
file(WRITE "${ozz_temp_directory}/good.content_renamed" "good content renamed")
|
||||
file(WRITE "${ozz_temp_directory}/non_unique_names.content" "good content but not unique joint names")
|
||||
|
||||
# Creates config test files.
|
||||
file(WRITE "${ozz_temp_directory}/valid_config.json" "{\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_valid_config.ozz\"}]}")
|
||||
file(WRITE "${ozz_temp_directory}/no_output_config.json" "{\"skeleton\":{\"import\":{\"enable\":false}},\"animations\":[]}")
|
||||
file(WRITE "${ozz_temp_directory}/invalid_config.json" "invalid json content")
|
||||
|
||||
# Run test2ozz generic failing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME test2ozz_no_arg COMMAND test2ozz)
|
||||
set_tests_properties(test2ozz_no_arg PROPERTIES PASS_REGULAR_EXPRESSION "Required option \"file\" is not specified.")
|
||||
|
||||
add_test(NAME test2ozz_bad_argument COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--bad")
|
||||
set_tests_properties(test2ozz_bad_argument PROPERTIES PASS_REGULAR_EXPRESSION "Invalid command line argument:\"--bad\".")
|
||||
|
||||
add_test(NAME test2ozz_bad_endian COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--endian=fat")
|
||||
set_tests_properties(test2ozz_bad_endian PROPERTIES PASS_REGULAR_EXPRESSION "Invalid endianness option \"fat\".")
|
||||
|
||||
add_test(NAME test2ozz_bad_log COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--log_level=loud")
|
||||
set_tests_properties(test2ozz_bad_log PROPERTIES PASS_REGULAR_EXPRESSION "Invalid log level option \"loud\".")
|
||||
|
||||
add_test(NAME test2ozz_bad_content COMMAND test2ozz "--file=${ozz_temp_directory}/bad.content")
|
||||
set_tests_properties(test2ozz_bad_content PROPERTIES PASS_REGULAR_EXPRESSION "Failed to import file \"${ozz_temp_directory}/bad.content\".")
|
||||
|
||||
add_test(NAME test2ozz_unexisting_test COMMAND test2ozz "--file=${ozz_temp_directory}/file_doesn_t_exist")
|
||||
set_tests_properties(test2ozz_unexisting_test PROPERTIES PASS_REGULAR_EXPRESSION "File \"${ozz_temp_directory}/file_doesn_t_exist\" doesn't exist.")
|
||||
|
||||
add_test(NAME test2ozz_exclusive_config COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={}" "--config_file=${ozz_temp_directory}/valid_config.json")
|
||||
set_tests_properties(test2ozz_exclusive_config PROPERTIES PASS_REGULAR_EXPRESSION "--config and --config_file are exclusive options.")
|
||||
|
||||
add_test(NAME test2ozz_unexisting_config_file COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/unexisting_config.json")
|
||||
set_tests_properties(test2ozz_unexisting_config_file PROPERTIES PASS_REGULAR_EXPRESSION "Failed to open config file: \"${ozz_temp_directory}/unexisting_config.json\".")
|
||||
|
||||
add_test(NAME test2ozz_invalid_config_file COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/invalid_config.json")
|
||||
set_tests_properties(test2ozz_invalid_config_file PROPERTIES PASS_REGULAR_EXPRESSION "Error while parsing configuration string")
|
||||
|
||||
add_test(NAME test2ozz_dump_config_bad_file COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_dump_reference=${ozz_temp_directory}/unexisting/config.json")
|
||||
set_tests_properties(test2ozz_dump_config_bad_file PROPERTIES PASS_REGULAR_EXPRESSION "Failed to open config file to dump" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_bad_type COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"animations\":[{\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\",\"sampling_rate\":\"1\"}]}")
|
||||
set_tests_properties(test2ozz_bad_type PROPERTIES PASS_REGULAR_EXPRESSION "Invalid type \"UTF-8 string\" for json member \"root.animations\\\[0\\\].sampling_rate\". \"float\" expected." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_bad_array COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"animations\":{\"sampling_rate\":true}}")
|
||||
set_tests_properties(test2ozz_bad_array PROPERTIES PASS_REGULAR_EXPRESSION "Invalid type \"object\" for json member \"root.animations\". \"array\" expected." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_bad_type_in_array COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"animations\":[{},{\"sampling_rate\":true}]}")
|
||||
set_tests_properties(test2ozz_bad_type_in_array PROPERTIES PASS_REGULAR_EXPRESSION "Invalid type \"boolean\" for json member \"root.animations\\\[1\\\].sampling_rate\". \"float\" expected." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_wrong_config_unexpected_member2 COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"animations\":[{},{\"foo\":true}]}")
|
||||
set_tests_properties(test2ozz_wrong_config_unexpected_member2 PROPERTIES PASS_REGULAR_EXPRESSION "Invalid json member \"root.animations\\\[1\\\].foo\"." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_wrong_optimize COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"animations\":[{\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\",\"optimize\":99}]}")
|
||||
set_tests_properties(test2ozz_wrong_optimize PROPERTIES PASS_REGULAR_EXPRESSION "Invalid type \"integer\" for json member \"root.animations\\\[0\\\].optimize\". \"boolean\" expected." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_wrong_config_unexpected_member1 COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":\"${ozz_temp_directory}/skeleton.ozz\",\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}")
|
||||
set_tests_properties(test2ozz_wrong_config_unexpected_member1 PROPERTIES PASS_REGULAR_EXPRESSION "Invalid json member \"root.filename\"." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_wrong_config_invalid_object COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"animations\":{\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}}")
|
||||
set_tests_properties(test2ozz_wrong_config_invalid_object PROPERTIES PASS_REGULAR_EXPRESSION "Invalid type \"object\" for json member \"root.animations\". \"array\" expected." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_wrong_config_invalid_array COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"animations\":[{\"optimize\":[]}]}")
|
||||
set_tests_properties(test2ozz_wrong_config_invalid_array PROPERTIES PASS_REGULAR_EXPRESSION "Invalid type \"array\" for json member \"root.animations\\\[0\\\].optimize\". \"boolean\" expected." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
# Run test2ozz generic passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME test2ozz_version COMMAND test2ozz "--version")
|
||||
set_tests_properties(test2ozz_version PROPERTIES PASS_REGULAR_EXPRESSION "version 2.0")
|
||||
|
||||
add_test(NAME test2ozz_log_verbose COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/no_output_config.json" "--log_level=verbose")
|
||||
set_tests_properties(test2ozz_log_verbose PROPERTIES PASS_REGULAR_EXPRESSION "Verbose log level activated.")
|
||||
|
||||
add_test(NAME test2ozz_native COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/no_output_config.json" "--endian=native")
|
||||
add_test(NAME test2ozz_little COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/no_output_config.json" "--endian=little" "--log_level=verbose")
|
||||
set_tests_properties(test2ozz_little PROPERTIES PASS_REGULAR_EXPRESSION "Little endian output binary format selected.")
|
||||
add_test(NAME test2ozz_big COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/no_output_config.json" "--endian=big" "--log_level=verbose")
|
||||
set_tests_properties(test2ozz_big PROPERTIES PASS_REGULAR_EXPRESSION "Big endian output binary format selected.")
|
||||
|
||||
add_test(NAME test2ozz_log_config_verbose COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/no_output_config.json" "--log_level=verbose")
|
||||
set_tests_properties(test2ozz_log_config_verbose PROPERTIES PASS_REGULAR_EXPRESSION "// Animations to import.")
|
||||
|
||||
add_test(NAME test2ozz_dump_ref_config COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/no_output_config.json" "--config_dump_reference=${ozz_temp_directory}/reference.json")
|
||||
add_test(NAME test2ozz_dump_ref_config_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/reference.json" "${ozz_temp_directory}/reference_should_exist.json")
|
||||
set_tests_properties(test2ozz_dump_ref_config_output PROPERTIES DEPENDS test2ozz_dump_ref_config)
|
||||
|
||||
file(MAKE_DIRECTORY ${ozz_temp_directory}/ref_config_relative)
|
||||
add_test(NAME test2ozz_load_ref_config COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/reference.json" WORKING_DIRECTORY "${ozz_temp_directory}/ref_config_relative")
|
||||
set_tests_properties(test2ozz_load_ref_config PROPERTIES DEPENDS test2ozz_dump_ref_config)
|
||||
|
||||
file(MAKE_DIRECTORY ${ozz_temp_directory}/ref_config_relative/cp)
|
||||
add_test(NAME test2ozz_load_ref_config_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/ref_config_relative/skeleton.ozz" "${ozz_temp_directory}/ref_config_relative/one.ozz" "${ozz_temp_directory}/ref_config_relative/joint0-property0.ozz" "${ozz_temp_directory}/ref_config_relative/joint0-property1.ozz" "${ozz_temp_directory}/ref_config_relative/joint1-property0.ozz" "${ozz_temp_directory}/ref_config_relative/joint1-property1.ozz" "${ozz_temp_directory}/ref_config_relative/cp/")
|
||||
set_tests_properties(test2ozz_load_ref_config_output PROPERTIES DEPENDS test2ozz_load_ref_config)
|
||||
|
||||
file(MAKE_DIRECTORY ${ozz_temp_directory}/test2ozz_no_config)
|
||||
add_test(NAME test2ozz_no_config COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" WORKING_DIRECTORY "${ozz_temp_directory}/test2ozz_no_config")
|
||||
set_tests_properties(test2ozz_no_config PROPERTIES PASS_REGULAR_EXPRESSION "No configuration provided, using default configuration.")
|
||||
|
||||
file(MAKE_DIRECTORY ${ozz_temp_directory}/test2ozz_no_config/cp)
|
||||
add_test(NAME test2ozz_no_config_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/test2ozz_no_config/skeleton.ozz" "${ozz_temp_directory}/test2ozz_no_config/one.ozz" "${ozz_temp_directory}/test2ozz_no_config/cp/")
|
||||
set_tests_properties(test2ozz_no_config_output PROPERTIES DEPENDS test2ozz_no_config)
|
||||
|
||||
# Run test2ozz skeleton import failing tests
|
||||
#----------------------
|
||||
|
||||
add_test(NAME test2ozz_skel_invalid_filename COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/invalid_path/skel_should_not_exist.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}")
|
||||
set_tests_properties(test2ozz_skel_invalid_filename PROPERTIES PASS_REGULAR_EXPRESSION "Failed to open output file: \"${ozz_temp_directory}/invalid_path/skel_should_not_exist.ozz\".")
|
||||
|
||||
add_test(NAME test2ozz_skel_invalid_filename_raw COMMAND test2ozz "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/invalid_path/skel_should_not_exist.ozz\",\"import\":{\"enable\":true,\"raw\":true}},\"animations\":[]}}")
|
||||
set_tests_properties(test2ozz_skel_invalid_filename_raw PROPERTIES WILL_FAIL true)
|
||||
|
||||
add_test(NAME test2ozz_skel_non_unique_names COMMAND test2ozz "--file=${ozz_temp_directory}/non_unique_names.content" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skel_should_not_exist.ozz\",\"import\":{\"enable\":true}},\"animations\":[]}}")
|
||||
set_tests_properties(test2ozz_skel_non_unique_names PROPERTIES PASS_REGULAR_EXPRESSION "Skeleton contains at least one non-unique joint name \"jointx\", which is not supported.")
|
||||
|
||||
# Run test2ozz skeleton passing tests
|
||||
#----------------------------
|
||||
add_test(NAME test2ozz_skel_simple COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\"},\"animations\":[]}}")
|
||||
add_test(NAME test2ozz_skel_simple_raw COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/raw_skeleton.ozz\",\"import\":{\"raw\":true}},\"animations\":[]}}")
|
||||
add_test(NAME test2ozz_skel_no_import COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skel_should_not_exist.ozz\",\"import\":{\"enable\":false}},\"animations\":[]}}")
|
||||
set_tests_properties(test2ozz_skel_no_import PROPERTIES PASS_REGULAR_EXPRESSION "Skeleton build disabled, import will be skipped")
|
||||
|
||||
add_test(NAME test2ozz_log_hierarchy COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton_${CMAKE_CURRENT_LIST_LINE}.ozz\"},\"animations\":[]}}" "--log_level=verbose")
|
||||
set_tests_properties(test2ozz_log_hierarchy PROPERTIES PASS_REGULAR_EXPRESSION ".joint0 t")
|
||||
|
||||
# Ensures nothing was outputted.
|
||||
add_test(NAME test2ozz_skel_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/skel_should_not_exist.ozz" "${ozz_temp_directory}/skel_should_not_exist_too.ozz")
|
||||
set_tests_properties(test2ozz_skel_output PROPERTIES WILL_FAIL true)
|
||||
set_tests_properties(test2ozz_skel_output PROPERTIES
|
||||
DEPENDS "test2ozz_skel_no_import
|
||||
test2ozz_skel_non_unique_names
|
||||
test2ozz_skel_invalid_filename
|
||||
test2ozz_skel_invalid_filename_raw")
|
||||
|
||||
# Run test2ozz animation import failing tests
|
||||
#----------------------------
|
||||
add_test(NAME test2ozz_anim_no_animation COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[]}")
|
||||
set_tests_properties(test2ozz_anim_no_animation PROPERTIES PASS_REGULAR_EXPRESSION "Configuration contains no animation import definition, animations import will be skipped." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_no_clip_name COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"clip\":\"\"}]}")
|
||||
set_tests_properties(test2ozz_anim_no_clip_name PROPERTIES PASS_REGULAR_EXPRESSION "No clip name provided. Animation import will be skipped." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_no_animation_output COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"\"}]}")
|
||||
set_tests_properties(test2ozz_anim_no_animation_output PROPERTIES PASS_REGULAR_EXPRESSION "Failed to open output file: \"\"." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_no_anim_test COMMAND test2ozz "--file=${ozz_temp_directory}/good.content0" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_no_anim_test PROPERTIES PASS_REGULAR_EXPRESSION "No animation found." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_bad_skeleton COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/bad.content\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_bad_skeleton PROPERTIES PASS_REGULAR_EXPRESSION "Failed to read input skeleton from binary file" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_unexisting_skeleton COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/unexisting.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_unexisting_skeleton PROPERTIES PASS_REGULAR_EXPRESSION "Failed to open input skeleton ozz binary file: \"${ozz_temp_directory}/unexisting.ozz\"")
|
||||
|
||||
add_test(NAME test2ozz_anim_invalid_filename COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/invalid_path/anim_should_not_exist.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_invalid_filename PROPERTIES PASS_REGULAR_EXPRESSION "Failed to open output file: \"${ozz_temp_directory}/invalid_path/anim_should_not_exist.ozz\"." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_no_match COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"clip\":\"won_t_match\",\"filename\":\"${ozz_temp_directory}/invalid_path/anim_should_not_exist.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_no_match PROPERTIES PASS_REGULAR_EXPRESSION "No matching animation found for \"won_t_match\"." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_additive_wrong_ref COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"additive\":true,\"additive_reference\":\"anim\"}]}")
|
||||
set_tests_properties(test2ozz_anim_additive_wrong_ref PROPERTIES PASS_REGULAR_EXPRESSION "Invalid additive reference pose \"anim\"." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
# Run test2ozz track import failing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME test2ozz_anim_track_bad_joint_name COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint3\",\"property_name\":\"property2\",\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_bad_joint_name PROPERTIES PASS_REGULAR_EXPRESSION "No joint found for track import definition \"joint3\"" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_track_bad_ppt_name COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint2\",\"property_name\":\"propertyx\",\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_bad_ppt_name PROPERTIES PASS_REGULAR_EXPRESSION "No property found for track import definition \"joint2:propertyx\"" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_track_bad_type COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint1\",\"property_name\":\"property2\",\"type\":\"float3\",\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_bad_type PROPERTIES PASS_REGULAR_EXPRESSION "Incompatible type \"float3\" for matching property \"joint1:property2\" of type \"float2\"" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_track_invalid_type COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint1\",\"property_name\":\"property2\",\"type\":\"1\",\"filename\":\"${ozz_temp_directory}/anim_should_not_exist.ozz\"}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_invalid_type PROPERTIES PASS_REGULAR_EXPRESSION "Invalid value \"1\" for import track type property." DEPENDS test2ozz_skel_simple)
|
||||
|
||||
# Ensures nothing was outputted.
|
||||
add_test(NAME test2ozz_anim_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/anim_should_not_exist.ozz" "${ozz_temp_directory}/anim_should_not_exist_too.ozz")
|
||||
set_tests_properties(test2ozz_anim_output PROPERTIES WILL_FAIL true)
|
||||
set_tests_properties(test2ozz_anim_output PROPERTIES
|
||||
DEPENDS "test2ozz_anim_output
|
||||
test2ozz_anim_missing_test
|
||||
test2ozz_anim_bad_test
|
||||
test2ozz_anim_bad_skeleton
|
||||
test2ozz_anim_unexisting_skeleton
|
||||
test2ozz_anim_invalid_filename
|
||||
test2ozz_anim_bad_log_level
|
||||
test2ozz_anim_track_bad_joint_name
|
||||
test2ozz_anim_track_bad_ppt_name
|
||||
test2ozz_anim_track_bad_type
|
||||
test2ozz_anim_track_invalid_type")
|
||||
|
||||
# Run test2ozz animation import passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME test2ozz_anim_simple COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_simple.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_simple PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_simple_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_simple.ozz" "${ozz_temp_directory}/animation_simple_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_simple_output PROPERTIES DEPENDS test2ozz_anim_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_simple_renamed COMMAND test2ozz "--file=${ozz_temp_directory}/good.content_renamed" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/*.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_simple_renamed PROPERTIES PASS_REGULAR_EXPRESSION "in order to be used as a valid filename" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
file(MAKE_DIRECTORY ${ozz_temp_directory}/anim_simple_relative)
|
||||
add_test(NAME test2ozz_anim_simple_relative COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"animation.ozz\"}]}" WORKING_DIRECTORY "${ozz_temp_directory}/anim_simple_relative")
|
||||
set_tests_properties(test2ozz_anim_simple_relative PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_simple_relative_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/anim_simple_relative/animation.ozz" "${ozz_temp_directory}/anim_simple_relative/animation_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_simple_relative_output PROPERTIES DEPENDS test2ozz_anim_simple_relative)
|
||||
|
||||
add_test(NAME test2ozz_anim_simple_config_file COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config_file=${ozz_temp_directory}/valid_config.json")
|
||||
set_tests_properties(test2ozz_anim_simple_config_file PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_optimize COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"optimize\":true}]}")
|
||||
set_tests_properties(test2ozz_anim_optimize PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_optimize_tol COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"optimize\":true,\"optimization_settings\":{\"tolerance\":0.002,\"distance\":0.002}}]}")
|
||||
set_tests_properties(test2ozz_anim_optimize_tol PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_optimize_joints_tol COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"optimize\":true,\"optimization_settings\":{\"override\":[{\"name\":\"joint?\",\"tolerance\":0.002,\"distance\":0.002}]}}]}")
|
||||
set_tests_properties(test2ozz_anim_optimize_joints_tol PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_optimize_joints_tol_verbose COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"optimize\":true,\"optimization_settings\":{\"override\":[{\"name\":\"joint?\",\"tolerance\":0.002,\"distance\":0.002}]}}]}" "--log_level=verbose")
|
||||
set_tests_properties(test2ozz_anim_optimize_joints_tol_verbose PROPERTIES PASS_REGULAR_EXPRESSION "Found joint \"joint2\" matching pattern" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_optimize_joints_not_found_tol COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"optimize\":true,\"optimization_settings\":{\"override\":[{\"name\":\"joint_won_t_find\",\"tolerance\":0.002,\"distance\":0.002}]}}]}")
|
||||
set_tests_properties(test2ozz_anim_optimize_joints_not_found_tol PROPERTIES PASS_REGULAR_EXPRESSION "No joint found for optimization setting" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_optimize_joints_redundant_tol COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"optimize\":true,\"optimization_settings\":{\"override\":[{\"name\":\"joint1\"},{\"name\":\"joint?\"}]}}]}")
|
||||
set_tests_properties(test2ozz_anim_optimize_joints_redundant_tol PROPERTIES PASS_REGULAR_EXPRESSION "Redundant optimization setting for pattern" DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_no_opt COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]},\"optimize\":false}]}")
|
||||
set_tests_properties(test2ozz_anim_no_opt PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_simple_raw COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/raw_animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"raw\":false}]}")
|
||||
set_tests_properties(test2ozz_anim_simple_raw PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_simple_from_raw COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/raw_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_simple_from_raw PROPERTIES DEPENDS test2ozz_skel_simple_raw)
|
||||
|
||||
add_test(NAME test2ozz_anim_simple_raw_from_raw COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/raw_skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"raw\":false}]}")
|
||||
set_tests_properties(test2ozz_anim_simple_raw_from_raw PROPERTIES DEPENDS test2ozz_skel_simple_raw)
|
||||
|
||||
add_test(NAME test2ozz_anim_additive COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"additive\":true}]}")
|
||||
set_tests_properties(test2ozz_anim_additive PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_additive_raw COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"raw\":false,\"additive\":true}]}")
|
||||
set_tests_properties(test2ozz_anim_additive_raw PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_additive_ref_anim COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"additive\":true,\"additive_reference\":\"animation\"}]}")
|
||||
set_tests_properties(test2ozz_anim_additive_ref_anim PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_additive_ref_skel COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"additive\":true,\"additive_reference\":\"skeleton\"}]}")
|
||||
set_tests_properties(test2ozz_anim_additive_ref_skel PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_native COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_native_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}" "--endian=native")
|
||||
set_tests_properties(test2ozz_anim_native PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_little COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_little_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}" "--endian=little")
|
||||
set_tests_properties(test2ozz_anim_little PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_big COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_big_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}" "--endian=big")
|
||||
set_tests_properties(test2ozz_anim_big PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_unmatch_skeleton COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_big_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}" "--endian=big")
|
||||
set_tests_properties(test2ozz_anim_unmatch_skeleton PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_sampling_rate COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"sampling_rate\":10.}]}")
|
||||
set_tests_properties(test2ozz_anim_sampling_rate PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_sampling_rate_int COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"sampling_rate\":1}]}")
|
||||
set_tests_properties(test2ozz_anim_sampling_rate_int PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_sampling_rate_0 COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"sampling_rate\":0}]}")
|
||||
set_tests_properties(test2ozz_anim_sampling_rate_0 PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_sampling_rate_neg COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\",\"sampling_rate\":-1}]}")
|
||||
set_tests_properties(test2ozz_anim_sampling_rate_neg PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_log_verbose COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_${CMAKE_CURRENT_LIST_LINE}.ozz\"}]}" "--log_level=verbose")
|
||||
set_tests_properties(test2ozz_anim_log_verbose PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_single1_wild COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_single1_wild_*.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_single1_wild PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_single1_wild_output1 COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_single1_wild_one.ozz" "${ozz_temp_directory}/animation_single1_wild_one_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_single1_wild_output1 PROPERTIES DEPENDS test2ozz_anim_single1_wild)
|
||||
|
||||
add_test(NAME test2ozz_anim_multi1 COMMAND test2ozz "--file=${ozz_temp_directory}/good.content2" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_multi2_*.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_multi1 PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_multi2_output1 COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_multi2_one.ozz" "${ozz_temp_directory}/animation_multi2_one_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_multi2_output1 PROPERTIES DEPENDS test2ozz_anim_multi1)
|
||||
add_test(NAME test2ozz_anim_multi2_output2 COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_multi2_TWO.ozz" "${ozz_temp_directory}/animation_multi1_TWO_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_multi2_output2 PROPERTIES DEPENDS test2ozz_anim_multi1)
|
||||
|
||||
add_test(NAME test2ozz_anim_multi2_single COMMAND test2ozz "--file=${ozz_temp_directory}/good.content2" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"clip\":\"T?O\",\"filename\":\"${ozz_temp_directory}/animation_multi2_single.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_multi2_single PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_multi2_single_output1 COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_multi2_single.ozz" "${ozz_temp_directory}/animation_multi2_single_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_multi2_single_output1 PROPERTIES DEPENDS test2ozz_anim_multi2_single)
|
||||
|
||||
add_test(NAME test2ozz_anim_multi2_multi COMMAND test2ozz "--file=${ozz_temp_directory}/good.content2" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"clip\":\"one\",\"filename\":\"${ozz_temp_directory}/animation_multi2_multi_one.ozz\"},{\"clip\":\"TWO\",\"filename\":\"${ozz_temp_directory}/animation_multi2_multi_TWO.ozz\"}]}")
|
||||
set_tests_properties(test2ozz_anim_multi2_multi PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_multi2_multi_output1 COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_multi2_multi_one.ozz" "${ozz_temp_directory}/animation_multi2_multi_one_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_multi2_multi_output1 PROPERTIES DEPENDS test2ozz_anim_multi2_multi)
|
||||
add_test(NAME test2ozz_anim_multi2_multi_output2 COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_multi2_multi_TWO.ozz" "${ozz_temp_directory}/animation_multi2_multi_TWO_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_multi2_multi_output2 PROPERTIES DEPENDS test2ozz_anim_multi2_multi)
|
||||
|
||||
# Run test2ozz tracks import passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME test2ozz_anim_track_simple COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_track_simple_*.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint0\",\"property_name\":\"property0\",\"filename\":\"${ozz_temp_directory}/track_simple.ozz\"}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_simple PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_track_simple_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/track_simple.ozz" "${ozz_temp_directory}/track_simple_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_simple_output PROPERTIES DEPENDS test2ozz_anim_track_simple)
|
||||
add_test(NAME test2ozz_anim_track_simple_output_anim COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_track_simple_one.ozz" "${ozz_temp_directory}/animation_track_simple_one_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_simple_output_anim PROPERTIES DEPENDS test2ozz_anim_track_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_track_simple_raw COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_track_simple_raw_*.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint0\",\"property_name\":\"property0\",\"filename\":\"${ozz_temp_directory}/track_simple_raw.ozz\",\"raw\":true}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_simple_raw PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_track_simple_raw_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/track_simple_raw.ozz" "${ozz_temp_directory}/track_simple_raw_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_simple_raw_output PROPERTIES DEPENDS test2ozz_anim_track_simple_raw)
|
||||
add_test(NAME test2ozz_anim_track_simple_raw_output_anim COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_track_simple_raw_one.ozz" "${ozz_temp_directory}/animation_track_simple_raw_one_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_simple_raw_output_anim PROPERTIES DEPENDS test2ozz_anim_track_simple_raw)
|
||||
|
||||
add_test(NAME test2ozz_anim_track_simple_no_opt COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_track_simple_no_opt_*.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint0\",\"property_name\":\"property0\",\"filename\":\"${ozz_temp_directory}/track_simple_no_opt.ozz\",\"optimize\":false}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_simple_no_opt PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_track_simple_no_opt_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/track_simple_no_opt.ozz" "${ozz_temp_directory}/track_simple_no_opt_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_simple_no_opt_output PROPERTIES DEPENDS test2ozz_anim_track_simple_no_opt)
|
||||
add_test(NAME test2ozz_anim_track_simple_no_opt_output_anim COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_track_simple_no_opt_one.ozz" "${ozz_temp_directory}/animation_track_simple_no_opt_one_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_simple_no_opt_output_anim PROPERTIES DEPENDS test2ozz_anim_track_simple_no_opt)
|
||||
|
||||
add_test(NAME test2ozz_anim_track_simple_no_opt_raw COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_track_simple_no_opt_raw_*.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint0\",\"property_name\":\"property0\",\"filename\":\"${ozz_temp_directory}/track_simple_no_opt_raw.ozz\",\"optimize\":false,\"raw\":true}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_simple_no_opt_raw PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_track_simple_no_opt_raw_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/track_simple_no_opt_raw.ozz" "${ozz_temp_directory}/track_simple_no_opt_raw_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_simple_no_opt_raw_output PROPERTIES DEPENDS test2ozz_anim_track_simple_no_opt_raw)
|
||||
add_test(NAME test2ozz_anim_track_simple_no_opt_raw_output_anim COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_track_simple_no_opt_raw_one.ozz" "${ozz_temp_directory}/animation_track_simple_no_opt_raw_one_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_simple_no_opt_raw_output_anim PROPERTIES DEPENDS test2ozz_anim_track_simple_no_opt_raw)
|
||||
|
||||
add_test(NAME test2ozz_anim_track2_simple COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_track2_simple_*.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint0\",\"property_name\":\"property2\",\"type\":\"float2\",\"filename\":\"${ozz_temp_directory}/track2_simple.ozz\"}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track2_simple PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_track2_simple_output COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/track2_simple.ozz" "${ozz_temp_directory}/track2_simple_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track2_simple_output PROPERTIES DEPENDS test2ozz_anim_track2_simple)
|
||||
add_test(NAME test2ozz_anim_track2_simple_output_anim COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/animation_track2_simple_one.ozz" "${ozz_temp_directory}/animation_track2_simple_one_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track2_simple_output_anim PROPERTIES DEPENDS test2ozz_anim_track2_simple)
|
||||
|
||||
add_test(NAME test2ozz_anim_track_wild_joint COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton.ozz\",\"import\":{\"enable\":false}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_track_wild_joint_*.ozz\",\"tracks\":[{\"properties\":[{\"joint_name\":\"joint?\",\"property_name\":\"property0\",\"filename\":\"${ozz_temp_directory}/track_wild_*.ozz\"}]}]}]}")
|
||||
set_tests_properties(test2ozz_anim_track_wild_joint PROPERTIES DEPENDS test2ozz_skel_simple)
|
||||
add_test(NAME test2ozz_anim_track_wild_joint_output0
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/track_wild_joint0-property0.ozz" "${ozz_temp_directory}/track_wild_joint0-property0_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_wild_joint_output0 PROPERTIES DEPENDS test2ozz_anim_track_wild_joint)
|
||||
add_test(NAME test2ozz_anim_track_wild_joint_output1
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${ozz_temp_directory}/track_wild_joint1-property0.ozz" "${ozz_temp_directory}/track_wild_joint1-property0_should_exist.ozz")
|
||||
set_tests_properties(test2ozz_anim_track_wild_joint_output1 PROPERTIES DEPENDS test2ozz_anim_track_wild_joint)
|
||||
|
||||
# Run test2ozz both skeleton and animation import passing tests
|
||||
#----------------------------
|
||||
|
||||
add_test(NAME test2ozz_skel_anim_simple COMMAND test2ozz "--file=${ozz_temp_directory}/good.content1" "--config={\"skeleton\":{\"filename\":\"${ozz_temp_directory}/skeleton_skel_anim.ozz\",\"import\":{\"enable\":true}},\"animations\":[{\"filename\":\"${ozz_temp_directory}/animation_skel_anim_simple.ozz\"}]}")
|
||||
|
||||
# Fused sources tests
|
||||
#----------------------------
|
||||
|
||||
# ozz_animation_tools fuse tests
|
||||
set_source_files_properties(${PROJECT_BINARY_DIR}/src_fused/ozz_animation_tools.cc PROPERTIES GENERATED 1)
|
||||
add_executable(test_fuse_ozz_animation_tools
|
||||
test2ozz.cc
|
||||
${PROJECT_BINARY_DIR}/src_fused/ozz_animation_tools.cc)
|
||||
add_dependencies(test_fuse_ozz_animation_tools BUILD_FUSE_ozz_animation_tools)
|
||||
target_link_libraries(test_fuse_ozz_animation_tools
|
||||
ozz_animation_offline
|
||||
ozz_options
|
||||
json
|
||||
gtest)
|
||||
|
||||
set_target_properties(test_fuse_ozz_animation_tools PROPERTIES FOLDER "ozz/tests/animation_offline")
|
||||
|
||||
add_test(NAME test_fuse_ozz_animation_tools_no_arg COMMAND test_fuse_ozz_animation_tools)
|
||||
set_tests_properties(test_fuse_ozz_animation_tools_no_arg PROPERTIES PASS_REGULAR_EXPRESSION "Required option \"file\" is not specified.")
|
||||
@@ -0,0 +1,319 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ozz/animation/offline/tools/import2ozz.h"
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
class TestConverter : public ozz::animation::offline::OzzImporter {
|
||||
public:
|
||||
TestConverter() {}
|
||||
~TestConverter() {}
|
||||
|
||||
private:
|
||||
virtual bool Load(const char* _filename) {
|
||||
file_ = ozz::make_unique<ozz::io::File>(_filename, "rb");
|
||||
if (!file_->opened()) {
|
||||
file_.reset(nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char good_content[] = "good content";
|
||||
char buffer[256];
|
||||
bool valid =
|
||||
file_->Read(buffer, sizeof(buffer)) >= sizeof(good_content) - 1 &&
|
||||
memcmp(buffer, good_content, sizeof(good_content) - 1) == 0;
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
return valid;
|
||||
}
|
||||
|
||||
virtual bool Import(ozz::animation::offline::RawSkeleton* _skeleton,
|
||||
const NodeType& _types) {
|
||||
(void)_types;
|
||||
if (file_ && file_->opened()) {
|
||||
char buffer[256];
|
||||
|
||||
{
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content 1";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
_skeleton->roots.resize(1);
|
||||
ozz::animation::offline::RawSkeleton::Joint& root =
|
||||
_skeleton->roots[0];
|
||||
root.name = "root";
|
||||
|
||||
root.children.resize(3);
|
||||
ozz::animation::offline::RawSkeleton::Joint& joint0 =
|
||||
root.children[0];
|
||||
joint0.name = "joint0";
|
||||
ozz::animation::offline::RawSkeleton::Joint& joint1 =
|
||||
root.children[1];
|
||||
joint1.name = "joint1";
|
||||
ozz::animation::offline::RawSkeleton::Joint& joint2 =
|
||||
root.children[2];
|
||||
joint2.name = "joint2";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
{
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content renamed";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
_skeleton->roots.resize(1);
|
||||
ozz::animation::offline::RawSkeleton::Joint& root =
|
||||
_skeleton->roots[0];
|
||||
root.name = "root";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
{
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] =
|
||||
"good content but not unique joint names";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
_skeleton->roots.resize(1);
|
||||
ozz::animation::offline::RawSkeleton::Joint& root =
|
||||
_skeleton->roots[0];
|
||||
root.name = "jointx";
|
||||
|
||||
root.children.resize(3);
|
||||
ozz::animation::offline::RawSkeleton::Joint& joint0 =
|
||||
root.children[0];
|
||||
joint0.name = "joint0";
|
||||
ozz::animation::offline::RawSkeleton::Joint& joint1 =
|
||||
root.children[1];
|
||||
joint1.name = "joint1";
|
||||
ozz::animation::offline::RawSkeleton::Joint& joint2 =
|
||||
root.children[2];
|
||||
joint2.name = "jointx";
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual AnimationNames GetAnimationNames() {
|
||||
AnimationNames names;
|
||||
|
||||
if (file_ && file_->opened()) {
|
||||
char buffer[256];
|
||||
|
||||
{
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content 0";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
return names; // No animations
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content 1";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
names.push_back("one");
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content renamed";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
names.push_back("renamed?");
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
// Handles more than one animation per file.
|
||||
{
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content 2";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
names.push_back("one");
|
||||
names.push_back("TWO");
|
||||
return names;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
virtual bool Import(const char* _animation_name,
|
||||
const ozz::animation::Skeleton& _skeleton,
|
||||
float _sampling_rate,
|
||||
ozz::animation::offline::RawAnimation* _animation) {
|
||||
(void)_sampling_rate;
|
||||
(void)_skeleton;
|
||||
|
||||
if (file_ && file_->opened()) {
|
||||
char buffer[256];
|
||||
{ // Handles a single animation per file.
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content 1";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
if (strcmp(_animation_name, "one") != 0) {
|
||||
return false;
|
||||
}
|
||||
_animation->tracks.resize(_skeleton.num_joints());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
{ // Handles a single animation per file that needs renaming.
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content renamed";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
if (strcmp(_animation_name, "renamed?") != 0) {
|
||||
return false;
|
||||
}
|
||||
_animation->tracks.resize(_skeleton.num_joints());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
{ // Handles more than one animation per file.
|
||||
file_->Seek(0, ozz::io::File::kSet);
|
||||
const char content[] = "good content 2";
|
||||
if (file_->Read(buffer, sizeof(buffer)) >= sizeof(content) - 1 &&
|
||||
memcmp(buffer, content, sizeof(content) - 1) == 0) {
|
||||
if (strcmp(_animation_name, "one") != 0 &&
|
||||
strcmp(_animation_name, "TWO") != 0) {
|
||||
return false;
|
||||
}
|
||||
_animation->tracks.resize(_skeleton.num_joints());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual NodeProperties GetNodeProperties(const char* _node_name) {
|
||||
NodeProperties ppts;
|
||||
bool found =
|
||||
strcmp(_node_name, "joint0") == 0 || strcmp(_node_name, "joint1") == 0;
|
||||
|
||||
if (found) {
|
||||
const NodeProperty ppt0 = {"property0", NodeProperty::kFloat1};
|
||||
ppts.push_back(ppt0);
|
||||
const NodeProperty ppt1 = {"property1", NodeProperty::kFloat1};
|
||||
ppts.push_back(ppt1);
|
||||
const NodeProperty ppt2 = {"property2", NodeProperty::kFloat2};
|
||||
ppts.push_back(ppt2);
|
||||
const NodeProperty ppt3 = {"property3", NodeProperty::kFloat3};
|
||||
ppts.push_back(ppt3);
|
||||
}
|
||||
return ppts;
|
||||
}
|
||||
|
||||
virtual bool Import(const char* _animation_name, const char* _node_name,
|
||||
const char* _track_name, NodeProperty::Type _track_type,
|
||||
float _sampling_rate,
|
||||
ozz::animation::offline::RawFloatTrack* _track) {
|
||||
(void)_animation_name;
|
||||
(void)_track_type;
|
||||
(void)_sampling_rate;
|
||||
(void)_track;
|
||||
|
||||
// joint2 doesn't have the property
|
||||
bool found = (strcmp(_node_name, "joint0") == 0 ||
|
||||
strcmp(_node_name, "joint1") == 0) &&
|
||||
(strcmp(_track_name, "property0") == 0 ||
|
||||
strcmp(_track_name, "property1") == 0);
|
||||
return found;
|
||||
}
|
||||
|
||||
virtual bool Import(const char* _animation_name, const char* _node_name,
|
||||
const char* _track_name, NodeProperty::Type _track_type,
|
||||
float _sampling_rate,
|
||||
ozz::animation::offline::RawFloat2Track* _track) {
|
||||
(void)_animation_name;
|
||||
(void)_track_type;
|
||||
(void)_sampling_rate;
|
||||
(void)_track;
|
||||
|
||||
// joint2 doesn't have the property
|
||||
bool found = (strcmp(_node_name, "joint0") == 0 ||
|
||||
strcmp(_node_name, "joint1") == 0) &&
|
||||
strcmp(_track_name, "property2") == 0;
|
||||
return found;
|
||||
}
|
||||
|
||||
virtual bool Import(const char* _animation_name, const char* _node_name,
|
||||
const char* _track_name, NodeProperty::Type _track_type,
|
||||
float _sampling_rate,
|
||||
ozz::animation::offline::RawFloat3Track* _track) {
|
||||
(void)_animation_name;
|
||||
(void)_track_type;
|
||||
(void)_sampling_rate;
|
||||
(void)_track;
|
||||
|
||||
// joint2 doesn't have the property
|
||||
bool found = (strcmp(_node_name, "joint0") == 0 ||
|
||||
strcmp(_node_name, "joint1") == 0) &&
|
||||
strcmp(_track_name, "property3") == 0;
|
||||
return found;
|
||||
}
|
||||
|
||||
virtual bool Import(const char* _animation_name, const char* _node_name,
|
||||
const char* _track_name, NodeProperty::Type _track_type,
|
||||
float _sampling_rate,
|
||||
ozz::animation::offline::RawFloat4Track* _track) {
|
||||
(void)_animation_name;
|
||||
(void)_track_type;
|
||||
(void)_sampling_rate;
|
||||
(void)_track;
|
||||
|
||||
// joint2 doesn't have the property
|
||||
bool found = (strcmp(_node_name, "joint0") == 0 ||
|
||||
strcmp(_node_name, "joint1") == 0) &&
|
||||
strcmp(_track_name, "property4") == 0;
|
||||
return found;
|
||||
}
|
||||
|
||||
ozz::unique_ptr<ozz::io::File> file_;
|
||||
};
|
||||
|
||||
int main(int _argc, const char** _argv) {
|
||||
TestConverter converter;
|
||||
return converter(_argc, _argv);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,402 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/track_optimizer.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_track.h"
|
||||
#include "ozz/animation/offline/track_builder.h"
|
||||
|
||||
using ozz::animation::offline::RawFloat2Track;
|
||||
using ozz::animation::offline::RawFloat3Track;
|
||||
using ozz::animation::offline::RawFloat4Track;
|
||||
using ozz::animation::offline::RawFloatTrack;
|
||||
using ozz::animation::offline::RawQuaternionTrack;
|
||||
using ozz::animation::offline::RawTrackInterpolation;
|
||||
using ozz::animation::offline::TrackOptimizer;
|
||||
|
||||
TEST(Error, TrackOptimizer) {
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
{ // nullptr output.
|
||||
RawFloatTrack input;
|
||||
EXPECT_TRUE(input.Validate());
|
||||
|
||||
// Builds animation
|
||||
EXPECT_FALSE(optimizer(input, nullptr));
|
||||
}
|
||||
|
||||
{ // Invalid input animation.
|
||||
RawFloatTrack input;
|
||||
input.keyframes.resize(1);
|
||||
input.keyframes[0].ratio = 99.f;
|
||||
EXPECT_FALSE(input.Validate());
|
||||
|
||||
// Builds animation
|
||||
RawFloatTrack output;
|
||||
output.keyframes.resize(1);
|
||||
EXPECT_FALSE(optimizer(input, &output));
|
||||
EXPECT_EQ(output.keyframes.size(), 0u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Name, FloatTrackOptimizer) {
|
||||
// Step keys aren't optimized.
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
RawFloatTrack raw_float_track;
|
||||
raw_float_track.name = "FloatTrackOptimizer test";
|
||||
|
||||
RawFloatTrack output;
|
||||
ASSERT_TRUE(optimizer(raw_float_track, &output));
|
||||
|
||||
EXPECT_STREQ(raw_float_track.name.c_str(), output.name.c_str());
|
||||
}
|
||||
|
||||
TEST(OptimizeSteps, TrackOptimizer) {
|
||||
// Step keys aren't optimized.
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
RawFloatTrack raw_float_track;
|
||||
const RawFloatTrack::Keyframe key0 = {RawTrackInterpolation::kStep, .5f,
|
||||
46.f};
|
||||
raw_float_track.keyframes.push_back(key0);
|
||||
const RawFloatTrack::Keyframe key1 = {RawTrackInterpolation::kStep, .7f, 0.f};
|
||||
raw_float_track.keyframes.push_back(key1);
|
||||
const RawFloatTrack::Keyframe key2 = {RawTrackInterpolation::kStep, .8f,
|
||||
1e-9f};
|
||||
raw_float_track.keyframes.push_back(key2);
|
||||
|
||||
RawFloatTrack output;
|
||||
ASSERT_TRUE(optimizer(raw_float_track, &output));
|
||||
|
||||
EXPECT_EQ(output.keyframes.size(), 3u);
|
||||
|
||||
EXPECT_EQ(output.keyframes[0].interpolation, key0.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].ratio, key0.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].value, key0.value);
|
||||
|
||||
EXPECT_EQ(output.keyframes[1].interpolation, key1.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].ratio, key1.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].value, key1.value);
|
||||
|
||||
EXPECT_EQ(output.keyframes[2].interpolation, key2.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[2].ratio, key2.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[2].value, key2.value);
|
||||
}
|
||||
|
||||
TEST(OptimizeInterpolate, TrackOptimizer) {
|
||||
// Step keys aren't optimized.
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
RawFloatTrack raw_float_track;
|
||||
const RawFloatTrack::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
69.f};
|
||||
raw_float_track.keyframes.push_back(key0);
|
||||
const RawFloatTrack::Keyframe key1 = {RawTrackInterpolation::kLinear, .25f,
|
||||
46.f};
|
||||
raw_float_track.keyframes.push_back(key1);
|
||||
const RawFloatTrack::Keyframe key2 = {RawTrackInterpolation::kLinear, .5f,
|
||||
23.f};
|
||||
raw_float_track.keyframes.push_back(key2);
|
||||
const RawFloatTrack::Keyframe key3 = {RawTrackInterpolation::kLinear,
|
||||
.500001f, 23.000001f};
|
||||
raw_float_track.keyframes.push_back(key3);
|
||||
const RawFloatTrack::Keyframe key4 = {RawTrackInterpolation::kLinear, .75f,
|
||||
0.f};
|
||||
raw_float_track.keyframes.push_back(key4);
|
||||
const RawFloatTrack::Keyframe key5 = {RawTrackInterpolation::kLinear, .8f,
|
||||
1e-12f};
|
||||
raw_float_track.keyframes.push_back(key5);
|
||||
const RawFloatTrack::Keyframe key6 = {RawTrackInterpolation::kLinear, 1.f,
|
||||
-1e-12f};
|
||||
raw_float_track.keyframes.push_back(key6);
|
||||
|
||||
{
|
||||
RawFloatTrack output;
|
||||
|
||||
optimizer.tolerance = 1e-3f;
|
||||
ASSERT_TRUE(optimizer(raw_float_track, &output));
|
||||
|
||||
EXPECT_EQ(output.keyframes.size(), 2u);
|
||||
|
||||
EXPECT_EQ(output.keyframes[0].interpolation, key0.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].ratio, key0.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].value, key0.value);
|
||||
|
||||
EXPECT_EQ(output.keyframes[1].interpolation, key4.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].ratio, key4.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].value, key4.value);
|
||||
}
|
||||
|
||||
{
|
||||
RawFloatTrack output;
|
||||
optimizer.tolerance = 1e-9f;
|
||||
ASSERT_TRUE(optimizer(raw_float_track, &output));
|
||||
|
||||
EXPECT_EQ(output.keyframes.size(), 4u);
|
||||
|
||||
EXPECT_EQ(output.keyframes[0].interpolation, key0.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].ratio, key0.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].value, key0.value);
|
||||
|
||||
EXPECT_EQ(output.keyframes[1].interpolation, key2.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].ratio, key2.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].value, key2.value);
|
||||
|
||||
EXPECT_EQ(output.keyframes[2].interpolation, key3.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[2].ratio, key3.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[2].value, key3.value);
|
||||
|
||||
EXPECT_EQ(output.keyframes[3].interpolation, key4.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[3].ratio, key4.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[3].value, key4.value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(float, TrackOptimizer) {
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
RawFloatTrack raw_track;
|
||||
const RawFloatTrack::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
6.9f};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const RawFloatTrack::Keyframe key1 = {RawTrackInterpolation::kLinear, .25f,
|
||||
4.6f};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const RawFloatTrack::Keyframe key2 = {RawTrackInterpolation::kLinear, .5f,
|
||||
2.3f};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const RawFloatTrack::Keyframe key3 = {RawTrackInterpolation::kLinear,
|
||||
.500001f, 2.300001f};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
const RawFloatTrack::Keyframe key4 = {RawTrackInterpolation::kLinear, .75f,
|
||||
0.f};
|
||||
raw_track.keyframes.push_back(key4);
|
||||
const RawFloatTrack::Keyframe key5 = {RawTrackInterpolation::kLinear, .8f,
|
||||
1e-12f};
|
||||
raw_track.keyframes.push_back(key5);
|
||||
const RawFloatTrack::Keyframe key6 = {RawTrackInterpolation::kLinear, 1.f,
|
||||
-1e-12f};
|
||||
raw_track.keyframes.push_back(key6);
|
||||
|
||||
RawFloatTrack output;
|
||||
ASSERT_TRUE(optimizer(raw_track, &output));
|
||||
|
||||
EXPECT_EQ(output.keyframes.size(), 2u);
|
||||
|
||||
EXPECT_EQ(output.keyframes[0].interpolation, key0.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].ratio, key0.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].value, key0.value);
|
||||
|
||||
EXPECT_EQ(output.keyframes[1].interpolation, key4.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].ratio, key4.ratio);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].value, key4.value);
|
||||
}
|
||||
|
||||
TEST(Float2, TrackOptimizer) {
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
RawFloat2Track raw_track;
|
||||
const RawFloat2Track::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Float2(6.9f, 0.f)};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const RawFloat2Track::Keyframe key1 = {RawTrackInterpolation::kLinear, .25f,
|
||||
ozz::math::Float2(4.6f, 0.f)};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const RawFloat2Track::Keyframe key2 = {RawTrackInterpolation::kLinear, .5f,
|
||||
ozz::math::Float2(2.3f, 0.f)};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const RawFloat2Track::Keyframe key3 = {RawTrackInterpolation::kLinear,
|
||||
.500001f,
|
||||
ozz::math::Float2(2.3000001f, 0.f)};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
const RawFloat2Track::Keyframe key4 = {RawTrackInterpolation::kLinear, .75f,
|
||||
ozz::math::Float2(0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key4);
|
||||
const RawFloat2Track::Keyframe key5 = {RawTrackInterpolation::kLinear, .8f,
|
||||
ozz::math::Float2(0.f, 1e-12f)};
|
||||
raw_track.keyframes.push_back(key5);
|
||||
const RawFloat2Track::Keyframe key6 = {RawTrackInterpolation::kLinear, 1.f,
|
||||
ozz::math::Float2(-1e-12f, 0.f)};
|
||||
raw_track.keyframes.push_back(key6);
|
||||
|
||||
RawFloat2Track output;
|
||||
ASSERT_TRUE(optimizer(raw_track, &output));
|
||||
|
||||
EXPECT_EQ(output.keyframes.size(), 2u);
|
||||
|
||||
EXPECT_EQ(output.keyframes[0].interpolation, key0.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].ratio, key0.ratio);
|
||||
EXPECT_FLOAT2_EQ(output.keyframes[0].value, key0.value.x, key0.value.y);
|
||||
|
||||
EXPECT_EQ(output.keyframes[1].interpolation, key4.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].ratio, key4.ratio);
|
||||
EXPECT_FLOAT2_EQ(output.keyframes[1].value, key4.value.x, key4.value.y);
|
||||
}
|
||||
|
||||
TEST(Float3, TrackOptimizer) {
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
RawFloat3Track raw_track;
|
||||
const RawFloat3Track::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Float3(6.9f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const RawFloat3Track::Keyframe key1 = {RawTrackInterpolation::kLinear, .25f,
|
||||
ozz::math::Float3(4.6f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const RawFloat3Track::Keyframe key2 = {RawTrackInterpolation::kLinear, .5f,
|
||||
ozz::math::Float3(2.3f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const RawFloat3Track::Keyframe key3 = {
|
||||
RawTrackInterpolation::kLinear, .500001f,
|
||||
ozz::math::Float3(2.3000001f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
const RawFloat3Track::Keyframe key4 = {RawTrackInterpolation::kLinear, .75f,
|
||||
ozz::math::Float3(0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key4);
|
||||
const RawFloat3Track::Keyframe key5 = {RawTrackInterpolation::kLinear, .8f,
|
||||
ozz::math::Float3(0.f, 0.f, 1e-12f)};
|
||||
raw_track.keyframes.push_back(key5);
|
||||
const RawFloat3Track::Keyframe key6 = {RawTrackInterpolation::kLinear, 1.f,
|
||||
ozz::math::Float3(0.f, -1e-12f, 0.f)};
|
||||
raw_track.keyframes.push_back(key6);
|
||||
|
||||
RawFloat3Track output;
|
||||
ASSERT_TRUE(optimizer(raw_track, &output));
|
||||
|
||||
EXPECT_EQ(output.keyframes.size(), 2u);
|
||||
|
||||
EXPECT_EQ(output.keyframes[0].interpolation, key0.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].ratio, key0.ratio);
|
||||
EXPECT_FLOAT3_EQ(output.keyframes[0].value, key0.value.x, key0.value.y,
|
||||
key0.value.z);
|
||||
|
||||
EXPECT_EQ(output.keyframes[1].interpolation, key4.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].ratio, key4.ratio);
|
||||
EXPECT_FLOAT3_EQ(output.keyframes[1].value, key4.value.x, key4.value.y,
|
||||
key4.value.z);
|
||||
}
|
||||
|
||||
TEST(Float4, TrackOptimizer) {
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
RawFloat4Track raw_track;
|
||||
const RawFloat4Track::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Float4(6.9f, 0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const RawFloat4Track::Keyframe key1 = {
|
||||
RawTrackInterpolation::kLinear, .25f,
|
||||
ozz::math::Float4(4.6f, 0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const RawFloat4Track::Keyframe key2 = {
|
||||
RawTrackInterpolation::kLinear, .5f,
|
||||
ozz::math::Float4(2.3f, 0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const RawFloat4Track::Keyframe key3 = {
|
||||
RawTrackInterpolation::kLinear, .500001f,
|
||||
ozz::math::Float4(2.3000001f, 0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
const RawFloat4Track::Keyframe key4 = {RawTrackInterpolation::kLinear, .75f,
|
||||
ozz::math::Float4(0.f, 0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key4);
|
||||
const RawFloat4Track::Keyframe key5 = {
|
||||
RawTrackInterpolation::kLinear, .8f,
|
||||
ozz::math::Float4(0.f, 0.f, 0.f, 1e-12f)};
|
||||
raw_track.keyframes.push_back(key5);
|
||||
const RawFloat4Track::Keyframe key6 = {
|
||||
RawTrackInterpolation::kLinear, 1.f,
|
||||
ozz::math::Float4(0.f, 0.f, 0.f, -1e-12f)};
|
||||
raw_track.keyframes.push_back(key6);
|
||||
|
||||
RawFloat4Track output;
|
||||
ASSERT_TRUE(optimizer(raw_track, &output));
|
||||
|
||||
EXPECT_EQ(output.keyframes.size(), 2u);
|
||||
|
||||
EXPECT_EQ(output.keyframes[0].interpolation, key0.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].ratio, key0.ratio);
|
||||
EXPECT_FLOAT4_EQ(output.keyframes[0].value, key0.value.x, key0.value.y,
|
||||
key0.value.z, key0.value.w);
|
||||
|
||||
EXPECT_EQ(output.keyframes[1].interpolation, key4.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].ratio, key4.ratio);
|
||||
EXPECT_FLOAT4_EQ(output.keyframes[1].value, key4.value.x, key4.value.y,
|
||||
key4.value.z, key0.value.w);
|
||||
}
|
||||
|
||||
TEST(Quaternion, TrackOptimizer) {
|
||||
TrackOptimizer optimizer;
|
||||
|
||||
RawQuaternionTrack raw_track;
|
||||
const RawQuaternionTrack::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Quaternion(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const RawQuaternionTrack::Keyframe key1 = {
|
||||
RawTrackInterpolation::kLinear, .1f,
|
||||
ozz::math::Quaternion(.6172133f, .1543033f, 0.f, .7715167f)}; // NLerp
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const RawQuaternionTrack::Keyframe key2 = {
|
||||
RawTrackInterpolation::kLinear, .5f,
|
||||
ozz::math::Quaternion(0.f, .70710677f, 0.f, .70710677f)};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const RawQuaternionTrack::Keyframe key3 = {
|
||||
RawTrackInterpolation::kLinear, .500001f,
|
||||
ozz::math::Quaternion(0.f, .70710676f, 0.f, .70710678f)};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
const RawQuaternionTrack::Keyframe key4 = {
|
||||
RawTrackInterpolation::kLinear, .75f,
|
||||
ozz::math::Quaternion(0.f, .70710677f, 0.f, .70710677f)};
|
||||
raw_track.keyframes.push_back(key4);
|
||||
const RawQuaternionTrack::Keyframe key5 = {
|
||||
RawTrackInterpolation::kLinear, .8f,
|
||||
ozz::math::Quaternion(-0.f, -0.70710677f, -0.f, -.70710677f)};
|
||||
raw_track.keyframes.push_back(key5);
|
||||
const RawQuaternionTrack::Keyframe key6 = {
|
||||
RawTrackInterpolation::kLinear, 1.f,
|
||||
ozz::math::Quaternion(0.f, .70710677f, 0.f, .70710677f)};
|
||||
raw_track.keyframes.push_back(key6);
|
||||
|
||||
RawQuaternionTrack output;
|
||||
ASSERT_TRUE(optimizer(raw_track, &output));
|
||||
|
||||
EXPECT_EQ(output.keyframes.size(), 2u);
|
||||
|
||||
EXPECT_EQ(output.keyframes[0].interpolation, key0.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[0].ratio, key0.ratio);
|
||||
EXPECT_QUATERNION_EQ(output.keyframes[0].value, key0.value.x, key0.value.y,
|
||||
key0.value.z, key0.value.w);
|
||||
|
||||
EXPECT_EQ(output.keyframes[1].interpolation, key2.interpolation);
|
||||
EXPECT_FLOAT_EQ(output.keyframes[1].ratio, key2.ratio);
|
||||
EXPECT_QUATERNION_EQ(output.keyframes[1].value, key2.value.x, key2.value.y,
|
||||
key2.value.z, key2.value.w);
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
# sampling_job_tests
|
||||
add_executable(test_sampling_job
|
||||
sampling_job_tests.cc)
|
||||
target_link_libraries(test_sampling_job
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_sampling_job PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_sampling_job COMMAND test_sampling_job)
|
||||
|
||||
# blending_job_tests
|
||||
add_executable(test_blending_job
|
||||
blending_job_tests.cc)
|
||||
target_link_libraries(test_blending_job
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_blending_job PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_blending_job COMMAND test_blending_job)
|
||||
|
||||
# local_to_model_job_tests
|
||||
add_executable(test_local_to_model_job
|
||||
local_to_model_job_tests.cc)
|
||||
target_link_libraries(test_local_to_model_job
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_local_to_model_job PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_local_to_model_job COMMAND test_local_to_model_job)
|
||||
|
||||
add_executable(test_animation_archive
|
||||
animation_archive_tests.cc)
|
||||
target_link_libraries(test_animation_archive
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_animation_archive PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_animation_archive COMMAND test_animation_archive)
|
||||
|
||||
add_executable(test_animation_archive_versioning
|
||||
animation_archive_versioning_tests.cc)
|
||||
target_link_libraries(test_animation_archive_versioning
|
||||
ozz_animation
|
||||
ozz_options
|
||||
gtest)
|
||||
set_target_properties(test_animation_archive_versioning PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_animation_archive_versioning_le COMMAND test_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/animation_v6_le.ozz" "--tracks=67" "--duration=.66666667" "--name=run")
|
||||
add_test(NAME test_animation_archive_versioning_be COMMAND test_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/animation_v6_be.ozz" "--tracks=67" "--duration=.66666667" "--name=run")
|
||||
|
||||
# Previous versions.
|
||||
add_test(NAME test_animation_archive_versioning_le_older5 COMMAND test_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/animation_v5_le.ozz" "--tracks=67" "--duration=.66666667" "--name=")
|
||||
set_tests_properties(test_animation_archive_versioning_le_older5 PROPERTIES WILL_FAIL true)
|
||||
add_test(NAME test_animation_archive_versioning_le_older4 COMMAND test_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/animation_v4_le.ozz" "--tracks=67" "--duration=.66666667" "--name=")
|
||||
set_tests_properties(test_animation_archive_versioning_le_older4 PROPERTIES WILL_FAIL true)
|
||||
add_test(NAME test_animation_archive_versioning_le_older3 COMMAND test_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/animation_v3_le.ozz" "--tracks=67" "--duration=.66666667" "--name=")
|
||||
set_tests_properties(test_animation_archive_versioning_le_older3 PROPERTIES WILL_FAIL true)
|
||||
add_test(NAME test_animation_archive_versioning_le_older2 COMMAND test_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/animation_v2_le.ozz" "--tracks=67" "--duration=1.33333302" "--name=")
|
||||
set_tests_properties(test_animation_archive_versioning_le_older2 PROPERTIES WILL_FAIL true)
|
||||
add_test(NAME test_animation_archive_versioning_le_older1 COMMAND test_animation_archive_versioning "--file=${ozz_media_directory}/bin/versioning/animation_v1_le.ozz" "--tracks=67" "--duration=.66666698" "--name=")
|
||||
set_tests_properties(test_animation_archive_versioning_le_older1 PROPERTIES WILL_FAIL true)
|
||||
|
||||
add_executable(test_skeleton_archive
|
||||
skeleton_archive_tests.cc)
|
||||
target_link_libraries(test_skeleton_archive
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_skeleton_archive PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_skeleton_archive COMMAND test_skeleton_archive)
|
||||
|
||||
add_executable(test_skeleton_archive_versioning
|
||||
skeleton_archive_versioning_tests.cc)
|
||||
target_link_libraries(test_skeleton_archive_versioning
|
||||
ozz_animation
|
||||
ozz_options
|
||||
gtest)
|
||||
set_target_properties(test_skeleton_archive_versioning PROPERTIES FOLDER "ozz/tests/animation")
|
||||
|
||||
# Previous skeleton versions.
|
||||
add_test(NAME test_skeleton_archive_versioning_le_older1 COMMAND test_skeleton_archive_versioning "--file=${ozz_media_directory}/bin/versioning/skeleton_v1_le.ozz" "--joints=67" "--root_name=Hips")
|
||||
set_tests_properties(test_skeleton_archive_versioning_le_older1 PROPERTIES WILL_FAIL true)
|
||||
|
||||
# Current skeleton version.
|
||||
add_test(NAME test_skeleton_archive_versioning_le COMMAND test_skeleton_archive_versioning "--file=${ozz_media_directory}/bin/versioning/skeleton_v2_le.ozz" "--joints=67" "--root_name=Hips")
|
||||
add_test(NAME test_skeleton_archive_versioning_be COMMAND test_skeleton_archive_versioning "--file=${ozz_media_directory}/bin/versioning/skeleton_v2_be.ozz" "--joints=67" "--root_name=Hips")
|
||||
|
||||
add_executable(test_skeleton_utils
|
||||
skeleton_utils_tests.cc)
|
||||
target_link_libraries(test_skeleton_utils
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_skeleton_utils PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_skeleton_utils COMMAND test_skeleton_utils)
|
||||
|
||||
add_executable(test_animation_utils
|
||||
animation_utils_tests.cc)
|
||||
target_link_libraries(test_animation_utils
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_animation_utils PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_animation_utils COMMAND test_skeleton_utils)
|
||||
|
||||
# track_sampling_job_tests
|
||||
add_executable(test_track_sampling_job
|
||||
track_sampling_job_tests.cc)
|
||||
target_link_libraries(test_track_sampling_job
|
||||
ozz_animation_offline
|
||||
ozz_animation
|
||||
ozz_base
|
||||
gtest)
|
||||
set_target_properties(test_track_sampling_job PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_track_sampling_job COMMAND test_track_sampling_job)
|
||||
|
||||
# test_track_triggering_job
|
||||
add_executable(test_track_triggering_job
|
||||
track_triggering_job_tests.cc
|
||||
track_triggering_job_trait_tests.cc)
|
||||
target_link_libraries(test_track_triggering_job
|
||||
ozz_animation_offline
|
||||
ozz_animation
|
||||
ozz_base
|
||||
gtest)
|
||||
set_target_properties(test_track_triggering_job PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_track_triggering_job COMMAND test_track_triggering_job)
|
||||
|
||||
add_executable(test_track_archive
|
||||
track_archive_tests.cc)
|
||||
target_link_libraries(test_track_archive
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
set_target_properties(test_track_archive PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_track_archive COMMAND test_track_archive)
|
||||
|
||||
add_executable(test_ik_aim_job
|
||||
ik_aim_job_tests.cc)
|
||||
target_link_libraries(test_ik_aim_job
|
||||
ozz_animation
|
||||
gtest)
|
||||
set_target_properties(test_ik_aim_job PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_ik_aim_job COMMAND test_ik_aim_job)
|
||||
|
||||
add_executable(test_ik_two_bone_job
|
||||
ik_two_bone_job_tests.cc)
|
||||
target_link_libraries(test_ik_two_bone_job
|
||||
ozz_animation
|
||||
gtest)
|
||||
set_target_properties(test_ik_two_bone_job PROPERTIES FOLDER "ozz/tests/animation")
|
||||
add_test(NAME test_ik_two_bone_job COMMAND test_ik_two_bone_job)
|
||||
|
||||
# ozz_animation fuse tests
|
||||
set_source_files_properties(${PROJECT_BINARY_DIR}/src_fused/ozz_animation.cc PROPERTIES GENERATED 1)
|
||||
add_executable(test_fuse_animation
|
||||
sampling_job_tests.cc
|
||||
${PROJECT_BINARY_DIR}/src_fused/ozz_animation.cc)
|
||||
add_dependencies(test_fuse_animation BUILD_FUSE_ozz_animation)
|
||||
target_link_libraries(test_fuse_animation
|
||||
ozz_animation_offline
|
||||
gtest)
|
||||
add_test(NAME test_fuse_animation COMMAND test_fuse_animation)
|
||||
set_target_properties(test_fuse_animation PROPERTIES FOLDER "ozz/tests/animation")
|
||||
@@ -0,0 +1,185 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/animation.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
|
||||
#include "ozz/animation/runtime/sampling_job.h"
|
||||
|
||||
#include "ozz/animation/offline/animation_builder.h"
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
|
||||
using ozz::animation::Animation;
|
||||
using ozz::animation::offline::RawAnimation;
|
||||
using ozz::animation::offline::AnimationBuilder;
|
||||
|
||||
TEST(Empty, AnimationSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
|
||||
Animation o_animation;
|
||||
o << o_animation;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
Animation i_animation;
|
||||
i >> i_animation;
|
||||
|
||||
EXPECT_EQ(o_animation.num_tracks(), i_animation.num_tracks());
|
||||
}
|
||||
|
||||
TEST(Filled, AnimationSerialize) {
|
||||
// Builds a valid animation.
|
||||
ozz::unique_ptr<Animation> o_animation;
|
||||
{
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(1);
|
||||
|
||||
RawAnimation::TranslationKey t_key0 = {0.f,
|
||||
ozz::math::Float3(93.f, 58.f, 46.f)};
|
||||
raw_animation.tracks[0].translations.push_back(t_key0);
|
||||
RawAnimation::TranslationKey t_key1 = {.9f,
|
||||
ozz::math::Float3(46.f, 58.f, 93.f)};
|
||||
raw_animation.tracks[0].translations.push_back(t_key1);
|
||||
|
||||
RawAnimation::RotationKey r_key = {
|
||||
0.7f, ozz::math::Quaternion(0.f, 1.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[0].rotations.push_back(r_key);
|
||||
|
||||
RawAnimation::ScaleKey s_key = {0.1f, ozz::math::Float3(99.f, 26.f, 14.f)};
|
||||
raw_animation.tracks[0].scales.push_back(s_key);
|
||||
|
||||
AnimationBuilder builder;
|
||||
o_animation = builder(raw_animation);
|
||||
ASSERT_TRUE(o_animation);
|
||||
}
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << *o_animation;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
Animation i_animation;
|
||||
i >> i_animation;
|
||||
|
||||
ASSERT_FLOAT_EQ(o_animation->duration(), i_animation.duration());
|
||||
ASSERT_EQ(o_animation->num_tracks(), i_animation.num_tracks());
|
||||
EXPECT_EQ(o_animation->size(), i_animation.size());
|
||||
|
||||
// Needs to sample to test the animation.
|
||||
ozz::animation::SamplingJob job;
|
||||
ozz::animation::SamplingCache cache(1);
|
||||
ozz::math::SoaTransform output[1];
|
||||
job.animation = o_animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
|
||||
// Samples and compares the two animations
|
||||
{ // Samples at t = 0
|
||||
job.ratio = 0.f;
|
||||
job.Run();
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 93.f, 0.f, 0.f, 0.f, 58.f,
|
||||
0.f, 0.f, 0.f, 46.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 1.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f,
|
||||
1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 99.f, 1.f, 1.f, 1.f, 26.f, 1.f,
|
||||
1.f, 1.f, 14.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
{ // Samples at t = 1
|
||||
job.ratio = 1.f;
|
||||
job.Run();
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 46.f, 0.f, 0.f, 0.f, 58.f,
|
||||
0.f, 0.f, 0.f, 93.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 1.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f,
|
||||
1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 99.f, 1.f, 1.f, 1.f, 26.f, 1.f,
|
||||
1.f, 1.f, 14.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlreadyInitialized, AnimationSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
{
|
||||
ozz::io::OArchive o(&stream);
|
||||
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(1);
|
||||
|
||||
AnimationBuilder builder;
|
||||
ozz::unique_ptr<Animation> o_animation(builder(raw_animation));
|
||||
ASSERT_TRUE(o_animation);
|
||||
o << *o_animation;
|
||||
|
||||
raw_animation.duration = 2.f;
|
||||
raw_animation.tracks.resize(2);
|
||||
o_animation = builder(raw_animation);
|
||||
ASSERT_TRUE(o_animation);
|
||||
o << *o_animation;
|
||||
}
|
||||
|
||||
{
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
// Reads and check the first animation.
|
||||
Animation i_animation;
|
||||
i >> i_animation;
|
||||
EXPECT_FLOAT_EQ(i_animation.duration(), 1.f);
|
||||
EXPECT_EQ(i_animation.num_tracks(), 1);
|
||||
|
||||
// Reuse the animation a second time.
|
||||
i >> i_animation;
|
||||
EXPECT_FLOAT_EQ(i_animation.duration(), 2.f);
|
||||
ASSERT_EQ(i_animation.num_tracks(), 2);
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/animation.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
#include "ozz/base/log.h"
|
||||
#include "ozz/options/options.h"
|
||||
|
||||
OZZ_OPTIONS_DECLARE_STRING(file, "Specifies input file", "", true)
|
||||
OZZ_OPTIONS_DECLARE_INT(tracks, "Number of tracks", 0, true)
|
||||
OZZ_OPTIONS_DECLARE_FLOAT(duration, "Duration", 0.f, true)
|
||||
OZZ_OPTIONS_DECLARE_STRING(name, "Name", "", true)
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
// Parses arguments.
|
||||
testing::InitGoogleTest(&_argc, _argv);
|
||||
ozz::options::ParseResult parse_result = ozz::options::ParseCommandLine(
|
||||
_argc, _argv, "1.0",
|
||||
"Test Animation archive versioning retrocompatibility");
|
||||
if (parse_result != ozz::options::kSuccess) {
|
||||
return parse_result == ozz::options::kExitSuccess ? EXIT_SUCCESS
|
||||
: EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
TEST(Versioning, AnimationSerialize) {
|
||||
// Open the file.
|
||||
const char* filename = OPTIONS_file;
|
||||
ozz::io::File file(filename, "rb");
|
||||
ASSERT_TRUE(file.opened());
|
||||
|
||||
// Open archive and test object tag.
|
||||
ozz::io::IArchive archive(&file);
|
||||
ASSERT_TRUE(archive.TestTag<ozz::animation::Animation>());
|
||||
|
||||
// Read the object.
|
||||
ozz::animation::Animation animation;
|
||||
archive >> animation;
|
||||
|
||||
// More testing
|
||||
EXPECT_EQ(animation.num_tracks(), OPTIONS_tracks);
|
||||
EXPECT_FLOAT_EQ(animation.duration(), OPTIONS_duration);
|
||||
EXPECT_STREQ(animation.name(), OPTIONS_name);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/animation_utils.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/animation/offline/animation_builder.h"
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
|
||||
using ozz::animation::Animation;
|
||||
using ozz::animation::offline::RawAnimation;
|
||||
using ozz::animation::offline::AnimationBuilder;
|
||||
|
||||
TEST(CountKeyframes, AnimationUtils) {
|
||||
// Builds a valid animation.
|
||||
ozz::unique_ptr<Animation> animation;
|
||||
|
||||
{
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(2);
|
||||
|
||||
RawAnimation::TranslationKey t_key0 = {0.f,
|
||||
ozz::math::Float3(93.f, 58.f, 46.f)};
|
||||
raw_animation.tracks[0].translations.push_back(t_key0);
|
||||
RawAnimation::TranslationKey t_key1 = {.9f,
|
||||
ozz::math::Float3(46.f, 58.f, 93.f)};
|
||||
raw_animation.tracks[0].translations.push_back(t_key1);
|
||||
RawAnimation::TranslationKey t_key2 = {1.f,
|
||||
ozz::math::Float3(46.f, 58.f, 99.f)};
|
||||
raw_animation.tracks[0].translations.push_back(t_key2);
|
||||
|
||||
RawAnimation::RotationKey r_key = {
|
||||
0.7f, ozz::math::Quaternion(0.f, 1.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[0].rotations.push_back(r_key);
|
||||
|
||||
RawAnimation::ScaleKey s_key = {0.1f, ozz::math::Float3(99.f, 26.f, 14.f)};
|
||||
raw_animation.tracks[1].scales.push_back(s_key);
|
||||
|
||||
AnimationBuilder builder;
|
||||
animation = builder(raw_animation);
|
||||
ASSERT_TRUE(animation);
|
||||
}
|
||||
|
||||
// 4 more tracks than expected due to SoA
|
||||
EXPECT_EQ(ozz::animation::CountTranslationKeyframes(*animation, -1), 9);
|
||||
EXPECT_EQ(ozz::animation::CountTranslationKeyframes(*animation, 0), 3);
|
||||
EXPECT_EQ(ozz::animation::CountTranslationKeyframes(*animation, 1), 2);
|
||||
|
||||
EXPECT_EQ(ozz::animation::CountRotationKeyframes(*animation, -1), 8);
|
||||
EXPECT_EQ(ozz::animation::CountRotationKeyframes(*animation, 0), 2);
|
||||
EXPECT_EQ(ozz::animation::CountRotationKeyframes(*animation, 1), 2);
|
||||
|
||||
EXPECT_EQ(ozz::animation::CountScaleKeyframes(*animation, -1), 8);
|
||||
EXPECT_EQ(ozz::animation::CountScaleKeyframes(*animation, 0), 2);
|
||||
EXPECT_EQ(ozz::animation::CountScaleKeyframes(*animation, 1), 2);
|
||||
}
|
||||
@@ -0,0 +1,871 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/animation/runtime/blending_job.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
|
||||
using ozz::animation::BlendingJob;
|
||||
|
||||
TEST(JobValidity, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
const ozz::math::SimdFloat4 zero = ozz::math::simd_float4::zero();
|
||||
BlendingJob::Layer layers[2];
|
||||
const ozz::math::SoaTransform bind_poses[3] = {identity, identity, identity};
|
||||
const ozz::math::SoaTransform input_transforms[3] = {identity, identity,
|
||||
identity};
|
||||
ozz::math::SoaTransform output_transforms[3] = {identity, identity, identity};
|
||||
ozz::math::SimdFloat4 joint_weights[3] = {zero, zero, zero};
|
||||
|
||||
layers[0].transform = input_transforms;
|
||||
layers[1].transform = {input_transforms, input_transforms + 2};
|
||||
|
||||
{ // Empty/default job.
|
||||
BlendingJob job;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid output.
|
||||
BlendingJob job;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
{ // Layers are optional.
|
||||
BlendingJob job;
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
{ // Invalid bind pose.
|
||||
BlendingJob job;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
{ // Invalid layer input range, too small.
|
||||
BlendingJob::Layer invalid_layers[2];
|
||||
invalid_layers[0].transform = {input_transforms, input_transforms + 1};
|
||||
invalid_layers[1].transform = {input_transforms, input_transforms + 2};
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = invalid_layers;
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
{ // Invalid output range, smaller output.
|
||||
BlendingJob job;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 1};
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid smaller input.
|
||||
BlendingJob job;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.bind_pose = {bind_poses, bind_poses + 3};
|
||||
job.output = {output_transforms, output_transforms + 3};
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid threshold.
|
||||
BlendingJob job;
|
||||
job.threshold = 0.f;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid joint weights range.
|
||||
layers[0].joint_weights = {joint_weights, joint_weights + 1};
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid job.
|
||||
layers[0].joint_weights = {nullptr, nullptr};
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid joint weights range.
|
||||
layers[0].joint_weights = {joint_weights, joint_weights + 2};
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid job, bigger output.
|
||||
layers[0].joint_weights = {joint_weights, joint_weights + 2};
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = {layers, layers + 2};
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 3};
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid no layers.
|
||||
BlendingJob job;
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(JobValidityAdditive, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
const ozz::math::SimdFloat4 zero = ozz::math::simd_float4::zero();
|
||||
BlendingJob::Layer layers[2];
|
||||
BlendingJob::Layer additive_layers[2];
|
||||
|
||||
const ozz::math::SoaTransform bind_poses[3] = {identity, identity, identity};
|
||||
const ozz::math::SoaTransform input_transforms[3] = {identity, identity,
|
||||
identity};
|
||||
ozz::math::SoaTransform output_transforms[3] = {identity, identity, identity};
|
||||
ozz::math::SimdFloat4 joint_weights[3] = {zero, zero, zero};
|
||||
|
||||
layers[0].transform = input_transforms;
|
||||
layers[1].transform = input_transforms;
|
||||
|
||||
additive_layers[0].transform = input_transforms;
|
||||
additive_layers[1].transform = input_transforms;
|
||||
|
||||
{ // Valid additive job, no normal blending.
|
||||
BlendingJob job;
|
||||
job.additive_layers = additive_layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid additive job, with normal blending also.
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = layers;
|
||||
job.additive_layers = additive_layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid layer input range, too small.
|
||||
BlendingJob::Layer invalid_layers[2];
|
||||
invalid_layers[0].transform = {input_transforms, input_transforms + 1};
|
||||
invalid_layers[1].transform = {input_transforms, input_transforms + 2};
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = layers;
|
||||
job.additive_layers = invalid_layers;
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid additive job, with per-joint weights.
|
||||
layers[0].joint_weights = {joint_weights, joint_weights + 2};
|
||||
|
||||
BlendingJob job;
|
||||
job.additive_layers = additive_layers;
|
||||
job.bind_pose = {bind_poses, bind_poses + 2};
|
||||
job.output = {output_transforms, output_transforms + 2};
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Empty, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
|
||||
// Initialize bind pose.
|
||||
ozz::math::SoaTransform bind_poses[2] = {identity, identity};
|
||||
bind_poses[0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
bind_poses[0].scale = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 10.f, 20.f, 30.f),
|
||||
ozz::math::simd_float4::Load(40.f, 50.f, 60.f, 70.f),
|
||||
ozz::math::simd_float4::Load(80.f, 90.f, 100.f, 110.f));
|
||||
bind_poses[1].translation = bind_poses[0].translation *
|
||||
ozz::math::simd_float4::Load(2.f, 2.f, 2.f, 2.f);
|
||||
bind_poses[1].scale =
|
||||
bind_poses[0].scale * ozz::math::simd_float4::Load(2.f, 2.f, 2.f, 2.f);
|
||||
|
||||
BlendingJob job;
|
||||
job.bind_pose = bind_poses;
|
||||
ozz::math::SoaTransform output_transforms[2];
|
||||
job.output = output_transforms;
|
||||
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 1.f, 2.f, 3.f, 4.f,
|
||||
5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 0.f, 10.f, 20.f, 30.f, 40.f,
|
||||
50.f, 60.f, 70.f, 80.f, 90.f, 100.f, 110.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].translation, 0.f, 2.f, 4.f, 6.f, 8.f,
|
||||
10.f, 12.f, 14.f, 16.f, 18.f, 20.f, 22.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].scale, 0.f, 20.f, 40.f, 60.f, 80.f,
|
||||
100.f, 120.f, 140.f, 160.f, 180.f, 200.f, 220.f);
|
||||
}
|
||||
|
||||
TEST(Weight, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
|
||||
// Initialize inputs.
|
||||
ozz::math::SoaTransform input_transforms[2][2] = {{identity, identity},
|
||||
{identity, identity}};
|
||||
input_transforms[0][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
input_transforms[0][1].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f),
|
||||
ozz::math::simd_float4::Load(16.f, 17.f, 18.f, 19.f),
|
||||
ozz::math::simd_float4::Load(20.f, 21.f, 22.f, 23.f));
|
||||
input_transforms[1][0].translation = -input_transforms[0][0].translation;
|
||||
input_transforms[1][1].translation = -input_transforms[0][1].translation;
|
||||
|
||||
// Initialize bind pose.
|
||||
ozz::math::SoaTransform bind_poses[2] = {identity, identity};
|
||||
bind_poses[0].scale = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
bind_poses[1].scale =
|
||||
bind_poses[0].scale * ozz::math::simd_float4::Load(2.f, 2.f, 2.f, 2.f);
|
||||
|
||||
{
|
||||
BlendingJob::Layer layers[2];
|
||||
layers[0].transform = input_transforms[0];
|
||||
layers[1].transform = input_transforms[1];
|
||||
|
||||
ozz::math::SoaTransform output_transforms[2];
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
// Weight 0 (a bit less must give the same result) for the first layer,
|
||||
// 1 for the second.
|
||||
layers[0].weight = -.07f;
|
||||
layers[1].weight = 1.f;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, -0.f, -1.f, -2.f,
|
||||
-3.f, -4.f, -5.f, -6.f, -7.f, -8.f, -9.f, -10.f, -11.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].translation, -12.f, -13.f, -14.f,
|
||||
-15.f, -16.f, -17.f, -18.f, -19.f, -20.f, -21.f, -22.f,
|
||||
-23.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// Weight 1 for the first layer, 0 for the second.
|
||||
layers[0].weight = 1.f;
|
||||
layers[1].weight = 1e-27f; // Very low weight value.
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 1.f, 2.f, 3.f,
|
||||
4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].translation, 12.f, 13.f, 14.f,
|
||||
15.f, 16.f, 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// Weight .5 for both layers.
|
||||
layers[0].weight = .5f;
|
||||
layers[1].weight = .5f;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].translation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(JointWeights, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
|
||||
// Initialize inputs.
|
||||
ozz::math::SoaTransform input_transforms[2][2] = {{identity, identity},
|
||||
{identity, identity}};
|
||||
input_transforms[0][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
input_transforms[0][1].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f),
|
||||
ozz::math::simd_float4::Load(16.f, 17.f, 18.f, 19.f),
|
||||
ozz::math::simd_float4::Load(20.f, 21.f, 22.f, 23.f));
|
||||
input_transforms[1][0].translation = -input_transforms[0][0].translation;
|
||||
input_transforms[1][1].translation = -input_transforms[0][1].translation;
|
||||
ozz::math::SimdFloat4 joint_weights[2][2] = {
|
||||
{ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, 1.f, 1.f)},
|
||||
{ozz::math::simd_float4::Load(1.f, 1.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 1.f, 1.f)}};
|
||||
// Initialize bind pose.
|
||||
ozz::math::SoaTransform bind_poses[2] = {identity, identity};
|
||||
bind_poses[0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(10.f, 11.f, 12.f, 13.f),
|
||||
ozz::math::simd_float4::Load(14.f, 15.f, 16.f, 17.f),
|
||||
ozz::math::simd_float4::Load(18.f, 19.f, 20.f, 21.f));
|
||||
bind_poses[0].scale = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
bind_poses[1].scale =
|
||||
bind_poses[0].scale * ozz::math::simd_float4::Load(2.f, 2.f, 2.f, 2.f);
|
||||
|
||||
BlendingJob::Layer layers[2];
|
||||
layers[0].transform = input_transforms[0];
|
||||
layers[0].joint_weights = joint_weights[0];
|
||||
layers[1].transform = input_transforms[1];
|
||||
layers[1].joint_weights = joint_weights[1];
|
||||
|
||||
{ // Weight .5 for both layers.
|
||||
ozz::math::SoaTransform output_transforms[3];
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
layers[0].weight = .5f;
|
||||
layers[1].weight = .5f;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 0.f, -2.f, 13.f,
|
||||
0.f, 0.f, -6.f, 17.f, 0.f, 0.f, -10.f, 21.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 3.f, 1.f,
|
||||
1.f, 1.f, 7.f, 1.f, 1.f, 1.f, 11.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].translation, 12.f, -13.f, 0.f, 0.f,
|
||||
16.f, -17.f, 0.f, 0.f, 20.f, -21.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
{ // Null weight for the first layer.
|
||||
ozz::math::SoaTransform output_transforms[2];
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
layers[0].weight = 0.f;
|
||||
layers[1].weight = 1.f;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, -0.f, -1.f, -2.f,
|
||||
13.f, -4.f, -5.f, -6.f, 17.f, -8.f, -9.f, -10.f, 21.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 3.f, 1.f,
|
||||
1.f, 1.f, 7.f, 1.f, 1.f, 1.f, 11.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].translation, 0.f, -13.f, -14.f,
|
||||
-15.f, 0.f, -17.f, -18.f, -19.f, 0.f, -21.f, -22.f,
|
||||
-23.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[1].scale, 0.f, 1.f, 1.f, 1.f, 8.f,
|
||||
1.f, 1.f, 1.f, 16.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Normalize, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
|
||||
// Initialize inputs.
|
||||
ozz::math::SoaTransform input_transforms[2][1] = {{identity}, {identity}};
|
||||
|
||||
// Initialize bind pose.
|
||||
ozz::math::SoaTransform bind_poses[1] = {identity};
|
||||
bind_poses[0].scale = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
|
||||
input_transforms[0][0].rotation = ozz::math::SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, .382683432f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, .70710677f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(.70710677f, 1.f, .70710677f, .9238795f));
|
||||
input_transforms[1][0].rotation = ozz::math::SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, -.70710677f, -.382683432f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, -.70710677f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, .70710677f, 0.f, -.9238795f));
|
||||
|
||||
{ // Un-normalized weights < 1.f.
|
||||
input_transforms[0][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(2.f, 3.f, 4.f, 5.f),
|
||||
ozz::math::simd_float4::Load(6.f, 7.f, 8.f, 9.f),
|
||||
ozz::math::simd_float4::Load(10.f, 11.f, 12.f, 13.f));
|
||||
input_transforms[1][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(3.f, 4.f, 5.f, 6.f),
|
||||
ozz::math::simd_float4::Load(7.f, 8.f, 9.f, 10.f),
|
||||
ozz::math::simd_float4::Load(11.f, 12.f, 13.f, 14.f));
|
||||
|
||||
BlendingJob::Layer layers[2];
|
||||
layers[0].weight = 0.2f;
|
||||
layers[0].transform = input_transforms[0];
|
||||
layers[1].weight = 0.3f;
|
||||
layers[1].transform = input_transforms[1];
|
||||
|
||||
ozz::math::SoaTransform output_transforms[1];
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 2.6f, 3.6f, 4.6f,
|
||||
5.6f, 6.6f, 7.6f, 8.6f, 9.6f, 10.6f, 11.6f, 12.6f,
|
||||
13.6f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, .30507791f,
|
||||
.45761687f, -.58843851f, .38268352f, 0.f, 0.f,
|
||||
.39229235f, 0.f, 0.f, 0.f, -.58843851f, 0.f,
|
||||
.95224595f, .88906217f, .39229235f, .92387962f);
|
||||
EXPECT_TRUE(
|
||||
ozz::math::AreAllTrue(IsNormalizedEst(output_transforms[0].rotation)));
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
{ // Un-normalized weights > 1.f.
|
||||
input_transforms[0][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(5.f, 10.f, 15.f, 20.f),
|
||||
ozz::math::simd_float4::Load(25.f, 30.f, 35.f, 40.f),
|
||||
ozz::math::simd_float4::Load(45.f, 50.f, 55.f, 60.f));
|
||||
input_transforms[1][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(10.f, 15.f, 20.f, 25.f),
|
||||
ozz::math::simd_float4::Load(30.f, 35.f, 40.f, 45.f),
|
||||
ozz::math::simd_float4::Load(50.f, 55.f, 60.f, 65.f));
|
||||
|
||||
BlendingJob::Layer layers[2];
|
||||
layers[0].weight = 2.f;
|
||||
layers[0].transform = input_transforms[0];
|
||||
layers[1].weight = 3.f;
|
||||
layers[1].transform = input_transforms[1];
|
||||
|
||||
ozz::math::SoaTransform output_transforms[1];
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 8.f, 13.f, 18.f, 23.f,
|
||||
28.f, 33.f, 38.f, 43.f, 48.f, 53.f, 58.f, 63.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, .30507791f,
|
||||
.45761687f, -.58843851f, .38268352f, 0.f, 0.f,
|
||||
.39229235f, 0.f, 0.f, 0.f, -.58843851f, 0.f,
|
||||
.95224595f, .88906217f, .39229235f, .92387962f);
|
||||
EXPECT_TRUE(
|
||||
ozz::math::AreAllTrue(IsNormalizedEst(output_transforms[0].rotation)));
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
{ // Un-normalized weights > 1.f, with per-joint weights.
|
||||
input_transforms[0][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(5.f, 10.f, 15.f, 20.f),
|
||||
ozz::math::simd_float4::Load(25.f, 30.f, 35.f, 40.f),
|
||||
ozz::math::simd_float4::Load(45.f, 50.f, 55.f, 60.f));
|
||||
input_transforms[1][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(10.f, 15.f, 20.f, 25.f),
|
||||
ozz::math::simd_float4::Load(30.f, 35.f, 40.f, 45.f),
|
||||
ozz::math::simd_float4::Load(50.f, 55.f, 60.f, 65.f));
|
||||
ozz::math::SimdFloat4 joint_weights[1] = {
|
||||
ozz::math::simd_float4::Load(1.f, -1.f, 2.f, .1f)};
|
||||
|
||||
BlendingJob::Layer layers[2];
|
||||
layers[0].weight = 2.f;
|
||||
layers[0].transform = input_transforms[0];
|
||||
layers[1].weight = 3.f;
|
||||
layers[1].transform = input_transforms[1];
|
||||
layers[1].joint_weights = joint_weights;
|
||||
|
||||
ozz::math::SoaTransform output_transforms[1];
|
||||
|
||||
BlendingJob job;
|
||||
job.layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 8.f, 10.f,
|
||||
150.f / 8.f, 47.5f / 2.3f, 28.f, 30.f, 310.f / 8.f,
|
||||
93.5f / 2.3f, 48.f, 50.f, 470.f / 8.f, 139.5f / 2.3f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Threshold, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
|
||||
// Initialize inputs.
|
||||
ozz::math::SoaTransform input_transforms[2][1] = {{identity}, {identity}};
|
||||
|
||||
// Initialize bind pose.
|
||||
ozz::math::SoaTransform bind_poses[1] = {identity};
|
||||
bind_poses[0].scale = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
|
||||
input_transforms[0][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(2.f, 3.f, 4.f, 5.f),
|
||||
ozz::math::simd_float4::Load(6.f, 7.f, 8.f, 9.f),
|
||||
ozz::math::simd_float4::Load(10.f, 11.f, 12.f, 13.f));
|
||||
input_transforms[1][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(3.f, 4.f, 5.f, 6.f),
|
||||
ozz::math::simd_float4::Load(7.f, 8.f, 9.f, 10.f),
|
||||
ozz::math::simd_float4::Load(11.f, 12.f, 13.f, 14.f));
|
||||
|
||||
{ // Threshold is not reached.
|
||||
BlendingJob::Layer layers[2];
|
||||
layers[0].weight = 0.04f;
|
||||
layers[0].transform = input_transforms[0];
|
||||
layers[1].weight = 0.06f;
|
||||
layers[1].transform = input_transforms[1];
|
||||
|
||||
ozz::math::SoaTransform output_transforms[1];
|
||||
|
||||
BlendingJob job;
|
||||
job.threshold = .1f;
|
||||
job.layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 2.6f, 3.6f, 4.6f,
|
||||
5.6f, 6.6f, 7.6f, 8.6f, 9.6f, 10.6f, 11.6f, 12.6f,
|
||||
13.6f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
{ // Threshold is reached at 100%.
|
||||
BlendingJob::Layer layers[2];
|
||||
layers[0].weight = 1e-27f;
|
||||
layers[0].transform = input_transforms[0];
|
||||
layers[1].weight = 0.f;
|
||||
layers[1].transform = input_transforms[1];
|
||||
|
||||
ozz::math::SoaTransform output_transforms[1];
|
||||
|
||||
BlendingJob job;
|
||||
job.threshold = .1f;
|
||||
job.layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 0.f, 1.f, 2.f, 3.f, 4.f,
|
||||
5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AdditiveWeight, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
|
||||
// Initialize inputs.
|
||||
ozz::math::SoaTransform input_transforms[2][1] = {{identity}, {identity}};
|
||||
input_transforms[0][0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
input_transforms[0][0].rotation = ozz::math::SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, .382683432f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, .70710677f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(.70710677f, 1.f, -.70710677f, .9238795f));
|
||||
input_transforms[0][0].scale = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f),
|
||||
ozz::math::simd_float4::Load(16.f, 17.f, 18.f, 19.f),
|
||||
ozz::math::simd_float4::Load(20.f, 21.f, 22.f, 23.f));
|
||||
input_transforms[1][0].translation = -input_transforms[0][0].translation;
|
||||
input_transforms[1][0].rotation = Conjugate(input_transforms[0][0].rotation);
|
||||
input_transforms[1][0].scale = -input_transforms[0][0].scale;
|
||||
|
||||
// Initialize bind pose.
|
||||
ozz::math::SoaTransform bind_poses[1] = {identity};
|
||||
|
||||
{
|
||||
BlendingJob::Layer layers[1];
|
||||
layers[0].transform = input_transforms[0];
|
||||
|
||||
ozz::math::SoaTransform output_transforms[1];
|
||||
|
||||
BlendingJob job;
|
||||
job.additive_layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
// No weight for the 1st layer.
|
||||
layers[0].weight = 0.f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// .5 weight for the 1st layer.
|
||||
layers[0].weight = .5f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, .5f, 1.f, 1.5f,
|
||||
2.f, 2.5f, 3.f, 3.5f, 4.f, 4.5f, 5.f, 5.5f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, .3826834f, 0.f,
|
||||
0.f, .19509032f, 0.f, 0.f, -.3826834f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, .9238795f, 1.f, .9238795f,
|
||||
.98078528f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 6.5f, 7.f, 7.5f, 8.f, 8.5f,
|
||||
9.f, 9.5f, 10.f, 10.5f, 11.f, 11.5f, 12.f);
|
||||
|
||||
// Full weight for the 1st layer.
|
||||
layers[0].weight = 1.f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 1.f, 2.f, 3.f,
|
||||
4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, .70710677f, 0.f,
|
||||
0.f, .382683432f, 0.f, 0.f, -.70710677f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, .70710677f, 1.f, .70710677f,
|
||||
.9238795f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 12.f, 13.f, 14.f, 15.f,
|
||||
16.f, 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f);
|
||||
}
|
||||
|
||||
{
|
||||
BlendingJob::Layer layers[2];
|
||||
layers[0].transform = input_transforms[0];
|
||||
layers[1].transform = input_transforms[1];
|
||||
|
||||
ozz::math::SoaTransform output_transforms[1];
|
||||
|
||||
BlendingJob job;
|
||||
job.additive_layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
// No weight for the 1st layer.
|
||||
layers[0].weight = 0.f;
|
||||
layers[1].weight = 1.f;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, -0.f, -1.f, -2.f,
|
||||
-3.f, -4.f, -5.f, -6.f, -7.f, -8.f, -9.f, -10.f, -11.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, -.70710677f,
|
||||
-0.f, -0.f, -.382683432f, -0.f, -0.f,
|
||||
.70710677f, -0.f, -0.f, -0.f, -0.f, -0.f,
|
||||
.70710677f, 1.f, .70710677f, .9238795f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, -12.f, -13.f, -14.f, -15.f,
|
||||
-16.f, -17.f, -18.f, -19.f, -20.f, -21.f, -22.f, -23.f);
|
||||
|
||||
// Full weight for the both layer.
|
||||
layers[0].weight = 1.f;
|
||||
layers[1].weight = 1.f;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, -144.f, -169.f, -196.f,
|
||||
-225.f, -256.f, -289.f, -324.f, -361.f, -400.f, -441.f,
|
||||
-484.f, -529.f);
|
||||
|
||||
// Subtract second layer.
|
||||
layers[0].weight = .5f;
|
||||
layers[1].transform = input_transforms[0];
|
||||
layers[1].weight = -.5f;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AdditiveJointWeight, BlendingJob) {
|
||||
const ozz::math::SoaTransform identity = ozz::math::SoaTransform::identity();
|
||||
|
||||
// Initialize inputs.
|
||||
ozz::math::SoaTransform input_transforms[1] = {identity};
|
||||
input_transforms[0].translation = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
input_transforms[0].rotation = ozz::math::SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, .382683432f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, .70710677f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(.70710677f, 1.f, -.70710677f, .9238795f));
|
||||
input_transforms[0].scale = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f),
|
||||
ozz::math::simd_float4::Load(16.f, 17.f, 18.f, 19.f),
|
||||
ozz::math::simd_float4::Load(20.f, 21.f, 22.f, 23.f));
|
||||
|
||||
ozz::math::SimdFloat4 joint_weights[1] = {
|
||||
ozz::math::simd_float4::Load(1.f, .5f, 0.f, -1.f)};
|
||||
|
||||
// Initialize bind pose.
|
||||
ozz::math::SoaTransform bind_poses[1] = {identity};
|
||||
|
||||
{
|
||||
BlendingJob::Layer layers[1];
|
||||
layers[0].transform = input_transforms;
|
||||
layers[0].joint_weights = joint_weights;
|
||||
|
||||
ozz::math::SoaTransform output_transforms[1];
|
||||
|
||||
BlendingJob job;
|
||||
job.additive_layers = layers;
|
||||
job.bind_pose = bind_poses;
|
||||
job.output = output_transforms;
|
||||
|
||||
// No weight for the 1st layer.
|
||||
layers[0].weight = 0.f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// .5 weight for the 1st layer.
|
||||
layers[0].weight = .5f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, .25f, 0.f, 0.f,
|
||||
2.f, 1.25f, 0.f, 0.f, 4.f, 2.25f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, .3826834f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, .9238795f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 6.5f, 4.f, 1.f, 1.f, 8.5f,
|
||||
5.f, 1.f, 1.f, 10.5f, 6.f, 1.f, 1.f);
|
||||
|
||||
// Full weight for the 1st layer.
|
||||
layers[0].weight = 1.f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, 0.f, .5f, 0.f, 0.f,
|
||||
4.f, 2.5f, 0.f, 0.f, 8.f, 4.5f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, .70710677f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, .70710677f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].scale, 12.f, 7.f, 1.f, 1.f, 16.f,
|
||||
9.f, 1.f, 1.f, 20.f, 11.f, 1.f, 1.f);
|
||||
|
||||
// Subtract layer.
|
||||
layers[0].weight = -1.f;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(output_transforms[0].translation, -0.f, -.5f, 0.f, 0.f,
|
||||
-4.f, -2.5f, 0.f, 0.f, -8.f, -4.5f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output_transforms[0].rotation, -.70710677f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, .70710677f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output_transforms[0].scale, 1.f / 12.f, 1.f / 7.f,
|
||||
1.f, 1.f, 1.f / 16.f, 1.f / 9.f, 1.f, 1.f,
|
||||
1.f / 20.f, 1.f / 11.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,626 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/ik_aim_job.h"
|
||||
|
||||
#include "ozz/base/maths/quaternion.h"
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
#include "ozz/base/maths/simd_quaternion.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
TEST(JobValidity, IKAimJob) {
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
ozz::math::SimdQuaternion quat;
|
||||
|
||||
{ // Default is invalid
|
||||
ozz::animation::IKAimJob job;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Invalid joint matrix
|
||||
ozz::animation::IKAimJob job;
|
||||
job.joint = &joint;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Invalid output
|
||||
ozz::animation::IKAimJob job;
|
||||
job.joint_correction = &quat;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Invalid non normalized forward vector.
|
||||
ozz::animation::IKAimJob job;
|
||||
job.forward = ozz::math::simd_float4::Load(.5f, 0.f, 0.f, 0.f);
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Valid
|
||||
ozz::animation::IKAimJob job;
|
||||
job.joint = &joint;
|
||||
job.joint_correction = &quat;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Correction, IKAimJob) {
|
||||
ozz::math::SimdQuaternion quat;
|
||||
|
||||
ozz::animation::IKAimJob job;
|
||||
job.joint_correction = &quat;
|
||||
|
||||
// Test will be executed with different root transformations
|
||||
const ozz::math::Float4x4 parents[] = {
|
||||
ozz::math::Float4x4::identity(), // No root transformation
|
||||
ozz::math::Float4x4::Translation(ozz::math::simd_float4::y_axis()), // Up
|
||||
ozz::math::Float4x4::FromEuler(ozz::math::simd_float4::Load(
|
||||
ozz::math::kPi / 3.f, 0.f, 0.f, 0.f)), // Rotated
|
||||
ozz::math::Float4x4::Scaling(ozz::math::simd_float4::Load(
|
||||
2.f, 2.f, 2.f, 0.f)), // Uniformly scaled
|
||||
ozz::math::Float4x4::Scaling(ozz::math::simd_float4::Load(
|
||||
1.f, 2.f, 1.f, 0.f)), // Non-uniformly scaled
|
||||
ozz::math::Float4x4::Scaling(
|
||||
ozz::math::simd_float4::Load(-3.f, -3.f, -3.f, 0.f)) // Mirrored
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < OZZ_ARRAY_SIZE(parents); ++i) {
|
||||
const ozz::math::Float4x4& parent = parents[i];
|
||||
job.joint = &parent;
|
||||
|
||||
// These are in joint local-space
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
|
||||
// Pole vector is in model space
|
||||
job.pole_vector = TransformVector(parent, ozz::math::simd_float4::y_axis());
|
||||
|
||||
{ // x
|
||||
job.target = TransformPoint(parent, ozz::math::simd_float4::x_axis());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // -x
|
||||
job.target = TransformPoint(parent, -ozz::math::simd_float4::x_axis());
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_Pi.x, y_Pi.y, y_Pi.z, y_Pi.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // z
|
||||
job.target = TransformPoint(parent, ozz::math::simd_float4::z_axis());
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_mPi_2 =
|
||||
ozz::math::Quaternion::FromAxisAngle(ozz::math::Float3::y_axis(),
|
||||
-ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_mPi_2.x, y_mPi_2.y, y_mPi_2.z,
|
||||
y_mPi_2.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // -z
|
||||
job.target = TransformPoint(parent, -ozz::math::simd_float4::z_axis());
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_Pi_2.x, y_Pi_2.y, y_Pi_2.z, y_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // 45 up y
|
||||
job.target = TransformPoint(
|
||||
parent, ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f));
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_4 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_4);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_4.x, z_Pi_4.y, z_Pi_4.z, z_Pi_4.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // 45 up y, further
|
||||
job.target = TransformPoint(
|
||||
parent, ozz::math::simd_float4::Load(2.f, 2.f, 0.f, 0.f));
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_4 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_4);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_4.x, z_Pi_4.y, z_Pi_4.z, z_Pi_4.w,
|
||||
2e-3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Forward, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
|
||||
job.target = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
|
||||
{ // forward x
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // forward -x
|
||||
job.forward = -ozz::math::simd_float4::x_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), -ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_Pi.x, y_Pi.y, y_Pi.z, y_Pi.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // forward z
|
||||
job.forward = ozz::math::simd_float4::z_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_Pi_2.x, y_Pi_2.y, y_Pi_2.z, y_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Up, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
|
||||
job.target = ozz::math::simd_float4::x_axis();
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
|
||||
{ // up y
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // up -y
|
||||
job.up = -ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_Pi.x, x_Pi.y, x_Pi.z, x_Pi.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // up z
|
||||
job.up = ozz::math::simd_float4::z_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_mPi_2.x, x_mPi_2.y, x_mPi_2.z,
|
||||
x_mPi_2.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // up 2*z
|
||||
job.up =
|
||||
ozz::math::simd_float4::z_axis() * ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_mPi_2.x, x_mPi_2.y, x_mPi_2.z,
|
||||
x_mPi_2.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // up very small z
|
||||
job.up =
|
||||
ozz::math::simd_float4::z_axis() * ozz::math::simd_float4::Load1(1e-9f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_mPi_2.x, x_mPi_2.y, x_mPi_2.z,
|
||||
x_mPi_2.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // up is zero
|
||||
job.up = ozz::math::simd_float4::zero();
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Pole, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
|
||||
job.target = ozz::math::simd_float4::x_axis();
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
|
||||
{ // Pole y
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // Pole -y
|
||||
job.pole_vector = -ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_Pi.x, x_Pi.y, x_Pi.z, x_Pi.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // Pole z
|
||||
job.pole_vector = ozz::math::simd_float4::z_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_Pi_2.x, x_Pi_2.y, x_Pi_2.z, x_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // Pole 2*z
|
||||
job.pole_vector =
|
||||
ozz::math::simd_float4::z_axis() * ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_Pi_2.x, x_Pi_2.y, x_Pi_2.z, x_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // Pole very small z
|
||||
job.pole_vector =
|
||||
ozz::math::simd_float4::z_axis() * ozz::math::simd_float4::Load1(1e-9f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_Pi_2.x, x_Pi_2.y, x_Pi_2.z, x_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Offset, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
|
||||
job.target = ozz::math::simd_float4::x_axis();
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
|
||||
{ // No offset
|
||||
reached = false;
|
||||
job.offset = ozz::math::simd_float4::zero();
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_TRUE(reached);
|
||||
}
|
||||
|
||||
{ // Offset inside target sphere
|
||||
reached = false;
|
||||
job.offset =
|
||||
ozz::math::simd_float4::Load(0.f, ozz::math::kSqrt2_2, 0.f, 0.f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_4 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_4);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_4.x, z_Pi_4.y, z_Pi_4.z, z_Pi_4.w,
|
||||
2e-3f);
|
||||
EXPECT_TRUE(reached);
|
||||
}
|
||||
|
||||
{ // Offset inside target sphere
|
||||
reached = false;
|
||||
job.offset = ozz::math::simd_float4::Load(.5f, .5f, 0.f, 0.f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_6 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi / 6.f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_6.x, z_Pi_6.y, z_Pi_6.z, z_Pi_6.w,
|
||||
2e-3f);
|
||||
EXPECT_TRUE(reached);
|
||||
}
|
||||
|
||||
{ // Offset inside target sphere
|
||||
reached = false;
|
||||
job.offset = ozz::math::simd_float4::Load(-.5f, .5f, 0.f, 0.f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_6 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi / 6.f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_6.x, z_Pi_6.y, z_Pi_6.z, z_Pi_6.w,
|
||||
2e-3f);
|
||||
EXPECT_TRUE(reached);
|
||||
}
|
||||
|
||||
{ // Offset inside target sphere
|
||||
reached = false;
|
||||
job.offset = ozz::math::simd_float4::Load(.5f, 0.f, .5f, 0.f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_Pi_6 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), ozz::math::kPi / 6.f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_Pi_6.x, y_Pi_6.y, y_Pi_6.z, y_Pi_6.w,
|
||||
2e-3f);
|
||||
EXPECT_TRUE(reached);
|
||||
}
|
||||
|
||||
{ // Offset on target sphere
|
||||
reached = false;
|
||||
job.offset = ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 0.f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
EXPECT_TRUE(reached);
|
||||
}
|
||||
|
||||
{ // Offset outside of target sphere, unreachable
|
||||
reached = true;
|
||||
job.offset = ozz::math::simd_float4::Load(0.f, 2.f, 0.f, 0.f);
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_FALSE(reached);
|
||||
}
|
||||
|
||||
const ozz::math::Float4x4 translated_joint =
|
||||
ozz::math::Float4x4::Translation(ozz::math::simd_float4::y_axis());
|
||||
job.joint = &translated_joint;
|
||||
|
||||
{ // Offset inside of target sphere, unreachable
|
||||
reached = false;
|
||||
job.offset = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
EXPECT_TRUE(reached);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Twist, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
|
||||
job.target = ozz::math::simd_float4::x_axis();
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
|
||||
{ // Pole y, twist 0
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.twist_angle = 0.f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // Pole y, twist pi
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.twist_angle = ozz::math::kPi;
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), -ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_Pi.x, x_Pi.y, x_Pi.z, x_Pi.w, 2e-3f);
|
||||
}
|
||||
|
||||
{ // Pole y, twist -pi
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.twist_angle = -ozz::math::kPi;
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_mPi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), -ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_mPi.x, x_mPi.y, x_mPi.z, x_mPi.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // Pole y, twist pi/2
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.twist_angle = ozz::math::kPi_2;
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_Pi_2.x, x_Pi_2.y, x_Pi_2.z, x_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // Pole z, twist pi/2
|
||||
job.pole_vector = ozz::math::simd_float4::z_axis();
|
||||
job.twist_angle = ozz::math::kPi_2;
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion x_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, x_Pi.x, x_Pi.y, x_Pi.z, x_Pi.w, 2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlignedTargetUp, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
|
||||
{ // Not aligned
|
||||
job.target = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // Aligned y
|
||||
job.target = ozz::math::simd_float4::y_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // Aligned 2*y
|
||||
job.target =
|
||||
ozz::math::simd_float4::y_axis() * ozz::math::simd_float4::Load1(2.f);
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // Aligned -2*y
|
||||
job.target =
|
||||
ozz::math::simd_float4::y_axis() * ozz::math::simd_float4::Load1(-2.f);
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_mPi_2.x, z_mPi_2.y, z_mPi_2.z,
|
||||
z_mPi_2.w, 2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlignedTargetPole, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
|
||||
{ // Not aligned
|
||||
job.target = ozz::math::simd_float4::x_axis();
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // Aligned y
|
||||
job.target = ozz::math::simd_float4::y_axis();
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TargetTooClose, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
|
||||
job.target = ozz::math::simd_float4::zero();
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
TEST(Weight, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint = ozz::math::Float4x4::identity();
|
||||
job.joint = &joint;
|
||||
|
||||
job.target = ozz::math::simd_float4::z_axis();
|
||||
job.forward = ozz::math::simd_float4::x_axis();
|
||||
job.up = ozz::math::simd_float4::y_axis();
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
|
||||
{ // Full weight
|
||||
job.weight = 1.f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_mPi2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_mPi2.x, y_mPi2.y, y_mPi2.z, y_mPi2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // > 1
|
||||
job.weight = 2.f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_mPi2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_mPi2.x, y_mPi2.y, y_mPi2.z, y_mPi2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // Half weight
|
||||
job.weight = .5f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
const ozz::math::Quaternion y_mPi4 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), -ozz::math::kPi_4);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, y_mPi4.x, y_mPi4.y, y_mPi4.z, y_mPi4.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
{ // Zero weight
|
||||
job.weight = 0.f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // < 0
|
||||
job.weight = -.5f;
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ZeroScale, IKAimJob) {
|
||||
ozz::animation::IKAimJob job;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.joint_correction = &quat;
|
||||
const ozz::math::Float4x4 joint =
|
||||
ozz::math::Float4x4::Scaling(ozz::math::simd_float4::zero());
|
||||
job.joint = &joint;
|
||||
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(quat, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
@@ -0,0 +1,976 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/ik_two_bone_job.h"
|
||||
|
||||
#include "ozz/base/maths/quaternion.h"
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
#include "ozz/base/maths/simd_quaternion.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
// Implement helper macro that verify that target was reached once ik job is
|
||||
// executed.
|
||||
#define EXPECT_REACHED(_job) \
|
||||
\
|
||||
do { \
|
||||
SCOPED_TRACE(""); \
|
||||
_ExpectReached(_job, true); \
|
||||
} while (void(0), 0)
|
||||
|
||||
#define EXPECT_NOT_REACHED(_job) \
|
||||
\
|
||||
do { \
|
||||
SCOPED_TRACE(""); \
|
||||
_ExpectReached(_job, false); \
|
||||
} while (void(0), 0)
|
||||
|
||||
void _ExpectReached(const ozz::animation::IKTwoBoneJob& _job, bool _reachable) {
|
||||
// Computes local transforms
|
||||
const ozz::math::Float4x4 mid_local =
|
||||
Invert(*_job.start_joint) * *_job.mid_joint;
|
||||
const ozz::math::Float4x4 end_local =
|
||||
Invert(*_job.mid_joint) * *_job.end_joint;
|
||||
|
||||
// Rebuild corrected model transforms
|
||||
const ozz::math::Float4x4 start_correction =
|
||||
ozz::math::Float4x4::FromQuaternion(_job.start_joint_correction->xyzw);
|
||||
const ozz::math::Float4x4 start_corrected =
|
||||
*_job.start_joint * start_correction;
|
||||
const ozz::math::Float4x4 mid_correction =
|
||||
ozz::math::Float4x4::FromQuaternion(_job.mid_joint_correction->xyzw);
|
||||
const ozz::math::Float4x4 mid_corrected =
|
||||
start_corrected * mid_local * mid_correction;
|
||||
const ozz::math::Float4x4 end_corrected = mid_corrected * end_local;
|
||||
|
||||
const ozz::math::SimdFloat4 diff =
|
||||
ozz::math::Length3(end_corrected.cols[3] - _job.target);
|
||||
EXPECT_EQ(ozz::math::GetX(diff) < 1e-2f, _reachable);
|
||||
|
||||
EXPECT_TRUE(_job.reached == nullptr || *_job.reached == _reachable);
|
||||
}
|
||||
|
||||
TEST(JobValidity, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
|
||||
{ // Default is invalid
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Missing start joint matrix
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.start_joint_correction = &quat;
|
||||
job.mid_joint_correction = &quat;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Missing mid joint matrix
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.start_joint_correction = &quat;
|
||||
job.mid_joint_correction = &quat;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Missing end joint matrix
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.start_joint_correction = &quat;
|
||||
job.mid_joint_correction = &quat;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Missing start joint output quaternion
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.mid_joint_correction = &quat;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Missing mid joint output quaternion
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.start_joint_correction = &quat;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Unnormalized mid axis
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.mid_axis =
|
||||
ozz::math::simd_float4::Load(0.f, .70710678f, 0.f, .70710678f);
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.start_joint_correction = &quat;
|
||||
job.mid_joint_correction = &quat;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
|
||||
{ // Valid
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion quat;
|
||||
job.start_joint_correction = &quat;
|
||||
job.mid_joint_correction = &quat;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StartJointCorrection, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 base_start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 base_mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 base_end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
|
||||
const ozz::math::SimdFloat4 mid_axis =
|
||||
ozz::math::Cross3(base_start.cols[3] - base_mid.cols[3],
|
||||
base_end.cols[3] - base_mid.cols[3]);
|
||||
|
||||
// Test will be executed with different root transformations
|
||||
const ozz::math::Float4x4 parents[] = {
|
||||
ozz::math::Float4x4::identity(), // No root transformation
|
||||
ozz::math::Float4x4::Translation(ozz::math::simd_float4::y_axis()), // Up
|
||||
ozz::math::Float4x4::FromEuler(ozz::math::simd_float4::Load(
|
||||
ozz::math::kPi / 3.f, 0.f, 0.f, 0.f)), // Rotated
|
||||
ozz::math::Float4x4::Scaling(ozz::math::simd_float4::Load(
|
||||
2.f, 2.f, 2.f, 0.f)), // Uniformly scaled
|
||||
ozz::math::Float4x4::Scaling(ozz::math::simd_float4::Load(
|
||||
1.f, 2.f, 1.f, 0.f)), // Non-uniformly scaled
|
||||
ozz::math::Float4x4::Scaling(
|
||||
ozz::math::simd_float4::Load(-3.f, -3.f, -3.f, 0.f)) // Mirrored
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < OZZ_ARRAY_SIZE(parents); ++i) {
|
||||
const ozz::math::Float4x4& parent = parents[i];
|
||||
const ozz::math::Float4x4 start = parent * base_start;
|
||||
const ozz::math::Float4x4 mid = parent * base_mid;
|
||||
const ozz::math::Float4x4 end = parent * base_end;
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.pole_vector = TransformVector(parent, ozz::math::simd_float4::y_axis());
|
||||
job.mid_axis = mid_axis;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
{ // No correction expected
|
||||
job.target = TransformPoint(
|
||||
parent, ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f));
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // 90
|
||||
job.target = TransformPoint(
|
||||
parent, ozz::math::simd_float4::Load(0.f, 1.f, 1.f, 0.f));
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion y_mPi_2 =
|
||||
ozz::math::Quaternion::FromAxisAngle(ozz::math::Float3::y_axis(),
|
||||
-ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, y_mPi_2.x, y_mPi_2.y, y_mPi_2.z,
|
||||
y_mPi_2.w, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // 180 behind
|
||||
job.target = TransformPoint(
|
||||
parent, ozz::math::simd_float4::Load(-1.f, 1.f, 0.f, 0.f));
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion y_kPi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, y_kPi.x, y_kPi.y, y_kPi.z, y_kPi.w,
|
||||
2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // 270
|
||||
job.target = TransformPoint(
|
||||
parent, ozz::math::simd_float4::Load(0.f, 1.f, -1.f, 0.f));
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion y_kPi_2 =
|
||||
ozz::math::Quaternion::FromAxisAngle(ozz::math::Float3::y_axis(),
|
||||
ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, y_kPi_2.x, y_kPi_2.y, y_kPi_2.z,
|
||||
y_kPi_2.w, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Pole, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
|
||||
const ozz::math::SimdFloat4 mid_axis =
|
||||
ozz::math::Cross3(start.cols[3] - mid.cols[3], end.cols[3] - mid.cols[3]);
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
job.mid_axis = mid_axis;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
// Pole Y
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f);
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Pole Z
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::z_axis();
|
||||
job.target = ozz::math::simd_float4::Load(1.f, 0.f, 1.f, 0.f);
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion x_kPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, x_kPi_2.x, x_kPi_2.y, x_kPi_2.z,
|
||||
x_kPi_2.w, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Pole -Z
|
||||
{
|
||||
job.pole_vector = -ozz::math::simd_float4::z_axis();
|
||||
job.target = ozz::math::simd_float4::Load(1.f, 0.f, -1.f, 0.f);
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion x_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::x_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, x_mPi_2.x, x_mPi_2.y, x_mPi_2.z,
|
||||
x_mPi_2.w, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Pole X
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::x_axis();
|
||||
job.target = ozz::math::simd_float4::Load(1.f, -1.f, 0.f, 0.f);
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion z_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, z_mPi_2.x, z_mPi_2.y, z_mPi_2.z,
|
||||
z_mPi_2.w, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Pole -X
|
||||
{
|
||||
job.pole_vector = -ozz::math::simd_float4::x_axis();
|
||||
job.target = ozz::math::simd_float4::Load(-1.f, 1.f, 0.f, 0.f);
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ZeroScale, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start =
|
||||
ozz::math::Float4x4::Scaling(ozz::math::simd_float4::zero());
|
||||
const ozz::math::Float4x4 mid = start;
|
||||
const ozz::math::Float4x4 end = start;
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
TEST(Soften, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
const ozz::math::SimdFloat4 mid_axis =
|
||||
ozz::math::Cross3(start.cols[3] - mid.cols[3], end.cols[3] - mid.cols[3]);
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
job.mid_axis = mid_axis;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
// Reachable
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 0.f);
|
||||
job.soften = 1.f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion z_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, z_mPi_2.x, z_mPi_2.y, z_mPi_2.z,
|
||||
z_mPi_2.w, 2e-3f);
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
// Reachable, softened
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f * .5f, 0.f, 0.f, 0.f);
|
||||
job.soften = .5f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
}
|
||||
|
||||
// Reachable, softened
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f * .4f, 0.f, 0.f, 0.f);
|
||||
job.soften = .5f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
}
|
||||
|
||||
// Not reachable, softened
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f * .6f, 0.f, 0.f, 0.f);
|
||||
job.soften = .5f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
}
|
||||
|
||||
// Not reachable, softened at max
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f * .6f, 0.f, 0.f, 0.f);
|
||||
job.soften = 0.f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
}
|
||||
|
||||
// Not reachable, softened
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 0.f);
|
||||
job.soften = .5f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
}
|
||||
|
||||
// Not reachable, a bit too far
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(3.f, 0.f, 0.f, 0.f);
|
||||
job.soften = 1.f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Twist, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
const ozz::math::SimdFloat4 mid_axis =
|
||||
ozz::math::Cross3(start.cols[3] - mid.cols[3], end.cols[3] - mid.cols[3]);
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f);
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
job.mid_axis = mid_axis;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
// Twist angle 0
|
||||
{
|
||||
job.twist_angle = 0.f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Twist angle pi / 2
|
||||
{
|
||||
job.twist_angle = ozz::math::kPi_2;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion h_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3(.70710678f, .70710678f, 0.f), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, h_Pi_2.x, h_Pi_2.y, h_Pi_2.z, h_Pi_2.w,
|
||||
2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Twist angle pi
|
||||
{
|
||||
job.twist_angle = ozz::math::kPi;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion h_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3(.70710678f, .70710678f, 0.f), -ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, h_Pi.x, h_Pi.y, h_Pi.z, h_Pi.w, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Twist angle 2pi
|
||||
{
|
||||
job.twist_angle = ozz::math::kPi * 2.f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Weight, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
const ozz::math::SimdFloat4 mid_axis =
|
||||
ozz::math::Cross3(start.cols[3] - mid.cols[3], end.cols[3] - mid.cols[3]);
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
job.mid_axis = mid_axis;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
// Maximum weight
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 0.f);
|
||||
job.weight = 1.f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion z_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, z_mPi_2.x, z_mPi_2.y, z_mPi_2.z,
|
||||
z_mPi_2.w, 2e-3f);
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
// Weight > 1 is clamped
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 0.f);
|
||||
job.weight = 1.1f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion z_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, z_mPi_2.x, z_mPi_2.y, z_mPi_2.z,
|
||||
z_mPi_2.w, 2e-3f);
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
// 0 weight
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 0.f);
|
||||
job.weight = 0.f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_EST(qstart, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDQUATERNION_EQ_EST(qmid, 0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
// Weight < 0 is clamped
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 0.f);
|
||||
job.weight = -.1f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_EST(qstart, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDQUATERNION_EQ_EST(qmid, 0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
// .5 weight
|
||||
{
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 0.f);
|
||||
job.weight = .5f;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion z_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2 * job.weight);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, z_mPi_2.x, z_mPi_2.y, z_mPi_2.z,
|
||||
z_mPi_2.w, 2e-3f);
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2 * job.weight);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PoleTargetAlignment, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
const ozz::math::SimdFloat4 mid_axis =
|
||||
ozz::math::Cross3(start.cols[3] - mid.cols[3], end.cols[3] - mid.cols[3]);
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
job.mid_axis = mid_axis;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
{ // Reachable, undefined qstart
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(0.f, ozz::math::kSqrt2, 0.f, 0.f);
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
// qstart is undefined, many solutions in this case
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // Reachable, defined qstart
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target =
|
||||
ozz::math::simd_float4::Load(.001f, ozz::math::kSqrt2, 0.f, 0.f);
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion z_Pi_4 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_4);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, z_Pi_4.x, z_Pi_4.y, z_Pi_4.z, z_Pi_4.w,
|
||||
2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
{ // Full extent, undefined qstart, end not reached
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(0.f, 3.f, 0.f, 0.f);
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
// qstart is undefined, many solutions in this case
|
||||
const ozz::math::Quaternion z_Pi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, z_Pi_2.x, z_Pi_2.y, z_Pi_2.z, z_Pi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MidAxis, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
const ozz::math::SimdFloat4 mid_axis =
|
||||
ozz::math::Cross3(start.cols[3] - mid.cols[3], end.cols[3] - mid.cols[3]);
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f);
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
// Positive mid_axis
|
||||
{
|
||||
job.mid_axis = mid_axis;
|
||||
job.target = ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Negative mid_axis
|
||||
{
|
||||
job.mid_axis = -mid_axis;
|
||||
job.target = ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
const ozz::math::Quaternion y_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::y_axis(), ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, y_Pi.x, y_Pi.y, y_Pi.z, y_Pi.w, 2e-3f);
|
||||
const ozz::math::Quaternion z_Pi = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), ozz::math::kPi);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, z_Pi.x, z_Pi.y, z_Pi.z, z_Pi.w, 2e-3f);
|
||||
}
|
||||
|
||||
// Aligned joints
|
||||
{
|
||||
// Replaces "end" joint matrix to align the 3 joints.
|
||||
const ozz::math::Float4x4 aligned_end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::Load(0.f, 2.f, 0.f, 0.f));
|
||||
job.end_joint = &aligned_end;
|
||||
|
||||
job.mid_axis = mid_axis;
|
||||
job.target = ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
// Restore end joint matrix
|
||||
job.end_joint = &end;
|
||||
|
||||
// Start rotates 180 on y, to allow Mid to turn positively on z axis.
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
const ozz::math::Quaternion z_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, z_mPi_2.x, z_mPi_2.y, z_mPi_2.z,
|
||||
z_mPi_2.w, 2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlignedJointsAndTarget, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid =
|
||||
ozz::math::Float4x4::Translation(ozz::math::simd_float4::x_axis());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::x_axis());
|
||||
const ozz::math::SimdFloat4 mid_axis = ozz::math::simd_float4::z_axis();
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.mid_axis = mid_axis;
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
// Aligned and reachable
|
||||
{
|
||||
job.target = ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_REACHED(job);
|
||||
|
||||
// Start rotates 180 on y, to allow Mid to turn positively on z axis.
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
|
||||
// Aligned and unreachable
|
||||
{
|
||||
job.target = ozz::math::simd_float4::Load(3.f, 0.f, 0.f, 0.f);
|
||||
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
|
||||
// Start rotates 180 on y, to allow Mid to turn positively on z axis.
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ZeroLengthStartTarget, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::Load1(ozz::math::kPi_2))
|
||||
.xyzw,
|
||||
ozz::math::simd_float4::one());
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::x_axis() + ozz::math::simd_float4::y_axis());
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = start.cols[3]; // 0 length from start to target
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
bool reached;
|
||||
job.reached = &reached;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qstart, 0.f, 0.f, 0.f, 1.f, 2e-3f);
|
||||
// Mid joint is bent -90 degrees to reach start.
|
||||
const ozz::math::Quaternion z_mPi_2 = ozz::math::Quaternion::FromAxisAngle(
|
||||
ozz::math::Float3::z_axis(), -ozz::math::kPi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ_TOL(qmid, z_mPi_2.x, z_mPi_2.y, z_mPi_2.z, z_mPi_2.w,
|
||||
2e-3f);
|
||||
}
|
||||
|
||||
TEST(ZeroLengthBoneChain, IKTwoBoneJob) {
|
||||
// Setup initial pose
|
||||
const ozz::math::Float4x4 start = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 mid = ozz::math::Float4x4::identity();
|
||||
const ozz::math::Float4x4 end = ozz::math::Float4x4::identity();
|
||||
|
||||
// Prepares job.
|
||||
ozz::animation::IKTwoBoneJob job;
|
||||
job.pole_vector = ozz::math::simd_float4::y_axis();
|
||||
job.target = ozz::math::simd_float4::x_axis();
|
||||
job.start_joint = &start;
|
||||
job.mid_joint = ∣
|
||||
job.end_joint = &end;
|
||||
ozz::math::SimdQuaternion qstart;
|
||||
job.start_joint_correction = &qstart;
|
||||
ozz::math::SimdQuaternion qmid;
|
||||
job.mid_joint_correction = &qmid;
|
||||
ASSERT_TRUE(job.Validate());
|
||||
|
||||
// Just expecting it's not crashing
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
EXPECT_NOT_REACHED(job);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,640 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/animation/offline/animation_builder.h"
|
||||
#include "ozz/animation/offline/raw_animation.h"
|
||||
#include "ozz/animation/runtime/animation.h"
|
||||
#include "ozz/animation/runtime/sampling_job.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
using ozz::animation::Animation;
|
||||
using ozz::animation::SamplingCache;
|
||||
using ozz::animation::SamplingJob;
|
||||
using ozz::animation::offline::AnimationBuilder;
|
||||
using ozz::animation::offline::RawAnimation;
|
||||
|
||||
TEST(JobValidity, SamplingJob) {
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(1);
|
||||
|
||||
AnimationBuilder builder;
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
// Allocates cache.
|
||||
SamplingCache cache(1);
|
||||
|
||||
{ // Empty/default job
|
||||
SamplingJob job;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid output
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid animation.
|
||||
ozz::math::SoaTransform output[1];
|
||||
|
||||
SamplingJob job;
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid cache.
|
||||
ozz::math::SoaTransform output[1];
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.output = output;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid cache size.
|
||||
SamplingCache zero_cache(0);
|
||||
ozz::math::SoaTransform output[1];
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.cache = &zero_cache;
|
||||
job.output = output;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid job with smaller output.
|
||||
ozz::math::SoaTransform* output = nullptr;
|
||||
SamplingJob job;
|
||||
job.ratio =
|
||||
2155.f; // Any time ratio can be set, it's clamped in unit interval.
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = ozz::span<ozz::math::SoaTransform>(output, size_t(0));
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid job.
|
||||
ozz::math::SoaTransform output[1];
|
||||
SamplingJob job;
|
||||
job.ratio = 2155.f; // Any time can be set.
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid job with bigger cache.
|
||||
SamplingCache big_cache(2);
|
||||
ozz::math::SoaTransform output[1];
|
||||
SamplingJob job;
|
||||
job.ratio = 2155.f; // Any time can be set.
|
||||
job.animation = animation.get();
|
||||
job.cache = &big_cache;
|
||||
job.output = output;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid job with bigger output.
|
||||
ozz::math::SoaTransform output[2];
|
||||
SamplingJob job;
|
||||
job.ratio = 2155.f; // Any time can be set.
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
|
||||
{ // Default animation.
|
||||
ozz::math::SoaTransform output[1];
|
||||
Animation default_animation;
|
||||
SamplingJob job;
|
||||
job.animation = &default_animation;
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Sampling, SamplingJob) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
AnimationBuilder builder;
|
||||
|
||||
// Building an Animation with unsorted keys fails.
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(4);
|
||||
|
||||
SamplingCache cache(4);
|
||||
|
||||
// Raw animation inputs.
|
||||
// 0 1
|
||||
// -----------------------
|
||||
// 0 - | A |
|
||||
// 1 - | |
|
||||
// 2 - B C D E F
|
||||
// 3 - | G H |
|
||||
|
||||
// Final animation.
|
||||
// 0 1
|
||||
// -----------------------
|
||||
// 0 - A-1 4
|
||||
// 1 - 1 5
|
||||
// 2 - B2 C6 D8 E10 F11
|
||||
// 3 - 3 G7 H9 12
|
||||
|
||||
struct {
|
||||
float sample_time;
|
||||
float trans[12];
|
||||
} result[] = {
|
||||
{-.2f, {-1.f, 0.f, 2.f, 7.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.0f, {-1.f, 0.f, 2.f, 7.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.0000001f,
|
||||
{-1.f, 0.f, 2.f, 7.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.1f, {-1.f, 0.f, 4.f, 7.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.2f, {-1.f, 0.f, 6.f, 7.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.3f, {-1.f, 0.f, 7.f, 7.5, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.4f, {-1.f, 0.f, 8.f, 8.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.3999999f,
|
||||
{-1.f, 0.f, 8.f, 8.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.4000001f,
|
||||
{-1.f, 0.f, 8.f, 8.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.5f, {-1.f, 0.f, 9.f, 8.5f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.6f, {-1.f, 0.f, 10.f, 9.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.9999999f,
|
||||
{-1.f, 0.f, 11.f, 9.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{1.f, {-1.f, 0.f, 11.f, 9.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{1.000001f,
|
||||
{-1.f, 0.f, 11.f, 9.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.5f, {-1.f, 0.f, 9.f, 8.5f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.9999999f,
|
||||
{-1.f, 0.f, 11.f, 9.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}},
|
||||
{.0000001f,
|
||||
{-1.f, 0.f, 2.f, 7.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}}};
|
||||
|
||||
RawAnimation::TranslationKey a = {.2f, ozz::math::Float3(-1.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[0].translations.push_back(a);
|
||||
|
||||
RawAnimation::TranslationKey b = {0.f, ozz::math::Float3(2.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(b);
|
||||
RawAnimation::TranslationKey c = {0.2f, ozz::math::Float3(6.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(c);
|
||||
RawAnimation::TranslationKey d = {0.4f, ozz::math::Float3(8.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(d);
|
||||
RawAnimation::TranslationKey e = {0.6f, ozz::math::Float3(10.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(e);
|
||||
RawAnimation::TranslationKey f = {1.f, ozz::math::Float3(11.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].translations.push_back(f);
|
||||
|
||||
RawAnimation::TranslationKey g = {0.2f, ozz::math::Float3(7.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[3].translations.push_back(g);
|
||||
RawAnimation::TranslationKey h = {0.6f, ozz::math::Float3(9.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[3].translations.push_back(h);
|
||||
|
||||
// Builds animation
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
ozz::math::SoaTransform output[1];
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
|
||||
for (size_t i = 0; i < OZZ_ARRAY_SIZE(result); ++i) {
|
||||
memset(output, 0xde, sizeof(output));
|
||||
job.ratio = result[i].sample_time / animation->duration();
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ_EST(
|
||||
output[0].translation, result[i].trans[0], result[i].trans[1],
|
||||
result[i].trans[2], result[i].trans[3], result[i].trans[4],
|
||||
result[i].trans[5], result[i].trans[6], result[i].trans[7],
|
||||
result[i].trans[8], result[i].trans[9], result[i].trans[10],
|
||||
result[i].trans[11]);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f,
|
||||
1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SamplingNoTrack, SamplingJob) {
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 46.f;
|
||||
|
||||
SamplingCache cache(1);
|
||||
|
||||
AnimationBuilder builder;
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
ozz::math::SoaTransform test_output[1];
|
||||
ozz::math::SoaTransform output[1];
|
||||
memset(test_output, 0xde, sizeof(test_output));
|
||||
memset(output, 0xde, sizeof(output));
|
||||
|
||||
SamplingJob job;
|
||||
job.ratio = 0.f;
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
// Tests output.
|
||||
EXPECT_EQ(memcmp(test_output, output, sizeof(output)), 0);
|
||||
}
|
||||
|
||||
TEST(Sampling1Track0Key, SamplingJob) {
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 46.f;
|
||||
raw_animation.tracks.resize(1); // Adds a joint.
|
||||
|
||||
SamplingCache cache(1);
|
||||
|
||||
AnimationBuilder builder;
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
ozz::math::SoaTransform output[1];
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
|
||||
for (float t = -.2f; t < 1.2f; t += .1f) {
|
||||
memset(output, 0xde, sizeof(output));
|
||||
job.ratio = t;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f,
|
||||
1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Sampling1Track1Key, SamplingJob) {
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 46.f;
|
||||
raw_animation.tracks.resize(1); // Adds a joint.
|
||||
|
||||
SamplingCache cache(1);
|
||||
|
||||
const RawAnimation::TranslationKey tkey = {.3f,
|
||||
ozz::math::Float3(1.f, -1.f, 5.f)};
|
||||
raw_animation.tracks[0].translations.push_back(tkey); // Adds a key.
|
||||
|
||||
AnimationBuilder builder;
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
ozz::math::SoaTransform output[1];
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
|
||||
for (float t = -.2f; t < 1.2f; t += .1f) {
|
||||
memset(output, 0xde, sizeof(output));
|
||||
job.ratio = t;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 0.f, 0.f, 0.f, -1.f,
|
||||
0.f, 0.f, 0.f, 5.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f,
|
||||
1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Sampling1Track2Keys, SamplingJob) {
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 46.f;
|
||||
raw_animation.tracks.resize(1); // Adds a joint.
|
||||
|
||||
SamplingCache cache(1);
|
||||
|
||||
const RawAnimation::TranslationKey tkey0 = {.5f,
|
||||
ozz::math::Float3(1.f, 2.f, 4.f)};
|
||||
raw_animation.tracks[0].translations.push_back(tkey0); // Adds a key.
|
||||
const RawAnimation::TranslationKey tkey1 = {.8f,
|
||||
ozz::math::Float3(2.f, 4.f, 8.f)};
|
||||
raw_animation.tracks[0].translations.push_back(tkey1); // Adds a key.
|
||||
|
||||
AnimationBuilder builder;
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
ozz::math::SoaTransform output[1];
|
||||
memset(output, 0xde, sizeof(output));
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
|
||||
// Samples at t = 0.
|
||||
job.ratio = 0.f;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 0.f, 0.f, 0.f, 2.f, 0.f,
|
||||
0.f, 0.f, 4.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// Samples at t = tkey0.
|
||||
job.ratio = tkey0.time / animation->duration();
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 0.f, 0.f, 0.f, 2.f, 0.f,
|
||||
0.f, 0.f, 4.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// Samples at t = tkey1.
|
||||
job.ratio = tkey1.time / animation->duration();
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 2.f, 0.f, 0.f, 0.f, 4.f, 0.f,
|
||||
0.f, 0.f, 8.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// Samples at t = end.
|
||||
job.ratio = 1.f;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 2.f, 0.f, 0.f, 0.f, 4.f, 0.f,
|
||||
0.f, 0.f, 8.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// Samples at tkey0.time < t < tkey1.time.
|
||||
job.ratio = (tkey0.time / animation->duration() +
|
||||
tkey1.time / animation->duration()) /
|
||||
2.f;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.5f, 0.f, 0.f, 0.f, 3.f, 0.f,
|
||||
0.f, 0.f, 6.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(Sampling4Track2Keys, SamplingJob) {
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 1.f;
|
||||
raw_animation.tracks.resize(4); // Adds a joint.
|
||||
|
||||
SamplingCache cache(1);
|
||||
|
||||
const RawAnimation::TranslationKey tkey00 = {
|
||||
.5f, ozz::math::Float3(1.f, 2.f, 4.f)};
|
||||
raw_animation.tracks[0].translations.push_back(tkey00); // Adds a key.
|
||||
const RawAnimation::TranslationKey tkey01 = {
|
||||
.8f, ozz::math::Float3(2.f, 4.f, 8.f)};
|
||||
raw_animation.tracks[0].translations.push_back(tkey01); // Adds a key.
|
||||
|
||||
// This quaternion will be negated as the builder ensures that the first key
|
||||
// is in identity quaternion hemisphere.
|
||||
const RawAnimation::RotationKey rkey10 = {
|
||||
0.f, ozz::math::Quaternion(0.f, 0.f, 0.f, -1.f)};
|
||||
raw_animation.tracks[1].rotations.push_back(rkey10); // Adds a key.
|
||||
const RawAnimation::RotationKey rkey11 = {
|
||||
1.f, ozz::math::Quaternion(0.f, 1.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[1].rotations.push_back(rkey11); // Adds a key.
|
||||
|
||||
const RawAnimation::ScaleKey skey20 = {.5f, ozz::math::Float3(0.f, 0.f, 0.f)};
|
||||
raw_animation.tracks[2].scales.push_back(skey20); // Adds a key.
|
||||
const RawAnimation::ScaleKey skey21 = {.8f,
|
||||
ozz::math::Float3(-1.f, -1.f, -1.f)};
|
||||
raw_animation.tracks[2].scales.push_back(skey21); // Adds a key.
|
||||
|
||||
const RawAnimation::TranslationKey tkey30 = {
|
||||
0.f, ozz::math::Float3(-1.f, -2.f, -4.f)};
|
||||
raw_animation.tracks[3].translations.push_back(tkey30); // Adds a key.
|
||||
const RawAnimation::TranslationKey tkey31 = {
|
||||
1.f, ozz::math::Float3(-2.f, -4.f, -8.f)};
|
||||
raw_animation.tracks[3].translations.push_back(tkey31); // Adds a key.
|
||||
|
||||
AnimationBuilder builder;
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
ozz::math::SoaTransform output[1];
|
||||
memset(output, 0xde, sizeof(output));
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.output = output;
|
||||
|
||||
// Samples at t = 0.
|
||||
job.ratio = 0.f;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 0.f, 0.f, -1.f, 2.f, 0.f,
|
||||
0.f, -2.f, 4.f, 0.f, 0.f, -4.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 0.f,
|
||||
1.f, 1.f, 1.f, 0.f, 1.f);
|
||||
|
||||
// Samples at t = tkey00.
|
||||
job.ratio = tkey00.time / animation->duration();
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 0.f, 0.f, -1.5f, 2.f, 0.f,
|
||||
0.f, -3.f, 4.f, 0.f, 0.f, -6.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
.7071067f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f,
|
||||
.7071067f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 0.f,
|
||||
1.f, 1.f, 1.f, 0.f, 1.f);
|
||||
|
||||
// Samples at t = end.
|
||||
job.ratio = 1.f;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 2.f, 0.f, 0.f, -2.f, 4.f, 0.f,
|
||||
0.f, -4.f, 8.f, 0.f, 0.f, -8.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, -1.f, 1.f, 1.f, 1.f, -1.f,
|
||||
1.f, 1.f, 1.f, -1.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(Cache, SamplingJob) {
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 46.f;
|
||||
raw_animation.tracks.resize(1); // Adds a joint.
|
||||
const RawAnimation::TranslationKey empty_key = {
|
||||
0.f, RawAnimation::TranslationKey::identity()};
|
||||
raw_animation.tracks[0].translations.push_back(empty_key);
|
||||
|
||||
SamplingCache cache(1);
|
||||
ozz::unique_ptr<Animation> animations[2];
|
||||
|
||||
{
|
||||
const RawAnimation::TranslationKey tkey = {
|
||||
.3f, ozz::math::Float3(1.f, -1.f, 5.f)};
|
||||
raw_animation.tracks[0].translations[0] = tkey;
|
||||
|
||||
AnimationBuilder builder;
|
||||
animations[0] = builder(raw_animation);
|
||||
ASSERT_TRUE(animations[0]);
|
||||
}
|
||||
{
|
||||
const RawAnimation::TranslationKey tkey = {
|
||||
.3f, ozz::math::Float3(-1.f, 1.f, -5.f)};
|
||||
raw_animation.tracks[0].translations[0] = tkey;
|
||||
|
||||
AnimationBuilder builder;
|
||||
animations[1] = builder(raw_animation);
|
||||
ASSERT_TRUE(animations[1]);
|
||||
}
|
||||
|
||||
ozz::math::SoaTransform output[1];
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animations[0].get();
|
||||
job.cache = &cache;
|
||||
job.ratio = 0.f;
|
||||
job.output = output;
|
||||
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 0.f, 0.f, 0.f, -1.f, 0.f,
|
||||
0.f, 0.f, 5.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// Re-uses cache.
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 0.f, 0.f, 0.f, -1.f, 0.f,
|
||||
0.f, 0.f, 5.f, 0.f, 0.f, 0.f);
|
||||
|
||||
// Invalidates cache.
|
||||
cache.Invalidate();
|
||||
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, 1.f, 0.f, 0.f, 0.f, -1.f, 0.f,
|
||||
0.f, 0.f, 5.f, 0.f, 0.f, 0.f);
|
||||
|
||||
// Changes animation.
|
||||
job.animation = animations[1].get();
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, -1.f, 0.f, 0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, -5.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(output[0].rotation, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].scale, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// Invalidates and changes animation.
|
||||
job.animation = animations[1].get();
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_SOAFLOAT3_EQ_EST(output[0].translation, -1.f, 0.f, 0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, -5.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(CacheResize, SamplingJob) {
|
||||
RawAnimation raw_animation;
|
||||
raw_animation.duration = 46.f;
|
||||
raw_animation.tracks.resize(7);
|
||||
|
||||
AnimationBuilder builder;
|
||||
ozz::unique_ptr<Animation> animation(builder(raw_animation));
|
||||
ASSERT_TRUE(animation);
|
||||
|
||||
// Empty cache by default
|
||||
SamplingCache cache;
|
||||
|
||||
ozz::math::SoaTransform output[7];
|
||||
|
||||
SamplingJob job;
|
||||
job.animation = animation.get();
|
||||
job.cache = &cache;
|
||||
job.ratio = 0.f;
|
||||
job.output = output;
|
||||
|
||||
// Cache is too small
|
||||
EXPECT_FALSE(job.Validate());
|
||||
|
||||
// Cache is ok.
|
||||
cache.Resize(7);
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
|
||||
// Cache is too small
|
||||
cache.Resize(1);
|
||||
EXPECT_FALSE(job.Validate());
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_skeleton.h"
|
||||
#include "ozz/animation/offline/skeleton_builder.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
using ozz::animation::Skeleton;
|
||||
using ozz::animation::offline::RawSkeleton;
|
||||
using ozz::animation::offline::SkeletonBuilder;
|
||||
|
||||
TEST(Empty, SkeletonSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
|
||||
Skeleton o_skeleton;
|
||||
o << o_skeleton;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
Skeleton i_skeleton;
|
||||
i >> i_skeleton;
|
||||
|
||||
EXPECT_EQ(o_skeleton.num_joints(), i_skeleton.num_joints());
|
||||
}
|
||||
|
||||
TEST(Filled, SkeletonSerialize) {
|
||||
ozz::unique_ptr<Skeleton> o_skeleton;
|
||||
/* Builds output skeleton.
|
||||
3 joints
|
||||
|
||||
*
|
||||
|
|
||||
root
|
||||
/ \
|
||||
j0 j1
|
||||
*/
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& root = raw_skeleton.roots[0];
|
||||
root.name = "root";
|
||||
|
||||
root.children.resize(2);
|
||||
root.children[0].name = "j0";
|
||||
root.children[1].name = "j1";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 3);
|
||||
|
||||
SkeletonBuilder builder;
|
||||
o_skeleton = builder(raw_skeleton);
|
||||
ASSERT_TRUE(o_skeleton);
|
||||
}
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << *o_skeleton;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive ia(&stream);
|
||||
|
||||
Skeleton i_skeleton;
|
||||
ia >> i_skeleton;
|
||||
|
||||
// Compares skeletons.
|
||||
EXPECT_EQ(o_skeleton->num_joints(), i_skeleton.num_joints());
|
||||
for (int i = 0; i < i_skeleton.num_joints(); ++i) {
|
||||
EXPECT_EQ(i_skeleton.joint_parents()[i],
|
||||
o_skeleton->joint_parents()[i]);
|
||||
EXPECT_STREQ(i_skeleton.joint_names()[i], o_skeleton->joint_names()[i]);
|
||||
}
|
||||
for (int i = 0; i < (i_skeleton.num_joints() + 3) / 4; ++i) {
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(
|
||||
i_skeleton.joint_bind_poses()[i].translation ==
|
||||
o_skeleton->joint_bind_poses()[i].translation));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(
|
||||
i_skeleton.joint_bind_poses()[i].rotation ==
|
||||
o_skeleton->joint_bind_poses()[i].rotation));
|
||||
EXPECT_TRUE(
|
||||
ozz::math::AreAllTrue(i_skeleton.joint_bind_poses()[i].scale ==
|
||||
o_skeleton->joint_bind_poses()[i].scale));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AlreadyInitialized, SkeletonSerialize) {
|
||||
ozz::unique_ptr<Skeleton> o_skeleton[2];
|
||||
/* Builds output skeleton.
|
||||
3 joints
|
||||
|
||||
*
|
||||
|
|
||||
root
|
||||
/ \
|
||||
j0 j1
|
||||
*/
|
||||
{
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
raw_skeleton.roots[0].name = "root0";
|
||||
|
||||
SkeletonBuilder builder;
|
||||
o_skeleton[0] = builder(raw_skeleton);
|
||||
ASSERT_TRUE(o_skeleton[0]);
|
||||
|
||||
raw_skeleton.roots.resize(2);
|
||||
raw_skeleton.roots[1].name = "root1";
|
||||
o_skeleton[1] = builder(raw_skeleton);
|
||||
ASSERT_TRUE(o_skeleton[1]);
|
||||
}
|
||||
|
||||
{
|
||||
// Streams out.
|
||||
ozz::io::MemoryStream stream;
|
||||
ozz::io::OArchive o(&stream);
|
||||
o << *o_skeleton[0];
|
||||
o << *o_skeleton[1];
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
// Reads and check the first skeleton.
|
||||
Skeleton i_skeleton;
|
||||
i >> i_skeleton;
|
||||
ASSERT_EQ(o_skeleton[0]->num_joints(), 1);
|
||||
EXPECT_STREQ(i_skeleton.joint_names()[0], o_skeleton[0]->joint_names()[0]);
|
||||
|
||||
// Reuse the skeleton a second time.
|
||||
i >> i_skeleton;
|
||||
ASSERT_EQ(o_skeleton[1]->num_joints(), 2);
|
||||
EXPECT_STREQ(i_skeleton.joint_names()[0], o_skeleton[1]->joint_names()[0]);
|
||||
EXPECT_STREQ(i_skeleton.joint_names()[1], o_skeleton[1]->joint_names()[1]);
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
#include "ozz/base/log.h"
|
||||
#include "ozz/options/options.h"
|
||||
|
||||
OZZ_OPTIONS_DECLARE_STRING(file, "Specifies input file", "", true)
|
||||
OZZ_OPTIONS_DECLARE_INT(joints, "Number of joints", 0, true)
|
||||
OZZ_OPTIONS_DECLARE_STRING(root_name, "Name of the root joint", "", true)
|
||||
|
||||
int main(int _argc, char** _argv) {
|
||||
// Parses arguments.
|
||||
testing::InitGoogleTest(&_argc, _argv);
|
||||
ozz::options::ParseResult parse_result = ozz::options::ParseCommandLine(
|
||||
_argc, _argv, "1.0",
|
||||
"Test Skeleton archive versioning retrocompatibility");
|
||||
if (parse_result != ozz::options::kSuccess) {
|
||||
return parse_result == ozz::options::kExitSuccess ? EXIT_SUCCESS
|
||||
: EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
TEST(Versioning, SkeletonSerialize) {
|
||||
// Open the file.
|
||||
const char* filename = OPTIONS_file;
|
||||
ozz::io::File file(filename, "rb");
|
||||
ASSERT_TRUE(file.opened());
|
||||
|
||||
// Open archive and test object tag.
|
||||
ozz::io::IArchive archive(&file);
|
||||
ASSERT_TRUE(archive.TestTag<ozz::animation::Skeleton>());
|
||||
|
||||
// Read the object.
|
||||
ozz::animation::Skeleton skeleton;
|
||||
archive >> skeleton;
|
||||
|
||||
// More testing
|
||||
EXPECT_EQ(skeleton.num_joints(), OPTIONS_joints);
|
||||
if (skeleton.num_joints()) {
|
||||
EXPECT_STREQ(skeleton.joint_names()[0], OPTIONS_root_name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/offline/raw_skeleton.h"
|
||||
#include "ozz/animation/offline/skeleton_builder.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
#include "ozz/animation/runtime/skeleton_utils.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
using ozz::animation::Skeleton;
|
||||
using ozz::animation::offline::RawSkeleton;
|
||||
using ozz::animation::offline::SkeletonBuilder;
|
||||
|
||||
TEST(JointBindPose, SkeletonUtils) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(1);
|
||||
RawSkeleton::Joint& r = raw_skeleton.roots[0];
|
||||
r.name = "r0";
|
||||
r.transform.translation = ozz::math::Float3::x_axis();
|
||||
r.transform.rotation = ozz::math::Quaternion::identity();
|
||||
r.transform.scale = ozz::math::Float3::zero();
|
||||
|
||||
r.children.resize(2);
|
||||
RawSkeleton::Joint& c0 = r.children[0];
|
||||
c0.name = "j0";
|
||||
c0.transform.translation = ozz::math::Float3::y_axis();
|
||||
c0.transform.rotation = -ozz::math::Quaternion::identity();
|
||||
c0.transform.scale = -ozz::math::Float3::one();
|
||||
|
||||
RawSkeleton::Joint& c1 = r.children[1];
|
||||
c1.name = "j1";
|
||||
c1.transform.translation = ozz::math::Float3::z_axis();
|
||||
c1.transform.rotation = Conjugate(ozz::math::Quaternion::identity());
|
||||
c1.transform.scale = ozz::math::Float3::one();
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 3);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 3);
|
||||
|
||||
// Out of range.
|
||||
EXPECT_ASSERTION(GetJointLocalBindPose(*skeleton, 3),
|
||||
"Joint index out of range.");
|
||||
|
||||
const ozz::math::Transform bind_pose0 = GetJointLocalBindPose(*skeleton, 0);
|
||||
EXPECT_FLOAT3_EQ(bind_pose0.translation, 1.f, 0.f, 0.f);
|
||||
EXPECT_QUATERNION_EQ(bind_pose0.rotation, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT3_EQ(bind_pose0.scale, 0.f, 0.f, 0.f);
|
||||
|
||||
const ozz::math::Transform bind_pose1 = GetJointLocalBindPose(*skeleton, 1);
|
||||
EXPECT_FLOAT3_EQ(bind_pose1.translation, 0.f, 1.f, 0.f);
|
||||
EXPECT_QUATERNION_EQ(bind_pose1.rotation, 0.f, 0.f, 0.f, -1.f);
|
||||
EXPECT_FLOAT3_EQ(bind_pose1.scale, -1.f, -1.f, -1.f);
|
||||
|
||||
const ozz::math::Transform bind_pose2 = GetJointLocalBindPose(*skeleton, 2);
|
||||
EXPECT_FLOAT3_EQ(bind_pose2.translation, 0.f, 0.f, 1.f);
|
||||
EXPECT_QUATERNION_EQ(bind_pose2.rotation, -0.f, -0.f, -0.f, 1.f);
|
||||
EXPECT_FLOAT3_EQ(bind_pose2.scale, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
/* Definition of the skeleton used by the tests.
|
||||
10 joints, 2 roots
|
||||
|
||||
*
|
||||
/ \
|
||||
j0 j8
|
||||
/ \ \
|
||||
j1 j4 j9
|
||||
| / \
|
||||
j2 j5 j6
|
||||
| |
|
||||
j3 j7
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
class IterateDFFailTester {
|
||||
public:
|
||||
void operator()(int, int) { ASSERT_TRUE(false); }
|
||||
};
|
||||
|
||||
class IterateDFTester {
|
||||
public:
|
||||
IterateDFTester(const ozz::animation::Skeleton* _skeleton, int _start)
|
||||
: skeleton_(_skeleton), start_(_start), num_iterations_(0) {}
|
||||
|
||||
void operator()(int _current, int _parent) {
|
||||
const int joint = start_ + num_iterations_;
|
||||
EXPECT_EQ(joint, _current);
|
||||
EXPECT_EQ(skeleton_->joint_parents()[joint], _parent);
|
||||
++num_iterations_;
|
||||
}
|
||||
|
||||
int num_iterations() const { return num_iterations_; }
|
||||
|
||||
private:
|
||||
// Iterated skeleton.
|
||||
const ozz::animation::Skeleton* skeleton_;
|
||||
|
||||
// First joint to explore.
|
||||
int start_;
|
||||
|
||||
// Number of iterations completed.
|
||||
int num_iterations_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(InterateDF, SkeletonUtils) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(2);
|
||||
RawSkeleton::Joint& j0 = raw_skeleton.roots[0];
|
||||
j0.name = "j0";
|
||||
RawSkeleton::Joint& j8 = raw_skeleton.roots[1];
|
||||
j8.name = "j8";
|
||||
|
||||
j0.children.resize(2);
|
||||
j0.children[0].name = "j1";
|
||||
j0.children[1].name = "j4";
|
||||
|
||||
j0.children[0].children.resize(1);
|
||||
j0.children[0].children[0].name = "j2";
|
||||
|
||||
j0.children[0].children[0].children.resize(1);
|
||||
j0.children[0].children[0].children[0].name = "j3";
|
||||
|
||||
j0.children[1].children.resize(2);
|
||||
j0.children[1].children[0].name = "j5";
|
||||
j0.children[1].children[1].name = "j6";
|
||||
|
||||
j0.children[1].children[1].children.resize(1);
|
||||
j0.children[1].children[1].children[0].name = "j7";
|
||||
|
||||
j8.children.resize(1);
|
||||
j8.children[0].name = "j9";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 10);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 10);
|
||||
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 0), -12);
|
||||
EXPECT_EQ(fct.num_iterations(), 10);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 0));
|
||||
EXPECT_EQ(fct.num_iterations(), 10);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct = IterateJointsDF(
|
||||
*skeleton, IterateDFTester(skeleton.get(), 0), Skeleton::kNoParent);
|
||||
EXPECT_EQ(fct.num_iterations(), 10);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 0), 0);
|
||||
EXPECT_EQ(fct.num_iterations(), 8);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 1), 1);
|
||||
EXPECT_EQ(fct.num_iterations(), 3);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 2), 2);
|
||||
EXPECT_EQ(fct.num_iterations(), 2);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 3), 3);
|
||||
EXPECT_EQ(fct.num_iterations(), 1);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 4), 4);
|
||||
EXPECT_EQ(fct.num_iterations(), 4);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 5), 5);
|
||||
EXPECT_EQ(fct.num_iterations(), 1);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 6), 6);
|
||||
EXPECT_EQ(fct.num_iterations(), 2);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 7), 7);
|
||||
EXPECT_EQ(fct.num_iterations(), 1);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 8), 8);
|
||||
EXPECT_EQ(fct.num_iterations(), 2);
|
||||
}
|
||||
{
|
||||
IterateDFTester fct =
|
||||
IterateJointsDF(*skeleton, IterateDFTester(skeleton.get(), 9), 9);
|
||||
EXPECT_EQ(fct.num_iterations(), 1);
|
||||
}
|
||||
IterateJointsDF(*skeleton, IterateDFFailTester(), 10);
|
||||
IterateJointsDF(*skeleton, IterateDFFailTester(), 99);
|
||||
}
|
||||
|
||||
TEST(InterateDFEmpty, SkeletonUtils) {
|
||||
ozz::animation::Skeleton empty;
|
||||
IterateJointsDF(empty, IterateDFFailTester(),
|
||||
ozz::animation::Skeleton::kNoParent);
|
||||
IterateJointsDF(empty, IterateDFFailTester(), 0);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class IterateDFReverseTester {
|
||||
public:
|
||||
IterateDFReverseTester(const ozz::animation::Skeleton* _skeleton)
|
||||
: skeleton_(_skeleton), num_iterations_(0) {}
|
||||
|
||||
void operator()(int _current, int _parent) {
|
||||
if (num_iterations_ == 0) {
|
||||
EXPECT_TRUE(ozz::animation::IsLeaf(*skeleton_, _current));
|
||||
}
|
||||
|
||||
// A joint is traversed once.
|
||||
ozz::vector<int>::const_iterator itc =
|
||||
std::find(processed_joints_.begin(), processed_joints_.end(), _current);
|
||||
EXPECT_TRUE(itc == processed_joints_.end());
|
||||
|
||||
// A parent can't be traversed before a child.
|
||||
ozz::vector<int>::const_iterator itp =
|
||||
std::find(processed_joints_.begin(), processed_joints_.end(), _parent);
|
||||
EXPECT_TRUE(itp == processed_joints_.end());
|
||||
|
||||
// joint processed
|
||||
processed_joints_.push_back(_current);
|
||||
|
||||
// Validates parent id.
|
||||
EXPECT_EQ(skeleton_->joint_parents()[_current], _parent);
|
||||
|
||||
++num_iterations_;
|
||||
}
|
||||
|
||||
int num_iterations() const { return num_iterations_; }
|
||||
|
||||
private:
|
||||
// Iterated skeleton.
|
||||
const ozz::animation::Skeleton* skeleton_;
|
||||
|
||||
// Number of iterations completed.
|
||||
int num_iterations_;
|
||||
|
||||
// Already processed joints
|
||||
ozz::vector<int> processed_joints_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(InterateDFReverse, SkeletonUtils) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(2);
|
||||
RawSkeleton::Joint& j0 = raw_skeleton.roots[0];
|
||||
j0.name = "j0";
|
||||
RawSkeleton::Joint& j8 = raw_skeleton.roots[1];
|
||||
j8.name = "j8";
|
||||
|
||||
j0.children.resize(2);
|
||||
j0.children[0].name = "j1";
|
||||
j0.children[1].name = "j4";
|
||||
|
||||
j0.children[0].children.resize(1);
|
||||
j0.children[0].children[0].name = "j2";
|
||||
|
||||
j0.children[0].children[0].children.resize(1);
|
||||
j0.children[0].children[0].children[0].name = "j3";
|
||||
|
||||
j0.children[1].children.resize(2);
|
||||
j0.children[1].children[0].name = "j5";
|
||||
j0.children[1].children[1].name = "j6";
|
||||
|
||||
j0.children[1].children[1].children.resize(1);
|
||||
j0.children[1].children[1].children[0].name = "j7";
|
||||
|
||||
j8.children.resize(1);
|
||||
j8.children[0].name = "j9";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 10);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 10);
|
||||
|
||||
{
|
||||
IterateDFReverseTester fct = IterateJointsDFReverse(
|
||||
*skeleton, IterateDFReverseTester(skeleton.get()));
|
||||
EXPECT_EQ(fct.num_iterations(), 10);
|
||||
}
|
||||
}
|
||||
|
||||
/* Definition of the skeleton used by the tests.
|
||||
10 joints, 2 roots
|
||||
|
||||
*
|
||||
/ \
|
||||
j0 j8
|
||||
/ \ \
|
||||
j1 j4 j9
|
||||
| / \
|
||||
j2 j5 j6
|
||||
| |
|
||||
j3 j7
|
||||
*/
|
||||
|
||||
TEST(IsLeaf, SkeletonUtils) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
SkeletonBuilder builder;
|
||||
|
||||
RawSkeleton raw_skeleton;
|
||||
raw_skeleton.roots.resize(2);
|
||||
RawSkeleton::Joint& j0 = raw_skeleton.roots[0];
|
||||
j0.name = "j0";
|
||||
RawSkeleton::Joint& j8 = raw_skeleton.roots[1];
|
||||
j8.name = "j8";
|
||||
|
||||
j0.children.resize(2);
|
||||
j0.children[0].name = "j1";
|
||||
j0.children[1].name = "j4";
|
||||
|
||||
j0.children[0].children.resize(1);
|
||||
j0.children[0].children[0].name = "j2";
|
||||
|
||||
j0.children[0].children[0].children.resize(1);
|
||||
j0.children[0].children[0].children[0].name = "j3";
|
||||
|
||||
j0.children[1].children.resize(2);
|
||||
j0.children[1].children[0].name = "j5";
|
||||
j0.children[1].children[1].name = "j6";
|
||||
|
||||
j0.children[1].children[1].children.resize(1);
|
||||
j0.children[1].children[1].children[0].name = "j7";
|
||||
|
||||
j8.children.resize(1);
|
||||
j8.children[0].name = "j9";
|
||||
|
||||
EXPECT_TRUE(raw_skeleton.Validate());
|
||||
EXPECT_EQ(raw_skeleton.num_joints(), 10);
|
||||
|
||||
ozz::unique_ptr<Skeleton> skeleton(builder(raw_skeleton));
|
||||
ASSERT_TRUE(skeleton);
|
||||
EXPECT_EQ(skeleton->num_joints(), 10);
|
||||
|
||||
// Out of bound
|
||||
EXPECT_ASSERTION(IsLeaf(*skeleton, 10), "_joint index out of range");
|
||||
EXPECT_ASSERTION(IsLeaf(*skeleton, 93), "_joint index out of range");
|
||||
EXPECT_ASSERTION(IsLeaf(*skeleton, ozz::animation::Skeleton::kNoParent),
|
||||
"_joint index out of range");
|
||||
|
||||
EXPECT_FALSE(IsLeaf(*skeleton, 0));
|
||||
EXPECT_FALSE(IsLeaf(*skeleton, 1));
|
||||
EXPECT_FALSE(IsLeaf(*skeleton, 2));
|
||||
EXPECT_TRUE(IsLeaf(*skeleton, 3));
|
||||
EXPECT_FALSE(IsLeaf(*skeleton, 4));
|
||||
EXPECT_TRUE(IsLeaf(*skeleton, 5));
|
||||
EXPECT_FALSE(IsLeaf(*skeleton, 6));
|
||||
EXPECT_TRUE(IsLeaf(*skeleton, 7));
|
||||
EXPECT_FALSE(IsLeaf(*skeleton, 8));
|
||||
EXPECT_TRUE(IsLeaf(*skeleton, 9));
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/track.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/animation/runtime/track_sampling_job.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_track.h"
|
||||
#include "ozz/animation/offline/track_builder.h"
|
||||
|
||||
using ozz::animation::FloatTrack;
|
||||
using ozz::animation::FloatTrackSamplingJob;
|
||||
using ozz::animation::Float2Track;
|
||||
using ozz::animation::Float2TrackSamplingJob;
|
||||
using ozz::animation::Float3Track;
|
||||
using ozz::animation::Float3TrackSamplingJob;
|
||||
using ozz::animation::Float4Track;
|
||||
using ozz::animation::Float4TrackSamplingJob;
|
||||
using ozz::animation::QuaternionTrack;
|
||||
using ozz::animation::QuaternionTrackSamplingJob;
|
||||
using ozz::animation::offline::RawFloatTrack;
|
||||
using ozz::animation::offline::RawFloat2Track;
|
||||
using ozz::animation::offline::RawFloat3Track;
|
||||
using ozz::animation::offline::RawFloat4Track;
|
||||
using ozz::animation::offline::RawQuaternionTrack;
|
||||
using ozz::animation::offline::RawTrackInterpolation;
|
||||
using ozz::animation::offline::TrackBuilder;
|
||||
|
||||
TEST(Empty, TrackSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
|
||||
FloatTrack o_track;
|
||||
o << o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
FloatTrack i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_EQ(o_track.size(), i_track.size());
|
||||
}
|
||||
|
||||
TEST(Name, TrackSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Instantiates a builder objects with default parameters.
|
||||
TrackBuilder builder;
|
||||
|
||||
{ // No name
|
||||
RawFloatTrack raw_float_track;
|
||||
|
||||
ozz::unique_ptr<FloatTrack> o_track(builder(raw_float_track));
|
||||
ASSERT_TRUE(o_track);
|
||||
|
||||
// Streams out.
|
||||
{
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
o << *o_track;
|
||||
}
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
FloatTrack i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_STREQ(o_track->name(), i_track.name());
|
||||
}
|
||||
|
||||
{ // A name
|
||||
RawFloatTrack raw_float_track;
|
||||
raw_float_track.name = "test name";
|
||||
|
||||
ozz::unique_ptr<FloatTrack> o_track(builder(raw_float_track));
|
||||
ASSERT_TRUE(o_track);
|
||||
|
||||
// Streams out.
|
||||
{
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
o << *o_track;
|
||||
}
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
FloatTrack i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_STREQ(o_track->name(), i_track.name());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FilledFloat, TrackSerialize) {
|
||||
// Builds a valid animation.
|
||||
ozz::unique_ptr<FloatTrack> o_track;
|
||||
{
|
||||
TrackBuilder builder;
|
||||
RawFloatTrack raw_float_track;
|
||||
|
||||
const RawFloatTrack::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
0.f};
|
||||
raw_float_track.keyframes.push_back(key0);
|
||||
const RawFloatTrack::Keyframe key1 = {RawTrackInterpolation::kStep, .5f,
|
||||
46.f};
|
||||
raw_float_track.keyframes.push_back(key1);
|
||||
const RawFloatTrack::Keyframe key2 = {RawTrackInterpolation::kLinear, .7f,
|
||||
0.f};
|
||||
raw_float_track.keyframes.push_back(key2);
|
||||
|
||||
// Builds track
|
||||
o_track = builder(raw_float_track);
|
||||
ASSERT_TRUE(o_track);
|
||||
}
|
||||
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
o << *o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
FloatTrack i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_EQ(o_track->size(), i_track.size());
|
||||
|
||||
// Samples and compares the two animations
|
||||
FloatTrackSamplingJob sampling;
|
||||
sampling.track = &i_track;
|
||||
float result;
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 46.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FilledFloat2, TrackSerialize) {
|
||||
TrackBuilder builder;
|
||||
RawFloat2Track raw_float2_track;
|
||||
|
||||
const RawFloat2Track::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Float2(0.f, 26.f)};
|
||||
raw_float2_track.keyframes.push_back(key0);
|
||||
const RawFloat2Track::Keyframe key1 = {RawTrackInterpolation::kStep, .5f,
|
||||
ozz::math::Float2(46.f, 0.f)};
|
||||
raw_float2_track.keyframes.push_back(key1);
|
||||
const RawFloat2Track::Keyframe key2 = {RawTrackInterpolation::kLinear, .7f,
|
||||
ozz::math::Float2(0.f, 5.f)};
|
||||
raw_float2_track.keyframes.push_back(key2);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<Float2Track> o_track(builder(raw_float2_track));
|
||||
ASSERT_TRUE(o_track);
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream);
|
||||
o << *o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
Float2Track i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_EQ(o_track->size(), i_track.size());
|
||||
|
||||
// Samples and compares the two animations
|
||||
Float2TrackSamplingJob sampling;
|
||||
sampling.track = &i_track;
|
||||
ozz::math::Float2 result;
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 0.f, 26.f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 46.f, 0.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 0.f, 5.f);
|
||||
}
|
||||
|
||||
TEST(FilledFloat3, TrackSerialize) {
|
||||
TrackBuilder builder;
|
||||
RawFloat3Track raw_float3_track;
|
||||
|
||||
const RawFloat3Track::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Float3(0.f, 26.f, 93.f)};
|
||||
raw_float3_track.keyframes.push_back(key0);
|
||||
const RawFloat3Track::Keyframe key1 = {RawTrackInterpolation::kStep, .5f,
|
||||
ozz::math::Float3(46.f, 0.f, 25.f)};
|
||||
raw_float3_track.keyframes.push_back(key1);
|
||||
const RawFloat3Track::Keyframe key2 = {RawTrackInterpolation::kLinear, .7f,
|
||||
ozz::math::Float3(0.f, 5.f, 0.f)};
|
||||
raw_float3_track.keyframes.push_back(key2);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<Float3Track> o_track(builder(raw_float3_track));
|
||||
ASSERT_TRUE(o_track);
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream);
|
||||
o << *o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
Float3Track i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_EQ(o_track->size(), i_track.size());
|
||||
|
||||
// Samples and compares the two animations
|
||||
Float3TrackSamplingJob sampling;
|
||||
sampling.track = &i_track;
|
||||
ozz::math::Float3 result;
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 26.f, 93.f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 46.f, 0.f, 25.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 5.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(FilledFloat4, TrackSerialize) {
|
||||
TrackBuilder builder;
|
||||
RawFloat4Track raw_float4_track;
|
||||
|
||||
const RawFloat4Track::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Float4(0.f, 26.f, 93.f, 5.f)};
|
||||
raw_float4_track.keyframes.push_back(key0);
|
||||
const RawFloat4Track::Keyframe key1 = {
|
||||
RawTrackInterpolation::kStep, .5f,
|
||||
ozz::math::Float4(46.f, 0.f, 25.f, 25.f)};
|
||||
raw_float4_track.keyframes.push_back(key1);
|
||||
const RawFloat4Track::Keyframe key2 = {RawTrackInterpolation::kLinear, .7f,
|
||||
ozz::math::Float4(0.f, 5.f, 0.f, 0.f)};
|
||||
raw_float4_track.keyframes.push_back(key2);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<Float4Track> o_track(builder(raw_float4_track));
|
||||
ASSERT_TRUE(o_track);
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream);
|
||||
o << *o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
Float4Track i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_EQ(o_track->size(), i_track.size());
|
||||
|
||||
// Samples and compares the two animations
|
||||
Float4TrackSamplingJob sampling;
|
||||
sampling.track = &i_track;
|
||||
ozz::math::Float4 result;
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 26.f, 93.f, 5.f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 46.f, 0.f, 25.f, 25.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 5.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(FilledQuaternion, TrackSerialize) {
|
||||
TrackBuilder builder;
|
||||
RawQuaternionTrack raw_quat_track;
|
||||
|
||||
const RawQuaternionTrack::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Quaternion(0.f, .70710677f, 0.f, .70710677f)};
|
||||
raw_quat_track.keyframes.push_back(key0);
|
||||
const RawQuaternionTrack::Keyframe key1 = {
|
||||
RawTrackInterpolation::kStep, .5f,
|
||||
ozz::math::Quaternion(.61721331f, .15430345f, 0.f, .77151674f)};
|
||||
raw_quat_track.keyframes.push_back(key1);
|
||||
const RawQuaternionTrack::Keyframe key2 = {
|
||||
RawTrackInterpolation::kLinear, .7f,
|
||||
ozz::math::Quaternion(1.f, 0.f, 0.f, 0.f)};
|
||||
raw_quat_track.keyframes.push_back(key2);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<QuaternionTrack> o_track(builder(raw_quat_track));
|
||||
ASSERT_TRUE(o_track);
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
// Streams out.
|
||||
ozz::io::OArchive o(&stream);
|
||||
o << *o_track;
|
||||
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
QuaternionTrack i_track;
|
||||
i >> i_track;
|
||||
|
||||
EXPECT_EQ(o_track->size(), i_track.size());
|
||||
|
||||
// Samples and compares the two animations
|
||||
QuaternionTrackSamplingJob sampling;
|
||||
sampling.track = &i_track;
|
||||
ozz::math::Quaternion result;
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, 0.f, .70710677f, 0.f, .70710677f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, .61721331f, .15430345f, 0.f, .77151674f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, 1.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(AlreadyInitialized, TrackSerialize) {
|
||||
ozz::io::MemoryStream stream;
|
||||
|
||||
{
|
||||
ozz::io::OArchive o(&stream);
|
||||
|
||||
TrackBuilder builder;
|
||||
RawFloatTrack raw_float_track;
|
||||
|
||||
const RawFloatTrack::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
0.f};
|
||||
raw_float_track.keyframes.push_back(key0);
|
||||
const RawFloatTrack::Keyframe key1 = {RawTrackInterpolation::kStep, .5f,
|
||||
46.f};
|
||||
raw_float_track.keyframes.push_back(key1);
|
||||
const RawFloatTrack::Keyframe key2 = {RawTrackInterpolation::kLinear, .7f,
|
||||
0.f};
|
||||
raw_float_track.keyframes.push_back(key2);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<FloatTrack> o_track(builder(raw_float_track));
|
||||
ASSERT_TRUE(o_track);
|
||||
|
||||
o << *o_track;
|
||||
|
||||
// Builds 2nd track
|
||||
const RawFloatTrack::Keyframe key3 = {RawTrackInterpolation::kStep, .9f,
|
||||
46.f};
|
||||
raw_float_track.keyframes.push_back(key3);
|
||||
|
||||
o_track = builder(raw_float_track);
|
||||
ASSERT_TRUE(o_track);
|
||||
o << *o_track;
|
||||
}
|
||||
|
||||
{
|
||||
// Streams in.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
// Reads and check the first animation.
|
||||
FloatTrack i_track;
|
||||
i >> i_track;
|
||||
const size_t size = i_track.size();
|
||||
|
||||
// Reuse the animation a second ratio.
|
||||
i >> i_track;
|
||||
ASSERT_TRUE(i_track.size() > size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/track_sampling_job.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_track.h"
|
||||
#include "ozz/animation/offline/track_builder.h"
|
||||
|
||||
#include "ozz/animation/runtime/track.h"
|
||||
|
||||
using ozz::animation::FloatTrack;
|
||||
using ozz::animation::Float2Track;
|
||||
using ozz::animation::Float3Track;
|
||||
using ozz::animation::Float4Track;
|
||||
using ozz::animation::QuaternionTrack;
|
||||
using ozz::animation::FloatTrackSamplingJob;
|
||||
using ozz::animation::offline::RawFloatTrack;
|
||||
using ozz::animation::offline::TrackBuilder;
|
||||
using ozz::animation::offline::RawTrackInterpolation;
|
||||
|
||||
TEST(JobValidity, TrackSamplingJob) {
|
||||
// Instantiates a builder objects with default parameters.
|
||||
TrackBuilder builder;
|
||||
|
||||
// Building default RawFloatTrack succeeds.
|
||||
RawFloatTrack raw_float_track;
|
||||
EXPECT_TRUE(raw_float_track.Validate());
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<FloatTrack> track(builder(raw_float_track));
|
||||
ASSERT_TRUE(track);
|
||||
|
||||
{ // Empty/default job
|
||||
FloatTrackSamplingJob job;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid output
|
||||
FloatTrackSamplingJob job;
|
||||
job.track = track.get();
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Invalid track.
|
||||
FloatTrackSamplingJob job;
|
||||
float result;
|
||||
job.result = &result;
|
||||
EXPECT_FALSE(job.Validate());
|
||||
EXPECT_FALSE(job.Run());
|
||||
}
|
||||
|
||||
{ // Valid
|
||||
FloatTrackSamplingJob job;
|
||||
job.track = track.get();
|
||||
float result;
|
||||
job.result = &result;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Default, TrackSamplingJob) {
|
||||
FloatTrack default_track;
|
||||
FloatTrackSamplingJob job;
|
||||
job.track = &default_track;
|
||||
float result = 1.f;
|
||||
job.result = &result;
|
||||
EXPECT_TRUE(job.Validate());
|
||||
EXPECT_TRUE(job.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
}
|
||||
|
||||
TEST(Bounds, TrackSamplingJob) {
|
||||
TrackBuilder builder;
|
||||
float result;
|
||||
|
||||
RawFloatTrack raw_float_track;
|
||||
|
||||
const RawFloatTrack::Keyframe key0 = {RawTrackInterpolation::kLinear, 0.f,
|
||||
0.f};
|
||||
raw_float_track.keyframes.push_back(key0);
|
||||
const RawFloatTrack::Keyframe key1 = {RawTrackInterpolation::kStep, .5f,
|
||||
46.f};
|
||||
raw_float_track.keyframes.push_back(key1);
|
||||
const RawFloatTrack::Keyframe key2 = {RawTrackInterpolation::kLinear, .7f,
|
||||
0.f};
|
||||
raw_float_track.keyframes.push_back(key2);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<FloatTrack> track(builder(raw_float_track));
|
||||
ASSERT_TRUE(track);
|
||||
|
||||
// Samples to verify build output.
|
||||
FloatTrackSamplingJob sampling;
|
||||
sampling.track = track.get();
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f - 1e-7f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 46.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
|
||||
sampling.ratio = 1.f + 1e-7f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
|
||||
sampling.ratio = 1.5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
}
|
||||
|
||||
TEST(Float, TrackSamplingJob) {
|
||||
TrackBuilder builder;
|
||||
float result;
|
||||
|
||||
ozz::animation::offline::RawFloatTrack raw_track;
|
||||
|
||||
const ozz::animation::offline::RawFloatTrack::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f, 0.f};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const ozz::animation::offline::RawFloatTrack::Keyframe key1 = {
|
||||
RawTrackInterpolation::kStep, .5f, 4.6f};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const ozz::animation::offline::RawFloatTrack::Keyframe key2 = {
|
||||
RawTrackInterpolation::kLinear, .7f, 9.2f};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const ozz::animation::offline::RawFloatTrack::Keyframe key3 = {
|
||||
RawTrackInterpolation::kLinear, .9f, 0.f};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<FloatTrack> track(builder(raw_track));
|
||||
ASSERT_TRUE(track);
|
||||
|
||||
// Samples to verify build output.
|
||||
ozz::animation::FloatTrackSamplingJob sampling;
|
||||
sampling.track = track.get();
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
|
||||
sampling.ratio = .25f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 2.3f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 4.6f);
|
||||
|
||||
sampling.ratio = .6f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 4.6f);
|
||||
|
||||
sampling.ratio = .7f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 9.2f);
|
||||
|
||||
sampling.ratio = .8f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 4.6f);
|
||||
|
||||
sampling.ratio = .9f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT_EQ(result, 0.f);
|
||||
}
|
||||
|
||||
TEST(Float2, TrackSamplingJob) {
|
||||
TrackBuilder builder;
|
||||
ozz::math::Float2 result;
|
||||
|
||||
ozz::animation::offline::RawFloat2Track raw_track;
|
||||
|
||||
const ozz::animation::offline::RawFloat2Track::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f, ozz::math::Float2(0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const ozz::animation::offline::RawFloat2Track::Keyframe key1 = {
|
||||
RawTrackInterpolation::kStep, .5f, ozz::math::Float2(2.3f, 4.6f)};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const ozz::animation::offline::RawFloat2Track::Keyframe key2 = {
|
||||
RawTrackInterpolation::kLinear, .7f, ozz::math::Float2(4.6f, 9.2f)};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const ozz::animation::offline::RawFloat2Track::Keyframe key3 = {
|
||||
RawTrackInterpolation::kLinear, .9f, ozz::math::Float2(0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<Float2Track> track(builder(raw_track));
|
||||
ASSERT_TRUE(track);
|
||||
|
||||
// Samples to verify build output.
|
||||
ozz::animation::Float2TrackSamplingJob sampling;
|
||||
sampling.track = track.get();
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 0.f, 0.f);
|
||||
|
||||
sampling.ratio = .25f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 1.15f, 2.3f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 2.3f, 4.6f);
|
||||
|
||||
sampling.ratio = .6f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 2.3f, 4.6f);
|
||||
|
||||
sampling.ratio = .7f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 4.6f, 9.2f);
|
||||
|
||||
sampling.ratio = .8f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 2.3f, 4.6f);
|
||||
|
||||
sampling.ratio = .9f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 0.f, 0.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT2_EQ(result, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(Float3, TrackSamplingJob) {
|
||||
TrackBuilder builder;
|
||||
ozz::math::Float3 result;
|
||||
|
||||
ozz::animation::offline::RawFloat3Track raw_track;
|
||||
|
||||
const ozz::animation::offline::RawFloat3Track::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f, ozz::math::Float3(0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const ozz::animation::offline::RawFloat3Track::Keyframe key1 = {
|
||||
RawTrackInterpolation::kStep, .5f, ozz::math::Float3(0.f, 2.3f, 4.6f)};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const ozz::animation::offline::RawFloat3Track::Keyframe key2 = {
|
||||
RawTrackInterpolation::kLinear, .7f, ozz::math::Float3(0.f, 4.6f, 9.2f)};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const ozz::animation::offline::RawFloat3Track::Keyframe key3 = {
|
||||
RawTrackInterpolation::kLinear, .9f, ozz::math::Float3(0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<Float3Track> track(builder(raw_track));
|
||||
ASSERT_TRUE(track);
|
||||
|
||||
// Samples to verify build output.
|
||||
ozz::animation::Float3TrackSamplingJob sampling;
|
||||
sampling.track = track.get();
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 0.f, 0.f);
|
||||
|
||||
sampling.ratio = .25f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 1.15f, 2.3f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 2.3f, 4.6f);
|
||||
|
||||
sampling.ratio = .6f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 2.3f, 4.6f);
|
||||
|
||||
sampling.ratio = .7f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 4.6f, 9.2f);
|
||||
|
||||
sampling.ratio = .8f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 2.3f, 4.6f);
|
||||
|
||||
sampling.ratio = .9f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 0.f, 0.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT3_EQ(result, 0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(Float4, TrackSamplingJob) {
|
||||
TrackBuilder builder;
|
||||
ozz::math::Float4 result;
|
||||
|
||||
ozz::animation::offline::RawFloat4Track raw_track;
|
||||
|
||||
const ozz::animation::offline::RawFloat4Track::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Float4(0.f, 0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const ozz::animation::offline::RawFloat4Track::Keyframe key1 = {
|
||||
RawTrackInterpolation::kStep, .5f,
|
||||
ozz::math::Float4(0.f, 2.3f, 0.f, 4.6f)};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const ozz::animation::offline::RawFloat4Track::Keyframe key2 = {
|
||||
RawTrackInterpolation::kLinear, .7f,
|
||||
ozz::math::Float4(0.f, 4.6f, 0.f, 9.2f)};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const ozz::animation::offline::RawFloat4Track::Keyframe key3 = {
|
||||
RawTrackInterpolation::kLinear, .9f,
|
||||
ozz::math::Float4(0.f, 0.f, 0.f, 0.f)};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<Float4Track> track(builder(raw_track));
|
||||
ASSERT_TRUE(track);
|
||||
|
||||
// Samples to verify build output.
|
||||
ozz::animation::Float4TrackSamplingJob sampling;
|
||||
sampling.track = track.get();
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
sampling.ratio = .25f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 1.15f, 0.f, 2.3f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 2.3f, 0.f, 4.6f);
|
||||
|
||||
sampling.ratio = .6f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 2.3f, 0.f, 4.6f);
|
||||
|
||||
sampling.ratio = .7f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 4.6f, 0.f, 9.2f);
|
||||
|
||||
sampling.ratio = .8f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 2.3f, 0.f, 4.6f);
|
||||
|
||||
sampling.ratio = .9f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_FLOAT4_EQ(result, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(Quaternion, TrackSamplingJob) {
|
||||
TrackBuilder builder;
|
||||
ozz::math::Quaternion result;
|
||||
|
||||
ozz::animation::offline::RawQuaternionTrack raw_track;
|
||||
|
||||
const ozz::animation::offline::RawQuaternionTrack::Keyframe key0 = {
|
||||
RawTrackInterpolation::kLinear, 0.f,
|
||||
ozz::math::Quaternion(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const ozz::animation::offline::RawQuaternionTrack::Keyframe key1 = {
|
||||
RawTrackInterpolation::kStep, .5f,
|
||||
ozz::math::Quaternion(0.f, .70710677f, 0.f, .70710677f)};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const ozz::animation::offline::RawQuaternionTrack::Keyframe key2 = {
|
||||
RawTrackInterpolation::kLinear, .7f,
|
||||
ozz::math::Quaternion(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
const ozz::animation::offline::RawQuaternionTrack::Keyframe key3 = {
|
||||
RawTrackInterpolation::kLinear, .9f, ozz::math::Quaternion::identity()};
|
||||
raw_track.keyframes.push_back(key3);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<QuaternionTrack> track(builder(raw_track));
|
||||
ASSERT_TRUE(track);
|
||||
// Samples to verify build output.
|
||||
ozz::animation::QuaternionTrackSamplingJob sampling;
|
||||
sampling.track = track.get();
|
||||
sampling.result = &result;
|
||||
|
||||
sampling.ratio = 0.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, .70710677f, 0.f, 0.f, .70710677f);
|
||||
|
||||
sampling.ratio = .1f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, .61721331f, .15430345f, 0.f, .77151674f);
|
||||
|
||||
sampling.ratio = .4999999f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, 0.f, .70710677f, 0.f, .70710677f);
|
||||
|
||||
sampling.ratio = .5f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, 0.f, .70710677f, 0.f, .70710677f);
|
||||
|
||||
sampling.ratio = .6f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, 0.f, .70710677f, 0.f, .70710677f);
|
||||
|
||||
sampling.ratio = .7f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, .70710677f, 0.f, 0.f, .70710677f);
|
||||
|
||||
sampling.ratio = .8f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, .38268333f, 0.f, 0.f, .92387962f);
|
||||
|
||||
sampling.ratio = .9f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
sampling.ratio = 1.f;
|
||||
ASSERT_TRUE(sampling.Run());
|
||||
EXPECT_QUATERNION_EQ(result, 0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
+1403
File diff suppressed because it is too large
Load Diff
+110
@@ -0,0 +1,110 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/animation/runtime/track_triggering_job_trait.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/animation/offline/raw_track.h"
|
||||
#include "ozz/animation/offline/track_builder.h"
|
||||
|
||||
#include "ozz/animation/runtime/track.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using ozz::animation::FloatTrack;
|
||||
using ozz::animation::TrackTriggeringJob;
|
||||
using ozz::animation::offline::RawFloatTrack;
|
||||
using ozz::animation::offline::RawTrackInterpolation;
|
||||
using ozz::animation::offline::TrackBuilder;
|
||||
|
||||
namespace {
|
||||
bool IsRising(const TrackTriggeringJob::Edge& _edge) { return _edge.rising; }
|
||||
} // namespace
|
||||
|
||||
TEST(Algorithm, TrackEdgeTriggerJob) {
|
||||
TrackBuilder builder;
|
||||
|
||||
ozz::animation::offline::RawFloatTrack raw_track;
|
||||
|
||||
// Keyframe values oscillate in range [0,2].
|
||||
const ozz::animation::offline::RawFloatTrack::Keyframe key0 = {
|
||||
RawTrackInterpolation::kStep, 0.f, 0.f};
|
||||
raw_track.keyframes.push_back(key0);
|
||||
const ozz::animation::offline::RawFloatTrack::Keyframe key1 = {
|
||||
RawTrackInterpolation::kStep, .5f, 2.f};
|
||||
raw_track.keyframes.push_back(key1);
|
||||
const ozz::animation::offline::RawFloatTrack::Keyframe key2 = {
|
||||
RawTrackInterpolation::kStep, 1.f, 0.f};
|
||||
raw_track.keyframes.push_back(key2);
|
||||
|
||||
// Builds track
|
||||
ozz::unique_ptr<FloatTrack> track(builder(raw_track));
|
||||
ASSERT_TRUE(track);
|
||||
|
||||
TrackTriggeringJob job;
|
||||
job.track = track.get();
|
||||
job.threshold = 1.f;
|
||||
|
||||
job.from = 0.f;
|
||||
job.to = 2.f;
|
||||
TrackTriggeringJob::Iterator iterator;
|
||||
job.iterator = &iterator;
|
||||
ASSERT_TRUE(job.Run());
|
||||
|
||||
{ // copy
|
||||
ozz::vector<TrackTriggeringJob::Edge> edges;
|
||||
std::copy(iterator, job.end(), std::back_inserter(edges));
|
||||
EXPECT_EQ(edges.size(), 4u);
|
||||
}
|
||||
|
||||
{ // count
|
||||
ozz::vector<TrackTriggeringJob::Edge> edges;
|
||||
std::iterator_traits<TrackTriggeringJob::Iterator>::difference_type count =
|
||||
std::count_if(iterator, job.end(), IsRising);
|
||||
EXPECT_EQ(count, 2);
|
||||
|
||||
std::iterator_traits<TrackTriggeringJob::Iterator>::difference_type
|
||||
count_end = std::count_if(job.end(), job.end(), IsRising);
|
||||
EXPECT_EQ(count_end, 0);
|
||||
}
|
||||
|
||||
{ // for_each
|
||||
ozz::vector<TrackTriggeringJob::Edge> edges;
|
||||
std::for_each(iterator, job.end(), IsRising);
|
||||
}
|
||||
|
||||
{ // find_if
|
||||
ozz::vector<TrackTriggeringJob::Edge> edges;
|
||||
TrackTriggeringJob::Iterator it_if =
|
||||
std::find_if(iterator, job.end(), IsRising);
|
||||
EXPECT_TRUE(it_if->rising);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
add_subdirectory(containers)
|
||||
add_subdirectory(io)
|
||||
add_subdirectory(maths)
|
||||
add_subdirectory(memory)
|
||||
|
||||
add_executable(test_endianness endianness_tests.cc)
|
||||
target_link_libraries(test_endianness
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_endianness COMMAND test_endianness)
|
||||
set_target_properties(test_endianness PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_log log_tests.cc)
|
||||
target_link_libraries(test_log
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_log COMMAND test_log)
|
||||
set_target_properties(test_log PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_platform
|
||||
platform_tests.cc
|
||||
span_tests.cc)
|
||||
target_link_libraries(test_platform
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_platform COMMAND test_platform)
|
||||
set_target_properties(test_platform PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
# ozz_base fuse tests
|
||||
set_source_files_properties(${PROJECT_BINARY_DIR}/src_fused/ozz_base.cc PROPERTIES GENERATED 1)
|
||||
add_executable(test_fuse_base
|
||||
log_tests.cc
|
||||
platform_tests.cc
|
||||
${PROJECT_BINARY_DIR}/src_fused/ozz_base.cc)
|
||||
add_dependencies(test_fuse_base BUILD_FUSE_ozz_base)
|
||||
target_include_directories(test_fuse_base
|
||||
PUBLIC "${PROJECT_SOURCE_DIR}/include")
|
||||
target_link_libraries(test_fuse_base
|
||||
gtest)
|
||||
add_test(NAME test_fuse_base COMMAND test_fuse_base)
|
||||
set_target_properties(test_fuse_base PROPERTIES FOLDER "ozz/tests/base")
|
||||
@@ -0,0 +1,22 @@
|
||||
add_executable(test_intrusive_list intrusive_list_tests.cc)
|
||||
target_include_directories(test_intrusive_list
|
||||
PUBLIC "${PROJECT_SOURCE_DIR}/include")
|
||||
target_link_libraries(test_intrusive_list
|
||||
gtest)
|
||||
add_test(NAME test_intrusive_list COMMAND test_intrusive_list)
|
||||
set_target_properties(test_intrusive_list PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_std_containers std_containers_tests.cc)
|
||||
target_link_libraries(test_std_containers
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_std_containers COMMAND test_std_containers)
|
||||
set_target_properties(test_std_containers PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_std_containers_archive
|
||||
std_containers_archive_tests.cc)
|
||||
target_link_libraries(test_std_containers_archive
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_std_containers_archive COMMAND test_std_containers_archive)
|
||||
set_target_properties(test_std_containers_archive PROPERTIES FOLDER "ozz/tests/base")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,145 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/containers/string_archive.h"
|
||||
#include "ozz/base/containers/vector_archive.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
|
||||
TEST(string, Archive) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Writes.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
ozz::string empty_o;
|
||||
o << empty_o;
|
||||
|
||||
ozz::string small_o("Forty-six");
|
||||
o << small_o;
|
||||
|
||||
ozz::string big_o(
|
||||
"Forty-six is a Wedderburn-Etherington number, an "
|
||||
"enneagonal number and a centered triangular number. It is the sum of "
|
||||
"the totient function for the first twelve integers. 46 is the largest "
|
||||
"even integer that can't be expressed as a sum of two abundant numbers."
|
||||
"46 is the 16th semiprime. 46 is the third semiprime with a semiprime"
|
||||
"aliquot sum. The aliquot sequence of 46 is (46,26,16,15,9,4,3,1,0)."
|
||||
"Since it is possible to find sequences of 46 consecutive integers "
|
||||
"such that each inner member shares a factor with either the first or "
|
||||
"the last member, 46 is an Erdos-Woods number.");
|
||||
o << big_o;
|
||||
|
||||
// Rewrite for the string reuse test.
|
||||
ozz::string reuse_o("Forty-six");
|
||||
o << reuse_o;
|
||||
|
||||
// Reads.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
ozz::string empty_i;
|
||||
i >> empty_i;
|
||||
EXPECT_STREQ(empty_o.c_str(), empty_i.c_str());
|
||||
|
||||
ozz::string small_i;
|
||||
i >> small_i;
|
||||
EXPECT_STREQ(small_o.c_str(), small_i.c_str());
|
||||
|
||||
ozz::string big_i;
|
||||
i >> big_i;
|
||||
EXPECT_STREQ(big_o.c_str(), big_i.c_str());
|
||||
|
||||
ozz::string reuse_i("already used string");
|
||||
i >> reuse_i;
|
||||
EXPECT_STREQ(reuse_o.c_str(), reuse_i.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Vector, Archive) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Writes.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
ozz::vector<int> empty_o;
|
||||
o << empty_o;
|
||||
|
||||
ozz::vector<int> small_o(5);
|
||||
std::generate(small_o.begin(), small_o.end(), std::rand);
|
||||
o << small_o;
|
||||
|
||||
ozz::vector<int> big_o(1263);
|
||||
std::generate(big_o.begin(), big_o.end(), std::rand);
|
||||
o << big_o;
|
||||
|
||||
// Rewrite for the Vector reuse test.
|
||||
ozz::vector<int> reuse_o(46);
|
||||
std::generate(reuse_o.begin(), reuse_o.end(), std::rand);
|
||||
o << reuse_o;
|
||||
|
||||
// Reads.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
ozz::vector<int> empty_i;
|
||||
i >> empty_i;
|
||||
EXPECT_EQ(empty_i.size(), 0u);
|
||||
|
||||
ozz::vector<int> small_i;
|
||||
i >> small_i;
|
||||
EXPECT_EQ(small_o.size(), small_i.size());
|
||||
for (size_t j = 0; j < empty_i.size(); ++j) {
|
||||
EXPECT_EQ(small_o[j], small_i[j]);
|
||||
}
|
||||
|
||||
ozz::vector<int> big_i;
|
||||
i >> big_i;
|
||||
EXPECT_EQ(big_o.size(), big_i.size());
|
||||
for (size_t j = 0; j < big_i.size(); ++j) {
|
||||
EXPECT_EQ(big_o[j], big_i[j]);
|
||||
}
|
||||
|
||||
ozz::vector<int> reuse_i(3);
|
||||
std::generate(reuse_i.begin(), reuse_i.end(), std::rand);
|
||||
i >> reuse_i;
|
||||
EXPECT_EQ(reuse_o.size(), reuse_i.size());
|
||||
for (size_t j = 0; j < reuse_i.size(); ++j) {
|
||||
EXPECT_EQ(reuse_o[j], reuse_i[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/containers/deque.h"
|
||||
#include "ozz/base/containers/list.h"
|
||||
#include "ozz/base/containers/map.h"
|
||||
#include "ozz/base/containers/queue.h"
|
||||
#include "ozz/base/containers/set.h"
|
||||
#include "ozz/base/containers/stack.h"
|
||||
#include "ozz/base/containers/string.h"
|
||||
#include "ozz/base/containers/unordered_map.h"
|
||||
#include "ozz/base/containers/unordered_set.h"
|
||||
#include "ozz/base/containers/vector.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/span.h"
|
||||
|
||||
TEST(Vector, Containers) {
|
||||
typedef ozz::vector<int> Container;
|
||||
Container container;
|
||||
container.push_back(1);
|
||||
container.insert(container.begin(), 0);
|
||||
container.push_back(2);
|
||||
container.push_back(std::move(3));
|
||||
EXPECT_EQ(container[0], 0);
|
||||
EXPECT_EQ(container[1], 1);
|
||||
EXPECT_EQ(container[2], 2);
|
||||
EXPECT_EQ(container[3], 3);
|
||||
|
||||
Container container2 = std::move(container);
|
||||
}
|
||||
|
||||
TEST(VectorExtensions, Containers) {
|
||||
typedef ozz::vector<int> Container;
|
||||
Container container;
|
||||
int* null = nullptr;
|
||||
|
||||
// Non-mutable access.
|
||||
EXPECT_EQ(array_begin(container), null);
|
||||
EXPECT_EQ(array_end(container), null);
|
||||
EXPECT_EQ(array_end(container), array_begin(container));
|
||||
EXPECT_TRUE(make_span(container).empty());
|
||||
|
||||
container.push_back(1);
|
||||
container.push_back(2);
|
||||
EXPECT_EQ(*array_begin(container), 1);
|
||||
EXPECT_EQ(*(array_begin(container) + 1), 2);
|
||||
EXPECT_EQ(array_begin(container) + 2, array_end(container));
|
||||
EXPECT_NE(array_end(container), null);
|
||||
EXPECT_EQ(*(array_end(container) - 2), 1);
|
||||
EXPECT_EQ(array_end(container) - array_begin(container), 2);
|
||||
EXPECT_EQ(make_span(container).begin(), array_begin(container));
|
||||
EXPECT_EQ(make_span(container).end(), array_end(container));
|
||||
|
||||
const Container const_container(container);
|
||||
EXPECT_EQ(*array_begin(const_container), 1);
|
||||
EXPECT_EQ(*(array_begin(const_container) + 1), 2);
|
||||
EXPECT_EQ(array_begin(const_container) + 2, array_end(const_container));
|
||||
EXPECT_NE(array_end(const_container), null);
|
||||
EXPECT_EQ(*(array_end(const_container) - 2), 1);
|
||||
EXPECT_EQ(array_end(const_container) - array_begin(const_container), 2);
|
||||
EXPECT_EQ(make_span(const_container).begin(), array_begin(const_container));
|
||||
EXPECT_EQ(make_span(const_container).end(), array_end(const_container));
|
||||
|
||||
// Mutable access.
|
||||
*array_begin(container) = 0;
|
||||
EXPECT_EQ(*array_begin(container), 0);
|
||||
EXPECT_EQ(*(array_begin(container) + 1), 2);
|
||||
}
|
||||
|
||||
TEST(Deque, Containers) {
|
||||
typedef ozz::deque<int> Container;
|
||||
Container container;
|
||||
container.push_back(1);
|
||||
container.push_front(0);
|
||||
container.push_back(2);
|
||||
EXPECT_EQ(container[0], 0);
|
||||
EXPECT_EQ(container[1], 1);
|
||||
EXPECT_EQ(container[2], 2);
|
||||
container.clear();
|
||||
|
||||
Container container2 = std::move(container);
|
||||
}
|
||||
|
||||
TEST(List, Containers) {
|
||||
typedef ozz::list<int> Container;
|
||||
Container container;
|
||||
container.push_back(1);
|
||||
container.push_front(0);
|
||||
container.push_back(2);
|
||||
EXPECT_EQ(container.front(), 0);
|
||||
EXPECT_EQ(container.back(), 2);
|
||||
container.clear();
|
||||
|
||||
Container container2 = std::move(container);
|
||||
}
|
||||
|
||||
TEST(Stack, Containers) {
|
||||
typedef ozz::stack<int> Container;
|
||||
Container container;
|
||||
container.push(1);
|
||||
container.push(2);
|
||||
EXPECT_EQ(container.top(), 2);
|
||||
container.pop();
|
||||
EXPECT_EQ(container.top(), 1);
|
||||
container.pop();
|
||||
|
||||
Container container2 = std::move(container);
|
||||
}
|
||||
|
||||
TEST(Queue, Containers) {
|
||||
{
|
||||
typedef ozz::queue<int> Container;
|
||||
Container container;
|
||||
container.push(1);
|
||||
container.push(2);
|
||||
EXPECT_EQ(container.back(), 2);
|
||||
EXPECT_EQ(container.front(), 1);
|
||||
container.pop();
|
||||
EXPECT_EQ(container.back(), 2);
|
||||
container.pop();
|
||||
|
||||
Container container2 = std::move(container);
|
||||
}
|
||||
{
|
||||
typedef ozz::priority_queue<int> Container;
|
||||
Container container;
|
||||
container.push(1);
|
||||
container.push(2);
|
||||
container.push(0);
|
||||
EXPECT_EQ(container.top(), 2);
|
||||
container.pop();
|
||||
EXPECT_EQ(container.top(), 1);
|
||||
container.pop();
|
||||
EXPECT_EQ(container.top(), 0);
|
||||
container.pop();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Set, Containers) {
|
||||
{
|
||||
typedef ozz::set<int> Container;
|
||||
Container container;
|
||||
EXPECT_TRUE(container.insert('c').second);
|
||||
EXPECT_TRUE(container.insert('a').second);
|
||||
EXPECT_TRUE(container.insert('b').second);
|
||||
EXPECT_FALSE(container.insert('b').second);
|
||||
EXPECT_TRUE(container.find('a') == container.begin());
|
||||
EXPECT_TRUE(container.find('c') == --container.end());
|
||||
EXPECT_EQ(container.erase('c'), 1u);
|
||||
|
||||
EXPECT_TRUE(container.find('b') == --container.end());
|
||||
container.clear();
|
||||
|
||||
Container container2 = std::move(container);
|
||||
}
|
||||
{
|
||||
typedef ozz::multiset<int> Container;
|
||||
Container container;
|
||||
container.insert('c');
|
||||
container.insert('a');
|
||||
container.insert('b');
|
||||
container.insert('a');
|
||||
EXPECT_TRUE(container.find('a') == container.begin() ||
|
||||
container.find('a') == ++container.begin());
|
||||
EXPECT_TRUE(container.find('c') == --container.end());
|
||||
EXPECT_EQ(container.erase('c'), 1u);
|
||||
EXPECT_TRUE(container.find('c') == container.end());
|
||||
EXPECT_EQ(container.erase('a'), 2u);
|
||||
EXPECT_TRUE(container.find('a') == container.end());
|
||||
container.clear();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UnorderedSet, Containers) {
|
||||
{
|
||||
typedef ozz::unordered_set<int> Container;
|
||||
Container container;
|
||||
EXPECT_TRUE(container.insert('c').second);
|
||||
EXPECT_TRUE(container.insert('a').second);
|
||||
EXPECT_TRUE(container.insert('b').second);
|
||||
EXPECT_FALSE(container.insert('a').second);
|
||||
EXPECT_TRUE(container.find('a') != container.end());
|
||||
EXPECT_TRUE(container.find('c') != container.end());
|
||||
EXPECT_EQ(container.erase('c'), 1u);
|
||||
EXPECT_TRUE(container.find('c') == container.end());
|
||||
container.clear();
|
||||
}
|
||||
{
|
||||
typedef ozz::unordered_multiset<int> Container;
|
||||
Container container;
|
||||
container.insert('c');
|
||||
container.insert('a');
|
||||
container.insert('b');
|
||||
container.insert('a');
|
||||
EXPECT_TRUE(container.find('a') != container.end());
|
||||
EXPECT_TRUE(container.find('c') != container.end());
|
||||
EXPECT_EQ(container.erase('c'), 1u);
|
||||
EXPECT_TRUE(container.find('c') == container.end());
|
||||
EXPECT_EQ(container.erase('a'), 2u);
|
||||
EXPECT_TRUE(container.find('a') == container.end());
|
||||
container.clear();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Map, Containers) {
|
||||
{
|
||||
typedef ozz::map<char, int> Container;
|
||||
Container container;
|
||||
container['a'] = -3;
|
||||
container['c'] = -1;
|
||||
container['b'] = -2;
|
||||
container['d'] = 1;
|
||||
EXPECT_EQ(container['a'], -3);
|
||||
EXPECT_EQ(container['b'], -2);
|
||||
EXPECT_EQ(container['c'], -1);
|
||||
EXPECT_EQ(container['d'], 1);
|
||||
EXPECT_EQ(container.erase('d'), 1u);
|
||||
EXPECT_TRUE(container.find('d') == container.end());
|
||||
container.clear();
|
||||
|
||||
Container container2 = std::move(container);
|
||||
}
|
||||
{
|
||||
typedef ozz::multimap<char, int> Container;
|
||||
Container container;
|
||||
container.insert(std::pair<char, int>('a', -3));
|
||||
container.insert(std::pair<char, int>('c', -1));
|
||||
container.insert(std::pair<char, int>('b', -2));
|
||||
container.insert(std::pair<char, int>('d', 1));
|
||||
container.insert(std::pair<char, int>('d', 2));
|
||||
EXPECT_EQ(container.find('a')->second, -3);
|
||||
EXPECT_EQ(container.find('b')->second, -2);
|
||||
EXPECT_EQ(container.find('c')->second, -1);
|
||||
EXPECT_TRUE(container.find('d')->second == 1 ||
|
||||
container.find('d')->second == 2);
|
||||
EXPECT_EQ(container.erase('d'), 2u);
|
||||
EXPECT_TRUE(container.find('d') == container.end());
|
||||
container.clear();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UnorderedMap, Containers) {
|
||||
{
|
||||
typedef ozz::unordered_map<char, int> Container;
|
||||
Container container;
|
||||
container['a'] = -3;
|
||||
container['c'] = -1;
|
||||
container['b'] = -2;
|
||||
container['d'] = 1;
|
||||
EXPECT_EQ(container['a'], -3);
|
||||
EXPECT_EQ(container['b'], -2);
|
||||
EXPECT_EQ(container['c'], -1);
|
||||
EXPECT_EQ(container['d'], 1);
|
||||
EXPECT_EQ(container.erase('d'), 1u);
|
||||
EXPECT_TRUE(container.find('d') == container.end());
|
||||
container.clear();
|
||||
}
|
||||
{
|
||||
typedef ozz::unordered_multimap<char, int> Container;
|
||||
Container container;
|
||||
container.insert(std::pair<char, int>('a', -3));
|
||||
container.insert(std::pair<char, int>('c', -1));
|
||||
container.insert(std::pair<char, int>('b', -2));
|
||||
container.insert(std::pair<char, int>('d', 1));
|
||||
container.insert(std::pair<char, int>('d', 2));
|
||||
EXPECT_EQ(container.find('a')->second, -3);
|
||||
EXPECT_EQ(container.find('b')->second, -2);
|
||||
EXPECT_EQ(container.find('c')->second, -1);
|
||||
EXPECT_TRUE(container.find('d')->second == 1 ||
|
||||
container.find('d')->second == 2);
|
||||
EXPECT_EQ(container.erase('d'), 2u);
|
||||
EXPECT_TRUE(container.find('d') == container.end());
|
||||
container.clear();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(string, Containers) {
|
||||
typedef ozz::string string;
|
||||
string str;
|
||||
EXPECT_EQ(str.size(), 0u);
|
||||
str += "a string";
|
||||
EXPECT_STREQ(str.c_str(), "a string");
|
||||
|
||||
string str2 = std::move(str);
|
||||
EXPECT_STREQ(str2.c_str(), "a string");
|
||||
|
||||
str2.clear();
|
||||
EXPECT_EQ(str2.size(), 0u);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/endianness.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(NativeEndianness, Endianness) {
|
||||
// Uses pre-defined macro to check know endianness.
|
||||
// Endianness detection does not rely on this as this is not standard, but it
|
||||
// helps with testing.
|
||||
|
||||
// x86 and x86-64 Little endian processors.
|
||||
#if defined(i386) || defined(__i386__) || /*GNU C*/ \
|
||||
defined(__X86__) || /*MinGW32*/ \
|
||||
defined(__x86_64__) || /*Intel C/C++*/ \
|
||||
defined(_M_IX86) || /*Visual Studio*/ \
|
||||
defined(_M_X64) /*Visual Studio*/
|
||||
EXPECT_EQ(ozz::GetNativeEndianness(), ozz::kLittleEndian);
|
||||
#endif
|
||||
|
||||
// PowerPc Big endian processors.
|
||||
#if defined(__POWERPC__) || defined(__ppc__) || \
|
||||
defined(__powerpc__) || /*GNU C*/ \
|
||||
defined(__IA64__) || defined(__ia64__) || \
|
||||
defined(_M_PPC) /*Visual Studio*/
|
||||
EXPECT_EQ(ozz::GetNativeEndianness(), ozz::kBigEndian);
|
||||
#endif
|
||||
|
||||
// Itanium Big endian processors.
|
||||
#if defined(_IA64) || /*GNU C*/ \
|
||||
defined(_M_IA64) || /*Visual Studio*/ \
|
||||
defined(_M_IA64) /*Intel C/C++*/
|
||||
EXPECT_EQ(ozz::GetNativeEndianness(), ozz::kBigEndian);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Swap, Endianness) {
|
||||
{ // 1 byte swapping.
|
||||
uint8_t uo = 0x46;
|
||||
EXPECT_EQ(ozz::EndianSwap(uo), 0x46);
|
||||
}
|
||||
{ // 1 byte array swapping.
|
||||
uint8_t uo[] = {0x46, 0x58};
|
||||
ozz::EndianSwap(uo, OZZ_ARRAY_SIZE(uo));
|
||||
EXPECT_EQ(uo[0], 0x46);
|
||||
EXPECT_EQ(uo[1], 0x58);
|
||||
}
|
||||
{ // 2 bytes swapping.
|
||||
uint16_t uo = 0x4699;
|
||||
EXPECT_EQ(ozz::EndianSwap(uo), 0x9946);
|
||||
}
|
||||
{ // 2 bytes array swapping.
|
||||
uint16_t uo[] = {0x4699, 0x5814};
|
||||
ozz::EndianSwap(uo, OZZ_ARRAY_SIZE(uo));
|
||||
EXPECT_EQ(uo[0], 0x9946);
|
||||
EXPECT_EQ(uo[1], 0x1458);
|
||||
}
|
||||
{ // 4 bytes swapping.
|
||||
uint32_t uo = 0x46992715;
|
||||
EXPECT_EQ(ozz::EndianSwap(uo), 0x15279946u);
|
||||
}
|
||||
{ // 2 bytes array swapping.
|
||||
uint32_t uo[] = {0x46992715, 0x58142611};
|
||||
ozz::EndianSwap(uo, OZZ_ARRAY_SIZE(uo));
|
||||
EXPECT_EQ(uo[0], 0x15279946u);
|
||||
EXPECT_EQ(uo[1], 0x11261458u);
|
||||
}
|
||||
{ // 8 bytes swapping.
|
||||
uint64_t uo = 0x4699271511190417ull;
|
||||
EXPECT_EQ(ozz::EndianSwap(uo), 0x1704191115279946ull);
|
||||
}
|
||||
{ // 8 bytes array swapping.
|
||||
uint64_t uo[] = {0x4699271511190417ull, 0x5814264669080735ull};
|
||||
ozz::EndianSwap(uo, OZZ_ARRAY_SIZE(uo));
|
||||
EXPECT_EQ(uo[0], 0x1704191115279946ull);
|
||||
EXPECT_EQ(uo[1], 0x3507086946261458ull);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
add_executable(test_archive
|
||||
archive_tests.cc
|
||||
archive_tests_objects.cc
|
||||
archive_tests_objects.h)
|
||||
target_link_libraries(test_archive
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_archive COMMAND test_archive)
|
||||
set_target_properties(test_archive PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_stream
|
||||
stream_tests.cc)
|
||||
target_link_libraries(test_stream
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_stream COMMAND test_stream)
|
||||
set_target_properties(test_stream PROPERTIES FOLDER "ozz/tests/base")
|
||||
@@ -0,0 +1,311 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
#include "archive_tests_objects.h"
|
||||
|
||||
TEST(Error, Archive) {
|
||||
{ // Invalid nullptr stream.
|
||||
EXPECT_ASSERTION(
|
||||
void(ozz::io::OArchive(nullptr, ozz::GetNativeEndianness())),
|
||||
"valid opened stream");
|
||||
EXPECT_ASSERTION(void(ozz::io::IArchive(nullptr)), "valid opened stream");
|
||||
}
|
||||
{ // Invalid not opened streams.
|
||||
ozz::io::File stream("root_that_does_not_exist:/file.ozz", "r");
|
||||
EXPECT_ASSERTION(
|
||||
void(ozz::io::OArchive(&stream, ozz::GetNativeEndianness())),
|
||||
"valid opened stream");
|
||||
EXPECT_ASSERTION(void(ozz::io::IArchive(&stream)), "valid opened stream");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Primitives, Archive) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Write primitive types.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
const int8_t i8o = 46;
|
||||
o << i8o;
|
||||
const uint8_t ui8o = 46;
|
||||
o << ui8o;
|
||||
const int16_t i16o = 46;
|
||||
o << i16o;
|
||||
const uint16_t ui16o = 46;
|
||||
o << ui16o;
|
||||
const int32_t i32o = 46;
|
||||
o << i32o;
|
||||
const uint32_t ui32o = 46;
|
||||
o << ui32o;
|
||||
const int64_t i64o = 46;
|
||||
o << i64o;
|
||||
const uint64_t ui64o = 46;
|
||||
o << ui64o;
|
||||
const bool bo = true;
|
||||
o << bo;
|
||||
const float fo = 46.f;
|
||||
o << fo;
|
||||
|
||||
// Read primitive types.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
int8_t i8i;
|
||||
i >> i8i;
|
||||
EXPECT_EQ(i8i, i8o);
|
||||
uint8_t ui8i;
|
||||
i >> ui8i;
|
||||
EXPECT_EQ(ui8i, ui8o);
|
||||
int16_t i16i;
|
||||
i >> i16i;
|
||||
EXPECT_EQ(i16i, i16o);
|
||||
uint16_t ui16i;
|
||||
i >> ui16i;
|
||||
EXPECT_EQ(ui16i, ui16o);
|
||||
int32_t i32i;
|
||||
i >> i32i;
|
||||
EXPECT_EQ(i32i, i32o);
|
||||
uint32_t ui32i;
|
||||
i >> ui32i;
|
||||
EXPECT_EQ(ui32i, ui32o);
|
||||
int64_t i64i;
|
||||
i >> i64i;
|
||||
EXPECT_EQ(i64i, i64o);
|
||||
uint64_t ui64i;
|
||||
i >> ui64i;
|
||||
EXPECT_EQ(ui64i, ui64o);
|
||||
bool bi;
|
||||
i >> bi;
|
||||
EXPECT_EQ(bi, bo);
|
||||
float fi;
|
||||
i >> fi;
|
||||
EXPECT_EQ(fi, fo);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PrimitiveArrays, Archive) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Write primitive types.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
const int8_t i8o[] = {46, 26, 14, 58, 99, 27};
|
||||
o << ozz::io::MakeArray(i8o);
|
||||
const uint8_t ui8o[] = {46, 26, 14, 58, 99, 27};
|
||||
o << ozz::io::MakeArray(ui8o);
|
||||
const int16_t i16o[] = {46, 26, 14, 58, 99, 27};
|
||||
o << ozz::io::MakeArray(i16o);
|
||||
const uint16_t ui16o[] = {46, 26, 14, 58, 99, 27};
|
||||
o << ozz::io::MakeArray(ui16o);
|
||||
const int32_t i32o[] = {46, 26, 14, 58, 99, 27};
|
||||
o << ozz::io::MakeArray(i32o);
|
||||
const uint32_t ui32o[] = {46, 26, 14, 58, 99, 27};
|
||||
o << ozz::io::MakeArray(ui32o);
|
||||
const int64_t i64o[] = {46, 26, 14, 58, 99, 27};
|
||||
o << ozz::io::MakeArray(i64o);
|
||||
const uint64_t ui64o[] = {46, 26, 14, 58, 99, 27};
|
||||
o << ozz::io::MakeArray(ui64o);
|
||||
const bool bo[] = {true, false, true};
|
||||
o << ozz::io::MakeArray(bo);
|
||||
const float fo[] = {46.f, 26.f, 14.f, 58.f, 99.f, 27.f};
|
||||
o << ozz::io::MakeArray(fo);
|
||||
const uint32_t* po_null = nullptr;
|
||||
o << ozz::io::MakeArray(po_null, 0);
|
||||
const ozz::span<const float> rfo(fo);
|
||||
o << ozz::io::MakeArray(rfo);
|
||||
|
||||
// Read primitive types.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
int8_t i8i[OZZ_ARRAY_SIZE(i8o)];
|
||||
i >> ozz::io::MakeArray(i8i);
|
||||
EXPECT_EQ(std::memcmp(i8i, i8o, sizeof(i8o)), 0);
|
||||
uint8_t ui8i[OZZ_ARRAY_SIZE(ui8o)];
|
||||
i >> ozz::io::MakeArray(ui8i);
|
||||
EXPECT_EQ(std::memcmp(ui8i, ui8o, sizeof(ui8o)), 0);
|
||||
int16_t i16i[OZZ_ARRAY_SIZE(i16o)];
|
||||
i >> ozz::io::MakeArray(i16i);
|
||||
EXPECT_EQ(std::memcmp(i16i, i16o, sizeof(i16o)), 0);
|
||||
uint16_t ui16i[OZZ_ARRAY_SIZE(ui16o)];
|
||||
i >> ozz::io::MakeArray(ui16i);
|
||||
EXPECT_EQ(std::memcmp(ui16i, ui16o, sizeof(ui16o)), 0);
|
||||
int32_t i32i[OZZ_ARRAY_SIZE(i32o)];
|
||||
i >> ozz::io::MakeArray(i32i);
|
||||
EXPECT_EQ(std::memcmp(i32i, i32o, sizeof(i32o)), 0);
|
||||
uint32_t ui32i[OZZ_ARRAY_SIZE(ui32o)];
|
||||
i >> ozz::io::MakeArray(ui32i);
|
||||
EXPECT_EQ(std::memcmp(ui32i, ui32o, sizeof(ui32o)), 0);
|
||||
int64_t i64i[OZZ_ARRAY_SIZE(i64o)];
|
||||
i >> ozz::io::MakeArray(i64i);
|
||||
EXPECT_EQ(std::memcmp(i64i, i64o, sizeof(i64o)), 0);
|
||||
uint64_t ui64i[OZZ_ARRAY_SIZE(ui64o)];
|
||||
i >> ozz::io::MakeArray(ui64i);
|
||||
EXPECT_EQ(std::memcmp(ui64i, ui64o, sizeof(ui64o)), 0);
|
||||
bool bi[OZZ_ARRAY_SIZE(bo)];
|
||||
i >> ozz::io::MakeArray(bi);
|
||||
EXPECT_EQ(std::memcmp(bi, bo, sizeof(bo)), 0);
|
||||
float fi[OZZ_ARRAY_SIZE(fo)];
|
||||
i >> ozz::io::MakeArray(fi);
|
||||
EXPECT_EQ(std::memcmp(fi, fo, sizeof(fo)), 0);
|
||||
uint32_t* pi_null = nullptr;
|
||||
i >> ozz::io::MakeArray(pi_null, 0);
|
||||
float fi2[OZZ_ARRAY_SIZE(fo)];
|
||||
ozz::span<float> rfi(fi2);
|
||||
i >> ozz::io::MakeArray(rfi);
|
||||
EXPECT_EQ(std::memcmp(rfi.data(), fo, sizeof(fo)), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Class, Archive) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Write classes.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
const Intrusive oi(46);
|
||||
o << oi;
|
||||
const Intrusive oi_mutable(46);
|
||||
o << oi_mutable;
|
||||
const Extrusive oe = {58};
|
||||
o << oe;
|
||||
const Extrusive oe_mutable = {58};
|
||||
o << oe_mutable;
|
||||
|
||||
// Read classes.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
Intrusive ii;
|
||||
i >> ii;
|
||||
EXPECT_EQ(ii.i, oi.i);
|
||||
Intrusive ii_mutable;
|
||||
i >> ii_mutable;
|
||||
EXPECT_EQ(ii_mutable.i, oi_mutable.i);
|
||||
Extrusive ie;
|
||||
i >> ie;
|
||||
EXPECT_EQ(ie.i, oe.i);
|
||||
Extrusive ie_mutable;
|
||||
i >> ie_mutable;
|
||||
EXPECT_EQ(ie_mutable.i, oe_mutable.i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ClassArrays, Archive) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Write classes.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
const Intrusive oi[12];
|
||||
o << ozz::io::MakeArray(oi);
|
||||
const Extrusive oe[] = {{46}, {58}, {14}, {26}, {99}};
|
||||
o << ozz::io::MakeArray(oe);
|
||||
|
||||
// Read classes.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
Intrusive ii[OZZ_ARRAY_SIZE(oi)];
|
||||
i >> ozz::io::MakeArray(ii);
|
||||
EXPECT_EQ(std::memcmp(oi, ii, sizeof(oi)), 0);
|
||||
Extrusive ie[OZZ_ARRAY_SIZE(oe)];
|
||||
i >> ozz::io::MakeArray(ie);
|
||||
EXPECT_EQ(std::memcmp(oe, ie, sizeof(oe)), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Tag, Archive) {
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Writes to archive.
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
Tagged1 ot;
|
||||
o << ot;
|
||||
|
||||
// Reads from archive.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
// Tests and reads a wrong object (different tag).
|
||||
OZZ_IF_DEBUG(Tagged2 it2);
|
||||
EXPECT_FALSE(i.TestTag<Tagged2>());
|
||||
EXPECT_ASSERTION(i >> it2, "Type tag does not match archive content.");
|
||||
|
||||
// Reads the right object (different tag).
|
||||
Tagged1 it1;
|
||||
EXPECT_TRUE(i.TestTag<Tagged1>());
|
||||
EXPECT_NO_FATAL_FAILURE(i >> it1);
|
||||
}
|
||||
|
||||
TEST(TagEOF, Archive) {
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Writes to archive n elements.
|
||||
const int n_writes = 10;
|
||||
ozz::io::OArchive o(&stream, ozz::GetNativeEndianness());
|
||||
for (int i = 0; i < n_writes; ++i) {
|
||||
Tagged1 ot;
|
||||
o << ot;
|
||||
}
|
||||
|
||||
// Reads from archive.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
|
||||
EXPECT_FALSE(i.TestTag<Tagged2>());
|
||||
|
||||
// Tests and reads all objects.
|
||||
int n_read = 0;
|
||||
while (i.TestTag<Tagged1>()) {
|
||||
Tagged1 it;
|
||||
i >> it;
|
||||
++n_read;
|
||||
}
|
||||
EXPECT_EQ(n_read, n_writes);
|
||||
|
||||
EXPECT_FALSE(i.TestTag<Tagged2>());
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "archive_tests_objects.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
|
||||
void Intrusive::Save(ozz::io::OArchive& _archive) const { _archive << i; }
|
||||
|
||||
void Intrusive::Load(ozz::io::IArchive& _archive, uint32_t _version) {
|
||||
EXPECT_EQ(_version, 46u);
|
||||
_archive >> i;
|
||||
}
|
||||
|
||||
namespace ozz {
|
||||
namespace io {
|
||||
|
||||
// Specializes Extrusive type external Save and Load functions.
|
||||
void Extern<Extrusive>::Save(OArchive& _archive, const Extrusive* _test,
|
||||
size_t _count) {
|
||||
_archive << ozz::io::MakeArray(&_test->i, _count);
|
||||
}
|
||||
void Extern<Extrusive>::Load(IArchive& _archive, Extrusive* _test,
|
||||
size_t _count, uint32_t _version) {
|
||||
EXPECT_EQ(_version, 0u);
|
||||
_archive >> ozz::io::MakeArray(&_test->i, _count);
|
||||
}
|
||||
} // namespace io
|
||||
} // namespace ozz
|
||||
|
||||
void Tagged1::Save(ozz::io::OArchive& /*_archive*/) const {}
|
||||
void Tagged1::Load(ozz::io::IArchive& /*_archive*/, uint32_t /*_version*/) {}
|
||||
void Tagged2::Save(ozz::io::OArchive& /*_archive*/) const {}
|
||||
void Tagged2::Load(ozz::io::IArchive& /*_archive*/, uint32_t /*_version*/) {}
|
||||
@@ -0,0 +1,90 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef OZZ_TEST_BASE_IO_ARCHIVE_TESTS_OBJECTS_H_
|
||||
#define OZZ_TEST_BASE_IO_ARCHIVE_TESTS_OBJECTS_H_
|
||||
|
||||
#include "ozz/base/io/archive_traits.h"
|
||||
#include "ozz/base/platform.h"
|
||||
|
||||
namespace ozz {
|
||||
namespace io {
|
||||
class OArchive;
|
||||
class IArchive;
|
||||
} // namespace io
|
||||
} // namespace ozz
|
||||
|
||||
struct Intrusive {
|
||||
explicit Intrusive(int32_t _i = 12) : i(_i) {}
|
||||
void Save(ozz::io::OArchive& _archive) const;
|
||||
void Load(ozz::io::IArchive& _archive, uint32_t _version);
|
||||
int32_t i;
|
||||
};
|
||||
|
||||
struct Extrusive {
|
||||
uint64_t i;
|
||||
};
|
||||
|
||||
namespace ozz {
|
||||
namespace io {
|
||||
// Give Intrusive type a version.
|
||||
OZZ_IO_TYPE_VERSION(46, Intrusive)
|
||||
|
||||
// Extrusive is not versionable.
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(Extrusive)
|
||||
|
||||
// Specializes Extrusive type external Save and Load functions.
|
||||
template <>
|
||||
struct Extern<Extrusive> {
|
||||
static void Save(OArchive& _archive, const Extrusive* _test, size_t _count);
|
||||
static void Load(IArchive& _archive, Extrusive* _test, size_t _count,
|
||||
uint32_t _version);
|
||||
};
|
||||
} // namespace io
|
||||
} // namespace ozz
|
||||
|
||||
class Tagged1 {
|
||||
public:
|
||||
void Save(ozz::io::OArchive& _archive) const;
|
||||
void Load(ozz::io::IArchive& _archive, uint32_t _version);
|
||||
};
|
||||
|
||||
class Tagged2 {
|
||||
public:
|
||||
void Save(ozz::io::OArchive& _archive) const;
|
||||
void Load(ozz::io::IArchive& _archive, uint32_t _version);
|
||||
};
|
||||
|
||||
namespace ozz {
|
||||
namespace io {
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(Tagged1)
|
||||
OZZ_IO_TYPE_TAG("tagged1", Tagged1)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(Tagged2)
|
||||
OZZ_IO_TYPE_TAG("tagged2", Tagged2)
|
||||
} // namespace io
|
||||
} // namespace ozz
|
||||
#endif // OZZ_TEST_BASE_IO_ARCHIVE_TESTS_OBJECTS_H_
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/io/stream.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/platform.h"
|
||||
|
||||
void TestStream(ozz::io::Stream* _stream) {
|
||||
ASSERT_TRUE(_stream->opened());
|
||||
EXPECT_EQ(_stream->Size(), 0u);
|
||||
EXPECT_EQ(_stream->Seek(0, ozz::io::Stream::kSet), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
typedef int Type;
|
||||
const Type to_write = 46;
|
||||
EXPECT_EQ(_stream->Write(&to_write, sizeof(Type)), sizeof(Type));
|
||||
EXPECT_EQ(_stream->Tell(), static_cast<int>(sizeof(Type)));
|
||||
EXPECT_EQ(_stream->Seek(0, ozz::io::Stream::kSet), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
EXPECT_EQ(_stream->Size(), sizeof(Type));
|
||||
Type to_read = 0;
|
||||
EXPECT_EQ(_stream->Read(&to_read, sizeof(Type)), sizeof(Type));
|
||||
EXPECT_EQ(to_read, to_write);
|
||||
EXPECT_EQ(_stream->Tell(), static_cast<int>(sizeof(Type)));
|
||||
EXPECT_EQ(_stream->Size(), sizeof(Type));
|
||||
}
|
||||
|
||||
void TestSeek(ozz::io::Stream* _stream) {
|
||||
ASSERT_TRUE(_stream->opened());
|
||||
EXPECT_EQ(_stream->Seek(0, ozz::io::Stream::kSet), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
EXPECT_EQ(_stream->Size(), 0u);
|
||||
|
||||
// Seeking before file's begin.
|
||||
EXPECT_NE(_stream->Seek(-1, ozz::io::Stream::kSet), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
EXPECT_NE(_stream->Seek(-1, ozz::io::Stream::kCurrent), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
EXPECT_NE(_stream->Seek(-1, ozz::io::Stream::kEnd), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
EXPECT_EQ(_stream->Size(), 0u);
|
||||
|
||||
// Bad seek argument.
|
||||
EXPECT_EQ(_stream->Seek(46, ozz::io::Stream::Origin(27)), -1);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
EXPECT_EQ(_stream->Size(), 0u);
|
||||
|
||||
typedef int Type;
|
||||
const Type to_write = 46;
|
||||
EXPECT_EQ(_stream->Write(&to_write, sizeof(Type)), sizeof(Type));
|
||||
EXPECT_EQ(_stream->Tell(), static_cast<int>(sizeof(Type)));
|
||||
EXPECT_EQ(_stream->Size(), sizeof(Type));
|
||||
|
||||
const int64_t kEnd = 465827;
|
||||
// Force file length to kEnd but do not write to the stream.
|
||||
EXPECT_EQ(_stream->Seek(kEnd - _stream->Tell(), ozz::io::Stream::kCurrent),
|
||||
0);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd);
|
||||
EXPECT_EQ(_stream->Size(), sizeof(Type));
|
||||
|
||||
Type to_read = 0;
|
||||
EXPECT_EQ(_stream->Seek(0, ozz::io::Stream::kSet), 0);
|
||||
EXPECT_EQ(_stream->Size(), sizeof(Type));
|
||||
EXPECT_EQ(_stream->Read(&to_read, sizeof(Type)), sizeof(Type));
|
||||
EXPECT_EQ(to_read, to_write);
|
||||
EXPECT_EQ(_stream->Tell(), static_cast<int>(sizeof(Type)));
|
||||
EXPECT_EQ(_stream->Read(&to_read, sizeof(Type)), 0u);
|
||||
EXPECT_EQ(_stream->Tell(), static_cast<int>(sizeof(Type)));
|
||||
EXPECT_EQ(_stream->Size(), sizeof(Type));
|
||||
|
||||
// Force file length to kEnd + sizeof(Type) and write to the stream.
|
||||
EXPECT_EQ(
|
||||
_stream->Seek(kEnd - _stream->Tell() - static_cast<int>(sizeof(Type)),
|
||||
ozz::io::Stream::kCurrent),
|
||||
0);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd - static_cast<int>(sizeof(Type)));
|
||||
EXPECT_EQ(_stream->Write(&to_write, sizeof(Type)), sizeof(Type));
|
||||
EXPECT_EQ(_stream->Tell(), kEnd);
|
||||
EXPECT_EQ(
|
||||
_stream->Seek(-static_cast<int>(sizeof(Type)), ozz::io::Stream::kEnd), 0);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd - static_cast<int>(sizeof(Type)));
|
||||
EXPECT_EQ(_stream->Read(&to_read, sizeof(Type)), sizeof(Type));
|
||||
EXPECT_EQ(to_read, to_write);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd);
|
||||
EXPECT_EQ(
|
||||
_stream->Seek(-static_cast<int>(sizeof(Type)) * 2, ozz::io::Stream::kEnd),
|
||||
0);
|
||||
EXPECT_EQ(_stream->Read(&to_read, sizeof(Type)), sizeof(Type));
|
||||
EXPECT_EQ(to_read, 0);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd - static_cast<int>(sizeof(Type)));
|
||||
// Rewind from kEnd.
|
||||
EXPECT_EQ(_stream->Seek(-kEnd, ozz::io::Stream::kEnd), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
EXPECT_EQ(_stream->Seek(kEnd, ozz::io::Stream::kSet), 0);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd);
|
||||
|
||||
// Read at the end of the file.
|
||||
EXPECT_EQ(_stream->Read(&to_read, sizeof(Type)), 0u);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd);
|
||||
|
||||
// Read after a seek beyond the end of the file.
|
||||
EXPECT_EQ(_stream->Seek(4, ozz::io::Stream::kCurrent), 0);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd + 4);
|
||||
EXPECT_EQ(_stream->Read(&to_read, sizeof(Type)), 0u);
|
||||
EXPECT_EQ(_stream->Tell(), kEnd + 4);
|
||||
EXPECT_EQ(_stream->Size(), static_cast<size_t>(kEnd));
|
||||
}
|
||||
|
||||
void TestTooBigStream(ozz::io::Stream* _stream) {
|
||||
const int max_size = std::numeric_limits<int>::max();
|
||||
ASSERT_TRUE(_stream->opened());
|
||||
EXPECT_EQ(_stream->Seek(0, ozz::io::Stream::kSet), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 0);
|
||||
|
||||
// Seeks outside of Stream valid range.
|
||||
EXPECT_EQ(_stream->Seek(max_size, ozz::io::Stream::kCurrent), 0);
|
||||
EXPECT_EQ(_stream->Tell(), max_size);
|
||||
EXPECT_EQ(_stream->Size(), 0u);
|
||||
EXPECT_NE(_stream->Seek(max_size, ozz::io::Stream::kCurrent), 0);
|
||||
EXPECT_EQ(_stream->Tell(), max_size);
|
||||
EXPECT_EQ(_stream->Size(), 0u);
|
||||
|
||||
// Writes/Reads outside of Stream valid range.
|
||||
EXPECT_EQ(_stream->Seek(1, ozz::io::Stream::kSet), 0);
|
||||
EXPECT_EQ(_stream->Tell(), 1);
|
||||
char c;
|
||||
EXPECT_EQ(_stream->Write(&c, max_size), 0u);
|
||||
EXPECT_EQ(_stream->Read(&c, max_size), 0u);
|
||||
EXPECT_EQ(_stream->Size(), 0u);
|
||||
}
|
||||
|
||||
TEST(File, Stream) {
|
||||
{
|
||||
ozz::io::File file(nullptr);
|
||||
EXPECT_FALSE(file.opened());
|
||||
}
|
||||
{ EXPECT_FALSE(ozz::io::File::Exist("unexisting.file")); }
|
||||
{
|
||||
ozz::io::File file("test.bin", "w+t");
|
||||
EXPECT_TRUE(file.opened());
|
||||
TestSeek(&file);
|
||||
}
|
||||
{ EXPECT_TRUE(ozz::io::File::Exist("test.bin")); }
|
||||
}
|
||||
|
||||
TEST(MemoryStream, Stream) {
|
||||
{
|
||||
ozz::io::MemoryStream stream;
|
||||
TestStream(&stream);
|
||||
}
|
||||
{
|
||||
ozz::io::MemoryStream stream;
|
||||
TestSeek(&stream);
|
||||
}
|
||||
{
|
||||
ozz::io::MemoryStream stream;
|
||||
TestTooBigStream(&stream);
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/log.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
int TestFunction(std::ostream& _stream, const char* _log) {
|
||||
_stream << _log << std::endl;
|
||||
return 46;
|
||||
}
|
||||
|
||||
void TestLogLevel(ozz::log::Level _level) {
|
||||
ozz::log::SetLevel(_level);
|
||||
|
||||
EXPECT_LOG_LOGV(TestFunction(ozz::log::LogV(), "logv"), "logv");
|
||||
EXPECT_LOG_LOG(TestFunction(ozz::log::Log(), "log"), "log");
|
||||
EXPECT_LOG_OUT(TestFunction(ozz::log::Out(), "out"), "out");
|
||||
EXPECT_LOG_ERR(TestFunction(ozz::log::Err(), "err"), "err");
|
||||
|
||||
EXPECT_EQ_LOG_LOGV(TestFunction(ozz::log::LogV(), "logv"), 46, "logv");
|
||||
EXPECT_EQ_LOG_LOG(TestFunction(ozz::log::Log(), "log"), 46, "log");
|
||||
EXPECT_EQ_LOG_OUT(TestFunction(ozz::log::Out(), "out"), 46, "out");
|
||||
EXPECT_EQ_LOG_ERR(TestFunction(ozz::log::Err(), "err"), 46, "err");
|
||||
}
|
||||
|
||||
TEST(Silent, Log) { TestLogLevel(ozz::log::kSilent); }
|
||||
|
||||
TEST(Standard, Log) { TestLogLevel(ozz::log::kStandard); }
|
||||
|
||||
TEST(Verbose, Log) { TestLogLevel(ozz::log::kVerbose); }
|
||||
|
||||
TEST(FloatPrecision, Log) {
|
||||
const float number = 46.9352099f;
|
||||
ozz::log::Log log;
|
||||
|
||||
ozz::log::FloatPrecision mod0(log, 0);
|
||||
EXPECT_LOG_LOG(log << number << '-' << std::endl, "47-");
|
||||
{
|
||||
ozz::log::FloatPrecision mod2(log, 2);
|
||||
EXPECT_LOG_LOG(log << number << '-' << std::endl, "46.94-");
|
||||
}
|
||||
EXPECT_LOG_LOG(log << number << '-' << std::endl, "47-");
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
add_executable(test_math
|
||||
math_ex_tests.cc
|
||||
box_tests.cc
|
||||
rect_tests.cc
|
||||
vec_float_tests.cc
|
||||
quaternion_tests.cc
|
||||
transform_tests.cc)
|
||||
target_link_libraries(test_math
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_math COMMAND test_math)
|
||||
set_target_properties(test_math PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_simd_math
|
||||
simd_int_math_tests.cc
|
||||
simd_float_math_tests.cc
|
||||
simd_float4x4_tests.cc
|
||||
simd_quaternion_math_tests.cc
|
||||
simd_math_transpose_tests.cc)
|
||||
target_link_libraries(test_simd_math
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_simd_math COMMAND test_simd_math)
|
||||
set_target_properties(test_simd_math PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_soa_math
|
||||
soa_float_tests.cc
|
||||
soa_quaternion_tests.cc
|
||||
soa_transform_tests.cc
|
||||
soa_float4x4_tests.cc)
|
||||
target_link_libraries(test_soa_math
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_soa_math COMMAND test_soa_math)
|
||||
set_target_properties(test_soa_math PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_archive_maths
|
||||
math_archive_tests.cc
|
||||
simd_math_archive_tests.cc
|
||||
soa_math_archive_tests.cc)
|
||||
target_link_libraries(test_archive_maths
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_archive_maths COMMAND test_archive_maths)
|
||||
set_target_properties(test_archive_maths PROPERTIES FOLDER "ozz/tests/base")
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/box.h"
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
TEST(BoxValidity, ozz_math) {
|
||||
EXPECT_FALSE(ozz::math::Box().is_valid());
|
||||
EXPECT_FALSE(ozz::math::Box(ozz::math::Float3(0.f, 1.f, 2.f),
|
||||
ozz::math::Float3(0.f, -1.f, 2.f))
|
||||
.is_valid());
|
||||
EXPECT_TRUE(ozz::math::Box(ozz::math::Float3(0.f, -1.f, 2.f),
|
||||
ozz::math::Float3(0.f, 1.f, 2.f))
|
||||
.is_valid());
|
||||
EXPECT_TRUE(ozz::math::Box(ozz::math::Float3(0.f, 1.f, 2.f),
|
||||
ozz::math::Float3(0.f, 1.f, 2.f))
|
||||
.is_valid());
|
||||
}
|
||||
|
||||
TEST(BoxInside, ozz_math) {
|
||||
const ozz::math::Box invalid(ozz::math::Float3(0.f, 1.f, 2.f),
|
||||
ozz::math::Float3(0.f, -1.f, 2.f));
|
||||
EXPECT_FALSE(invalid.is_valid());
|
||||
EXPECT_FALSE(invalid.is_inside(ozz::math::Float3(0.f, 1.f, 2.f)));
|
||||
EXPECT_FALSE(invalid.is_inside(ozz::math::Float3(0.f, -.5f, 2.f)));
|
||||
EXPECT_FALSE(invalid.is_inside(ozz::math::Float3(-1.f, -2.f, -3.f)));
|
||||
|
||||
const ozz::math::Box valid(ozz::math::Float3(-1.f, -2.f, -3.f),
|
||||
ozz::math::Float3(1.f, 2.f, 3.f));
|
||||
EXPECT_TRUE(valid.is_valid());
|
||||
EXPECT_FALSE(valid.is_inside(ozz::math::Float3(0.f, -3.f, 0.f)));
|
||||
EXPECT_FALSE(valid.is_inside(ozz::math::Float3(0.f, 3.f, 0.f)));
|
||||
EXPECT_TRUE(valid.is_inside(ozz::math::Float3(-1.f, -2.f, -3.f)));
|
||||
EXPECT_TRUE(valid.is_inside(ozz::math::Float3(0.f, 0.f, 0.f)));
|
||||
}
|
||||
|
||||
TEST(BoxMerge, ozz_math) {
|
||||
const ozz::math::Box invalid1(ozz::math::Float3(0.f, 1.f, 2.f),
|
||||
ozz::math::Float3(0.f, -1.f, 2.f));
|
||||
EXPECT_FALSE(invalid1.is_valid());
|
||||
const ozz::math::Box invalid2(ozz::math::Float3(0.f, -1.f, 2.f),
|
||||
ozz::math::Float3(0.f, 1.f, -2.f));
|
||||
EXPECT_FALSE(invalid2.is_valid());
|
||||
|
||||
const ozz::math::Box valid1(ozz::math::Float3(-1.f, -2.f, -3.f),
|
||||
ozz::math::Float3(1.f, 2.f, 3.f));
|
||||
EXPECT_TRUE(valid1.is_valid());
|
||||
const ozz::math::Box valid2(ozz::math::Float3(0.f, 5.f, -8.f),
|
||||
ozz::math::Float3(1.f, 6.f, 0.f));
|
||||
EXPECT_TRUE(valid2.is_valid());
|
||||
|
||||
// Both boxes are invalid.
|
||||
EXPECT_FALSE(Merge(invalid1, invalid2).is_valid());
|
||||
|
||||
// One box is invalid.
|
||||
EXPECT_TRUE(Merge(invalid1, valid1).is_valid());
|
||||
EXPECT_TRUE(Merge(valid1, invalid1).is_valid());
|
||||
|
||||
// Both boxes are valid.
|
||||
const ozz::math::Box merge = Merge(valid1, valid2);
|
||||
EXPECT_FLOAT3_EQ(merge.min, -1.f, -2.f, -8.f);
|
||||
EXPECT_FLOAT3_EQ(merge.max, 1.f, 6.f, 3.f);
|
||||
}
|
||||
|
||||
TEST(BoxTransform, ozz_math) {
|
||||
const ozz::math::Box a(ozz::math::Float3(1.f, 2.f, 3.f),
|
||||
ozz::math::Float3(4.f, 5.f, 6.f));
|
||||
|
||||
const ozz::math::Box ia = TransformBox(ozz::math::Float4x4::identity(), a);
|
||||
EXPECT_FLOAT3_EQ(ia.min, 1.f, 2.f, 3.f);
|
||||
EXPECT_FLOAT3_EQ(ia.max, 4.f, 5.f, 6.f);
|
||||
|
||||
const ozz::math::Box ta =
|
||||
TransformBox(ozz::math::Float4x4::Translation(
|
||||
ozz::math::simd_float4::Load(2.f, -2.f, 3.f, 0.f)),
|
||||
a);
|
||||
EXPECT_FLOAT3_EQ(ta.min, 3.f, 0.f, 6.f);
|
||||
EXPECT_FLOAT3_EQ(ta.max, 6.f, 3.f, 9.f);
|
||||
|
||||
const ozz::math::Box ra =
|
||||
TransformBox(ozz::math::Float4x4::FromAxisAngle(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::LoadX(ozz::math::kPi)),
|
||||
a);
|
||||
EXPECT_FLOAT3_EQ(ra.min, -4.f, 2.f, -6.f);
|
||||
EXPECT_FLOAT3_EQ(ra.max, -1.f, 5.f, -3.f);
|
||||
}
|
||||
|
||||
TEST(BoxBuild, ozz_math) {
|
||||
const struct {
|
||||
ozz::math::Float3 value;
|
||||
char pad;
|
||||
} points[] = {
|
||||
{ozz::math::Float3(0.f, 0.f, 0.f), 0},
|
||||
{ozz::math::Float3(1.f, -1.f, 0.f), 0},
|
||||
{ozz::math::Float3(0.f, 0.f, 46.f), 0},
|
||||
{ozz::math::Float3(-27.f, 0.f, 0.f), 0},
|
||||
{ozz::math::Float3(0.f, 58.f, 0.f), 0},
|
||||
};
|
||||
|
||||
// Builds from a single point
|
||||
const ozz::math::Box single_valid(points[1].value);
|
||||
EXPECT_TRUE(single_valid.is_valid());
|
||||
EXPECT_FLOAT3_EQ(single_valid.min, 1.f, -1.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(single_valid.max, 1.f, -1.f, 0.f);
|
||||
|
||||
// Builds from multiple points
|
||||
EXPECT_ASSERTION(ozz::math::Box(&points->value, 1, OZZ_ARRAY_SIZE(points)),
|
||||
"_stride must be greater or equal to sizeof\\(Float3\\)");
|
||||
|
||||
const ozz::math::Box multi_invalid(&points->value, sizeof(points[0]), 0);
|
||||
EXPECT_FALSE(multi_invalid.is_valid());
|
||||
|
||||
const ozz::math::Box multi_valid(&points->value, sizeof(points[0]),
|
||||
OZZ_ARRAY_SIZE(points));
|
||||
EXPECT_TRUE(multi_valid.is_valid());
|
||||
EXPECT_FLOAT3_EQ(multi_valid.min, -27.f, -1.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(multi_valid.max, 1.f, 58.f, 46.f);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/math_archive.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/maths/box.h"
|
||||
#include "ozz/base/maths/quaternion.h"
|
||||
#include "ozz/base/maths/rect.h"
|
||||
#include "ozz/base/maths/transform.h"
|
||||
#include "ozz/base/maths/vec_float.h"
|
||||
|
||||
TEST(MathArchive, ozz_math) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Write math types.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
const ozz::math::Float2 of2(46.f, 69.f);
|
||||
o << of2;
|
||||
const ozz::math::Float3 of3(46.f, 69.f, 58.f);
|
||||
o << of3;
|
||||
const ozz::math::Float4 of4(46.f, 69.f, 58.f, 35.f);
|
||||
o << of4;
|
||||
const ozz::math::Quaternion oquat(46.f, 69.f, 58.f, 35.f);
|
||||
o << oquat;
|
||||
const ozz::math::Transform otrans = {of3, oquat, of3};
|
||||
o << otrans;
|
||||
const ozz::math::Box o_box(ozz::math::Float3(14.f, 26.f, 46.f),
|
||||
ozz::math::Float3(58.f, 69.f, 99.f));
|
||||
o << o_box;
|
||||
const ozz::math::RectFloat o_rect_float(46.f, 69.f, 58.f, 35.f);
|
||||
o << o_rect_float;
|
||||
const ozz::math::RectInt o_rect_int(46, 69, 58, 35);
|
||||
o << o_rect_int;
|
||||
|
||||
// Reads math types.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
ozz::math::Float2 if2;
|
||||
i >> if2;
|
||||
EXPECT_FLOAT2_EQ(if2, 46.f, 69.f);
|
||||
ozz::math::Float3 if3;
|
||||
i >> if3;
|
||||
EXPECT_FLOAT3_EQ(if3, 46.f, 69.f, 58.f);
|
||||
ozz::math::Float4 if4;
|
||||
i >> if4;
|
||||
EXPECT_FLOAT4_EQ(if4, 46.f, 69.f, 58.f, 35.f);
|
||||
ozz::math::Quaternion iquat;
|
||||
i >> iquat;
|
||||
EXPECT_QUATERNION_EQ(iquat, 46.f, 69.f, 58.f, 35.f);
|
||||
ozz::math::Transform itrans;
|
||||
i >> itrans;
|
||||
EXPECT_FLOAT3_EQ(itrans.translation, 46.f, 69.f, 58.f);
|
||||
EXPECT_QUATERNION_EQ(itrans.rotation, 46.f, 69.f, 58.f, 35.f);
|
||||
EXPECT_FLOAT3_EQ(itrans.scale, 46.f, 69.f, 58.f);
|
||||
ozz::math::Box i_box;
|
||||
i >> i_box;
|
||||
EXPECT_FLOAT3_EQ(i_box.min, 14.f, 26.f, 46.f);
|
||||
EXPECT_FLOAT3_EQ(i_box.max, 58.f, 69.f, 99.f);
|
||||
ozz::math::RectFloat i_rect_float;
|
||||
i >> i_rect_float;
|
||||
EXPECT_FLOAT_EQ(i_rect_float.left, 46.f);
|
||||
EXPECT_FLOAT_EQ(i_rect_float.bottom, 69.f);
|
||||
EXPECT_FLOAT_EQ(i_rect_float.width, 58.f);
|
||||
EXPECT_FLOAT_EQ(i_rect_float.height, 35.f);
|
||||
ozz::math::RectInt i_rect_int;
|
||||
i >> i_rect_int;
|
||||
EXPECT_EQ(i_rect_int.left, 46);
|
||||
EXPECT_EQ(i_rect_int.bottom, 69);
|
||||
EXPECT_EQ(i_rect_int.width, 58);
|
||||
EXPECT_EQ(i_rect_int.height, 35);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
TEST(Trigonometry, ozz_math_ex) {
|
||||
EXPECT_FLOAT_EQ(ozz::math::kPi, 3.1415926535897932384626433832795f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::kPi * ozz::math::kRadianToDegree, 180.f);
|
||||
EXPECT_FLOAT_EQ(180.f * ozz::math::kDegreeToRadian, ozz::math::kPi);
|
||||
}
|
||||
|
||||
TEST(FloatArithmetic, ozz_math_ex) {
|
||||
EXPECT_FLOAT_EQ(ozz::math::Lerp(0.f, 1.f, 0.f), 0.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::Lerp(0.f, 1.f, 1.f), 1.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::Lerp(0.f, 1.f, .3f), .3f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::Lerp(0.f, 1.f, 12.f), 12.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::Lerp(0.f, 1.f, -12.f), -12.f);
|
||||
}
|
||||
|
||||
TEST(FloatComparison, ozz_math_ex) {
|
||||
const float a = {.5f};
|
||||
const float b = {4.f};
|
||||
const float c = {2.f};
|
||||
|
||||
const float min = ozz::math::Min(a, b);
|
||||
EXPECT_FLOAT_EQ(min, a);
|
||||
|
||||
const float max = ozz::math::Max(a, b);
|
||||
EXPECT_FLOAT_EQ(max, b);
|
||||
|
||||
const float clamp = ozz::math::Clamp(a, c, b);
|
||||
EXPECT_FLOAT_EQ(clamp, c);
|
||||
|
||||
const float clamp0 = ozz::math::Clamp(a, b, c);
|
||||
EXPECT_FLOAT_EQ(clamp0, c);
|
||||
|
||||
const float clamp1 = ozz::math::Clamp(c, a, b);
|
||||
EXPECT_FLOAT_EQ(clamp1, c);
|
||||
}
|
||||
|
||||
TEST(Select, ozz_math_ex) {
|
||||
int a = -27, b = 46;
|
||||
int *pa = &a, *pb = &b;
|
||||
int *cpa = &a, *cpb = &b;
|
||||
|
||||
{ // Integer select
|
||||
EXPECT_EQ(ozz::math::Select(true, a, b), a);
|
||||
EXPECT_EQ(ozz::math::Select(true, b, a), b);
|
||||
EXPECT_EQ(ozz::math::Select(false, a, b), b);
|
||||
}
|
||||
|
||||
{ // Float select
|
||||
EXPECT_FLOAT_EQ(ozz::math::Select(true, 46.f, 27.f), 46.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::Select(false, 99.f, 46.f), 46.f);
|
||||
}
|
||||
|
||||
{ // Pointer select
|
||||
EXPECT_EQ(ozz::math::Select(true, pa, pb), pa);
|
||||
EXPECT_EQ(ozz::math::Select(true, pb, pa), pb);
|
||||
EXPECT_EQ(ozz::math::Select(false, pa, pb), pb);
|
||||
}
|
||||
|
||||
{ // Const pointer select
|
||||
EXPECT_EQ(ozz::math::Select(true, cpa, cpb), cpa);
|
||||
EXPECT_EQ(ozz::math::Select(true, cpb, cpa), cpb);
|
||||
EXPECT_EQ(ozz::math::Select(false, cpa, cpb), cpb);
|
||||
EXPECT_EQ(ozz::math::Select(false, pa, cpb), cpb);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/quaternion.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::math::Float3;
|
||||
using ozz::math::Float4;
|
||||
using ozz::math::Quaternion;
|
||||
|
||||
TEST(QuaternionConstant, ozz_math) {
|
||||
EXPECT_QUATERNION_EQ(Quaternion::identity(), 0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(QuaternionAxisAngle, ozz_math) {
|
||||
// Expect assertions from invalid inputs
|
||||
EXPECT_ASSERTION(Quaternion::FromAxisAngle(Float3::zero(), 0.f),
|
||||
"axis is not normalized");
|
||||
EXPECT_ASSERTION(ToAxisAngle(Quaternion(0.f, 0.f, 0.f, 2.f)), "IsNormalized");
|
||||
|
||||
// Identity
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromAxisAngle(Float3::y_axis(), 0.f), 0.f,
|
||||
0.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT4_EQ(ToAxisAngle(Quaternion::identity()), 1.f, 0.f, 0.f, 0.f);
|
||||
|
||||
// Other axis angles
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromAxisAngle(Float3::y_axis(), ozz::math::kPi_2), 0.f,
|
||||
.70710677f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT4_EQ(ToAxisAngle(Quaternion(0.f, .70710677f, 0.f, .70710677f)),
|
||||
0.f, 1.f, 0.f, ozz::math::kPi_2);
|
||||
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromAxisAngle(Float3::y_axis(), -ozz::math::kPi_2), 0.f,
|
||||
-.70710677f, 0.f, .70710677f);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromAxisAngle(-Float3::y_axis(), ozz::math::kPi_2), 0.f,
|
||||
-.70710677f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT4_EQ(ToAxisAngle(Quaternion(0.f, -.70710677f, 0.f, .70710677f)),
|
||||
0.f, -1.f, 0.f, ozz::math::kPi_2);
|
||||
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromAxisAngle(Float3::y_axis(), 3.f * ozz::math::kPi_4), 0.f,
|
||||
0.923879504f, 0.f, 0.382683426f);
|
||||
EXPECT_FLOAT4_EQ(
|
||||
ToAxisAngle(Quaternion(0.f, 0.923879504f, 0.f, 0.382683426f)), 0.f, 1.f,
|
||||
0.f, 3.f * ozz::math::kPi_4);
|
||||
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromAxisAngle(Float3(.819865f, .033034f, -.571604f), 1.123f),
|
||||
.4365425f, .017589169f, -.30435428f, .84645736f);
|
||||
EXPECT_FLOAT4_EQ(
|
||||
ToAxisAngle(Quaternion(.4365425f, .017589169f, -.30435428f, .84645736f)),
|
||||
.819865f, .033034f, -.571604f, 1.123f);
|
||||
}
|
||||
|
||||
TEST(QuaternionAxisCosAngle, ozz_math) {
|
||||
// Expect assertions from invalid inputs
|
||||
EXPECT_ASSERTION(Quaternion::FromAxisCosAngle(Float3::zero(), 0.f),
|
||||
"axis is not normalized");
|
||||
EXPECT_ASSERTION(Quaternion::FromAxisCosAngle(Float3::y_axis(), -1.0000001f),
|
||||
"cos is not in \\[-1,1\\] range.");
|
||||
EXPECT_ASSERTION(Quaternion::FromAxisCosAngle(Float3::y_axis(), 1.0000001f),
|
||||
"cos is not in \\[-1,1\\] range.");
|
||||
|
||||
// Identity
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromAxisCosAngle(Float3::y_axis(), 1.f), 0.f,
|
||||
0.f, 0.f, 1.f);
|
||||
|
||||
// Other axis angles
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromAxisCosAngle(Float3::y_axis(),
|
||||
std::cos(ozz::math::kPi_2)),
|
||||
0.f, .70710677f, 0.f, .70710677f);
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromAxisCosAngle(-Float3::y_axis(),
|
||||
std::cos(ozz::math::kPi_2)),
|
||||
0.f, -.70710677f, 0.f, .70710677f);
|
||||
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromAxisCosAngle(
|
||||
Float3::y_axis(), std::cos(3.f * ozz::math::kPi_4)),
|
||||
0.f, 0.923879504f, 0.f, 0.382683426f);
|
||||
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromAxisCosAngle(Float3(.819865f, .033034f, -.571604f),
|
||||
std::cos(1.123f)),
|
||||
.4365425f, .017589169f, -.30435428f, .84645736f);
|
||||
}
|
||||
|
||||
TEST(QuaternionQuaternionEuler, ozz_math) {
|
||||
// Identity
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromEuler(0.f, 0.f, 0.f), 0.f, 0.f, 0.f,
|
||||
1.f);
|
||||
EXPECT_FLOAT3_EQ(ToEuler(Quaternion::identity()), 0.f, 0.f, 0.f);
|
||||
|
||||
// Heading
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromEuler(ozz::math::kPi_2, 0.f, 0.f), 0.f,
|
||||
.70710677f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(ToEuler(Quaternion(0.f, .70710677f, 0.f, .70710677f)),
|
||||
ozz::math::kPi_2, 0.f, 0.f);
|
||||
|
||||
// Elevation
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromEuler(0.f, ozz::math::kPi_2, 0.f), 0.f,
|
||||
0.f, .70710677f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(ToEuler(Quaternion(0.f, 0.f, .70710677f, .70710677f)), 0.f,
|
||||
ozz::math::kPi_2, 0.f);
|
||||
|
||||
// Bank
|
||||
EXPECT_QUATERNION_EQ(Quaternion::FromEuler(0.f, 0.f, ozz::math::kPi_2),
|
||||
.70710677f, 0.f, 0.f, .70710677f);
|
||||
EXPECT_FLOAT3_EQ(ToEuler(Quaternion(.70710677f, 0.f, 0.f, .70710677f)), 0.f,
|
||||
0.f, ozz::math::kPi_2);
|
||||
|
||||
// Any rotation
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromEuler(ozz::math::kPi / 4.f, -ozz::math::kPi / 6.f,
|
||||
ozz::math::kPi_2),
|
||||
.56098551f, .092295974f, -0.43045932f, .70105737f);
|
||||
EXPECT_FLOAT3_EQ(
|
||||
ToEuler(Quaternion(.56098551f, .092295974f, -0.43045932f, .70105737f)),
|
||||
ozz::math::kPi / 4.f, -ozz::math::kPi / 6.f, ozz::math::kPi_2);
|
||||
}
|
||||
|
||||
TEST(QuaternionFromVectors, ozz_math) {
|
||||
// Returns identity for a 0 length vector
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::zero(), Float3::x_axis()), 0.f, 0.f, 0.f,
|
||||
1.f);
|
||||
|
||||
// pi/2 around y
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::z_axis(), Float3::x_axis()), 0.f,
|
||||
0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// Non unit pi/2 around y
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::z_axis() * 7.f, Float3::x_axis()), 0.f,
|
||||
0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// Minus pi/2 around y
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::x_axis(), Float3::z_axis()), 0.f,
|
||||
-0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// pi/2 around x
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::y_axis(), Float3::z_axis()), 0.707106769f,
|
||||
0.f, 0.f, 0.707106769f);
|
||||
|
||||
// Non unit pi/2 around x
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::y_axis() * 9.f, Float3::z_axis() * 13.f),
|
||||
0.707106769f, 0.f, 0.f, 0.707106769f);
|
||||
|
||||
// pi/2 around z
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::x_axis(), Float3::y_axis()), 0.f, 0.f,
|
||||
0.707106769f, 0.707106769f);
|
||||
|
||||
// pi/2 around z also
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3(0.707106769f, 0.707106769f, 0.f),
|
||||
Float3(-0.707106769f, 0.707106769f, 0.f)),
|
||||
0.f, 0.f, 0.707106769f, 0.707106769f);
|
||||
|
||||
// Aligned vectors
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::x_axis(), Float3::x_axis()), 0.f, 0.f,
|
||||
0.f, 1.f);
|
||||
|
||||
// Non-unit aligned vectors
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::x_axis(), Float3::x_axis() * 2.f), 0.f,
|
||||
0.f, 0.f, 1.f);
|
||||
|
||||
// Opposed vectors
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::x_axis(), -Float3::x_axis()), 0.f, 1.f,
|
||||
0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(-Float3::x_axis(), Float3::x_axis()), 0.f, -1.f,
|
||||
0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::y_axis(), -Float3::y_axis()), 0.f, 0.f,
|
||||
1.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(-Float3::y_axis(), Float3::y_axis()), 0.f, 0.f,
|
||||
-1.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3::z_axis(), -Float3::z_axis()), 0.f, -1.f,
|
||||
0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(-Float3::z_axis(), Float3::z_axis()), 0.f, 1.f,
|
||||
0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3(0.707106769f, 0.707106769f, 0.f),
|
||||
-Float3(0.707106769f, 0.707106769f, 0.f)),
|
||||
-0.707106769f, 0.707106769f, 0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3(0.f, 0.707106769f, 0.707106769f),
|
||||
-Float3(0.f, 0.707106769f, 0.707106769f)),
|
||||
0.f, -0.707106769f, 0.707106769f, 0);
|
||||
|
||||
// Non-unit opposed vectors
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromVectors(Float3(2.f, 2.f, 2.f), -Float3(2.f, 2.f, 2.f)),
|
||||
0.f, -0.707106769f, 0.707106769f, 0);
|
||||
}
|
||||
|
||||
TEST(QuaternionFromUnitVectors, ozz_math) {
|
||||
// assert 0 length vectors
|
||||
EXPECT_ASSERTION(
|
||||
Quaternion::FromUnitVectors(Float3::zero(), Float3::x_axis()),
|
||||
"Input vectors must be normalized.");
|
||||
EXPECT_ASSERTION(
|
||||
Quaternion::FromUnitVectors(Float3::x_axis(), Float3::zero()),
|
||||
"Input vectors must be normalized.");
|
||||
// assert non unit vectors
|
||||
EXPECT_ASSERTION(
|
||||
Quaternion::FromUnitVectors(Float3::x_axis() * 2.f, Float3::x_axis()),
|
||||
"Input vectors must be normalized.");
|
||||
EXPECT_ASSERTION(
|
||||
Quaternion::FromUnitVectors(Float3::x_axis(), Float3::x_axis() * .5f),
|
||||
"Input vectors must be normalized.");
|
||||
|
||||
// pi/2 around y
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3::z_axis(), Float3::x_axis()), 0.f,
|
||||
0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// Minus pi/2 around y
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3::x_axis(), Float3::z_axis()), 0.f,
|
||||
-0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// pi/2 around x
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3::y_axis(), Float3::z_axis()),
|
||||
0.707106769f, 0.f, 0.f, 0.707106769f);
|
||||
|
||||
// pi/2 around z
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3::x_axis(), Float3::y_axis()), 0.f, 0.f,
|
||||
0.707106769f, 0.707106769f);
|
||||
|
||||
// pi/2 around z also
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3(0.707106769f, 0.707106769f, 0.f),
|
||||
Float3(-0.707106769f, 0.707106769f, 0.f)),
|
||||
0.f, 0.f, 0.707106769f, 0.707106769f);
|
||||
|
||||
// Aligned vectors
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3::x_axis(), Float3::x_axis()), 0.f, 0.f,
|
||||
0.f, 1.f);
|
||||
|
||||
// Opposed vectors
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3::x_axis(), -Float3::x_axis()), 0.f,
|
||||
1.f, 0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(-Float3::x_axis(), Float3::x_axis()), 0.f,
|
||||
-1.f, 0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3::y_axis(), -Float3::y_axis()), 0.f,
|
||||
0.f, 1.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(-Float3::y_axis(), Float3::y_axis()), 0.f,
|
||||
0.f, -1.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3::z_axis(), -Float3::z_axis()), 0.f,
|
||||
-1.f, 0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(-Float3::z_axis(), Float3::z_axis()), 0.f,
|
||||
1.f, 0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3(0.707106769f, 0.707106769f, 0.f),
|
||||
-Float3(0.707106769f, 0.707106769f, 0.f)),
|
||||
-0.707106769f, 0.707106769f, 0.f, 0);
|
||||
EXPECT_QUATERNION_EQ(
|
||||
Quaternion::FromUnitVectors(Float3(0.f, 0.707106769f, 0.707106769f),
|
||||
-Float3(0.f, 0.707106769f, 0.707106769f)),
|
||||
0.f, -0.707106769f, 0.707106769f, 0);
|
||||
}
|
||||
|
||||
TEST(QuaternionCompare, ozz_math) {
|
||||
EXPECT_TRUE(Quaternion::identity() == Quaternion(0.f, 0.f, 0.f, 1.f));
|
||||
EXPECT_TRUE(Quaternion::identity() != Quaternion(1.f, 0.f, 0.f, 0.f));
|
||||
EXPECT_TRUE(Compare(Quaternion::identity(), Quaternion::identity(), std::cos(.5f * 0.f)));
|
||||
EXPECT_TRUE(Compare(Quaternion::identity(),
|
||||
Quaternion::FromEuler(0.f, 0.f, ozz::math::kPi / 100.f),
|
||||
std::cos(.5f * ozz::math::kPi / 50.f)));
|
||||
EXPECT_TRUE(Compare(Quaternion::identity(),
|
||||
-Quaternion::FromEuler(0.f, 0.f, ozz::math::kPi / 100.f),
|
||||
std::cos(.5f * ozz::math::kPi / 50.f)));
|
||||
EXPECT_FALSE(Compare(Quaternion::identity(),
|
||||
Quaternion::FromEuler(0.f, 0.f, ozz::math::kPi / 100.f),
|
||||
std::cos(.5f * ozz::math::kPi / 200.f)));
|
||||
}
|
||||
|
||||
TEST(QuaternionArithmetic, ozz_math) {
|
||||
const Quaternion a(.70710677f, 0.f, 0.f, .70710677f);
|
||||
const Quaternion b(0.f, .70710677f, 0.f, .70710677f);
|
||||
const Quaternion c(0.f, .70710677f, 0.f, -.70710677f);
|
||||
const Quaternion denorm(1.414212f, 0.f, 0.f, 1.414212f);
|
||||
|
||||
EXPECT_TRUE(IsNormalized(a));
|
||||
EXPECT_TRUE(IsNormalized(b));
|
||||
EXPECT_TRUE(IsNormalized(c));
|
||||
EXPECT_FALSE(IsNormalized(denorm));
|
||||
|
||||
const Quaternion conjugate = Conjugate(a);
|
||||
EXPECT_QUATERNION_EQ(conjugate, -a.x, -a.y, -a.z, a.w);
|
||||
EXPECT_TRUE(IsNormalized(conjugate));
|
||||
|
||||
const Quaternion negate = -a;
|
||||
EXPECT_QUATERNION_EQ(negate, -a.x, -a.y, -a.z, -a.w);
|
||||
EXPECT_TRUE(IsNormalized(negate));
|
||||
|
||||
const Quaternion add = a + b;
|
||||
EXPECT_QUATERNION_EQ(add, .70710677f, .70710677f, 0.f, 1.41421354f);
|
||||
|
||||
const Quaternion mul0 = a * conjugate;
|
||||
EXPECT_QUATERNION_EQ(mul0, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_TRUE(IsNormalized(mul0));
|
||||
|
||||
const Quaternion muls = a * 2.f;
|
||||
EXPECT_QUATERNION_EQ(muls, 1.41421354f, 0.f, 0.f, 1.41421354f);
|
||||
|
||||
const Quaternion mul1 = conjugate * a;
|
||||
EXPECT_QUATERNION_EQ(mul1, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_TRUE(IsNormalized(mul1));
|
||||
|
||||
const Quaternion q1234(1.f, 2.f, 3.f, 4.f);
|
||||
const Quaternion q5678(5.f, 6.f, 7.f, 8.f);
|
||||
const Quaternion mul12345678 = q1234 * q5678;
|
||||
EXPECT_QUATERNION_EQ(mul12345678, 24.f, 48.f, 48.f, -6.f);
|
||||
|
||||
EXPECT_ASSERTION(Normalize(Quaternion(0.f, 0.f, 0.f, 0.f)),
|
||||
"is not normalizable");
|
||||
const Quaternion normalize = Normalize(denorm);
|
||||
EXPECT_TRUE(IsNormalized(normalize));
|
||||
EXPECT_QUATERNION_EQ(normalize, .7071068f, 0.f, 0.f, .7071068f);
|
||||
|
||||
EXPECT_ASSERTION(NormalizeSafe(denorm, Quaternion(0.f, 0.f, 0.f, 0.f)),
|
||||
"_safer is not normalized");
|
||||
const Quaternion normalize_safe =
|
||||
NormalizeSafe(denorm, Quaternion::identity());
|
||||
EXPECT_TRUE(IsNormalized(normalize_safe));
|
||||
EXPECT_QUATERNION_EQ(normalize_safe, .7071068f, 0.f, 0.f, .7071068f);
|
||||
|
||||
const Quaternion normalize_safer =
|
||||
NormalizeSafe(Quaternion(0.f, 0.f, 0.f, 0.f), Quaternion::identity());
|
||||
EXPECT_TRUE(IsNormalized(normalize_safer));
|
||||
EXPECT_QUATERNION_EQ(normalize_safer, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
const Quaternion lerp_0 = Lerp(a, b, 0.f);
|
||||
EXPECT_QUATERNION_EQ(lerp_0, a.x, a.y, a.z, a.w);
|
||||
|
||||
const Quaternion lerp_1 = Lerp(a, b, 1.f);
|
||||
EXPECT_QUATERNION_EQ(lerp_1, b.x, b.y, b.z, b.w);
|
||||
|
||||
const Quaternion lerp_0_2 = Lerp(a, b, .2f);
|
||||
EXPECT_QUATERNION_EQ(lerp_0_2, .5656853f, .1414213f, 0.f, .7071068f);
|
||||
|
||||
const Quaternion nlerp_0 = NLerp(a, b, 0.f);
|
||||
EXPECT_TRUE(IsNormalized(nlerp_0));
|
||||
EXPECT_QUATERNION_EQ(nlerp_0, a.x, a.y, a.z, a.w);
|
||||
|
||||
const Quaternion nlerp_1 = NLerp(a, b, 1.f);
|
||||
EXPECT_TRUE(IsNormalized(nlerp_1));
|
||||
EXPECT_QUATERNION_EQ(nlerp_1, b.x, b.y, b.z, b.w);
|
||||
|
||||
const Quaternion nlerp_0_2 = NLerp(a, b, .2f);
|
||||
EXPECT_TRUE(IsNormalized(nlerp_0_2));
|
||||
EXPECT_QUATERNION_EQ(nlerp_0_2, .6172133f, .1543033f, 0.f, .7715167f);
|
||||
|
||||
EXPECT_ASSERTION(SLerp(denorm, b, 0.f), "IsNormalized\\(_a\\)");
|
||||
EXPECT_ASSERTION(SLerp(a, denorm, 0.f), "IsNormalized\\(_b\\)");
|
||||
|
||||
const Quaternion slerp_0 = SLerp(a, b, 0.f);
|
||||
EXPECT_TRUE(IsNormalized(slerp_0));
|
||||
EXPECT_QUATERNION_EQ(slerp_0, a.x, a.y, a.z, a.w);
|
||||
|
||||
const Quaternion slerp_c_0 = SLerp(a, c, 0.f);
|
||||
EXPECT_TRUE(IsNormalized(slerp_c_0));
|
||||
EXPECT_QUATERNION_EQ(slerp_c_0, a.x, a.y, a.z, a.w);
|
||||
|
||||
const Quaternion slerp_c_1 = SLerp(a, c, 1.f);
|
||||
EXPECT_TRUE(IsNormalized(slerp_c_1));
|
||||
EXPECT_QUATERNION_EQ(slerp_c_1, c.x, c.y, c.z, c.w);
|
||||
|
||||
const Quaternion slerp_c_0_6 = SLerp(a, c, .6f);
|
||||
EXPECT_TRUE(IsNormalized(slerp_c_0_6));
|
||||
EXPECT_QUATERNION_EQ(slerp_c_0_6, .6067752f, .7765344f, 0.f, -.1697592f);
|
||||
|
||||
const Quaternion slerp_1 = SLerp(a, b, 1.f);
|
||||
EXPECT_TRUE(IsNormalized(slerp_1));
|
||||
EXPECT_QUATERNION_EQ(slerp_1, b.x, b.y, b.z, b.w);
|
||||
|
||||
const Quaternion slerp_0_2 = SLerp(a, b, .2f);
|
||||
EXPECT_TRUE(IsNormalized(slerp_0_2));
|
||||
EXPECT_QUATERNION_EQ(slerp_0_2, .6067752f, .1697592f, 0.f, .7765344f);
|
||||
|
||||
const Quaternion slerp_0_7 = SLerp(a, b, .7f);
|
||||
EXPECT_TRUE(IsNormalized(slerp_0_7));
|
||||
EXPECT_QUATERNION_EQ(slerp_0_7, .2523113f, .5463429f, 0.f, .798654f);
|
||||
|
||||
const float dot = Dot(a, b);
|
||||
EXPECT_FLOAT_EQ(dot, .5f);
|
||||
}
|
||||
|
||||
TEST(QuaternionTransformVector, ozz_math) {
|
||||
// 0 length
|
||||
EXPECT_FLOAT3_EQ(
|
||||
TransformVector(Quaternion::FromAxisAngle(Float3::y_axis(), 0.f),
|
||||
Float3::zero()),
|
||||
0, 0, 0);
|
||||
|
||||
// Unit length
|
||||
EXPECT_FLOAT3_EQ(
|
||||
TransformVector(Quaternion::FromAxisAngle(Float3::y_axis(), 0.f),
|
||||
Float3::z_axis()),
|
||||
0, 0, 1);
|
||||
EXPECT_FLOAT3_EQ(TransformVector(Quaternion::FromAxisAngle(Float3::y_axis(),
|
||||
ozz::math::kPi_2),
|
||||
Float3::y_axis()),
|
||||
0, 1, 0);
|
||||
EXPECT_FLOAT3_EQ(TransformVector(Quaternion::FromAxisAngle(Float3::y_axis(),
|
||||
ozz::math::kPi_2),
|
||||
Float3::x_axis()),
|
||||
0, 0, -1);
|
||||
EXPECT_FLOAT3_EQ(TransformVector(Quaternion::FromAxisAngle(Float3::y_axis(),
|
||||
ozz::math::kPi_2),
|
||||
Float3::z_axis()),
|
||||
1, 0, 0);
|
||||
|
||||
// Non unit
|
||||
EXPECT_FLOAT3_EQ(TransformVector(Quaternion::FromAxisAngle(Float3::z_axis(),
|
||||
ozz::math::kPi_2),
|
||||
Float3::x_axis() * 2),
|
||||
0, 2, 0);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/rect.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
TEST(RectInt, ozz_math) {
|
||||
ozz::math::RectInt rect(10, 20, 30, 40);
|
||||
|
||||
EXPECT_EQ(rect.right(), 40);
|
||||
EXPECT_EQ(rect.top(), 60);
|
||||
|
||||
EXPECT_TRUE(rect.is_inside(10, 20));
|
||||
EXPECT_TRUE(rect.is_inside(39, 59));
|
||||
|
||||
EXPECT_FALSE(rect.is_inside(9, 20));
|
||||
EXPECT_FALSE(rect.is_inside(10, 19));
|
||||
EXPECT_FALSE(rect.is_inside(40, 59));
|
||||
EXPECT_FALSE(rect.is_inside(39, 60));
|
||||
}
|
||||
|
||||
TEST(RectFloat, ozz_math) {
|
||||
ozz::math::RectFloat rect(10.f, 20.f, 30.f, 40.f);
|
||||
|
||||
EXPECT_FLOAT_EQ(rect.right(), 40.f);
|
||||
EXPECT_FLOAT_EQ(rect.top(), 60.f);
|
||||
|
||||
EXPECT_TRUE(rect.is_inside(10.f, 20.f));
|
||||
EXPECT_TRUE(rect.is_inside(39.f, 59.f));
|
||||
|
||||
EXPECT_FALSE(rect.is_inside(9.f, 20.f));
|
||||
EXPECT_FALSE(rect.is_inside(10.f, 19.f));
|
||||
EXPECT_FALSE(rect.is_inside(40.f, 59.f));
|
||||
EXPECT_FALSE(rect.is_inside(39.f, 60.f));
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
|
||||
using ozz::math::Float4x4;
|
||||
using ozz::math::SimdFloat4;
|
||||
|
||||
TEST(Float4x4Constant, ) {
|
||||
const Float4x4 identity = Float4x4::identity();
|
||||
EXPECT_FLOAT4x4_EQ(identity, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(Float4x4Arithmetic, ozz_simd_math) {
|
||||
const Float4x4 m0 = {{ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)}};
|
||||
const Float4x4 m1 = {
|
||||
{ozz::math::simd_float4::Load(-0.f, -1.f, -2.f, -3.f),
|
||||
ozz::math::simd_float4::Load(-4.f, -5.f, -6.f, -7.f),
|
||||
ozz::math::simd_float4::Load(-8.f, -9.f, -10.f, -11.f),
|
||||
ozz::math::simd_float4::Load(-12.f, -13.f, -14.f, -15.f)}};
|
||||
const Float4x4 m2 = {
|
||||
{ozz::math::simd_float4::Load(0.f, -1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(-4.f, 5.f, 6.f, -7.f),
|
||||
ozz::math::simd_float4::Load(8.f, -9.f, -10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(-12.f, 13.f, -14.f, 15.f)}};
|
||||
const SimdFloat4 v = ozz::math::simd_float4::Load(-0.f, -1.f, -2.f, -3.f);
|
||||
|
||||
const SimdFloat4 mul_vector = m0 * v;
|
||||
EXPECT_SIMDFLOAT_EQ(mul_vector, -56.f, -62.f, -68.f, -74.f);
|
||||
|
||||
const SimdFloat4 transform_point = TransformPoint(m0, v);
|
||||
EXPECT_SIMDFLOAT_EQ(transform_point, -8.f, -10.f, -12.f, -14.f);
|
||||
|
||||
const SimdFloat4 transform_vector = TransformVector(m0, v);
|
||||
EXPECT_SIMDFLOAT_EQ(transform_vector, -20.f, -23.f, -26.f, -29.f);
|
||||
|
||||
const Float4x4 mul_mat = m0 * m1;
|
||||
EXPECT_FLOAT4x4_EQ(mul_mat, -56.f, -62.f, -68.f, -74.f, -152.f, -174.f,
|
||||
-196.f, -218.f, -248.f, -286.f, -324.f, -362.f, -344.f,
|
||||
-398.f, -452.f, -506.f);
|
||||
|
||||
const Float4x4 add_mat = m0 + m1;
|
||||
EXPECT_FLOAT4x4_EQ(add_mat, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const Float4x4 sub_mat = m0 - m1;
|
||||
EXPECT_FLOAT4x4_EQ(sub_mat, 0.f, 2.f, 4.f, 6.f, 8.f, 10.f, 12.f, 14.f, 16.f,
|
||||
18.f, 20.f, 22.f, 24.f, 26.f, 28.f, 30.f);
|
||||
|
||||
const Float4x4 transpose = Transpose(m0);
|
||||
EXPECT_FLOAT4x4_EQ(transpose, 0.f, 4.f, 8.f, 12.f, 1.f, 5.f, 9.f, 13.f, 2.f,
|
||||
6.f, 10.f, 14.f, 3.f, 7.f, 11.f, 15.f);
|
||||
|
||||
// Invertible
|
||||
const Float4x4 invert_ident = Invert(Float4x4::identity());
|
||||
EXPECT_FLOAT4x4_EQ(invert_ident, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
const Float4x4 invert = Invert(m2);
|
||||
EXPECT_FLOAT4x4_EQ(invert, .216667f, 2.75f, 1.6f, .066666f, .2f, 2.5f, 1.4f,
|
||||
.1f, .25f, .5f, .25f, 0.f, .233333f, .5f, .3f, .03333f);
|
||||
|
||||
const Float4x4 invert_mul = m2 * invert;
|
||||
EXPECT_FLOAT4x4_EQ(invert_mul, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
ozz::math::SimdInt4 invertible;
|
||||
EXPECT_FLOAT4x4_EQ(Invert(m2, &invertible), 0.216667f, 2.75f, 1.6f, .066666f,
|
||||
.2f, 2.5f, 1.4f, .1f, .25f, .5f, .25f, 0.f, .233333f, .5f,
|
||||
.3f, .03333f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(invertible));
|
||||
|
||||
// Non invertible
|
||||
EXPECT_ASSERTION(Invert(m0), "Matrix is not invertible");
|
||||
|
||||
ozz::math::SimdInt4 not_invertible;
|
||||
EXPECT_FLOAT4x4_EQ(Invert(m0, ¬_invertible), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(not_invertible));
|
||||
}
|
||||
|
||||
TEST(Float4x4Normal, ozz_simd_math) {
|
||||
const Float4x4 not_orthogonal = {
|
||||
{ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 1.f)}};
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(IsNormalized(not_orthogonal)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(IsNormalized(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(1.f, -1.f, 1.f, 0.f)))));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue3(IsNormalized(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(1.f, 46.f, 1.f, 0.f)))));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(IsNormalized(Float4x4::identity())));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(IsNormalized(
|
||||
Float4x4::FromAxisAngle(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::LoadX(1.24f)))));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(IsNormalized(Float4x4::Translation(
|
||||
ozz::math::simd_float4::Load(46.f, 0.f, 0.f, 1.f)))));
|
||||
}
|
||||
|
||||
TEST(Float4x4Orthogonal, ozz_simd_math) {
|
||||
const Float4x4 zero = {{ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 1.f)}};
|
||||
const Float4x4 not_orthogonal = {
|
||||
{ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 1.f)}};
|
||||
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(IsOrthogonal(not_orthogonal)));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(IsOrthogonal(zero)));
|
||||
|
||||
const Float4x4 reflexion1x =
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(-1.f, 1.f, 1.f, 0.f));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(IsOrthogonal(reflexion1x)));
|
||||
const Float4x4 reflexion1y =
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(1.f, -1.f, 1.f, 0.f));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(IsOrthogonal(reflexion1y)));
|
||||
const Float4x4 reflexion1z =
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(1.f, 1.f, -1.f, 0.f));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(IsOrthogonal(reflexion1z)));
|
||||
const Float4x4 reflexion2x =
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(1.f, -1.f, -1.f, 0.f));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(reflexion2x)));
|
||||
const Float4x4 reflexion2y =
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(-1.f, 1.f, -1.f, 0.f));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(reflexion2y)));
|
||||
const Float4x4 reflexion2z =
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(-1.f, -1.f, 1.f, 0.f));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(reflexion2z)));
|
||||
const Float4x4 reflexion3 =
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(-1.f, -1.f, -1.f, 0.f));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(IsOrthogonal(reflexion3)));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(Float4x4::identity())));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(Float4x4::Translation(
|
||||
ozz::math::simd_float4::Load(46.f, 0.f, 0.f, 1.f)))));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(
|
||||
Float4x4::FromAxisAngle(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::LoadX(1.24f)))));
|
||||
}
|
||||
|
||||
TEST(Float4x4Translate, ozz_simd_math) {
|
||||
const SimdFloat4 v = ozz::math::simd_float4::Load(-1.f, 1.f, 2.f, 3.f);
|
||||
const Float4x4 m0 = {{ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)}};
|
||||
|
||||
const Float4x4 translation = Float4x4::Translation(v);
|
||||
EXPECT_FLOAT4x4_EQ(translation, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, -1.f, 1.f, 2.f, 1.f);
|
||||
|
||||
const Float4x4 translate_mul = m0 * translation;
|
||||
EXPECT_FLOAT4x4_EQ(translate_mul, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
|
||||
9.f, 10.f, 11.f, 32.f, 35.f, 38.f, 41.f);
|
||||
|
||||
const Float4x4 translate = Translate(m0, v);
|
||||
EXPECT_FLOAT4x4_EQ(translate, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
|
||||
9.f, 10.f, 11.f, 32.f, 35.f, 38.f, 41.f);
|
||||
}
|
||||
|
||||
TEST(Float4x4Scale, ozz_simd_math) {
|
||||
const SimdFloat4 v = ozz::math::simd_float4::Load(-1.f, 1.f, 2.f, 3.f);
|
||||
const Float4x4 m0 = {{ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)}};
|
||||
|
||||
const Float4x4 scaling = Float4x4::Scaling(v);
|
||||
EXPECT_FLOAT4x4_EQ(scaling, -1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f,
|
||||
2.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
const Float4x4 scale_mul = m0 * scaling;
|
||||
EXPECT_FLOAT4x4_EQ(scale_mul, 0.f, -1.f, -2.f, -3.f, 4.f, 5.f, 6.f, 7.f, 16.f,
|
||||
18.f, 20.f, 22.f, 12.f, 13.f, 14.f, 15.f);
|
||||
|
||||
const Float4x4 scale = Scale(m0, v);
|
||||
EXPECT_FLOAT4x4_EQ(scale, 0.f, -1.f, -2.f, -3.f, 4.f, 5.f, 6.f, 7.f, 16.f,
|
||||
18.f, 20.f, 22.f, 12.f, 13.f, 14.f, 15.f);
|
||||
}
|
||||
|
||||
TEST(Float4x4ColumnMultiply, ozz_simd_math) {
|
||||
const SimdFloat4 v = ozz::math::simd_float4::Load(-1.f, -2.f, -3.f, -4.f);
|
||||
const Float4x4 m0 = {{ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)}};
|
||||
|
||||
const Float4x4 column_multiply = ozz::math::ColumnMultiply(m0, v);
|
||||
EXPECT_FLOAT4x4_EQ(column_multiply, 0.f, -2.f, -6.f, -12.f, -4.f, -10.f,
|
||||
-18.f, -28.f, -8.f, -18.f, -30.f, -44.f, -12.f, -26.f,
|
||||
-42.f, -60.f);
|
||||
}
|
||||
|
||||
TEST(Float4x4Rotate, ozz_simd_math) {
|
||||
const Float4x4 euler_identity =
|
||||
Float4x4::FromEuler(ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f));
|
||||
EXPECT_FLOAT4x4_EQ(euler_identity, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
const Float4x4 euler = Float4x4::FromEuler(
|
||||
ozz::math::simd_float4::Load(ozz::math::kPi_2, 0.f, 0.f, 0.f));
|
||||
EXPECT_FLOAT4x4_EQ(euler, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f, -1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(IsNormalized(euler)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(euler)));
|
||||
|
||||
EXPECT_ASSERTION(Float4x4::FromQuaternion(
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 1.f)),
|
||||
"IsNormalized");
|
||||
const Float4x4 quaternion_identity = Float4x4::FromQuaternion(
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 1.f));
|
||||
EXPECT_FLOAT4x4_EQ(quaternion_identity, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(IsNormalized(quaternion_identity)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(quaternion_identity)));
|
||||
|
||||
const Float4x4 quaternion = Float4x4::FromQuaternion(
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 0.f, .70710677f));
|
||||
EXPECT_FLOAT4x4_EQ(quaternion, 0.f, 0.f, -1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
EXPECT_ASSERTION(
|
||||
Float4x4::FromAxisAngle(ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::zero()),
|
||||
"IsNormalized");
|
||||
const Float4x4 axis_angle_identity = Float4x4::FromAxisAngle(
|
||||
ozz::math::simd_float4::y_axis(), ozz::math::simd_float4::zero());
|
||||
EXPECT_FLOAT4x4_EQ(axis_angle_identity, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
const Float4x4 axis_angle =
|
||||
Float4x4::FromAxisAngle(ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::LoadX(ozz::math::kPi_2));
|
||||
EXPECT_FLOAT4x4_EQ(axis_angle, 0.f, 0.f, -1.f, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(IsNormalized(axis_angle)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(axis_angle)));
|
||||
}
|
||||
|
||||
TEST(Float4x4Affine, ozz_simd_math) {
|
||||
EXPECT_ASSERTION(
|
||||
Float4x4::FromAffine(ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 1.f),
|
||||
ozz::math::simd_float4::Load(1.f, 1.f, 1.f, 1.f)),
|
||||
"IsNormalized");
|
||||
|
||||
const Float4x4 identity =
|
||||
Float4x4::FromAffine(ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 1.f),
|
||||
ozz::math::simd_float4::Load(1.f, 1.f, 1.f, 1.f));
|
||||
EXPECT_FLOAT4x4_EQ(identity, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 0.f, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
const Float4x4 affine = Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::Load(-12.f, 46.f, 12.f, 9.f),
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 0.f, .70710677f),
|
||||
ozz::math::simd_float4::Load(2.f, 46.f, 3.f, 1.f));
|
||||
EXPECT_FLOAT4x4_EQ(affine, 0.f, 0.f, -2.f, 0.f, 0.f, 46.f, 0.f, 0.f, 3.f, 0.f,
|
||||
0.f, 0.f, -12.f, 46.f, 12.f, 1.f);
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue3(IsNormalized(affine)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(IsOrthogonal(affine)));
|
||||
|
||||
const Float4x4 affine_reflexion = Float4x4::FromAffine(
|
||||
ozz::math::simd_float4::Load(-12.f, 46.f, 12.f, 9.f),
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 0.f, .70710677f),
|
||||
ozz::math::simd_float4::Load(2.f, -1.f, 3.f, 1.f));
|
||||
EXPECT_FLOAT4x4_EQ(affine_reflexion, 0.f, 0.f, -2.f, 0.f, 0.f, -1.f, 0.f, 0.f,
|
||||
3.f, 0.f, 0.f, 0.f, -12.f, 46.f, 12.f, 1.f);
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue3(IsNormalized(affine_reflexion)));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(IsOrthogonal(affine_reflexion)));
|
||||
}
|
||||
|
||||
TEST(Float4x4ToQuaternion, ozz_simd_math) {
|
||||
#ifndef NDEBUG
|
||||
const Float4x4 not_normalized = {
|
||||
{ozz::math::simd_float4::Load(1.1f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 1.f)}};
|
||||
const Float4x4 not_orthogonal = {
|
||||
{ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 1.f)}};
|
||||
#endif // NDEBUG
|
||||
|
||||
EXPECT_ASSERTION(ToQuaternion(not_normalized), "IsNormalized");
|
||||
EXPECT_ASSERTION(ToQuaternion(not_orthogonal), "IsOrthogonal");
|
||||
EXPECT_SIMDFLOAT_EQ(ToQuaternion(Float4x4::identity()), 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ToQuaternion(Float4x4::FromQuaternion(
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 1.f, 0.f))),
|
||||
0.f, 0.f, 1.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ToQuaternion(Float4x4::FromQuaternion(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 0.f))),
|
||||
0.f, 1.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ToQuaternion(Float4x4::FromQuaternion(
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f))),
|
||||
1.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ToQuaternion(Float4x4::FromQuaternion(
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, .70710677f))),
|
||||
.70710677f, 0.f, 0.f, .70710677f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ToQuaternion(Float4x4::FromQuaternion(ozz::math::simd_float4::Load(
|
||||
.4365425f, .017589169f, -.30435428f, .84645736f))),
|
||||
.4365425f, .017589169f, -.30435428f, .84645736f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ToQuaternion(Float4x4::FromQuaternion(ozz::math::simd_float4::Load(
|
||||
.56098551f, -.092295974f, 0.43045932f, .70105737f))),
|
||||
.56098551f, -.092295974f, 0.43045932f, .70105737f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ToQuaternion(Float4x4::FromQuaternion(ozz::math::simd_float4::Load(
|
||||
-.6172133f, -.1543033f, 0.f, .7715167f))),
|
||||
-.6172133f, -.1543033f, 0.f, .7715167f);
|
||||
}
|
||||
|
||||
TEST(Float4x4ToAffine, ozz_simd_math) {
|
||||
SimdFloat4 translate = ozz::math::simd_float4::zero();
|
||||
SimdFloat4 rotate = ozz::math::simd_float4::zero();
|
||||
SimdFloat4 scale = ozz::math::simd_float4::zero();
|
||||
|
||||
EXPECT_FALSE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(0.f, 0.f, 1.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_FALSE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_FALSE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
|
||||
EXPECT_TRUE(ToAffine(Float4x4::identity(), &translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(0.f, 1.f, 1.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 0.f, 1.f, 1.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(1.f, 0.f, 1.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 1.f, 0.f, 1.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(1.f, 1.f, 0.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 1.f, 1.f, 0.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Translation(
|
||||
ozz::math::simd_float4::Load(46.f, 69.f, 58.f, 1.f)) *
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(2.f, 3.f, 4.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 46.f, 69.f, 58.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 2.f, 3.f, 4.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Translation(
|
||||
ozz::math::simd_float4::Load(46.f, -69.f, -58.f, 1.f)) *
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(-2.f, 3.f, 4.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 46.f, -69.f, -58.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 1.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 2.f, -3.f, 4.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(2.f, -3.f, 4.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 2.f, -3.f, 4.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(2.f, 3.f, -4.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 1.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 2.f, -3.f, 4.f, 1.f);
|
||||
|
||||
// This one is not a reflexion.
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(-2.f, -3.f, 4.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 1.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 2.f, 3.f, 4.f, 1.f);
|
||||
|
||||
// This one is not a reflexion.
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(2.f, -3.f, -4.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 1.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 2.f, 3.f, 4.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Translation(
|
||||
ozz::math::simd_float4::Load(46.f, -69.f, -58.f, 1.f)) *
|
||||
Float4x4::FromQuaternion(ozz::math::simd_float4::Load(
|
||||
-.6172133f, -.1543033f, 0.f, .7715167f)) *
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(2.f, 3.f, 4.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 46.f, -69.f, -58.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, -.6172133f, -.1543033f, 0.f, .7715167f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 2.f, 3.f, 4.f, 1.f);
|
||||
|
||||
EXPECT_TRUE(ToAffine(
|
||||
Float4x4::Translation(
|
||||
ozz::math::simd_float4::Load(46.f, -69.f, -58.f, 1.f)) *
|
||||
Float4x4::FromQuaternion(
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, .70710677f)) *
|
||||
Float4x4::Scaling(ozz::math::simd_float4::Load(2.f, -3.f, 4.f, 0.f)),
|
||||
&translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 46.f, -69.f, -58.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, .70710677f, 0.f, 0.f, .70710677f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 2.f, -3.f, 4.f, 1.f);
|
||||
|
||||
const Float4x4 trace = {
|
||||
{ozz::math::simd_float4::Load(-.916972f, 0.f, -.398952f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, -1, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-.398952f, 0, .916972f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 1.f)}};
|
||||
EXPECT_TRUE(ToAffine(trace, &translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, -.20375007f, 0.f, .97902298f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
const Float4x4 small = {
|
||||
{ozz::math::simd_float4::Load(.000907520065f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, .000959928846f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, .0159599986f, 0.f),
|
||||
ozz::math::simd_float4::Load(.00649994006f, .00719946623f,
|
||||
-.000424541620f, .999999940f)}};
|
||||
EXPECT_TRUE(ToAffine(small, &translate, &rotate, &scale));
|
||||
EXPECT_SIMDFLOAT_EQ(translate, .00649994006f, .00719946623f, -.000424541620f,
|
||||
1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(rotate, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(scale, .000907520065f, .000959928846f, .0159599986f, 1.f);
|
||||
}
|
||||
@@ -0,0 +1,839 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
|
||||
using ozz::math::SimdFloat4;
|
||||
using ozz::math::SimdInt4;
|
||||
|
||||
static_assert(sizeof(SimdFloat4) == 4 * sizeof(float),
|
||||
"Expects SimdFloat4 to be the size of 4 floats.");
|
||||
static_assert(alignof(SimdFloat4) == 16,
|
||||
"Expects SimdFloat4 to be the size of 16 bytes.");
|
||||
|
||||
TEST(Name, ozz_simd_math) {
|
||||
EXPECT_TRUE(ozz::math::SimdImplementationName() != nullptr);
|
||||
}
|
||||
|
||||
TEST(LoadFloat, ozz_simd_math) {
|
||||
const SimdFloat4 fX = ozz::math::simd_float4::LoadX(15.f);
|
||||
EXPECT_SIMDFLOAT_EQ(fX, 15.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SimdFloat4 f1 = ozz::math::simd_float4::Load1(15.f);
|
||||
EXPECT_SIMDFLOAT_EQ(f1, 15.f, 15.f, 15.f, 15.f);
|
||||
|
||||
const SimdFloat4 f4 = ozz::math::simd_float4::Load(1.f, -1.f, 2.f, -3.f);
|
||||
EXPECT_SIMDFLOAT_EQ(f4, 1.f, -1.f, 2.f, -3.f);
|
||||
}
|
||||
|
||||
TEST(LoadFloatPtr, ozz_simd_math) {
|
||||
union Data {
|
||||
float f[4 + 5];
|
||||
char c[(4 + 5) * sizeof(float)]; // The 2nd char isn't aligned to a float.
|
||||
};
|
||||
const Data d_in = {{-1.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f}};
|
||||
const int aligned_offset =
|
||||
(16 - (reinterpret_cast<intptr_t>(d_in.f) & 0xf)) / sizeof(float);
|
||||
assert(aligned_offset > 0 && aligned_offset <= 4);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::simd_float4::LoadPtr(d_in.f + aligned_offset),
|
||||
d_in.f[aligned_offset + 0], d_in.f[aligned_offset + 1],
|
||||
d_in.f[aligned_offset + 2], d_in.f[aligned_offset + 3]);
|
||||
EXPECT_ASSERTION(ozz::math::simd_float4::LoadPtr(d_in.f + aligned_offset - 1),
|
||||
"alignment");
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::simd_float4::LoadPtrU(d_in.f + aligned_offset + 1),
|
||||
d_in.f[aligned_offset + 1], d_in.f[aligned_offset + 2],
|
||||
d_in.f[aligned_offset + 3], d_in.f[aligned_offset + 4]);
|
||||
EXPECT_ASSERTION(ozz::math::simd_float4::LoadPtrU(
|
||||
reinterpret_cast<const float*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::simd_float4::LoadXPtrU(d_in.f + aligned_offset + 1),
|
||||
d_in.f[aligned_offset + 1], 0.f, 0.f, 0.f);
|
||||
EXPECT_ASSERTION(ozz::math::simd_float4::LoadXPtrU(
|
||||
reinterpret_cast<const float*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::simd_float4::Load1PtrU(d_in.f + aligned_offset + 1),
|
||||
d_in.f[aligned_offset + 1], d_in.f[aligned_offset + 1],
|
||||
d_in.f[aligned_offset + 1], d_in.f[aligned_offset + 1]);
|
||||
EXPECT_ASSERTION(ozz::math::simd_float4::Load1PtrU(
|
||||
reinterpret_cast<const float*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::simd_float4::Load2PtrU(d_in.f + aligned_offset + 1),
|
||||
d_in.f[aligned_offset + 1], d_in.f[aligned_offset + 2], 0.f, 0.f);
|
||||
EXPECT_ASSERTION(ozz::math::simd_float4::Load2PtrU(
|
||||
reinterpret_cast<const float*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::simd_float4::Load3PtrU(d_in.f + aligned_offset + 1),
|
||||
d_in.f[aligned_offset + 1], d_in.f[aligned_offset + 2],
|
||||
d_in.f[aligned_offset + 3], 0.f);
|
||||
EXPECT_ASSERTION(ozz::math::simd_float4::Load3PtrU(
|
||||
reinterpret_cast<const float*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
|
||||
TEST(GetFloat, ozz_simd_math) {
|
||||
const SimdFloat4 f = ozz::math::simd_float4::Load(1.f, 2.f, 3.f, 4.f);
|
||||
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(f), 1.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetY(f), 2.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetZ(f), 3.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetW(f), 4.f);
|
||||
}
|
||||
|
||||
TEST(SetFloat, ozz_simd_math) {
|
||||
const SimdFloat4 a = ozz::math::simd_float4::Load(1.f, 2.f, 3.f, 4.f);
|
||||
const SimdFloat4 b = ozz::math::simd_float4::Load(5.f, 6.f, 7.f, 8.f);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SetX(a, b), 5.f, 2.f, 3.f, 4.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SetY(a, b), 1.f, 5.f, 3.f, 4.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SetZ(a, b), 1.f, 2.f, 5.f, 4.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SetW(a, b), 1.f, 2.f, 3.f, 5.f);
|
||||
|
||||
EXPECT_ASSERTION(ozz::math::SetI(a, b, 4), "Invalid index, out of range.");
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SetI(a, b, 0), 5.f, 2.f, 3.f, 4.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SetI(a, b, 1), 1.f, 5.f, 3.f, 4.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SetI(a, b, 2), 1.f, 2.f, 5.f, 4.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SetI(a, b, 3), 1.f, 2.f, 3.f, 5.f);
|
||||
}
|
||||
|
||||
TEST(StoreFloatPtr, ozz_simd_math) {
|
||||
const SimdFloat4 f4 = ozz::math::simd_float4::Load(-1.f, 1.f, 2.f, 3.f);
|
||||
|
||||
union Data {
|
||||
float f[4 + 4]; // The 2nd float isn't aligned to a SimdFloat4.
|
||||
SimdFloat4 f4[2]; // Forces alignment.
|
||||
char c[(4 + 4) * sizeof(float)]; // The 2nd char isn't aligned to a float.
|
||||
};
|
||||
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::StorePtrU(f4, d_out.f + 1);
|
||||
EXPECT_FLOAT_EQ(d_out.f[0], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[1], -1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[2], 1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[3], 2.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[4], 3.f);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::StorePtrU(f4, reinterpret_cast<float*>(d_out.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store1PtrU(f4, d_out.f + 1);
|
||||
EXPECT_FLOAT_EQ(d_out.f[0], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[1], -1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[2], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[3], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[4], 0.f);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::Store1PtrU(f4, reinterpret_cast<float*>(d_out.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store2PtrU(f4, d_out.f + 1);
|
||||
EXPECT_FLOAT_EQ(d_out.f[0], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[1], -1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[2], 1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[3], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[4], 0.f);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::Store2Ptr(f4, reinterpret_cast<float*>(d_out.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store3PtrU(f4, d_out.f + 1);
|
||||
EXPECT_FLOAT_EQ(d_out.f[0], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[1], -1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[2], 1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[3], 2.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[4], 0.f);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::Store3Ptr(f4, reinterpret_cast<float*>(d_out.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::StorePtr(f4, d_out.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[0], -1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[1], 1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[2], 2.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[3], 3.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[4], 0.f);
|
||||
EXPECT_ASSERTION(ozz::math::StorePtr(f4, d_out.f + 1), "alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store1Ptr(f4, d_out.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[0], -1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[1], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[2], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[3], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[4], 0.f);
|
||||
EXPECT_ASSERTION(ozz::math::Store1Ptr(f4, d_out.f + 1), "alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store2Ptr(f4, d_out.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[0], -1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[1], 1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[2], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[3], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[4], 0.f);
|
||||
EXPECT_ASSERTION(ozz::math::Store2Ptr(f4, d_out.f + 1), "alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store3Ptr(f4, d_out.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[0], -1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[1], 1.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[2], 2.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[3], 0.f);
|
||||
EXPECT_FLOAT_EQ(d_out.f[4], 0.f);
|
||||
EXPECT_ASSERTION(ozz::math::Store3Ptr(f4, d_out.f + 1), "alignment");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantFloat, ozz_simd_math) {
|
||||
const SimdFloat4 zero = ozz::math::simd_float4::zero();
|
||||
EXPECT_SIMDFLOAT_EQ(zero, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SimdFloat4 one = ozz::math::simd_float4::one();
|
||||
EXPECT_SIMDFLOAT_EQ(one, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
const SimdFloat4 x_axis = ozz::math::simd_float4::x_axis();
|
||||
EXPECT_SIMDFLOAT_EQ(x_axis, 1.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SimdFloat4 y_axis = ozz::math::simd_float4::y_axis();
|
||||
EXPECT_SIMDFLOAT_EQ(y_axis, 0.f, 1.f, 0.f, 0.f);
|
||||
|
||||
const SimdFloat4 z_axis = ozz::math::simd_float4::z_axis();
|
||||
EXPECT_SIMDFLOAT_EQ(z_axis, 0.f, 0.f, 1.f, 0.f);
|
||||
|
||||
const SimdFloat4 w_axis = ozz::math::simd_float4::w_axis();
|
||||
EXPECT_SIMDFLOAT_EQ(w_axis, 0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(SplatFloat, ozz_simd_math) {
|
||||
const SimdFloat4 f = ozz::math::simd_float4::Load(1.f, -1.f, 2.f, -3.f);
|
||||
|
||||
const SimdFloat4 x = ozz::math::SplatX(f);
|
||||
EXPECT_SIMDFLOAT_EQ(x, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
const SimdFloat4 y = ozz::math::SplatY(f);
|
||||
EXPECT_SIMDFLOAT_EQ(y, -1.f, -1.f, -1.f, -1.f);
|
||||
|
||||
const SimdFloat4 z = ozz::math::SplatZ(f);
|
||||
EXPECT_SIMDFLOAT_EQ(z, 2.f, 2.f, 2.f, 2.f);
|
||||
|
||||
const SimdFloat4 w = ozz::math::SplatW(f);
|
||||
EXPECT_SIMDFLOAT_EQ(w, -3.f, -3.f, -3.f, -3.f);
|
||||
|
||||
const SimdFloat4 s3210 = ozz::math::Swizzle<3, 2, 1, 0>(f);
|
||||
EXPECT_SIMDFLOAT_EQ(s3210, -3.f, 2.f, -1.f, 1.f);
|
||||
|
||||
const SimdFloat4 s0123 = ozz::math::Swizzle<0, 1, 2, 3>(f);
|
||||
EXPECT_SIMDFLOAT_EQ(s0123, 1.f, -1.f, 2.f, -3.f);
|
||||
|
||||
const SimdFloat4 s0011 = ozz::math::Swizzle<0, 0, 1, 1>(f);
|
||||
EXPECT_SIMDFLOAT_EQ(s0011, 1.f, 1.f, -1.f, -1.f);
|
||||
|
||||
const SimdFloat4 s2233 = ozz::math::Swizzle<2, 2, 3, 3>(f);
|
||||
EXPECT_SIMDFLOAT_EQ(s2233, 2.f, 2.f, -3.f, -3.f);
|
||||
|
||||
const SimdFloat4 s0101 = ozz::math::Swizzle<0, 1, 0, 1>(f);
|
||||
EXPECT_SIMDFLOAT_EQ(s0101, 1.f, -1.f, 1.f, -1.f);
|
||||
|
||||
const SimdFloat4 s2323 = ozz::math::Swizzle<2, 3, 2, 3>(f);
|
||||
EXPECT_SIMDFLOAT_EQ(s2323, 2.f, -3.f, 2.f, -3.f);
|
||||
}
|
||||
|
||||
TEST(FromInt, ozz_simd_math) {
|
||||
const ozz::math::SimdInt4 i = ozz::math::simd_int4::Load(0, 46, -93, 9926429);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::simd_float4::FromInt(i), 0.f, 46.f, -93.f,
|
||||
9926429.f);
|
||||
}
|
||||
|
||||
TEST(ArithmeticFloat, ozz_simd_math) {
|
||||
const ozz::math::SimdFloat4 a =
|
||||
ozz::math::simd_float4::Load(0.5f, 1.f, 2.f, 3.f);
|
||||
const ozz::math::SimdFloat4 b =
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, -6.f, 0.f);
|
||||
const ozz::math::SimdFloat4 c =
|
||||
ozz::math::simd_float4::Load(-8.f, 9.f, 10.f, 11.f);
|
||||
|
||||
const ozz::math::SimdFloat4 add = a + b;
|
||||
EXPECT_SIMDFLOAT_EQ(add, 4.5f, 6.f, -4.f, 3.f);
|
||||
|
||||
const ozz::math::SimdFloat4 sub = a - b;
|
||||
EXPECT_SIMDFLOAT_EQ(sub, -3.5f, -4.f, 8.f, 3.f);
|
||||
|
||||
const ozz::math::SimdFloat4 neg = -b;
|
||||
EXPECT_SIMDFLOAT_EQ(neg, -4.f, -5.f, 6.f, -0.f);
|
||||
|
||||
const ozz::math::SimdFloat4 mul = a * b;
|
||||
EXPECT_SIMDFLOAT_EQ(mul, 2.f, 5.f, -12.f, 0.f);
|
||||
|
||||
const ozz::math::SimdFloat4 div = a / b;
|
||||
EXPECT_SIMDFLOAT3_EQ(div, 0.5f / 4.f, 1.f / 5.f, -2.f / 6.f);
|
||||
|
||||
const ozz::math::SimdFloat4 madd = ozz::math::MAdd(a, b, c);
|
||||
EXPECT_SIMDFLOAT_EQ(madd, -6.f, 14.f, -2.f, 11.f);
|
||||
|
||||
const ozz::math::SimdFloat4 msub = ozz::math::MSub(a, b, c);
|
||||
EXPECT_SIMDFLOAT_EQ(msub, 10.f, -4.f, -22.f, -11.f);
|
||||
|
||||
const ozz::math::SimdFloat4 nmadd = ozz::math::NMAdd(a, b, c);
|
||||
EXPECT_SIMDFLOAT_EQ(nmadd, -10.f, 4.f, 22.f, 11.f);
|
||||
|
||||
const ozz::math::SimdFloat4 nmsub = ozz::math::NMSub(a, b, c);
|
||||
EXPECT_SIMDFLOAT_EQ(nmsub, 6.f, -14.f, 2.f, -11.f);
|
||||
|
||||
const ozz::math::SimdFloat4 divx = ozz::math::DivX(a, b);
|
||||
EXPECT_SIMDFLOAT_EQ(divx, 0.5f / 4.f, 1.f, 2.f, 3.f);
|
||||
|
||||
const ozz::math::SimdFloat4 hadd2 = ozz::math::HAdd2(a);
|
||||
EXPECT_SIMDFLOAT_EQ(hadd2, 1.5f, 1.f, 2.f, 3.f);
|
||||
|
||||
const ozz::math::SimdFloat4 hadd3 = ozz::math::HAdd3(a);
|
||||
EXPECT_SIMDFLOAT_EQ(hadd3, 3.5f, 1.f, 2.f, 3.f);
|
||||
|
||||
const ozz::math::SimdFloat4 hadd4 = ozz::math::HAdd4(a);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(hadd4), 6.5f);
|
||||
|
||||
const ozz::math::SimdFloat4 dot2 = ozz::math::Dot2(a, b);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(dot2), 7.f);
|
||||
|
||||
const ozz::math::SimdFloat4 dot3 = ozz::math::Dot3(a, b);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(dot3), -5.f);
|
||||
|
||||
const ozz::math::SimdFloat4 dot4 = ozz::math::Dot4(a, b);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(dot4), -5.f);
|
||||
|
||||
const ozz::math::SimdFloat4 cross =
|
||||
ozz::math::Cross3(ozz::math::simd_float4::Load(1.f, -2.f, 3.f, 46.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 27.f));
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(cross), -27.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetY(cross), 6.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetZ(cross), 13.f);
|
||||
|
||||
const ozz::math::SimdFloat4 rcp = ozz::math::RcpEst(b);
|
||||
EXPECT_SIMDFLOAT3_EQ_EST(rcp, 1.f / 4.f, 1.f / 5.f, -1.f / 6.f);
|
||||
|
||||
const ozz::math::SimdFloat4 rcpnr = ozz::math::RcpEstNR(b);
|
||||
EXPECT_SIMDFLOAT3_EQ(rcpnr, 1.f / 4.f, 1.f / 5.f, -1.f / 6.f);
|
||||
|
||||
const ozz::math::SimdFloat4 rcpxnr = ozz::math::RcpEstXNR(b);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(rcpxnr), 1.f / 4.f);
|
||||
|
||||
const ozz::math::SimdFloat4 rcpx = ozz::math::RcpEstX(b);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(rcpx, 1.f / 4.f, 5.f, -6.f, 0.f);
|
||||
|
||||
const ozz::math::SimdFloat4 sqrt = ozz::math::Sqrt(a);
|
||||
EXPECT_SIMDFLOAT_EQ(sqrt, .7071068f, 1.f, 1.4142135f, 1.7320508f);
|
||||
|
||||
const ozz::math::SimdFloat4 sqrtx = ozz::math::SqrtX(b);
|
||||
EXPECT_SIMDFLOAT_EQ(sqrtx, 2.f, 5.f, -6.f, 0.f);
|
||||
|
||||
const ozz::math::SimdFloat4 rsqrt = ozz::math::RSqrtEst(b);
|
||||
EXPECT_SIMDFLOAT2_EQ_EST(rsqrt, 1.f / 2.f, 1.f / 2.23606798f);
|
||||
|
||||
const ozz::math::SimdFloat4 rsqrtnr = ozz::math::RSqrtEstNR(b);
|
||||
EXPECT_SIMDFLOAT2_EQ_EST(rsqrtnr, 1.f / 2.f, 1.f / 2.23606798f);
|
||||
|
||||
const ozz::math::SimdFloat4 rsqrtx = ozz::math::RSqrtEstX(a);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(rsqrtx, 1.f / .7071068f, 1.f, 2.f, 3.f);
|
||||
|
||||
const ozz::math::SimdFloat4 rsqrtxnr = ozz::math::RSqrtEstXNR(a);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(rsqrtxnr), 1.f / .7071068f);
|
||||
|
||||
const ozz::math::SimdFloat4 abs = ozz::math::Abs(b);
|
||||
EXPECT_SIMDFLOAT_EQ(abs, 4.f, 5.f, 6.f, 0.f);
|
||||
|
||||
const SimdInt4 sign = ozz::math::Sign(b);
|
||||
EXPECT_SIMDINT_EQ(sign, 0, 0, 0x80000000, 0);
|
||||
}
|
||||
|
||||
TEST(LengthFloat, ozz_simd_math) {
|
||||
const SimdFloat4 f = ozz::math::simd_float4::Load(1.f, 2.f, 4.f, 8.f);
|
||||
|
||||
const SimdFloat4 len2 = ozz::math::Length2(f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(len2), 2.236068f);
|
||||
|
||||
const SimdFloat4 len3 = ozz::math::Length3(f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(len3), 4.5825758f);
|
||||
|
||||
const SimdFloat4 len4 = ozz::math::Length4(f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(len4), 9.2195444f);
|
||||
|
||||
const SimdFloat4 len2sqr = ozz::math::Length2Sqr(f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(len2sqr), 5.f);
|
||||
|
||||
const SimdFloat4 len3sqr = ozz::math::Length3Sqr(f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(len3sqr), 21.f);
|
||||
|
||||
const SimdFloat4 len4sqr = ozz::math::Length4Sqr(f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(len4sqr), 85.f);
|
||||
}
|
||||
|
||||
TEST(NormalizeFloat, ozz_simd_math) {
|
||||
const SimdFloat4 f = ozz::math::simd_float4::Load(1.f, 2.f, 4.f, 8.f);
|
||||
const SimdFloat4 unit = ozz::math::simd_float4::x_axis();
|
||||
const SimdFloat4 zero = ozz::math::simd_float4::zero();
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized2(f), 0, 0, 0, 0);
|
||||
const SimdFloat4 norm2 = ozz::math::Normalize2(f);
|
||||
EXPECT_SIMDFLOAT_EQ(norm2, .44721359f, .89442718f, 4.f, 8.f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized2(norm2), 0xffffffff, 0, 0, 0);
|
||||
|
||||
const SimdFloat4 norm_est2 = ozz::math::NormalizeEst2(f);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(norm_est2, .44721359f, .89442718f, 4.f, 8.f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalizedEst2(norm_est2), 0xffffffff, 0, 0,
|
||||
0);
|
||||
|
||||
EXPECT_ASSERTION(ozz::math::Normalize2(zero), "_v is not normalizable");
|
||||
EXPECT_ASSERTION(ozz::math::NormalizeEst2(zero), "_v is not normalizable");
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized3(f), 0, 0, 0, 0);
|
||||
const SimdFloat4 norm3 = ozz::math::Normalize3(f);
|
||||
EXPECT_SIMDFLOAT_EQ(norm3, .21821788f, .43643576f, .87287152f, 8.f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized3(norm3), 0xffffffff, 0, 0, 0);
|
||||
|
||||
const SimdFloat4 norm_est3 = ozz::math::NormalizeEst3(f);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(norm_est3, .21821788f, .43643576f, .87287152f, 8.f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalizedEst3(norm_est3), 0xffffffff, 0, 0,
|
||||
0);
|
||||
|
||||
EXPECT_ASSERTION(ozz::math::Normalize3(zero), "_v is not normalizable");
|
||||
EXPECT_ASSERTION(ozz::math::NormalizeEst3(zero), "_v is not normalizable");
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized4(f), 0, 0, 0, 0);
|
||||
const SimdFloat4 norm4 = ozz::math::Normalize4(f);
|
||||
EXPECT_SIMDFLOAT_EQ(norm4, .1084652f, .2169304f, .4338609f, .86772186f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized4(norm4), 0xffffffff, 0, 0, 0);
|
||||
|
||||
const SimdFloat4 norm_est4 = ozz::math::NormalizeEst4(f);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(norm_est4, .1084652f, .2169304f, .4338609f,
|
||||
.86772186f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalizedEst4(norm_est4), 0xffffffff, 0, 0,
|
||||
0);
|
||||
|
||||
EXPECT_ASSERTION(ozz::math::Normalize4(zero), "_v is not normalizable");
|
||||
EXPECT_ASSERTION(ozz::math::NormalizeEst4(zero), "_v is not normalizable");
|
||||
|
||||
const SimdFloat4 safe2 = ozz::math::NormalizeSafe2(f, unit);
|
||||
EXPECT_SIMDFLOAT_EQ(safe2, .4472136f, .8944272f, 4.f, 8.f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized2(safe2), 0xffffffff, 0, 0, 0);
|
||||
const SimdFloat4 safer2 = ozz::math::NormalizeSafe2(zero, unit);
|
||||
EXPECT_SIMDFLOAT_EQ(safer2, 1.f, 0.f, 0.f, 0.f);
|
||||
const SimdFloat4 safe_est2 = ozz::math::NormalizeSafeEst2(f, unit);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(safe_est2, .4472136f, .8944272f, 4.f, 8.f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalizedEst2(safe_est2), 0xffffffff, 0, 0,
|
||||
0);
|
||||
const SimdFloat4 safer_est2 = ozz::math::NormalizeSafeEst2(zero, unit);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(safer_est2, 1.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SimdFloat4 safe3 = ozz::math::NormalizeSafe3(f, unit);
|
||||
EXPECT_SIMDFLOAT_EQ(safe3, .21821788f, .43643576f, .87287152f, 8.f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized3(safe3), 0xffffffff, 0, 0, 0);
|
||||
const SimdFloat4 safer3 = ozz::math::NormalizeSafe3(zero, unit);
|
||||
EXPECT_SIMDFLOAT_EQ(safer3, 1.f, 0.f, 0.f, 0.f);
|
||||
const SimdFloat4 safe_est3 = ozz::math::NormalizeSafeEst3(f, unit);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(safe_est3, .21821788f, .43643576f, .87287152f, 8.f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalizedEst3(safe_est3), 0xffffffff, 0, 0,
|
||||
0);
|
||||
const SimdFloat4 safer_est3 = ozz::math::NormalizeSafeEst3(zero, unit);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(safer_est3, 1.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SimdFloat4 safe4 = ozz::math::NormalizeSafe4(f, unit);
|
||||
EXPECT_SIMDFLOAT_EQ(safe4, .1084652f, .2169305f, .433861f, .8677219f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized4(safe4), 0xffffffff, 0, 0, 0);
|
||||
const SimdFloat4 safer4 = ozz::math::NormalizeSafe4(zero, unit);
|
||||
EXPECT_SIMDFLOAT_EQ(safer4, 1.f, 0.f, 0.f, 0.f);
|
||||
const SimdFloat4 safe_est4 = ozz::math::NormalizeSafeEst4(f, unit);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(safe_est4, .1084652f, .2169305f, .433861f, .8677219f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalizedEst4(safe_est4), 0xffffffff, 0, 0,
|
||||
0);
|
||||
const SimdFloat4 safer_est4 = ozz::math::NormalizeSafeEst4(zero, unit);
|
||||
EXPECT_SIMDFLOAT_EQ_EST(safer_est4, 1.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(CompareFloat, ozz_simd_math) {
|
||||
const SimdFloat4 a = ozz::math::simd_float4::Load(0.5f, 1.f, 2.f, 3.f);
|
||||
const SimdFloat4 b = ozz::math::simd_float4::Load(4.f, 1.f, -6.f, 7.f);
|
||||
const SimdFloat4 c = ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f);
|
||||
|
||||
const SimdFloat4 min = ozz::math::Min(a, b);
|
||||
EXPECT_SIMDFLOAT_EQ(min, 0.5f, 1.f, -6.f, 3.f);
|
||||
|
||||
const SimdFloat4 max = ozz::math::Max(a, b);
|
||||
EXPECT_SIMDFLOAT_EQ(max, 4.f, 1.f, 2.f, 7.f);
|
||||
|
||||
const SimdFloat4 min0 = ozz::math::Min0(b);
|
||||
EXPECT_SIMDFLOAT_EQ(min0, 0.f, 0.f, -6.f, 0.f);
|
||||
|
||||
const SimdFloat4 max0 = ozz::math::Max0(b);
|
||||
EXPECT_SIMDFLOAT_EQ(max0, 4.f, 1.f, 0.f, 7.f);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::Clamp(a, ozz::math::simd_float4::Load(-12.f, 2.f, 9.f, 3.f),
|
||||
c),
|
||||
.5f, 2.f, 6.f, 3.f);
|
||||
|
||||
const SimdInt4 eq1 = ozz::math::CmpEq(a, b);
|
||||
EXPECT_SIMDINT_EQ(eq1, 0, 0xffffffff, 0, 0);
|
||||
|
||||
const SimdInt4 eq2 = ozz::math::CmpEq(a, a);
|
||||
EXPECT_SIMDINT_EQ(eq2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
const SimdInt4 neq1 = ozz::math::CmpNe(a, b);
|
||||
EXPECT_SIMDINT_EQ(neq1, 0xffffffff, 0, 0xffffffff, 0xffffffff);
|
||||
|
||||
const SimdInt4 neq2 = ozz::math::CmpNe(a, a);
|
||||
EXPECT_SIMDINT_EQ(neq2, 0, 0, 0, 0);
|
||||
|
||||
const SimdInt4 lt = ozz::math::CmpLt(a, b);
|
||||
EXPECT_SIMDINT_EQ(lt, 0xffffffff, 0, 0, 0xffffffff);
|
||||
|
||||
const SimdInt4 le = ozz::math::CmpLe(a, b);
|
||||
EXPECT_SIMDINT_EQ(le, 0xffffffff, 0xffffffff, 0u, 0xffffffff);
|
||||
|
||||
const SimdInt4 gt = ozz::math::CmpGt(a, b);
|
||||
EXPECT_SIMDINT_EQ(gt, 0u, 0u, 0xffffffff, 0u);
|
||||
|
||||
const SimdInt4 ge = ozz::math::CmpGe(a, b);
|
||||
EXPECT_SIMDINT_EQ(ge, 0u, 0xffffffff, 0xffffffff, 0u);
|
||||
}
|
||||
|
||||
TEST(LerpFloat, ozz_simd_math) {
|
||||
const SimdFloat4 a = ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 4.f);
|
||||
const SimdFloat4 b = ozz::math::simd_float4::Load(0.f, -1.f, -2.f, -4.f);
|
||||
const SimdFloat4 zero = ozz::math::simd_float4::Load1(0.f);
|
||||
const SimdFloat4 one = ozz::math::simd_float4::Load1(1.f);
|
||||
|
||||
const SimdFloat4 lerp0 = ozz::math::Lerp(a, b, zero);
|
||||
EXPECT_SIMDFLOAT_EQ(lerp0, 0.f, 1.f, 2.f, 4.f);
|
||||
|
||||
const SimdFloat4 lerp1 = ozz::math::Lerp(a, b, one);
|
||||
EXPECT_SIMDFLOAT_EQ(lerp1, 0.f, -1.f, -2.f, -4.f);
|
||||
|
||||
const SimdFloat4 lhalf =
|
||||
ozz::math::Lerp(a, b, ozz::math::simd_float4::Load1(0.5f));
|
||||
EXPECT_SIMDFLOAT_EQ(lhalf, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SimdFloat4 lmixed =
|
||||
ozz::math::Lerp(a, b, ozz::math::simd_float4::Load(0.f, -1.f, 0.5f, 2.f));
|
||||
EXPECT_SIMDFLOAT_EQ(lmixed, 0.f, 3.f, 0.f, -12.f);
|
||||
}
|
||||
|
||||
TEST(TrigonometryFloat, ozz_simd_math) {
|
||||
using ozz::math::k2Pi;
|
||||
using ozz::math::kPi;
|
||||
using ozz::math::kPi_2;
|
||||
|
||||
const SimdFloat4 angle =
|
||||
ozz::math::simd_float4::Load(kPi, kPi / 6.f, -kPi_2, 5.f * kPi_2);
|
||||
const SimdFloat4 cos =
|
||||
ozz::math::simd_float4::Load(-1.f, .86602539f, 0.f, 0.f);
|
||||
const SimdFloat4 sin = ozz::math::simd_float4::Load(0.f, .5f, -1.f, 1.f);
|
||||
|
||||
const SimdFloat4 angle_tan =
|
||||
ozz::math::simd_float4::Load(0.f, kPi / 6.f, -kPi / 3.f, 9.f * kPi / 4.f);
|
||||
const SimdFloat4 tan =
|
||||
ozz::math::simd_float4::Load(0.f, .57735f, -1.73205f, 1.f);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::Cos(angle), -1.f, .86602539f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::Cos(angle + ozz::math::simd_float4::Load1(k2Pi)), -1.f,
|
||||
.86602539f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::Cos(angle + ozz::math::simd_float4::Load1(k2Pi * 12.f)), -1.f,
|
||||
.86602539f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::Cos(angle - ozz::math::simd_float4::Load1(k2Pi * 24.f)), -1.f,
|
||||
.86602539f, 0.f, 0.f);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::CosX(angle), -1.f, kPi / 6.f, -kPi_2,
|
||||
5.f * kPi_2);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::CosX(angle + ozz::math::simd_float4::LoadX(k2Pi)), -1.f,
|
||||
kPi / 6.f, -kPi_2, 5.f * kPi_2);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::CosX(angle + ozz::math::simd_float4::LoadX(k2Pi * 12.f)), -1.f,
|
||||
kPi / 6.f, -kPi_2, 5.f * kPi_2);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::CosX(angle - ozz::math::simd_float4::LoadX(k2Pi * 24.f)), -1.f,
|
||||
kPi / 6.f, -kPi_2, 5.f * kPi_2);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::Sin(angle), 0.f, .5f, -1.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::Sin(angle + ozz::math::simd_float4::Load1(k2Pi)), 0.f, 0.5f,
|
||||
-1.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::Sin(angle + ozz::math::simd_float4::Load1(k2Pi * 12.f)), 0.f,
|
||||
.5f, -1.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::Sin(angle - ozz::math::simd_float4::Load1(k2Pi * 24.f)), 0.f,
|
||||
.5f, -1.f, 1.f);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::SinX(angle), 0.f, kPi / 6.f, -kPi_2,
|
||||
5.f * kPi_2);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::SinX(angle + ozz::math::simd_float4::LoadX(k2Pi)), 0.f,
|
||||
kPi / 6.f, -kPi_2, 5.f * kPi_2);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::SinX(angle + ozz::math::simd_float4::LoadX(k2Pi * 12.f)), 0.f,
|
||||
kPi / 6.f, -kPi_2, 5.f * kPi_2);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::SinX(angle - ozz::math::simd_float4::LoadX(k2Pi * 24.f)), 0.f,
|
||||
kPi / 6.f, -kPi_2, 5.f * kPi_2);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::ACos(cos), kPi, kPi / 6.f, kPi_2, kPi_2);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::ACosX(cos), kPi, .86602539f, 0.f, 0.f);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::ASin(sin), 0.f, kPi / 6.f, -kPi_2, kPi_2);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::ASinX(sin), 0.f, .5f, -1.f, 1.f);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::Tan(angle_tan), 0.f, 0.57735f, -1.73205f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::TanX(angle_tan), 0.f, kPi / 6.f, -kPi / 3.f,
|
||||
9.f * kPi / 4.f);
|
||||
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::ATan(tan), 0.f, kPi / 6.f, -kPi / 3.f,
|
||||
kPi / 4.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::ATanX(tan), 0.f, .57735f, -1.73205f, 1.f);
|
||||
}
|
||||
|
||||
TEST(LogicalFloat, ozz_simd_math) {
|
||||
const SimdFloat4 a = ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f);
|
||||
const SimdFloat4 b = ozz::math::simd_float4::Load(1.f, -1.f, -3.f, -4.f);
|
||||
const SimdInt4 mbool =
|
||||
ozz::math::simd_int4::Load(0xffffffff, 0, 0, 0xffffffff);
|
||||
const SimdInt4 mbit =
|
||||
ozz::math::simd_int4::Load(0xffffffff, 0, 0x80000000, 0x7fffffff);
|
||||
const SimdFloat4 mfloat = ozz::math::simd_float4::Load(1.f, 0.f, -0.f, 3.f);
|
||||
|
||||
const SimdFloat4 select = ozz::math::Select(mbool, a, b);
|
||||
EXPECT_SIMDFLOAT_EQ(select, 0.f, -1.f, -3.f, 3.f);
|
||||
|
||||
const SimdFloat4 andm = ozz::math::And(b, mbit);
|
||||
EXPECT_SIMDFLOAT_EQ(andm, 1.f, 0.f, 0.f, 4.f);
|
||||
|
||||
const SimdFloat4 andnm = ozz::math::AndNot(b, mbit);
|
||||
EXPECT_SIMDFLOAT_EQ(andnm, 0.f, -1.f, 3.f, -0.f);
|
||||
|
||||
const SimdFloat4 andf = ozz::math::And(b, mfloat);
|
||||
EXPECT_SIMDFLOAT_EQ(andf, 1.f, 0.f, -0.f, 2.f);
|
||||
|
||||
const SimdFloat4 orm = ozz::math::Or(a, mbit);
|
||||
union {
|
||||
float f;
|
||||
unsigned int i;
|
||||
} orx = {ozz::math::GetX(orm)};
|
||||
EXPECT_EQ(orx.i, 0xffffffff);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetY(orm), 1.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetZ(orm), -2.f);
|
||||
union {
|
||||
float f;
|
||||
int i;
|
||||
} orw = {ozz::math::GetW(orm)};
|
||||
EXPECT_TRUE(orw.i == 0x7fffffff);
|
||||
|
||||
const SimdFloat4 ormf = ozz::math::Or(a, mfloat);
|
||||
EXPECT_SIMDFLOAT_EQ(ormf, 1.f, 1.f, -2.f, 3.f);
|
||||
|
||||
const SimdFloat4 xorm = ozz::math::Xor(a, mbit);
|
||||
union {
|
||||
float f;
|
||||
unsigned int i;
|
||||
} xorx = {ozz::math::GetX(xorm)};
|
||||
EXPECT_TRUE(xorx.i == 0xffffffff);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetY(xorm), 1.f);
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetZ(xorm), -2.f);
|
||||
union {
|
||||
float f;
|
||||
unsigned int i;
|
||||
} xorw = {ozz::math::GetW(xorm)};
|
||||
EXPECT_TRUE(xorw.i == 0x3fbfffff);
|
||||
|
||||
const SimdFloat4 xormf = ozz::math::Xor(a, mfloat);
|
||||
EXPECT_SIMDFLOAT_EQ(xormf, 1.f, 1.f, -2.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(Half, ozz_simd_math) {
|
||||
// 0
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(0.f), 0);
|
||||
EXPECT_FLOAT_EQ(ozz::math::HalfToFloat(0), 0.f);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(-0.f), 0x8000);
|
||||
EXPECT_FLOAT_EQ(ozz::math::HalfToFloat(0x8000), -0.f);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(std::numeric_limits<float>::min()), 0);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(std::numeric_limits<float>::denorm_min()),
|
||||
0);
|
||||
EXPECT_EQ(
|
||||
ozz::math::FloatToHalf(std::numeric_limits<float>::denorm_min() / 10.f),
|
||||
0);
|
||||
|
||||
// 1
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(1.f), 0x3c00);
|
||||
EXPECT_FLOAT_EQ(ozz::math::HalfToFloat(0x3c00), 1.f);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(-1.f), 0xbc00);
|
||||
EXPECT_FLOAT_EQ(ozz::math::HalfToFloat(0xbc00), -1.f);
|
||||
|
||||
// Bounds
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(65504.f), 0x7bff);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(-65504.f), 0xfbff);
|
||||
|
||||
// Min, Max, Infinity
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(10e-16f), 0);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(10e+16f), 0x7c00);
|
||||
EXPECT_FLOAT_EQ(ozz::math::HalfToFloat(0x7c00),
|
||||
std::numeric_limits<float>::infinity());
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(std::numeric_limits<float>::max()), 0x7c00);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(std::numeric_limits<float>::infinity()),
|
||||
0x7c00);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(-10e+16f), 0xfc00);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(-std::numeric_limits<float>::infinity()),
|
||||
0xfc00);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(-std::numeric_limits<float>::max()), 0xfc00);
|
||||
EXPECT_FLOAT_EQ(ozz::math::HalfToFloat(0xfc00),
|
||||
-std::numeric_limits<float>::infinity());
|
||||
|
||||
// Nan
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(std::numeric_limits<float>::quiet_NaN()),
|
||||
0x7e00);
|
||||
EXPECT_EQ(ozz::math::FloatToHalf(std::numeric_limits<float>::signaling_NaN()),
|
||||
0x7e00);
|
||||
// According to the IEEE standard, NaN values have the odd property that
|
||||
// comparisons involving them are always false
|
||||
EXPECT_FALSE(ozz::math::HalfToFloat(0x7e00) ==
|
||||
ozz::math::HalfToFloat(0x7e00));
|
||||
|
||||
// Random tries in range [10e-4,10e4].
|
||||
for (float pow = -4.f; pow <= 4.f; pow += 1.f) {
|
||||
const float max = powf(10.f, pow);
|
||||
// Expect a 1/1000 precision over floats.
|
||||
const float precision = max / 1000.f;
|
||||
|
||||
const int n = 1000;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const float frand = max * (2.f * i / n - 1.f);
|
||||
|
||||
const uint16_t h = ozz::math::FloatToHalf(frand);
|
||||
const float f = ozz::math::HalfToFloat(h);
|
||||
EXPECT_NEAR(frand, f, precision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SimdHalf, ozz_simd_math) {
|
||||
// 0
|
||||
EXPECT_SIMDINT_EQ(ozz::math::FloatToHalf(ozz::math::simd_float4::Load(
|
||||
0.f, -0.f, std::numeric_limits<float>::min(),
|
||||
std::numeric_limits<float>::denorm_min())),
|
||||
0, 0x00008000, 0, 0);
|
||||
EXPECT_SIMDFLOAT_EQ(
|
||||
ozz::math::HalfToFloat(ozz::math::simd_int4::Load(0, 0x00008000, 0, 0)),
|
||||
0.f, -0.f, 0.f, 0.f);
|
||||
|
||||
// 1
|
||||
EXPECT_SIMDINT_EQ(ozz::math::FloatToHalf(
|
||||
ozz::math::simd_float4::Load(1.f, -1.f, 0.f, -0.f)),
|
||||
0x00003c00, 0x0000bc00, 0, 0x00008000);
|
||||
EXPECT_SIMDFLOAT_EQ(ozz::math::HalfToFloat(ozz::math::simd_int4::Load(
|
||||
0x3c00, 0xbc00, 0, 0x00008000)),
|
||||
1.f, -1.f, 0.f, -0.f);
|
||||
|
||||
// Bounds
|
||||
EXPECT_SIMDINT_EQ(ozz::math::FloatToHalf(ozz::math::simd_float4::Load(
|
||||
65504.f, -65504.f, 65604.f, -65604.f)),
|
||||
0x00007bff, 0x0000fbff, 0x00007c00, 0x0000fc00);
|
||||
|
||||
// Min, Max, Infinity
|
||||
EXPECT_SIMDINT_EQ(ozz::math::FloatToHalf(ozz::math::simd_float4::Load(
|
||||
10e-16f, 10e+16f, std::numeric_limits<float>::max(),
|
||||
std::numeric_limits<float>::infinity())),
|
||||
0, 0x00007c00, 0x00007c00, 0x00007c00);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::FloatToHalf(ozz::math::simd_float4::Load(
|
||||
-10e-16f, -10e+16f, -std::numeric_limits<float>::max(),
|
||||
-std::numeric_limits<float>::max())),
|
||||
0x00008000, 0x0000fc00, 0x0000fc00, 0x0000fc00);
|
||||
|
||||
// Nan
|
||||
EXPECT_SIMDINT_EQ(ozz::math::FloatToHalf(ozz::math::simd_float4::Load(
|
||||
std::numeric_limits<float>::quiet_NaN(),
|
||||
std::numeric_limits<float>::signaling_NaN(), 0, 0)),
|
||||
0x00007e00, 0x00007e00, 0, 0);
|
||||
|
||||
// Inf and NAN
|
||||
const SimdFloat4 infnan = ozz::math::HalfToFloat(
|
||||
ozz::math::simd_int4::Load(0x00007c00, 0x0000fc00, 0x00007e00, 0));
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetX(infnan),
|
||||
std::numeric_limits<float>::infinity());
|
||||
EXPECT_FLOAT_EQ(ozz::math::GetY(infnan),
|
||||
-std::numeric_limits<float>::infinity());
|
||||
EXPECT_FALSE(ozz::math::GetZ(infnan) == ozz::math::GetZ(infnan));
|
||||
|
||||
// Random tries in range [10e-4,10e4].
|
||||
srand(0);
|
||||
for (float pow = -4.f; pow <= 4.f; pow += 1.f) {
|
||||
const float max = powf(10.f, pow);
|
||||
// Expect a 1/1000 precision over floats.
|
||||
const float precision = max / 1000.f;
|
||||
|
||||
const int n = 1000;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const SimdFloat4 frand = ozz::math::simd_float4::Load(
|
||||
max * (.5f * i / n - .25f), max * (1.f * i / n - .5f),
|
||||
max * (1.5f * i / n - .75f), max * (2.f * i / n - 1.f));
|
||||
|
||||
const SimdInt4 h = ozz::math::FloatToHalf(frand);
|
||||
const SimdFloat4 f = ozz::math::HalfToFloat(h);
|
||||
|
||||
EXPECT_NEAR(ozz::math::GetX(frand), ozz::math::GetX(f), precision);
|
||||
EXPECT_NEAR(ozz::math::GetY(frand), ozz::math::GetY(f), precision);
|
||||
EXPECT_NEAR(ozz::math::GetZ(frand), ozz::math::GetZ(f), precision);
|
||||
EXPECT_NEAR(ozz::math::GetW(frand), ozz::math::GetW(f), precision);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,524 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
|
||||
using ozz::math::SimdInt4;
|
||||
|
||||
static_assert(sizeof(SimdInt4) == 4 * sizeof(int32_t),
|
||||
"Expects SimdInt4 to be the size of 4 int32_t.");
|
||||
static_assert(alignof(SimdInt4) == 16,
|
||||
"Expects SimdInt4 to be the size of 16 bytes.");
|
||||
|
||||
TEST(LoadInt, ozz_simd_math) {
|
||||
const SimdInt4 iX = ozz::math::simd_int4::LoadX(15);
|
||||
EXPECT_SIMDINT_EQ(iX, 15, 0, 0, 0);
|
||||
|
||||
const SimdInt4 i1 = ozz::math::simd_int4::Load1(15);
|
||||
EXPECT_SIMDINT_EQ(i1, 15, 15, 15, 15);
|
||||
|
||||
const SimdInt4 i4 = ozz::math::simd_int4::Load(1, -1, 2, -3);
|
||||
EXPECT_SIMDINT_EQ(i4, 1, -1, 2, -3);
|
||||
|
||||
const SimdInt4 itX = ozz::math::simd_int4::LoadX(true);
|
||||
EXPECT_SIMDINT_EQ(itX, 0xffffffff, 0, 0, 0);
|
||||
|
||||
const SimdInt4 ifX = ozz::math::simd_int4::LoadX(false);
|
||||
EXPECT_SIMDINT_EQ(ifX, 0, 0, 0, 0);
|
||||
|
||||
const SimdInt4 it1 = ozz::math::simd_int4::Load1(true);
|
||||
EXPECT_SIMDINT_EQ(it1, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
const SimdInt4 if1 = ozz::math::simd_int4::Load1(false);
|
||||
EXPECT_SIMDINT_EQ(if1, 0, 0, 0, 0);
|
||||
|
||||
const SimdInt4 ibttff = ozz::math::simd_int4::Load(true, true, false, false);
|
||||
EXPECT_SIMDINT_EQ(ibttff, 0xffffffff, 0xffffffff, 0, 0);
|
||||
|
||||
const SimdInt4 ibftft = ozz::math::simd_int4::Load(false, true, false, true);
|
||||
EXPECT_SIMDINT_EQ(ibftft, 0, 0xffffffff, 0, 0xffffffff);
|
||||
}
|
||||
|
||||
TEST(LoadIntPtr, ozz_simd_math) {
|
||||
union Data {
|
||||
int i[4 + 5];
|
||||
char c[(4 + 5) * sizeof(int)]; // The 2nd char isn't aligned to an integer.
|
||||
};
|
||||
const Data d_in = {{-1, 1, 2, 3, 4, 5, 6, 7, 8}};
|
||||
const int aligned_offset =
|
||||
(16 - (reinterpret_cast<intptr_t>(d_in.i) & 0xf)) / sizeof(float);
|
||||
assert(aligned_offset > 0 && aligned_offset <= 4);
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::LoadPtrU(d_in.i + aligned_offset + 1),
|
||||
d_in.i[aligned_offset + 1], d_in.i[aligned_offset + 2],
|
||||
d_in.i[aligned_offset + 3], d_in.i[aligned_offset + 4]);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::simd_int4::LoadPtrU(reinterpret_cast<const int*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::LoadPtr(d_in.i + aligned_offset),
|
||||
d_in.i[aligned_offset], d_in.i[aligned_offset + 1],
|
||||
d_in.i[aligned_offset + 2], d_in.i[aligned_offset + 3]);
|
||||
EXPECT_ASSERTION(ozz::math::simd_int4::LoadPtr(d_in.i + aligned_offset + 1),
|
||||
"alignment");
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::LoadXPtrU(d_in.i + aligned_offset),
|
||||
d_in.i[aligned_offset], 0, 0, 0);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::simd_int4::LoadXPtrU(reinterpret_cast<const int*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::Load1PtrU(d_in.i + aligned_offset),
|
||||
d_in.i[aligned_offset], d_in.i[aligned_offset],
|
||||
d_in.i[aligned_offset], d_in.i[aligned_offset]);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::simd_int4::Load1PtrU(reinterpret_cast<const int*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::LoadXPtr(d_in.i + aligned_offset),
|
||||
d_in.i[aligned_offset], 0, 0, 0);
|
||||
EXPECT_ASSERTION(ozz::math::simd_int4::LoadXPtr(d_in.i + aligned_offset + 1),
|
||||
"alignment");
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::Load1Ptr(d_in.i + aligned_offset),
|
||||
d_in.i[aligned_offset], d_in.i[aligned_offset],
|
||||
d_in.i[aligned_offset], d_in.i[aligned_offset]);
|
||||
EXPECT_ASSERTION(ozz::math::simd_int4::Load1Ptr(d_in.i + aligned_offset + 1),
|
||||
"alignment");
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::Load2Ptr(d_in.i + aligned_offset),
|
||||
d_in.i[aligned_offset], d_in.i[aligned_offset + 1], 0, 0);
|
||||
EXPECT_ASSERTION(ozz::math::simd_int4::Load2Ptr(d_in.i + aligned_offset + 1),
|
||||
"alignment");
|
||||
EXPECT_SIMDINT_EQ(
|
||||
ozz::math::simd_int4::Load2PtrU(d_in.i + aligned_offset + 1),
|
||||
d_in.i[aligned_offset + 1], d_in.i[aligned_offset + 2], 0, 0);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::simd_int4::Load2PtrU(reinterpret_cast<const int*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::Load3Ptr(d_in.i + aligned_offset),
|
||||
d_in.i[aligned_offset], d_in.i[aligned_offset + 1],
|
||||
d_in.i[aligned_offset + 2], 0);
|
||||
EXPECT_ASSERTION(ozz::math::simd_int4::Load3Ptr(d_in.i + aligned_offset + 1),
|
||||
"alignment");
|
||||
EXPECT_SIMDINT_EQ(
|
||||
ozz::math::simd_int4::Load3PtrU(d_in.i + aligned_offset + 1),
|
||||
d_in.i[aligned_offset + 1], d_in.i[aligned_offset + 2],
|
||||
d_in.i[aligned_offset + 3], 0);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::simd_int4::Load3PtrU(reinterpret_cast<const int*>(d_in.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
|
||||
TEST(GetInt, ozz_simd_math) {
|
||||
const SimdInt4 i = ozz::math::simd_int4::Load(1, 2, 3, 4);
|
||||
|
||||
EXPECT_EQ(ozz::math::GetX(i), 1);
|
||||
EXPECT_EQ(ozz::math::GetY(i), 2);
|
||||
EXPECT_EQ(ozz::math::GetZ(i), 3);
|
||||
EXPECT_EQ(ozz::math::GetW(i), 4);
|
||||
}
|
||||
|
||||
TEST(SetInt, ozz_simd_math) {
|
||||
const SimdInt4 a = ozz::math::simd_int4::Load(1, 2, 3, 4);
|
||||
const SimdInt4 b = ozz::math::simd_int4::Load(5, 6, 7, 8);
|
||||
|
||||
EXPECT_SIMDINT_EQ(ozz::math::SetX(a, b), 5, 2, 3, 4);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::SetY(a, b), 1, 5, 3, 4);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::SetZ(a, b), 1, 2, 5, 4);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::SetW(a, b), 1, 2, 3, 5);
|
||||
|
||||
EXPECT_ASSERTION(ozz::math::SetI(a, b, 4), "Invalid index, out of range.");
|
||||
EXPECT_SIMDINT_EQ(ozz::math::SetI(a, b, 0), 5, 2, 3, 4);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::SetI(a, b, 1), 1, 5, 3, 4);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::SetI(a, b, 2), 1, 2, 5, 4);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::SetI(a, b, 3), 1, 2, 3, 5);
|
||||
}
|
||||
|
||||
TEST(StoreIntPtr, ozz_simd_math) {
|
||||
const SimdInt4 i4 = ozz::math::simd_int4::Load(-1, 1, 2, 3);
|
||||
|
||||
union Data {
|
||||
int i[4 + 4]; // The 2nd float isn't aligned to a SimdInt4.
|
||||
SimdInt4 i4[2]; // Forces alignment.
|
||||
char c[(4 + 4) * sizeof(int)]; // The 2nd char isn't aligned to an integer.
|
||||
};
|
||||
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::StorePtrU(i4, d_out.i + 1);
|
||||
EXPECT_EQ(d_out.i[0], 0);
|
||||
EXPECT_EQ(d_out.i[1], -1);
|
||||
EXPECT_EQ(d_out.i[2], 1);
|
||||
EXPECT_EQ(d_out.i[3], 2);
|
||||
EXPECT_EQ(d_out.i[4], 3);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::StorePtrU(i4, reinterpret_cast<int*>(d_out.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store1PtrU(i4, d_out.i + 1);
|
||||
EXPECT_EQ(d_out.i[0], 0);
|
||||
EXPECT_EQ(d_out.i[1], -1);
|
||||
EXPECT_EQ(d_out.i[2], 0);
|
||||
EXPECT_EQ(d_out.i[3], 0);
|
||||
EXPECT_EQ(d_out.i[4], 0);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::Store1PtrU(i4, reinterpret_cast<int*>(d_out.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store2PtrU(i4, d_out.i + 1);
|
||||
EXPECT_EQ(d_out.i[0], 0);
|
||||
EXPECT_EQ(d_out.i[1], -1);
|
||||
EXPECT_EQ(d_out.i[2], 1);
|
||||
EXPECT_EQ(d_out.i[3], 0);
|
||||
EXPECT_EQ(d_out.i[4], 0);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::Store2Ptr(i4, reinterpret_cast<int*>(d_out.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store3PtrU(i4, d_out.i + 1);
|
||||
EXPECT_EQ(d_out.i[0], 0);
|
||||
EXPECT_EQ(d_out.i[1], -1);
|
||||
EXPECT_EQ(d_out.i[2], 1);
|
||||
EXPECT_EQ(d_out.i[3], 2);
|
||||
EXPECT_EQ(d_out.i[4], 0);
|
||||
EXPECT_ASSERTION(
|
||||
ozz::math::Store3Ptr(i4, reinterpret_cast<int*>(d_out.c + 1)),
|
||||
"alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::StorePtr(i4, d_out.i);
|
||||
EXPECT_EQ(d_out.i[0], -1);
|
||||
EXPECT_EQ(d_out.i[1], 1);
|
||||
EXPECT_EQ(d_out.i[2], 2);
|
||||
EXPECT_EQ(d_out.i[3], 3);
|
||||
EXPECT_EQ(d_out.i[4], 0);
|
||||
EXPECT_ASSERTION(ozz::math::StorePtr(i4, d_out.i + 1), "alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store1Ptr(i4, d_out.i);
|
||||
EXPECT_EQ(d_out.i[0], -1);
|
||||
EXPECT_EQ(d_out.i[1], 0);
|
||||
EXPECT_EQ(d_out.i[2], 0);
|
||||
EXPECT_EQ(d_out.i[3], 0);
|
||||
EXPECT_EQ(d_out.i[4], 0);
|
||||
EXPECT_ASSERTION(ozz::math::Store1Ptr(i4, d_out.i + 1), "alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store2Ptr(i4, d_out.i);
|
||||
EXPECT_EQ(d_out.i[0], -1);
|
||||
EXPECT_EQ(d_out.i[1], 1);
|
||||
EXPECT_EQ(d_out.i[2], 0);
|
||||
EXPECT_EQ(d_out.i[3], 0);
|
||||
EXPECT_EQ(d_out.i[4], 0);
|
||||
EXPECT_ASSERTION(ozz::math::Store2Ptr(i4, d_out.i + 1), "alignment");
|
||||
}
|
||||
{
|
||||
Data d_out = {};
|
||||
ozz::math::Store3Ptr(i4, d_out.i);
|
||||
EXPECT_EQ(d_out.i[0], -1);
|
||||
EXPECT_EQ(d_out.i[1], 1);
|
||||
EXPECT_EQ(d_out.i[2], 2);
|
||||
EXPECT_EQ(d_out.i[3], 0);
|
||||
EXPECT_EQ(d_out.i[4], 0);
|
||||
EXPECT_ASSERTION(ozz::math::Store3Ptr(i4, d_out.i + 1), "alignment");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantInt, ozz_simd_math) {
|
||||
const SimdInt4 zero = ozz::math::simd_int4::zero();
|
||||
EXPECT_SIMDINT_EQ(zero, 0, 0, 0, 0);
|
||||
|
||||
const SimdInt4 one = ozz::math::simd_int4::one();
|
||||
EXPECT_SIMDINT_EQ(one, 1, 1, 1, 1);
|
||||
|
||||
const SimdInt4 x_axis = ozz::math::simd_int4::x_axis();
|
||||
EXPECT_SIMDINT_EQ(x_axis, 1, 0, 0, 0);
|
||||
|
||||
const SimdInt4 y_axis = ozz::math::simd_int4::y_axis();
|
||||
EXPECT_SIMDINT_EQ(y_axis, 0, 1, 0, 0);
|
||||
|
||||
const SimdInt4 z_axis = ozz::math::simd_int4::z_axis();
|
||||
EXPECT_SIMDINT_EQ(z_axis, 0, 0, 1, 0);
|
||||
|
||||
const SimdInt4 w_axis = ozz::math::simd_int4::w_axis();
|
||||
EXPECT_SIMDINT_EQ(w_axis, 0, 0, 0, 1);
|
||||
|
||||
const SimdInt4 all_true = ozz::math::simd_int4::all_true();
|
||||
EXPECT_SIMDINT_EQ(all_true, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
const SimdInt4 all_false = ozz::math::simd_int4::all_false();
|
||||
EXPECT_SIMDINT_EQ(all_false, 0, 0, 0, 0);
|
||||
|
||||
const SimdInt4 mask_sign = ozz::math::simd_int4::mask_sign();
|
||||
EXPECT_SIMDINT_EQ(mask_sign, 0x80000000, 0x80000000, 0x80000000, 0x80000000);
|
||||
|
||||
const SimdInt4 mask_sign_xyz = ozz::math::simd_int4::mask_sign_xyz();
|
||||
EXPECT_SIMDINT_EQ(mask_sign_xyz, 0x80000000, 0x80000000, 0x80000000,
|
||||
0x00000000);
|
||||
|
||||
const SimdInt4 mask_sign_w = ozz::math::simd_int4::mask_sign_w();
|
||||
EXPECT_SIMDINT_EQ(mask_sign_w, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x80000000);
|
||||
|
||||
const SimdInt4 mask_not_sign = ozz::math::simd_int4::mask_not_sign();
|
||||
EXPECT_SIMDINT_EQ(mask_not_sign, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
0x7fffffff);
|
||||
|
||||
const SimdInt4 mask_ffff = ozz::math::simd_int4::mask_ffff();
|
||||
EXPECT_SIMDINT_EQ(mask_ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
const SimdInt4 mask_0000 = ozz::math::simd_int4::mask_0000();
|
||||
EXPECT_SIMDINT_EQ(mask_0000, 0, 0, 0, 0);
|
||||
|
||||
const SimdInt4 mask_fff0 = ozz::math::simd_int4::mask_fff0();
|
||||
EXPECT_SIMDINT_EQ(mask_fff0, 0xffffffff, 0xffffffff, 0xffffffff, 0);
|
||||
|
||||
const SimdInt4 mask_f000 = ozz::math::simd_int4::mask_f000();
|
||||
EXPECT_SIMDINT_EQ(mask_f000, 0xffffffff, 0, 0, 0);
|
||||
|
||||
const SimdInt4 mask_0f00 = ozz::math::simd_int4::mask_0f00();
|
||||
EXPECT_SIMDINT_EQ(mask_0f00, 0, 0xffffffff, 0, 0);
|
||||
|
||||
const SimdInt4 mask_00f0 = ozz::math::simd_int4::mask_00f0();
|
||||
EXPECT_SIMDINT_EQ(mask_00f0, 0, 0, 0xffffffff, 0);
|
||||
|
||||
const SimdInt4 mask_000f = ozz::math::simd_int4::mask_000f();
|
||||
EXPECT_SIMDINT_EQ(mask_000f, 0, 0, 0, 0xffffffff);
|
||||
}
|
||||
|
||||
TEST(SplatInt, ozz_simd_math) {
|
||||
const SimdInt4 i = ozz::math::simd_int4::Load(1, -1, 2, -3);
|
||||
|
||||
const SimdInt4 x = ozz::math::SplatX(i);
|
||||
EXPECT_SIMDINT_EQ(x, 1, 1, 1, 1);
|
||||
|
||||
const SimdInt4 y = ozz::math::SplatY(i);
|
||||
EXPECT_SIMDINT_EQ(y, -1, -1, -1, -1);
|
||||
|
||||
const SimdInt4 z = ozz::math::SplatZ(i);
|
||||
EXPECT_SIMDINT_EQ(z, 2, 2, 2, 2);
|
||||
|
||||
const SimdInt4 w = ozz::math::SplatW(i);
|
||||
EXPECT_SIMDINT_EQ(w, -3, -3, -3, -3);
|
||||
|
||||
const SimdInt4 s3210 = ozz::math::Swizzle<3, 2, 1, 0>(i);
|
||||
EXPECT_SIMDINT_EQ(s3210, -3, 2, -1, 1);
|
||||
|
||||
const SimdInt4 s0123 = ozz::math::Swizzle<0, 1, 2, 3>(i);
|
||||
EXPECT_SIMDINT_EQ(s0123, 1, -1, 2, -3);
|
||||
|
||||
const SimdInt4 s0011 = ozz::math::Swizzle<0, 0, 1, 1>(i);
|
||||
EXPECT_SIMDINT_EQ(s0011, 1, 1, -1, -1);
|
||||
|
||||
const SimdInt4 s2233 = ozz::math::Swizzle<2, 2, 3, 3>(i);
|
||||
EXPECT_SIMDINT_EQ(s2233, 2, 2, -3, -3);
|
||||
|
||||
const SimdInt4 s0101 = ozz::math::Swizzle<0, 1, 0, 1>(i);
|
||||
EXPECT_SIMDINT_EQ(s0101, 1, -1, 1, -1);
|
||||
|
||||
const SimdInt4 s2323 = ozz::math::Swizzle<2, 3, 2, 3>(i);
|
||||
EXPECT_SIMDINT_EQ(s2323, 2, -3, 2, -3);
|
||||
}
|
||||
|
||||
TEST(FromFloat, ozz_simd_math) {
|
||||
const ozz::math::SimdFloat4 f =
|
||||
ozz::math::simd_float4::Load(0.f, 46.93f, 46.26f, -93.99f);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::FromFloatRound(f), 0, 47, 46, -94);
|
||||
EXPECT_SIMDINT_EQ(ozz::math::simd_int4::FromFloatTrunc(f), 0, 46, 46, -93);
|
||||
}
|
||||
|
||||
TEST(ArithmeticInt, ozz_simd_math) {
|
||||
const SimdInt4 a = ozz::math::simd_int4::Load(0, 1, 2, 3);
|
||||
const SimdInt4 b = ozz::math::simd_int4::Load(4, 5, -6, 7);
|
||||
|
||||
const SimdInt4 hadd2 = ozz::math::HAdd2(a);
|
||||
EXPECT_SIMDINT_EQ(hadd2, 1, 1, 2, 3);
|
||||
|
||||
const SimdInt4 hadd3 = ozz::math::HAdd3(a);
|
||||
EXPECT_SIMDINT_EQ(hadd3, 3, 1, 2, 3);
|
||||
|
||||
const SimdInt4 hadd4 = ozz::math::HAdd4(a);
|
||||
EXPECT_SIMDINT_EQ(hadd4, 6, 1, 2, 3);
|
||||
|
||||
const SimdInt4 abs = ozz::math::Abs(b);
|
||||
EXPECT_SIMDINT_EQ(abs, 4, 5, 6, 7);
|
||||
|
||||
const SimdInt4 sign = ozz::math::Sign(b);
|
||||
EXPECT_SIMDINT_EQ(sign, 0, 0, 0x80000000, 0);
|
||||
}
|
||||
|
||||
TEST(CompareInt, ozz_simd_math) {
|
||||
const SimdInt4 a = ozz::math::simd_int4::Load(0, 1, 2, 3);
|
||||
const SimdInt4 b = ozz::math::simd_int4::Load(4, 1, -6, 7);
|
||||
const SimdInt4 c = ozz::math::simd_int4::Load(4, 5, 6, 7);
|
||||
|
||||
const SimdInt4 min = ozz::math::Min(a, b);
|
||||
EXPECT_SIMDINT_EQ(min, 0, 1, -6, 3);
|
||||
|
||||
const SimdInt4 max = ozz::math::Max(a, b);
|
||||
EXPECT_SIMDINT_EQ(max, 4, 1, 2, 7);
|
||||
|
||||
const SimdInt4 min0 = ozz::math::Min0(b);
|
||||
EXPECT_SIMDINT_EQ(min0, 0, 0, -6, 0);
|
||||
|
||||
const SimdInt4 max0 = ozz::math::Max0(b);
|
||||
EXPECT_SIMDINT_EQ(max0, 4, 1, 0, 7);
|
||||
|
||||
EXPECT_SIMDINT_EQ(
|
||||
ozz::math::Clamp(a, ozz::math::simd_int4::Load(-12, 2, 9, 3), c), 0, 2, 6,
|
||||
3);
|
||||
|
||||
const SimdInt4 eq1 = ozz::math::CmpEq(a, b);
|
||||
EXPECT_SIMDINT_EQ(eq1, 0, 0xffffffff, 0, 0);
|
||||
|
||||
const SimdInt4 eq2 = ozz::math::CmpEq(a, a);
|
||||
EXPECT_SIMDINT_EQ(eq2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
const SimdInt4 neq1 = ozz::math::CmpNe(a, b);
|
||||
EXPECT_SIMDINT_EQ(neq1, 0xffffffff, 0, 0xffffffff, 0xffffffff);
|
||||
|
||||
const SimdInt4 neq2 = ozz::math::CmpNe(a, a);
|
||||
EXPECT_SIMDINT_EQ(neq2, 0, 0, 0, 0);
|
||||
|
||||
const SimdInt4 lt = ozz::math::CmpLt(a, b);
|
||||
EXPECT_SIMDINT_EQ(lt, 0xffffffff, 0, 0, 0xffffffff);
|
||||
|
||||
const SimdInt4 le = ozz::math::CmpLe(a, b);
|
||||
EXPECT_SIMDINT_EQ(le, 0xffffffff, 0xffffffff, 0, 0xffffffff);
|
||||
|
||||
const SimdInt4 gt = ozz::math::CmpGt(a, b);
|
||||
EXPECT_SIMDINT_EQ(gt, 0, 0, 0xffffffff, 0);
|
||||
|
||||
const SimdInt4 ge = ozz::math::CmpGe(a, b);
|
||||
EXPECT_SIMDINT_EQ(ge, 0, 0xffffffff, 0xffffffff, 0);
|
||||
}
|
||||
|
||||
TEST(MaskInt, ozz_simd_math) {
|
||||
EXPECT_EQ(ozz::math::MoveMask(ozz::math::simd_int4::all_false()), 0x00000000);
|
||||
EXPECT_EQ(ozz::math::MoveMask(ozz::math::simd_int4::all_true()), 0x0000000f);
|
||||
EXPECT_EQ(ozz::math::MoveMask(ozz::math::simd_int4::mask_f000()), 0x00000001);
|
||||
EXPECT_EQ(ozz::math::MoveMask(ozz::math::simd_int4::mask_0f00()), 0x00000002);
|
||||
EXPECT_EQ(ozz::math::MoveMask(ozz::math::simd_int4::mask_00f0()), 0x00000004);
|
||||
EXPECT_EQ(ozz::math::MoveMask(ozz::math::simd_int4::mask_000f()), 0x00000008);
|
||||
EXPECT_EQ(ozz::math::MoveMask(ozz::math::simd_int4::Load(
|
||||
0xffffffff, 0x00000000, 0x80000001, 0x7fffffff)),
|
||||
0x00000005);
|
||||
EXPECT_EQ(ozz::math::MoveMask(ozz::math::simd_int4::Load(
|
||||
0xffffffff, 0x1000000f, 0x80000001, 0x8ffffffe)),
|
||||
0x0000000d);
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse(ozz::math::simd_int4::all_false()));
|
||||
EXPECT_FALSE(ozz::math::AreAllFalse(ozz::math::simd_int4::all_true()));
|
||||
EXPECT_FALSE(ozz::math::AreAllFalse(ozz::math::simd_int4::mask_000f()));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(ozz::math::simd_int4::all_true()));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue(ozz::math::simd_int4::all_false()));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue(ozz::math::simd_int4::mask_000f()));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse3(ozz::math::simd_int4::all_false()));
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse3(ozz::math::simd_int4::mask_000f()));
|
||||
EXPECT_FALSE(ozz::math::AreAllFalse3(ozz::math::simd_int4::all_true()));
|
||||
EXPECT_FALSE(ozz::math::AreAllFalse3(ozz::math::simd_int4::mask_f000()));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue3(ozz::math::simd_int4::all_true()));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue3(ozz::math::simd_int4::all_false()));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue3(ozz::math::simd_int4::mask_f000()));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse2(ozz::math::simd_int4::all_false()));
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse2(ozz::math::simd_int4::mask_000f()));
|
||||
EXPECT_FALSE(ozz::math::AreAllFalse2(ozz::math::simd_int4::all_true()));
|
||||
EXPECT_FALSE(ozz::math::AreAllFalse2(ozz::math::simd_int4::mask_f000()));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue2(ozz::math::simd_int4::all_true()));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue2(ozz::math::simd_int4::all_false()));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue2(ozz::math::simd_int4::mask_f000()));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse1(ozz::math::simd_int4::all_false()));
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse1(ozz::math::simd_int4::mask_000f()));
|
||||
EXPECT_FALSE(ozz::math::AreAllFalse1(ozz::math::simd_int4::all_true()));
|
||||
EXPECT_FALSE(ozz::math::AreAllFalse1(ozz::math::simd_int4::mask_f000()));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(ozz::math::simd_int4::all_true()));
|
||||
EXPECT_FALSE(ozz::math::AreAllTrue1(ozz::math::simd_int4::all_false()));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue1(ozz::math::simd_int4::mask_f000()));
|
||||
}
|
||||
|
||||
TEST(LogicalInt, ozz_simd_math) {
|
||||
const SimdInt4 a = ozz::math::simd_int4::Load(0xffffffff, 0x00000000,
|
||||
0x80000001, 0x7fffffff);
|
||||
const SimdInt4 b = ozz::math::simd_int4::Load(0x80000001, 0xffffffff,
|
||||
0x7fffffff, 0x00000000);
|
||||
const SimdInt4 c = ozz::math::simd_int4::Load(0x01234567, 0x89abcdef,
|
||||
0x01234567, 0x89abcdef);
|
||||
const SimdInt4 cond = ozz::math::simd_int4::Load(0xffffffff, 0x00000000,
|
||||
0xffffffff, 0x00000000);
|
||||
|
||||
const SimdInt4 andm = ozz::math::And(a, b);
|
||||
EXPECT_SIMDINT_EQ(andm, 0x80000001, 0x00000000, 0x00000001, 0x00000000);
|
||||
|
||||
const SimdInt4 andnm = ozz::math::AndNot(a, b);
|
||||
EXPECT_SIMDINT_EQ(andnm, 0x7ffffffe, 0x00000000, 0x80000000, 0x7fffffff);
|
||||
|
||||
const SimdInt4 orm = ozz::math::Or(a, b);
|
||||
EXPECT_SIMDINT_EQ(orm, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff);
|
||||
|
||||
const SimdInt4 xorm = ozz::math::Xor(a, b);
|
||||
EXPECT_SIMDINT_EQ(xorm, 0x7ffffffe, 0xffffffff, 0xfffffffe, 0x7fffffff);
|
||||
|
||||
const SimdInt4 select = ozz::math::Select(cond, b, c);
|
||||
EXPECT_SIMDINT_EQ(select, 0x80000001, 0x89abcdef, 0x7fffffff, 0x89abcdef);
|
||||
}
|
||||
|
||||
TEST(ShiftInt, ozz_simd_math) {
|
||||
const SimdInt4 a = ozz::math::simd_int4::Load(0xffffffff, 0x00000000,
|
||||
0x80000001, 0x7fffffff);
|
||||
|
||||
const SimdInt4 shift_l = ozz::math::ShiftL(a, 3);
|
||||
EXPECT_SIMDINT_EQ(shift_l, 0xfffffff8, 0x00000000, 0x00000008, 0xfffffff8);
|
||||
|
||||
const SimdInt4 shift_r = ozz::math::ShiftR(a, 3);
|
||||
EXPECT_SIMDINT_EQ(shift_r, 0xffffffff, 0x00000000, 0xf0000000, 0x0fffffff);
|
||||
|
||||
const SimdInt4 shift_ru = ozz::math::ShiftRu(a, 3);
|
||||
EXPECT_SIMDINT_EQ(shift_ru, 0x1fffffff, 0x00000000, 0x10000000, 0x0fffffff);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/simd_math_archive.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
|
||||
TEST(SimdMathArchive, ozz_simd_math) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Write soa math types.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
const ozz::math::SimdFloat4 of4 =
|
||||
ozz::math::simd_float4::Load(46.f, 58.f, 14.f, 5.f);
|
||||
o << of4;
|
||||
const ozz::math::SimdInt4 oi4 = ozz::math::simd_int4::Load(46, 58, 14, 5);
|
||||
o << oi4;
|
||||
const ozz::math::Float4x4 of44 = {
|
||||
{ozz::math::simd_float4::Load(46.f, 58.f, 14.f, 5.f),
|
||||
ozz::math::simd_float4::Load(26.f, 35.f, 1.f, 27.f),
|
||||
ozz::math::simd_float4::Load(99.f, 11.f, 4.f, 46.f),
|
||||
ozz::math::simd_float4::Load(58.f, 26.f, 14.f, 99.f)}};
|
||||
o << of44;
|
||||
|
||||
// Reads soa math types.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
ozz::math::SimdFloat4 if4;
|
||||
i >> if4;
|
||||
EXPECT_SIMDFLOAT_EQ(if4, 46.f, 58.f, 14.f, 5.f);
|
||||
ozz::math::SimdInt4 ii4;
|
||||
i >> ii4;
|
||||
EXPECT_SIMDINT_EQ(ii4, 46, 58, 14, 5);
|
||||
ozz::math::Float4x4 if44;
|
||||
i >> if44;
|
||||
EXPECT_FLOAT4x4_EQ(if44, 46.f, 58.f, 14.f, 5.f, 26.f, 35.f, 1.f, 27.f, 99.f,
|
||||
11.f, 4.f, 46.f, 58.f, 26.f, 14.f, 99.f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/simd_math.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::math::SimdFloat4;
|
||||
|
||||
TEST(TransposeFloat, ozz_simd_math) {
|
||||
const SimdFloat4 src[4] = {
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)};
|
||||
|
||||
SimdFloat4 t4x1[1];
|
||||
ozz::math::Transpose4x1(src, t4x1);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x1[0], 0.f, 4.f, 8.f, 12.f);
|
||||
|
||||
SimdFloat4 t1x4[4];
|
||||
ozz::math::Transpose1x4(src, t1x4);
|
||||
EXPECT_SIMDFLOAT_EQ(t1x4[0], 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t1x4[1], 1.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t1x4[2], 2.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t1x4[3], 3.f, 0.f, 0.f, 0.f);
|
||||
|
||||
SimdFloat4 t4x2[2];
|
||||
ozz::math::Transpose4x2(src, t4x2);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x2[0], 0.f, 4.f, 8.f, 12.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x2[1], 1.f, 5.f, 9.f, 13.f);
|
||||
|
||||
SimdFloat4 t2x4[4];
|
||||
ozz::math::Transpose2x4(src, t2x4);
|
||||
EXPECT_SIMDFLOAT_EQ(t2x4[0], 0.f, 4.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t2x4[1], 1.f, 5.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t2x4[2], 2.f, 6.f, 0.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t2x4[3], 3.f, 7.f, 0.f, 0.f);
|
||||
|
||||
SimdFloat4 t4x3[3];
|
||||
ozz::math::Transpose4x3(src, t4x3);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x3[0], 0.f, 4.f, 8.f, 12.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x3[1], 1.f, 5.f, 9.f, 13.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x3[2], 2.f, 6.f, 10.f, 14.f);
|
||||
|
||||
SimdFloat4 t3x4[4];
|
||||
ozz::math::Transpose3x4(src, t3x4);
|
||||
EXPECT_SIMDFLOAT_EQ(t3x4[0], 0.f, 4.f, 8.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t3x4[1], 1.f, 5.f, 9.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t3x4[2], 2.f, 6.f, 10.f, 0.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t3x4[3], 3.f, 7.f, 11.f, 0.f);
|
||||
|
||||
SimdFloat4 t4x4[4];
|
||||
ozz::math::Transpose4x4(src, t4x4);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x4[0], 0.f, 4.f, 8.f, 12.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x4[1], 1.f, 5.f, 9.f, 13.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x4[2], 2.f, 6.f, 10.f, 14.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t4x4[3], 3.f, 7.f, 11.f, 15.f);
|
||||
|
||||
const SimdFloat4 src2[16] = {
|
||||
ozz::math::simd_float4::Load(0.f, 16.f, 32.f, 48.f),
|
||||
ozz::math::simd_float4::Load(1.f, 17.f, 33.f, 49.f),
|
||||
ozz::math::simd_float4::Load(2.f, 18.f, 34.f, 50.f),
|
||||
ozz::math::simd_float4::Load(3.f, 19.f, 35.f, 51.f),
|
||||
ozz::math::simd_float4::Load(4.f, 20.f, 36.f, 52.f),
|
||||
ozz::math::simd_float4::Load(5.f, 21.f, 37.f, 53.f),
|
||||
ozz::math::simd_float4::Load(6.f, 22.f, 38.f, 54.f),
|
||||
ozz::math::simd_float4::Load(7.f, 23.f, 39.f, 55.f),
|
||||
ozz::math::simd_float4::Load(8.f, 24.f, 40.f, 56.f),
|
||||
ozz::math::simd_float4::Load(9.f, 25.f, 41.f, 57.f),
|
||||
ozz::math::simd_float4::Load(10.f, 26.f, 42.f, 58.f),
|
||||
ozz::math::simd_float4::Load(11.f, 27.f, 43.f, 59.f),
|
||||
ozz::math::simd_float4::Load(12.f, 28.f, 44.f, 60.f),
|
||||
ozz::math::simd_float4::Load(13.f, 29.f, 45.f, 61.f),
|
||||
ozz::math::simd_float4::Load(14.f, 30.f, 46.f, 62.f),
|
||||
ozz::math::simd_float4::Load(15.f, 31.f, 47.f, 63.f)};
|
||||
SimdFloat4 t16x16[16];
|
||||
ozz::math::Transpose16x16(src2, t16x16);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[0], 0.f, 1.f, 2.f, 3.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[1], 4.f, 5.f, 6.f, 7.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[2], 8.f, 9.f, 10.f, 11.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[3], 12.f, 13.f, 14.f, 15.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[4], 16.f, 17.f, 18.f, 19.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[5], 20.f, 21.f, 22.f, 23.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[6], 24.f, 25.f, 26.f, 27.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[7], 28.f, 29.f, 30.f, 31.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[8], 32.f, 33.f, 34.f, 35.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[9], 36.f, 37.f, 38.f, 39.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[10], 40.f, 41.f, 42.f, 43.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[11], 44.f, 45.f, 46.f, 47.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[12], 48.f, 49.f, 50.f, 51.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[13], 52.f, 53.f, 54.f, 55.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[14], 56.f, 57.f, 58.f, 59.f);
|
||||
EXPECT_SIMDFLOAT_EQ(t16x16[15], 60.f, 61.f, 62.f, 63.f);
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/simd_quaternion.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
#include "ozz/base/maths/math_constant.h"
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
|
||||
using ozz::math::SimdQuaternion;
|
||||
|
||||
TEST(QuaternionConstant, ozz_simd_math) {
|
||||
EXPECT_SIMDQUATERNION_EQ(SimdQuaternion::identity(), 0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(QuaternionArithmetic, ozz_simd_math) {
|
||||
const SimdQuaternion a = {
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, .70710677f)};
|
||||
const SimdQuaternion b = {
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 0.f, .70710677f)};
|
||||
const SimdQuaternion c = {
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 0.f, -.70710677f)};
|
||||
const SimdQuaternion denorm = {
|
||||
ozz::math::simd_float4::Load(1.414212f, 0.f, 0.f, 1.414212f)};
|
||||
const SimdQuaternion zero = {ozz::math::simd_float4::zero()};
|
||||
|
||||
EXPECT_SIMDINT_EQ(IsNormalized(a), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDINT_EQ(IsNormalized(b), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDINT_EQ(IsNormalized(c), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDINT_EQ(IsNormalized(denorm), 0, 0, 0, 0);
|
||||
|
||||
const SimdQuaternion conjugate = Conjugate(a);
|
||||
EXPECT_SIMDQUATERNION_EQ(conjugate, -.70710677f, 0.f, 0.f, .70710677f);
|
||||
|
||||
const SimdQuaternion negate = -a;
|
||||
EXPECT_SIMDQUATERNION_EQ(negate, -.70710677f, 0.f, 0.f, -.70710677f);
|
||||
|
||||
const SimdQuaternion mul0 = a * conjugate;
|
||||
EXPECT_SIMDQUATERNION_EQ(mul0, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
const SimdQuaternion mul1 = conjugate * a;
|
||||
EXPECT_SIMDQUATERNION_EQ(mul1, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
const SimdQuaternion q1234 = {
|
||||
ozz::math::simd_float4::Load(1.f, 2.f, 3.f, 4.f)};
|
||||
const SimdQuaternion q5678 = {
|
||||
ozz::math::simd_float4::Load(5.f, 6.f, 7.f, 8.f)};
|
||||
const SimdQuaternion mul12345678 = q1234 * q5678;
|
||||
EXPECT_SIMDQUATERNION_EQ(mul12345678, 24.f, 48.f, 48.f, -6.f);
|
||||
|
||||
EXPECT_ASSERTION(Normalize(zero), "is not normalizable");
|
||||
const SimdQuaternion norm = Normalize(denorm);
|
||||
EXPECT_SIMDINT_EQ(IsNormalized(norm), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(norm, .7071068f, 0.f, 0.f, .7071068f);
|
||||
|
||||
// EXPECT_ASSERTION(NormalizeSafe(denorm, zero), "_safer is not normalized");
|
||||
const SimdQuaternion norm_safe = NormalizeSafe(denorm, b);
|
||||
EXPECT_SIMDINT_EQ(IsNormalized(norm_safe), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(norm_safe, .7071068f, 0.f, 0.f, .7071068f);
|
||||
const SimdQuaternion norm_safer = NormalizeSafe(zero, b);
|
||||
EXPECT_SIMDINT_EQ(IsNormalized(norm_safer), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(norm_safer, 0.f, .70710677f, 0.f, .70710677f);
|
||||
|
||||
EXPECT_ASSERTION(NormalizeEst(zero), "is not normalizable");
|
||||
const SimdQuaternion norm_est = NormalizeEst(denorm);
|
||||
EXPECT_SIMDINT_EQ(IsNormalizedEst(norm_est), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ_EST(norm_est, .7071068f, 0.f, 0.f, .7071068f);
|
||||
|
||||
// EXPECT_ASSERTION(NormalizeSafe(denorm, zero), "_safer is not normalized");
|
||||
const SimdQuaternion norm_safe_est = NormalizeSafeEst(denorm, b);
|
||||
EXPECT_SIMDINT_EQ(IsNormalizedEst(norm_safe_est), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ_EST(norm_safe_est, .7071068f, 0.f, 0.f, .7071068f);
|
||||
const SimdQuaternion norm_safer_est = NormalizeSafeEst(zero, b);
|
||||
EXPECT_SIMDINT_EQ(IsNormalizedEst(norm_safer_est), 0xffffffff, 0, 0, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ_EST(norm_safer_est, 0.f, .70710677f, 0.f,
|
||||
.70710677f);
|
||||
}
|
||||
|
||||
TEST(QuaternionFromVectors, ozz_simd_math) {
|
||||
// Returns identity for a 0 length vector
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::zero(),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
// pi/2 around y
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
0.f, 0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// Non unit pi/2 around y
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::x_axis() *
|
||||
ozz::math::simd_float4::Load1(27.f)),
|
||||
0.f, 0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// Minus pi/2 around y
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::z_axis()),
|
||||
0.f, -0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// pi/2 around x
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::z_axis()),
|
||||
0.707106769f, 0.f, 0.f, 0.707106769f);
|
||||
|
||||
// pi/2 around z
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::y_axis()),
|
||||
0.f, 0.f, 0.707106769f, 0.707106769f);
|
||||
|
||||
// pi/2 around z also
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(
|
||||
ozz::math::simd_float4::Load(0.707106769f, 0.707106769f, 0.f, 99.f),
|
||||
ozz::math::simd_float4::Load(-0.707106769f, 0.707106769f, 0.f, 93.f)),
|
||||
0.f, 0.f, 0.707106769f, 0.707106769f);
|
||||
|
||||
// Non unit pi/2 around z also
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(
|
||||
ozz::math::simd_float4::Load(0.707106769f, 0.707106769f, 0.f, 99.f) *
|
||||
ozz::math::simd_float4::Load1(9.f),
|
||||
ozz::math::simd_float4::Load(-0.707106769f, 0.707106769f, 0.f, 93.f) *
|
||||
ozz::math::simd_float4::Load1(46.f)),
|
||||
0.f, 0.f, 0.707106769f, 0.707106769f);
|
||||
|
||||
// Non-unit pi/2 around z
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::y_axis() *
|
||||
ozz::math::simd_float4::Load1(2.f)),
|
||||
0.f, 0.f, 0.707106769f, 0.707106769f);
|
||||
|
||||
// Aligned vectors
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
// Non-unit aligned vectors
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::x_axis() *
|
||||
ozz::math::simd_float4::Load1(2.f)),
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
// Opposed vectors
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::x_axis(),
|
||||
-ozz::math::simd_float4::x_axis()),
|
||||
0.f, 1.f, 0.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(-ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
0.f, -1.f, 0.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::y_axis(),
|
||||
-ozz::math::simd_float4::y_axis()),
|
||||
0.f, 0.f, 1.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(-ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::y_axis()),
|
||||
0.f, 0.f, -1.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(ozz::math::simd_float4::z_axis(),
|
||||
-ozz::math::simd_float4::z_axis()),
|
||||
0.f, -1.f, 0.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(-ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::z_axis()),
|
||||
0.f, 1.f, 0.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(
|
||||
ozz::math::simd_float4::Load(0.707106769f, 0.707106769f, 0.f, 93.f),
|
||||
-ozz::math::simd_float4::Load(0.707106769f, 0.707106769f, 0.f, 99.f)),
|
||||
-0.707106769f, 0.707106769f, 0.f, 0.f);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(
|
||||
ozz::math::simd_float4::Load(0.f, 0.707106769f, 0.707106769f, 93.f),
|
||||
-ozz::math::simd_float4::Load(0.f, 0.707106769f, 0.707106769f, 99.f)),
|
||||
0.f, -0.707106769f, 0.707106769f, 0.f);
|
||||
|
||||
// Non-unit opposed vectors
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromVectors(
|
||||
ozz::math::simd_float4::Load(2.f, 2.f, 2.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-2.f, -2.f, -2.f, 0.f)),
|
||||
0.f, -0.707106769f, 0.707106769f, 0);
|
||||
}
|
||||
|
||||
TEST(QuaternionFromUnitVectors, ozz_simd_math) {
|
||||
// assert 0 length vectors
|
||||
EXPECT_ASSERTION(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::zero(),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
"Input vectors must be normalized.");
|
||||
EXPECT_ASSERTION(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::zero()),
|
||||
"Input vectors must be normalized.");
|
||||
// assert non unit vectors
|
||||
EXPECT_ASSERTION(
|
||||
SimdQuaternion::FromUnitVectors(
|
||||
ozz::math::simd_float4::x_axis() * ozz::math::simd_float4::Load1(2.f),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
"Input vectors must be normalized.");
|
||||
EXPECT_ASSERTION(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::x_axis() *
|
||||
ozz::math::simd_float4::Load1(.5f)),
|
||||
"Input vectors must be normalized.");
|
||||
|
||||
// pi/2 around y
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
0.f, 0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// Minus pi/2 around y
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::z_axis()),
|
||||
0.f, -0.707106769f, 0.f, 0.707106769f);
|
||||
|
||||
// pi/2 around x
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::z_axis()),
|
||||
0.707106769f, 0.f, 0.f, 0.707106769f);
|
||||
|
||||
// pi/2 around z
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::y_axis()),
|
||||
0.f, 0.f, 0.707106769f, 0.707106769f);
|
||||
|
||||
// pi/2 around z also
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(
|
||||
ozz::math::simd_float4::Load(0.707106769f, 0.707106769f, 0.f, 99.f),
|
||||
ozz::math::simd_float4::Load(-0.707106769f, 0.707106769f, 0.f, 93.f)),
|
||||
0.f, 0.f, 0.707106769f, 0.707106769f);
|
||||
|
||||
// Aligned vectors
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
// Opposed vectors
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::x_axis(),
|
||||
-ozz::math::simd_float4::x_axis()),
|
||||
0.f, 1.f, 0.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(-ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
0.f, -1.f, 0.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::y_axis(),
|
||||
-ozz::math::simd_float4::y_axis()),
|
||||
0.f, 0.f, 1.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(-ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::y_axis()),
|
||||
0.f, 0.f, -1.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(ozz::math::simd_float4::z_axis(),
|
||||
-ozz::math::simd_float4::z_axis()),
|
||||
0.f, -1.f, 0.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(-ozz::math::simd_float4::z_axis(),
|
||||
ozz::math::simd_float4::z_axis()),
|
||||
0.f, 1.f, 0.f, 0);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(
|
||||
ozz::math::simd_float4::Load(0.707106769f, 0.707106769f, 0.f, 93.f),
|
||||
-ozz::math::simd_float4::Load(0.707106769f, 0.707106769f, 0.f, 99.f)),
|
||||
-0.707106769f, 0.707106769f, 0.f, 0.f);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromUnitVectors(
|
||||
ozz::math::simd_float4::Load(0.f, 0.707106769f, 0.707106769f, 93.f),
|
||||
-ozz::math::simd_float4::Load(0.f, 0.707106769f, 0.707106769f, 99.f)),
|
||||
0.f, -0.707106769f, 0.707106769f, 0.f);
|
||||
}
|
||||
|
||||
TEST(QuaternionAxisAngle, ozz_simd_math) {
|
||||
// Expect assertions from invalid inputs
|
||||
EXPECT_ASSERTION(
|
||||
SimdQuaternion::FromAxisAngle(ozz::math::simd_float4::zero(),
|
||||
ozz::math::simd_float4::zero()),
|
||||
"axis is not normalized.");
|
||||
#ifndef NDEBUG
|
||||
const SimdQuaternion unorm = {
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 2.f)};
|
||||
#endif // NDEBUG
|
||||
EXPECT_ASSERTION(ToAxisAngle(unorm), "_q is not normalized.");
|
||||
|
||||
// Identity
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromAxisAngle(ozz::math::simd_float4::x_axis(),
|
||||
ozz::math::simd_float4::zero()),
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_SIMDFLOAT_EQ(ToAxisAngle(SimdQuaternion::identity()), 1.f, 0.f, 0.f,
|
||||
0.f);
|
||||
|
||||
// Other axis angles
|
||||
const ozz::math::SimdFloat4 pi_2 =
|
||||
ozz::math::simd_float4::LoadX(ozz::math::kPi_2);
|
||||
const SimdQuaternion qy_pi_2 =
|
||||
SimdQuaternion::FromAxisAngle(ozz::math::simd_float4::y_axis(), pi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ(qy_pi_2, 0.f, .70710677f, 0.f, .70710677f);
|
||||
EXPECT_SIMDFLOAT_EQ(ToAxisAngle(qy_pi_2), 0.f, 1.f, 0.f, ozz::math::kPi_2);
|
||||
|
||||
const SimdQuaternion qy_mpi_2 =
|
||||
SimdQuaternion::FromAxisAngle(ozz::math::simd_float4::y_axis(), -pi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ(qy_mpi_2, 0.f, -.70710677f, 0.f, .70710677f);
|
||||
EXPECT_SIMDFLOAT_EQ(ToAxisAngle(qy_mpi_2), 0.f, -1.f, 0.f,
|
||||
ozz::math::kPi_2); // q = -q
|
||||
const SimdQuaternion qmy_pi_2 =
|
||||
SimdQuaternion::FromAxisAngle(-ozz::math::simd_float4::y_axis(), pi_2);
|
||||
EXPECT_SIMDQUATERNION_EQ(qmy_pi_2, 0.f, -.70710677f, 0.f, .70710677f);
|
||||
|
||||
const ozz::math::SimdFloat4 any_axis =
|
||||
ozz::math::simd_float4::Load(.819865f, .033034f, -.571604f, 99.f);
|
||||
const ozz::math::SimdFloat4 any_angle =
|
||||
ozz::math::simd_float4::Load(1.123f, 99.f, 26.f, 93.f);
|
||||
const SimdQuaternion qany =
|
||||
SimdQuaternion::FromAxisAngle(any_axis, any_angle);
|
||||
EXPECT_SIMDQUATERNION_EQ(qany, .4365425f, .017589169f, -.30435428f,
|
||||
.84645736f);
|
||||
EXPECT_SIMDFLOAT_EQ(ToAxisAngle(qany), .819865f, .033034f, -.571604f, 1.123f);
|
||||
}
|
||||
|
||||
TEST(QuaternionAxisCosAngle, ozz_simd_math) {
|
||||
// Expect assertions from invalid inputs
|
||||
EXPECT_ASSERTION(
|
||||
SimdQuaternion::FromAxisCosAngle(ozz::math::simd_float4::zero(),
|
||||
ozz::math::simd_float4::Load1(0.f)),
|
||||
"axis is not normalized");
|
||||
EXPECT_ASSERTION(SimdQuaternion::FromAxisCosAngle(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::Load1(-1.0000001f)),
|
||||
"cos is not in \\[-1,1\\] range.");
|
||||
EXPECT_ASSERTION(SimdQuaternion::FromAxisCosAngle(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::Load1(1.0000001f)),
|
||||
"cos is not in \\[-1,1\\] range.");
|
||||
|
||||
// Identity
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromAxisCosAngle(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::Load(1.f, 99.f, 93.f, 5.f)),
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
// Other axis angles
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromAxisCosAngle(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::Load(std::cos(ozz::math::kPi_2), 99.f, 93.f,
|
||||
5.f)),
|
||||
0.f, .70710677f, 0.f, .70710677f);
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromAxisCosAngle(
|
||||
-ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::Load(std::cos(ozz::math::kPi_2), 99.f, 93.f,
|
||||
5.f)),
|
||||
0.f, -.70710677f, 0.f, .70710677f);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromAxisCosAngle(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::Load(std::cos(3.f * ozz::math::kPi_4), 99.f,
|
||||
93.f, 5.f)),
|
||||
0.f, 0.923879504f, 0.f, 0.382683426f);
|
||||
|
||||
EXPECT_SIMDQUATERNION_EQ(
|
||||
SimdQuaternion::FromAxisCosAngle(
|
||||
ozz::math::simd_float4::Load(.819865f, .033034f, -.571604f, 99.f),
|
||||
ozz::math::simd_float4::Load(std::cos(1.123f), 99.f, 93.f, 5.f)),
|
||||
.4365425f, .017589169f, -.30435428f, .84645736f);
|
||||
}
|
||||
|
||||
TEST(QuaternionTransformVector, ozz_simd_math) {
|
||||
// 0 length
|
||||
EXPECT_SIMDFLOAT3_EQ(TransformVector(SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::zero()),
|
||||
ozz::math::simd_float4::zero()),
|
||||
0, 0, 0);
|
||||
|
||||
// Unit length
|
||||
EXPECT_SIMDFLOAT3_EQ(TransformVector(SimdQuaternion::FromAxisAngle(
|
||||
ozz::math::simd_float4::y_axis(),
|
||||
ozz::math::simd_float4::zero()),
|
||||
ozz::math::simd_float4::z_axis()),
|
||||
0, 0, 1);
|
||||
|
||||
const ozz::math::SimdFloat4 pi_2 =
|
||||
ozz::math::simd_float4::LoadX(ozz::math::kPi_2);
|
||||
EXPECT_SIMDFLOAT3_EQ(
|
||||
TransformVector(
|
||||
SimdQuaternion::FromAxisAngle(ozz::math::simd_float4::y_axis(), pi_2),
|
||||
ozz::math::simd_float4::y_axis()),
|
||||
0, 1, 0);
|
||||
EXPECT_SIMDFLOAT3_EQ(
|
||||
TransformVector(
|
||||
SimdQuaternion::FromAxisAngle(ozz::math::simd_float4::y_axis(), pi_2),
|
||||
ozz::math::simd_float4::x_axis()),
|
||||
0, 0, -1);
|
||||
EXPECT_SIMDFLOAT3_EQ(
|
||||
TransformVector(
|
||||
SimdQuaternion::FromAxisAngle(ozz::math::simd_float4::y_axis(), pi_2),
|
||||
ozz::math::simd_float4::z_axis()),
|
||||
1, 0, 0);
|
||||
|
||||
// Non unit
|
||||
EXPECT_SIMDFLOAT3_EQ(
|
||||
TransformVector(
|
||||
SimdQuaternion::FromAxisAngle(ozz::math::simd_float4::z_axis(), pi_2),
|
||||
ozz::math::simd_float4::x_axis() *
|
||||
ozz::math::simd_float4::Load1(2.f)),
|
||||
0, 2, 0);
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/soa_float4x4.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::math::SoaFloat3;
|
||||
using ozz::math::SoaFloat4;
|
||||
using ozz::math::SoaFloat4x4;
|
||||
using ozz::math::SoaQuaternion;
|
||||
|
||||
TEST(SoaFloat4x4Constant, ozz_soa_math) {
|
||||
const SoaFloat4x4 identity = SoaFloat4x4::identity();
|
||||
EXPECT_SOAFLOAT4x4_EQ(identity, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f,
|
||||
1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloat4x4Arithmetic, ozz_soa_math) {
|
||||
const SoaFloat4x4 m0 = {
|
||||
{{ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(2.f, 0.f, 0.f, -1.f),
|
||||
ozz::math::simd_float4::Load(3.f, 0.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(4.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(5.f, 1.f, 0.f, 1.f),
|
||||
ozz::math::simd_float4::Load(6.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(7.f, 0.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(8.f, 0.f, 0.f, 1.f),
|
||||
ozz::math::simd_float4::Load(9.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(10.f, 1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(11.f, 0.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(12.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(13.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(14.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(15.f, 1.f, 0.f, 1.f)}}};
|
||||
const SoaFloat4x4 m1 = {
|
||||
{{ozz::math::simd_float4::Load(-0.f, 0.f, 0.f, 1.f),
|
||||
ozz::math::simd_float4::Load(-1.f, -1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-2.f, 2.f, -1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-3.f, 3.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(-4.f, -4.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-5.f, 5.f, 1.f, 1.f),
|
||||
ozz::math::simd_float4::Load(-6.f, 6.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-7.f, -7.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(-8.f, 8.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-9.f, -9.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-10.f, -10.f, 0.f, 1.f),
|
||||
ozz::math::simd_float4::Load(-11.f, 11.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(-12.f, -12.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-13.f, 13.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-14.f, -14.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-15.f, 15.f, 1.f, 1.f)}}};
|
||||
const SoaFloat4x4 m2 = {
|
||||
{{ozz::math::simd_float4::Load(2.f, 0.f, 0.f, 1.f),
|
||||
ozz::math::simd_float4::Load(0.f, -1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 2.f, -1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 3.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(0.f, -4.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 5.f, 1.f, 1.f),
|
||||
ozz::math::simd_float4::Load(-2.f, 6.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, -7.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(0.f, 8.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(3.f, -9.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, -10.f, 0.f, 1.f),
|
||||
ozz::math::simd_float4::Load(0.f, 11.f, 0.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(0.f, -12.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(46.f, 13.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(12.f, -14.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 15.f, 1.f, 1.f)}}};
|
||||
const SoaFloat4 v = {ozz::math::simd_float4::Load(0.f, 1.f, -2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(-1.f, 2.f, 5.f, 46.f),
|
||||
ozz::math::simd_float4::Load(-2.f, 3.f, 7.f, -1.f),
|
||||
ozz::math::simd_float4::Load(-3.f, 4.f, 0.f, 1.f)};
|
||||
const SoaFloat4 mul_vector = m0 * v;
|
||||
EXPECT_SOAFLOAT4_EQ(mul_vector, -56.f, 1.f, 0.f, -1.f, -62.f, 2.f, 0.f, 46,
|
||||
-68.f, 3.f, 0.f, -3.f, -74.f, 4.f, 0.f, 1.f);
|
||||
|
||||
const SoaFloat4x4 mul_mat = m0 * m1;
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
mul_mat, -56.f, 0.f, 0.f, 0.f, -62.f, -1.f, 0.f, 0.f, -68.f, 2.f, 0.f,
|
||||
-1.f, -74.f, 3.f, 0.f, 0.f, -152.f, -4.f, 0.f, 0.f, -174.f, 5.f, 0.f, 1.f,
|
||||
-196.f, 6.f, 0.f, 0.f, -218.f, -7.f, 0.f, 0.f, -248.f, 8.f, 0.f, 1.f,
|
||||
-286.f, -9.f, 0.f, 0.f, -324.f, -10.f, 0.f, 0.f, -362.f, 11.f, 0.f, 0.f,
|
||||
-344.f, -12.f, 0.f, 0.f, -398.f, 13.f, 0.f, 0.f, -452.f, -14.f, 0.f, 0.f,
|
||||
-506.f, 15.f, 0.f, 1.f);
|
||||
|
||||
const SoaFloat4x4 add_mat = m0 + m1;
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
add_mat, 0.f, 1.f, 0.f, 1.f, 0.f, -1.f, 0.f, 0.f, 0.f, 2.f, -1.f, -1.f,
|
||||
0.f, 3.f, 0.f, 0.f, 0.f, -4.f, 0.f, 0.f, 0.f, 6.f, 1.f, 2.f, 0.f, 6.f,
|
||||
0.f, 0.f, 0.f, -7.f, 0.f, 0.f, 0.f, 8.f, 1.f, 1.f, 0.f, -9.f, 0.f, 0.f,
|
||||
0.f, -9.f, 0.f, 1.f, 0.f, 11.f, 0.f, 0.f, 0.f, -12.f, 0.f, 0.f, 0.f, 13.f,
|
||||
0.f, 0.f, 0.f, -14.f, 0.f, 0.f, 0.f, 16.f, 1.f, 2.f);
|
||||
|
||||
const SoaFloat4x4 sub_mat = m0 - m1;
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
sub_mat, 0.f, 1.f, 0.f, -1.f, 2.f, 1.f, 0.f, 0.f, 4.f, -2.f, 1.f, -1.f,
|
||||
6.f, -3.f, 0.f, 0.f, 8.f, 4.f, 0.f, 0.f, 10.f, -4.f, -1.f, 0.f, 12.f,
|
||||
-6.f, 0.f, 0.f, 14.f, 7.f, 0.f, 0.f, 16.f, -8.f, -1.f, 1.f, 18.f, 9.f,
|
||||
0.f, 0.f, 20.f, 11.f, 0.f, -1.f, 22.f, -11.f, 0.f, 0.f, 24.f, 12.f, 0.f,
|
||||
0.f, 26.f, -13.f, 0.f, 0.f, 28.f, 14.f, 0.f, 0.f, 30.f, -14.f, -1.f, 0.f);
|
||||
|
||||
const SoaFloat4x4 transpose = Transpose(m0);
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
transpose, 0.f, 1.f, 0.f, 0.f, 4.f, 0.f, 0.f, 0.f, 8.f, 0.f, 0.f, 1.f,
|
||||
12.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 5.f, 1.f, 0.f, 1.f, 9.f, 0.f,
|
||||
0.f, 0.f, 13.f, 0.f, 0.f, 0.f, 2.f, 0.f, 0.f, -1.f, 6.f, 0.f, 0.f, 0.f,
|
||||
10.f, 1.f, 0.f, 0.f, 14.f, 0.f, 0.f, 0.f, 3.f, 0.f, 0.f, 0.f, 7.f, 0.f,
|
||||
0.f, 0.f, 11.f, 0.f, 0.f, 0.f, 15.f, 1.f, 0.f, 1.f);
|
||||
|
||||
const SoaFloat4x4 invert_ident = Invert(SoaFloat4x4::identity());
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
invert_ident, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f,
|
||||
1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
const SoaFloat4x4 invert = Invert(m2);
|
||||
EXPECT_SOAFLOAT4x4_EQ(invert, .5f, .216667f, 0.f, 1.f, 0.f, 2.75f, 0.f, 0.f,
|
||||
0.f, 1.6f, 1.f, 0.f, 0.f, .066666f, 0.f, 0.f, 0.f, .2f,
|
||||
0.f, 0.f, 0.f, 2.5f, 1.f, 1.f, .333333f, 1.4f, 0.f, 0.f,
|
||||
0.f, .1f, 0.f, 0.f, 0.f, .25f, -1.f, 0.f, -.5f, .5f,
|
||||
0.f, 0.f, 0.f, .25f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
.233333f, 0.f, 0.f, 6.f, .5f, 0.f, 0.f, -15.33333f, .3f,
|
||||
0.f, 0.f, 1.f, .03333f, 1.f, 1.f);
|
||||
|
||||
const SoaFloat4x4 invert_mul = m2 * invert;
|
||||
EXPECT_SOAFLOAT4x4_EQ(invert_mul, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f,
|
||||
1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// EXPECT_ASSERTION(Invert(m0), "Matrix is not invertible");
|
||||
|
||||
// Invertible
|
||||
ozz::math::SimdInt4 invertible;
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
Invert(m2, &invertible), .5f, .216667f, 0.f, 1.f, 0.f, 2.75f, 0.f, 0.f,
|
||||
0.f, 1.6f, 1.f, 0.f, 0.f, .066666f, 0.f, 0.f, 0.f, .2f, 0.f, 0.f, 0.f,
|
||||
2.5f, 1.f, 1.f, .333333f, 1.4f, 0.f, 0.f, 0.f, .1f, 0.f, 0.f, 0.f, .25f,
|
||||
-1.f, 0.f, -.5f, .5f, 0.f, 0.f, 0.f, .25f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, .233333f, 0.f, 0.f, 6.f, .5f, 0.f, 0.f, -15.33333f, .3f, 0.f, 0.f,
|
||||
1.f, .03333f, 1.f, 1.f);
|
||||
EXPECT_SIMDINT_EQ(invertible, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
// Non invertible
|
||||
EXPECT_ASSERTION(Invert(m0), "Matrix is not invertible");
|
||||
|
||||
ozz::math::SimdInt4 not_invertible;
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
Invert(m0, ¬_invertible), 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f);
|
||||
EXPECT_SIMDINT_EQ(not_invertible, 0, 0xffffffff, 0, 0xffffffff);
|
||||
}
|
||||
|
||||
TEST(SoaFloat4x4Scale, ozz_soa_math) {
|
||||
const SoaFloat4x4 m0 = {
|
||||
{{ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, -1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(2.f, 0.f, 2.f, -1.f),
|
||||
ozz::math::simd_float4::Load(3.f, 0.f, 3.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(4.f, 0.f, -4.f, 0.f),
|
||||
ozz::math::simd_float4::Load(5.f, 1.f, 5.f, 1.f),
|
||||
ozz::math::simd_float4::Load(6.f, 0.f, 6.f, 0.f),
|
||||
ozz::math::simd_float4::Load(7.f, 0.f, -7.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(8.f, 0.f, 8.f, 1.f),
|
||||
ozz::math::simd_float4::Load(9.f, 0.f, -9.f, 0.f),
|
||||
ozz::math::simd_float4::Load(10.f, 1.f, -10.f, 0.f),
|
||||
ozz::math::simd_float4::Load(11.f, 0.f, 11.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(12.f, 0.f, -12.f, 0.f),
|
||||
ozz::math::simd_float4::Load(13.f, 0.f, 13.f, 0.f),
|
||||
ozz::math::simd_float4::Load(14.f, 0.f, -14.f, 0.f),
|
||||
ozz::math::simd_float4::Load(15.f, 1.f, 15.f, 1.f)}}};
|
||||
const SoaFloat4 v = {ozz::math::simd_float4::Load(0.f, 1.f, -2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(-1.f, 2.f, 5.f, 46.f),
|
||||
ozz::math::simd_float4::Load(-2.f, 3.f, 7.f, -1.f),
|
||||
ozz::math::simd_float4::Load(-3.f, 4.f, 0.f, 1.f)};
|
||||
|
||||
const SoaFloat4x4 scaling = SoaFloat4x4::Scaling(v);
|
||||
EXPECT_SOAFLOAT4x4_EQ(scaling, 0.f, 1.f, -2.f, 3.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
-1.f, 2.f, 5.f, 46.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -2.f, 3.f,
|
||||
7.f, -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
const SoaFloat4x4 scale_mul = m0 * scaling;
|
||||
EXPECT_SOAFLOAT4x4_EQ(scale_mul, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 2.f, 0.f, 0.f,
|
||||
0.f, -4.f, -3.f, 0.f, 0.f, -6.f, 0.f, -4.f, 0.f, -20.f,
|
||||
0.f, -5.f, 2.f, 25.f, 46.f, -6.f, 0.f, 30.f, 0.f, -7.f,
|
||||
0.f, -35.f, 0.f, -16.f, 0.f, 56.f, -1.f, -18.f, 0.f,
|
||||
-63.f, 0.f, -20.f, 3.f, -70.f, 0.f, -22.f, 0.f, 77.f,
|
||||
0.f, 12.f, 0.f, -12.f, 0.f, 13.f, 0.f, 13.f, 0.f, 14.f,
|
||||
0.f, -14.f, 0.f, 15.f, 1.f, 15.f, 1.f);
|
||||
|
||||
const SoaFloat4x4 scale = Scale(m0, v);
|
||||
EXPECT_SOAFLOAT4x4_EQ(scale, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 2.f, 0.f, 0.f, 0.f,
|
||||
-4.f, -3.f, 0.f, 0.f, -6.f, 0.f, -4.f, 0.f, -20.f, 0.f,
|
||||
-5.f, 2.f, 25.f, 46.f, -6.f, 0.f, 30.f, 0.f, -7.f, 0.f,
|
||||
-35.f, 0.f, -16.f, 0.f, 56.f, -1.f, -18.f, 0.f, -63.f,
|
||||
0.f, -20.f, 3.f, -70.f, 0.f, -22.f, 0.f, 77.f, 0.f,
|
||||
12.f, 0.f, -12.f, 0.f, 13.f, 0.f, 13.f, 0.f, 14.f, 0.f,
|
||||
-14.f, 0.f, 15.f, 1.f, 15.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloat4x4Rotate, ozz_soa_math) {
|
||||
#ifndef NDEBUG
|
||||
const SoaQuaternion unormalized =
|
||||
SoaQuaternion::Load(ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 1.f, 1.f, 1.f));
|
||||
#endif // NDEBUG
|
||||
EXPECT_ASSERTION(SoaFloat4x4::FromQuaternion(unormalized), "IsNormalized");
|
||||
|
||||
const SoaFloat4x4 identity =
|
||||
SoaFloat4x4::FromQuaternion(SoaQuaternion::identity());
|
||||
EXPECT_SOAFLOAT4x4_EQ(identity, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f,
|
||||
1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
const SoaQuaternion quaternion = SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, -.382683432f),
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 1.f, .9238795f));
|
||||
const SoaFloat4x4 matrix = SoaFloat4x4::FromQuaternion(quaternion);
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
matrix, 0.f, 0.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f, -1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.f, 1.f, 1.f, .707106f, 0.f, 0.f,
|
||||
0.f, -.707106f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
.707106f, 0.f, 0.f, 1.f, .707106f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloat4x4Affine, ozz_soa_math) {
|
||||
const SoaFloat4x4 identity = SoaFloat4x4::FromAffine(
|
||||
SoaFloat3::zero(), SoaQuaternion::identity(), SoaFloat3::one());
|
||||
EXPECT_SOAFLOAT4x4_EQ(identity, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f,
|
||||
1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
const SoaFloat3 translation =
|
||||
SoaFloat3::Load(ozz::math::simd_float4::Load(0.f, 46.f, 7.f, -12.f),
|
||||
ozz::math::simd_float4::Load(0.f, 12.f, 7.f, -46.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 7.f, 46.f));
|
||||
const SoaFloat3 scale =
|
||||
SoaFloat3::Load(ozz::math::simd_float4::Load(1.f, 1.f, -1.f, 0.1f),
|
||||
ozz::math::simd_float4::Load(1.f, 2.f, -1.f, 0.1f),
|
||||
ozz::math::simd_float4::Load(1.f, 3.f, -1.f, 0.1f));
|
||||
const SoaQuaternion quaternion = SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, -.382683432f),
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 1.f, .9238795f));
|
||||
const SoaFloat4x4 matrix =
|
||||
SoaFloat4x4::FromAffine(translation, quaternion, scale);
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
matrix, 0.f, 0.f, -1.f, .1f, 0.f, 0.f, 0.f, 0.f, 1.f, -1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.f, 2.f, -1.f, .0707106f, 0.f, 0.f,
|
||||
0.f, -.0707106f, 0.f, 0.f, 0.f, 0.f, 1.f, 3.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
.0707106f, 0.f, 0.f, -1.f, .0707106f, 0.f, 0.f, 0.f, 0.f, 0.f, 46.f, 7.f,
|
||||
-12.f, 0.f, 12.f, 7.f, -46.f, 0.f, 0.f, 7.f, 46.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
@@ -0,0 +1,515 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/soa_float.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::math::SimdFloat4;
|
||||
using ozz::math::SoaFloat2;
|
||||
using ozz::math::SoaFloat3;
|
||||
using ozz::math::SoaFloat4;
|
||||
|
||||
TEST(SoaFloatLoad4, ozz_soa_math) {
|
||||
EXPECT_SOAFLOAT4_EQ(
|
||||
SoaFloat4::Load(ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)),
|
||||
0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f,
|
||||
14.f, 15.f);
|
||||
EXPECT_SOAFLOAT4_EQ(
|
||||
SoaFloat4::Load(
|
||||
SoaFloat3::Load(ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f)),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)),
|
||||
0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f,
|
||||
14.f, 15.f);
|
||||
EXPECT_SOAFLOAT4_EQ(
|
||||
SoaFloat4::Load(
|
||||
SoaFloat2::Load(ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f)),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)),
|
||||
0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f,
|
||||
14.f, 15.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatLoad3, ozz_soa_math) {
|
||||
EXPECT_SOAFLOAT3_EQ(
|
||||
SoaFloat3::Load(ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f)),
|
||||
0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f);
|
||||
EXPECT_SOAFLOAT3_EQ(
|
||||
SoaFloat3::Load(
|
||||
SoaFloat2::Load(ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f)),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f)),
|
||||
0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatLoad2, ozz_soa_math) {
|
||||
EXPECT_SOAFLOAT2_EQ(
|
||||
SoaFloat2::Load(ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f)),
|
||||
0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatConstant4, ozz_soa_math) {
|
||||
EXPECT_SOAFLOAT4_EQ(SoaFloat4::zero(), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT4_EQ(SoaFloat4::one(), 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT4_EQ(SoaFloat4::x_axis(), 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT4_EQ(SoaFloat4::y_axis(), 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f,
|
||||
1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT4_EQ(SoaFloat4::z_axis(), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT4_EQ(SoaFloat4::w_axis(), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatConstant3, ozz_soa_math) {
|
||||
EXPECT_SOAFLOAT3_EQ(SoaFloat3::zero(), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT3_EQ(SoaFloat3::one(), 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(SoaFloat3::x_axis(), 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT3_EQ(SoaFloat3::y_axis(), 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f,
|
||||
1.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAFLOAT3_EQ(SoaFloat3::z_axis(), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatConstant2, ozz_soa_math) {
|
||||
EXPECT_SOAFLOAT2_EQ(SoaFloat2::zero(), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f);
|
||||
EXPECT_SOAFLOAT2_EQ(SoaFloat2::one(), 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_SOAFLOAT2_EQ(SoaFloat2::x_axis(), 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f,
|
||||
0.f);
|
||||
EXPECT_SOAFLOAT2_EQ(SoaFloat2::y_axis(), 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f,
|
||||
1.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatArithmetic4, ozz_soa_math) {
|
||||
const SoaFloat4 a = {ozz::math::simd_float4::Load(.5f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f)};
|
||||
const SoaFloat4 b = {
|
||||
ozz::math::simd_float4::Load(-.5f, -1.f, -2.f, -3.f),
|
||||
ozz::math::simd_float4::Load(-4.f, -5.f, -6.f, -7.f),
|
||||
ozz::math::simd_float4::Load(-8.f, -9.f, -10.f, -11.f),
|
||||
ozz::math::simd_float4::Load(-12.f, -13.f, -14.f, -15.f)};
|
||||
const SoaFloat4 c = {ozz::math::simd_float4::Load(.05f, .1f, .2f, .3f),
|
||||
ozz::math::simd_float4::Load(.4f, .5f, .6f, .7f),
|
||||
ozz::math::simd_float4::Load(.8f, .9f, 1.f, 1.1f),
|
||||
ozz::math::simd_float4::Load(1.2f, 1.3f, 1.4f, 1.5f)};
|
||||
|
||||
const SoaFloat4 add = a + b;
|
||||
EXPECT_SOAFLOAT4_EQ(add, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SoaFloat4 sub = a - b;
|
||||
EXPECT_SOAFLOAT4_EQ(sub, 1.f, 2.f, 4.f, 6.f, 8.f, 10.f, 12.f, 14.f, 16.f,
|
||||
18.f, 20.f, 22.f, 24.f, 26.f, 28.f, 30.f);
|
||||
|
||||
const SoaFloat4 neg = -a;
|
||||
EXPECT_SOAFLOAT4_EQ(neg, -.5f, -1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f, -8.f,
|
||||
-9.f, -10.f, -11.f, -12.f, -13.f, -14.f, -15.f);
|
||||
|
||||
const SoaFloat4 mul = a * b;
|
||||
EXPECT_SOAFLOAT4_EQ(mul, -0.25f, -1.f, -4.f, -9.f, -16.f, -25.f, -36.f, -49.f,
|
||||
-64.f, -81.f, -100.f, -121.f, -144.f, -169.f, -196.f,
|
||||
-225.f);
|
||||
|
||||
const SoaFloat4 mul_add = MAdd(a, b, c);
|
||||
EXPECT_SOAFLOAT4_EQ(mul_add, -0.2f, -.9f, -3.8f, -8.7f, -15.6f, -24.5f,
|
||||
-35.4f, -48.3f, -63.2f, -80.1f, -99.f, -119.9f, -142.8f,
|
||||
-167.7f, -194.6f, -223.5f);
|
||||
|
||||
const SoaFloat4 mul_scal = a * ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_SOAFLOAT4_EQ(mul_scal, 1.f, 2.f, 4.f, 6.f, 8.f, 10.f, 12.f, 14.f, 16.f,
|
||||
18.f, 20.f, 22.f, 24.f, 26.f, 28.f, 30.f);
|
||||
|
||||
const SoaFloat4 div = a / b;
|
||||
EXPECT_SOAFLOAT4_EQ(div, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f,
|
||||
-1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f);
|
||||
|
||||
const SoaFloat4 div_scal = a / ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_SOAFLOAT4_EQ(div_scal, 0.25f, .5f, 1.f, 1.5f, 2.f, 2.5f, 3.f, 3.5f,
|
||||
4.f, 4.5, 5.f, 5.5f, 6.f, 6.5f, 7.f, 7.5f);
|
||||
|
||||
const SimdFloat4 hadd4 = HAdd(a);
|
||||
EXPECT_SOAFLOAT1_EQ(hadd4, 24.5f, 28.f, 32.f, 36.f);
|
||||
|
||||
const SimdFloat4 dot = Dot(a, b);
|
||||
EXPECT_SOAFLOAT1_EQ(dot, -224.25f, -276.f, -336.f, -404.f);
|
||||
|
||||
const SimdFloat4 length = Length(a);
|
||||
EXPECT_SOAFLOAT1_EQ(length, 14.974979f, 16.613247f, 18.3303f, 20.09975f);
|
||||
|
||||
const SimdFloat4 length2 = LengthSqr(a);
|
||||
EXPECT_SOAFLOAT1_EQ(length2, 224.25f, 276.f, 336.f, 404.f);
|
||||
|
||||
EXPECT_ASSERTION(Normalize(SoaFloat4::zero()), "_v is not normalizable");
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse(IsNormalized(a)));
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse(IsNormalizedEst(a)));
|
||||
const SoaFloat4 normalize = Normalize(a);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize)));
|
||||
EXPECT_SOAFLOAT4_EQ(normalize, .033389f, .0601929f, .1091089f, .1492555f,
|
||||
.267112f, .300964f, .3273268f, .348263f, .53422445f,
|
||||
.541736f, .545544f, .547270f, .80133667f, .782508f,
|
||||
.763762f, .74627789f);
|
||||
|
||||
EXPECT_ASSERTION(NormalizeSafe(a, a), "_safer is not normalized");
|
||||
const SoaFloat4 safe = ozz::math::SoaFloat4::x_axis();
|
||||
const SoaFloat4 normalize_safe = NormalizeSafe(a, safe);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize_safe)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize_safe)));
|
||||
EXPECT_SOAFLOAT4_EQ(normalize_safe, .033389f, .0601929f, .1091089f, .1492555f,
|
||||
.267112f, .300964f, .3273268f, .348263f, .53422445f,
|
||||
.541736f, .545544f, .547270f, .80133667f, .782508f,
|
||||
.763762f, .74627789f);
|
||||
|
||||
const SoaFloat4 normalize_safer = NormalizeSafe(SoaFloat4::zero(), safe);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize_safer)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize_safer)));
|
||||
EXPECT_SOAFLOAT4_EQ(normalize_safer, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SoaFloat4 lerp_0 = Lerp(a, b, ozz::math::simd_float4::zero());
|
||||
EXPECT_SOAFLOAT4_EQ(lerp_0, .5f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f,
|
||||
10.f, 11.f, 12.f, 13.f, 14.f, 15.f);
|
||||
|
||||
const SoaFloat4 lerp_1 = Lerp(a, b, ozz::math::simd_float4::one());
|
||||
EXPECT_SOAFLOAT4_EQ(lerp_1, -.5f, -1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f,
|
||||
-8.f, -9.f, -10.f, -11.f, -12.f, -13.f, -14.f, -15.f);
|
||||
|
||||
const SoaFloat4 lerp_0_5 = Lerp(a, b, ozz::math::simd_float4::Load1(.5f));
|
||||
EXPECT_SOAFLOAT4_EQ(lerp_0_5, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatArithmetic3, ozz_soa_math) {
|
||||
const SoaFloat3 a = {ozz::math::simd_float4::Load(.5f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f)};
|
||||
const SoaFloat3 b = {ozz::math::simd_float4::Load(-.5f, -1.f, -2.f, -3.f),
|
||||
ozz::math::simd_float4::Load(-4.f, -5.f, -6.f, -7.f),
|
||||
ozz::math::simd_float4::Load(-8.f, -9.f, -10.f, -11.f)};
|
||||
const SoaFloat3 c = {ozz::math::simd_float4::Load(.05f, .1f, .2f, .3f),
|
||||
ozz::math::simd_float4::Load(.4f, .5f, .6f, .7f),
|
||||
ozz::math::simd_float4::Load(.8f, .9f, 1.f, 1.1f)};
|
||||
|
||||
const SoaFloat3 add = a + b;
|
||||
EXPECT_SOAFLOAT3_EQ(add, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f);
|
||||
|
||||
const SoaFloat3 sub = a - b;
|
||||
EXPECT_SOAFLOAT3_EQ(sub, 1.f, 2.f, 4.f, 6.f, 8.f, 10.f, 12.f, 14.f, 16.f,
|
||||
18.f, 20.f, 22.f);
|
||||
|
||||
const SoaFloat3 neg = -a;
|
||||
EXPECT_SOAFLOAT3_EQ(neg, -.5f, -1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f, -8.f,
|
||||
-9.f, -10.f, -11.f);
|
||||
|
||||
const SoaFloat3 mul = a * b;
|
||||
EXPECT_SOAFLOAT3_EQ(mul, -0.25f, -1.f, -4.f, -9.f, -16.f, -25.f, -36.f, -49.f,
|
||||
-64.f, -81.f, -100.f, -121.f);
|
||||
|
||||
const SoaFloat3 mul_add = MAdd(a, b, c);
|
||||
EXPECT_SOAFLOAT3_EQ(mul_add, -0.2f, -.9f, -3.8f, -8.7f, -15.6f, -24.5f,
|
||||
-35.4f, -48.3f, -63.2f, -80.1f, -99.f, -119.9f);
|
||||
|
||||
const SoaFloat3 mul_scal = a * ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_SOAFLOAT3_EQ(mul_scal, 1.f, 2.f, 4.f, 6.f, 8.f, 10.f, 12.f, 14.f, 16.f,
|
||||
18.f, 20.f, 22.f);
|
||||
|
||||
const SoaFloat3 div = a / b;
|
||||
EXPECT_SOAFLOAT3_EQ(div, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f,
|
||||
-1.f, -1.f, -1.f);
|
||||
|
||||
const SoaFloat3 div_scal = a / ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_SOAFLOAT3_EQ(div_scal, 0.25f, .5f, 1.f, 1.5f, 2.f, 2.5f, 3.f, 3.5f,
|
||||
4.f, 4.5, 5.f, 5.5f);
|
||||
|
||||
const SimdFloat4 hadd4 = HAdd(a);
|
||||
EXPECT_SOAFLOAT1_EQ(hadd4, 12.5f, 15.f, 18.f, 21.f);
|
||||
|
||||
const SimdFloat4 dot = Dot(a, b);
|
||||
EXPECT_SOAFLOAT1_EQ(dot, -80.25f, -107.f, -140.f, -179.f);
|
||||
|
||||
const SimdFloat4 length = Length(a);
|
||||
EXPECT_SOAFLOAT1_EQ(length, 8.958236f, 10.34408f, 11.83216f, 13.37909f);
|
||||
|
||||
const SimdFloat4 length2 = LengthSqr(a);
|
||||
EXPECT_SOAFLOAT1_EQ(length2, 80.25f, 107.f, 140.f, 179.f);
|
||||
|
||||
const SoaFloat3 cross = Cross(a, b);
|
||||
EXPECT_SOAFLOAT3_EQ(cross, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f);
|
||||
|
||||
EXPECT_ASSERTION(Normalize(SoaFloat3::zero()), "_v is not normalizable");
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse(IsNormalized(a)));
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse(IsNormalizedEst(a)));
|
||||
const SoaFloat3 normalize = Normalize(a);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize)));
|
||||
EXPECT_SOAFLOAT3_EQ(normalize, .055814f, .096673f, .16903f, .22423f, .446516f,
|
||||
.483368f, .50709f, .52320f, .893033f, .870063f, .84515f,
|
||||
.822178f);
|
||||
|
||||
EXPECT_ASSERTION(NormalizeSafe(a, a), "_safer is not normalized");
|
||||
const SoaFloat3 safe = ozz::math::SoaFloat3::x_axis();
|
||||
const SoaFloat3 normalize_safe = NormalizeSafe(a, safe);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize_safe)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize_safe)));
|
||||
EXPECT_SOAFLOAT3_EQ(normalize_safe, .055814f, .096673f, .16903f, .22423f,
|
||||
.446516f, .483368f, .50709f, .52320f, .893033f, .870063f,
|
||||
.84515f, .822178f);
|
||||
|
||||
const SoaFloat3 normalize_safer = NormalizeSafe(SoaFloat3::zero(), safe);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize_safer)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize_safer)));
|
||||
EXPECT_SOAFLOAT3_EQ(normalize_safer, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SoaFloat3 lerp_0 = Lerp(a, b, ozz::math::simd_float4::zero());
|
||||
EXPECT_SOAFLOAT3_EQ(lerp_0, .5f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f,
|
||||
10.f, 11.f);
|
||||
|
||||
const SoaFloat3 lerp_1 = Lerp(a, b, ozz::math::simd_float4::one());
|
||||
EXPECT_SOAFLOAT3_EQ(lerp_1, -.5f, -1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f,
|
||||
-8.f, -9.f, -10.f, -11.f);
|
||||
|
||||
const SoaFloat3 lerp_0_5 = Lerp(a, b, ozz::math::simd_float4::Load1(.5f));
|
||||
EXPECT_SOAFLOAT3_EQ(lerp_0_5, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatArithmetic2, ozz_soa_math) {
|
||||
const SoaFloat2 a = {ozz::math::simd_float4::Load(.5f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f)};
|
||||
const SoaFloat2 b = {ozz::math::simd_float4::Load(-.5f, -1.f, -2.f, -3.f),
|
||||
ozz::math::simd_float4::Load(-4.f, -5.f, -6.f, -7.f)};
|
||||
const SoaFloat2 c = {ozz::math::simd_float4::Load(.05f, .1f, .2f, .3f),
|
||||
ozz::math::simd_float4::Load(.4f, .5f, .6f, .7f)};
|
||||
|
||||
const SoaFloat2 add = a + b;
|
||||
EXPECT_SOAFLOAT2_EQ(add, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SoaFloat2 sub = a - b;
|
||||
EXPECT_SOAFLOAT2_EQ(sub, 1.f, 2.f, 4.f, 6.f, 8.f, 10.f, 12.f, 14.f);
|
||||
|
||||
const SoaFloat2 neg = -a;
|
||||
EXPECT_SOAFLOAT2_EQ(neg, -.5f, -1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f);
|
||||
|
||||
const SoaFloat2 mul = a * b;
|
||||
EXPECT_SOAFLOAT2_EQ(mul, -0.25f, -1.f, -4.f, -9.f, -16.f, -25.f, -36.f,
|
||||
-49.f);
|
||||
|
||||
const SoaFloat2 mul_add = MAdd(a, b, c);
|
||||
EXPECT_SOAFLOAT2_EQ(mul_add, -0.2f, -.9f, -3.8f, -8.7f, -15.6f, -24.5f,
|
||||
-35.4f, -48.3f);
|
||||
|
||||
const SoaFloat2 mul_scal = a * ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_SOAFLOAT2_EQ(mul_scal, 1.f, 2.f, 4.f, 6.f, 8.f, 10.f, 12.f, 14.f);
|
||||
|
||||
const SoaFloat2 div = a / b;
|
||||
EXPECT_SOAFLOAT2_EQ(div, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f, -1.f);
|
||||
|
||||
const SoaFloat2 div_scal = a / ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_SOAFLOAT2_EQ(div_scal, 0.25f, .5f, 1.f, 1.5f, 2.f, 2.5f, 3.f, 3.5f);
|
||||
|
||||
const SimdFloat4 hadd4 = HAdd(a);
|
||||
EXPECT_SOAFLOAT1_EQ(hadd4, 4.5f, 6.f, 8.f, 10.f);
|
||||
|
||||
const SimdFloat4 dot = Dot(a, b);
|
||||
EXPECT_SOAFLOAT1_EQ(dot, -16.25f, -26.f, -40.f, -58.f);
|
||||
|
||||
const SimdFloat4 length = Length(a);
|
||||
EXPECT_SOAFLOAT1_EQ(length, 4.031129f, 5.09902f, 6.324555f, 7.615773f);
|
||||
|
||||
const SimdFloat4 length2 = LengthSqr(a);
|
||||
EXPECT_SOAFLOAT1_EQ(length2, 16.25f, 26.f, 40.f, 58.f);
|
||||
|
||||
EXPECT_ASSERTION(Normalize(SoaFloat2::zero()), "_v is not normalizable");
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse(IsNormalized(a)));
|
||||
EXPECT_TRUE(ozz::math::AreAllFalse(IsNormalizedEst(a)));
|
||||
const SoaFloat2 normalize = Normalize(a);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize)));
|
||||
EXPECT_SOAFLOAT2_EQ(normalize, .124034f, .196116f, .316227f, .393919f,
|
||||
.992277f, .980580f, .9486832f, .919145f);
|
||||
|
||||
EXPECT_ASSERTION(NormalizeSafe(a, a), "_safer is not normalized");
|
||||
const SoaFloat2 safe = ozz::math::SoaFloat2::x_axis();
|
||||
const SoaFloat2 normalize_safe = NormalizeSafe(a, safe);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize_safe)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize_safe)));
|
||||
EXPECT_SOAFLOAT2_EQ(normalize, .124034f, .196116f, .316227f, .393919f,
|
||||
.992277f, .980580f, .9486832f, .919145f);
|
||||
|
||||
const SoaFloat2 normalize_safer = NormalizeSafe(SoaFloat2::zero(), safe);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize_safer)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize_safer)));
|
||||
EXPECT_SOAFLOAT2_EQ(normalize_safer, 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
const SoaFloat2 lerp_0 = Lerp(a, b, ozz::math::simd_float4::zero());
|
||||
EXPECT_SOAFLOAT2_EQ(lerp_0, .5f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f);
|
||||
|
||||
const SoaFloat2 lerp_1 = Lerp(a, b, ozz::math::simd_float4::one());
|
||||
EXPECT_SOAFLOAT2_EQ(lerp_1, -.5f, -1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f);
|
||||
|
||||
const SoaFloat2 lerp_0_5 = Lerp(a, b, ozz::math::simd_float4::Load1(.5f));
|
||||
EXPECT_SOAFLOAT2_EQ(lerp_0_5, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(SoaFloatComparison4, ozz_soa_math) {
|
||||
const SoaFloat4 a = {ozz::math::simd_float4::Load(.5f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(1.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(2.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(3.f, 13.f, 14.f, 15.f)};
|
||||
const SoaFloat4 b = {ozz::math::simd_float4::Load(4.f, 3.f, 7.f, 3.f),
|
||||
ozz::math::simd_float4::Load(2.f, -5.f, 6.f, 5.f),
|
||||
ozz::math::simd_float4::Load(-6.f, 9.f, -10.f, 2.f),
|
||||
ozz::math::simd_float4::Load(7.f, -8.f, 1.f, 5.f)};
|
||||
const SoaFloat4 c = {ozz::math::simd_float4::Load(7.5f, 12.f, 46.f, 31.f),
|
||||
ozz::math::simd_float4::Load(1.f, 58.f, 16.f, 78.f),
|
||||
ozz::math::simd_float4::Load(2.5f, 9.f, 111.f, 22.f),
|
||||
ozz::math::simd_float4::Load(8.f, 23.f, 41.f, 18.f)};
|
||||
const SoaFloat4 min = Min(a, b);
|
||||
EXPECT_SOAFLOAT4_EQ(min, .5f, 1.f, 2.f, 3.f, 1.f, -5.f, 6.f, 5.f, -6.f, 9.f,
|
||||
-10.f, 2.f, 3.f, -8.f, 1.f, 5.f);
|
||||
|
||||
const SoaFloat4 max = Max(a, b);
|
||||
EXPECT_SOAFLOAT4_EQ(max, 4.f, 3.f, 7.f, 3.f, 2.f, 5.f, 6.f, 7.f, 2.f, 9.f,
|
||||
10.f, 11.f, 7.f, 13.f, 14.f, 15.f);
|
||||
|
||||
EXPECT_SOAFLOAT4_EQ(
|
||||
Clamp(a, SoaFloat4::Load(
|
||||
ozz::math::simd_float4::Load(1.5f, 5.f, -2.f, 24.f),
|
||||
ozz::math::simd_float4::Load(2.f, -5.f, 7.f, 1.f),
|
||||
ozz::math::simd_float4::Load(-3.f, 1.f, 200.f, 0.f),
|
||||
ozz::math::simd_float4::Load(-9.f, 15.f, 46.f, -1.f)),
|
||||
c),
|
||||
1.5f, 5.f, 2.f, 24.f, 1.f, 5.f, 7.f, 7.f, 2.f, 9.f, 111.f, 11.f, 3.f,
|
||||
15.f, 41.f, 15.f);
|
||||
|
||||
EXPECT_SIMDINT_EQ(a < c, 0, 0, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a <= c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(c <= c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
EXPECT_SIMDINT_EQ(c > a, 0, 0, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(c >= a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a >= a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
EXPECT_SIMDINT_EQ(a == a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a == c, 0, 0, 0, 0);
|
||||
EXPECT_SIMDINT_EQ(a != b, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
}
|
||||
|
||||
TEST(SoaFloatComparison3, ozz_soa_math) {
|
||||
const SoaFloat3 a = {ozz::math::simd_float4::Load(.5f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(1.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(2.f, 9.f, 10.f, 11.f)};
|
||||
const SoaFloat3 b = {ozz::math::simd_float4::Load(4.f, 3.f, 7.f, 3.f),
|
||||
ozz::math::simd_float4::Load(2.f, -5.f, 6.f, 5.f),
|
||||
ozz::math::simd_float4::Load(-6.f, 9.f, -10.f, 2.f)};
|
||||
const SoaFloat3 c = {ozz::math::simd_float4::Load(7.5f, 12.f, 46.f, 31.f),
|
||||
ozz::math::simd_float4::Load(1.f, 58.f, 16.f, 78.f),
|
||||
ozz::math::simd_float4::Load(2.5f, 9.f, 111.f, 22.f)};
|
||||
const SoaFloat3 min = Min(a, b);
|
||||
EXPECT_SOAFLOAT3_EQ(min, .5f, 1.f, 2.f, 3.f, 1.f, -5.f, 6.f, 5.f, -6.f, 9.f,
|
||||
-10.f, 2.f);
|
||||
|
||||
const SoaFloat3 max = Max(a, b);
|
||||
EXPECT_SOAFLOAT3_EQ(max, 4.f, 3.f, 7.f, 3.f, 2.f, 5.f, 6.f, 7.f, 2.f, 9.f,
|
||||
10.f, 11.f);
|
||||
|
||||
EXPECT_SOAFLOAT3_EQ(
|
||||
Clamp(a, SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(1.5f, 5.f, -2.f, 24.f),
|
||||
ozz::math::simd_float4::Load(2.f, -5.f, 7.f, 1.f),
|
||||
ozz::math::simd_float4::Load(-3.f, 1.f, 200.f, 0.f)),
|
||||
c),
|
||||
1.5f, 5.f, 2.f, 24.f, 1.f, 5.f, 7.f, 7.f, 2.f, 9.f, 111.f, 11.f);
|
||||
|
||||
EXPECT_SIMDINT_EQ(a < c, 0, 0, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a <= c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(c <= c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
EXPECT_SIMDINT_EQ(c > a, 0, 0, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(c >= a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a >= a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
EXPECT_SIMDINT_EQ(a == a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a == c, 0, 0, 0, 0);
|
||||
EXPECT_SIMDINT_EQ(a != b, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
}
|
||||
|
||||
TEST(SoaFloatComparison2, ozz_soa_math) {
|
||||
const SoaFloat2 a = {ozz::math::simd_float4::Load(.5f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(1.f, 5.f, 6.f, 7.f)};
|
||||
const SoaFloat2 b = {ozz::math::simd_float4::Load(4.f, 3.f, 7.f, 3.f),
|
||||
ozz::math::simd_float4::Load(2.f, -5.f, 6.f, 5.f)};
|
||||
const SoaFloat2 c = {ozz::math::simd_float4::Load(7.5f, 12.f, 46.f, 31.f),
|
||||
ozz::math::simd_float4::Load(1.f, 58.f, 16.f, 78.f)};
|
||||
const SoaFloat2 min = Min(a, b);
|
||||
EXPECT_SOAFLOAT2_EQ(min, .5f, 1.f, 2.f, 3.f, 1.f, -5.f, 6.f, 5.f);
|
||||
|
||||
const SoaFloat2 max = Max(a, b);
|
||||
EXPECT_SOAFLOAT2_EQ(max, 4.f, 3.f, 7.f, 3.f, 2.f, 5.f, 6.f, 7.f);
|
||||
|
||||
EXPECT_SOAFLOAT2_EQ(
|
||||
Clamp(a,
|
||||
SoaFloat2::Load(ozz::math::simd_float4::Load(1.5f, 5.f, -2.f, 24.f),
|
||||
ozz::math::simd_float4::Load(2.f, -5.f, 7.f, 1.f)),
|
||||
c),
|
||||
1.5f, 5.f, 2.f, 24.f, 1.f, 5.f, 7.f, 7.f);
|
||||
|
||||
EXPECT_SIMDINT_EQ(a < c, 0, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a <= c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(c <= c, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
EXPECT_SIMDINT_EQ(c > a, 0, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(c >= a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a >= a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
|
||||
EXPECT_SIMDINT_EQ(a == a, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
EXPECT_SIMDINT_EQ(a == c, 0, 0, 0, 0);
|
||||
EXPECT_SIMDINT_EQ(a != b, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/soa_math_archive.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
#include "ozz/base/io/archive.h"
|
||||
#include "ozz/base/maths/soa_float.h"
|
||||
#include "ozz/base/maths/soa_float4x4.h"
|
||||
#include "ozz/base/maths/soa_quaternion.h"
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
|
||||
TEST(SoaMathArchive, ozz_soa_math) {
|
||||
for (int e = 0; e < 2; ++e) {
|
||||
ozz::Endianness endianess = e == 0 ? ozz::kBigEndian : ozz::kLittleEndian;
|
||||
|
||||
ozz::io::MemoryStream stream;
|
||||
ASSERT_TRUE(stream.opened());
|
||||
|
||||
// Write soa math types.
|
||||
ozz::io::OArchive o(&stream, endianess);
|
||||
const ozz::math::SoaFloat2 of2 = ozz::math::SoaFloat2::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f));
|
||||
o << of2;
|
||||
const ozz::math::SoaFloat3 of3 = ozz::math::SoaFloat3::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f));
|
||||
o << of3;
|
||||
const ozz::math::SoaFloat4 of4 = ozz::math::SoaFloat4::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f));
|
||||
o << of4;
|
||||
const ozz::math::SoaQuaternion oquat = ozz::math::SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(0.f, 1.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 5.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 9.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 13.f, 14.f, 15.f));
|
||||
o << oquat;
|
||||
const ozz::math::SoaTransform otrans = {of3, oquat, of3};
|
||||
o << otrans;
|
||||
const ozz::math::SoaFloat4x4 of44 = {
|
||||
{{ozz::math::simd_float4::Load(0.f, 1.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, 0.f, -1.f, 0.f),
|
||||
ozz::math::simd_float4::Load(2.f, 0.f, 2.f, -1.f),
|
||||
ozz::math::simd_float4::Load(3.f, 0.f, 3.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(4.f, 0.f, -4.f, 0.f),
|
||||
ozz::math::simd_float4::Load(5.f, 1.f, 5.f, 1.f),
|
||||
ozz::math::simd_float4::Load(6.f, 0.f, 6.f, 0.f),
|
||||
ozz::math::simd_float4::Load(7.f, 0.f, -7.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(8.f, 0.f, 8.f, 1.f),
|
||||
ozz::math::simd_float4::Load(9.f, 0.f, -9.f, 0.f),
|
||||
ozz::math::simd_float4::Load(10.f, 1.f, -10.f, 0.f),
|
||||
ozz::math::simd_float4::Load(11.f, 0.f, 11.f, 0.f)},
|
||||
{ozz::math::simd_float4::Load(12.f, 0.f, -12.f, 0.f),
|
||||
ozz::math::simd_float4::Load(13.f, 0.f, 13.f, 0.f),
|
||||
ozz::math::simd_float4::Load(14.f, 0.f, -14.f, 0.f),
|
||||
ozz::math::simd_float4::Load(15.f, 1.f, 15.f, 1.f)}}};
|
||||
o << of44;
|
||||
|
||||
// Reads soa math types.
|
||||
stream.Seek(0, ozz::io::Stream::kSet);
|
||||
ozz::io::IArchive i(&stream);
|
||||
ozz::math::SoaFloat2 if2;
|
||||
i >> if2;
|
||||
EXPECT_SOAFLOAT2_EQ(if2, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f);
|
||||
ozz::math::SoaFloat3 if3;
|
||||
i >> if3;
|
||||
EXPECT_SOAFLOAT3_EQ(if3, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f,
|
||||
10.f, 11.f);
|
||||
ozz::math::SoaFloat4 if4;
|
||||
i >> if4;
|
||||
EXPECT_SOAFLOAT4_EQ(if4, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f,
|
||||
10.f, 11.f, 12.f, 13.f, 14.f, 15.f);
|
||||
ozz::math::SoaQuaternion iquat;
|
||||
i >> iquat;
|
||||
EXPECT_SOAQUATERNION_EQ(iquat, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f,
|
||||
9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f);
|
||||
ozz::math::SoaTransform itrans;
|
||||
i >> itrans;
|
||||
EXPECT_SOAFLOAT3_EQ(itrans.translation, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f,
|
||||
7.f, 8.f, 9.f, 10.f, 11.f);
|
||||
EXPECT_SOAQUATERNION_EQ(itrans.rotation, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f,
|
||||
7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f);
|
||||
EXPECT_SOAFLOAT3_EQ(itrans.scale, 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f,
|
||||
8.f, 9.f, 10.f, 11.f);
|
||||
ozz::math::SoaFloat4x4 if44;
|
||||
i >> if44;
|
||||
EXPECT_SOAFLOAT4x4_EQ(
|
||||
if44, 0.f, 1.f, 0.f, 0.f, 1.f, 0.f, -1.f, 0.f, 2.f, 0.f, 2.f, -1.f, 3.f,
|
||||
0.f, 3.f, 0.f, 4.f, 0.f, -4.f, 0.f, 5.f, 1.f, 5.f, 1.f, 6.f, 0.f, 6.f,
|
||||
0.f, 7.f, 0.f, -7.f, 0.f, 8.f, 0.f, 8.f, 1.f, 9.f, 0.f, -9.f, 0.f, 10.f,
|
||||
1.f, -10.f, 0.f, 11.f, 0.f, 11.f, 0.f, 12.f, 0.f, -12.f, 0.f, 13.f, 0.f,
|
||||
13.f, 0.f, 14.f, 0.f, -14.f, 0.f, 15.f, 1.f, 15.f, 1.f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/soa_quaternion.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::math::SoaQuaternion;
|
||||
using ozz::math::SoaFloat4;
|
||||
using ozz::math::SoaFloat3;
|
||||
|
||||
TEST(SoaQuaternionConstant, ozz_soa_math) {
|
||||
EXPECT_SOAQUATERNION_EQ(SoaQuaternion::identity(), 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f,
|
||||
1.f);
|
||||
}
|
||||
|
||||
TEST(SoaQuaternionArithmetic, ozz_soa_math) {
|
||||
const SoaQuaternion a = SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(.70710677f, 0.f, 0.f, .382683432f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, .70710677f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(.70710677f, 1.f, .70710677f, .9238795f));
|
||||
const SoaQuaternion b = SoaQuaternion::Load(
|
||||
ozz::math::simd_float4::Load(0.f, .70710677f, 0.f, -.382683432f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, .70710677f, 0.f),
|
||||
ozz::math::simd_float4::Load(0.f, 0.f, 0.f, 0.f),
|
||||
ozz::math::simd_float4::Load(1.f, .70710677f, .70710677f, .9238795f));
|
||||
const SoaQuaternion denorm =
|
||||
SoaQuaternion::Load(ozz::math::simd_float4::Load(.5f, 0.f, 2.f, 3.f),
|
||||
ozz::math::simd_float4::Load(4.f, 0.f, 6.f, 7.f),
|
||||
ozz::math::simd_float4::Load(8.f, 0.f, 10.f, 11.f),
|
||||
ozz::math::simd_float4::Load(12.f, 1.f, 14.f, 15.f));
|
||||
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(a)));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(b)));
|
||||
EXPECT_SIMDINT_EQ(ozz::math::IsNormalized(denorm), 0, 0xffffffff, 0, 0);
|
||||
|
||||
const SoaQuaternion conjugate = Conjugate(a);
|
||||
EXPECT_SOAQUATERNION_EQ(conjugate, -.70710677f, -0.f, -0.f, -.382683432f,
|
||||
-0.f, -0.f, -.70710677f, -0.f, -0.f, -0.f, -0.f, -0.f,
|
||||
.70710677f, 1.f, .70710677f, .9238795f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(conjugate)));
|
||||
|
||||
const SoaQuaternion negate = -a;
|
||||
EXPECT_SOAQUATERNION_EQ(negate, -.70710677f, 0.f, 0.f, -.382683432f, 0.f, 0.f,
|
||||
-.70710677f, 0.f, 0.f, 0.f, 0.f, 0.f, -.70710677f,
|
||||
-1.f, -.70710677f, -.9238795f);
|
||||
|
||||
const SoaQuaternion add = a + b;
|
||||
EXPECT_SOAQUATERNION_EQ(add, .70710677f, .70710677f, 0.f, 0.f, 0.f, 0.f,
|
||||
1.41421354f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.70710677f,
|
||||
1.70710677f, 1.41421354f, 1.847759f);
|
||||
|
||||
const SoaQuaternion muls = a * ozz::math::simd_float4::Load1(2.f);
|
||||
EXPECT_SOAQUATERNION_EQ(muls, 1.41421354f, 0.f, 0.f, .765366864f, 0.f, 0.f,
|
||||
1.41421354f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.41421354f,
|
||||
2.f, 1.41421354f, 1.847759f);
|
||||
|
||||
const SoaQuaternion mul0 = a * conjugate;
|
||||
EXPECT_SOAQUATERNION_EQ(mul0, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(mul0)));
|
||||
|
||||
const SoaQuaternion mul1 = conjugate * a;
|
||||
EXPECT_SOAQUATERNION_EQ(mul1, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(mul1)));
|
||||
|
||||
const ozz::math::SimdFloat4 dot = Dot(a, b);
|
||||
EXPECT_SOAFLOAT1_EQ(dot, .70710677f, .70710677f, 1.f, .70710677f);
|
||||
|
||||
const SoaQuaternion normalize = Normalize(denorm);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(normalize)));
|
||||
EXPECT_SOAQUATERNION_EQ(normalize, .033389f, 0.f, .1091089f, .1492555f,
|
||||
.267112f, 0.f, .3273268f, .348263f, .53422445f, 0.f,
|
||||
.545544f, .547270f, .80133667f, 1.f, .763762f,
|
||||
.74627789f);
|
||||
|
||||
const SoaQuaternion normalize_est = NormalizeEst(denorm);
|
||||
EXPECT_SOAQUATERNION_EQ_EST(normalize_est, .033389f, 0.f, .1091089f,
|
||||
.1492555f, .267112f, 0.f, .3273268f, .348263f,
|
||||
.53422445f, 0.f, .545544f, .547270f, .80133667f,
|
||||
1.f, .763762f, .74627789f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(normalize_est)));
|
||||
|
||||
const SoaQuaternion lerp_0 = Lerp(a, b, ozz::math::simd_float4::zero());
|
||||
EXPECT_SOAQUATERNION_EQ(lerp_0, .70710677f, 0.f, 0.f, .382683432f, 0.f, 0.f,
|
||||
.70710677f, 0.f, 0.f, 0.f, 0.f, 0.f, .70710677f, 1.f,
|
||||
.70710677f, .9238795f);
|
||||
|
||||
const SoaQuaternion lerp_1 = Lerp(a, b, ozz::math::simd_float4::one());
|
||||
EXPECT_SOAQUATERNION_EQ(lerp_1, 0.f, .70710677f, 0.f, -.382683432f, 0.f, 0.f,
|
||||
.70710677f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, .70710677f,
|
||||
.70710677f, .9238795f);
|
||||
|
||||
const SoaQuaternion lerp_0_2 = Lerp(a, b, ozz::math::simd_float4::Load1(.2f));
|
||||
EXPECT_SOAQUATERNION_EQ(lerp_0_2, .565685416f, .14142136f, 0.f, .22961006f,
|
||||
0.f, 0.f, .70710677f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
.76568544f, .94142133f, .70710677f, .92387950f);
|
||||
|
||||
const SoaQuaternion lerp_m =
|
||||
Lerp(a, b, ozz::math::simd_float4::Load(0.f, 1.f, 1.f, .2f));
|
||||
EXPECT_SOAQUATERNION_EQ(lerp_m, .70710677f, .70710677f, 0.f, .22961006f, 0.f,
|
||||
0.f, .70710677f, 0.f, 0.f, 0.f, 0.f, 0.f, .70710677f,
|
||||
.70710677f, .70710677f, .92387950f);
|
||||
|
||||
const SoaQuaternion nlerp_0 = NLerp(a, b, ozz::math::simd_float4::zero());
|
||||
EXPECT_SOAQUATERNION_EQ(nlerp_0, .70710677f, 0.f, 0.f, .382683432f, 0.f, 0.f,
|
||||
.70710677f, 0.f, 0.f, 0.f, 0.f, 0.f, .70710677f, 1.f,
|
||||
.70710677f, .9238795f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(nlerp_0)));
|
||||
|
||||
const SoaQuaternion nlerp_1 = NLerp(a, b, ozz::math::simd_float4::one());
|
||||
EXPECT_SOAQUATERNION_EQ(nlerp_1, 0.f, .70710677f, 0.f, -.382683432f, 0.f, 0.f,
|
||||
.70710677f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, .70710677f,
|
||||
.70710677f, .9238795f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(nlerp_1)));
|
||||
|
||||
const SoaQuaternion nlerp_0_2 =
|
||||
NLerp(a, b, ozz::math::simd_float4::Load1(.2f));
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(nlerp_0_2)));
|
||||
EXPECT_SOAQUATERNION_EQ(nlerp_0_2, .59421712f, .14855431f, 0.f, .24119100f,
|
||||
0.f, 0.f, .70710683f, 0.f, 0.f, 0.f, 0.f, 0.f,
|
||||
.80430466f, .98890430f, .70710683f, .97047764f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(nlerp_0_2)));
|
||||
|
||||
const SoaQuaternion nlerp_m =
|
||||
NLerp(a, b, ozz::math::simd_float4::Load(0.f, 1.f, 1.f, .2f));
|
||||
EXPECT_SOAQUATERNION_EQ(nlerp_m, .70710677f, .70710677f, 0.f, .24119100f, 0.f,
|
||||
0.f, .70710677f, 0.f, 0.f, 0.f, 0.f, 0.f, .70710677f,
|
||||
.70710677f, .70710677f, .97047764f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalized(nlerp_m)));
|
||||
|
||||
const SoaQuaternion nlerp_est_m =
|
||||
NLerpEst(a, b, ozz::math::simd_float4::Load(0.f, 1.f, 1.f, .2f));
|
||||
EXPECT_SOAQUATERNION_EQ_EST(nlerp_est_m, .70710677f, .70710677f, 0.f,
|
||||
.24119100f, 0.f, 0.f, .70710677f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, .70710677f, .70710677f, .70710677f,
|
||||
.97047764f);
|
||||
EXPECT_TRUE(ozz::math::AreAllTrue(IsNormalizedEst(nlerp_est_m)));
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/soa_transform.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::math::SoaTransform;
|
||||
|
||||
TEST(SoaTransformConstant, ozz_soa_math) {
|
||||
EXPECT_SOAFLOAT3_EQ(SoaTransform::identity().translation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_SOAQUATERNION_EQ(SoaTransform::identity().rotation, 0.f, 0.f, 0.f, 0.f,
|
||||
0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f,
|
||||
1.f);
|
||||
EXPECT_SOAFLOAT3_EQ(SoaTransform::identity().scale, 1.f, 1.f, 1.f, 1.f, 1.f,
|
||||
1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/transform.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::math::Transform;
|
||||
|
||||
TEST(TransformConstant, ozz_math) {
|
||||
EXPECT_FLOAT3_EQ(Transform::identity().translation, 0.f, 0.f, 0.f);
|
||||
EXPECT_QUATERNION_EQ(Transform::identity().rotation, 0.f, 0.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT3_EQ(Transform::identity().scale, 1.f, 1.f, 1.f);
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/maths/vec_float.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/maths/gtest_math_helper.h"
|
||||
|
||||
using ozz::math::Float2;
|
||||
using ozz::math::Float3;
|
||||
using ozz::math::Float4;
|
||||
|
||||
TEST(VectorLoad4, ozz_math) {
|
||||
EXPECT_FLOAT4_EQ(Float4(46.f), 46.f, 46.f, 46.f, 46.f);
|
||||
EXPECT_FLOAT4_EQ(Float4(-1.f, 0.f, 1.f, 2.f), -1.f, 0.f, 1.f, 2.f);
|
||||
const Float3 f3(-1.f, 0.f, 1.f);
|
||||
EXPECT_FLOAT4_EQ(Float4(f3, 2.f), -1.f, 0.f, 1.f, 2.f);
|
||||
const Float2 f2(-1.f, 0.f);
|
||||
EXPECT_FLOAT4_EQ(Float4(f2, 1.f, 2.f), -1.f, 0.f, 1.f, 2.f);
|
||||
}
|
||||
|
||||
TEST(VectorLoad3, ozz_math) {
|
||||
EXPECT_FLOAT3_EQ(Float3(46.f), 46.f, 46.f, 46.f);
|
||||
EXPECT_FLOAT3_EQ(Float3(-1.f, 0.f, 1.f), -1.f, 0.f, 1.f);
|
||||
const Float2 f2(-1.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(Float3(f2, 1.f), -1.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(VectorLoad2, ozz_math) {
|
||||
EXPECT_FLOAT2_EQ(Float2(46.f), 46.f, 46.f);
|
||||
EXPECT_FLOAT2_EQ(Float2(-1.f, 0.f), -1.f, 0.f);
|
||||
}
|
||||
|
||||
TEST(VectorConstant4, ozz_math) {
|
||||
EXPECT_FLOAT4_EQ(Float4::zero(), 0.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT4_EQ(Float4::one(), 1.f, 1.f, 1.f, 1.f);
|
||||
EXPECT_FLOAT4_EQ(Float4::x_axis(), 1.f, 0.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT4_EQ(Float4::y_axis(), 0.f, 1.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT4_EQ(Float4::z_axis(), 0.f, 0.f, 1.f, 0.f);
|
||||
EXPECT_FLOAT4_EQ(Float4::w_axis(), 0.f, 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(VectorConstant3, ozz_math) {
|
||||
EXPECT_FLOAT3_EQ(Float3::zero(), 0.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(Float3::one(), 1.f, 1.f, 1.f);
|
||||
EXPECT_FLOAT3_EQ(Float3::x_axis(), 1.f, 0.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(Float3::y_axis(), 0.f, 1.f, 0.f);
|
||||
EXPECT_FLOAT3_EQ(Float3::z_axis(), 0.f, 0.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(VectorConstant2, ozz_math) {
|
||||
EXPECT_FLOAT2_EQ(Float2::zero(), 0.f, 0.f);
|
||||
EXPECT_FLOAT2_EQ(Float2::one(), 1.f, 1.f);
|
||||
EXPECT_FLOAT2_EQ(Float2::x_axis(), 1.f, 0.f);
|
||||
EXPECT_FLOAT2_EQ(Float2::y_axis(), 0.f, 1.f);
|
||||
}
|
||||
|
||||
TEST(VectorArithmetic4, ozz_math) {
|
||||
const Float4 a(.5f, 1.f, 2.f, 3.f);
|
||||
const Float4 b(4.f, 5.f, -6.f, 7.f);
|
||||
|
||||
const Float4 add = a + b;
|
||||
EXPECT_FLOAT4_EQ(add, 4.5f, 6.f, -4.f, 10.f);
|
||||
|
||||
const Float4 sub = a - b;
|
||||
EXPECT_FLOAT4_EQ(sub, -3.5f, -4.f, 8.f, -4.f);
|
||||
|
||||
const Float4 neg = -b;
|
||||
EXPECT_FLOAT4_EQ(neg, -4.f, -5.f, 6.f, -7.f);
|
||||
|
||||
const Float4 mul = a * b;
|
||||
EXPECT_FLOAT4_EQ(mul, 2.f, 5.f, -12.f, 21.f);
|
||||
|
||||
const Float4 mul_scal = a * 2.f;
|
||||
EXPECT_FLOAT4_EQ(mul_scal, 1.f, 2.f, 4.f, 6.f);
|
||||
|
||||
const Float4 div = a / b;
|
||||
EXPECT_FLOAT4_EQ(div, .5f / 4.f, 1.f / 5.f, -2.f / 6.f, 3.f / 7.f);
|
||||
|
||||
const Float4 div_scal = a / 2.f;
|
||||
EXPECT_FLOAT4_EQ(div_scal, .5f / 2.f, 1.f / 2.f, 2.f / 2.f, 3.f / 2.f);
|
||||
|
||||
const float hadd4 = HAdd(a);
|
||||
EXPECT_FLOAT_EQ(hadd4, 6.5f);
|
||||
|
||||
const float dot = Dot(a, b);
|
||||
EXPECT_FLOAT_EQ(dot, 16.f);
|
||||
|
||||
const float length = Length(a);
|
||||
EXPECT_FLOAT_EQ(length, std::sqrt(14.25f));
|
||||
|
||||
const float length2 = LengthSqr(a);
|
||||
EXPECT_FLOAT_EQ(length2, 14.25f);
|
||||
|
||||
EXPECT_ASSERTION(Normalize(Float4::zero()), "is not normalizable");
|
||||
EXPECT_FALSE(IsNormalized(a));
|
||||
const Float4 normalize = Normalize(a);
|
||||
EXPECT_TRUE(IsNormalized(normalize));
|
||||
EXPECT_FLOAT4_EQ(normalize, .13245323f, .26490647f, .52981293f, .79471946f);
|
||||
|
||||
EXPECT_ASSERTION(NormalizeSafe(a, a), "_safer is not normalized");
|
||||
const Float4 safe(1.f, 0.f, 0.f, 0.f);
|
||||
const Float4 normalize_safe = NormalizeSafe(a, safe);
|
||||
EXPECT_TRUE(IsNormalized(normalize_safe));
|
||||
EXPECT_FLOAT4_EQ(normalize_safe, .13245323f, .26490647f, .52981293f,
|
||||
.79471946f);
|
||||
|
||||
const Float4 normalize_safer = NormalizeSafe(Float4::zero(), safe);
|
||||
EXPECT_TRUE(IsNormalized(normalize_safer));
|
||||
EXPECT_FLOAT4_EQ(normalize_safer, safe.x, safe.y, safe.z, safe.w);
|
||||
|
||||
const Float4 lerp_0 = Lerp(a, b, 0.f);
|
||||
EXPECT_FLOAT4_EQ(lerp_0, a.x, a.y, a.z, a.w);
|
||||
|
||||
const Float4 lerp_1 = Lerp(a, b, 1.f);
|
||||
EXPECT_FLOAT4_EQ(lerp_1, b.x, b.y, b.z, b.w);
|
||||
|
||||
const Float4 lerp_0_5 = Lerp(a, b, .5f);
|
||||
EXPECT_FLOAT4_EQ(lerp_0_5, (a.x + b.x) * .5f, (a.y + b.y) * .5f,
|
||||
(a.z + b.z) * .5f, (a.w + b.w) * .5f);
|
||||
|
||||
const Float4 lerp_2 = Lerp(a, b, 2.f);
|
||||
EXPECT_FLOAT4_EQ(lerp_2, 2.f * b.x - a.x, 2.f * b.y - a.y, 2.f * b.z - a.z,
|
||||
2.f * b.w - a.w);
|
||||
}
|
||||
|
||||
TEST(VectorArithmetic3, ozz_math) {
|
||||
const Float3 a(.5f, 1.f, 2.f);
|
||||
const Float3 b(4.f, 5.f, -6.f);
|
||||
|
||||
const Float3 add = a + b;
|
||||
EXPECT_FLOAT3_EQ(add, 4.5f, 6.f, -4.f);
|
||||
|
||||
const Float3 sub = a - b;
|
||||
EXPECT_FLOAT3_EQ(sub, -3.5f, -4.f, 8.f);
|
||||
|
||||
const Float3 neg = -b;
|
||||
EXPECT_FLOAT3_EQ(neg, -4.f, -5.f, 6.f);
|
||||
|
||||
const Float3 mul = a * b;
|
||||
EXPECT_FLOAT3_EQ(mul, 2.f, 5.f, -12.f);
|
||||
|
||||
const Float3 mul_scal = a * 2.f;
|
||||
EXPECT_FLOAT3_EQ(mul_scal, 1.f, 2.f, 4.f);
|
||||
|
||||
const Float3 div = a / b;
|
||||
EXPECT_FLOAT3_EQ(div, .5f / 4.f, 1.f / 5.f, -2.f / 6.f);
|
||||
|
||||
const Float3 div_scal = a / 2.f;
|
||||
EXPECT_FLOAT3_EQ(div_scal, .5f / 2.f, 1.f / 2.f, 2.f / 2.f);
|
||||
|
||||
const float hadd4 = HAdd(a);
|
||||
EXPECT_FLOAT_EQ(hadd4, 3.5f);
|
||||
|
||||
const float dot = Dot(a, b);
|
||||
EXPECT_FLOAT_EQ(dot, -5.f);
|
||||
|
||||
const Float3 cross = Cross(a, b);
|
||||
EXPECT_FLOAT3_EQ(cross, -16.f, 11.f, -1.5f);
|
||||
|
||||
const float length = Length(a);
|
||||
EXPECT_FLOAT_EQ(length, std::sqrt(5.25f));
|
||||
|
||||
const float length2 = LengthSqr(a);
|
||||
EXPECT_FLOAT_EQ(length2, 5.25f);
|
||||
|
||||
EXPECT_ASSERTION(Normalize(Float3::zero()), "is not normalizable");
|
||||
EXPECT_FALSE(IsNormalized(a));
|
||||
const Float3 normalize = Normalize(a);
|
||||
EXPECT_TRUE(IsNormalized(normalize));
|
||||
EXPECT_FLOAT3_EQ(normalize, .21821788f, .43643576f, .87287152f);
|
||||
|
||||
EXPECT_ASSERTION(NormalizeSafe(a, a), "_safer is not normalized");
|
||||
const Float3 safe(1.f, 0.f, 0.f);
|
||||
const Float3 normalize_safe = NormalizeSafe(a, safe);
|
||||
EXPECT_TRUE(IsNormalized(normalize_safe));
|
||||
EXPECT_FLOAT3_EQ(normalize_safe, .21821788f, .43643576f, .87287152f);
|
||||
|
||||
const Float3 normalize_safer = NormalizeSafe(Float3::zero(), safe);
|
||||
EXPECT_TRUE(IsNormalized(normalize_safer));
|
||||
EXPECT_FLOAT3_EQ(normalize_safer, safe.x, safe.y, safe.z);
|
||||
|
||||
const Float3 lerp_0 = Lerp(a, b, 0.f);
|
||||
EXPECT_FLOAT3_EQ(lerp_0, a.x, a.y, a.z);
|
||||
|
||||
const Float3 lerp_1 = Lerp(a, b, 1.f);
|
||||
EXPECT_FLOAT3_EQ(lerp_1, b.x, b.y, b.z);
|
||||
|
||||
const Float3 lerp_0_5 = Lerp(a, b, .5f);
|
||||
EXPECT_FLOAT3_EQ(lerp_0_5, (a.x + b.x) * .5f, (a.y + b.y) * .5f,
|
||||
(a.z + b.z) * .5f);
|
||||
|
||||
const Float3 lerp_2 = Lerp(a, b, 2.f);
|
||||
EXPECT_FLOAT3_EQ(lerp_2, 2.f * b.x - a.x, 2.f * b.y - a.y, 2.f * b.z - a.z);
|
||||
}
|
||||
|
||||
TEST(VectorArithmetic2, ozz_math) {
|
||||
const Float2 a(.5f, 1.f);
|
||||
const Float2 b(4.f, 5.f);
|
||||
|
||||
const Float2 add = a + b;
|
||||
EXPECT_FLOAT2_EQ(add, 4.5f, 6.f);
|
||||
|
||||
const Float2 sub = a - b;
|
||||
EXPECT_FLOAT2_EQ(sub, -3.5f, -4.f);
|
||||
|
||||
const Float2 neg = -b;
|
||||
EXPECT_FLOAT2_EQ(neg, -4.f, -5.f);
|
||||
|
||||
const Float2 mul = a * b;
|
||||
EXPECT_FLOAT2_EQ(mul, 2.f, 5.f);
|
||||
|
||||
const Float2 mul_scal = a * 2.f;
|
||||
EXPECT_FLOAT2_EQ(mul_scal, 1.f, 2.f);
|
||||
|
||||
const Float2 div = a / b;
|
||||
EXPECT_FLOAT2_EQ(div, .5f / 4.f, 1.f / 5.f);
|
||||
const Float2 div_scal = a / 2.f;
|
||||
EXPECT_FLOAT2_EQ(div_scal, .5f / 2.f, 1.f / 2.f);
|
||||
|
||||
const float hadd4 = HAdd(a);
|
||||
EXPECT_FLOAT_EQ(hadd4, 1.5f);
|
||||
|
||||
const float dot = Dot(a, b);
|
||||
EXPECT_FLOAT_EQ(dot, 7.f);
|
||||
|
||||
const float length = Length(a);
|
||||
EXPECT_FLOAT_EQ(length, std::sqrt(1.25f));
|
||||
|
||||
const float length2 = LengthSqr(a);
|
||||
EXPECT_FLOAT_EQ(length2, 1.25f);
|
||||
|
||||
EXPECT_ASSERTION(Normalize(Float2::zero()), "is not normalizable");
|
||||
EXPECT_FALSE(IsNormalized(a));
|
||||
const Float2 normalize = Normalize(a);
|
||||
EXPECT_TRUE(IsNormalized(normalize));
|
||||
EXPECT_FLOAT2_EQ(normalize, .44721359f, .89442718f);
|
||||
|
||||
EXPECT_ASSERTION(NormalizeSafe(a, a), "_safer is not normalized");
|
||||
const Float2 safe(1.f, 0.f);
|
||||
const Float2 normalize_safe = NormalizeSafe(a, safe);
|
||||
EXPECT_TRUE(IsNormalized(normalize_safe));
|
||||
EXPECT_FLOAT2_EQ(normalize_safe, .44721359f, .89442718f);
|
||||
|
||||
const Float2 normalize_safer = NormalizeSafe(Float2::zero(), safe);
|
||||
EXPECT_TRUE(IsNormalized(normalize_safer));
|
||||
EXPECT_FLOAT2_EQ(normalize_safer, safe.x, safe.y);
|
||||
|
||||
const Float2 lerp_0 = Lerp(a, b, 0.f);
|
||||
EXPECT_FLOAT2_EQ(lerp_0, a.x, a.y);
|
||||
|
||||
const Float2 lerp_1 = Lerp(a, b, 1.f);
|
||||
EXPECT_FLOAT2_EQ(lerp_1, b.x, b.y);
|
||||
|
||||
const Float2 lerp_0_5 = Lerp(a, b, .5f);
|
||||
EXPECT_FLOAT2_EQ(lerp_0_5, (a.x + b.x) * .5f, (a.y + b.y) * .5f);
|
||||
|
||||
const Float2 lerp_2 = Lerp(a, b, 2.f);
|
||||
EXPECT_FLOAT2_EQ(lerp_2, 2.f * b.x - a.x, 2.f * b.y - a.y);
|
||||
}
|
||||
|
||||
TEST(VectorComparison4, ozz_math) {
|
||||
const Float4 a(.5f, 1.f, 2.f, 3.f);
|
||||
const Float4 b(4.f, 5.f, -6.f, 7.f);
|
||||
const Float4 c(4.f, 5.f, 6.f, 7.f);
|
||||
const Float4 d(4.f, 5.f, 6.f, 7.1f);
|
||||
|
||||
const Float4 min = Min(a, b);
|
||||
EXPECT_FLOAT4_EQ(min, .5f, 1.f, -6.f, 3.f);
|
||||
|
||||
const Float4 max = Max(a, b);
|
||||
EXPECT_FLOAT4_EQ(max, 4.f, 5.f, 2.f, 7.f);
|
||||
|
||||
EXPECT_FLOAT4_EQ(Clamp(a, Float4(-12.f, 2.f, 9.f, 3.f), c), .5f, 2.f, 6.f,
|
||||
3.f);
|
||||
|
||||
EXPECT_TRUE(a < c);
|
||||
EXPECT_TRUE(a <= c);
|
||||
EXPECT_TRUE(c <= c);
|
||||
|
||||
EXPECT_TRUE(c > a);
|
||||
EXPECT_TRUE(c >= a);
|
||||
EXPECT_TRUE(a >= a);
|
||||
|
||||
EXPECT_TRUE(a == a);
|
||||
EXPECT_TRUE(a != b);
|
||||
|
||||
EXPECT_TRUE(Compare(a, a, 0.f));
|
||||
EXPECT_TRUE(Compare(c, d, .2f));
|
||||
EXPECT_FALSE(Compare(c, d, .05f));
|
||||
}
|
||||
|
||||
TEST(VectorComparison3, ozz_math) {
|
||||
const Float3 a(.5f, -1.f, 2.f);
|
||||
const Float3 b(4.f, 5.f, -6.f);
|
||||
const Float3 c(4.f, 5.f, 6.f);
|
||||
const Float3 d(4.f, 5.f, 6.1f);
|
||||
|
||||
const Float3 min = Min(a, b);
|
||||
EXPECT_FLOAT3_EQ(min, .5f, -1.f, -6.f);
|
||||
|
||||
const Float3 max = Max(a, b);
|
||||
EXPECT_FLOAT3_EQ(max, 4.f, 5.f, 2.f);
|
||||
|
||||
EXPECT_FLOAT3_EQ(Clamp(a, Float3(-12.f, 2.f, 9.f), c), .5f, 2.f, 6.f);
|
||||
|
||||
EXPECT_TRUE(a < c);
|
||||
EXPECT_TRUE(a <= c);
|
||||
EXPECT_TRUE(c <= c);
|
||||
|
||||
EXPECT_TRUE(c > a);
|
||||
EXPECT_TRUE(c >= a);
|
||||
EXPECT_TRUE(a >= a);
|
||||
|
||||
EXPECT_TRUE(a == a);
|
||||
EXPECT_TRUE(a != b);
|
||||
|
||||
EXPECT_TRUE(Compare(a, a, 1e-3f));
|
||||
EXPECT_TRUE(Compare(c, d, .2f));
|
||||
EXPECT_FALSE(Compare(c, d, .05f));
|
||||
}
|
||||
|
||||
TEST(VectorComparison2, ozz_math) {
|
||||
const Float2 a(.5f, 1.f);
|
||||
const Float2 b(4.f, -5.f);
|
||||
const Float2 c(4.f, 5.f);
|
||||
const Float2 d(4.f, 5.1f);
|
||||
|
||||
const Float2 min = Min(a, b);
|
||||
EXPECT_FLOAT2_EQ(min, .5f, -5.f);
|
||||
|
||||
const Float2 max = Max(a, b);
|
||||
EXPECT_FLOAT2_EQ(max, 4.f, 1.f);
|
||||
|
||||
EXPECT_FLOAT2_EQ(Clamp(a, Float2(-12.f, 2.f), c), .5f, 2.f);
|
||||
|
||||
EXPECT_TRUE(a < c);
|
||||
EXPECT_TRUE(a <= c);
|
||||
EXPECT_TRUE(c <= c);
|
||||
|
||||
EXPECT_TRUE(c > a);
|
||||
EXPECT_TRUE(c >= a);
|
||||
EXPECT_TRUE(a >= a);
|
||||
|
||||
EXPECT_TRUE(a == a);
|
||||
EXPECT_TRUE(a != b);
|
||||
|
||||
EXPECT_TRUE(Compare(a, a, 1e-3f));
|
||||
EXPECT_TRUE(Compare(c, d, .2f));
|
||||
EXPECT_FALSE(Compare(c, d, .05f));
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
add_executable(test_memory
|
||||
allocator_tests.cc)
|
||||
target_link_libraries(test_memory
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_memory COMMAND test_memory)
|
||||
set_target_properties(test_memory PROPERTIES FOLDER "ozz/tests/base")
|
||||
|
||||
add_executable(test_unique_ptr
|
||||
unique_ptr_tests.cc)
|
||||
target_link_libraries(test_unique_ptr
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_unique_ptr COMMAND test_unique_ptr)
|
||||
set_target_properties(test_unique_ptr PROPERTIES FOLDER "ozz/tests/base")
|
||||
@@ -0,0 +1,154 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/maths/math_ex.h"
|
||||
#include "ozz/base/memory/allocator.h"
|
||||
|
||||
TEST(Allocate, Memory) {
|
||||
void* p = ozz::memory::default_allocator()->Allocate(12, 1024);
|
||||
EXPECT_TRUE(p != nullptr);
|
||||
EXPECT_TRUE(ozz::IsAligned(p, 1024));
|
||||
|
||||
// Fills allocated memory.
|
||||
memset(p, 0, 12);
|
||||
|
||||
ozz::memory::default_allocator()->Deallocate(p);
|
||||
}
|
||||
|
||||
TEST(MallocCompliance, Memory) {
|
||||
{ // Allocating 0 byte gives a valid pointer.
|
||||
void* p = ozz::memory::default_allocator()->Allocate(0, 1024);
|
||||
EXPECT_TRUE(p != nullptr);
|
||||
ozz::memory::default_allocator()->Deallocate(p);
|
||||
}
|
||||
|
||||
{ // Freeing of a nullptr pointer is valid.
|
||||
ozz::memory::default_allocator()->Deallocate(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
struct AlignedInts {
|
||||
AlignedInts() {
|
||||
for (int i = 0; i < array_size; ++i) {
|
||||
array[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
AlignedInts(int _i0) {
|
||||
array[0] = _i0;
|
||||
for (int i = 1; i < array_size; ++i) {
|
||||
array[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
AlignedInts(int _i0, int _i1) {
|
||||
array[0] = _i0;
|
||||
array[1] = _i1;
|
||||
for (int i = 2; i < array_size; ++i) {
|
||||
array[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
AlignedInts(int _i0, int _i1, int _i2) {
|
||||
array[0] = _i0;
|
||||
array[1] = _i1;
|
||||
array[2] = _i2;
|
||||
for (int i = 3; i < array_size; ++i) {
|
||||
array[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
static const int array_size = 517;
|
||||
alignas(64) int array[array_size];
|
||||
};
|
||||
|
||||
TEST(NewDelete, Memory) {
|
||||
AlignedInts* ai0 = ozz::New<AlignedInts>();
|
||||
ASSERT_TRUE(ai0 != nullptr);
|
||||
for (int i = 0; i < ai0->array_size; ++i) {
|
||||
EXPECT_EQ(ai0->array[i], i);
|
||||
}
|
||||
ozz::Delete(ai0);
|
||||
|
||||
AlignedInts* ai1 = ozz::New<AlignedInts>(46);
|
||||
ASSERT_TRUE(ai1 != nullptr);
|
||||
EXPECT_EQ(ai1->array[0], 46);
|
||||
for (int i = 1; i < ai1->array_size; ++i) {
|
||||
EXPECT_EQ(ai1->array[i], i);
|
||||
}
|
||||
ozz::Delete(ai1);
|
||||
|
||||
AlignedInts* ai2 = ozz::New<AlignedInts>(46, 69);
|
||||
ASSERT_TRUE(ai2 != nullptr);
|
||||
EXPECT_EQ(ai2->array[0], 46);
|
||||
EXPECT_EQ(ai2->array[1], 69);
|
||||
for (int i = 2; i < ai2->array_size; ++i) {
|
||||
EXPECT_EQ(ai2->array[i], i);
|
||||
}
|
||||
ozz::Delete(ai2);
|
||||
|
||||
AlignedInts* ai3 = ozz::New<AlignedInts>(46, 69, 58);
|
||||
ASSERT_TRUE(ai3 != nullptr);
|
||||
EXPECT_EQ(ai3->array[0], 46);
|
||||
EXPECT_EQ(ai3->array[1], 69);
|
||||
EXPECT_EQ(ai3->array[2], 58);
|
||||
for (int i = 3; i < ai3->array_size; ++i) {
|
||||
EXPECT_EQ(ai3->array[i], i);
|
||||
}
|
||||
ozz::Delete(ai3);
|
||||
}
|
||||
|
||||
class TestAllocator : public ozz::memory::Allocator {
|
||||
public:
|
||||
TestAllocator() : hard_coded_address_(&hard_coded_address_) {}
|
||||
|
||||
void* hard_coded_address() const { return hard_coded_address_; }
|
||||
|
||||
private:
|
||||
virtual void* Allocate(size_t _size, size_t _alignment) {
|
||||
(void)_size;
|
||||
(void)_alignment;
|
||||
return hard_coded_address_;
|
||||
}
|
||||
virtual void Deallocate(void* _block) { (void)_block; }
|
||||
|
||||
void* hard_coded_address_;
|
||||
};
|
||||
|
||||
TEST(AllocatorOverride, Memory) {
|
||||
TestAllocator test_allocator;
|
||||
ozz::memory::Allocator* previous =
|
||||
ozz::memory::SetDefaulAllocator(&test_allocator);
|
||||
ozz::memory::Allocator* current = ozz::memory::default_allocator();
|
||||
|
||||
void* alloc = current->Allocate(1, 1);
|
||||
EXPECT_EQ(alloc, test_allocator.hard_coded_address());
|
||||
current->Deallocate(alloc);
|
||||
|
||||
EXPECT_EQ(ozz::memory::SetDefaulAllocator(previous), current);
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/base/memory/unique_ptr.h"
|
||||
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
TEST(Construction, unique_ptr) {
|
||||
{ const ozz::unique_ptr<int> pi; }
|
||||
{ const ozz::unique_ptr<int> pi(ozz::New<int>()); }
|
||||
}
|
||||
|
||||
TEST(Reset, unique_ptr) {
|
||||
{
|
||||
ozz::unique_ptr<int> pi;
|
||||
pi.reset(nullptr);
|
||||
|
||||
pi.reset(ozz::New<int>());
|
||||
}
|
||||
{
|
||||
ozz::unique_ptr<int> pi(ozz::New<int>());
|
||||
pi.reset(ozz::New<int>());
|
||||
pi.reset(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
struct A {
|
||||
int i;
|
||||
};
|
||||
|
||||
TEST(Dereference, unique_ptr) {
|
||||
{
|
||||
const ozz::unique_ptr<int> pi;
|
||||
EXPECT_TRUE(pi.get() == nullptr);
|
||||
EXPECT_FALSE(pi);
|
||||
}
|
||||
{
|
||||
const ozz::unique_ptr<int> pi(ozz::New<int>(46));
|
||||
EXPECT_EQ(*pi, 46);
|
||||
EXPECT_TRUE(pi.get() != nullptr);
|
||||
EXPECT_TRUE(pi);
|
||||
}
|
||||
{
|
||||
const ozz::unique_ptr<A> pa(ozz::New<A>());
|
||||
pa->i = 46;
|
||||
EXPECT_EQ((*pa).i, 46);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Bool, unique_ptr) {
|
||||
{
|
||||
const ozz::unique_ptr<int> pi;
|
||||
EXPECT_TRUE(!pi);
|
||||
EXPECT_FALSE(pi);
|
||||
}
|
||||
{
|
||||
const ozz::unique_ptr<int> pi(ozz::New<int>(46));
|
||||
EXPECT_FALSE(!pi);
|
||||
EXPECT_TRUE(pi);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Swap, unique_ptr) {
|
||||
{
|
||||
int* i = ozz::New<int>(46);
|
||||
ozz::unique_ptr<int> pi;
|
||||
ozz::unique_ptr<int> pii(i);
|
||||
EXPECT_TRUE(pi.get() == nullptr);
|
||||
EXPECT_TRUE(pii.get() == i);
|
||||
|
||||
pi.swap(pii);
|
||||
EXPECT_TRUE(pii.get() == nullptr);
|
||||
EXPECT_TRUE(pi.get() == i);
|
||||
}
|
||||
{
|
||||
int* i = ozz::New<int>(46);
|
||||
ozz::unique_ptr<int> pi;
|
||||
ozz::unique_ptr<int> pii(i);
|
||||
EXPECT_TRUE(pi.get() == nullptr);
|
||||
EXPECT_TRUE(pii.get() == i);
|
||||
|
||||
swap(pi, pii);
|
||||
EXPECT_TRUE(pii.get() == nullptr);
|
||||
EXPECT_TRUE(pi.get() == i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Release, unique_ptr) {
|
||||
int* i = ozz::New<int>(46);
|
||||
{
|
||||
ozz::unique_ptr<int> pi(i);
|
||||
int* ri = pi.release();
|
||||
EXPECT_EQ(i, ri);
|
||||
}
|
||||
ozz::Delete(i);
|
||||
}
|
||||
|
||||
struct B : public A {};
|
||||
|
||||
TEST(Upcast, unique_ptr) {
|
||||
ozz::unique_ptr<A> a = ozz::unique_ptr<B>();
|
||||
a = ozz::unique_ptr<B>();
|
||||
}
|
||||
|
||||
TEST(make_unique, unique_ptr) {
|
||||
{ // No argument
|
||||
EXPECT_TRUE(ozz::make_unique<int>());
|
||||
EXPECT_EQ(*ozz::make_unique<int>(), 0);
|
||||
}
|
||||
|
||||
{ // 1 argument
|
||||
EXPECT_TRUE(ozz::make_unique<int>(46));
|
||||
EXPECT_EQ(*ozz::make_unique<int>(46), 46);
|
||||
}
|
||||
|
||||
{ // N arguments
|
||||
auto p5 =
|
||||
ozz::make_unique<std::tuple<int, int, int, int, int>>(0, 1, 2, 3, 4);
|
||||
EXPECT_TRUE(p5);
|
||||
EXPECT_EQ(*p5, std::make_tuple(0, 1, 2, 3, 4));
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/platform.h"
|
||||
|
||||
TEST(StaticAssertion, Platform) {
|
||||
static_assert(2 == 2, "Must compile.");
|
||||
// static_assert(1 == 2, "Must not compile.);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Declares a structure that should have at least 8 bytes aligned.
|
||||
struct Misc {
|
||||
double d;
|
||||
char c;
|
||||
int i;
|
||||
};
|
||||
|
||||
// Declares an aligned structure in order to test OZZ_ALIGN and AlignOf.
|
||||
struct Aligned {
|
||||
alignas(128) char c;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(Alignment, Platform) {
|
||||
static_assert(alignof(char) == 1, "Unexpected type size");
|
||||
static_assert(alignof(double) == 8, "Unexpected type size");
|
||||
static_assert(alignof(Misc) == 8, "Unexpected type size");
|
||||
static_assert(alignof(Aligned) == 128, "Unexpected type size");
|
||||
|
||||
Aligned alined;
|
||||
EXPECT_EQ(reinterpret_cast<uintptr_t>(&alined) & (128 - 1), 0u);
|
||||
}
|
||||
|
||||
TEST(IntegerAlignment, Platform) {
|
||||
{
|
||||
short s = 0x1234;
|
||||
int aligned_s = ozz::Align(s, 128);
|
||||
EXPECT_TRUE(aligned_s == 0x1280);
|
||||
EXPECT_TRUE(ozz::IsAligned(aligned_s, 128));
|
||||
}
|
||||
|
||||
{
|
||||
int i = 0x00a01234;
|
||||
int aligned_i = ozz::Align(i, 1024);
|
||||
EXPECT_TRUE(aligned_i == 0x00a01400);
|
||||
EXPECT_TRUE(ozz::IsAligned(aligned_i, 1024));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PointerAlignment, Platform) {
|
||||
void* p = reinterpret_cast<void*>(0x00a01234);
|
||||
void* aligned_p = ozz::Align(p, 1024);
|
||||
EXPECT_TRUE(aligned_p == reinterpret_cast<void*>(0x00a01400));
|
||||
EXPECT_TRUE(ozz::IsAligned(aligned_p, 1024));
|
||||
}
|
||||
|
||||
TEST(TypeSize, Platform) {
|
||||
// Checks sizes.
|
||||
static_assert(CHAR_BIT == 8, "Unexpected type size");
|
||||
static_assert(sizeof(int8_t) == 1, "Unexpected type size");
|
||||
static_assert(sizeof(uint8_t) == 1, "Unexpected type size");
|
||||
static_assert(sizeof(int16_t) == 2, "Unexpected type size");
|
||||
static_assert(sizeof(uint16_t) == 2, "Unexpected type size");
|
||||
static_assert(sizeof(int32_t) == 4, "Unexpected type size");
|
||||
static_assert(sizeof(uint32_t) == 4, "Unexpected type size");
|
||||
static_assert(sizeof(int64_t) == 8, "Unexpected type size");
|
||||
static_assert(sizeof(uint64_t) == 8, "Unexpected type size");
|
||||
static_assert(sizeof(intptr_t) == sizeof(int*), "Unexpected type size");
|
||||
static_assert(sizeof(uintptr_t) == sizeof(unsigned int*),
|
||||
"Unexpected type size");
|
||||
|
||||
// Checks signs. Right shift maintains sign bit for signed types, and fills
|
||||
// with 0 for unsigned types.
|
||||
static_assert((int8_t(-1) >> 1) == -1, "Unexpected type sign");
|
||||
static_assert((int16_t(-1) >> 1) == -1, "Unexpected type sign");
|
||||
static_assert((int32_t(-1) >> 1) == -1, "Unexpected type sign");
|
||||
static_assert((int64_t(-1) >> 1) == -1, "Unexpected type sign");
|
||||
static_assert((uint8_t(-1) >> 1) == 0x7f, "Unexpected type sign");
|
||||
static_assert((uint16_t(-1) >> 1) == 0x7fff, "Unexpected type sign");
|
||||
static_assert((uint32_t(-1) >> 1) == 0x7fffffff, "Unexpected type sign");
|
||||
static_assert((uint64_t(-1) >> 1) == 0x7fffffffffffffffLL,
|
||||
"Unexpected type sign");
|
||||
|
||||
// Assumes that an "int" is at least 32 bits.
|
||||
static_assert(sizeof(int) >= 4, "Unexpected type size");
|
||||
|
||||
// "char" type is used to manipulate bytes. Can be signed or unsigned.
|
||||
static_assert(sizeof(char) == 1, "Unexpected type size");
|
||||
}
|
||||
|
||||
TEST(DebudNDebug, Platform) {
|
||||
OZZ_IF_DEBUG(assert(true));
|
||||
OZZ_IF_NDEBUG(assert(false));
|
||||
}
|
||||
|
||||
TEST(ArraySize, Platform) {
|
||||
int ai[46];
|
||||
(void)ai;
|
||||
static_assert(OZZ_ARRAY_SIZE(ai) == 46, "Unexpected array size");
|
||||
|
||||
char ac[] = "forty six";
|
||||
(void)ac;
|
||||
static_assert(OZZ_ARRAY_SIZE(ac) == 10, "Unexpected array size");
|
||||
}
|
||||
|
||||
TEST(StrMatch, Platform) {
|
||||
EXPECT_TRUE(ozz::strmatch("a", "a"));
|
||||
EXPECT_FALSE(ozz::strmatch("a", "b"));
|
||||
EXPECT_TRUE(ozz::strmatch("a", "a*"));
|
||||
EXPECT_FALSE(ozz::strmatch("a", "a?"));
|
||||
EXPECT_TRUE(ozz::strmatch("ab", "a?"));
|
||||
EXPECT_TRUE(ozz::strmatch("ab", "?b"));
|
||||
EXPECT_FALSE(ozz::strmatch("ab", "a"));
|
||||
EXPECT_TRUE(ozz::strmatch("ab", "ab"));
|
||||
EXPECT_TRUE(ozz::strmatch("", ""));
|
||||
EXPECT_TRUE(ozz::strmatch("", "*"));
|
||||
EXPECT_FALSE(ozz::strmatch("", "?"));
|
||||
EXPECT_FALSE(ozz::strmatch("ab", ""));
|
||||
EXPECT_FALSE(ozz::strmatch("ab", "?"));
|
||||
EXPECT_TRUE(ozz::strmatch("ab", "??"));
|
||||
EXPECT_TRUE(ozz::strmatch("a*b", "a*b"));
|
||||
EXPECT_TRUE(ozz::strmatch("a*b", "a?b"));
|
||||
EXPECT_TRUE(ozz::strmatch("ab", "ab*"));
|
||||
EXPECT_TRUE(ozz::strmatch("ab", "a*"));
|
||||
EXPECT_TRUE(ozz::strmatch("ab", "*b"));
|
||||
EXPECT_TRUE(ozz::strmatch("ab", "a*b"));
|
||||
EXPECT_TRUE(ozz::strmatch("acb", "a*b"));
|
||||
EXPECT_FALSE(ozz::strmatch("abc", "a*b"));
|
||||
EXPECT_TRUE(ozz::strmatch("abcdef", "a*c*"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "a*c.*"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "abc.def"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "abc.def***"));
|
||||
EXPECT_FALSE(ozz::strmatch("abc.def", "abc.def?"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "abc?def"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "a*c?*"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "a*.*"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "a*c.*e?"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "*"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "*.*"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "???.???"));
|
||||
EXPECT_FALSE(ozz::strmatch("abc.def", "??.???"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "*??.???"));
|
||||
EXPECT_TRUE(ozz::strmatch("abc.def", "*??.??*"));
|
||||
EXPECT_TRUE(
|
||||
ozz::strmatch("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
"aaaaaaaaaaaaaaa",
|
||||
"*a*??????a?????????a???????????????"));
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
#include "ozz/base/span.h"
|
||||
|
||||
TEST(Span, Platform) {
|
||||
const size_t kSize = 46;
|
||||
int i = 20;
|
||||
int ai[kSize];
|
||||
const size_t array_size = OZZ_ARRAY_SIZE(ai);
|
||||
|
||||
ozz::span<int> empty;
|
||||
EXPECT_TRUE(empty.begin() == nullptr);
|
||||
EXPECT_EQ(empty.size(), 0u);
|
||||
EXPECT_EQ(empty.size_bytes(), 0u);
|
||||
|
||||
EXPECT_ASSERTION(empty[46], "Index out of range.");
|
||||
|
||||
ozz::span<int> single(i);
|
||||
EXPECT_TRUE(single.begin() == &i);
|
||||
EXPECT_EQ(single.size(), 1u);
|
||||
EXPECT_EQ(single.size_bytes(), sizeof(i));
|
||||
|
||||
EXPECT_ASSERTION(single[46], "Index out of range.");
|
||||
|
||||
ozz::span<int> cs1(ai, ai + array_size);
|
||||
EXPECT_EQ(cs1.begin(), ai);
|
||||
EXPECT_EQ(cs1.size(), array_size);
|
||||
EXPECT_EQ(cs1.size_bytes(), sizeof(ai));
|
||||
|
||||
// Re-inint
|
||||
ozz::span<int> reinit;
|
||||
reinit = ai;
|
||||
EXPECT_EQ(reinit.begin(), ai);
|
||||
EXPECT_EQ(reinit.size(), array_size);
|
||||
EXPECT_EQ(reinit.size_bytes(), sizeof(ai));
|
||||
|
||||
// Clear
|
||||
reinit = {};
|
||||
EXPECT_EQ(reinit.size(), 0u);
|
||||
EXPECT_EQ(reinit.size_bytes(), 0u);
|
||||
|
||||
cs1[12] = 46;
|
||||
EXPECT_EQ(cs1[12], 46);
|
||||
EXPECT_ASSERTION(cs1[46], "Index out of range.");
|
||||
|
||||
ozz::span<int> cs2(ai, array_size);
|
||||
EXPECT_EQ(cs2.begin(), ai);
|
||||
EXPECT_EQ(cs2.size(), array_size);
|
||||
EXPECT_EQ(cs2.size_bytes(), sizeof(ai));
|
||||
|
||||
ozz::span<int> carray(ai);
|
||||
EXPECT_EQ(carray.begin(), ai);
|
||||
EXPECT_EQ(carray.size(), array_size);
|
||||
EXPECT_EQ(carray.size_bytes(), sizeof(ai));
|
||||
|
||||
ozz::span<int> copy(cs2);
|
||||
EXPECT_EQ(cs2.begin(), copy.begin());
|
||||
EXPECT_EQ(cs2.size_bytes(), copy.size_bytes());
|
||||
|
||||
ozz::span<const int> const_copy(cs2);
|
||||
EXPECT_EQ(cs2.begin(), const_copy.begin());
|
||||
EXPECT_EQ(cs2.size_bytes(), const_copy.size_bytes());
|
||||
|
||||
EXPECT_EQ(cs2[12], 46);
|
||||
EXPECT_ASSERTION(cs2[46], "Index out of range.");
|
||||
|
||||
// Invalid range
|
||||
EXPECT_ASSERTION(ozz::span<int>(ai, ai - array_size), "Invalid range.");
|
||||
}
|
||||
|
||||
TEST(SpanAsBytes, Platform) {
|
||||
const size_t kSize = 46;
|
||||
int ai[kSize];
|
||||
{
|
||||
ozz::span<int> si(ai);
|
||||
EXPECT_EQ(si.size(), kSize);
|
||||
|
||||
ozz::span<const char> ab = as_bytes(si);
|
||||
EXPECT_EQ(ab.size(), kSize * sizeof(int));
|
||||
|
||||
ozz::span<char> awb = as_writable_bytes(si);
|
||||
EXPECT_EQ(awb.size(), kSize * sizeof(int));
|
||||
}
|
||||
|
||||
{ // mutable char
|
||||
char ac[kSize];
|
||||
ozz::span<char> sc(ac);
|
||||
EXPECT_EQ(sc.size(), kSize);
|
||||
|
||||
ozz::span<const char> ab = as_bytes(sc);
|
||||
EXPECT_EQ(ab.size(), sc.size());
|
||||
|
||||
ozz::span<char> awbc = as_writable_bytes(sc);
|
||||
EXPECT_EQ(awbc.size(), sc.size());
|
||||
}
|
||||
{ // const
|
||||
ozz::span<const int> si(ai);
|
||||
EXPECT_EQ(si.size(), kSize);
|
||||
|
||||
ozz::span<const char> ab = as_bytes(si);
|
||||
EXPECT_EQ(ab.size(), kSize * sizeof(int));
|
||||
}
|
||||
|
||||
// const char
|
||||
{
|
||||
const char ac[kSize] = {};
|
||||
ozz::span<const char> sc(ac);
|
||||
EXPECT_EQ(sc.size(), kSize);
|
||||
|
||||
ozz::span<const char> ab = as_bytes(sc);
|
||||
EXPECT_EQ(ab.size(), sc.size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SpanFill, Platform) {
|
||||
alignas(alignof(int)) char abuffer[16];
|
||||
ozz::span<char> src(abuffer);
|
||||
|
||||
ozz::span<int> ispan1 = ozz::fill_span<int>(src, 3);
|
||||
EXPECT_EQ(ispan1.size(), 3u);
|
||||
ozz::span<int> ispan2 = ozz::fill_span<int>(src, 1);
|
||||
EXPECT_EQ(ispan2.size(), 1u);
|
||||
EXPECT_TRUE(src.empty());
|
||||
EXPECT_ASSERTION(ozz::fill_span<int>(src, 1), "Invalid range.");
|
||||
|
||||
// Bad aligment
|
||||
src = ozz::make_span(abuffer);
|
||||
|
||||
ozz::span<char> cspan = ozz::fill_span<char>(src, 1);
|
||||
EXPECT_EQ(cspan.size(), 1u);
|
||||
EXPECT_ASSERTION(ozz::fill_span<int>(src, 1), "Invalid alignment.");
|
||||
}
|
||||
|
||||
TEST(SpanRangeLoop, Platform) {
|
||||
const size_t kSize = 46;
|
||||
size_t ai[kSize];
|
||||
|
||||
// non const
|
||||
ozz::span<size_t> si = ozz::make_span(ai);
|
||||
size_t i = 0;
|
||||
for (size_t& li : si) {
|
||||
li = i++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(i, kSize);
|
||||
|
||||
// const
|
||||
ozz::span<const size_t> sci = si;
|
||||
i = 0;
|
||||
for (const size_t& li : sci) {
|
||||
EXPECT_EQ(i, li);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
add_subdirectory(runtime)
|
||||
@@ -0,0 +1,21 @@
|
||||
# skinning_job_tests
|
||||
add_executable(test_skinning_job
|
||||
skinning_job_tests.cc)
|
||||
target_link_libraries(test_skinning_job
|
||||
ozz_geometry
|
||||
ozz_base
|
||||
gtest)
|
||||
set_target_properties(test_skinning_job PROPERTIES FOLDER "ozz/tests/geometry")
|
||||
add_test(NAME test_skinning_job COMMAND test_skinning_job)
|
||||
|
||||
# ozz_geometry fuse tests
|
||||
set_source_files_properties(${PROJECT_BINARY_DIR}/src_fused/ozz_geometry.cc PROPERTIES GENERATED 1)
|
||||
add_executable(test_fuse_geometry
|
||||
skinning_job_tests.cc
|
||||
${PROJECT_BINARY_DIR}/src_fused/ozz_geometry.cc)
|
||||
add_dependencies(test_fuse_geometry BUILD_FUSE_ozz_geometry)
|
||||
target_link_libraries(test_fuse_geometry
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_fuse_geometry COMMAND test_fuse_geometry)
|
||||
set_target_properties(test_fuse_geometry PROPERTIES FOLDER "ozz/tests/geometry")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
add_executable(test_options options_tests.cc)
|
||||
target_link_libraries(test_options
|
||||
ozz_options
|
||||
ozz_base
|
||||
gtest)
|
||||
add_test(NAME test_options COMMAND test_options)
|
||||
set_target_properties(test_options PROPERTIES FOLDER "ozz/tests/options")
|
||||
|
||||
add_executable(test_options_registration options_registration_tests.cc)
|
||||
target_link_libraries(test_options_registration
|
||||
ozz_options
|
||||
gtest)
|
||||
add_test(NAME test_options_registration COMMAND test_options_registration)
|
||||
set_target_properties(test_options_registration PROPERTIES FOLDER "ozz/tests/options")
|
||||
|
||||
add_executable(test_options_registration_empty options_registration_empty_tests.cc)
|
||||
target_link_libraries(test_options_registration_empty
|
||||
ozz_options
|
||||
gtest)
|
||||
add_test(NAME test_options_registration_empty COMMAND test_options_registration_empty)
|
||||
set_target_properties(test_options_registration_empty PROPERTIES FOLDER "ozz/tests/options")
|
||||
|
||||
# ozz_options fuse tests
|
||||
set_source_files_properties(${PROJECT_BINARY_DIR}/src_fused/ozz_options.cc PROPERTIES GENERATED 1)
|
||||
add_executable(test_fuse_options
|
||||
options_registration_tests.cc
|
||||
${PROJECT_BINARY_DIR}/src_fused/ozz_options.cc)
|
||||
add_dependencies(test_fuse_options BUILD_FUSE_ozz_options)
|
||||
target_include_directories(test_fuse_options
|
||||
PUBLIC "${PROJECT_SOURCE_DIR}/include")
|
||||
target_link_libraries(test_fuse_options
|
||||
gtest)
|
||||
add_test(NAME test_fuse_options COMMAND test_fuse_options)
|
||||
set_target_properties(test_fuse_options PROPERTIES FOLDER "ozz/tests/options")
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/options/options.h"
|
||||
|
||||
#include "ozz/base/platform.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
TEST(EmptyRegistration, Options) {
|
||||
{ // No argument is specified.
|
||||
const char* argv[] = {"test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(ozz::options::ParseCommandLine(argc, argv, "1.0",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kSuccess);
|
||||
}
|
||||
|
||||
{ // An invalid argument is specified.
|
||||
const char* argv[] = {"test.exe", "--something"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ_LOG(ozz::options::ParseCommandLine(argc, argv, "1.0",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kExitFailure, std::cout, "Usage");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BuiltInEmptyRegistration, Options) {
|
||||
{ // Built-in version.
|
||||
const char* argv[] = {"test.exe", "--version"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ_LOG(ozz::options::ParseCommandLine(argc, argv, "1.046",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kExitSuccess, std::cout, "1.046");
|
||||
}
|
||||
{ // Built-in help.
|
||||
const char* argv[] = {"test.exe", "--help"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ_LOG(ozz::options::ParseCommandLine(argc, argv, "1.046",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kExitSuccess, std::cout, "--version");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BuiltInArgv0, Options) {
|
||||
const char* argv[] = {"c:/a path/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(ozz::options::ParseCommandLine(argc, argv, "1.046",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kSuccess);
|
||||
|
||||
EXPECT_STREQ(ozz::options::ParsedExecutablePath().c_str(), "c:/a path/");
|
||||
EXPECT_STREQ(ozz::options::ParsedExecutableName(), "test.exe");
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/options/options.h"
|
||||
|
||||
#include "ozz/base/platform.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
// Register some options.
|
||||
OZZ_OPTIONS_DECLARE_BOOL(a_bool, "A bool", false, false);
|
||||
OZZ_OPTIONS_DECLARE_INT(a_int, "A int", 46, false);
|
||||
OZZ_OPTIONS_DECLARE_FLOAT(a_float, "A float", 46.f, false);
|
||||
OZZ_OPTIONS_DECLARE_STRING(a_string, "A string", "Forty six", false);
|
||||
|
||||
TEST(AutoRegistration, Options) {
|
||||
{ // No argument is specified.
|
||||
const char* argv[] = {"c:/a path/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(ozz::options::ParseCommandLine(argc, argv, "1.0",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kSuccess);
|
||||
|
||||
EXPECT_FALSE(OPTIONS_a_bool);
|
||||
EXPECT_EQ(OPTIONS_a_int, 46);
|
||||
EXPECT_FLOAT_EQ(OPTIONS_a_float, 46.f);
|
||||
EXPECT_STREQ(OPTIONS_a_string, "Forty six");
|
||||
}
|
||||
|
||||
{ // An argument is specified.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--a_bool"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(ozz::options::ParseCommandLine(argc, argv, "1.0",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kSuccess);
|
||||
|
||||
EXPECT_TRUE(OPTIONS_a_bool);
|
||||
OPTIONS_a_bool.RestoreDefault();
|
||||
|
||||
EXPECT_EQ(OPTIONS_a_int, 46);
|
||||
EXPECT_FLOAT_EQ(OPTIONS_a_float, 46.f);
|
||||
EXPECT_STREQ(OPTIONS_a_string, "Forty six");
|
||||
}
|
||||
|
||||
{ // An invalid argument is specified.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--a_boolean"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ_LOG(ozz::options::ParseCommandLine(argc, argv, "1.0",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kExitFailure, std::cout, "--a_bool=<bool>");
|
||||
|
||||
EXPECT_FALSE(OPTIONS_a_bool);
|
||||
EXPECT_EQ(OPTIONS_a_int, 46);
|
||||
EXPECT_FLOAT_EQ(OPTIONS_a_float, 46.f);
|
||||
EXPECT_STREQ(OPTIONS_a_string, "Forty six");
|
||||
}
|
||||
|
||||
{ // An invalid argument value is specified.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--a_bool=46"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ_LOG(ozz::options::ParseCommandLine(argc, argv, "1.0",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kExitFailure, std::cout, "--a_bool=<bool>");
|
||||
|
||||
EXPECT_FALSE(OPTIONS_a_bool);
|
||||
EXPECT_EQ(OPTIONS_a_int, 46);
|
||||
EXPECT_FLOAT_EQ(OPTIONS_a_float, 46.f);
|
||||
EXPECT_STREQ(OPTIONS_a_string, "Forty six");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BuiltInRegistration, Options) {
|
||||
{ // Built-in version.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--version"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ_LOG(ozz::options::ParseCommandLine(argc, argv, "1.046",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kExitSuccess, std::cout, "1.046");
|
||||
}
|
||||
{ // Built-in help.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--help"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ_LOG(ozz::options::ParseCommandLine(argc, argv, "1.046",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kExitSuccess, std::cout,
|
||||
"AutoRegistration test");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BuiltInArgv0, Options) {
|
||||
const char* argv[] = {"c:/a path/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(ozz::options::ParseCommandLine(argc, argv, "1.046",
|
||||
"AutoRegistration test"),
|
||||
ozz::options::kSuccess);
|
||||
|
||||
EXPECT_STREQ(ozz::options::ParsedExecutablePath().c_str(), "c:/a path/");
|
||||
EXPECT_STREQ(ozz::options::ParsedExecutableName(), "test.exe");
|
||||
}
|
||||
@@ -0,0 +1,877 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include "ozz/options/options.h"
|
||||
|
||||
#include "ozz/base/platform.h"
|
||||
|
||||
#include "ozz/base/containers/string.h"
|
||||
#include "ozz/base/containers/vector.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ozz/base/gtest_helper.h"
|
||||
|
||||
TEST(Registration, Options) {
|
||||
{ // Parser construction/destruction.
|
||||
ozz::options::Parser parser;
|
||||
}
|
||||
|
||||
{ // Automatic un-registration
|
||||
ozz::options::BoolOption b1("b1", "1st option", false, false);
|
||||
ozz::options::Parser parser;
|
||||
ozz::options::BoolOption b2("b2", "2nd option", false, false);
|
||||
EXPECT_TRUE(parser.RegisterOption(&b1));
|
||||
EXPECT_TRUE(parser.RegisterOption(&b2));
|
||||
}
|
||||
|
||||
{ // Registration/un-registration.
|
||||
ozz::options::Parser parser;
|
||||
|
||||
ozz::options::BoolOption b1("b1", "1st option", false, false);
|
||||
EXPECT_TRUE(parser.RegisterOption(&b1));
|
||||
|
||||
ozz::options::BoolOption b2("b2", nullptr, false, false);
|
||||
EXPECT_TRUE(parser.RegisterOption(&b2));
|
||||
|
||||
EXPECT_FALSE(parser.UnregisterOption(&b2));
|
||||
EXPECT_TRUE(parser.UnregisterOption(&b1));
|
||||
}
|
||||
|
||||
{ // Invalid registration.
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_FALSE(parser.RegisterOption(nullptr));
|
||||
|
||||
ozz::options::BoolOption bnull(nullptr, "A option", false, false);
|
||||
EXPECT_FALSE(parser.RegisterOption(&bnull));
|
||||
|
||||
ozz::options::BoolOption bversion("version", nullptr, false, false);
|
||||
EXPECT_FALSE(parser.RegisterOption(&bversion));
|
||||
|
||||
ozz::options::BoolOption bhelp("help", nullptr, false, false);
|
||||
EXPECT_FALSE(parser.RegisterOption(&bhelp));
|
||||
}
|
||||
|
||||
{ // Invalid registration (too much options).
|
||||
ozz::options::Parser parser;
|
||||
|
||||
// Needs to pre-allocate vectors to avoid objects to move in memory.
|
||||
ozz::vector<ozz::options::BoolOption> options;
|
||||
options.reserve(parser.max_options() + 1);
|
||||
ozz::vector<ozz::string> names;
|
||||
names.reserve(parser.max_options());
|
||||
|
||||
// Registers the maximum allowed options.
|
||||
for (int i = 0; i < parser.max_options(); ++i) {
|
||||
std::stringstream str;
|
||||
str << "option " << i << std::ends;
|
||||
names.push_back(str.str().c_str());
|
||||
options.push_back(
|
||||
ozz::options::BoolOption(names[i].c_str(), nullptr, false, false));
|
||||
EXPECT_TRUE(parser.RegisterOption(&options.back()));
|
||||
}
|
||||
|
||||
// Registers "too much" options.
|
||||
options.push_back(ozz::options::BoolOption("too much", nullptr, false, false));
|
||||
EXPECT_FALSE(parser.RegisterOption(&options.back()));
|
||||
|
||||
// Unregisters all options.
|
||||
for (int i = parser.max_options(); i > 0; --i) {
|
||||
EXPECT_EQ(parser.UnregisterOption(&options[i]), i == 0);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Invalid registration (registers twice).
|
||||
ozz::options::BoolOption b("b", "A option", false, false);
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&b));
|
||||
EXPECT_FALSE(parser.RegisterOption(&b));
|
||||
EXPECT_TRUE(parser.UnregisterOption(&b));
|
||||
}
|
||||
|
||||
{ // Invalid un-registration (un-registers twice).
|
||||
ozz::options::BoolOption b("b", "A option", false, false);
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&b));
|
||||
EXPECT_TRUE(parser.UnregisterOption(&b));
|
||||
EXPECT_FALSE(parser.UnregisterOption(&b));
|
||||
}
|
||||
|
||||
{ // Invalid un-registration (nullptr option).
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_FALSE(parser.UnregisterOption(nullptr));
|
||||
}
|
||||
|
||||
{ // Duplicated option names.
|
||||
ozz::options::Parser parser;
|
||||
ozz::options::BoolOption b1("boolean", nullptr, false, false);
|
||||
EXPECT_TRUE(parser.RegisterOption(&b1));
|
||||
|
||||
ozz::options::BoolOption b2("boolean", nullptr, false, false);
|
||||
EXPECT_FALSE(parser.RegisterOption(&b2));
|
||||
|
||||
EXPECT_FALSE(parser.UnregisterOption(&b2));
|
||||
EXPECT_TRUE(parser.UnregisterOption(&b1));
|
||||
EXPECT_FALSE(parser.UnregisterOption(&b2));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ParseErrors, Options) {
|
||||
const char* argv[] = {""};
|
||||
|
||||
ozz::options::Parser parser;
|
||||
ozz::options::BoolOption bool_option("boolean", "", true, false);
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
|
||||
EXPECT_EQ(parser.Parse(0, nullptr), ozz::options::kExitFailure);
|
||||
EXPECT_EQ(parser.Parse(0, argv), ozz::options::kExitFailure);
|
||||
|
||||
// Expects empty path and name by default.
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "");
|
||||
EXPECT_STREQ(parser.executable_name(), "");
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&bool_option));
|
||||
}
|
||||
|
||||
TEST(ParseInvalid, Options) {
|
||||
const char* argv[] = {"c:/a path/test.exe", "--bool"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
ozz::options::BoolOption bool_option("boolean", "", true, false);
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitFailure, std::cout,
|
||||
"Usage");
|
||||
|
||||
// Expects empty path and name by default
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "c:/a path/");
|
||||
EXPECT_STREQ(parser.executable_name(), "test.exe");
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&bool_option));
|
||||
}
|
||||
|
||||
TEST(OptionDefault, Options) {
|
||||
{ // First argument is mandatory
|
||||
ozz::options::Parser parser;
|
||||
const char* argv[] = {"c:/a path/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
}
|
||||
|
||||
{
|
||||
ozz::options::BoolOption boption("bt", "A option", true, false);
|
||||
EXPECT_TRUE(boption);
|
||||
ozz::options::IntOption ioption("int_option", "A option", 46, false);
|
||||
EXPECT_EQ(ioption, 46);
|
||||
ozz::options::FloatOption foption("float_option", "A option", 46.f, false);
|
||||
EXPECT_FLOAT_EQ(foption, 46.f);
|
||||
ozz::options::StringOption soption("string_option", "A option", "forty six",
|
||||
false);
|
||||
EXPECT_STREQ(soption, "forty six");
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&boption));
|
||||
EXPECT_TRUE(parser.RegisterOption(&ioption));
|
||||
EXPECT_TRUE(parser.RegisterOption(&foption));
|
||||
EXPECT_TRUE(parser.RegisterOption(&soption));
|
||||
|
||||
const char* argv[] = {"c:/a path/test.exe"}; // No valid option is set.
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
|
||||
EXPECT_TRUE(boption);
|
||||
EXPECT_FALSE(parser.UnregisterOption(&boption));
|
||||
EXPECT_EQ(ioption, 46);
|
||||
EXPECT_EQ(ioption, ioption.default_value());
|
||||
EXPECT_FALSE(parser.UnregisterOption(&ioption));
|
||||
EXPECT_FLOAT_EQ(foption, 46.f);
|
||||
EXPECT_FLOAT_EQ(foption, foption.default_value());
|
||||
EXPECT_FALSE(parser.UnregisterOption(&foption));
|
||||
EXPECT_STREQ(soption, "forty six");
|
||||
EXPECT_EQ(soption, soption.default_value());
|
||||
EXPECT_TRUE(parser.UnregisterOption(&soption));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Parsing, Options) {
|
||||
ozz::options::BoolOption bool_option("bool", "", false, false);
|
||||
EXPECT_FALSE(bool_option);
|
||||
ozz::options::IntOption int_option("int", "", 27, false);
|
||||
EXPECT_EQ(int_option, 27);
|
||||
ozz::options::IntOption int_sic_option("sic", "rip", 58, false);
|
||||
EXPECT_EQ(int_sic_option, 58);
|
||||
ozz::options::FloatOption float_option("float", "", 99.f, false);
|
||||
EXPECT_FLOAT_EQ(float_option, 99.f);
|
||||
ozz::options::StringOption string_option("string", "", "twenty six", false);
|
||||
EXPECT_STREQ(string_option, "twenty six");
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_option));
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_sic_option));
|
||||
EXPECT_TRUE(parser.RegisterOption(&float_option));
|
||||
EXPECT_TRUE(parser.RegisterOption(&string_option));
|
||||
|
||||
const char* argv[] = {"c:/a path/test.exe",
|
||||
"--bool",
|
||||
"", // empty argument isn't a error
|
||||
"--float=46.00000",
|
||||
"", // empty argument isn't a error
|
||||
"--string=forty six",
|
||||
"--int=46",
|
||||
"", // empty argument isn't a error
|
||||
"--", // "--" hides all further options.
|
||||
"--sic=0"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_EQ(int_sic_option, 58);
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_STREQ(string_option, "forty six");
|
||||
|
||||
EXPECT_FALSE(parser.UnregisterOption(&bool_option));
|
||||
EXPECT_FALSE(parser.UnregisterOption(&float_option));
|
||||
EXPECT_FALSE(parser.UnregisterOption(&string_option));
|
||||
EXPECT_FALSE(parser.UnregisterOption(&int_sic_option));
|
||||
EXPECT_TRUE(parser.UnregisterOption(&int_option));
|
||||
}
|
||||
|
||||
TEST(BuiltPath, Options) {
|
||||
ozz::options::Parser parser;
|
||||
|
||||
// Expects empty path and name by default.
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "");
|
||||
EXPECT_STREQ(parser.executable_name(), "");
|
||||
|
||||
{ // Empty path.
|
||||
const char* argv[] = {""};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "");
|
||||
EXPECT_STREQ(parser.executable_name(), "");
|
||||
}
|
||||
|
||||
{ // Executable name only.
|
||||
const char* argv[] = {"test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "");
|
||||
EXPECT_STREQ(parser.executable_name(), "test.exe");
|
||||
}
|
||||
|
||||
{ // Executable path only.
|
||||
const char* argv[] = {"path/"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "path/");
|
||||
EXPECT_STREQ(parser.executable_name(), "");
|
||||
}
|
||||
|
||||
{ // Full path.
|
||||
const char* argv[] = {"dir1/dir2/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "dir1/dir2/");
|
||||
EXPECT_STREQ(parser.executable_name(), "test.exe");
|
||||
}
|
||||
|
||||
{ // Full path strting with /.
|
||||
const char* argv[] = {"/dir1/dir2/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "/dir1/dir2/");
|
||||
EXPECT_STREQ(parser.executable_name(), "test.exe");
|
||||
}
|
||||
|
||||
{ // Full path with \ separator.
|
||||
const char* argv[] = {"dir1\\dir2\\test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "dir1\\dir2\\");
|
||||
EXPECT_STREQ(parser.executable_name(), "test.exe");
|
||||
}
|
||||
|
||||
{ // Full path with spaces.
|
||||
const char* argv[] = {"dir 1\\dir 2\\test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "dir 1\\dir 2\\");
|
||||
EXPECT_STREQ(parser.executable_name(), "test.exe");
|
||||
}
|
||||
|
||||
{ // Full path with mixed / and \ separator.
|
||||
const char* argv[] = {"dir1/dir2\\test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "dir1/dir2\\");
|
||||
EXPECT_STREQ(parser.executable_name(), "test.exe");
|
||||
}
|
||||
|
||||
{ // Full path with mixed / and \ separator.
|
||||
const char* argv[] = {"dir1\\dir2/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_STREQ(parser.executable_path().c_str(), "dir1\\dir2/");
|
||||
EXPECT_STREQ(parser.executable_name(), "test.exe");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BuiltInOptions, Options) {
|
||||
{ // Default built-in values.
|
||||
const char* argv[] = {"c:/a path/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
}
|
||||
|
||||
{ // Default built-in command line error.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--option", "--version"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kExitFailure);
|
||||
}
|
||||
|
||||
{ // Other built-in command line error.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--version", "--option"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kExitFailure);
|
||||
}
|
||||
|
||||
{ // Multiple built-in options.
|
||||
const char* argv[] = {"c:/a path/test.exe",
|
||||
"--help"
|
||||
"--version"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kExitFailure);
|
||||
}
|
||||
|
||||
{ // Hidden built-in options are ignored.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--", "--version"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
}
|
||||
|
||||
{ // Valid built-in "version" option.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--version"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
parser.set_version("1.2.3");
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitSuccess,
|
||||
std::cout, "version 1.2.3");
|
||||
}
|
||||
|
||||
{ // Valid built-in "version" option, with required arguments.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--version"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
ozz::options::BoolOption bool_option("bool", "", false, true);
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
parser.set_version("1.2.3");
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitSuccess,
|
||||
std::cout, "version 1.2.3");
|
||||
EXPECT_TRUE(parser.UnregisterOption(&bool_option));
|
||||
}
|
||||
|
||||
{ // Valid built-in "version" option.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--version=true"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
parser.set_version("1.2.3");
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitSuccess,
|
||||
std::cout, "version 1.2.3");
|
||||
}
|
||||
|
||||
{ // Valid negative built-in "version" option.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--noversion"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
parser.set_version("1.2.3");
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
}
|
||||
|
||||
{ // -- End option scanning after the built in argument.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--version", "--", "something"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
parser.set_version("1.2.3");
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitSuccess,
|
||||
std::cout, "version 1.2.3");
|
||||
}
|
||||
|
||||
{ // Built-in help version option is exclusive.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--version", "--something"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
ozz::options::BoolOption something("something", nullptr, false, false);
|
||||
EXPECT_TRUE(parser.RegisterOption(&something));
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitFailure,
|
||||
std::cout, "exclusive");
|
||||
}
|
||||
|
||||
{ // Valid built-in "help" option.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--help"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitSuccess,
|
||||
std::cout, "Usage");
|
||||
}
|
||||
|
||||
{ // Built-in help option is exclusive.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--help", "--something"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
ozz::options::Parser parser;
|
||||
ozz::options::BoolOption something("something", nullptr, false, false);
|
||||
EXPECT_TRUE(parser.RegisterOption(&something));
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitFailure,
|
||||
std::cout, "exclusive");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RequiredOption, Options) {
|
||||
ozz::options::BoolOption bool_option("bool", "", false, false);
|
||||
EXPECT_FALSE(bool_option);
|
||||
ozz::options::IntOption int_required_option("int", "", 27, true);
|
||||
EXPECT_EQ(int_required_option, 27);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_required_option));
|
||||
|
||||
{ // Required flag missing.
|
||||
const char* argv[] = {"c:/a path/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitFailure,
|
||||
std::cout, "Required");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_EQ(int_required_option, 27);
|
||||
}
|
||||
{ // Required flag specified.
|
||||
const char* required_argv[] = {"c:/a path/test.exe", "--int=46"};
|
||||
const int required_argc = OZZ_ARRAY_SIZE(required_argv);
|
||||
EXPECT_EQ(parser.Parse(required_argc, required_argv),
|
||||
ozz::options::kSuccess);
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_EQ(int_required_option, 46);
|
||||
}
|
||||
{ // Validate help output
|
||||
EXPECT_LOG(parser.Help(), std::cout, " \\[--int\\]");
|
||||
EXPECT_LOG(parser.Help(), std::cout, " --bool");
|
||||
}
|
||||
|
||||
EXPECT_FALSE(parser.UnregisterOption(&bool_option));
|
||||
EXPECT_TRUE(parser.UnregisterOption(&int_required_option));
|
||||
}
|
||||
|
||||
TEST(DuplicatedOption, Options) {
|
||||
ozz::options::BoolOption bool_option("bool", "", false, false);
|
||||
EXPECT_FALSE(bool_option);
|
||||
ozz::options::IntOption int_option("int", "", 27, false);
|
||||
EXPECT_EQ(int_option, 27);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_option));
|
||||
|
||||
{ // Duplicated flags.
|
||||
const char* duplicated_argv[] = {"c:/a path/test.exe", "--int=46",
|
||||
"--int=47"};
|
||||
const int duplicated_argc = OZZ_ARRAY_SIZE(duplicated_argv);
|
||||
EXPECT_EQ(parser.Parse(duplicated_argc, duplicated_argv),
|
||||
ozz::options::kExitFailure);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(parser.UnregisterOption(&bool_option));
|
||||
EXPECT_TRUE(parser.UnregisterOption(&int_option));
|
||||
}
|
||||
|
||||
namespace {
|
||||
static bool TestFn(const ozz::options::Option& _option, int /*_argc*/) {
|
||||
const ozz::options::IntOption& option =
|
||||
static_cast<const ozz::options::IntOption&>(_option);
|
||||
bool valid = option == 46;
|
||||
if (!valid) {
|
||||
std::cout << "46 only option" << std::endl;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(ValidateFnOption, Options) {
|
||||
ozz::options::IntOption int_option("int", "", 58, false, &TestFn);
|
||||
EXPECT_EQ(int_option, 58);
|
||||
ozz::options::IntOption int_required_option("required_int", "", 58, true,
|
||||
&TestFn);
|
||||
EXPECT_EQ(int_required_option, 58);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_option));
|
||||
|
||||
{ // Validate function failed.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--int=27"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitFailure,
|
||||
std::cout, "46 only option");
|
||||
EXPECT_EQ(int_option, 27);
|
||||
}
|
||||
{ // Validate function passed.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--int=46"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_EQ(int_option, 46);
|
||||
}
|
||||
EXPECT_TRUE(parser.UnregisterOption(&int_option));
|
||||
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_required_option));
|
||||
{ // Validate function failed (required option).
|
||||
const char* argv[] = {"c:/a path/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitFailure,
|
||||
std::cout, "Required");
|
||||
EXPECT_EQ(int_required_option, 58);
|
||||
}
|
||||
{ // Validate function failed (required option).
|
||||
const char* argv[] = {"c:/a path/test.exe", "--required_int=27"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitFailure,
|
||||
std::cout, "46 only option");
|
||||
EXPECT_EQ(int_required_option, 27);
|
||||
}
|
||||
{ // Validate function success (required option).
|
||||
const char* argv[] = {"c:/a path/test.exe", "--required_int=46"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_EQ(int_required_option, 46);
|
||||
}
|
||||
EXPECT_TRUE(parser.UnregisterOption(&int_required_option));
|
||||
}
|
||||
|
||||
TEST(MultipleCall, Options) {
|
||||
ozz::options::BoolOption bool_option("bool", "", false, false);
|
||||
EXPECT_FALSE(bool_option);
|
||||
ozz::options::IntOption int_required_option("int", "", 27, true);
|
||||
EXPECT_EQ(int_required_option, 27);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_required_option));
|
||||
|
||||
{ // Required flag.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--int=46"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ(parser.Parse(argc, argv), ozz::options::kSuccess);
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_EQ(int_required_option, 46);
|
||||
}
|
||||
{ // Built-in flag.
|
||||
const char* argv[] = {"c:/a path/test.exe", "--help"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitSuccess,
|
||||
std::cout, "Usage");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_EQ(int_required_option, 27);
|
||||
}
|
||||
{ // Required flag missing.
|
||||
const char* argv[] = {"c:/a path/test.exe"};
|
||||
const int argc = OZZ_ARRAY_SIZE(argv);
|
||||
EXPECT_EQ_LOG(parser.Parse(argc, argv), ozz::options::kExitFailure,
|
||||
std::cout, "Required");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_EQ(int_required_option, 27);
|
||||
}
|
||||
}
|
||||
|
||||
// Internal test EXPECT_ macro. Ensures parse failed, display usage and exit.
|
||||
#define EXPECT_FLAG_INVALID(_parser, _arg) \
|
||||
do { \
|
||||
const char* argv[] = {"c:/a path/test.exe", _arg}; \
|
||||
const int argc = OZZ_ARRAY_SIZE(argv); \
|
||||
EXPECT_EQ_LOG(_parser.Parse(argc, argv), ozz::options::kExitFailure, \
|
||||
std::cout, "Usage"); \
|
||||
} while (void(0), 0)
|
||||
|
||||
// Internal test EXPECT_ macro. Ensures parse succeed.
|
||||
#define EXPECT_FLAG_VALID(_parser, _arg) \
|
||||
do { \
|
||||
const char* argv[] = {"c:/a path/test.exe", _arg}; \
|
||||
const int argc = OZZ_ARRAY_SIZE(argv); \
|
||||
EXPECT_EQ(_parser.Parse(argc, argv), ozz::options::kSuccess); \
|
||||
} while (void(0), 0)
|
||||
|
||||
TEST(ParseBool, Options) {
|
||||
{ // Invalid options
|
||||
ozz::options::BoolOption bool_option("option", "", false, false);
|
||||
EXPECT_FALSE(bool_option);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
|
||||
EXPECT_FLAG_INVALID(parser, "option");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_INVALID(parser, "-option");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_INVALID(parser, "--option_value");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_INVALID(parser, "--fla");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_INVALID(parser, "--option_value");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_INVALID(parser, "--option true");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_INVALID(parser, "--nooption=");
|
||||
EXPECT_FALSE(bool_option);
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&bool_option));
|
||||
}
|
||||
|
||||
{ // Valid true values.
|
||||
ozz::options::BoolOption bool_option("option", "", false, false);
|
||||
EXPECT_FALSE(bool_option);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
|
||||
EXPECT_FLAG_VALID(parser, "--option");
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=yes");
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=true");
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=1");
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option= true");
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--Option=1");
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=y");
|
||||
EXPECT_TRUE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=t");
|
||||
EXPECT_TRUE(bool_option);
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&bool_option));
|
||||
}
|
||||
|
||||
{ // Valid false values.
|
||||
ozz::options::BoolOption bool_option("option", "", true, false);
|
||||
EXPECT_TRUE(bool_option);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&bool_option));
|
||||
|
||||
EXPECT_FLAG_VALID(parser, "--nooption");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=no");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=false");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=0");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option= \tno");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=n");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--option=f");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--Nooption");
|
||||
EXPECT_FALSE(bool_option);
|
||||
EXPECT_FLAG_VALID(parser, "--nooption");
|
||||
EXPECT_FALSE(bool_option);
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&bool_option));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ParseFloat, Options) {
|
||||
{ // Invalid options
|
||||
ozz::options::FloatOption float_option("option", "", 46.f, false);
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&float_option));
|
||||
|
||||
EXPECT_FLAG_INVALID(parser, "option");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_INVALID(parser, "-option");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_INVALID(parser, "--option");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_INVALID(parser, "--fla");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_INVALID(parser, "--option=");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_INVALID(parser, "--option 46");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&float_option));
|
||||
}
|
||||
|
||||
{ // Valid options
|
||||
ozz::options::FloatOption float_option("option", "", 0.f, false);
|
||||
EXPECT_FLOAT_EQ(float_option, 0.f);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&float_option));
|
||||
|
||||
EXPECT_FLAG_VALID(parser, "--option=46.000");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_VALID(parser, "--option=0.0046");
|
||||
EXPECT_FLOAT_EQ(float_option, .0046f);
|
||||
EXPECT_FLAG_VALID(parser, "--option=.0046");
|
||||
EXPECT_FLOAT_EQ(float_option, .0046f);
|
||||
EXPECT_FLAG_VALID(parser, "--option=460e-1");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_VALID(parser, "--option=-46");
|
||||
EXPECT_FLOAT_EQ(float_option, -46.f);
|
||||
EXPECT_FLAG_VALID(parser, "--option= 046");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_VALID(parser, "--option= \t 046");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
EXPECT_FLAG_VALID(parser, "--Option=46E0");
|
||||
EXPECT_FLOAT_EQ(float_option, 46.f);
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&float_option));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ParseInt, Options) {
|
||||
{ // Invalid options
|
||||
ozz::options::IntOption int_option("option", "", 46, false);
|
||||
EXPECT_EQ(int_option, 46);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_option));
|
||||
|
||||
EXPECT_FLAG_INVALID(parser, "option");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_INVALID(parser, "-option");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_INVALID(parser, "--option");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_INVALID(parser, "--fla");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_INVALID(parser, "--option=");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_INVALID(parser, "--option 99");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_INVALID(parser, "--option=99.0");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&int_option));
|
||||
}
|
||||
|
||||
{ // Valid options
|
||||
ozz::options::IntOption int_option("option", "", 0, false);
|
||||
EXPECT_EQ(int_option, 0);
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&int_option));
|
||||
|
||||
EXPECT_FLAG_VALID(parser, "--option=46");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_VALID(parser, "--option=0046");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_VALID(parser, "--option=-46");
|
||||
EXPECT_EQ(int_option, -46);
|
||||
EXPECT_FLAG_VALID(parser, "--option= 46");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_VALID(parser, "--option=\t46");
|
||||
EXPECT_EQ(int_option, 46);
|
||||
EXPECT_FLAG_VALID(parser, "--Option=-46");
|
||||
EXPECT_EQ(int_option, -46);
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&int_option));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ParseString, Options) {
|
||||
{ // Invalid options
|
||||
ozz::options::StringOption string_option("option", "", "default", false);
|
||||
EXPECT_STREQ(string_option, "default");
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&string_option));
|
||||
|
||||
EXPECT_FLAG_INVALID(parser, "option");
|
||||
EXPECT_STREQ(string_option, "default");
|
||||
EXPECT_FLAG_INVALID(parser, "-option");
|
||||
EXPECT_STREQ(string_option, "default");
|
||||
EXPECT_FLAG_INVALID(parser, "--option");
|
||||
EXPECT_STREQ(string_option, "default");
|
||||
EXPECT_FLAG_INVALID(parser, "--fla=twenty seven");
|
||||
EXPECT_STREQ(string_option, "default");
|
||||
EXPECT_FLAG_INVALID(parser, "--option forty six");
|
||||
EXPECT_STREQ(string_option, "default");
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&string_option));
|
||||
}
|
||||
|
||||
{ // Valid options
|
||||
ozz::options::StringOption string_option("option", "", "default", false);
|
||||
EXPECT_STREQ(string_option, "default");
|
||||
|
||||
ozz::options::Parser parser;
|
||||
EXPECT_TRUE(parser.RegisterOption(&string_option));
|
||||
|
||||
EXPECT_FLAG_VALID(parser, "--option=");
|
||||
EXPECT_STREQ(string_option, "");
|
||||
EXPECT_FLAG_VALID(parser, "--option=forty-six");
|
||||
EXPECT_STREQ(string_option, "forty-six");
|
||||
EXPECT_FLAG_VALID(parser, "--option=forty six");
|
||||
EXPECT_STREQ(string_option, "forty six");
|
||||
EXPECT_FLAG_VALID(parser, "--option=\"forty six\"");
|
||||
EXPECT_STREQ(string_option, "\"forty six\"");
|
||||
EXPECT_FLAG_VALID(parser, "--option= forty six");
|
||||
EXPECT_STREQ(string_option, "forty six");
|
||||
EXPECT_FLAG_VALID(parser, "--option=\t forty six");
|
||||
EXPECT_STREQ(string_option, "forty six");
|
||||
EXPECT_FLAG_VALID(parser, "--option=46");
|
||||
EXPECT_STREQ(string_option, "46");
|
||||
EXPECT_FLAG_VALID(parser, "--optiOn=forty-six");
|
||||
EXPECT_STREQ(string_option, "forty-six");
|
||||
|
||||
EXPECT_TRUE(parser.UnregisterOption(&string_option));
|
||||
}
|
||||
}
|
||||
|
||||
#undef EXPECT_FLAG_INVALID
|
||||
#undef EXPECT_FLAG_VALID
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required (VERSION 3.0)
|
||||
|
||||
# Defines the project's name
|
||||
project(ozz_sub)
|
||||
|
||||
# ozz requires C++11
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Activates unit tests
|
||||
enable_testing()
|
||||
|
||||
# Includes ozz-animation as a sub directory, using an arbitrary "ozz-animation/" binary output folder.
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../.." ozz-animation/)
|
||||
|
||||
# Then link with ozz libraries as any other cmake target.
|
||||
add_executable(test_sub_project
|
||||
test_sub_project.cc)
|
||||
target_link_libraries(test_sub_project
|
||||
ozz_animation)
|
||||
|
||||
# Adds some tests
|
||||
add_test(NAME test_sub_project COMMAND test_sub_project)
|
||||
if(TARGET fbx2ozz)
|
||||
add_test(NAME test_sub_fbx2ozz COMMAND fbx2ozz "--version")
|
||||
endif()
|
||||
+1
@@ -0,0 +1 @@
|
||||
Files in this folder are used to test building ozz as a sub project, aka included (add_subdirectory) from the CMakeLists.txt of another project.
|
||||
@@ -0,0 +1,41 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a //
|
||||
// copy of this software and associated documentation files (the "Software"), //
|
||||
// to deal in the Software without restriction, including without limitation //
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
|
||||
// and/or sell copies of the Software, and to permit persons to whom the //
|
||||
// Software is furnished to do so, subject to the following conditions: //
|
||||
// //
|
||||
// The above copyright notice and this permission notice shall be included in //
|
||||
// all copies or substantial portions of the Software. //
|
||||
// //
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
|
||||
// DEALINGS IN THE SOFTWARE. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
// Includes a file from ozz
|
||||
#include "ozz/animation/runtime/skeleton.h"
|
||||
|
||||
int main(int argc, char const* argv[]) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
// Instantaiates an object from ozz library.
|
||||
ozz::animation::Skeleton skeleton;
|
||||
|
||||
return skeleton.num_joints() == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
Reference in New Issue
Block a user