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