diff options
Diffstat (limited to 'src/3rdparty/assimp/code/FBXDocument.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/FBXDocument.cpp | 934 |
1 files changed, 480 insertions, 454 deletions
diff --git a/src/3rdparty/assimp/code/FBXDocument.cpp b/src/3rdparty/assimp/code/FBXDocument.cpp index 404a8d6e2..cf5f6da86 100644 --- a/src/3rdparty/assimp/code/FBXDocument.cpp +++ b/src/3rdparty/assimp/code/FBXDocument.cpp @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, 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 +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 @@ -23,16 +23,16 @@ following conditions are met: 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 +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 +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 +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 +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. ---------------------------------------------------------------------- @@ -41,20 +41,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file FBXDocument.cpp * @brief Implementation of the FBX DOM classes */ -#include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER -#include <functional> - -#include "FBXParser.h" #include "FBXDocument.h" +#include "FBXMeshGeometry.h" +#include "FBXParser.h" #include "FBXUtil.h" #include "FBXImporter.h" #include "FBXImportSettings.h" #include "FBXDocumentUtil.h" #include "FBXProperties.h" +#include <memory> +#include <functional> + + namespace Assimp { namespace FBX { @@ -77,143 +79,156 @@ LazyObject::~LazyObject() } // ------------------------------------------------------------------------------------------------ +static void dumpObjectClassInfo( const char* obtype, const std::string &classtag ) { + DefaultLogger::get()->debug( "obtype: " + std::string(obtype )); + DefaultLogger::get()->debug( "Classtag: " + classtag ); +} + +// ------------------------------------------------------------------------------------------------ const Object* LazyObject::Get(bool dieOnError) { - if(IsBeingConstructed() || FailedToConstruct()) { - return NULL; - } - - if (object.get()) { - return object.get(); - } - - // if this is the root object, we return a dummy since there - // is no root object int he fbx file - it is just referenced - // with id 0. - if(id == 0L) { - object.reset(new Object(id, element, "Model::RootNode")); - return object.get(); - } - - const Token& key = element.KeyToken(); - const TokenList& tokens = element.Tokens(); - - if(tokens.size() < 3) { - DOMError("expected at least 3 tokens: id, name and class tag",&element); - } - - const char* err; - std::string name = ParseTokenAsString(*tokens[1],err); - if (err) { - DOMError(err,&element); - } - - // small fix for binary reading: binary fbx files don't use - // prefixes such as Model:: in front of their names. The - // loading code expects this at many places, though! - // so convert the binary representation (a 0x0001) to the - // double colon notation. - if(tokens[1]->IsBinary()) { - for (size_t i = 0; i < name.length(); ++i) { - if (name[i] == 0x0 && name[i+1] == 0x1) { - name = name.substr(i+2) + "::" + name.substr(0,i); - } - } - } - - const std::string classtag = ParseTokenAsString(*tokens[2],err); - if (err) { - DOMError(err,&element); - } - - // prevent recursive calls - flags |= BEING_CONSTRUCTED; - - try { - // this needs to be relatively fast since it happens a lot, - // so avoid constructing strings all the time. - const char* obtype = key.begin(); - const size_t length = static_cast<size_t>(key.end()-key.begin()); - if (!strncmp(obtype,"Geometry",length)) { - if (!strcmp(classtag.c_str(),"Mesh")) { - object.reset(new MeshGeometry(id,element,name,doc)); - } - } - else if (!strncmp(obtype,"NodeAttribute",length)) { - if (!strcmp(classtag.c_str(),"Camera")) { - object.reset(new Camera(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"CameraSwitcher")) { - object.reset(new CameraSwitcher(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"Light")) { - object.reset(new Light(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"Null")) { - object.reset(new Null(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"LimbNode")) { - object.reset(new LimbNode(id,element,doc,name)); - } - } - else if (!strncmp(obtype,"Deformer",length)) { - if (!strcmp(classtag.c_str(),"Cluster")) { - object.reset(new Cluster(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"Skin")) { - object.reset(new Skin(id,element,doc,name)); - } - } - else if (!strncmp(obtype,"Model",length)) { - // FK and IK effectors are not supported - if (strcmp(classtag.c_str(),"IKEffector") && strcmp(classtag.c_str(),"FKEffector")) { - object.reset(new Model(id,element,doc,name)); - } - } - else if (!strncmp(obtype,"Material",length)) { - object.reset(new Material(id,element,doc,name)); - } - else if (!strncmp(obtype,"Texture",length)) { - object.reset(new Texture(id,element,doc,name)); - } - else if (!strncmp(obtype,"LayeredTexture",length)) { - object.reset(new LayeredTexture(id,element,doc,name)); - } - else if (!strncmp(obtype,"AnimationStack",length)) { - object.reset(new AnimationStack(id,element,name,doc)); - } - else if (!strncmp(obtype,"AnimationLayer",length)) { - object.reset(new AnimationLayer(id,element,name,doc)); - } - // note: order matters for these two - else if (!strncmp(obtype,"AnimationCurve",length)) { - object.reset(new AnimationCurve(id,element,name,doc)); - } - else if (!strncmp(obtype,"AnimationCurveNode",length)) { - object.reset(new AnimationCurveNode(id,element,name,doc)); - } - } - catch(std::exception& ex) { - flags &= ~BEING_CONSTRUCTED; - flags |= FAILED_TO_CONSTRUCT; - - if(dieOnError || doc.Settings().strictMode) { - throw; - } - - // note: the error message is already formatted, so raw logging is ok - if(!DefaultLogger::isNullLogger()) { - DefaultLogger::get()->error(ex.what()); - } - return NULL; - } - - if (!object.get()) { - //DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element); - } - - flags &= ~BEING_CONSTRUCTED; - return object.get(); + if(IsBeingConstructed() || FailedToConstruct()) { + return NULL; + } + + if (object.get()) { + return object.get(); + } + + // if this is the root object, we return a dummy since there + // is no root object int he fbx file - it is just referenced + // with id 0. + if(id == 0L) { + object.reset(new Object(id, element, "Model::RootNode")); + return object.get(); + } + + const Token& key = element.KeyToken(); + const TokenList& tokens = element.Tokens(); + + if(tokens.size() < 3) { + DOMError("expected at least 3 tokens: id, name and class tag",&element); + } + + const char* err; + std::string name = ParseTokenAsString(*tokens[1],err); + if (err) { + DOMError(err,&element); + } + + // small fix for binary reading: binary fbx files don't use + // prefixes such as Model:: in front of their names. The + // loading code expects this at many places, though! + // so convert the binary representation (a 0x0001) to the + // double colon notation. + if(tokens[1]->IsBinary()) { + for (size_t i = 0; i < name.length(); ++i) { + if (name[i] == 0x0 && name[i+1] == 0x1) { + name = name.substr(i+2) + "::" + name.substr(0,i); + } + } + } + + const std::string classtag = ParseTokenAsString(*tokens[2],err); + if (err) { + DOMError(err,&element); + } + + // prevent recursive calls + flags |= BEING_CONSTRUCTED; + + try { + // this needs to be relatively fast since it happens a lot, + // so avoid constructing strings all the time. + const char* obtype = key.begin(); + const size_t length = static_cast<size_t>(key.end()-key.begin()); + + // For debugging + //dumpObjectClassInfo( objtype, classtag ); + + if (!strncmp(obtype,"Geometry",length)) { + if (!strcmp(classtag.c_str(),"Mesh")) { + object.reset(new MeshGeometry(id,element,name,doc)); + } + } + else if (!strncmp(obtype,"NodeAttribute",length)) { + if (!strcmp(classtag.c_str(),"Camera")) { + object.reset(new Camera(id,element,doc,name)); + } + else if (!strcmp(classtag.c_str(),"CameraSwitcher")) { + object.reset(new CameraSwitcher(id,element,doc,name)); + } + else if (!strcmp(classtag.c_str(),"Light")) { + object.reset(new Light(id,element,doc,name)); + } + else if (!strcmp(classtag.c_str(),"Null")) { + object.reset(new Null(id,element,doc,name)); + } + else if (!strcmp(classtag.c_str(),"LimbNode")) { + object.reset(new LimbNode(id,element,doc,name)); + } + } + else if (!strncmp(obtype,"Deformer",length)) { + if (!strcmp(classtag.c_str(),"Cluster")) { + object.reset(new Cluster(id,element,doc,name)); + } + else if (!strcmp(classtag.c_str(),"Skin")) { + object.reset(new Skin(id,element,doc,name)); + } + } + else if ( !strncmp( obtype, "Model", length ) ) { + // FK and IK effectors are not supported + if ( strcmp( classtag.c_str(), "IKEffector" ) && strcmp( classtag.c_str(), "FKEffector" ) ) { + object.reset( new Model( id, element, doc, name ) ); + } + } + else if (!strncmp(obtype,"Material",length)) { + object.reset(new Material(id,element,doc,name)); + } + else if (!strncmp(obtype,"Texture",length)) { + object.reset(new Texture(id,element,doc,name)); + } + else if (!strncmp(obtype,"LayeredTexture",length)) { + object.reset(new LayeredTexture(id,element,doc,name)); + } + else if (!strncmp(obtype,"Video",length)) { + object.reset(new Video(id,element,doc,name)); + } + else if (!strncmp(obtype,"AnimationStack",length)) { + object.reset(new AnimationStack(id,element,name,doc)); + } + else if (!strncmp(obtype,"AnimationLayer",length)) { + object.reset(new AnimationLayer(id,element,name,doc)); + } + // note: order matters for these two + else if (!strncmp(obtype,"AnimationCurve",length)) { + object.reset(new AnimationCurve(id,element,name,doc)); + } + else if (!strncmp(obtype,"AnimationCurveNode",length)) { + object.reset(new AnimationCurveNode(id,element,name,doc)); + } + } + catch(std::exception& ex) { + flags &= ~BEING_CONSTRUCTED; + flags |= FAILED_TO_CONSTRUCT; + + if(dieOnError || doc.Settings().strictMode) { + throw; + } + + // note: the error message is already formatted, so raw logging is ok + if(!DefaultLogger::isNullLogger()) { + DefaultLogger::get()->error(ex.what()); + } + return NULL; + } + + if (!object.get()) { + //DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element); + } + + flags &= ~BEING_CONSTRUCTED; + return object.get(); } // ------------------------------------------------------------------------------------------------ @@ -233,9 +248,9 @@ Object::~Object() // ------------------------------------------------------------------------------------------------ -FileGlobalSettings::FileGlobalSettings(const Document& doc, boost::shared_ptr<const PropertyTable> props) +FileGlobalSettings::FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props) : props(props) -, doc(doc) +, doc(doc) { } @@ -253,209 +268,215 @@ Document::Document(const Parser& parser, const ImportSettings& settings) : settings(settings) , parser(parser) { - // cannot use array default initialization syntax because vc8 fails on it - for (unsigned int i = 0; i < 7; ++i) { - creationTimeStamp[i] = 0; - } + // Cannot use array default initialization syntax because vc8 fails on it + for (auto &timeStamp : creationTimeStamp) { + timeStamp = 0; + } - ReadHeader(); - ReadPropertyTemplates(); + ReadHeader(); + ReadPropertyTemplates(); - ReadGlobalSettings(); + ReadGlobalSettings(); - // this order is important, connections need parsed objects to check - // whether connections are ok or not. Objects may not be evaluated yet, - // though, since this may require valid connections. - ReadObjects(); - ReadConnections(); + // This order is important, connections need parsed objects to check + // whether connections are ok or not. Objects may not be evaluated yet, + // though, since this may require valid connections. + ReadObjects(); + ReadConnections(); } // ------------------------------------------------------------------------------------------------ Document::~Document() { - BOOST_FOREACH(ObjectMap::value_type& v, objects) { - delete v.second; - } + for(ObjectMap::value_type& v : objects) { + delete v.second; + } + + for(ConnectionMap::value_type& v : src_connections) { + delete v.second; + } + // |dest_connections| contain the same Connection objects as the |src_connections| } - // ------------------------------------------------------------------------------------------------ +static const int LowerSupportedVersion = 7100; +static const int UpperSupportedVersion = 7400; + void Document::ReadHeader() { - // read ID objects from "Objects" section - const Scope& sc = parser.GetRootScope(); - const Element* const ehead = sc["FBXHeaderExtension"]; - if(!ehead || !ehead->Compound()) { - DOMError("no FBXHeaderExtension dictionary found"); - } - - const Scope& shead = *ehead->Compound(); - fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0)); - - // while we maye have some success with newer files, we don't support - // the older 6.n fbx format - if(fbxVersion < 7100) { - DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013"); - } - if(fbxVersion > 7300) { - if(Settings().strictMode) { - DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013" - " (turn off strict mode to try anyhow) "); - } - else { - DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013," - " trying to read it nevertheless"); - } - } - - - const Element* const ecreator = shead["Creator"]; - if(ecreator) { - creator = ParseTokenAsString(GetRequiredToken(*ecreator,0)); - } - - const Element* const etimestamp = shead["CreationTimeStamp"]; - if(etimestamp && etimestamp->Compound()) { - const Scope& stimestamp = *etimestamp->Compound(); - creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0)); - creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0)); - creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0)); - creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0)); - creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0)); - creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0)); - creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0)); - } + // Read ID objects from "Objects" section + const Scope& sc = parser.GetRootScope(); + const Element* const ehead = sc["FBXHeaderExtension"]; + if(!ehead || !ehead->Compound()) { + DOMError("no FBXHeaderExtension dictionary found"); + } + + const Scope& shead = *ehead->Compound(); + fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0)); + + // While we maye have some success with newer files, we don't support + // the older 6.n fbx format + if(fbxVersion < LowerSupportedVersion ) { + DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013"); + } + if(fbxVersion > UpperSupportedVersion ) { + if(Settings().strictMode) { + DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013" + " (turn off strict mode to try anyhow) "); + } + else { + DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013," + " trying to read it nevertheless"); + } + } + + + const Element* const ecreator = shead["Creator"]; + if(ecreator) { + creator = ParseTokenAsString(GetRequiredToken(*ecreator,0)); + } + + const Element* const etimestamp = shead["CreationTimeStamp"]; + if(etimestamp && etimestamp->Compound()) { + const Scope& stimestamp = *etimestamp->Compound(); + creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0)); + creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0)); + creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0)); + creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0)); + creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0)); + creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0)); + creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0)); + } } // ------------------------------------------------------------------------------------------------ void Document::ReadGlobalSettings() { - const Scope& sc = parser.GetRootScope(); - const Element* const ehead = sc["GlobalSettings"]; - if(!ehead || !ehead->Compound()) { - DOMWarning("no GlobalSettings dictionary found"); + const Scope& sc = parser.GetRootScope(); + const Element* const ehead = sc["GlobalSettings"]; + if(!ehead || !ehead->Compound()) { + DOMWarning("no GlobalSettings dictionary found"); - globals.reset(new FileGlobalSettings(*this, boost::make_shared<const PropertyTable>())); - return; - } + globals.reset(new FileGlobalSettings(*this, std::make_shared<const PropertyTable>())); + return; + } - boost::shared_ptr<const PropertyTable> props = GetPropertyTable(*this, "", *ehead, *ehead->Compound(), true); + std::shared_ptr<const PropertyTable> props = GetPropertyTable(*this, "", *ehead, *ehead->Compound(), true); - if(!props) { - DOMError("GlobalSettings dictionary contains no property table"); - } + if(!props) { + DOMError("GlobalSettings dictionary contains no property table"); + } - globals.reset(new FileGlobalSettings(*this, props)); + globals.reset(new FileGlobalSettings(*this, props)); } // ------------------------------------------------------------------------------------------------ void Document::ReadObjects() { - // read ID objects from "Objects" section - const Scope& sc = parser.GetRootScope(); - const Element* const eobjects = sc["Objects"]; - if(!eobjects || !eobjects->Compound()) { - DOMError("no Objects dictionary found"); - } - - // add a dummy entry to represent the Model::RootNode object (id 0), - // which is only indirectly defined in the input file - objects[0] = new LazyObject(0L, *eobjects, *this); - - const Scope& sobjects = *eobjects->Compound(); - BOOST_FOREACH(const ElementMap::value_type& el, sobjects.Elements()) { - - // extract ID - const TokenList& tok = el.second->Tokens(); - - if (tok.empty()) { - DOMError("expected ID after object key",el.second); - } - - const char* err; - - const uint64_t id = ParseTokenAsID(*tok[0], err); - if(err) { - DOMError(err,el.second); - } - - // id=0 is normally implicit - if(id == 0L) { - DOMError("encountered object with implicitly defined id 0",el.second); - } - - if(objects.find(id) != objects.end()) { - DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second); - } - - objects[id] = new LazyObject(id, *el.second, *this); - - // grab all animation stacks upfront since there is no listing of them - if(!strcmp(el.first.c_str(),"AnimationStack")) { - animationStacks.push_back(id); - } - } + // read ID objects from "Objects" section + const Scope& sc = parser.GetRootScope(); + const Element* const eobjects = sc["Objects"]; + if(!eobjects || !eobjects->Compound()) { + DOMError("no Objects dictionary found"); + } + + // add a dummy entry to represent the Model::RootNode object (id 0), + // which is only indirectly defined in the input file + objects[0] = new LazyObject(0L, *eobjects, *this); + + const Scope& sobjects = *eobjects->Compound(); + for(const ElementMap::value_type& el : sobjects.Elements()) { + + // extract ID + const TokenList& tok = el.second->Tokens(); + + if (tok.empty()) { + DOMError("expected ID after object key",el.second); + } + + const char* err; + + const uint64_t id = ParseTokenAsID(*tok[0], err); + if(err) { + DOMError(err,el.second); + } + + // id=0 is normally implicit + if(id == 0L) { + DOMError("encountered object with implicitly defined id 0",el.second); + } + + if(objects.find(id) != objects.end()) { + DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second); + } + + objects[id] = new LazyObject(id, *el.second, *this); + + // grab all animation stacks upfront since there is no listing of them + if(!strcmp(el.first.c_str(),"AnimationStack")) { + animationStacks.push_back(id); + } + } } - // ------------------------------------------------------------------------------------------------ void Document::ReadPropertyTemplates() { - const Scope& sc = parser.GetRootScope(); - // read property templates from "Definitions" section - const Element* const edefs = sc["Definitions"]; - if(!edefs || !edefs->Compound()) { - DOMWarning("no Definitions dictionary found"); - return; - } - - const Scope& sdefs = *edefs->Compound(); - const ElementCollection otypes = sdefs.GetCollection("ObjectType"); - for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) { - const Element& el = *(*it).second; - const Scope* sc = el.Compound(); - if(!sc) { - DOMWarning("expected nested scope in ObjectType, ignoring",&el); - continue; - } - - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - DOMWarning("expected name for ObjectType element, ignoring",&el); - continue; - } - - const std::string& oname = ParseTokenAsString(*tok[0]); - - const ElementCollection templs = sc->GetCollection("PropertyTemplate"); - for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) { - const Element& el = *(*it).second; - const Scope* sc = el.Compound(); - if(!sc) { - DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el); - continue; - } - - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - DOMWarning("expected name for PropertyTemplate element, ignoring",&el); - continue; - } - - const std::string& pname = ParseTokenAsString(*tok[0]); - - const Element* Properties70 = (*sc)["Properties70"]; - if(Properties70) { - boost::shared_ptr<const PropertyTable> props = boost::make_shared<const PropertyTable>( - *Properties70,boost::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL)) - ); - - templates[oname+"."+pname] = props; - } - } - } + const Scope& sc = parser.GetRootScope(); + // read property templates from "Definitions" section + const Element* const edefs = sc["Definitions"]; + if(!edefs || !edefs->Compound()) { + DOMWarning("no Definitions dictionary found"); + return; + } + + const Scope& sdefs = *edefs->Compound(); + const ElementCollection otypes = sdefs.GetCollection("ObjectType"); + for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) { + const Element& el = *(*it).second; + const Scope* sc = el.Compound(); + if(!sc) { + DOMWarning("expected nested scope in ObjectType, ignoring",&el); + continue; + } + + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + DOMWarning("expected name for ObjectType element, ignoring",&el); + continue; + } + + const std::string& oname = ParseTokenAsString(*tok[0]); + + const ElementCollection templs = sc->GetCollection("PropertyTemplate"); + for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) { + const Element& el = *(*it).second; + const Scope* sc = el.Compound(); + if(!sc) { + DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el); + continue; + } + + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + DOMWarning("expected name for PropertyTemplate element, ignoring",&el); + continue; + } + + const std::string& pname = ParseTokenAsString(*tok[0]); + + const Element* Properties70 = (*sc)["Properties70"]; + if(Properties70) { + std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>( + *Properties70,std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL)) + ); + + templates[oname+"."+pname] = props; + } + } + } } @@ -463,202 +484,207 @@ void Document::ReadPropertyTemplates() // ------------------------------------------------------------------------------------------------ void Document::ReadConnections() { - const Scope& sc = parser.GetRootScope(); - // read property templates from "Definitions" section - const Element* const econns = sc["Connections"]; - if(!econns || !econns->Compound()) { - DOMError("no Connections dictionary found"); - } - - uint64_t insertionOrder = 0l; - - const Scope& sconns = *econns->Compound(); - const ElementCollection conns = sconns.GetCollection("C"); - for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) { - const Element& el = *(*it).second; - const std::string& type = ParseTokenAsString(GetRequiredToken(el,0)); - const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1)); - const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2)); - - // OO = object-object connection - // OP = object-property connection, in which case the destination property follows the object ID - const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : ""); - - if(objects.find(src) == objects.end()) { - DOMWarning("source object for connection does not exist",&el); - continue; - } - - // dest may be 0 (root node) but we added a dummy object before - if(objects.find(dest) == objects.end()) { - DOMWarning("destination object for connection does not exist",&el); - continue; - } - - // add new connection - const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this); - src_connections.insert(ConnectionMap::value_type(src,c)); - dest_connections.insert(ConnectionMap::value_type(dest,c)); - } + const Scope& sc = parser.GetRootScope(); + // read property templates from "Definitions" section + const Element* const econns = sc["Connections"]; + if(!econns || !econns->Compound()) { + DOMError("no Connections dictionary found"); + } + + uint64_t insertionOrder = 0l; + + const Scope& sconns = *econns->Compound(); + const ElementCollection conns = sconns.GetCollection("C"); + for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) { + const Element& el = *(*it).second; + const std::string& type = ParseTokenAsString(GetRequiredToken(el,0)); + + // PP = property-property connection, ignored for now + // (tokens: "PP", ID1, "Property1", ID2, "Property2") + if(type == "PP") continue; + + const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1)); + const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2)); + + // OO = object-object connection + // OP = object-property connection, in which case the destination property follows the object ID + const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : ""); + + if(objects.find(src) == objects.end()) { + DOMWarning("source object for connection does not exist",&el); + continue; + } + + // dest may be 0 (root node) but we added a dummy object before + if(objects.find(dest) == objects.end()) { + DOMWarning("destination object for connection does not exist",&el); + continue; + } + + // add new connection + const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this); + src_connections.insert(ConnectionMap::value_type(src,c)); + dest_connections.insert(ConnectionMap::value_type(dest,c)); + } } // ------------------------------------------------------------------------------------------------ const std::vector<const AnimationStack*>& Document::AnimationStacks() const { - if (!animationStacksResolved.empty() || !animationStacks.size()) { - return animationStacksResolved; - } - - animationStacksResolved.reserve(animationStacks.size()); - BOOST_FOREACH(uint64_t id, animationStacks) { - LazyObject* const lazy = GetObject(id); - const AnimationStack* stack; - if(!lazy || !(stack = lazy->Get<AnimationStack>())) { - DOMWarning("failed to read AnimationStack object"); - continue; - } - animationStacksResolved.push_back(stack); - } - - return animationStacksResolved; + if (!animationStacksResolved.empty() || !animationStacks.size()) { + return animationStacksResolved; + } + + animationStacksResolved.reserve(animationStacks.size()); + for(uint64_t id : animationStacks) { + LazyObject* const lazy = GetObject(id); + const AnimationStack* stack; + if(!lazy || !(stack = lazy->Get<AnimationStack>())) { + DOMWarning("failed to read AnimationStack object"); + continue; + } + animationStacksResolved.push_back(stack); + } + + return animationStacksResolved; } // ------------------------------------------------------------------------------------------------ LazyObject* Document::GetObject(uint64_t id) const { - ObjectMap::const_iterator it = objects.find(id); - return it == objects.end() ? NULL : (*it).second; + ObjectMap::const_iterator it = objects.find(id); + return it == objects.end() ? NULL : (*it).second; } #define MAX_CLASSNAMES 6 // ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, - const ConnectionMap& conns) const +std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, + const ConnectionMap& conns) const { - std::vector<const Connection*> temp; + std::vector<const Connection*> temp; - const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range = - conns.equal_range(id); + const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range = + conns.equal_range(id); - temp.reserve(std::distance(range.first,range.second)); - for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { - temp.push_back((*it).second); - } + temp.reserve(std::distance(range.first,range.second)); + for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { + temp.push_back((*it).second); + } - std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare)); + std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare)); - return temp; // NRVO should handle this + return temp; // NRVO should handle this } // ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src, - const ConnectionMap& conns, - const char* const* classnames, - size_t count) const +std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src, + const ConnectionMap& conns, + const char* const* classnames, + size_t count) const { - ai_assert(classnames); - ai_assert(count != 0 && count <= MAX_CLASSNAMES); + ai_assert(classnames); + ai_assert(count != 0 && count <= MAX_CLASSNAMES); - size_t lenghts[MAX_CLASSNAMES]; + size_t lenghts[MAX_CLASSNAMES]; - const size_t c = count; - for (size_t i = 0; i < c; ++i) { - lenghts[i] = strlen(classnames[i]); - } + const size_t c = count; + for (size_t i = 0; i < c; ++i) { + lenghts[i] = strlen(classnames[i]); + } - std::vector<const Connection*> temp; + std::vector<const Connection*> temp; - const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range = - conns.equal_range(id); + const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range = + conns.equal_range(id); - temp.reserve(std::distance(range.first,range.second)); - for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { - const Token& key = (is_src - ? (*it).second->LazyDestinationObject() - : (*it).second->LazySourceObject() - ).GetElement().KeyToken(); + temp.reserve(std::distance(range.first,range.second)); + for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { + const Token& key = (is_src + ? (*it).second->LazyDestinationObject() + : (*it).second->LazySourceObject() + ).GetElement().KeyToken(); - const char* obtype = key.begin(); + const char* obtype = key.begin(); - for (size_t i = 0; i < c; ++i) { - ai_assert(classnames[i]); - if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lenghts[i] && !strncmp(classnames[i],obtype,lenghts[i])) { - obtype = NULL; - break; - } - } + for (size_t i = 0; i < c; ++i) { + ai_assert(classnames[i]); + if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lenghts[i] && !strncmp(classnames[i],obtype,lenghts[i])) { + obtype = NULL; + break; + } + } - if(obtype) { - continue; - } + if(obtype) { + continue; + } - temp.push_back((*it).second); - } + temp.push_back((*it).second); + } - std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare)); - return temp; // NRVO should handle this + std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare)); + return temp; // NRVO should handle this } // ------------------------------------------------------------------------------------------------ std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const { - return GetConnectionsSequenced(source, ConnectionsBySource()); + return GetConnectionsSequenced(source, ConnectionsBySource()); } // ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t dest, - const char* classname) const +std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t dest, + const char* classname) const { - const char* arr[] = {classname}; - return GetConnectionsBySourceSequenced(dest, arr,1); + const char* arr[] = {classname}; + return GetConnectionsBySourceSequenced(dest, arr,1); } // ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source, - const char* const* classnames, size_t count) const +std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source, + const char* const* classnames, size_t count) const { - return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count); + return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count); } // ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest, - const char* classname) const +std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest, + const char* classname) const { - const char* arr[] = {classname}; - return GetConnectionsByDestinationSequenced(dest, arr,1); + const char* arr[] = {classname}; + return GetConnectionsByDestinationSequenced(dest, arr,1); } // ------------------------------------------------------------------------------------------------ std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const { - return GetConnectionsSequenced(dest, ConnectionsByDestination()); + return GetConnectionsSequenced(dest, ConnectionsByDestination()); } // ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest, - const char* const* classnames, size_t count) const +std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest, + const char* const* classnames, size_t count) const { - return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count); + return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count); } // ------------------------------------------------------------------------------------------------ -Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, - const Document& doc) +Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, + const Document& doc) : insertionOrder(insertionOrder) , prop(prop) @@ -666,9 +692,9 @@ Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, co , dest(dest) , doc(doc) { - ai_assert(doc.Objects().find(src) != doc.Objects().end()); - // dest may be 0 (root node) - ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end()); + ai_assert(doc.Objects().find(src) != doc.Objects().end()); + // dest may be 0 (root node) + ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end()); } @@ -682,36 +708,36 @@ Connection::~Connection() // ------------------------------------------------------------------------------------------------ LazyObject& Connection::LazySourceObject() const { - LazyObject* const lazy = doc.GetObject(src); - ai_assert(lazy); - return *lazy; + LazyObject* const lazy = doc.GetObject(src); + ai_assert(lazy); + return *lazy; } // ------------------------------------------------------------------------------------------------ LazyObject& Connection::LazyDestinationObject() const { - LazyObject* const lazy = doc.GetObject(dest); - ai_assert(lazy); - return *lazy; + LazyObject* const lazy = doc.GetObject(dest); + ai_assert(lazy); + return *lazy; } // ------------------------------------------------------------------------------------------------ const Object* Connection::SourceObject() const { - LazyObject* const lazy = doc.GetObject(src); - ai_assert(lazy); - return lazy->Get(); + LazyObject* const lazy = doc.GetObject(src); + ai_assert(lazy); + return lazy->Get(); } // ------------------------------------------------------------------------------------------------ const Object* Connection::DestinationObject() const { - LazyObject* const lazy = doc.GetObject(dest); - ai_assert(lazy); - return lazy->Get(); + LazyObject* const lazy = doc.GetObject(dest); + ai_assert(lazy); + return lazy->Get(); } } // !FBX |