| /* |
| Open Asset Import Library (assimp) |
| ---------------------------------------------------------------------- |
| |
| Copyright (c) 2006-2017, assimp team |
| |
| All rights reserved. |
| |
| Redistribution and use of this software in source and binary forms, |
| with or without modification, are permitted provided that the |
| following conditions are met: |
| |
| * Redistributions of source code must retain the above |
| copyright notice, this list of conditions and the |
| following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the |
| following disclaimer in the documentation and/or other |
| materials provided with the distribution. |
| |
| * Neither the name of the assimp team, nor the names of its |
| contributors may be used to endorse or promote products |
| derived from this software without specific prior |
| written permission of the assimp team. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| ---------------------------------------------------------------------- |
| */ |
| |
| /** @file FBXAnimation.cpp |
| * @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode, |
| * Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack |
| */ |
| |
| #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER |
| |
| #include "FBXParser.h" |
| #include "FBXDocument.h" |
| #include "FBXImporter.h" |
| #include "FBXDocumentUtil.h" |
| |
| namespace Assimp { |
| namespace FBX { |
| |
| using namespace Util; |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/) |
| : Object(id, element, name) |
| { |
| const Scope& sc = GetRequiredScope(element); |
| const Element& KeyTime = GetRequiredElement(sc,"KeyTime"); |
| const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat"); |
| |
| ParseVectorDataArray(keys, KeyTime); |
| ParseVectorDataArray(values, KeyValueFloat); |
| |
| if(keys.size() != values.size()) { |
| DOMError("the number of key times does not match the number of keyframe values",&KeyTime); |
| } |
| |
| // check if the key times are well-ordered |
| if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) { |
| DOMError("the keyframes are not in ascending order",&KeyTime); |
| } |
| |
| const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"]; |
| if(KeyAttrDataFloat) { |
| ParseVectorDataArray(attributes, *KeyAttrDataFloat); |
| } |
| |
| const Element* KeyAttrFlags = sc["KeyAttrFlags"]; |
| if(KeyAttrFlags) { |
| ParseVectorDataArray(flags, *KeyAttrFlags); |
| } |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationCurve::~AnimationCurve() |
| { |
| // empty |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, |
| const Document& doc, const char* const * target_prop_whitelist /*= NULL*/, |
| size_t whitelist_size /*= 0*/) |
| : Object(id, element, name) |
| , target() |
| , doc(doc) |
| { |
| const Scope& sc = GetRequiredScope(element); |
| |
| // find target node |
| const char* whitelist[] = {"Model","NodeAttribute"}; |
| const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,2); |
| |
| for(const Connection* con : conns) { |
| |
| // link should go for a property |
| if (!con->PropertyName().length()) { |
| continue; |
| } |
| |
| if(target_prop_whitelist) { |
| const char* const s = con->PropertyName().c_str(); |
| bool ok = false; |
| for (size_t i = 0; i < whitelist_size; ++i) { |
| if (!strcmp(s, target_prop_whitelist[i])) { |
| ok = true; |
| break; |
| } |
| } |
| |
| if (!ok) { |
| throw std::range_error("AnimationCurveNode target property is not in whitelist"); |
| } |
| } |
| |
| const Object* const ob = con->DestinationObject(); |
| if(!ob) { |
| DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element); |
| continue; |
| } |
| |
| // XXX support constraints as DOM class |
| //ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob)); |
| target = ob; |
| if(!target) { |
| continue; |
| } |
| |
| prop = con->PropertyName(); |
| break; |
| } |
| |
| if(!target) { |
| DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element); |
| } |
| |
| props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false); |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationCurveNode::~AnimationCurveNode() |
| { |
| // empty |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| const AnimationCurveMap& AnimationCurveNode::Curves() const |
| { |
| if ( curves.empty() ) { |
| // resolve attached animation curves |
| const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve"); |
| |
| for(const Connection* con : conns) { |
| |
| // link should go for a property |
| if (!con->PropertyName().length()) { |
| continue; |
| } |
| |
| const Object* const ob = con->SourceObject(); |
| if(!ob) { |
| DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element); |
| continue; |
| } |
| |
| const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob); |
| if(!anim) { |
| DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element); |
| continue; |
| } |
| |
| curves[con->PropertyName()] = anim; |
| } |
| } |
| |
| return curves; |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc) |
| : Object(id, element, name) |
| , doc(doc) |
| { |
| const Scope& sc = GetRequiredScope(element); |
| |
| // note: the props table here bears little importance and is usually absent |
| props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true); |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationLayer::~AnimationLayer() |
| { |
| // empty |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/, |
| size_t whitelist_size /*= 0*/) const |
| { |
| AnimationCurveNodeList nodes; |
| |
| // resolve attached animation nodes |
| const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode"); |
| nodes.reserve(conns.size()); |
| |
| for(const Connection* con : conns) { |
| |
| // link should not go to a property |
| if (con->PropertyName().length()) { |
| continue; |
| } |
| |
| const Object* const ob = con->SourceObject(); |
| if(!ob) { |
| DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element); |
| continue; |
| } |
| |
| const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob); |
| if(!anim) { |
| DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element); |
| continue; |
| } |
| |
| if(target_prop_whitelist) { |
| const char* s = anim->TargetProperty().c_str(); |
| bool ok = false; |
| for (size_t i = 0; i < whitelist_size; ++i) { |
| if (!strcmp(s, target_prop_whitelist[i])) { |
| ok = true; |
| break; |
| } |
| } |
| if(!ok) { |
| continue; |
| } |
| } |
| nodes.push_back(anim); |
| } |
| |
| return nodes; // pray for NRVO |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc) |
| : Object(id, element, name) |
| { |
| const Scope& sc = GetRequiredScope(element); |
| |
| // note: we don't currently use any of these properties so we shouldn't bother if it is missing |
| props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true); |
| |
| // resolve attached animation layers |
| const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer"); |
| layers.reserve(conns.size()); |
| |
| for(const Connection* con : conns) { |
| |
| // link should not go to a property |
| if (con->PropertyName().length()) { |
| continue; |
| } |
| |
| const Object* const ob = con->SourceObject(); |
| if(!ob) { |
| DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element); |
| continue; |
| } |
| |
| const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob); |
| if(!anim) { |
| DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element); |
| continue; |
| } |
| layers.push_back(anim); |
| } |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| AnimationStack::~AnimationStack() |
| { |
| // empty |
| } |
| |
| } //!FBX |
| } //!Assimp |
| |
| #endif // ASSIMP_BUILD_NO_FBX_IMPORTER |