6c92d6a3ec24eb02fed9a5ccf33a610532eb09ae
[platform/core/uifw/dali-toolkit.git] / dali-scene-loader / public-api / facial-animation-loader.cpp
1 /*\r
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  * http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  *\r
16  */\r
17 \r
18 // FILE HEADER\r
19 #include <dali-scene-loader/public-api/facial-animation-loader.h>\r
20 \r
21 // EXTERNAL INCLUDES\r
22 #include <sstream>\r
23 \r
24 // INTERNAL INCLUDES\r
25 #include <dali-scene-loader/internal/json-reader.h>\r
26 #include <dali-scene-loader/public-api/blend-shape-details.h>\r
27 #include <dali-scene-loader/public-api/utils.h>\r
28 \r
29 namespace js = json;\r
30 \r
31 namespace Dali\r
32 {\r
33 namespace\r
34 {\r
35 const float MILLISECONDS_TO_SECONDS = 0.001f;\r
36 \r
37 struct BlendShape\r
38 {\r
39   std::vector<std::vector<float>> mKeys;\r
40   std::string_view                mNodeName;\r
41   uint32_t                        mNumberOfMorphTarget;\r
42   std::string_view                mVersion;\r
43   std::string_view                mFullName;\r
44   std::vector<std::string_view>   mMorphNames;\r
45 };\r
46 \r
47 struct FacialAnimation\r
48 {\r
49   std::string_view        mName;\r
50   std::vector<BlendShape> mBlendShapes;\r
51   std::string_view        mVersion;\r
52   uint32_t                mNumberOfShapes;\r
53   std::vector<uint32_t>   mTime;\r
54   uint32_t                mNumberOfFrames;\r
55 };\r
56 \r
57 std::vector<std::vector<float>> ReadBlendShapeKeys(const json_value_s& j)\r
58 {\r
59   auto&                           jo = js::Cast<json_array_s>(j);\r
60   std::vector<std::vector<float>> result;\r
61 \r
62   result.reserve(jo.length);\r
63 \r
64   auto i = jo.start;\r
65   while(i)\r
66   {\r
67     result.push_back(std::move(js::Read::Array<float, js::Read::Number>(*i->value)));\r
68     i = i->next;\r
69   }\r
70 \r
71   return result;\r
72 }\r
73 \r
74 const auto BLEND_SHAPE_READER = std::move(js::Reader<BlendShape>()\r
75                                             .Register(*js::MakeProperty("key", ReadBlendShapeKeys, &BlendShape::mKeys))\r
76                                             .Register(*new js::Property<BlendShape, std::string_view>("name", js::Read::StringView, &BlendShape::mNodeName))\r
77                                             .Register(*js::MakeProperty("morphtarget", js::Read::Number<uint32_t>, &BlendShape::mNumberOfMorphTarget))\r
78                                             .Register(*new js::Property<BlendShape, std::string_view>("blendShapeVersion", js::Read::StringView, &BlendShape::mVersion))\r
79                                             .Register(*new js::Property<BlendShape, std::string_view>("fullName", js::Read::StringView, &BlendShape::mFullName))\r
80                                             .Register(*js::MakeProperty("morphname", js::Read::Array<std::string_view, js::Read::StringView>, &BlendShape::mMorphNames)));\r
81 \r
82 const auto FACIAL_ANIMATION_READER = std::move(js::Reader<FacialAnimation>()\r
83                                                  .Register(*new js::Property<FacialAnimation, std::string_view>("name", js::Read::StringView, &FacialAnimation::mName))\r
84                                                  .Register(*js::MakeProperty("blendShapes", js::Read::Array<BlendShape, js::ObjectReader<BlendShape>::Read>, &FacialAnimation::mBlendShapes))\r
85                                                  .Register(*new js::Property<FacialAnimation, std::string_view>("version", js::Read::StringView, &FacialAnimation::mVersion))\r
86                                                  .Register(*js::MakeProperty("shapesAmount", js::Read::Number<uint32_t>, &FacialAnimation::mNumberOfShapes))\r
87                                                  .Register(*js::MakeProperty("time", js::Read::Array<uint32_t, js::Read::Number>, &FacialAnimation::mTime))\r
88                                                  .Register(*js::MakeProperty("frames", js::Read::Number<uint32_t>, &FacialAnimation::mNumberOfFrames)));\r
89 \r
90 } // unnamed namespace\r
91 \r
92 namespace SceneLoader\r
93 {\r
94 AnimationDefinition LoadFacialAnimation(const std::string& url)\r
95 {\r
96   bool failed = false;\r
97   auto js     = LoadTextFile(url.c_str(), &failed);\r
98   if(failed)\r
99   {\r
100     ExceptionFlinger(ASSERT_LOCATION) << "Failed to load " << url << ".";\r
101   }\r
102 \r
103   json::unique_ptr root(json_parse(js.c_str(), js.size()));\r
104   if(!root)\r
105   {\r
106     ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse " << url << ".";\r
107   }\r
108 \r
109   static bool setObjectReaders = true;\r
110   if(setObjectReaders)\r
111   {\r
112     // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change.\r
113     js::SetObjectReader(BLEND_SHAPE_READER);\r
114     setObjectReaders = false;\r
115   }\r
116 \r
117   auto& rootObj = js::Cast<json_object_s>(*root);\r
118 \r
119   FacialAnimation facialAnimation;\r
120   FACIAL_ANIMATION_READER.Read(rootObj, facialAnimation);\r
121 \r
122   AnimationDefinition animationDefinition;\r
123   animationDefinition.mName     = std::string(facialAnimation.mName.data());\r
124   animationDefinition.mDuration = MILLISECONDS_TO_SECONDS * static_cast<float>(facialAnimation.mTime[facialAnimation.mNumberOfFrames - 1u]);\r
125 \r
126   // Calculate the number of animated properties.\r
127   uint32_t numberOfAnimatedProperties = 0u;\r
128   for(const auto& blendShape : facialAnimation.mBlendShapes)\r
129   {\r
130     numberOfAnimatedProperties += blendShape.mNumberOfMorphTarget;\r
131   }\r
132   animationDefinition.mProperties.resize(numberOfAnimatedProperties);\r
133 \r
134   // Create the key frame instances.\r
135   for(auto& animatedProperty : animationDefinition.mProperties)\r
136   {\r
137     animatedProperty.mKeyFrames = Dali::KeyFrames::New();\r
138   }\r
139 \r
140   // Set the property names\r
141   uint32_t targets = 0u;\r
142   for(const auto& blendShape : facialAnimation.mBlendShapes)\r
143   {\r
144     for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)\r
145     {\r
146       AnimatedProperty& animatedProperty = animationDefinition.mProperties[targets + morphTargetIndex];\r
147       animatedProperty.mTimePeriod       = Dali::TimePeriod(animationDefinition.mDuration);\r
148 \r
149       animatedProperty.mNodeName = blendShape.mNodeName;\r
150 \r
151       std::stringstream weightPropertyStream;\r
152       weightPropertyStream << BlendShapes::WEIGHTS_UNIFORM << "[" << morphTargetIndex << "]";\r
153       animatedProperty.mPropertyName = weightPropertyStream.str();\r
154     }\r
155     targets += blendShape.mNumberOfMorphTarget;\r
156   }\r
157 \r
158   targets = 0u;\r
159   for(const auto& blendShape : facialAnimation.mBlendShapes)\r
160   {\r
161     for(uint32_t timeIndex = 0u; timeIndex < facialAnimation.mNumberOfFrames; ++timeIndex)\r
162     {\r
163       const float progress = MILLISECONDS_TO_SECONDS * static_cast<float>(facialAnimation.mTime[timeIndex]) / animationDefinition.mDuration;\r
164 \r
165       for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)\r
166       {\r
167         AnimatedProperty& animatedProperty = animationDefinition.mProperties[targets + morphTargetIndex];\r
168 \r
169         animatedProperty.mKeyFrames.Add(progress, blendShape.mKeys[timeIndex][morphTargetIndex]);\r
170       }\r
171     }\r
172     targets += blendShape.mNumberOfMorphTarget;\r
173   }\r
174 \r
175   return animationDefinition;\r
176 }\r
177 \r
178 } // namespace SceneLoader\r
179 } // namespace Dali\r