1 // Copyright 2017 The Draco Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 #include "draco/animation/keyframe_animation.h"
16 #include "draco/animation/keyframe_animation_decoder.h"
17 #include "draco/animation/keyframe_animation_encoder.h"
18 #include "draco/core/draco_test_base.h"
19 #include "draco/core/draco_test_utils.h"
20
21 namespace draco {
22
23 class KeyframeAnimationEncodingTest : public ::testing::Test {
24 protected:
KeyframeAnimationEncodingTest()25 KeyframeAnimationEncodingTest() {}
26
CreateAndAddTimestamps(int32_t num_frames)27 bool CreateAndAddTimestamps(int32_t num_frames) {
28 timestamps_.resize(num_frames);
29 for (int i = 0; i < timestamps_.size(); ++i)
30 timestamps_[i] = static_cast<draco::KeyframeAnimation::TimestampType>(i);
31 return keyframe_animation_.SetTimestamps(timestamps_);
32 }
33
CreateAndAddAnimationData(int32_t num_frames,uint32_t num_components)34 int32_t CreateAndAddAnimationData(int32_t num_frames,
35 uint32_t num_components) {
36 // Create and add animation data with.
37 animation_data_.resize(num_frames * num_components);
38 for (int i = 0; i < animation_data_.size(); ++i)
39 animation_data_[i] = static_cast<float>(i);
40 return keyframe_animation_.AddKeyframes(draco::DT_FLOAT32, num_components,
41 animation_data_);
42 }
43
44 template <int num_components_t>
CompareAnimationData(const KeyframeAnimation & animation0,const KeyframeAnimation & animation1,bool quantized)45 void CompareAnimationData(const KeyframeAnimation &animation0,
46 const KeyframeAnimation &animation1,
47 bool quantized) {
48 ASSERT_EQ(animation0.num_frames(), animation1.num_frames());
49 ASSERT_EQ(animation0.num_animations(), animation1.num_animations());
50
51 if (quantized) {
52 // TODO(hemmer) : Add test for stable quantization.
53 // Quantization will result in slightly different values.
54 // Skip comparing values.
55 return;
56 }
57
58 // Compare time stamp.
59 const auto timestamp_att0 = animation0.timestamps();
60 const auto timestamp_att1 = animation0.timestamps();
61 for (int i = 0; i < animation0.num_frames(); ++i) {
62 std::array<float, 1> att_value0;
63 std::array<float, 1> att_value1;
64 ASSERT_TRUE((timestamp_att0->GetValue<float, 1>(
65 draco::AttributeValueIndex(i), &att_value0)));
66 ASSERT_TRUE((timestamp_att1->GetValue<float, 1>(
67 draco::AttributeValueIndex(i), &att_value1)));
68 ASSERT_FLOAT_EQ(att_value0[0], att_value1[0]);
69 }
70
71 for (int animation_id = 1; animation_id < animation0.num_animations();
72 ++animation_id) {
73 // Compare keyframe data.
74 const auto keyframe_att0 = animation0.keyframes(animation_id);
75 const auto keyframe_att1 = animation1.keyframes(animation_id);
76 ASSERT_EQ(keyframe_att0->num_components(),
77 keyframe_att1->num_components());
78 for (int i = 0; i < animation0.num_frames(); ++i) {
79 std::array<float, num_components_t> att_value0;
80 std::array<float, num_components_t> att_value1;
81 ASSERT_TRUE((keyframe_att0->GetValue<float, num_components_t>(
82 draco::AttributeValueIndex(i), &att_value0)));
83 ASSERT_TRUE((keyframe_att1->GetValue<float, num_components_t>(
84 draco::AttributeValueIndex(i), &att_value1)));
85 for (int j = 0; j < att_value0.size(); ++j) {
86 ASSERT_FLOAT_EQ(att_value0[j], att_value1[j]);
87 }
88 }
89 }
90 }
91
92 template <int num_components_t>
TestKeyframeAnimationEncoding()93 void TestKeyframeAnimationEncoding() {
94 TestKeyframeAnimationEncoding<num_components_t>(false);
95 }
96
97 template <int num_components_t>
TestKeyframeAnimationEncoding(bool quantized)98 void TestKeyframeAnimationEncoding(bool quantized) {
99 // Encode animation class.
100 draco::EncoderBuffer buffer;
101 draco::KeyframeAnimationEncoder encoder;
102 EncoderOptions options = EncoderOptions::CreateDefaultOptions();
103 if (quantized) {
104 // Set quantization for timestamps.
105 options.SetAttributeInt(0, "quantization_bits", 20);
106 // Set quantization for keyframes.
107 for (int i = 1; i <= keyframe_animation_.num_animations(); ++i) {
108 options.SetAttributeInt(i, "quantization_bits", 20);
109 }
110 }
111
112 ASSERT_TRUE(
113 encoder.EncodeKeyframeAnimation(keyframe_animation_, options, &buffer)
114 .ok());
115
116 draco::DecoderBuffer dec_decoder;
117 draco::KeyframeAnimationDecoder decoder;
118 DecoderBuffer dec_buffer;
119 dec_buffer.Init(buffer.data(), buffer.size());
120
121 // Decode animation class.
122 std::unique_ptr<KeyframeAnimation> decoded_animation(
123 new KeyframeAnimation());
124 DecoderOptions dec_options;
125 ASSERT_TRUE(
126 decoder.Decode(dec_options, &dec_buffer, decoded_animation.get()).ok());
127
128 // Verify if animation before and after compression is identical.
129 CompareAnimationData<num_components_t>(keyframe_animation_,
130 *decoded_animation, quantized);
131 }
132
133 draco::KeyframeAnimation keyframe_animation_;
134 std::vector<draco::KeyframeAnimation::TimestampType> timestamps_;
135 std::vector<float> animation_data_;
136 };
137
TEST_F(KeyframeAnimationEncodingTest,OneComponent)138 TEST_F(KeyframeAnimationEncodingTest, OneComponent) {
139 const int num_frames = 1;
140 ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
141 ASSERT_EQ(CreateAndAddAnimationData(num_frames, 1), 1);
142 TestKeyframeAnimationEncoding<1>();
143 }
144
TEST_F(KeyframeAnimationEncodingTest,ManyComponents)145 TEST_F(KeyframeAnimationEncodingTest, ManyComponents) {
146 const int num_frames = 100;
147 ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
148 ASSERT_EQ(CreateAndAddAnimationData(num_frames, 100), 1);
149 TestKeyframeAnimationEncoding<100>();
150 }
151
TEST_F(KeyframeAnimationEncodingTest,ManyComponentsWithQuantization)152 TEST_F(KeyframeAnimationEncodingTest, ManyComponentsWithQuantization) {
153 const int num_frames = 100;
154 ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
155 ASSERT_EQ(CreateAndAddAnimationData(num_frames, 4), 1);
156 // Test compression with quantization.
157 TestKeyframeAnimationEncoding<4>(true);
158 }
159
TEST_F(KeyframeAnimationEncodingTest,MultipleAnimations)160 TEST_F(KeyframeAnimationEncodingTest, MultipleAnimations) {
161 const int num_frames = 5;
162 ASSERT_TRUE(CreateAndAddTimestamps(num_frames));
163 ASSERT_EQ(CreateAndAddAnimationData(num_frames, 3), 1);
164 ASSERT_EQ(CreateAndAddAnimationData(num_frames, 3), 2);
165 TestKeyframeAnimationEncoding<3>();
166 }
167
168 } // namespace draco
169