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