2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
\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
8 * http://www.apache.org/licenses/LICENSE-2.0
\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
19 #include <dali-scene3d/public-api/loader/facial-animation-loader.h>
\r
21 // EXTERNAL INCLUDES
\r
24 // INTERNAL INCLUDES
\r
25 #include <dali-scene3d/internal/loader/json-reader.h>
\r
26 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
\r
27 #include <dali-scene3d/public-api/loader/utils.h>
\r
29 namespace js = json;
\r
35 const float MILLISECONDS_TO_SECONDS = 0.001f;
\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
47 struct FacialAnimation
\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
57 std::vector<std::vector<float>> ReadBlendShapeKeys(const json_value_s& j)
\r
59 auto& jo = js::Cast<json_array_s>(j);
\r
60 std::vector<std::vector<float>> result;
\r
62 result.reserve(jo.length);
\r
67 result.push_back(std::move(js::Read::Array<float, js::Read::Number>(*i->value)));
\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
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
90 } // unnamed namespace
\r
96 AnimationDefinition LoadFacialAnimation(const std::string& url)
\r
98 bool failed = false;
\r
99 auto js = LoadTextFile(url.c_str(), &failed);
\r
102 ExceptionFlinger(ASSERT_LOCATION) << "Failed to load " << url << ".";
\r
105 json::unique_ptr root(json_parse(js.c_str(), js.size()));
\r
108 ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse " << url << ".";
\r
111 static bool setObjectReaders = true;
\r
112 if(setObjectReaders)
\r
114 // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change.
\r
115 js::SetObjectReader(BLEND_SHAPE_READER);
\r
116 setObjectReaders = false;
\r
119 auto& rootObj = js::Cast<json_object_s>(*root);
\r
121 FacialAnimation facialAnimation;
\r
122 FACIAL_ANIMATION_READER.Read(rootObj, facialAnimation);
\r
124 AnimationDefinition animationDefinition;
\r
125 animationDefinition.mName = std::string(facialAnimation.mName.data());
\r
126 animationDefinition.mDuration = MILLISECONDS_TO_SECONDS * static_cast<float>(facialAnimation.mTime[facialAnimation.mNumberOfFrames - 1u]);
\r
128 // Calculate the number of animated properties.
\r
129 uint32_t numberOfAnimatedProperties = 0u;
\r
130 for(const auto& blendShape : facialAnimation.mBlendShapes)
\r
132 numberOfAnimatedProperties += blendShape.mNumberOfMorphTarget;
\r
134 animationDefinition.mProperties.resize(numberOfAnimatedProperties);
\r
136 // Create the key frame instances.
\r
137 for(auto& animatedProperty : animationDefinition.mProperties)
\r
139 animatedProperty.mKeyFrames = Dali::KeyFrames::New();
\r
142 // Set the property names
\r
143 uint32_t targets = 0u;
\r
144 for(const auto& blendShape : facialAnimation.mBlendShapes)
\r
146 for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)
\r
148 AnimatedProperty& animatedProperty = animationDefinition.mProperties[targets + morphTargetIndex];
\r
149 animatedProperty.mTimePeriod = Dali::TimePeriod(animationDefinition.mDuration);
\r
151 animatedProperty.mNodeName = blendShape.mNodeName;
\r
153 std::stringstream weightPropertyStream;
\r
154 weightPropertyStream << BlendShapes::WEIGHTS_UNIFORM << "[" << morphTargetIndex << "]";
\r
155 animatedProperty.mPropertyName = weightPropertyStream.str();
\r
157 targets += blendShape.mNumberOfMorphTarget;
\r
161 for(const auto& blendShape : facialAnimation.mBlendShapes)
\r
163 for(uint32_t timeIndex = 0u; timeIndex < facialAnimation.mNumberOfFrames; ++timeIndex)
\r
165 const float progress = MILLISECONDS_TO_SECONDS * static_cast<float>(facialAnimation.mTime[timeIndex]) / animationDefinition.mDuration;
\r
167 for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)
\r
169 AnimatedProperty& animatedProperty = animationDefinition.mProperties[targets + morphTargetIndex];
\r
171 animatedProperty.mKeyFrames.Add(progress, blendShape.mKeys[timeIndex][morphTargetIndex]);
\r
174 targets += blendShape.mNumberOfMorphTarget;
\r
177 return animationDefinition;
\r
180 } // namespace Loader
\r
181 } // namespace Scene3D
\r
182 } // namespace Dali
\r