1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4
5 Copyright (c) 2006-2019, assimp team
6
7
8 All rights reserved.
9
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the
12 following conditions are met:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
40 ----------------------------------------------------------------------
41 */
42
43 /** @file FBXAnimation.cpp
44 * @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode,
45 * Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack
46 */
47
48 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
49
50 #include "FBXParser.h"
51 #include "FBXDocument.h"
52 #include "FBXImporter.h"
53 #include "FBXDocumentUtil.h"
54
55 namespace Assimp {
56 namespace FBX {
57
58 using namespace Util;
59
60 // ------------------------------------------------------------------------------------------------
AnimationCurve(uint64_t id,const Element & element,const std::string & name,const Document &)61 AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/)
62 : Object(id, element, name)
63 {
64 const Scope& sc = GetRequiredScope(element);
65 const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
66 const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
67
68 ParseVectorDataArray(keys, KeyTime);
69 ParseVectorDataArray(values, KeyValueFloat);
70
71 if(keys.size() != values.size()) {
72 DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
73 }
74
75 // check if the key times are well-ordered
76 if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
77 DOMError("the keyframes are not in ascending order",&KeyTime);
78 }
79
80 const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
81 if(KeyAttrDataFloat) {
82 ParseVectorDataArray(attributes, *KeyAttrDataFloat);
83 }
84
85 const Element* KeyAttrFlags = sc["KeyAttrFlags"];
86 if(KeyAttrFlags) {
87 ParseVectorDataArray(flags, *KeyAttrFlags);
88 }
89 }
90
91 // ------------------------------------------------------------------------------------------------
~AnimationCurve()92 AnimationCurve::~AnimationCurve()
93 {
94 // empty
95 }
96
97 // ------------------------------------------------------------------------------------------------
AnimationCurveNode(uint64_t id,const Element & element,const std::string & name,const Document & doc,const char * const * target_prop_whitelist,size_t whitelist_size)98 AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name,
99 const Document& doc, const char* const * target_prop_whitelist /*= NULL*/,
100 size_t whitelist_size /*= 0*/)
101 : Object(id, element, name)
102 , target()
103 , doc(doc)
104 {
105 const Scope& sc = GetRequiredScope(element);
106
107 // find target node
108 const char* whitelist[] = {"Model","NodeAttribute","Deformer"};
109 const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,3);
110
111 for(const Connection* con : conns) {
112
113 // link should go for a property
114 if (!con->PropertyName().length()) {
115 continue;
116 }
117
118 if(target_prop_whitelist) {
119 const char* const s = con->PropertyName().c_str();
120 bool ok = false;
121 for (size_t i = 0; i < whitelist_size; ++i) {
122 if (!strcmp(s, target_prop_whitelist[i])) {
123 ok = true;
124 break;
125 }
126 }
127
128 if (!ok) {
129 throw std::range_error("AnimationCurveNode target property is not in whitelist");
130 }
131 }
132
133 const Object* const ob = con->DestinationObject();
134 if(!ob) {
135 DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element);
136 continue;
137 }
138
139 // XXX support constraints as DOM class
140 //ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
141 target = ob;
142 if(!target) {
143 continue;
144 }
145
146 prop = con->PropertyName();
147 break;
148 }
149
150 if(!target) {
151 DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element);
152 }
153
154 props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
155 }
156
157 // ------------------------------------------------------------------------------------------------
~AnimationCurveNode()158 AnimationCurveNode::~AnimationCurveNode()
159 {
160 // empty
161 }
162
163 // ------------------------------------------------------------------------------------------------
Curves() const164 const AnimationCurveMap& AnimationCurveNode::Curves() const
165 {
166 if ( curves.empty() ) {
167 // resolve attached animation curves
168 const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
169
170 for(const Connection* con : conns) {
171
172 // link should go for a property
173 if (!con->PropertyName().length()) {
174 continue;
175 }
176
177 const Object* const ob = con->SourceObject();
178 if(!ob) {
179 DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element);
180 continue;
181 }
182
183 const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob);
184 if(!anim) {
185 DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element);
186 continue;
187 }
188
189 curves[con->PropertyName()] = anim;
190 }
191 }
192
193 return curves;
194 }
195
196 // ------------------------------------------------------------------------------------------------
AnimationLayer(uint64_t id,const Element & element,const std::string & name,const Document & doc)197 AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc)
198 : Object(id, element, name)
199 , doc(doc)
200 {
201 const Scope& sc = GetRequiredScope(element);
202
203 // note: the props table here bears little importance and is usually absent
204 props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
205 }
206
207 // ------------------------------------------------------------------------------------------------
~AnimationLayer()208 AnimationLayer::~AnimationLayer()
209 {
210 // empty
211 }
212
213 // ------------------------------------------------------------------------------------------------
Nodes(const char * const * target_prop_whitelist,size_t whitelist_size) const214 AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/,
215 size_t whitelist_size /*= 0*/) const
216 {
217 AnimationCurveNodeList nodes;
218
219 // resolve attached animation nodes
220 const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
221 nodes.reserve(conns.size());
222
223 for(const Connection* con : conns) {
224
225 // link should not go to a property
226 if (con->PropertyName().length()) {
227 continue;
228 }
229
230 const Object* const ob = con->SourceObject();
231 if(!ob) {
232 DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element);
233 continue;
234 }
235
236 const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob);
237 if(!anim) {
238 DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
239 continue;
240 }
241
242 if(target_prop_whitelist) {
243 const char* s = anim->TargetProperty().c_str();
244 bool ok = false;
245 for (size_t i = 0; i < whitelist_size; ++i) {
246 if (!strcmp(s, target_prop_whitelist[i])) {
247 ok = true;
248 break;
249 }
250 }
251 if(!ok) {
252 continue;
253 }
254 }
255 nodes.push_back(anim);
256 }
257
258 return nodes; // pray for NRVO
259 }
260
261 // ------------------------------------------------------------------------------------------------
AnimationStack(uint64_t id,const Element & element,const std::string & name,const Document & doc)262 AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc)
263 : Object(id, element, name)
264 {
265 const Scope& sc = GetRequiredScope(element);
266
267 // note: we don't currently use any of these properties so we shouldn't bother if it is missing
268 props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true);
269
270 // resolve attached animation layers
271 const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
272 layers.reserve(conns.size());
273
274 for(const Connection* con : conns) {
275
276 // link should not go to a property
277 if (con->PropertyName().length()) {
278 continue;
279 }
280
281 const Object* const ob = con->SourceObject();
282 if(!ob) {
283 DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element);
284 continue;
285 }
286
287 const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob);
288 if(!anim) {
289 DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
290 continue;
291 }
292 layers.push_back(anim);
293 }
294 }
295
296 // ------------------------------------------------------------------------------------------------
~AnimationStack()297 AnimationStack::~AnimationStack()
298 {
299 // empty
300 }
301
302 } //!FBX
303 } //!Assimp
304
305 #endif // ASSIMP_BUILD_NO_FBX_IMPORTER
306