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-scene-loader/public-api/facial-animation-loader.h>
\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
26 namespace js = json;
\r
32 const float MILLISECONDS_TO_SECONDS = 0.001f;
\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
44 struct FacialAnimation
\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
54 std::vector<std::vector<float>> ReadBlendShapeKeys(const json_value_s& j)
\r
56 auto& jo = js::Cast<json_array_s>(j);
\r
57 std::vector<std::vector<float>> result;
\r
59 result.reserve(jo.length);
\r
64 result.push_back(std::move(js::Read::Array<float, js::Read::Number>(*i->value)));
\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
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
87 } // unnamed namespace
\r
89 namespace SceneLoader
\r
91 AnimationDefinition LoadFacialAnimation(const std::string& url)
\r
93 bool failed = false;
\r
94 auto js = LoadTextFile(url.c_str(), &failed);
\r
97 ExceptionFlinger(ASSERT_LOCATION) << "Failed to load " << url << ".";
\r
100 json::unique_ptr root(json_parse(js.c_str(), js.size()));
\r
103 ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse " << url << ".";
\r
106 static bool setObjectReaders = true;
\r
107 if(setObjectReaders)
\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
114 auto& rootObj = js::Cast<json_object_s>(*root);
\r
116 FacialAnimation facialAnimation;
\r
117 FACIAL_ANIMATION_READER.Read(rootObj, facialAnimation);
\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
123 // Calculate the number of animated properties.
\r
124 uint32_t numberOfAnimatedProperties = 0u;
\r
125 for(const auto& blendShape : facialAnimation.mBlendShapes)
\r
127 numberOfAnimatedProperties += blendShape.mNumberOfMorphTarget;
\r
129 animationDefinition.mProperties.resize(numberOfAnimatedProperties);
\r
131 // Create the key frame instances.
\r
132 for(auto& animatedProperty : animationDefinition.mProperties)
\r
134 animatedProperty.mKeyFrames = Dali::KeyFrames::New();
\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
143 for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)
\r
145 AnimatedProperty& animatedProperty = animationDefinition.mProperties[targets + morphTargetIndex];
\r
146 animatedProperty.mTimePeriod = Dali::TimePeriod(animationDefinition.mDuration);
\r
148 animatedProperty.mNodeName = blendShape.mNodeName;
\r
150 snprintf(pWeightName, sizeof(weightNameBuffer) - (pWeightName - weightNameBuffer), "[%d]", morphTargetIndex);
\r
151 animatedProperty.mPropertyName = weightNameBuffer;
\r
153 targets += blendShape.mNumberOfMorphTarget;
\r
157 for(const auto& blendShape : facialAnimation.mBlendShapes)
\r
159 for(uint32_t timeIndex = 0u; timeIndex < facialAnimation.mNumberOfFrames; ++timeIndex)
\r
161 const float progress = MILLISECONDS_TO_SECONDS * static_cast<float>(facialAnimation.mTime[timeIndex]) / animationDefinition.mDuration;
\r
163 for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)
\r
165 AnimatedProperty& animatedProperty = animationDefinition.mProperties[targets + morphTargetIndex];
\r
167 animatedProperty.mKeyFrames.Add(progress, blendShape.mKeys[timeIndex][morphTargetIndex]);
\r
170 targets += blendShape.mNumberOfMorphTarget;
\r
173 return animationDefinition;
\r
176 } // namespace SceneLoader
\r
177 } // namespace Dali
\r