3209467a60021411faf5827eed869231b9710017
[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 // INTERNAL INCLUDES\r
22 #include <dali-scene-loader/internal/json-reader.h>\r
23 #include <dali-scene-loader/public-api/blend-shape-details.h>\r
24 #include <dali-scene-loader/public-api/utils.h>\r
25 \r
26 namespace js = json;\r
27 \r
28 namespace Dali\r
29 {\r
30 namespace\r
31 {\r
32 const float MILLISECONDS_TO_SECONDS = 0.001f;\r
33 \r
34 struct BlendShape\r
35 {\r
36   std::vector<std::vector<float>> mKeys;\r
37   std::string_view                mNodeName;\r
38   uint32_t                        mNumberOfMorphTarget;\r
39   std::string_view                mVersion;\r
40   std::string_view                mFullName;\r
41   std::vector<std::string_view>   mMorphNames;\r
42 };\r
43 \r
44 struct FacialAnimation\r
45 {\r
46   std::string_view        mName;\r
47   std::vector<BlendShape> mBlendShapes;\r
48   std::string_view        mVersion;\r
49   uint32_t                mNumberOfShapes;\r
50   std::vector<uint32_t>   mTime;\r
51   uint32_t                mNumberOfFrames;\r
52 };\r
53 \r
54 std::vector<std::vector<float>> ReadBlendShapeKeys(const json_value_s& j)\r
55 {\r
56   auto&                           jo = js::Cast<json_array_s>(j);\r
57   std::vector<std::vector<float>> result;\r
58 \r
59   result.reserve(jo.length);\r
60 \r
61   auto i = jo.start;\r
62   while(i)\r
63   {\r
64     result.push_back(std::move(js::Read::Array<float, js::Read::Number>(*i->value)));\r
65     i = i->next;\r
66   }\r
67 \r
68   return result;\r
69 }\r
70 \r
71 const auto BLEND_SHAPE_READER = std::move(js::Reader<BlendShape>()\r
72                                             .Register(*js::MakeProperty("key", ReadBlendShapeKeys, &BlendShape::mKeys))\r
73                                             .Register(*new js::Property<BlendShape, std::string_view>("name", js::Read::StringView, &BlendShape::mNodeName))\r
74                                             .Register(*js::MakeProperty("morphtarget", js::Read::Number<uint32_t>, &BlendShape::mNumberOfMorphTarget))\r
75                                             .Register(*new js::Property<BlendShape, std::string_view>("blendShapeVersion", js::Read::StringView, &BlendShape::mVersion))\r
76                                             .Register(*new js::Property<BlendShape, std::string_view>("fullName", js::Read::StringView, &BlendShape::mFullName))\r
77                                             .Register(*js::MakeProperty("morphname", js::Read::Array<std::string_view, js::Read::StringView>, &BlendShape::mMorphNames)));\r
78 \r
79 const auto FACIAL_ANIMATION_READER = std::move(js::Reader<FacialAnimation>()\r
80                                                  .Register(*new js::Property<FacialAnimation, std::string_view>("name", js::Read::StringView, &FacialAnimation::mName))\r
81                                                  .Register(*js::MakeProperty("blendShapes", js::Read::Array<BlendShape, js::ObjectReader<BlendShape>::Read>, &FacialAnimation::mBlendShapes))\r
82                                                  .Register(*new js::Property<FacialAnimation, std::string_view>("version", js::Read::StringView, &FacialAnimation::mVersion))\r
83                                                  .Register(*js::MakeProperty("shapesAmount", js::Read::Number<uint32_t>, &FacialAnimation::mNumberOfShapes))\r
84                                                  .Register(*js::MakeProperty("time", js::Read::Array<uint32_t, js::Read::Number>, &FacialAnimation::mTime))\r
85                                                  .Register(*js::MakeProperty("frames", js::Read::Number<uint32_t>, &FacialAnimation::mNumberOfFrames)));\r
86 \r
87 } // unnamed namespace\r
88 \r
89 namespace SceneLoader\r
90 {\r
91 AnimationDefinition LoadFacialAnimation(const std::string& url)\r
92 {\r
93   bool failed = false;\r
94   auto js     = LoadTextFile(url.c_str(), &failed);\r
95   if(failed)\r
96   {\r
97     ExceptionFlinger(ASSERT_LOCATION) << "Failed to load " << url << ".";\r
98   }\r
99 \r
100   json::unique_ptr root(json_parse(js.c_str(), js.size()));\r
101   if(!root)\r
102   {\r
103     ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse " << url << ".";\r
104   }\r
105 \r
106   static bool setObjectReaders = true;\r
107   if(setObjectReaders)\r
108   {\r
109     // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change.\r
110     js::SetObjectReader(BLEND_SHAPE_READER);\r
111     setObjectReaders = false;\r
112   }\r
113 \r
114   auto& rootObj = js::Cast<json_object_s>(*root);\r
115 \r
116   FacialAnimation facialAnimation;\r
117   FACIAL_ANIMATION_READER.Read(rootObj, facialAnimation);\r
118 \r
119   AnimationDefinition animationDefinition;\r
120   animationDefinition.mName     = std::string(facialAnimation.mName.data());\r
121   animationDefinition.mDuration = MILLISECONDS_TO_SECONDS * static_cast<float>(facialAnimation.mTime[facialAnimation.mNumberOfFrames - 1u]);\r
122 \r
123   // Calculate the number of animated properties.\r
124   uint32_t numberOfAnimatedProperties = 0u;\r
125   for(const auto& blendShape : facialAnimation.mBlendShapes)\r
126   {\r
127     numberOfAnimatedProperties += blendShape.mNumberOfMorphTarget;\r
128   }\r
129   animationDefinition.mProperties.resize(numberOfAnimatedProperties);\r
130 \r
131   // Create the key frame instances.\r
132   for(auto& animatedProperty : animationDefinition.mProperties)\r
133   {\r
134     animatedProperty.mKeyFrames = Dali::KeyFrames::New();\r
135   }\r
136 \r
137   // Set the property names\r
138   char        weightNameBuffer[32];\r
139   char* const pWeightName = weightNameBuffer + sprintf(weightNameBuffer, "%s", BlendShapes::WEIGHTS_UNIFORM.c_str());\r
140   uint32_t    targets     = 0u;\r
141   for(const auto& blendShape : facialAnimation.mBlendShapes)\r
142   {\r
143     for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)\r
144     {\r
145       AnimatedProperty& animatedProperty = animationDefinition.mProperties[targets + morphTargetIndex];\r
146       animatedProperty.mTimePeriod       = Dali::TimePeriod(animationDefinition.mDuration);\r
147 \r
148       animatedProperty.mNodeName = blendShape.mNodeName;\r
149 \r
150       snprintf(pWeightName, sizeof(weightNameBuffer) - (pWeightName - weightNameBuffer), "[%d]", morphTargetIndex);\r
151       animatedProperty.mPropertyName = weightNameBuffer;\r
152     }\r
153     targets += blendShape.mNumberOfMorphTarget;\r
154   }\r
155 \r
156   targets = 0u;\r
157   for(const auto& blendShape : facialAnimation.mBlendShapes)\r
158   {\r
159     for(uint32_t timeIndex = 0u; timeIndex < facialAnimation.mNumberOfFrames; ++timeIndex)\r
160     {\r
161       const float progress = MILLISECONDS_TO_SECONDS * static_cast<float>(facialAnimation.mTime[timeIndex]) / animationDefinition.mDuration;\r
162 \r
163       for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)\r
164       {\r
165         AnimatedProperty& animatedProperty = animationDefinition.mProperties[targets + morphTargetIndex];\r
166 \r
167         animatedProperty.mKeyFrames.Add(progress, blendShape.mKeys[timeIndex][morphTargetIndex]);\r
168       }\r
169     }\r
170     targets += blendShape.mNumberOfMorphTarget;\r
171   }\r
172 \r
173   return animationDefinition;\r
174 }\r
175 \r
176 } // namespace SceneLoader\r
177 } // namespace Dali\r