summaryrefslogtreecommitdiff
path: root/thirdparty/assimp/code/FBX
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/assimp/code/FBX')
-rw-r--r--thirdparty/assimp/code/FBX/FBXAnimation.cpp305
-rw-r--r--thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp466
-rw-r--r--thirdparty/assimp/code/FBX/FBXCommon.h86
-rw-r--r--thirdparty/assimp/code/FBX/FBXCompileConfig.h78
-rw-r--r--thirdparty/assimp/code/FBX/FBXConverter.cpp3727
-rw-r--r--thirdparty/assimp/code/FBX/FBXConverter.h491
-rw-r--r--thirdparty/assimp/code/FBX/FBXDeformer.cpp213
-rw-r--r--thirdparty/assimp/code/FBX/FBXDocument.cpp718
-rw-r--r--thirdparty/assimp/code/FBX/FBXDocument.h1215
-rw-r--r--thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp135
-rw-r--r--thirdparty/assimp/code/FBX/FBXDocumentUtil.h120
-rw-r--r--thirdparty/assimp/code/FBX/FBXExportNode.cpp571
-rw-r--r--thirdparty/assimp/code/FBX/FBXExportNode.h271
-rw-r--r--thirdparty/assimp/code/FBX/FBXExportProperty.cpp385
-rw-r--r--thirdparty/assimp/code/FBX/FBXExportProperty.h129
-rw-r--r--thirdparty/assimp/code/FBX/FBXExporter.cpp2556
-rw-r--r--thirdparty/assimp/code/FBX/FBXExporter.h178
-rw-r--r--thirdparty/assimp/code/FBX/FBXImportSettings.h164
-rw-r--r--thirdparty/assimp/code/FBX/FBXImporter.cpp198
-rw-r--r--thirdparty/assimp/code/FBX/FBXImporter.h100
-rw-r--r--thirdparty/assimp/code/FBX/FBXMaterial.cpp405
-rw-r--r--thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp709
-rw-r--r--thirdparty/assimp/code/FBX/FBXMeshGeometry.h235
-rw-r--r--thirdparty/assimp/code/FBX/FBXModel.cpp153
-rw-r--r--thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp170
-rw-r--r--thirdparty/assimp/code/FBX/FBXParser.cpp1309
-rw-r--r--thirdparty/assimp/code/FBX/FBXParser.h235
-rw-r--r--thirdparty/assimp/code/FBX/FBXProperties.cpp235
-rw-r--r--thirdparty/assimp/code/FBX/FBXProperties.h185
-rw-r--r--thirdparty/assimp/code/FBX/FBXTokenizer.cpp248
-rw-r--r--thirdparty/assimp/code/FBX/FBXTokenizer.h187
-rw-r--r--thirdparty/assimp/code/FBX/FBXUtil.cpp243
-rw-r--r--thirdparty/assimp/code/FBX/FBXUtil.h137
33 files changed, 0 insertions, 16557 deletions
diff --git a/thirdparty/assimp/code/FBX/FBXAnimation.cpp b/thirdparty/assimp/code/FBX/FBXAnimation.cpp
deleted file mode 100644
index 874914431b..0000000000
--- a/thirdparty/assimp/code/FBX/FBXAnimation.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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","Deformer"};
- const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,3);
-
- 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
diff --git a/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp b/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp
deleted file mode 100644
index a4a2bc8e79..0000000000
--- a/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXBinaryTokenizer.cpp
- * @brief Implementation of a fake lexer for binary fbx files -
- * we emit tokens so the parser needs almost no special handling
- * for binary files.
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include "FBXTokenizer.h"
-#include "FBXUtil.h"
-#include <assimp/defs.h>
-#include <stdint.h>
-#include <assimp/Exceptional.h>
-#include <assimp/ByteSwapper.h>
-
-namespace Assimp {
-namespace FBX {
-
-//enum Flag
-//{
-// e_unknown_0 = 1 << 0,
-// e_unknown_1 = 1 << 1,
-// e_unknown_2 = 1 << 2,
-// e_unknown_3 = 1 << 3,
-// e_unknown_4 = 1 << 4,
-// e_unknown_5 = 1 << 5,
-// e_unknown_6 = 1 << 6,
-// e_unknown_7 = 1 << 7,
-// e_unknown_8 = 1 << 8,
-// e_unknown_9 = 1 << 9,
-// e_unknown_10 = 1 << 10,
-// e_unknown_11 = 1 << 11,
-// e_unknown_12 = 1 << 12,
-// e_unknown_13 = 1 << 13,
-// e_unknown_14 = 1 << 14,
-// e_unknown_15 = 1 << 15,
-// e_unknown_16 = 1 << 16,
-// e_unknown_17 = 1 << 17,
-// e_unknown_18 = 1 << 18,
-// e_unknown_19 = 1 << 19,
-// e_unknown_20 = 1 << 20,
-// e_unknown_21 = 1 << 21,
-// e_unknown_22 = 1 << 22,
-// e_unknown_23 = 1 << 23,
-// e_flag_field_size_64_bit = 1 << 24, // Not sure what is
-// e_unknown_25 = 1 << 25,
-// e_unknown_26 = 1 << 26,
-// e_unknown_27 = 1 << 27,
-// e_unknown_28 = 1 << 28,
-// e_unknown_29 = 1 << 29,
-// e_unknown_30 = 1 << 30,
-// e_unknown_31 = 1 << 31
-//};
-//
-//bool check_flag(uint32_t flags, Flag to_check)
-//{
-// return (flags & to_check) != 0;
-//}
-// ------------------------------------------------------------------------------------------------
-Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset)
- :
- #ifdef DEBUG
- contents(sbegin, static_cast<size_t>(send-sbegin)),
- #endif
- sbegin(sbegin)
- , send(send)
- , type(type)
- , line(offset)
- , column(BINARY_MARKER)
-{
- ai_assert(sbegin);
- ai_assert(send);
-
- // binary tokens may have zero length because they are sometimes dummies
- // inserted by TokenizeBinary()
- ai_assert(send >= sbegin);
-}
-
-
-namespace {
-
-// ------------------------------------------------------------------------------------------------
-// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError.
-AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX;
-AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset)
-{
- throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
-}
-
-
-// ------------------------------------------------------------------------------------------------
-size_t Offset(const char* begin, const char* cursor) {
- ai_assert(begin <= cursor);
-
- return cursor - begin;
-}
-
-// ------------------------------------------------------------------------------------------------
-void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
- TokenizeError(message, Offset(begin, cursor));
-}
-
-// ------------------------------------------------------------------------------------------------
-uint32_t ReadWord(const char* input, const char*& cursor, const char* end) {
- const size_t k_to_read = sizeof( uint32_t );
- if(Offset(cursor, end) < k_to_read ) {
- TokenizeError("cannot ReadWord, out of bounds",input, cursor);
- }
-
- uint32_t word;
- ::memcpy(&word, cursor, 4);
- AI_SWAP4(word);
-
- cursor += k_to_read;
-
- return word;
-}
-
-// ------------------------------------------------------------------------------------------------
-uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) {
- const size_t k_to_read = sizeof(uint64_t);
- if(Offset(cursor, end) < k_to_read) {
- TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor);
- }
-
- uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
- ::memcpy( &dword, cursor, sizeof( uint64_t ) );
- AI_SWAP8(dword);
-
- cursor += k_to_read;
-
- return dword;
-}
-
-// ------------------------------------------------------------------------------------------------
-uint8_t ReadByte(const char* input, const char*& cursor, const char* end) {
- if(Offset(cursor, end) < sizeof( uint8_t ) ) {
- TokenizeError("cannot ReadByte, out of bounds",input, cursor);
- }
-
- uint8_t word;/* = *reinterpret_cast< const uint8_t* >( cursor )*/
- ::memcpy( &word, cursor, sizeof( uint8_t ) );
- ++cursor;
-
- return word;
-}
-
-// ------------------------------------------------------------------------------------------------
-unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input,
- const char*& cursor, const char* end, bool long_length = false, bool allow_null = false) {
- const uint32_t len_len = long_length ? 4 : 1;
- if(Offset(cursor, end) < len_len) {
- TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
- }
-
- const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
-
- if (Offset(cursor, end) < length) {
- TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
- }
-
- sbegin_out = cursor;
- cursor += length;
-
- send_out = cursor;
-
- if(!allow_null) {
- for (unsigned int i = 0; i < length; ++i) {
- if(sbegin_out[i] == '\0') {
- TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
- }
- }
- }
-
- return length;
-}
-
-// ------------------------------------------------------------------------------------------------
-void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) {
- if(Offset(cursor, end) < 1) {
- TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
- }
-
- const char type = *cursor;
- sbegin_out = cursor++;
-
- switch(type)
- {
- // 16 bit int
- case 'Y':
- cursor += 2;
- break;
-
- // 1 bit bool flag (yes/no)
- case 'C':
- cursor += 1;
- break;
-
- // 32 bit int
- case 'I':
- // <- fall through
-
- // float
- case 'F':
- cursor += 4;
- break;
-
- // double
- case 'D':
- cursor += 8;
- break;
-
- // 64 bit int
- case 'L':
- cursor += 8;
- break;
-
- // note: do not write cursor += ReadWord(...cursor) as this would be UB
-
- // raw binary data
- case 'R':
- {
- const uint32_t length = ReadWord(input, cursor, end);
- cursor += length;
- break;
- }
-
- case 'b':
- // TODO: what is the 'b' type code? Right now we just skip over it /
- // take the full range we could get
- cursor = end;
- break;
-
- // array of *
- case 'f':
- case 'd':
- case 'l':
- case 'i':
- case 'c': {
- const uint32_t length = ReadWord(input, cursor, end);
- const uint32_t encoding = ReadWord(input, cursor, end);
-
- const uint32_t comp_len = ReadWord(input, cursor, end);
-
- // compute length based on type and check against the stored value
- if(encoding == 0) {
- uint32_t stride = 0;
- switch(type)
- {
- case 'f':
- case 'i':
- stride = 4;
- break;
-
- case 'd':
- case 'l':
- stride = 8;
- break;
-
- case 'c':
- stride = 1;
- break;
-
- default:
- ai_assert(false);
- };
- ai_assert(stride > 0);
- if(length * stride != comp_len) {
- TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor);
- }
- }
- // zip/deflate algorithm (encoding==1)? take given length. anything else? die
- else if (encoding != 1) {
- TokenizeError("cannot ReadData, unknown encoding",input, cursor);
- }
- cursor += comp_len;
- break;
- }
-
- // string
- case 'S': {
- const char* sb, *se;
- // 0 characters can legally happen in such strings
- ReadString(sb, se, input, cursor, end, true, true);
- break;
- }
- default:
- TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor);
- }
-
- if(cursor > end) {
- TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor);
- }
-
- // the type code is contained in the returned range
- send_out = cursor;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits)
-{
- // the first word contains the offset at which this block ends
- const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
-
- // we may get 0 if reading reached the end of the file -
- // fbx files have a mysterious extra footer which I don't know
- // how to extract any information from, but at least it always
- // starts with a 0.
- if(!end_offset) {
- return false;
- }
-
- if(end_offset > Offset(input, end)) {
- TokenizeError("block offset is out of range",input, cursor);
- }
- else if(end_offset < Offset(input, cursor)) {
- TokenizeError("block offset is negative out of range",input, cursor);
- }
-
- // the second data word contains the number of properties in the scope
- const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
-
- // the third data word contains the length of the property list
- const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
-
- // now comes the name of the scope/key
- const char* sbeg, *send;
- ReadString(sbeg, send, input, cursor, end);
-
- output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) ));
-
- // now come the individual properties
- const char* begin_cursor = cursor;
- for (unsigned int i = 0; i < prop_count; ++i) {
- ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
-
- output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) ));
-
- if(i != prop_count-1) {
- output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) ));
- }
- }
-
- if (Offset(begin_cursor, cursor) != prop_length) {
- TokenizeError("property length not reached, something is wrong",input, cursor);
- }
-
- // at the end of each nested block, there is a NUL record to indicate
- // that the sub-scope exists (i.e. to distinguish between P: and P : {})
- // this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit.
- const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1);
-
- if (Offset(input, cursor) < end_offset) {
- if (end_offset - Offset(input, cursor) < sentinel_block_length) {
- TokenizeError("insufficient padding bytes at block end",input, cursor);
- }
-
- output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) ));
-
- // XXX this is vulnerable to stack overflowing ..
- while(Offset(input, cursor) < end_offset - sentinel_block_length) {
- ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
- }
- output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
-
- for (unsigned int i = 0; i < sentinel_block_length; ++i) {
- if(cursor[i] != '\0') {
- TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor);
- }
- }
- cursor += sentinel_block_length;
- }
-
- if (Offset(input, cursor) != end_offset) {
- TokenizeError("scope length not reached, something is wrong",input, cursor);
- }
-
- return true;
-}
-
-} // anonymous namespace
-
-// ------------------------------------------------------------------------------------------------
-// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
-void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
-{
- ai_assert(input);
-
- if(length < 0x1b) {
- TokenizeError("file is too short",0);
- }
-
- //uint32_t offset = 0x15;
-/* const char* cursor = input + 0x15;
-
- const uint32_t flags = ReadWord(input, cursor, input + length);
-
- const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused
- const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused*/
-
- if (strncmp(input,"Kaydara FBX Binary",18)) {
- TokenizeError("magic bytes not found",0);
- }
-
- const char* cursor = input + 18;
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- /*Result ignored*/ ReadByte(input, cursor, input + length);
- const uint32_t version = ReadWord(input, cursor, input + length);
- const bool is64bits = version >= 7500;
- const char *end = input + length;
- while (cursor < end ) {
- if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
- break;
- }
- }
-}
-
-} // !FBX
-} // !Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXCommon.h b/thirdparty/assimp/code/FBX/FBXCommon.h
deleted file mode 100644
index e516449130..0000000000
--- a/thirdparty/assimp/code/FBX/FBXCommon.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXCommon.h
-* Some useful constants and enums for dealing with FBX files.
-*/
-#ifndef AI_FBXCOMMON_H_INC
-#define AI_FBXCOMMON_H_INC
-
-#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
-
-namespace Assimp {
-namespace FBX
-{
- const std::string NULL_RECORD = { // 13 null bytes
- '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
- }; // who knows why
- const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings
- const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
- const int64_t SECOND = 46186158000; // FBX's kTime unit
-
- // rotation order. We'll probably use EulerXYZ for everything
- enum RotOrder {
- RotOrder_EulerXYZ = 0,
- RotOrder_EulerXZY,
- RotOrder_EulerYZX,
- RotOrder_EulerYXZ,
- RotOrder_EulerZXY,
- RotOrder_EulerZYX,
-
- RotOrder_SphericXYZ,
-
- RotOrder_MAX // end-of-enum sentinel
- };
-
- // transformation inheritance method. Most of the time RSrs
- enum TransformInheritance {
- TransformInheritance_RrSs = 0,
- TransformInheritance_RSrs,
- TransformInheritance_Rrs,
-
- TransformInheritance_MAX // end-of-enum sentinel
- };
-}
-}
-#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#endif // AI_FBXCOMMON_H_INC
diff --git a/thirdparty/assimp/code/FBX/FBXCompileConfig.h b/thirdparty/assimp/code/FBX/FBXCompileConfig.h
deleted file mode 100644
index 03536a1823..0000000000
--- a/thirdparty/assimp/code/FBX/FBXCompileConfig.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXCompileConfig.h
- * @brief FBX importer compile-time switches
- */
-#ifndef INCLUDED_AI_FBX_COMPILECONFIG_H
-#define INCLUDED_AI_FBX_COMPILECONFIG_H
-
-#include <map>
-#include <set>
-
-//
-#if _MSC_VER > 1500 || (defined __GNUC___)
-# define ASSIMP_FBX_USE_UNORDERED_MULTIMAP
-# else
-# define fbx_unordered_map map
-# define fbx_unordered_multimap multimap
-# define fbx_unordered_set set
-# define fbx_unordered_multiset multiset
-#endif
-
-#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
-# include <unordered_map>
-# include <unordered_set>
-# if _MSC_VER > 1600
-# define fbx_unordered_map unordered_map
-# define fbx_unordered_multimap unordered_multimap
-# define fbx_unordered_set unordered_set
-# define fbx_unordered_multiset unordered_multiset
-# else
-# define fbx_unordered_map tr1::unordered_map
-# define fbx_unordered_multimap tr1::unordered_multimap
-# define fbx_unordered_set tr1::unordered_set
-# define fbx_unordered_multiset tr1::unordered_multiset
-# endif
-#endif
-
-#endif // INCLUDED_AI_FBX_COMPILECONFIG_H
diff --git a/thirdparty/assimp/code/FBX/FBXConverter.cpp b/thirdparty/assimp/code/FBX/FBXConverter.cpp
deleted file mode 100644
index d8a22d9f74..0000000000
--- a/thirdparty/assimp/code/FBX/FBXConverter.cpp
+++ /dev/null
@@ -1,3727 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXConverter.cpp
- * @brief Implementation of the FBX DOM -> aiScene converter
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include "FBXConverter.h"
-#include "FBXParser.h"
-#include "FBXMeshGeometry.h"
-#include "FBXDocument.h"
-#include "FBXUtil.h"
-#include "FBXProperties.h"
-#include "FBXImporter.h"
-
-#include <assimp/StringComparison.h>
-#include <assimp/MathFunctions.h>
-
-#include <assimp/scene.h>
-
-#include <assimp/CreateAnimMesh.h>
-
-#include <tuple>
-#include <memory>
-#include <iterator>
-#include <vector>
-#include <sstream>
-#include <iomanip>
-#include <cstdint>
-#include <iostream>
-#include <stdlib.h>
-
-namespace Assimp {
- namespace FBX {
-
- using namespace Util;
-
-#define MAGIC_NODE_TAG "_$AssimpFbx$"
-
-#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
-
- FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones )
- : defaultMaterialIndex()
- , lights()
- , cameras()
- , textures()
- , materials_converted()
- , textures_converted()
- , meshes_converted()
- , node_anim_chain_bits()
- , mNodeNames()
- , anim_fps()
- , out(out)
- , doc(doc) {
- // animations need to be converted first since this will
- // populate the node_anim_chain_bits map, which is needed
- // to determine which nodes need to be generated.
- ConvertAnimations();
- // Embedded textures in FBX could be connected to nothing but to itself,
- // for instance Texture -> Video connection only but not to the main graph,
- // The idea here is to traverse all objects to find these Textures and convert them,
- // so later during material conversion it will find converted texture in the textures_converted array.
- if (doc.Settings().readTextures)
- {
- ConvertOrphantEmbeddedTextures();
- }
- ConvertRootNode();
-
- if (doc.Settings().readAllMaterials) {
- // unfortunately this means we have to evaluate all objects
- for (const ObjectMap::value_type& v : doc.Objects()) {
-
- const Object* ob = v.second->Get();
- if (!ob) {
- continue;
- }
-
- const Material* mat = dynamic_cast<const Material*>(ob);
- if (mat) {
-
- if (materials_converted.find(mat) == materials_converted.end()) {
- ConvertMaterial(*mat, 0);
- }
- }
- }
- }
-
- ConvertGlobalSettings();
- TransferDataToScene();
-
- // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE
- // to make sure the scene passes assimp's validation. FBX files
- // need not contain geometry (i.e. camera animations, raw armatures).
- if (out->mNumMeshes == 0) {
- out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
- }
- }
-
-
- FBXConverter::~FBXConverter() {
- std::for_each(meshes.begin(), meshes.end(), Util::delete_fun<aiMesh>());
- std::for_each(materials.begin(), materials.end(), Util::delete_fun<aiMaterial>());
- std::for_each(animations.begin(), animations.end(), Util::delete_fun<aiAnimation>());
- std::for_each(lights.begin(), lights.end(), Util::delete_fun<aiLight>());
- std::for_each(cameras.begin(), cameras.end(), Util::delete_fun<aiCamera>());
- std::for_each(textures.begin(), textures.end(), Util::delete_fun<aiTexture>());
- }
-
- void FBXConverter::ConvertRootNode() {
- out->mRootNode = new aiNode();
- std::string unique_name;
- GetUniqueName("RootNode", unique_name);
- out->mRootNode->mName.Set(unique_name);
-
- // root has ID 0
- ConvertNodes(0L, out->mRootNode, out->mRootNode);
- }
-
- static std::string getAncestorBaseName(const aiNode* node)
- {
- const char* nodeName = nullptr;
- size_t length = 0;
- while (node && (!nodeName || length == 0))
- {
- nodeName = node->mName.C_Str();
- length = node->mName.length;
- node = node->mParent;
- }
-
- if (!nodeName || length == 0)
- {
- return {};
- }
- // could be std::string_view if c++17 available
- return std::string(nodeName, length);
- }
-
- // Make unique name
- std::string FBXConverter::MakeUniqueNodeName(const Model* const model, const aiNode& parent)
- {
- std::string original_name = FixNodeName(model->Name());
- if (original_name.empty())
- {
- original_name = getAncestorBaseName(&parent);
- }
- std::string unique_name;
- GetUniqueName(original_name, unique_name);
- return unique_name;
- }
- /// todo: pre-build node hierarchy
- /// todo: get bone from stack
- /// todo: make map of aiBone* to aiNode*
- /// then update convert clusters to the new format
- void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
-
- std::vector<aiNode*> nodes;
- nodes.reserve(conns.size());
-
- std::vector<aiNode*> nodes_chain;
- std::vector<aiNode*> post_nodes_chain;
-
- try {
- for (const Connection* con : conns) {
- // ignore object-property links
- if (con->PropertyName().length()) {
- // really important we document why this is ignored.
- FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
- continue; //?
- }
-
- // convert connection source object into Object base class
- const Object* const object = con->SourceObject();
- if (nullptr == object) {
- FBXImporter::LogError("failed to convert source object for Model link");
- continue;
- }
-
- // FBX Model::Cube, Model::Bone001, etc elements
- // This detects if we can cast the object into this model structure.
- const Model* const model = dynamic_cast<const Model*>(object);
-
- if (nullptr != model) {
- nodes_chain.clear();
- post_nodes_chain.clear();
-
- aiMatrix4x4 new_abs_transform = parent->mTransformation;
- std::string node_name = FixNodeName(model->Name());
- // even though there is only a single input node, the design of
- // assimp (or rather: the complicated transformation chain that
- // is employed by fbx) means that we may need multiple aiNode's
- // to represent a fbx node's transformation.
-
-
- // generate node transforms - this includes pivot data
- // if need_additional_node is true then you t
- const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
-
- // assert that for the current node we must have at least a single transform
- ai_assert(nodes_chain.size());
-
- if (need_additional_node) {
- nodes_chain.push_back(new aiNode(node_name));
- }
-
- //setup metadata on newest node
- SetupNodeMetadata(*model, *nodes_chain.back());
-
- // link all nodes in a row
- aiNode* last_parent = parent;
- for (aiNode* child : nodes_chain) {
- ai_assert(child);
-
- if (last_parent != parent) {
- last_parent->mNumChildren = 1;
- last_parent->mChildren = new aiNode*[1];
- last_parent->mChildren[0] = child;
- }
-
- child->mParent = last_parent;
- last_parent = child;
-
- new_abs_transform *= child->mTransformation;
- }
-
- // attach geometry
- ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform);
-
- // check if there will be any child nodes
- const std::vector<const Connection*>& child_conns
- = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
-
- // if so, link the geometric transform inverse nodes
- // before we attach any child nodes
- if (child_conns.size()) {
- for (aiNode* postnode : post_nodes_chain) {
- ai_assert(postnode);
-
- if (last_parent != parent) {
- last_parent->mNumChildren = 1;
- last_parent->mChildren = new aiNode*[1];
- last_parent->mChildren[0] = postnode;
- }
-
- postnode->mParent = last_parent;
- last_parent = postnode;
-
- new_abs_transform *= postnode->mTransformation;
- }
- }
- else {
- // free the nodes we allocated as we don't need them
- Util::delete_fun<aiNode> deleter;
- std::for_each(
- post_nodes_chain.begin(),
- post_nodes_chain.end(),
- deleter
- );
- }
-
- // recursion call - child nodes
- ConvertNodes(model->ID(), last_parent, root_node);
-
- if (doc.Settings().readLights) {
- ConvertLights(*model, node_name);
- }
-
- if (doc.Settings().readCameras) {
- ConvertCameras(*model, node_name);
- }
-
- nodes.push_back(nodes_chain.front());
- nodes_chain.clear();
- }
- }
-
- if (nodes.size()) {
- parent->mChildren = new aiNode*[nodes.size()]();
- parent->mNumChildren = static_cast<unsigned int>(nodes.size());
-
- std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren);
- }
- else
- {
- parent->mNumChildren = 0;
- parent->mChildren = nullptr;
- }
-
- }
- catch (std::exception&) {
- Util::delete_fun<aiNode> deleter;
- std::for_each(nodes.begin(), nodes.end(), deleter);
- std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter);
- std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter);
- }
- }
-
-
- void FBXConverter::ConvertLights(const Model& model, const std::string &orig_name) {
- const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
- for (const NodeAttribute* attr : node_attrs) {
- const Light* const light = dynamic_cast<const Light*>(attr);
- if (light) {
- ConvertLight(*light, orig_name);
- }
- }
- }
-
- void FBXConverter::ConvertCameras(const Model& model, const std::string &orig_name) {
- const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
- for (const NodeAttribute* attr : node_attrs) {
- const Camera* const cam = dynamic_cast<const Camera*>(attr);
- if (cam) {
- ConvertCamera(*cam, orig_name);
- }
- }
- }
-
- void FBXConverter::ConvertLight(const Light& light, const std::string &orig_name) {
- lights.push_back(new aiLight());
- aiLight* const out_light = lights.back();
-
- out_light->mName.Set(orig_name);
-
- const float intensity = light.Intensity() / 100.0f;
- const aiVector3D& col = light.Color();
-
- out_light->mColorDiffuse = aiColor3D(col.x, col.y, col.z);
- out_light->mColorDiffuse.r *= intensity;
- out_light->mColorDiffuse.g *= intensity;
- out_light->mColorDiffuse.b *= intensity;
-
- out_light->mColorSpecular = out_light->mColorDiffuse;
-
- //lights are defined along negative y direction
- out_light->mPosition = aiVector3D(0.0f);
- out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f);
- out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f);
-
- switch (light.LightType())
- {
- case Light::Type_Point:
- out_light->mType = aiLightSource_POINT;
- break;
-
- case Light::Type_Directional:
- out_light->mType = aiLightSource_DIRECTIONAL;
- break;
-
- case Light::Type_Spot:
- out_light->mType = aiLightSource_SPOT;
- out_light->mAngleOuterCone = AI_DEG_TO_RAD(light.OuterAngle());
- out_light->mAngleInnerCone = AI_DEG_TO_RAD(light.InnerAngle());
- break;
-
- case Light::Type_Area:
- FBXImporter::LogWarn("cannot represent area light, set to UNDEFINED");
- out_light->mType = aiLightSource_UNDEFINED;
- break;
-
- case Light::Type_Volume:
- FBXImporter::LogWarn("cannot represent volume light, set to UNDEFINED");
- out_light->mType = aiLightSource_UNDEFINED;
- break;
- default:
- ai_assert(false);
- }
-
- float decay = light.DecayStart();
- switch (light.DecayType())
- {
- case Light::Decay_None:
- out_light->mAttenuationConstant = decay;
- out_light->mAttenuationLinear = 0.0f;
- out_light->mAttenuationQuadratic = 0.0f;
- break;
- case Light::Decay_Linear:
- out_light->mAttenuationConstant = 0.0f;
- out_light->mAttenuationLinear = 2.0f / decay;
- out_light->mAttenuationQuadratic = 0.0f;
- break;
- case Light::Decay_Quadratic:
- out_light->mAttenuationConstant = 0.0f;
- out_light->mAttenuationLinear = 0.0f;
- out_light->mAttenuationQuadratic = 2.0f / (decay * decay);
- break;
- case Light::Decay_Cubic:
- FBXImporter::LogWarn("cannot represent cubic attenuation, set to Quadratic");
- out_light->mAttenuationQuadratic = 1.0f;
- break;
- default:
- ai_assert(false);
- break;
- }
- }
-
- void FBXConverter::ConvertCamera(const Camera& cam, const std::string &orig_name)
- {
- cameras.push_back(new aiCamera());
- aiCamera* const out_camera = cameras.back();
-
- out_camera->mName.Set(orig_name);
-
- out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
-
- out_camera->mPosition = aiVector3D(0.0f);
- out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
- out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
-
- out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
-
- out_camera->mClipPlaneNear = cam.NearPlane();
- out_camera->mClipPlaneFar = cam.FarPlane();
-
- out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
- out_camera->mClipPlaneNear = cam.NearPlane();
- out_camera->mClipPlaneFar = cam.FarPlane();
- }
-
- void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName)
- {
- uniqueName = name;
- auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
- unsigned int& i = it_pair.first->second;
- while (!it_pair.second)
- {
- i++;
- std::ostringstream ext;
- ext << name << std::setfill('0') << std::setw(3) << i;
- uniqueName = ext.str();
- it_pair = mNodeNames.insert({ uniqueName, 0 });
- }
- }
-
- const char* FBXConverter::NameTransformationComp(TransformationComp comp) {
- switch (comp) {
- case TransformationComp_Translation:
- return "Translation";
- case TransformationComp_RotationOffset:
- return "RotationOffset";
- case TransformationComp_RotationPivot:
- return "RotationPivot";
- case TransformationComp_PreRotation:
- return "PreRotation";
- case TransformationComp_Rotation:
- return "Rotation";
- case TransformationComp_PostRotation:
- return "PostRotation";
- case TransformationComp_RotationPivotInverse:
- return "RotationPivotInverse";
- case TransformationComp_ScalingOffset:
- return "ScalingOffset";
- case TransformationComp_ScalingPivot:
- return "ScalingPivot";
- case TransformationComp_Scaling:
- return "Scaling";
- case TransformationComp_ScalingPivotInverse:
- return "ScalingPivotInverse";
- case TransformationComp_GeometricScaling:
- return "GeometricScaling";
- case TransformationComp_GeometricRotation:
- return "GeometricRotation";
- case TransformationComp_GeometricTranslation:
- return "GeometricTranslation";
- case TransformationComp_GeometricScalingInverse:
- return "GeometricScalingInverse";
- case TransformationComp_GeometricRotationInverse:
- return "GeometricRotationInverse";
- case TransformationComp_GeometricTranslationInverse:
- return "GeometricTranslationInverse";
- case TransformationComp_MAXIMUM: // this is to silence compiler warnings
- default:
- break;
- }
-
- ai_assert(false);
-
- return nullptr;
- }
-
- const char* FBXConverter::NameTransformationCompProperty(TransformationComp comp) {
- switch (comp) {
- case TransformationComp_Translation:
- return "Lcl Translation";
- case TransformationComp_RotationOffset:
- return "RotationOffset";
- case TransformationComp_RotationPivot:
- return "RotationPivot";
- case TransformationComp_PreRotation:
- return "PreRotation";
- case TransformationComp_Rotation:
- return "Lcl Rotation";
- case TransformationComp_PostRotation:
- return "PostRotation";
- case TransformationComp_RotationPivotInverse:
- return "RotationPivotInverse";
- case TransformationComp_ScalingOffset:
- return "ScalingOffset";
- case TransformationComp_ScalingPivot:
- return "ScalingPivot";
- case TransformationComp_Scaling:
- return "Lcl Scaling";
- case TransformationComp_ScalingPivotInverse:
- return "ScalingPivotInverse";
- case TransformationComp_GeometricScaling:
- return "GeometricScaling";
- case TransformationComp_GeometricRotation:
- return "GeometricRotation";
- case TransformationComp_GeometricTranslation:
- return "GeometricTranslation";
- case TransformationComp_GeometricScalingInverse:
- return "GeometricScalingInverse";
- case TransformationComp_GeometricRotationInverse:
- return "GeometricRotationInverse";
- case TransformationComp_GeometricTranslationInverse:
- return "GeometricTranslationInverse";
- case TransformationComp_MAXIMUM: // this is to silence compiler warnings
- break;
- }
-
- ai_assert(false);
-
- return nullptr;
- }
-
- aiVector3D FBXConverter::TransformationCompDefaultValue(TransformationComp comp)
- {
- // XXX a neat way to solve the never-ending special cases for scaling
- // would be to do everything in log space!
- return comp == TransformationComp_Scaling ? aiVector3D(1.f, 1.f, 1.f) : aiVector3D();
- }
-
- void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out)
- {
- if (mode == Model::RotOrder_SphericXYZ) {
- FBXImporter::LogError("Unsupported RotationMode: SphericXYZ");
- out = aiMatrix4x4();
- return;
- }
-
- const float angle_epsilon = Math::getEpsilon<float>();
-
- out = aiMatrix4x4();
-
- bool is_id[3] = { true, true, true };
-
- aiMatrix4x4 temp[3];
- if (std::fabs(rotation.z) > angle_epsilon) {
- aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z), temp[2]);
- is_id[2] = false;
- }
- if (std::fabs(rotation.y) > angle_epsilon) {
- aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y), temp[1]);
- is_id[1] = false;
- }
- if (std::fabs(rotation.x) > angle_epsilon) {
- aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x), temp[0]);
- is_id[0] = false;
- }
-
- int order[3] = { -1, -1, -1 };
-
- // note: rotation order is inverted since we're left multiplying as is usual in assimp
- switch (mode)
- {
- case Model::RotOrder_EulerXYZ:
- order[0] = 2;
- order[1] = 1;
- order[2] = 0;
- break;
-
- case Model::RotOrder_EulerXZY:
- order[0] = 1;
- order[1] = 2;
- order[2] = 0;
- break;
-
- case Model::RotOrder_EulerYZX:
- order[0] = 0;
- order[1] = 2;
- order[2] = 1;
- break;
-
- case Model::RotOrder_EulerYXZ:
- order[0] = 2;
- order[1] = 0;
- order[2] = 1;
- break;
-
- case Model::RotOrder_EulerZXY:
- order[0] = 1;
- order[1] = 0;
- order[2] = 2;
- break;
-
- case Model::RotOrder_EulerZYX:
- order[0] = 0;
- order[1] = 1;
- order[2] = 2;
- break;
-
- default:
- ai_assert(false);
- break;
- }
-
- ai_assert(order[0] >= 0);
- ai_assert(order[0] <= 2);
- ai_assert(order[1] >= 0);
- ai_assert(order[1] <= 2);
- ai_assert(order[2] >= 0);
- ai_assert(order[2] <= 2);
-
- if (!is_id[order[0]]) {
- out = temp[order[0]];
- }
-
- if (!is_id[order[1]]) {
- out = out * temp[order[1]];
- }
-
- if (!is_id[order[2]]) {
- out = out * temp[order[2]];
- }
- }
-
- bool FBXConverter::NeedsComplexTransformationChain(const Model& model)
- {
- const PropertyTable& props = model.Props();
- bool ok;
-
- const float zero_epsilon = 1e-6f;
- const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
- for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
- const TransformationComp comp = static_cast<TransformationComp>(i);
-
- if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) {
- continue;
- }
-
- bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
-
- const aiVector3D& v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
- if (ok && scale_compare) {
- if ((v - all_ones).SquareLength() > zero_epsilon) {
- return true;
- }
- } else if (ok) {
- if (v.SquareLength() > zero_epsilon) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- std::string FBXConverter::NameTransformationChainNode(const std::string& name, TransformationComp comp)
- {
- return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
- }
-
- bool FBXConverter::GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes,
- std::vector<aiNode*>& post_output_nodes) {
- const PropertyTable& props = model.Props();
- const Model::RotOrder rot = model.RotationOrder();
-
- bool ok;
-
- aiMatrix4x4 chain[TransformationComp_MAXIMUM];
-
- ai_assert(TransformationComp_MAXIMUM < 32);
- std::uint32_t chainBits = 0;
- // A node won't need a node chain if it only has these.
- const std::uint32_t chainMaskSimple = (1 << TransformationComp_Translation) + (1 << TransformationComp_Scaling) + (1 << TransformationComp_Rotation);
- // A node will need a node chain if it has any of these.
- const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple;
-
- std::fill_n(chain, static_cast<unsigned int>(TransformationComp_MAXIMUM), aiMatrix4x4());
-
- // generate transformation matrices for all the different transformation components
- const float zero_epsilon = Math::getEpsilon<float>();
- const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
-
- const aiVector3D& PreRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
- if (ok && PreRotation.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_PreRotation);
-
- GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]);
- }
-
- const aiVector3D& PostRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok);
- if (ok && PostRotation.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_PostRotation);
-
- GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]);
- }
-
- const aiVector3D& RotationPivot = PropertyGet<aiVector3D>(props, "RotationPivot", ok);
- if (ok && RotationPivot.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse);
-
- aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]);
- aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]);
- }
-
- const aiVector3D& RotationOffset = PropertyGet<aiVector3D>(props, "RotationOffset", ok);
- if (ok && RotationOffset.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_RotationOffset);
-
- aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]);
- }
-
- const aiVector3D& ScalingOffset = PropertyGet<aiVector3D>(props, "ScalingOffset", ok);
- if (ok && ScalingOffset.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_ScalingOffset);
-
- aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]);
- }
-
- const aiVector3D& ScalingPivot = PropertyGet<aiVector3D>(props, "ScalingPivot", ok);
- if (ok && ScalingPivot.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse);
-
- aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]);
- aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]);
- }
-
- const aiVector3D& Translation = PropertyGet<aiVector3D>(props, "Lcl Translation", ok);
- if (ok && Translation.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_Translation);
-
- aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]);
- }
-
- const aiVector3D& Scaling = PropertyGet<aiVector3D>(props, "Lcl Scaling", ok);
- if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_Scaling);
-
- aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]);
- }
-
- const aiVector3D& Rotation = PropertyGet<aiVector3D>(props, "Lcl Rotation", ok);
- if (ok && Rotation.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_Rotation);
-
- GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]);
- }
-
- const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok);
- if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_GeometricScaling);
- aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]);
- aiVector3D GeometricScalingInverse = GeometricScaling;
- bool canscale = true;
- for (unsigned int i = 0; i < 3; ++i) {
- if (std::fabs(GeometricScalingInverse[i]) > zero_epsilon) {
- GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
- }
- else {
- FBXImporter::LogError("cannot invert geometric scaling matrix with a 0.0 scale component");
- canscale = false;
- break;
- }
- }
- if (canscale) {
- chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse);
- aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]);
- }
- }
-
- const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>(props, "GeometricRotation", ok);
- if (ok && GeometricRotation.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse);
- GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]);
- GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]);
- chain[TransformationComp_GeometricRotationInverse].Inverse();
- }
-
- const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>(props, "GeometricTranslation", ok);
- if (ok && GeometricTranslation.SquareLength() > zero_epsilon) {
- chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse);
- aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]);
- aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]);
- }
-
- // is_complex needs to be consistent with NeedsComplexTransformationChain()
- // or the interplay between this code and the animation converter would
- // not be guaranteed.
- //ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0));
-
- // now, if we have more than just Translation, Scaling and Rotation,
- // we need to generate a full node chain to accommodate for assimp's
- // lack to express pivots and offsets.
- if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) {
- FBXImporter::LogInfo("generating full transformation chain for node: " + name);
-
- // query the anim_chain_bits dictionary to find out which chain elements
- // have associated node animation channels. These can not be dropped
- // even if they have identity transform in bind pose.
- NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find(name);
- const unsigned int anim_chain_bitmask = (it == node_anim_chain_bits.end() ? 0 : (*it).second);
-
- unsigned int bit = 0x1;
- for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) {
- const TransformationComp comp = static_cast<TransformationComp>(i);
-
- if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) {
- continue;
- }
-
- if (comp == TransformationComp_PostRotation) {
- chain[i] = chain[i].Inverse();
- }
-
- aiNode* nd = new aiNode();
- nd->mName.Set(NameTransformationChainNode(name, comp));
- nd->mTransformation = chain[i];
-
- // geometric inverses go in a post-node chain
- if (comp == TransformationComp_GeometricScalingInverse ||
- comp == TransformationComp_GeometricRotationInverse ||
- comp == TransformationComp_GeometricTranslationInverse
- ) {
- post_output_nodes.push_back(nd);
- }
- else {
- output_nodes.push_back(nd);
- }
- }
-
- ai_assert(output_nodes.size());
- return true;
- }
-
- // else, we can just multiply the matrices together
- aiNode* nd = new aiNode();
- output_nodes.push_back(nd);
-
- // name passed to the method is already unique
- nd->mName.Set(name);
-
- for (const auto &transform : chain) {
- nd->mTransformation = nd->mTransformation * transform;
- }
- return false;
- }
-
- void FBXConverter::SetupNodeMetadata(const Model& model, aiNode& nd)
- {
- const PropertyTable& props = model.Props();
- DirectPropertyMap unparsedProperties = props.GetUnparsedProperties();
-
- // create metadata on node
- const std::size_t numStaticMetaData = 2;
- aiMetadata* data = aiMetadata::Alloc(static_cast<unsigned int>(unparsedProperties.size() + numStaticMetaData));
- nd.mMetaData = data;
- int index = 0;
-
- // find user defined properties (3ds Max)
- data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", "")));
- // preserve the info that a node was marked as Null node in the original file.
- data->Set(index++, "IsNull", model.IsNull() ? true : false);
-
- // add unparsed properties to the node's metadata
- for (const DirectPropertyMap::value_type& prop : unparsedProperties) {
- // Interpret the property as a concrete type
- if (const TypedProperty<bool>* interpreted = prop.second->As<TypedProperty<bool> >()) {
- data->Set(index++, prop.first, interpreted->Value());
- }
- else if (const TypedProperty<int>* interpreted = prop.second->As<TypedProperty<int> >()) {
- data->Set(index++, prop.first, interpreted->Value());
- }
- else if (const TypedProperty<uint64_t>* interpreted = prop.second->As<TypedProperty<uint64_t> >()) {
- data->Set(index++, prop.first, interpreted->Value());
- }
- else if (const TypedProperty<float>* interpreted = prop.second->As<TypedProperty<float> >()) {
- data->Set(index++, prop.first, interpreted->Value());
- }
- else if (const TypedProperty<std::string>* interpreted = prop.second->As<TypedProperty<std::string> >()) {
- data->Set(index++, prop.first, aiString(interpreted->Value()));
- }
- else if (const TypedProperty<aiVector3D>* interpreted = prop.second->As<TypedProperty<aiVector3D> >()) {
- data->Set(index++, prop.first, interpreted->Value());
- }
- else {
- ai_assert(false);
- }
- }
- }
-
- void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
- const aiMatrix4x4 &absolute_transform)
- {
- const std::vector<const Geometry*>& geos = model.GetGeometry();
-
- std::vector<unsigned int> meshes;
- meshes.reserve(geos.size());
-
- for (const Geometry* geo : geos) {
-
- const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*>(geo);
- const LineGeometry* const line = dynamic_cast<const LineGeometry*>(geo);
- if (mesh) {
- const std::vector<unsigned int>& indices = ConvertMesh(*mesh, model, parent, root_node,
- absolute_transform);
- std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
- }
- else if (line) {
- const std::vector<unsigned int>& indices = ConvertLine(*line, model, parent, root_node);
- std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
- }
- else {
- FBXImporter::LogWarn("ignoring unrecognized geometry: " + geo->Name());
- }
- }
-
- if (meshes.size()) {
- parent->mMeshes = new unsigned int[meshes.size()]();
- parent->mNumMeshes = static_cast<unsigned int>(meshes.size());
-
- std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes);
- }
- }
-
- std::vector<unsigned int>
- FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
- const aiMatrix4x4 &absolute_transform)
- {
- std::vector<unsigned int> temp;
-
- MeshMap::const_iterator it = meshes_converted.find(&mesh);
- if (it != meshes_converted.end()) {
- std::copy((*it).second.begin(), (*it).second.end(), std::back_inserter(temp));
- return temp;
- }
-
- const std::vector<aiVector3D>& vertices = mesh.GetVertices();
- const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
- if (vertices.empty() || faces.empty()) {
- FBXImporter::LogWarn("ignoring empty geometry: " + mesh.Name());
- return temp;
- }
-
- // one material per mesh maps easily to aiMesh. Multiple material
- // meshes need to be split.
- const MatIndexArray& mindices = mesh.GetMaterialIndices();
- if (doc.Settings().readMaterials && !mindices.empty()) {
- const MatIndexArray::value_type base = mindices[0];
- for (MatIndexArray::value_type index : mindices) {
- if (index != base) {
- return ConvertMeshMultiMaterial(mesh, model, parent, root_node, absolute_transform);
- }
- }
- }
-
- // faster code-path, just copy the data
- temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
- return temp;
- }
-
- std::vector<unsigned int> FBXConverter::ConvertLine(const LineGeometry& line, const Model& model,
- aiNode *parent, aiNode *root_node)
- {
- std::vector<unsigned int> temp;
-
- const std::vector<aiVector3D>& vertices = line.GetVertices();
- const std::vector<int>& indices = line.GetIndices();
- if (vertices.empty() || indices.empty()) {
- FBXImporter::LogWarn("ignoring empty line: " + line.Name());
- return temp;
- }
-
- aiMesh* const out_mesh = SetupEmptyMesh(line, root_node);
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
-
- // copy vertices
- out_mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
- out_mesh->mVertices = new aiVector3D[out_mesh->mNumVertices];
- std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices);
-
- //Number of line segments (faces) is "Number of Points - Number of Endpoints"
- //N.B.: Endpoints in FbxLine are denoted by negative indices.
- //If such an Index is encountered, add 1 and multiply by -1 to get the real index.
- unsigned int epcount = 0;
- for (unsigned i = 0; i < indices.size(); i++)
- {
- if (indices[i] < 0) {
- epcount++;
- }
- }
- unsigned int pcount = static_cast<unsigned int>( indices.size() );
- unsigned int scount = out_mesh->mNumFaces = pcount - epcount;
-
- aiFace* fac = out_mesh->mFaces = new aiFace[scount]();
- for (unsigned int i = 0; i < pcount; ++i) {
- if (indices[i] < 0) continue;
- aiFace& f = *fac++;
- f.mNumIndices = 2; //2 == aiPrimitiveType_LINE
- f.mIndices = new unsigned int[2];
- f.mIndices[0] = indices[i];
- int segid = indices[(i + 1 == pcount ? 0 : i + 1)]; //If we have reached he last point, wrap around
- f.mIndices[1] = (segid < 0 ? (segid + 1)*-1 : segid); //Convert EndPoint Index to normal Index
- }
- temp.push_back(static_cast<unsigned int>(meshes.size() - 1));
- return temp;
- }
-
- aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode *parent)
- {
- aiMesh* const out_mesh = new aiMesh();
- meshes.push_back(out_mesh);
- meshes_converted[&mesh].push_back(static_cast<unsigned int>(meshes.size() - 1));
-
- // set name
- std::string name = mesh.Name();
- if (name.substr(0, 10) == "Geometry::") {
- name = name.substr(10);
- }
-
- if (name.length()) {
- out_mesh->mName.Set(name);
- }
- else
- {
- out_mesh->mName = parent->mName;
- }
-
- return out_mesh;
- }
-
- unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
- const aiMatrix4x4 &absolute_transform, aiNode *parent,
- aiNode *root_node)
- {
- const MatIndexArray& mindices = mesh.GetMaterialIndices();
- aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent);
-
- const std::vector<aiVector3D>& vertices = mesh.GetVertices();
- const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
-
- // copy vertices
- out_mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
- out_mesh->mVertices = new aiVector3D[vertices.size()];
-
- std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices);
-
- // generate dummy faces
- out_mesh->mNumFaces = static_cast<unsigned int>(faces.size());
- aiFace* fac = out_mesh->mFaces = new aiFace[faces.size()]();
-
- unsigned int cursor = 0;
- for (unsigned int pcount : faces) {
- aiFace& f = *fac++;
- f.mNumIndices = pcount;
- f.mIndices = new unsigned int[pcount];
- switch (pcount)
- {
- case 1:
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
- break;
- case 2:
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
- break;
- case 3:
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
- break;
- default:
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
- break;
- }
- for (unsigned int i = 0; i < pcount; ++i) {
- f.mIndices[i] = cursor++;
- }
- }
-
- // copy normals
- const std::vector<aiVector3D>& normals = mesh.GetNormals();
- if (normals.size()) {
- ai_assert(normals.size() == vertices.size());
-
- out_mesh->mNormals = new aiVector3D[vertices.size()];
- std::copy(normals.begin(), normals.end(), out_mesh->mNormals);
- }
-
- // copy tangents - assimp requires both tangents and bitangents (binormals)
- // to be present, or neither of them. Compute binormals from normals
- // and tangents if needed.
- const std::vector<aiVector3D>& tangents = mesh.GetTangents();
- const std::vector<aiVector3D>* binormals = &mesh.GetBinormals();
-
- if (tangents.size()) {
- std::vector<aiVector3D> tempBinormals;
- if (!binormals->size()) {
- if (normals.size()) {
- tempBinormals.resize(normals.size());
- for (unsigned int i = 0; i < tangents.size(); ++i) {
- tempBinormals[i] = normals[i] ^ tangents[i];
- }
-
- binormals = &tempBinormals;
- }
- else {
- binormals = nullptr;
- }
- }
-
- if (binormals) {
- ai_assert(tangents.size() == vertices.size());
- ai_assert(binormals->size() == vertices.size());
-
- out_mesh->mTangents = new aiVector3D[vertices.size()];
- std::copy(tangents.begin(), tangents.end(), out_mesh->mTangents);
-
- out_mesh->mBitangents = new aiVector3D[vertices.size()];
- std::copy(binormals->begin(), binormals->end(), out_mesh->mBitangents);
- }
- }
-
- // copy texture coords
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
- const std::vector<aiVector2D>& uvs = mesh.GetTextureCoords(i);
- if (uvs.empty()) {
- break;
- }
-
- aiVector3D* out_uv = out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()];
- for (const aiVector2D& v : uvs) {
- *out_uv++ = aiVector3D(v.x, v.y, 0.0f);
- }
-
- out_mesh->mNumUVComponents[i] = 2;
- }
-
- // copy vertex colors
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
- const std::vector<aiColor4D>& colors = mesh.GetVertexColors(i);
- if (colors.empty()) {
- break;
- }
-
- out_mesh->mColors[i] = new aiColor4D[vertices.size()];
- std::copy(colors.begin(), colors.end(), out_mesh->mColors[i]);
- }
-
- if (!doc.Settings().readMaterials || mindices.empty()) {
- FBXImporter::LogError("no material assigned to mesh, setting default material");
- out_mesh->mMaterialIndex = GetDefaultMaterial();
- }
- else {
- ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
- }
-
- if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) {
- ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, NO_MATERIAL_SEPARATION,
- nullptr);
- }
-
- std::vector<aiAnimMesh*> animMeshes;
- for (const BlendShape* blendShape : mesh.GetBlendShapes()) {
- for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) {
- const std::vector<const ShapeGeometry*>& shapeGeometries = blendShapeChannel->GetShapeGeometries();
- for (size_t i = 0; i < shapeGeometries.size(); i++) {
- aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh);
- const ShapeGeometry* shapeGeometry = shapeGeometries.at(i);
- const std::vector<aiVector3D>& vertices = shapeGeometry->GetVertices();
- const std::vector<aiVector3D>& normals = shapeGeometry->GetNormals();
- const std::vector<unsigned int>& indices = shapeGeometry->GetIndices();
- animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
- for (size_t j = 0; j < indices.size(); j++) {
- unsigned int index = indices.at(j);
- aiVector3D vertex = vertices.at(j);
- aiVector3D normal = normals.at(j);
- unsigned int count = 0;
- const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count);
- for (unsigned int k = 0; k < count; k++) {
- unsigned int index = outIndices[k];
- animMesh->mVertices[index] += vertex;
- if (animMesh->mNormals != nullptr) {
- animMesh->mNormals[index] += normal;
- animMesh->mNormals[index].NormalizeSafe();
- }
- }
- }
- animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f;
- animMeshes.push_back(animMesh);
- }
- }
- }
- const size_t numAnimMeshes = animMeshes.size();
- if (numAnimMeshes > 0) {
- out_mesh->mNumAnimMeshes = static_cast<unsigned int>(numAnimMeshes);
- out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes];
- for (size_t i = 0; i < numAnimMeshes; i++) {
- out_mesh->mAnimMeshes[i] = animMeshes.at(i);
- }
- }
- return static_cast<unsigned int>(meshes.size() - 1);
- }
-
- std::vector<unsigned int>
- FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent,
- aiNode *root_node,
- const aiMatrix4x4 &absolute_transform)
- {
- const MatIndexArray& mindices = mesh.GetMaterialIndices();
- ai_assert(mindices.size());
-
- std::set<MatIndexArray::value_type> had;
- std::vector<unsigned int> indices;
-
- for (MatIndexArray::value_type index : mindices) {
- if (had.find(index) == had.end()) {
-
- indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node, absolute_transform));
- had.insert(index);
- }
- }
-
- return indices;
- }
-
- unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model,
- MatIndexArray::value_type index,
- aiNode *parent, aiNode *root_node,
- const aiMatrix4x4 &absolute_transform)
- {
- aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent);
-
- const MatIndexArray& mindices = mesh.GetMaterialIndices();
- const std::vector<aiVector3D>& vertices = mesh.GetVertices();
- const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
-
- const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != nullptr;
-
- unsigned int count_faces = 0;
- unsigned int count_vertices = 0;
-
- // count faces
- std::vector<unsigned int>::const_iterator itf = faces.begin();
- for (MatIndexArray::const_iterator it = mindices.begin(),
- end = mindices.end(); it != end; ++it, ++itf)
- {
- if ((*it) != index) {
- continue;
- }
- ++count_faces;
- count_vertices += *itf;
- }
-
- ai_assert(count_faces);
- ai_assert(count_vertices);
-
- // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes
- std::vector<unsigned int> reverseMapping;
- std::map<unsigned int, unsigned int> translateIndexMap;
- if (process_weights || mesh.GetBlendShapes().size() > 0) {
- reverseMapping.resize(count_vertices);
- }
-
- // allocate output data arrays, but don't fill them yet
- out_mesh->mNumVertices = count_vertices;
- out_mesh->mVertices = new aiVector3D[count_vertices];
-
- out_mesh->mNumFaces = count_faces;
- aiFace* fac = out_mesh->mFaces = new aiFace[count_faces]();
-
-
- // allocate normals
- const std::vector<aiVector3D>& normals = mesh.GetNormals();
- if (normals.size()) {
- ai_assert(normals.size() == vertices.size());
- out_mesh->mNormals = new aiVector3D[vertices.size()];
- }
-
- // allocate tangents, binormals.
- const std::vector<aiVector3D>& tangents = mesh.GetTangents();
- const std::vector<aiVector3D>* binormals = &mesh.GetBinormals();
- std::vector<aiVector3D> tempBinormals;
-
- if (tangents.size()) {
- if (!binormals->size()) {
- if (normals.size()) {
- // XXX this computes the binormals for the entire mesh, not only
- // the part for which we need them.
- tempBinormals.resize(normals.size());
- for (unsigned int i = 0; i < tangents.size(); ++i) {
- tempBinormals[i] = normals[i] ^ tangents[i];
- }
-
- binormals = &tempBinormals;
- }
- else {
- binormals = nullptr;
- }
- }
-
- if (binormals) {
- ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size());
-
- out_mesh->mTangents = new aiVector3D[vertices.size()];
- out_mesh->mBitangents = new aiVector3D[vertices.size()];
- }
- }
-
- // allocate texture coords
- unsigned int num_uvs = 0;
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i, ++num_uvs) {
- const std::vector<aiVector2D>& uvs = mesh.GetTextureCoords(i);
- if (uvs.empty()) {
- break;
- }
-
- out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()];
- out_mesh->mNumUVComponents[i] = 2;
- }
-
- // allocate vertex colors
- unsigned int num_vcs = 0;
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i, ++num_vcs) {
- const std::vector<aiColor4D>& colors = mesh.GetVertexColors(i);
- if (colors.empty()) {
- break;
- }
-
- out_mesh->mColors[i] = new aiColor4D[vertices.size()];
- }
-
- unsigned int cursor = 0, in_cursor = 0;
-
- itf = faces.begin();
- for (MatIndexArray::const_iterator it = mindices.begin(), end = mindices.end(); it != end; ++it, ++itf)
- {
- const unsigned int pcount = *itf;
- if ((*it) != index) {
- in_cursor += pcount;
- continue;
- }
-
- aiFace& f = *fac++;
-
- f.mNumIndices = pcount;
- f.mIndices = new unsigned int[pcount];
- switch (pcount)
- {
- case 1:
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
- break;
- case 2:
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
- break;
- case 3:
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
- break;
- default:
- out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
- break;
- }
- for (unsigned int i = 0; i < pcount; ++i, ++cursor, ++in_cursor) {
- f.mIndices[i] = cursor;
-
- if (reverseMapping.size()) {
- reverseMapping[cursor] = in_cursor;
- translateIndexMap[in_cursor] = cursor;
- }
-
- out_mesh->mVertices[cursor] = vertices[in_cursor];
-
- if (out_mesh->mNormals) {
- out_mesh->mNormals[cursor] = normals[in_cursor];
- }
-
- if (out_mesh->mTangents) {
- out_mesh->mTangents[cursor] = tangents[in_cursor];
- out_mesh->mBitangents[cursor] = (*binormals)[in_cursor];
- }
-
- for (unsigned int j = 0; j < num_uvs; ++j) {
- const std::vector<aiVector2D>& uvs = mesh.GetTextureCoords(j);
- out_mesh->mTextureCoords[j][cursor] = aiVector3D(uvs[in_cursor].x, uvs[in_cursor].y, 0.0f);
- }
-
- for (unsigned int j = 0; j < num_vcs; ++j) {
- const std::vector<aiColor4D>& cols = mesh.GetVertexColors(j);
- out_mesh->mColors[j][cursor] = cols[in_cursor];
- }
- }
- }
-
- ConvertMaterialForMesh(out_mesh, model, mesh, index);
-
- if (process_weights) {
- ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, index, &reverseMapping);
- }
-
- std::vector<aiAnimMesh*> animMeshes;
- for (const BlendShape* blendShape : mesh.GetBlendShapes()) {
- for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) {
- const std::vector<const ShapeGeometry*>& shapeGeometries = blendShapeChannel->GetShapeGeometries();
- for (size_t i = 0; i < shapeGeometries.size(); i++) {
- aiAnimMesh* animMesh = aiCreateAnimMesh(out_mesh);
- const ShapeGeometry* shapeGeometry = shapeGeometries.at(i);
- const std::vector<aiVector3D>& vertices = shapeGeometry->GetVertices();
- const std::vector<aiVector3D>& normals = shapeGeometry->GetNormals();
- const std::vector<unsigned int>& indices = shapeGeometry->GetIndices();
- animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
- for (size_t j = 0; j < indices.size(); j++) {
- unsigned int index = indices.at(j);
- aiVector3D vertex = vertices.at(j);
- aiVector3D normal = normals.at(j);
- unsigned int count = 0;
- const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count);
- for (unsigned int k = 0; k < count; k++) {
- unsigned int outIndex = outIndices[k];
- if (translateIndexMap.find(outIndex) == translateIndexMap.end())
- continue;
- unsigned int index = translateIndexMap[outIndex];
- animMesh->mVertices[index] += vertex;
- if (animMesh->mNormals != nullptr) {
- animMesh->mNormals[index] += normal;
- animMesh->mNormals[index].NormalizeSafe();
- }
- }
- }
- animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f;
- animMeshes.push_back(animMesh);
- }
- }
- }
-
- const size_t numAnimMeshes = animMeshes.size();
- if (numAnimMeshes > 0) {
- out_mesh->mNumAnimMeshes = static_cast<unsigned int>(numAnimMeshes);
- out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes];
- for (size_t i = 0; i < numAnimMeshes; i++) {
- out_mesh->mAnimMeshes[i] = animMeshes.at(i);
- }
- }
-
- return static_cast<unsigned int>(meshes.size() - 1);
- }
-
- void FBXConverter::ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo,
- const aiMatrix4x4 &absolute_transform,
- aiNode *parent, aiNode *root_node, unsigned int materialIndex,
- std::vector<unsigned int> *outputVertStartIndices)
- {
- ai_assert(geo.DeformerSkin());
-
- std::vector<size_t> out_indices;
- std::vector<size_t> index_out_indices;
- std::vector<size_t> count_out_indices;
-
- const Skin& sk = *geo.DeformerSkin();
-
- std::vector<aiBone*> bones;
-
- const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
- ai_assert(no_mat_check || outputVertStartIndices);
-
- try {
- // iterate over the sub deformers
- for (const Cluster* cluster : sk.Clusters()) {
- ai_assert(cluster);
-
- const WeightIndexArray& indices = cluster->GetIndices();
-
- const MatIndexArray& mats = geo.GetMaterialIndices();
-
- const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
-
- count_out_indices.clear();
- index_out_indices.clear();
- out_indices.clear();
-
-
- // now check if *any* of these weights is contained in the output mesh,
- // taking notes so we don't need to do it twice.
- for (WeightIndexArray::value_type index : indices) {
-
- unsigned int count = 0;
- const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count);
- // ToOutputVertexIndex only returns nullptr if index is out of bounds
- // which should never happen
- ai_assert(out_idx != nullptr);
-
- index_out_indices.push_back(no_index_sentinel);
- count_out_indices.push_back(0);
-
- for (unsigned int i = 0; i < count; ++i) {
- if (no_mat_check || static_cast<size_t>(mats[geo.FaceForVertexIndex(out_idx[i])]) == materialIndex) {
-
- if (index_out_indices.back() == no_index_sentinel) {
- index_out_indices.back() = out_indices.size();
- }
-
- if (no_mat_check) {
- out_indices.push_back(out_idx[i]);
- } else {
- // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn)
- const std::vector<unsigned int>::iterator it = std::lower_bound(
- outputVertStartIndices->begin(),
- outputVertStartIndices->end(),
- out_idx[i]
- );
-
- out_indices.push_back(std::distance(outputVertStartIndices->begin(), it));
- }
-
- ++count_out_indices.back();
- }
- }
- }
-
- // if we found at least one, generate the output bones
- // XXX this could be heavily simplified by collecting the bone
- // data in a single step.
- ConvertCluster(bones, cluster, out_indices, index_out_indices,
- count_out_indices, absolute_transform, parent, root_node);
- }
-
- bone_map.clear();
- }
- catch (std::exception&e) {
- std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>());
- throw;
- }
-
- if (bones.empty()) {
- out->mBones = nullptr;
- out->mNumBones = 0;
- return;
- } else {
- out->mBones = new aiBone *[bones.size()]();
- out->mNumBones = static_cast<unsigned int>(bones.size());
-
- std::swap_ranges(bones.begin(), bones.end(), out->mBones);
- }
- }
-
- const aiNode* FBXConverter::GetNodeByName( const aiString& name, aiNode *current_node )
- {
- aiNode * iter = current_node;
- //printf("Child count: %d", iter->mNumChildren);
- return iter;
- }
-
- void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
- std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
- std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
- aiNode *parent, aiNode *root_node) {
- ai_assert(cl); // make sure cluster valid
- std::string deformer_name = cl->TargetNode()->Name();
- aiString bone_name = aiString(FixNodeName(deformer_name));
-
- aiBone *bone = nullptr;
-
- if (bone_map.count(deformer_name)) {
- std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name
- << std::endl;
- bone = bone_map[deformer_name];
- } else {
- std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl;
- bone = new aiBone();
- bone->mName = bone_name;
-
- // store local transform link for post processing
- bone->mOffsetMatrix = cl->TransformLink();
- bone->mOffsetMatrix.Inverse();
-
- aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
-
- bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
-
-
- //
- // Now calculate the aiVertexWeights
- //
-
- aiVertexWeight *cursor = nullptr;
-
- bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
- cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
-
- const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
- const WeightArray& weights = cl->GetWeights();
-
- const size_t c = index_out_indices.size();
- for (size_t i = 0; i < c; ++i) {
- const size_t index_index = index_out_indices[i];
-
- if (index_index == no_index_sentinel) {
- continue;
- }
-
- const size_t cc = count_out_indices[i];
- for (size_t j = 0; j < cc; ++j) {
- // cursor runs from first element relative to the start
- // or relative to the start of the next indexes.
- aiVertexWeight& out_weight = *cursor++;
-
- out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]);
- out_weight.mWeight = weights[i];
- }
- }
-
- bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone));
- }
-
- std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl;
-
- // lookup must be populated in case something goes wrong
- // this also allocates bones to mesh instance outside
- local_mesh_bones.push_back(bone);
- }
-
- void FBXConverter::ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
- MatIndexArray::value_type materialIndex)
- {
- // locate source materials for this mesh
- const std::vector<const Material*>& mats = model.GetMaterials();
- if (static_cast<unsigned int>(materialIndex) >= mats.size() || materialIndex < 0) {
- FBXImporter::LogError("material index out of bounds, setting default material");
- out->mMaterialIndex = GetDefaultMaterial();
- return;
- }
-
- const Material* const mat = mats[materialIndex];
- MaterialMap::const_iterator it = materials_converted.find(mat);
- if (it != materials_converted.end()) {
- out->mMaterialIndex = (*it).second;
- return;
- }
-
- out->mMaterialIndex = ConvertMaterial(*mat, &geo);
- materials_converted[mat] = out->mMaterialIndex;
- }
-
- unsigned int FBXConverter::GetDefaultMaterial()
- {
- if (defaultMaterialIndex) {
- return defaultMaterialIndex - 1;
- }
-
- aiMaterial* out_mat = new aiMaterial();
- materials.push_back(out_mat);
-
- const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f);
- out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
-
- aiString s;
- s.Set(AI_DEFAULT_MATERIAL_NAME);
-
- out_mat->AddProperty(&s, AI_MATKEY_NAME);
-
- defaultMaterialIndex = static_cast<unsigned int>(materials.size());
- return defaultMaterialIndex - 1;
- }
-
-
- unsigned int FBXConverter::ConvertMaterial(const Material& material, const MeshGeometry* const mesh)
- {
- const PropertyTable& props = material.Props();
-
- // generate empty output material
- aiMaterial* out_mat = new aiMaterial();
- materials_converted[&material] = static_cast<unsigned int>(materials.size());
-
- materials.push_back(out_mat);
-
- aiString str;
-
- // strip Material:: prefix
- std::string name = material.Name();
- if (name.substr(0, 10) == "Material::") {
- name = name.substr(10);
- }
-
- // set material name if not empty - this could happen
- // and there should be no key for it in this case.
- if (name.length()) {
- str.Set(name);
- out_mat->AddProperty(&str, AI_MATKEY_NAME);
- }
-
- // Set the shading mode as best we can: The FBX specification only mentions Lambert and Phong, and only Phong is mentioned in Assimp's aiShadingMode enum.
- if (material.GetShadingModel() == "phong")
- {
- aiShadingMode shadingMode = aiShadingMode_Phong;
- out_mat->AddProperty<aiShadingMode>(&shadingMode, 1, AI_MATKEY_SHADING_MODEL);
- }
-
- // shading stuff and colors
- SetShadingPropertiesCommon(out_mat, props);
- SetShadingPropertiesRaw( out_mat, props, material.Textures(), mesh );
-
- // texture assignments
- SetTextureProperties(out_mat, material.Textures(), mesh);
- SetTextureProperties(out_mat, material.LayeredTextures(), mesh);
-
- return static_cast<unsigned int>(materials.size() - 1);
- }
-
- unsigned int FBXConverter::ConvertVideo(const Video& video)
- {
- // generate empty output texture
- aiTexture* out_tex = new aiTexture();
- textures.push_back(out_tex);
-
- // assuming the texture is compressed
- out_tex->mWidth = static_cast<unsigned int>(video.ContentLength()); // total data size
- out_tex->mHeight = 0; // fixed to 0
-
- // steal the data from the Video to avoid an additional copy
- out_tex->pcData = reinterpret_cast<aiTexel*>(const_cast<Video&>(video).RelinquishContent());
-
- // try to extract a hint from the file extension
- const std::string& filename = video.RelativeFilename().empty() ? video.FileName() : video.RelativeFilename();
- std::string ext = BaseImporter::GetExtension(filename);
-
- if (ext == "jpeg") {
- ext = "jpg";
- }
-
- if (ext.size() <= 3) {
- memcpy(out_tex->achFormatHint, ext.c_str(), ext.size());
- }
-
- out_tex->mFilename.Set(filename.c_str());
-
- return static_cast<unsigned int>(textures.size() - 1);
- }
-
- aiString FBXConverter::GetTexturePath(const Texture* tex)
- {
- aiString path;
- path.Set(tex->RelativeFilename());
-
- const Video* media = tex->Media();
- if (media != nullptr) {
- bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
- unsigned int index;
-
- VideoMap::const_iterator it = textures_converted.find(*media);
- if (it != textures_converted.end()) {
- index = (*it).second;
- textureReady = true;
- }
- else {
- if (media->ContentLength() > 0) {
- index = ConvertVideo(*media);
- textures_converted[*media] = index;
- textureReady = true;
- }
- }
-
- // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
- if (doc.Settings().useLegacyEmbeddedTextureNaming) {
- if (textureReady) {
- // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
- // In FBX files textures are now stored internally by Assimp with their filename included
- // Now Assimp can lookup through the loaded textures after all data is processed
- // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
- // This may occur on this case too, it has to be studied
- path.data[0] = '*';
- path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
- }
- }
- }
-
- return path;
- }
-
- void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
- const std::string& propName,
- aiTextureType target, const MeshGeometry* const mesh) {
- TextureMap::const_iterator it = textures.find(propName);
- if (it == textures.end()) {
- return;
- }
-
- const Texture* const tex = (*it).second;
- if (tex != 0)
- {
- aiString path = GetTexturePath(tex);
- out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, 0);
-
- aiUVTransform uvTrafo;
- // XXX handle all kinds of UV transformations
- uvTrafo.mScaling = tex->UVScaling();
- uvTrafo.mTranslation = tex->UVTranslation();
- out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0);
-
- const PropertyTable& props = tex->Props();
-
- int uvIndex = 0;
-
- bool ok;
- const std::string& uvSet = PropertyGet<std::string>(props, "UVSet", ok);
- if (ok) {
- // "default" is the name which usually appears in the FbxFileTexture template
- if (uvSet != "default" && uvSet.length()) {
- // this is a bit awkward - we need to find a mesh that uses this
- // material and scan its UV channels for the given UV name because
- // assimp references UV channels by index, not by name.
-
- // XXX: the case that UV channels may appear in different orders
- // in meshes is unhandled. A possible solution would be to sort
- // the UV channels alphabetically, but this would have the side
- // effect that the primary (first) UV channel would sometimes
- // be moved, causing trouble when users read only the first
- // UV channel and ignore UV channel assignments altogether.
-
- const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(),
- std::find(materials.begin(), materials.end(), out_mat)
- ));
-
-
- uvIndex = -1;
- if (!mesh)
- {
- for (const MeshMap::value_type& v : meshes_converted) {
- const MeshGeometry* const meshGeom = dynamic_cast<const MeshGeometry*> (v.first);
- if (!meshGeom) {
- continue;
- }
-
- const MatIndexArray& mats = meshGeom->GetMaterialIndices();
- if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) {
- continue;
- }
-
- int index = -1;
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
- if (meshGeom->GetTextureCoords(i).empty()) {
- break;
- }
- const std::string& name = meshGeom->GetTextureCoordChannelName(i);
- if (name == uvSet) {
- index = static_cast<int>(i);
- break;
- }
- }
- if (index == -1) {
- FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
- continue;
- }
-
- if (uvIndex == -1) {
- uvIndex = index;
- }
- else {
- FBXImporter::LogWarn("the UV channel named " + uvSet +
- " appears at different positions in meshes, results will be wrong");
- }
- }
- }
- else
- {
- int index = -1;
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
- if (mesh->GetTextureCoords(i).empty()) {
- break;
- }
- const std::string& name = mesh->GetTextureCoordChannelName(i);
- if (name == uvSet) {
- index = static_cast<int>(i);
- break;
- }
- }
- if (index == -1) {
- FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
- }
-
- if (uvIndex == -1) {
- uvIndex = index;
- }
- }
-
- if (uvIndex == -1) {
- FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel");
- uvIndex = 0;
- }
- }
- }
-
- out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0);
- }
- }
-
- void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
- const std::string& propName,
- aiTextureType target, const MeshGeometry* const mesh) {
- LayeredTextureMap::const_iterator it = layeredTextures.find(propName);
- if (it == layeredTextures.end()) {
- return;
- }
-
- int texCount = (*it).second->textureCount();
-
- // Set the blend mode for layered textures
- int blendmode = (*it).second->GetBlendMode();
- out_mat->AddProperty(&blendmode, 1, _AI_MATKEY_TEXOP_BASE, target, 0);
-
- for (int texIndex = 0; texIndex < texCount; texIndex++) {
-
- const Texture* const tex = (*it).second->getTexture(texIndex);
-
- aiString path = GetTexturePath(tex);
- out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, texIndex);
-
- aiUVTransform uvTrafo;
- // XXX handle all kinds of UV transformations
- uvTrafo.mScaling = tex->UVScaling();
- uvTrafo.mTranslation = tex->UVTranslation();
- out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex);
-
- const PropertyTable& props = tex->Props();
-
- int uvIndex = 0;
-
- bool ok;
- const std::string& uvSet = PropertyGet<std::string>(props, "UVSet", ok);
- if (ok) {
- // "default" is the name which usually appears in the FbxFileTexture template
- if (uvSet != "default" && uvSet.length()) {
- // this is a bit awkward - we need to find a mesh that uses this
- // material and scan its UV channels for the given UV name because
- // assimp references UV channels by index, not by name.
-
- // XXX: the case that UV channels may appear in different orders
- // in meshes is unhandled. A possible solution would be to sort
- // the UV channels alphabetically, but this would have the side
- // effect that the primary (first) UV channel would sometimes
- // be moved, causing trouble when users read only the first
- // UV channel and ignore UV channel assignments altogether.
-
- const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(),
- std::find(materials.begin(), materials.end(), out_mat)
- ));
-
- uvIndex = -1;
- if (!mesh)
- {
- for (const MeshMap::value_type& v : meshes_converted) {
- const MeshGeometry* const meshGeom = dynamic_cast<const MeshGeometry*> (v.first);
- if (!meshGeom) {
- continue;
- }
-
- const MatIndexArray& mats = meshGeom->GetMaterialIndices();
- if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) {
- continue;
- }
-
- int index = -1;
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
- if (meshGeom->GetTextureCoords(i).empty()) {
- break;
- }
- const std::string& name = meshGeom->GetTextureCoordChannelName(i);
- if (name == uvSet) {
- index = static_cast<int>(i);
- break;
- }
- }
- if (index == -1) {
- FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
- continue;
- }
-
- if (uvIndex == -1) {
- uvIndex = index;
- }
- else {
- FBXImporter::LogWarn("the UV channel named " + uvSet +
- " appears at different positions in meshes, results will be wrong");
- }
- }
- }
- else
- {
- int index = -1;
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
- if (mesh->GetTextureCoords(i).empty()) {
- break;
- }
- const std::string& name = mesh->GetTextureCoordChannelName(i);
- if (name == uvSet) {
- index = static_cast<int>(i);
- break;
- }
- }
- if (index == -1) {
- FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
- }
-
- if (uvIndex == -1) {
- uvIndex = index;
- }
- }
-
- if (uvIndex == -1) {
- FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel");
- uvIndex = 0;
- }
- }
- }
-
- out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, texIndex);
- }
- }
-
- void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh)
- {
- TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
- TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh);
- TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
- TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh);
- TrySetTextureProperties(out_mat, textures, "SpecularFactor", aiTextureType_SPECULAR, mesh);
- TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh);
- TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
- TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
- TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh);
- TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh);
- TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh);
- TrySetTextureProperties( out_mat, textures, "TransparencyFactor", aiTextureType_OPACITY, mesh );
- TrySetTextureProperties( out_mat, textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh );
- //Maya counterparts
- TrySetTextureProperties(out_mat, textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh);
-
- // Maya PBR
- TrySetTextureProperties(out_mat, textures, "Maya|baseColor|file", aiTextureType_BASE_COLOR, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|normalCamera|file", aiTextureType_NORMAL_CAMERA, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|emissionColor|file", aiTextureType_EMISSION_COLOR, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|metalness|file", aiTextureType_METALNESS, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|diffuseRoughness|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
-
- // Maya stingray
- TrySetTextureProperties(out_mat, textures, "Maya|TEX_color_map|file", aiTextureType_BASE_COLOR, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|TEX_normal_map|file", aiTextureType_NORMAL_CAMERA, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
- TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh);
- }
-
- void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh)
- {
- TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh);
- TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh);
- TrySetTextureProperties( out_mat, layeredTextures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh );
- TrySetTextureProperties( out_mat, layeredTextures, "TransparencyFactor", aiTextureType_OPACITY, mesh );
- }
-
- aiColor3D FBXConverter::GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName,
- const std::string& factorName, bool& result, bool useTemplate)
- {
- result = true;
-
- bool ok;
- aiVector3D BaseColor = PropertyGet<aiVector3D>(props, colorName, ok, useTemplate);
- if (!ok) {
- result = false;
- return aiColor3D(0.0f, 0.0f, 0.0f);
- }
-
- // if no factor name, return the colour as is
- if (factorName.empty()) {
- return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z);
- }
-
- // otherwise it should be multiplied by the factor, if found.
- float factor = PropertyGet<float>(props, factorName, ok, useTemplate);
- if (ok) {
- BaseColor *= factor;
- }
- return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z);
- }
-
- aiColor3D FBXConverter::GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName,
- bool& result)
- {
- return GetColorPropertyFactored(props, baseName + "Color", baseName + "Factor", result, true);
- }
-
- aiColor3D FBXConverter::GetColorProperty(const PropertyTable& props, const std::string& colorName,
- bool& result, bool useTemplate)
- {
- result = true;
- bool ok;
- const aiVector3D& ColorVec = PropertyGet<aiVector3D>(props, colorName, ok, useTemplate);
- if (!ok) {
- result = false;
- return aiColor3D(0.0f, 0.0f, 0.0f);
- }
- return aiColor3D(ColorVec.x, ColorVec.y, ColorVec.z);
- }
-
- void FBXConverter::SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props)
- {
- // Set shading properties.
- // Modern FBX Files have two separate systems for defining these,
- // with only the more comprehensive one described in the property template.
- // Likely the other values are a legacy system,
- // which is still always exported by the official FBX SDK.
- //
- // Blender's FBX import and export mostly ignore this legacy system,
- // and as we only support recent versions of FBX anyway, we can do the same.
- bool ok;
-
- const aiColor3D& Diffuse = GetColorPropertyFromMaterial(props, "Diffuse", ok);
- if (ok) {
- out_mat->AddProperty(&Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
- }
-
- const aiColor3D& Emissive = GetColorPropertyFromMaterial(props, "Emissive", ok);
- if (ok) {
- out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE);
- }
-
- const aiColor3D& Ambient = GetColorPropertyFromMaterial(props, "Ambient", ok);
- if (ok) {
- out_mat->AddProperty(&Ambient, 1, AI_MATKEY_COLOR_AMBIENT);
- }
-
- // we store specular factor as SHININESS_STRENGTH, so just get the color
- const aiColor3D& Specular = GetColorProperty(props, "SpecularColor", ok, true);
- if (ok) {
- out_mat->AddProperty(&Specular, 1, AI_MATKEY_COLOR_SPECULAR);
- }
-
- // and also try to get SHININESS_STRENGTH
- const float SpecularFactor = PropertyGet<float>(props, "SpecularFactor", ok, true);
- if (ok) {
- out_mat->AddProperty(&SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH);
- }
-
- // and the specular exponent
- const float ShininessExponent = PropertyGet<float>(props, "ShininessExponent", ok);
- if (ok) {
- out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS);
- }
-
- // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
- const aiColor3D& Transparent = GetColorPropertyFactored(props, "TransparentColor", "TransparencyFactor", ok);
- float CalculatedOpacity = 1.0f;
- if (ok) {
- out_mat->AddProperty(&Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
- // as calculated by FBX SDK 2017:
- CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f);
- }
-
- // try to get the transparency factor
- const float TransparencyFactor = PropertyGet<float>(props, "TransparencyFactor", ok);
- if (ok) {
- out_mat->AddProperty(&TransparencyFactor, 1, AI_MATKEY_TRANSPARENCYFACTOR);
- }
-
- // use of TransparencyFactor is inconsistent.
- // Maya always stores it as 1.0,
- // so we can't use it to set AI_MATKEY_OPACITY.
- // Blender is more sensible and stores it as the alpha value.
- // However both the FBX SDK and Blender always write an additional
- // legacy "Opacity" field, so we can try to use that.
- //
- // If we can't find it,
- // we can fall back to the value which the FBX SDK calculates
- // from transparency colour (RGB) and factor (F) as
- // 1.0 - F*((R+G+B)/3).
- //
- // There's no consistent way to interpret this opacity value,
- // so it's up to clients to do the correct thing.
- const float Opacity = PropertyGet<float>(props, "Opacity", ok);
- if (ok) {
- out_mat->AddProperty(&Opacity, 1, AI_MATKEY_OPACITY);
- }
- else if (CalculatedOpacity != 1.0) {
- out_mat->AddProperty(&CalculatedOpacity, 1, AI_MATKEY_OPACITY);
- }
-
- // reflection color and factor are stored separately
- const aiColor3D& Reflection = GetColorProperty(props, "ReflectionColor", ok, true);
- if (ok) {
- out_mat->AddProperty(&Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE);
- }
-
- float ReflectionFactor = PropertyGet<float>(props, "ReflectionFactor", ok, true);
- if (ok) {
- out_mat->AddProperty(&ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY);
- }
-
- const float BumpFactor = PropertyGet<float>(props, "BumpFactor", ok);
- if (ok) {
- out_mat->AddProperty(&BumpFactor, 1, AI_MATKEY_BUMPSCALING);
- }
-
- const float DispFactor = PropertyGet<float>(props, "DisplacementFactor", ok);
- if (ok) {
- out_mat->AddProperty(&DispFactor, 1, "$mat.displacementscaling", 0, 0);
- }
-}
-
-
-void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh)
-{
- // Add all the unparsed properties with a "$raw." prefix
-
- const std::string prefix = "$raw.";
-
- for (const DirectPropertyMap::value_type& prop : props.GetUnparsedProperties()) {
-
- std::string name = prefix + prop.first;
-
- if (const TypedProperty<aiVector3D>* interpreted = prop.second->As<TypedProperty<aiVector3D> >())
- {
- out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0);
- }
- else if (const TypedProperty<aiColor3D>* interpreted = prop.second->As<TypedProperty<aiColor3D> >())
- {
- out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0);
- }
- else if (const TypedProperty<aiColor4D>* interpreted = prop.second->As<TypedProperty<aiColor4D> >())
- {
- out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0);
- }
- else if (const TypedProperty<float>* interpreted = prop.second->As<TypedProperty<float> >())
- {
- out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0);
- }
- else if (const TypedProperty<int>* interpreted = prop.second->As<TypedProperty<int> >())
- {
- out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0);
- }
- else if (const TypedProperty<bool>* interpreted = prop.second->As<TypedProperty<bool> >())
- {
- int value = interpreted->Value() ? 1 : 0;
- out_mat->AddProperty(&value, 1, name.c_str(), 0, 0);
- }
- else if (const TypedProperty<std::string>* interpreted = prop.second->As<TypedProperty<std::string> >())
- {
- const aiString value = aiString(interpreted->Value());
- out_mat->AddProperty(&value, name.c_str(), 0, 0);
- }
- }
-
- // Add the textures' properties
-
- for (TextureMap::const_iterator it = textures.begin(); it != textures.end(); it++) {
-
- std::string name = prefix + it->first;
-
- const Texture* const tex = (*it).second;
- if (tex != nullptr)
- {
- aiString path;
- path.Set(tex->RelativeFilename());
-
- const Video* media = tex->Media();
- if (media != nullptr && media->ContentLength() > 0) {
- unsigned int index;
-
- VideoMap::const_iterator it = textures_converted.find(*media);
- if (it != textures_converted.end()) {
- index = (*it).second;
- }
- else {
- index = ConvertVideo(*media);
- textures_converted[*media] = index;
- }
-
- // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
- path.data[0] = '*';
- path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
- }
-
- out_mat->AddProperty(&path, (name + "|file").c_str(), aiTextureType_UNKNOWN, 0);
-
- aiUVTransform uvTrafo;
- // XXX handle all kinds of UV transformations
- uvTrafo.mScaling = tex->UVScaling();
- uvTrafo.mTranslation = tex->UVTranslation();
- out_mat->AddProperty(&uvTrafo, 1, (name + "|uvtrafo").c_str(), aiTextureType_UNKNOWN, 0);
-
- int uvIndex = 0;
-
- bool uvFound = false;
- const std::string& uvSet = PropertyGet<std::string>(tex->Props(), "UVSet", uvFound);
- if (uvFound) {
- // "default" is the name which usually appears in the FbxFileTexture template
- if (uvSet != "default" && uvSet.length()) {
- // this is a bit awkward - we need to find a mesh that uses this
- // material and scan its UV channels for the given UV name because
- // assimp references UV channels by index, not by name.
-
- // XXX: the case that UV channels may appear in different orders
- // in meshes is unhandled. A possible solution would be to sort
- // the UV channels alphabetically, but this would have the side
- // effect that the primary (first) UV channel would sometimes
- // be moved, causing trouble when users read only the first
- // UV channel and ignore UV channel assignments altogether.
-
- std::vector<aiMaterial*>::iterator materialIt = std::find(materials.begin(), materials.end(), out_mat);
- const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), materialIt));
-
- uvIndex = -1;
- if (!mesh)
- {
- for (const MeshMap::value_type& v : meshes_converted) {
- const MeshGeometry* const meshGeom = dynamic_cast<const MeshGeometry*>(v.first);
- if (!meshGeom) {
- continue;
- }
-
- const MatIndexArray& mats = meshGeom->GetMaterialIndices();
- if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) {
- continue;
- }
-
- int index = -1;
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
- if (meshGeom->GetTextureCoords(i).empty()) {
- break;
- }
- const std::string& name = meshGeom->GetTextureCoordChannelName(i);
- if (name == uvSet) {
- index = static_cast<int>(i);
- break;
- }
- }
- if (index == -1) {
- FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
- continue;
- }
-
- if (uvIndex == -1) {
- uvIndex = index;
- }
- else {
- FBXImporter::LogWarn("the UV channel named " + uvSet + " appears at different positions in meshes, results will be wrong");
- }
- }
- }
- else
- {
- int index = -1;
- for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
- if (mesh->GetTextureCoords(i).empty()) {
- break;
- }
- const std::string& name = mesh->GetTextureCoordChannelName(i);
- if (name == uvSet) {
- index = static_cast<int>(i);
- break;
- }
- }
- if (index == -1) {
- FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
- }
-
- if (uvIndex == -1) {
- uvIndex = index;
- }
- }
-
- if (uvIndex == -1) {
- FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel");
- uvIndex = 0;
- }
- }
- }
-
- out_mat->AddProperty(&uvIndex, 1, (name + "|uvwsrc").c_str(), aiTextureType_UNKNOWN, 0);
- }
- }
- }
-
-
- double FBXConverter::FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal) {
- switch (fp) {
- case FileGlobalSettings::FrameRate_DEFAULT:
- return 1.0;
-
- case FileGlobalSettings::FrameRate_120:
- return 120.0;
-
- case FileGlobalSettings::FrameRate_100:
- return 100.0;
-
- case FileGlobalSettings::FrameRate_60:
- return 60.0;
-
- case FileGlobalSettings::FrameRate_50:
- return 50.0;
-
- case FileGlobalSettings::FrameRate_48:
- return 48.0;
-
- case FileGlobalSettings::FrameRate_30:
- case FileGlobalSettings::FrameRate_30_DROP:
- return 30.0;
-
- case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME:
- case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME:
- return 29.9700262;
-
- case FileGlobalSettings::FrameRate_PAL:
- return 25.0;
-
- case FileGlobalSettings::FrameRate_CINEMA:
- return 24.0;
-
- case FileGlobalSettings::FrameRate_1000:
- return 1000.0;
-
- case FileGlobalSettings::FrameRate_CINEMA_ND:
- return 23.976;
-
- case FileGlobalSettings::FrameRate_CUSTOM:
- return customFPSVal;
-
- case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings
- break;
- }
-
- ai_assert(false);
-
- return -1.0f;
- }
-
-
- void FBXConverter::ConvertAnimations()
- {
- // first of all determine framerate
- const FileGlobalSettings::FrameRate fps = doc.GlobalSettings().TimeMode();
- const float custom = doc.GlobalSettings().CustomFrameRate();
- anim_fps = FrameRateToDouble(fps, custom);
-
- const std::vector<const AnimationStack*>& animations = doc.AnimationStacks();
- for (const AnimationStack* stack : animations) {
- ConvertAnimationStack(*stack);
- }
- }
-
- std::string FBXConverter::FixNodeName(const std::string& name) {
- // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
- // this causes ambiguities, well possible between empty identifiers,
- // such as "Model::" and ""). Make sure the behaviour is consistent
- // across multiple calls to FixNodeName().
- if (name.substr(0, 7) == "Model::") {
- std::string temp = name.substr(7);
- return temp;
- }
-
- return name;
- }
-
- std::string FBXConverter::FixAnimMeshName(const std::string& name) {
- if (name.length()) {
- size_t indexOf = name.find_first_of("::");
- if (indexOf != std::string::npos && indexOf < name.size() - 2) {
- return name.substr(indexOf + 2);
- }
- }
- return name.length() ? name : "AnimMesh";
- }
-
- void FBXConverter::ConvertAnimationStack(const AnimationStack& st)
- {
- const AnimationLayerList& layers = st.Layers();
- if (layers.empty()) {
- return;
- }
-
- aiAnimation* const anim = new aiAnimation();
- animations.push_back(anim);
-
- // strip AnimationStack:: prefix
- std::string name = st.Name();
- if (name.substr(0, 16) == "AnimationStack::") {
- name = name.substr(16);
- }
- else if (name.substr(0, 11) == "AnimStack::") {
- name = name.substr(11);
- }
-
- anim->mName.Set(name);
-
- // need to find all nodes for which we need to generate node animations -
- // it may happen that we need to merge multiple layers, though.
- NodeMap node_map;
-
- // reverse mapping from curves to layers, much faster than querying
- // the FBX DOM for it.
- LayerMap layer_map;
-
- const char* prop_whitelist[] = {
- "Lcl Scaling",
- "Lcl Rotation",
- "Lcl Translation",
- "DeformPercent"
- };
-
- std::map<std::string, morphAnimData*> morphAnimDatas;
-
- for (const AnimationLayer* layer : layers) {
- ai_assert(layer);
- const AnimationCurveNodeList& nodes = layer->Nodes(prop_whitelist, 4);
- for (const AnimationCurveNode* node : nodes) {
- ai_assert(node);
- const Model* const model = dynamic_cast<const Model*>(node->Target());
- if (model) {
- const std::string& name = FixNodeName(model->Name());
- node_map[name].push_back(node);
- layer_map[node] = layer;
- continue;
- }
- const BlendShapeChannel* const bsc = dynamic_cast<const BlendShapeChannel*>(node->Target());
- if (bsc) {
- ProcessMorphAnimDatas(&morphAnimDatas, bsc, node);
- }
- }
- }
-
- // generate node animations
- std::vector<aiNodeAnim*> node_anims;
-
- double min_time = 1e10;
- double max_time = -1e10;
-
- int64_t start_time = st.LocalStart();
- int64_t stop_time = st.LocalStop();
- bool has_local_startstop = start_time != 0 || stop_time != 0;
- if (!has_local_startstop) {
- // no time range given, so accept every keyframe and use the actual min/max time
- // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000
- start_time = -9223372036854775807ll + 20000;
- stop_time = 9223372036854775807ll - 20000;
- }
-
- try {
- for (const NodeMap::value_type& kv : node_map) {
- GenerateNodeAnimations(node_anims,
- kv.first,
- kv.second,
- layer_map,
- start_time, stop_time,
- max_time,
- min_time);
- }
- }
- catch (std::exception&) {
- std::for_each(node_anims.begin(), node_anims.end(), Util::delete_fun<aiNodeAnim>());
- throw;
- }
-
- if (node_anims.size() || morphAnimDatas.size()) {
- if (node_anims.size()) {
- anim->mChannels = new aiNodeAnim*[node_anims.size()]();
- anim->mNumChannels = static_cast<unsigned int>(node_anims.size());
- std::swap_ranges(node_anims.begin(), node_anims.end(), anim->mChannels);
- }
- if (morphAnimDatas.size()) {
- unsigned int numMorphMeshChannels = static_cast<unsigned int>(morphAnimDatas.size());
- anim->mMorphMeshChannels = new aiMeshMorphAnim*[numMorphMeshChannels];
- anim->mNumMorphMeshChannels = numMorphMeshChannels;
- unsigned int i = 0;
- for (auto morphAnimIt : morphAnimDatas) {
- morphAnimData* animData = morphAnimIt.second;
- unsigned int numKeys = static_cast<unsigned int>(animData->size());
- aiMeshMorphAnim* meshMorphAnim = new aiMeshMorphAnim();
- meshMorphAnim->mName.Set(morphAnimIt.first);
- meshMorphAnim->mNumKeys = numKeys;
- meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
- unsigned int j = 0;
- for (auto animIt : *animData) {
- morphKeyData* keyData = animIt.second;
- unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
- meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
- meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights];
- meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights];
- meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first) * anim_fps;
- for (unsigned int k = 0; k < numValuesAndWeights; k++) {
- meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k);
- meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k);
- }
- j++;
- }
- anim->mMorphMeshChannels[i++] = meshMorphAnim;
- }
- }
- }
- else {
- // empty animations would fail validation, so drop them
- delete anim;
- animations.pop_back();
- FBXImporter::LogInfo("ignoring empty AnimationStack (using IK?): " + name);
- return;
- }
-
- double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time;
- double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time;
-
- // adjust relative timing for animation
- for (unsigned int c = 0; c < anim->mNumChannels; c++) {
- aiNodeAnim* channel = anim->mChannels[c];
- for (uint32_t i = 0; i < channel->mNumPositionKeys; i++) {
- channel->mPositionKeys[i].mTime -= start_time_fps;
- }
- for (uint32_t i = 0; i < channel->mNumRotationKeys; i++) {
- channel->mRotationKeys[i].mTime -= start_time_fps;
- }
- for (uint32_t i = 0; i < channel->mNumScalingKeys; i++) {
- channel->mScalingKeys[i].mTime -= start_time_fps;
- }
- }
- for (unsigned int c = 0; c < anim->mNumMorphMeshChannels; c++) {
- aiMeshMorphAnim* channel = anim->mMorphMeshChannels[c];
- for (uint32_t i = 0; i < channel->mNumKeys; i++) {
- channel->mKeys[i].mTime -= start_time_fps;
- }
- }
-
- // for some mysterious reason, mDuration is simply the maximum key -- the
- // validator always assumes animations to start at zero.
- anim->mDuration = stop_time_fps - start_time_fps;
- anim->mTicksPerSecond = anim_fps;
- }
-
- // ------------------------------------------------------------------------------------------------
- void FBXConverter::ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node) {
- std::vector<const Connection*> bscConnections = doc.GetConnectionsBySourceSequenced(bsc->ID(), "Deformer");
- for (const Connection* bscConnection : bscConnections) {
- auto bs = dynamic_cast<const BlendShape*>(bscConnection->DestinationObject());
- if (bs) {
- auto channelIt = std::find(bs->BlendShapeChannels().begin(), bs->BlendShapeChannels().end(), bsc);
- if (channelIt != bs->BlendShapeChannels().end()) {
- auto channelIndex = static_cast<unsigned int>(std::distance(bs->BlendShapeChannels().begin(), channelIt));
- std::vector<const Connection*> bsConnections = doc.GetConnectionsBySourceSequenced(bs->ID(), "Geometry");
- for (const Connection* bsConnection : bsConnections) {
- auto geo = dynamic_cast<const Geometry*>(bsConnection->DestinationObject());
- if (geo) {
- std::vector<const Connection*> geoConnections = doc.GetConnectionsBySourceSequenced(geo->ID(), "Model");
- for (const Connection* geoConnection : geoConnections) {
- auto model = dynamic_cast<const Model*>(geoConnection->DestinationObject());
- if (model) {
- auto geoIt = std::find(model->GetGeometry().begin(), model->GetGeometry().end(), geo);
- auto geoIndex = static_cast<unsigned int>(std::distance(model->GetGeometry().begin(), geoIt));
- auto name = aiString(FixNodeName(model->Name() + "*"));
- name.length = 1 + ASSIMP_itoa10(name.data + name.length, MAXLEN - 1, geoIndex);
- morphAnimData* animData;
- auto animIt = morphAnimDatas->find(name.C_Str());
- if (animIt == morphAnimDatas->end()) {
- animData = new morphAnimData();
- morphAnimDatas->insert(std::make_pair(name.C_Str(), animData));
- }
- else {
- animData = animIt->second;
- }
- for (std::pair<std::string, const AnimationCurve*> curvesIt : node->Curves()) {
- if (curvesIt.first == "d|DeformPercent") {
- const AnimationCurve* animationCurve = curvesIt.second;
- const KeyTimeList& keys = animationCurve->GetKeys();
- const KeyValueList& values = animationCurve->GetValues();
- unsigned int k = 0;
- for (auto key : keys) {
- morphKeyData* keyData;
- auto keyIt = animData->find(key);
- if (keyIt == animData->end()) {
- keyData = new morphKeyData();
- animData->insert(std::make_pair(key, keyData));
- }
- else {
- keyData = keyIt->second;
- }
- keyData->values.push_back(channelIndex);
- keyData->weights.push_back(values.at(k) / 100.0f);
- k++;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- // ------------------------------------------------------------------------------------------------
-#ifdef ASSIMP_BUILD_DEBUG
- // ------------------------------------------------------------------------------------------------
- // sanity check whether the input is ok
- static void validateAnimCurveNodes(const std::vector<const AnimationCurveNode*>& curves,
- bool strictMode) {
- const Object* target(nullptr);
- for (const AnimationCurveNode* node : curves) {
- if (!target) {
- target = node->Target();
- }
- if (node->Target() != target) {
- FBXImporter::LogWarn("Node target is nullptr type.");
- }
- if (strictMode) {
- ai_assert(node->Target() == target);
- }
- }
- }
-#endif // ASSIMP_BUILD_DEBUG
-
- // ------------------------------------------------------------------------------------------------
- void FBXConverter::GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
- const std::string& fixed_name,
- const std::vector<const AnimationCurveNode*>& curves,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time)
- {
-
- NodeMap node_property_map;
- ai_assert(curves.size());
-
-#ifdef ASSIMP_BUILD_DEBUG
- validateAnimCurveNodes(curves, doc.Settings().strictMode);
-#endif
- const AnimationCurveNode* curve_node = nullptr;
- for (const AnimationCurveNode* node : curves) {
- ai_assert(node);
-
- if (node->TargetProperty().empty()) {
- FBXImporter::LogWarn("target property for animation curve not set: " + node->Name());
- continue;
- }
-
- curve_node = node;
- if (node->Curves().empty()) {
- FBXImporter::LogWarn("no animation curves assigned to AnimationCurveNode: " + node->Name());
- continue;
- }
-
- node_property_map[node->TargetProperty()].push_back(node);
- }
-
- ai_assert(curve_node);
- ai_assert(curve_node->TargetAsModel());
-
- const Model& target = *curve_node->TargetAsModel();
-
- // check for all possible transformation components
- NodeMap::const_iterator chain[TransformationComp_MAXIMUM];
-
- bool has_any = false;
- bool has_complex = false;
-
- for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
- const TransformationComp comp = static_cast<TransformationComp>(i);
-
- // inverse pivots don't exist in the input, we just generate them
- if (comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse) {
- chain[i] = node_property_map.end();
- continue;
- }
-
- chain[i] = node_property_map.find(NameTransformationCompProperty(comp));
- if (chain[i] != node_property_map.end()) {
-
- // check if this curves contains redundant information by looking
- // up the corresponding node's transformation chain.
- if (doc.Settings().optimizeEmptyAnimationCurves &&
- IsRedundantAnimationData(target, comp, (*chain[i]).second)) {
-
- FBXImporter::LogDebug("dropping redundant animation channel for node " + target.Name());
- continue;
- }
-
- has_any = true;
-
- if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation)
- {
- has_complex = true;
- }
- }
- }
-
- if (!has_any) {
- FBXImporter::LogWarn("ignoring node animation, did not find any transformation key frames");
- return;
- }
-
- // this needs to play nicely with GenerateTransformationNodeChain() which will
- // be invoked _later_ (animations come first). If this node has only rotation,
- // scaling and translation _and_ there are no animated other components either,
- // we can use a single node and also a single node animation channel.
- if (!has_complex && !NeedsComplexTransformationChain(target)) {
-
- aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain,
- node_property_map.end(),
- layer_map,
- start, stop,
- max_time,
- min_time,
- true // input is TRS order, assimp is SRT
- );
-
- ai_assert(nd);
- if (nd->mNumPositionKeys == 0 && nd->mNumRotationKeys == 0 && nd->mNumScalingKeys == 0) {
- delete nd;
- }
- else {
- node_anims.push_back(nd);
- }
- return;
- }
-
- // otherwise, things get gruesome and we need separate animation channels
- // for each part of the transformation chain. Remember which channels
- // we generated and pass this information to the node conversion
- // code to avoid nodes that have identity transform, but non-identity
- // animations, being dropped.
- unsigned int flags = 0, bit = 0x1;
- for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) {
- const TransformationComp comp = static_cast<TransformationComp>(i);
-
- if (chain[i] != node_property_map.end()) {
- flags |= bit;
-
- ai_assert(comp != TransformationComp_RotationPivotInverse);
- ai_assert(comp != TransformationComp_ScalingPivotInverse);
-
- const std::string& chain_name = NameTransformationChainNode(fixed_name, comp);
-
- aiNodeAnim* na = nullptr;
- switch (comp)
- {
- case TransformationComp_Rotation:
- case TransformationComp_PreRotation:
- case TransformationComp_PostRotation:
- case TransformationComp_GeometricRotation:
- na = GenerateRotationNodeAnim(chain_name,
- target,
- (*chain[i]).second,
- layer_map,
- start, stop,
- max_time,
- min_time);
-
- break;
-
- case TransformationComp_RotationOffset:
- case TransformationComp_RotationPivot:
- case TransformationComp_ScalingOffset:
- case TransformationComp_ScalingPivot:
- case TransformationComp_Translation:
- case TransformationComp_GeometricTranslation:
- na = GenerateTranslationNodeAnim(chain_name,
- target,
- (*chain[i]).second,
- layer_map,
- start, stop,
- max_time,
- min_time);
-
- // pivoting requires us to generate an implicit inverse channel to undo the pivot translation
- if (comp == TransformationComp_RotationPivot) {
- const std::string& invName = NameTransformationChainNode(fixed_name,
- TransformationComp_RotationPivotInverse);
-
- aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName,
- target,
- (*chain[i]).second,
- layer_map,
- start, stop,
- max_time,
- min_time,
- true);
-
- ai_assert(inv);
- if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) {
- delete inv;
- }
- else {
- node_anims.push_back(inv);
- }
-
- ai_assert(TransformationComp_RotationPivotInverse > i);
- flags |= bit << (TransformationComp_RotationPivotInverse - i);
- }
- else if (comp == TransformationComp_ScalingPivot) {
- const std::string& invName = NameTransformationChainNode(fixed_name,
- TransformationComp_ScalingPivotInverse);
-
- aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName,
- target,
- (*chain[i]).second,
- layer_map,
- start, stop,
- max_time,
- min_time,
- true);
-
- ai_assert(inv);
- if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) {
- delete inv;
- }
- else {
- node_anims.push_back(inv);
- }
-
- ai_assert(TransformationComp_RotationPivotInverse > i);
- flags |= bit << (TransformationComp_RotationPivotInverse - i);
- }
-
- break;
-
- case TransformationComp_Scaling:
- case TransformationComp_GeometricScaling:
- na = GenerateScalingNodeAnim(chain_name,
- target,
- (*chain[i]).second,
- layer_map,
- start, stop,
- max_time,
- min_time);
-
- break;
-
- default:
- ai_assert(false);
- }
-
- ai_assert(na);
- if (na->mNumPositionKeys == 0 && na->mNumRotationKeys == 0 && na->mNumScalingKeys == 0) {
- delete na;
- }
- else {
- node_anims.push_back(na);
- }
- continue;
- }
- }
-
- node_anim_chain_bits[fixed_name] = flags;
- }
-
-
- bool FBXConverter::IsRedundantAnimationData(const Model& target,
- TransformationComp comp,
- const std::vector<const AnimationCurveNode*>& curves) {
- ai_assert(curves.size());
-
- // look for animation nodes with
- // * sub channels for all relevant components set
- // * one key/value pair per component
- // * combined values match up the corresponding value in the bind pose node transformation
- // only such nodes are 'redundant' for this function.
-
- if (curves.size() > 1) {
- return false;
- }
-
- const AnimationCurveNode& nd = *curves.front();
- const AnimationCurveMap& sub_curves = nd.Curves();
-
- const AnimationCurveMap::const_iterator dx = sub_curves.find("d|X");
- const AnimationCurveMap::const_iterator dy = sub_curves.find("d|Y");
- const AnimationCurveMap::const_iterator dz = sub_curves.find("d|Z");
-
- if (dx == sub_curves.end() || dy == sub_curves.end() || dz == sub_curves.end()) {
- return false;
- }
-
- const KeyValueList& vx = (*dx).second->GetValues();
- const KeyValueList& vy = (*dy).second->GetValues();
- const KeyValueList& vz = (*dz).second->GetValues();
-
- if (vx.size() != 1 || vy.size() != 1 || vz.size() != 1) {
- return false;
- }
-
- const aiVector3D dyn_val = aiVector3D(vx[0], vy[0], vz[0]);
- const aiVector3D& static_val = PropertyGet<aiVector3D>(target.Props(),
- NameTransformationCompProperty(comp),
- TransformationCompDefaultValue(comp)
- );
-
- const float epsilon = Math::getEpsilon<float>();
- return (dyn_val - static_val).SquareLength() < epsilon;
- }
-
-
- aiNodeAnim* FBXConverter::GenerateRotationNodeAnim(const std::string& name,
- const Model& target,
- const std::vector<const AnimationCurveNode*>& curves,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time)
- {
- std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
- na->mNodeName.Set(name);
-
- ConvertRotationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time, target.RotationOrder());
-
- // dummy scaling key
- na->mScalingKeys = new aiVectorKey[1];
- na->mNumScalingKeys = 1;
-
- na->mScalingKeys[0].mTime = 0.;
- na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f);
-
- // dummy position key
- na->mPositionKeys = new aiVectorKey[1];
- na->mNumPositionKeys = 1;
-
- na->mPositionKeys[0].mTime = 0.;
- na->mPositionKeys[0].mValue = aiVector3D();
-
- return na.release();
- }
-
- aiNodeAnim* FBXConverter::GenerateScalingNodeAnim(const std::string& name,
- const Model& /*target*/,
- const std::vector<const AnimationCurveNode*>& curves,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time)
- {
- std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
- na->mNodeName.Set(name);
-
- ConvertScaleKeys(na.get(), curves, layer_map, start, stop, max_time, min_time);
-
- // dummy rotation key
- na->mRotationKeys = new aiQuatKey[1];
- na->mNumRotationKeys = 1;
-
- na->mRotationKeys[0].mTime = 0.;
- na->mRotationKeys[0].mValue = aiQuaternion();
-
- // dummy position key
- na->mPositionKeys = new aiVectorKey[1];
- na->mNumPositionKeys = 1;
-
- na->mPositionKeys[0].mTime = 0.;
- na->mPositionKeys[0].mValue = aiVector3D();
-
- return na.release();
- }
-
- aiNodeAnim* FBXConverter::GenerateTranslationNodeAnim(const std::string& name,
- const Model& /*target*/,
- const std::vector<const AnimationCurveNode*>& curves,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time,
- bool inverse) {
- std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
- na->mNodeName.Set(name);
-
- ConvertTranslationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time);
-
- if (inverse) {
- for (unsigned int i = 0; i < na->mNumPositionKeys; ++i) {
- na->mPositionKeys[i].mValue *= -1.0f;
- }
- }
-
- // dummy scaling key
- na->mScalingKeys = new aiVectorKey[1];
- na->mNumScalingKeys = 1;
-
- na->mScalingKeys[0].mTime = 0.;
- na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f);
-
- // dummy rotation key
- na->mRotationKeys = new aiQuatKey[1];
- na->mNumRotationKeys = 1;
-
- na->mRotationKeys[0].mTime = 0.;
- na->mRotationKeys[0].mValue = aiQuaternion();
-
- return na.release();
- }
-
- aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
- const Model& target,
- NodeMap::const_iterator chain[TransformationComp_MAXIMUM],
- NodeMap::const_iterator iter_end,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time,
- bool reverse_order)
-
- {
- std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
- na->mNodeName.Set(name);
-
- const PropertyTable& props = target.Props();
-
- // need to convert from TRS order to SRT?
- if (reverse_order) {
-
- aiVector3D def_scale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f));
- aiVector3D def_translate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f));
- aiVector3D def_rot = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f));
-
- KeyFrameListList scaling;
- KeyFrameListList translation;
- KeyFrameListList rotation;
-
- if (chain[TransformationComp_Scaling] != iter_end) {
- scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop);
- }
-
- if (chain[TransformationComp_Translation] != iter_end) {
- translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop);
- }
-
- if (chain[TransformationComp_Rotation] != iter_end) {
- rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop);
- }
-
- KeyFrameListList joined;
- joined.insert(joined.end(), scaling.begin(), scaling.end());
- joined.insert(joined.end(), translation.begin(), translation.end());
- joined.insert(joined.end(), rotation.begin(), rotation.end());
-
- const KeyTimeList& times = GetKeyTimeList(joined);
-
- aiQuatKey* out_quat = new aiQuatKey[times.size()];
- aiVectorKey* out_scale = new aiVectorKey[times.size()];
- aiVectorKey* out_translation = new aiVectorKey[times.size()];
-
- if (times.size())
- {
- ConvertTransformOrder_TRStoSRT(out_quat, out_scale, out_translation,
- scaling,
- translation,
- rotation,
- times,
- max_time,
- min_time,
- target.RotationOrder(),
- def_scale,
- def_translate,
- def_rot);
- }
-
- // XXX remove duplicates / redundant keys which this operation did
- // likely produce if not all three channels were equally dense.
-
- na->mNumScalingKeys = static_cast<unsigned int>(times.size());
- na->mNumRotationKeys = na->mNumScalingKeys;
- na->mNumPositionKeys = na->mNumScalingKeys;
-
- na->mScalingKeys = out_scale;
- na->mRotationKeys = out_quat;
- na->mPositionKeys = out_translation;
- }
- else {
-
- // if a particular transformation is not given, grab it from
- // the corresponding node to meet the semantics of aiNodeAnim,
- // which requires all of rotation, scaling and translation
- // to be set.
- if (chain[TransformationComp_Scaling] != iter_end) {
- ConvertScaleKeys(na.get(), (*chain[TransformationComp_Scaling]).second,
- layer_map,
- start, stop,
- max_time,
- min_time);
- }
- else {
- na->mScalingKeys = new aiVectorKey[1];
- na->mNumScalingKeys = 1;
-
- na->mScalingKeys[0].mTime = 0.;
- na->mScalingKeys[0].mValue = PropertyGet(props, "Lcl Scaling",
- aiVector3D(1.f, 1.f, 1.f));
- }
-
- if (chain[TransformationComp_Rotation] != iter_end) {
- ConvertRotationKeys(na.get(), (*chain[TransformationComp_Rotation]).second,
- layer_map,
- start, stop,
- max_time,
- min_time,
- target.RotationOrder());
- }
- else {
- na->mRotationKeys = new aiQuatKey[1];
- na->mNumRotationKeys = 1;
-
- na->mRotationKeys[0].mTime = 0.;
- na->mRotationKeys[0].mValue = EulerToQuaternion(
- PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f)),
- target.RotationOrder());
- }
-
- if (chain[TransformationComp_Translation] != iter_end) {
- ConvertTranslationKeys(na.get(), (*chain[TransformationComp_Translation]).second,
- layer_map,
- start, stop,
- max_time,
- min_time);
- }
- else {
- na->mPositionKeys = new aiVectorKey[1];
- na->mNumPositionKeys = 1;
-
- na->mPositionKeys[0].mTime = 0.;
- na->mPositionKeys[0].mValue = PropertyGet(props, "Lcl Translation",
- aiVector3D(0.f, 0.f, 0.f));
- }
-
- }
- return na.release();
- }
-
- FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop)
- {
- KeyFrameListList inputs;
- inputs.reserve(nodes.size() * 3);
-
- //give some breathing room for rounding errors
- int64_t adj_start = start - 10000;
- int64_t adj_stop = stop + 10000;
-
- for (const AnimationCurveNode* node : nodes) {
- ai_assert(node);
-
- const AnimationCurveMap& curves = node->Curves();
- for (const AnimationCurveMap::value_type& kv : curves) {
-
- unsigned int mapto;
- if (kv.first == "d|X") {
- mapto = 0;
- }
- else if (kv.first == "d|Y") {
- mapto = 1;
- }
- else if (kv.first == "d|Z") {
- mapto = 2;
- }
- else {
- FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component");
- continue;
- }
-
- const AnimationCurve* const curve = kv.second;
- ai_assert(curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size());
-
- //get values within the start/stop time window
- std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
- std::shared_ptr<KeyValueList> Values(new KeyValueList());
- const size_t count = curve->GetKeys().size();
- Keys->reserve(count);
- Values->reserve(count);
- for (size_t n = 0; n < count; n++)
- {
- int64_t k = curve->GetKeys().at(n);
- if (k >= adj_start && k <= adj_stop)
- {
- Keys->push_back(k);
- Values->push_back(curve->GetValues().at(n));
- }
- }
-
- inputs.push_back(std::make_tuple(Keys, Values, mapto));
- }
- }
- return inputs; // pray for NRVO :-)
- }
-
-
- KeyTimeList FBXConverter::GetKeyTimeList(const KeyFrameListList& inputs) {
- ai_assert(!inputs.empty());
-
- // reserve some space upfront - it is likely that the key-frame lists
- // have matching time values, so max(of all key-frame lists) should
- // be a good estimate.
- KeyTimeList keys;
-
- size_t estimate = 0;
- for (const KeyFrameList& kfl : inputs) {
- estimate = std::max(estimate, std::get<0>(kfl)->size());
- }
-
- keys.reserve(estimate);
-
- std::vector<unsigned int> next_pos;
- next_pos.resize(inputs.size(), 0);
-
- const size_t count = inputs.size();
- while (true) {
-
- int64_t min_tick = std::numeric_limits<int64_t>::max();
- for (size_t i = 0; i < count; ++i) {
- const KeyFrameList& kfl = inputs[i];
-
- if (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) < min_tick) {
- min_tick = std::get<0>(kfl)->at(next_pos[i]);
- }
- }
-
- if (min_tick == std::numeric_limits<int64_t>::max()) {
- break;
- }
- keys.push_back(min_tick);
-
- for (size_t i = 0; i < count; ++i) {
- const KeyFrameList& kfl = inputs[i];
-
-
- while (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == min_tick) {
- ++next_pos[i];
- }
- }
- }
-
- return keys;
- }
-
- void FBXConverter::InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
- const aiVector3D& def_value,
- double& max_time,
- double& min_time) {
- ai_assert(!keys.empty());
- ai_assert(nullptr != valOut);
-
- std::vector<unsigned int> next_pos;
- const size_t count(inputs.size());
-
- next_pos.resize(inputs.size(), 0);
-
- for (KeyTimeList::value_type time : keys) {
- ai_real result[3] = { def_value.x, def_value.y, def_value.z };
-
- for (size_t i = 0; i < count; ++i) {
- const KeyFrameList& kfl = inputs[i];
-
- const size_t ksize = std::get<0>(kfl)->size();
- if (ksize == 0) {
- continue;
- }
- if (ksize > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == time) {
- ++next_pos[i];
- }
-
- const size_t id0 = next_pos[i] > 0 ? next_pos[i] - 1 : 0;
- const size_t id1 = next_pos[i] == ksize ? ksize - 1 : next_pos[i];
-
- // use lerp for interpolation
- const KeyValueList::value_type valueA = std::get<1>(kfl)->at(id0);
- const KeyValueList::value_type valueB = std::get<1>(kfl)->at(id1);
-
- const KeyTimeList::value_type timeA = std::get<0>(kfl)->at(id0);
- const KeyTimeList::value_type timeB = std::get<0>(kfl)->at(id1);
-
- const ai_real factor = timeB == timeA ? ai_real(0.) : static_cast<ai_real>((time - timeA)) / (timeB - timeA);
- const ai_real interpValue = static_cast<ai_real>(valueA + (valueB - valueA) * factor);
-
- result[std::get<2>(kfl)] = interpValue;
- }
-
- // magic value to convert fbx times to seconds
- valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps;
-
- min_time = std::min(min_time, valOut->mTime);
- max_time = std::max(max_time, valOut->mTime);
-
- valOut->mValue.x = result[0];
- valOut->mValue.y = result[1];
- valOut->mValue.z = result[2];
-
- ++valOut;
- }
- }
-
- void FBXConverter::InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
- const aiVector3D& def_value,
- double& maxTime,
- double& minTime,
- Model::RotOrder order)
- {
- ai_assert(!keys.empty());
- ai_assert(nullptr != valOut);
-
- std::unique_ptr<aiVectorKey[]> temp(new aiVectorKey[keys.size()]);
- InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime);
-
- aiMatrix4x4 m;
-
- aiQuaternion lastq;
-
- for (size_t i = 0, c = keys.size(); i < c; ++i) {
-
- valOut[i].mTime = temp[i].mTime;
-
- GetRotationMatrix(order, temp[i].mValue, m);
- aiQuaternion quat = aiQuaternion(aiMatrix3x3(m));
-
- // take shortest path by checking the inner product
- // http://www.3dkingdoms.com/weekly/weekly.php?a=36
- if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0)
- {
- quat.x = -quat.x;
- quat.y = -quat.y;
- quat.z = -quat.z;
- quat.w = -quat.w;
- }
- lastq = quat;
-
- valOut[i].mValue = quat;
- }
- }
-
- void FBXConverter::ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale,
- aiVectorKey* out_translation,
- const KeyFrameListList& scaling,
- const KeyFrameListList& translation,
- const KeyFrameListList& rotation,
- const KeyTimeList& times,
- double& maxTime,
- double& minTime,
- Model::RotOrder order,
- const aiVector3D& def_scale,
- const aiVector3D& def_translate,
- const aiVector3D& def_rotation)
- {
- if (rotation.size()) {
- InterpolateKeys(out_quat, times, rotation, def_rotation, maxTime, minTime, order);
- }
- else {
- for (size_t i = 0; i < times.size(); ++i) {
- out_quat[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps;
- out_quat[i].mValue = EulerToQuaternion(def_rotation, order);
- }
- }
-
- if (scaling.size()) {
- InterpolateKeys(out_scale, times, scaling, def_scale, maxTime, minTime);
- }
- else {
- for (size_t i = 0; i < times.size(); ++i) {
- out_scale[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps;
- out_scale[i].mValue = def_scale;
- }
- }
-
- if (translation.size()) {
- InterpolateKeys(out_translation, times, translation, def_translate, maxTime, minTime);
- }
- else {
- for (size_t i = 0; i < times.size(); ++i) {
- out_translation[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps;
- out_translation[i].mValue = def_translate;
- }
- }
-
- const size_t count = times.size();
- for (size_t i = 0; i < count; ++i) {
- aiQuaternion& r = out_quat[i].mValue;
- aiVector3D& s = out_scale[i].mValue;
- aiVector3D& t = out_translation[i].mValue;
-
- aiMatrix4x4 mat, temp;
- aiMatrix4x4::Translation(t, mat);
- mat *= aiMatrix4x4(r.GetMatrix());
- mat *= aiMatrix4x4::Scaling(s, temp);
-
- mat.Decompose(s, r, t);
- }
- }
-
- aiQuaternion FBXConverter::EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order)
- {
- aiMatrix4x4 m;
- GetRotationMatrix(order, rot, m);
-
- return aiQuaternion(aiMatrix3x3(m));
- }
-
- void FBXConverter::ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
- int64_t start, int64_t stop,
- double& maxTime,
- double& minTime)
- {
- ai_assert(nodes.size());
-
- // XXX for now, assume scale should be blended geometrically (i.e. two
- // layers should be multiplied with each other). There is a FBX
- // property in the layer to specify the behaviour, though.
-
- const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop);
- const KeyTimeList& keys = GetKeyTimeList(inputs);
-
- na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
- na->mScalingKeys = new aiVectorKey[keys.size()];
- if (keys.size() > 0) {
- InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime);
- }
- }
-
- void FBXConverter::ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
- const LayerMap& /*layers*/,
- int64_t start, int64_t stop,
- double& maxTime,
- double& minTime)
- {
- ai_assert(nodes.size());
-
- // XXX see notes in ConvertScaleKeys()
- const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop);
- const KeyTimeList& keys = GetKeyTimeList(inputs);
-
- na->mNumPositionKeys = static_cast<unsigned int>(keys.size());
- na->mPositionKeys = new aiVectorKey[keys.size()];
- if (keys.size() > 0)
- InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime);
- }
-
- void FBXConverter::ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
- const LayerMap& /*layers*/,
- int64_t start, int64_t stop,
- double& maxTime,
- double& minTime,
- Model::RotOrder order)
- {
- ai_assert(nodes.size());
-
- // XXX see notes in ConvertScaleKeys()
- const std::vector< KeyFrameList >& inputs = GetKeyframeList(nodes, start, stop);
- const KeyTimeList& keys = GetKeyTimeList(inputs);
-
- na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
- na->mRotationKeys = new aiQuatKey[keys.size()];
- if (!keys.empty()) {
- InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order);
- }
- }
-
- void FBXConverter::ConvertGlobalSettings() {
- if (nullptr == out) {
- return;
- }
-
- out->mMetaData = aiMetadata::Alloc(15);
- out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis());
- out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign());
- out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis());
- out->mMetaData->Set(3, "FrontAxisSign", doc.GlobalSettings().FrontAxisSign());
- out->mMetaData->Set(4, "CoordAxis", doc.GlobalSettings().CoordAxis());
- out->mMetaData->Set(5, "CoordAxisSign", doc.GlobalSettings().CoordAxisSign());
- out->mMetaData->Set(6, "OriginalUpAxis", doc.GlobalSettings().OriginalUpAxis());
- out->mMetaData->Set(7, "OriginalUpAxisSign", doc.GlobalSettings().OriginalUpAxisSign());
- out->mMetaData->Set(8, "UnitScaleFactor", (double)doc.GlobalSettings().UnitScaleFactor());
- out->mMetaData->Set(9, "OriginalUnitScaleFactor", doc.GlobalSettings().OriginalUnitScaleFactor());
- out->mMetaData->Set(10, "AmbientColor", doc.GlobalSettings().AmbientColor());
- out->mMetaData->Set(11, "FrameRate", (int)doc.GlobalSettings().TimeMode());
- out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart());
- out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop());
- out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate());
- }
-
- void FBXConverter::TransferDataToScene()
- {
- ai_assert(!out->mMeshes);
- ai_assert(!out->mNumMeshes);
-
- // note: the trailing () ensures initialization with nullptr - not
- // many C++ users seem to know this, so pointing it out to avoid
- // confusion why this code works.
-
- if (meshes.size()) {
- out->mMeshes = new aiMesh*[meshes.size()]();
- out->mNumMeshes = static_cast<unsigned int>(meshes.size());
-
- std::swap_ranges(meshes.begin(), meshes.end(), out->mMeshes);
- }
-
- if (materials.size()) {
- out->mMaterials = new aiMaterial*[materials.size()]();
- out->mNumMaterials = static_cast<unsigned int>(materials.size());
-
- std::swap_ranges(materials.begin(), materials.end(), out->mMaterials);
- }
-
- if (animations.size()) {
- out->mAnimations = new aiAnimation*[animations.size()]();
- out->mNumAnimations = static_cast<unsigned int>(animations.size());
-
- std::swap_ranges(animations.begin(), animations.end(), out->mAnimations);
- }
-
- if (lights.size()) {
- out->mLights = new aiLight*[lights.size()]();
- out->mNumLights = static_cast<unsigned int>(lights.size());
-
- std::swap_ranges(lights.begin(), lights.end(), out->mLights);
- }
-
- if (cameras.size()) {
- out->mCameras = new aiCamera*[cameras.size()]();
- out->mNumCameras = static_cast<unsigned int>(cameras.size());
-
- std::swap_ranges(cameras.begin(), cameras.end(), out->mCameras);
- }
-
- if (textures.size()) {
- out->mTextures = new aiTexture*[textures.size()]();
- out->mNumTextures = static_cast<unsigned int>(textures.size());
-
- std::swap_ranges(textures.begin(), textures.end(), out->mTextures);
- }
- }
-
- void FBXConverter::ConvertOrphantEmbeddedTextures()
- {
- // in C++14 it could be:
- // for (auto&& [id, object] : objects)
- for (auto&& id_and_object : doc.Objects())
- {
- auto&& id = std::get<0>(id_and_object);
- auto&& object = std::get<1>(id_and_object);
- // If an object doesn't have parent
- if (doc.ConnectionsBySource().count(id) == 0)
- {
- const Texture* realTexture = nullptr;
- try
- {
- const auto& element = object->GetElement();
- const Token& key = element.KeyToken();
- const char* obtype = key.begin();
- const size_t length = static_cast<size_t>(key.end() - key.begin());
- if (strncmp(obtype, "Texture", length) == 0)
- {
- const Texture* texture = static_cast<const Texture*>(object->Get());
- if (texture->Media() && texture->Media()->ContentLength() > 0)
- {
- realTexture = texture;
- }
- }
- }
- catch (...)
- {
- // do nothing
- }
- if (realTexture)
- {
- const Video* media = realTexture->Media();
- unsigned int index = ConvertVideo(*media);
- textures_converted[*media] = index;
- }
- }
- }
- }
-
- // ------------------------------------------------------------------------------------------------
- void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones)
- {
- FBXConverter converter(out, doc, removeEmptyBones);
- }
-
- } // !FBX
-} // !Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXConverter.h b/thirdparty/assimp/code/FBX/FBXConverter.h
deleted file mode 100644
index 46693bdca6..0000000000
--- a/thirdparty/assimp/code/FBX/FBXConverter.h
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXDConverter.h
- * @brief FBX DOM to aiScene conversion
- */
-#ifndef INCLUDED_AI_FBX_CONVERTER_H
-#define INCLUDED_AI_FBX_CONVERTER_H
-
-#include "FBXParser.h"
-#include "FBXMeshGeometry.h"
-#include "FBXDocument.h"
-#include "FBXUtil.h"
-#include "FBXProperties.h"
-#include "FBXImporter.h"
-
-#include <assimp/anim.h>
-#include <assimp/material.h>
-#include <assimp/light.h>
-#include <assimp/texture.h>
-#include <assimp/camera.h>
-#include <assimp/StringComparison.h>
-#include <unordered_map>
-#include <unordered_set>
-
-struct aiScene;
-struct aiNode;
-struct aiMaterial;
-
-struct morphKeyData {
- std::vector<unsigned int> values;
- std::vector<float> weights;
-};
-typedef std::map<int64_t, morphKeyData*> morphAnimData;
-
-namespace Assimp {
-namespace FBX {
-
-class Document;
-/**
- * Convert a FBX #Document to #aiScene
- * @param out Empty scene to be populated
- * @param doc Parsed FBX document
- * @param removeEmptyBones Will remove bones, which do not have any references to vertices.
- */
-void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones);
-
-/** Dummy class to encapsulate the conversion process */
-class FBXConverter {
-public:
- /**
- * The different parts that make up the final local transformation of a fbx-node
- */
- enum TransformationComp {
- TransformationComp_GeometricScalingInverse = 0,
- TransformationComp_GeometricRotationInverse,
- TransformationComp_GeometricTranslationInverse,
- TransformationComp_Translation,
- TransformationComp_RotationOffset,
- TransformationComp_RotationPivot,
- TransformationComp_PreRotation,
- TransformationComp_Rotation,
- TransformationComp_PostRotation,
- TransformationComp_RotationPivotInverse,
- TransformationComp_ScalingOffset,
- TransformationComp_ScalingPivot,
- TransformationComp_Scaling,
- TransformationComp_ScalingPivotInverse,
- TransformationComp_GeometricTranslation,
- TransformationComp_GeometricRotation,
- TransformationComp_GeometricScaling,
-
- TransformationComp_MAXIMUM
- };
-
-public:
- FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones);
- ~FBXConverter();
-
-private:
- // ------------------------------------------------------------------------------------------------
- // find scene root and trigger recursive scene conversion
- void ConvertRootNode();
-
- // ------------------------------------------------------------------------------------------------
- // collect and assign child nodes
- void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node);
-
- // ------------------------------------------------------------------------------------------------
- void ConvertLights(const Model& model, const std::string &orig_name );
-
- // ------------------------------------------------------------------------------------------------
- void ConvertCameras(const Model& model, const std::string &orig_name );
-
- // ------------------------------------------------------------------------------------------------
- void ConvertLight( const Light& light, const std::string &orig_name );
-
- // ------------------------------------------------------------------------------------------------
- void ConvertCamera( const Camera& cam, const std::string &orig_name );
-
- // ------------------------------------------------------------------------------------------------
- void GetUniqueName( const std::string &name, std::string& uniqueName );
-
- // ------------------------------------------------------------------------------------------------
- // this returns unified names usable within assimp identifiers (i.e. no space characters -
- // while these would be allowed, they are a potential trouble spot so better not use them).
- const char* NameTransformationComp(TransformationComp comp);
-
- // ------------------------------------------------------------------------------------------------
- // Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and
- // then makes this name unique
- std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent);
-
- // ------------------------------------------------------------------------------------------------
- // note: this returns the REAL fbx property names
- const char* NameTransformationCompProperty(TransformationComp comp);
-
- // ------------------------------------------------------------------------------------------------
- aiVector3D TransformationCompDefaultValue(TransformationComp comp);
-
- // ------------------------------------------------------------------------------------------------
- void GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out);
- // ------------------------------------------------------------------------------------------------
- /**
- * checks if a node has more than just scaling, rotation and translation components
- */
- bool NeedsComplexTransformationChain(const Model& model);
-
- // ------------------------------------------------------------------------------------------------
- // note: name must be a FixNodeName() result
- std::string NameTransformationChainNode(const std::string& name, TransformationComp comp);
-
- // ------------------------------------------------------------------------------------------------
- /**
- * note: memory for output_nodes will be managed by the caller
- */
- bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
-
- // ------------------------------------------------------------------------------------------------
- void SetupNodeMetadata(const Model& model, aiNode& nd);
-
- // ------------------------------------------------------------------------------------------------
- void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
- const aiMatrix4x4 &absolute_transform);
-
- // ------------------------------------------------------------------------------------------------
- // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
- std::vector<unsigned int>
- ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
- const aiMatrix4x4 &absolute_transform);
-
- // ------------------------------------------------------------------------------------------------
- std::vector<unsigned int> ConvertLine(const LineGeometry& line, const Model& model,
- aiNode *parent, aiNode *root_node);
-
- // ------------------------------------------------------------------------------------------------
- aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
-
- // ------------------------------------------------------------------------------------------------
- unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
- const aiMatrix4x4 &absolute_transform, aiNode *parent,
- aiNode *root_node);
-
- // ------------------------------------------------------------------------------------------------
- std::vector<unsigned int>
- ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
- const aiMatrix4x4 &absolute_transform);
-
- // ------------------------------------------------------------------------------------------------
- unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index,
- aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
-
- // ------------------------------------------------------------------------------------------------
- static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */
- static_cast<unsigned int>(-1);
-
- // ------------------------------------------------------------------------------------------------
- /**
- * - if materialIndex == NO_MATERIAL_SEPARATION, materials are not taken into
- * account when determining which weights to include.
- * - outputVertStartIndices is only used when a material index is specified, it gives for
- * each output vertex the DOM index it maps to.
- */
- void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
- aiNode *parent = NULL, aiNode *root_node = NULL,
- unsigned int materialIndex = NO_MATERIAL_SEPARATION,
- std::vector<unsigned int> *outputVertStartIndices = NULL);
- // lookup
- static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node );
- // ------------------------------------------------------------------------------------------------
- void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
- std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
- std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
- aiNode *parent, aiNode *root_node);
-
- // ------------------------------------------------------------------------------------------------
- void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
- MatIndexArray::value_type materialIndex);
-
- // ------------------------------------------------------------------------------------------------
- unsigned int GetDefaultMaterial();
-
- // ------------------------------------------------------------------------------------------------
- // Material -> aiMaterial
- unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh);
-
- // ------------------------------------------------------------------------------------------------
- // Video -> aiTexture
- unsigned int ConvertVideo(const Video& video);
-
- // ------------------------------------------------------------------------------------------------
- // convert embedded texture if necessary and return actual texture path
- aiString GetTexturePath(const Texture* tex);
-
- // ------------------------------------------------------------------------------------------------
- void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
- const std::string& propName,
- aiTextureType target, const MeshGeometry* const mesh);
-
- // ------------------------------------------------------------------------------------------------
- void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
- const std::string& propName,
- aiTextureType target, const MeshGeometry* const mesh);
-
- // ------------------------------------------------------------------------------------------------
- void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh);
-
- // ------------------------------------------------------------------------------------------------
- void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh);
-
- // ------------------------------------------------------------------------------------------------
- aiColor3D GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName,
- bool& result);
- aiColor3D GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName,
- const std::string& factorName, bool& result, bool useTemplate = true);
- aiColor3D GetColorProperty(const PropertyTable& props, const std::string& colorName,
- bool& result, bool useTemplate = true);
-
- // ------------------------------------------------------------------------------------------------
- void SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props);
- void SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh);
-
- // ------------------------------------------------------------------------------------------------
- // get the number of fps for a FrameRate enumerated value
- static double FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal = -1.0);
-
- // ------------------------------------------------------------------------------------------------
- // convert animation data to aiAnimation et al
- void ConvertAnimations();
-
- // ------------------------------------------------------------------------------------------------
- // takes a fbx node name and returns the identifier to be used in the assimp output scene.
- // the function is guaranteed to provide consistent results over multiple invocations
- // UNLESS RenameNode() is called for a particular node name.
- std::string FixNodeName(const std::string& name);
- std::string FixAnimMeshName(const std::string& name);
-
- typedef std::map<const AnimationCurveNode*, const AnimationLayer*> LayerMap;
-
- // XXX: better use multi_map ..
- typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap;
-
- // ------------------------------------------------------------------------------------------------
- void ConvertAnimationStack(const AnimationStack& st);
-
- // ------------------------------------------------------------------------------------------------
- void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node);
-
- // ------------------------------------------------------------------------------------------------
- void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
- const std::string& fixed_name,
- const std::vector<const AnimationCurveNode*>& curves,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time);
-
- // ------------------------------------------------------------------------------------------------
- bool IsRedundantAnimationData(const Model& target,
- TransformationComp comp,
- const std::vector<const AnimationCurveNode*>& curves);
-
- // ------------------------------------------------------------------------------------------------
- aiNodeAnim* GenerateRotationNodeAnim(const std::string& name,
- const Model& target,
- const std::vector<const AnimationCurveNode*>& curves,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time);
-
- // ------------------------------------------------------------------------------------------------
- aiNodeAnim* GenerateScalingNodeAnim(const std::string& name,
- const Model& /*target*/,
- const std::vector<const AnimationCurveNode*>& curves,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time);
-
- // ------------------------------------------------------------------------------------------------
- aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name,
- const Model& /*target*/,
- const std::vector<const AnimationCurveNode*>& curves,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time,
- bool inverse = false);
-
- // ------------------------------------------------------------------------------------------------
- // generate node anim, extracting only Rotation, Scaling and Translation from the given chain
- aiNodeAnim* GenerateSimpleNodeAnim(const std::string& name,
- const Model& target,
- NodeMap::const_iterator chain[TransformationComp_MAXIMUM],
- NodeMap::const_iterator iter_end,
- const LayerMap& layer_map,
- int64_t start, int64_t stop,
- double& max_time,
- double& min_time,
- bool reverse_order = false);
-
- // key (time), value, mapto (component index)
- typedef std::tuple<std::shared_ptr<KeyTimeList>, std::shared_ptr<KeyValueList>, unsigned int > KeyFrameList;
- typedef std::vector<KeyFrameList> KeyFrameListList;
-
- // ------------------------------------------------------------------------------------------------
- KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop);
-
- // ------------------------------------------------------------------------------------------------
- KeyTimeList GetKeyTimeList(const KeyFrameListList& inputs);
-
- // ------------------------------------------------------------------------------------------------
- void InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
- const aiVector3D& def_value,
- double& max_time,
- double& min_time);
-
- // ------------------------------------------------------------------------------------------------
- void InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
- const aiVector3D& def_value,
- double& maxTime,
- double& minTime,
- Model::RotOrder order);
-
- // ------------------------------------------------------------------------------------------------
- void ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale,
- aiVectorKey* out_translation,
- const KeyFrameListList& scaling,
- const KeyFrameListList& translation,
- const KeyFrameListList& rotation,
- const KeyTimeList& times,
- double& maxTime,
- double& minTime,
- Model::RotOrder order,
- const aiVector3D& def_scale,
- const aiVector3D& def_translate,
- const aiVector3D& def_rotation);
-
- // ------------------------------------------------------------------------------------------------
- // euler xyz -> quat
- aiQuaternion EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order);
-
- // ------------------------------------------------------------------------------------------------
- void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
- int64_t start, int64_t stop,
- double& maxTime,
- double& minTime);
-
- // ------------------------------------------------------------------------------------------------
- void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
- const LayerMap& /*layers*/,
- int64_t start, int64_t stop,
- double& maxTime,
- double& minTime);
-
- // ------------------------------------------------------------------------------------------------
- void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
- const LayerMap& /*layers*/,
- int64_t start, int64_t stop,
- double& maxTime,
- double& minTime,
- Model::RotOrder order);
-
- void ConvertGlobalSettings();
-
- // ------------------------------------------------------------------------------------------------
- // copy generated meshes, animations, lights, cameras and textures to the output scene
- void TransferDataToScene();
-
- // ------------------------------------------------------------------------------------------------
- // FBX file could have embedded textures not connected to anything
- void ConvertOrphantEmbeddedTextures();
-
-private:
- // 0: not assigned yet, others: index is value - 1
- unsigned int defaultMaterialIndex;
-
- std::vector<aiMesh*> meshes;
- std::vector<aiMaterial*> materials;
- std::vector<aiAnimation*> animations;
- std::vector<aiLight*> lights;
- std::vector<aiCamera*> cameras;
- std::vector<aiTexture*> textures;
-
- using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
- MaterialMap materials_converted;
-
- using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
- VideoMap textures_converted;
-
- using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;
- MeshMap meshes_converted;
-
- // fixed node name -> which trafo chain components have animations?
- using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ;
- NodeAnimBitMap node_anim_chain_bits;
-
- // number of nodes with the same name
- using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>;
- NodeNameCache mNodeNames;
-
- // Deformer name is not the same as a bone name - it does contain the bone name though :)
- // Deformer names in FBX are always unique in an FBX file.
- std::map<const std::string, aiBone *> bone_map;
-
- double anim_fps;
-
- aiScene* const out;
- const FBX::Document& doc;
-
- static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
- std::vector<aiBone*>& bones);
-
- void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
- const std::vector<aiBone *> &bones,
- std::map<aiBone *, aiNode *> &bone_stack,
- std::vector<aiNode*> &node_stack );
-
- static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes);
-
- static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes);
-
- static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list);
-
- static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones);
-};
-
-}
-}
-
-#endif // INCLUDED_AI_FBX_CONVERTER_H
diff --git a/thirdparty/assimp/code/FBX/FBXDeformer.cpp b/thirdparty/assimp/code/FBX/FBXDeformer.cpp
deleted file mode 100644
index 6927553450..0000000000
--- a/thirdparty/assimp/code/FBX/FBXDeformer.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXNoteAttribute.cpp
- * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include "FBXParser.h"
-#include "FBXDocument.h"
-#include "FBXMeshGeometry.h"
-#include "FBXImporter.h"
-#include "FBXDocumentUtil.h"
-
-namespace Assimp {
-namespace FBX {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name)
- : Object(id,element,name)
-{
- const Scope& sc = GetRequiredScope(element);
-
- const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
- props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Deformer::~Deformer()
-{
-
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: Deformer(id,element,doc,name)
-, node()
-{
- const Scope& sc = GetRequiredScope(element);
-
- const Element* const Indexes = sc["Indexes"];
- const Element* const Weights = sc["Weights"];
-
- const Element& Transform = GetRequiredElement(sc,"Transform",&element);
- const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&element);
-
- transform = ReadMatrix(Transform);
- transformLink = ReadMatrix(TransformLink);
-
- // it is actually possible that there be Deformer's with no weights
- if (!!Indexes != !!Weights) {
- DOMError("either Indexes or Weights are missing from Cluster",&element);
- }
-
- if(Indexes) {
- ParseVectorDataArray(indices,*Indexes);
- ParseVectorDataArray(weights,*Weights);
- }
-
- if(indices.size() != weights.size()) {
- DOMError("sizes of index and weight array don't match up",&element);
- }
-
- // read assigned node
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model");
- for(const Connection* con : conns) {
- const Model* const mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
- if(mod) {
- node = mod;
- break;
- }
- }
-
- if (!node) {
- DOMError("failed to read target Node for Cluster",&element);
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Cluster::~Cluster()
-{
-
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: Deformer(id,element,doc,name)
-, accuracy( 0.0f ) {
- const Scope& sc = GetRequiredScope(element);
-
- const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"];
- if(Link_DeformAcuracy) {
- accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0));
- }
-
- // resolve assigned clusters
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
-
- clusters.reserve(conns.size());
- for(const Connection* con : conns) {
-
- const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
- if(cluster) {
- clusters.push_back(cluster);
- continue;
- }
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Skin::~Skin()
-{
-
-}
-// ------------------------------------------------------------------------------------------------
-BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name)
- : Deformer(id, element, doc, name)
-{
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
- blendShapeChannels.reserve(conns.size());
- for (const Connection* con : conns) {
- const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element);
- if (bspc) {
- blendShapeChannels.push_back(bspc);
- continue;
- }
- }
-}
-// ------------------------------------------------------------------------------------------------
-BlendShape::~BlendShape()
-{
-
-}
-// ------------------------------------------------------------------------------------------------
-BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name)
- : Deformer(id, element, doc, name)
-{
- const Scope& sc = GetRequiredScope(element);
- const Element* const DeformPercent = sc["DeformPercent"];
- if (DeformPercent) {
- percent = ParseTokenAsFloat(GetRequiredToken(*DeformPercent, 0));
- }
- const Element* const FullWeights = sc["FullWeights"];
- if (FullWeights) {
- ParseVectorDataArray(fullWeights, *FullWeights);
- }
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry");
- shapeGeometries.reserve(conns.size());
- for (const Connection* con : conns) {
- const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element);
- if (sg) {
- shapeGeometries.push_back(sg);
- continue;
- }
- }
-}
-// ------------------------------------------------------------------------------------------------
-BlendShapeChannel::~BlendShapeChannel()
-{
-
-}
-// ------------------------------------------------------------------------------------------------
-}
-}
-#endif
-
diff --git a/thirdparty/assimp/code/FBX/FBXDocument.cpp b/thirdparty/assimp/code/FBX/FBXDocument.cpp
deleted file mode 100644
index 506fd978dd..0000000000
--- a/thirdparty/assimp/code/FBX/FBXDocument.cpp
+++ /dev/null
@@ -1,718 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXDocument.cpp
- * @brief Implementation of the FBX DOM classes
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#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>
-#include <map>
-
-namespace Assimp {
-namespace FBX {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc)
-: doc(doc)
-, element(element)
-, id(id)
-, flags() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-LazyObject::~LazyObject()
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-const Object* LazyObject::Get(bool dieOnError)
-{
- if(IsBeingConstructed() || FailedToConstruct()) {
- return nullptr;
- }
-
- if (object.get()) {
- 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));
- }
- if (!strcmp(classtag.c_str(), "Shape")) {
- object.reset(new ShapeGeometry(id, element, name, doc));
- }
- if (!strcmp(classtag.c_str(), "Line")) {
- object.reset(new LineGeometry(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 (!strcmp(classtag.c_str(), "BlendShape")) {
- object.reset(new BlendShape(id, element, doc, name));
- }
- else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) {
- object.reset(new BlendShapeChannel(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()) {
- ASSIMP_LOG_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();
-}
-
-// ------------------------------------------------------------------------------------------------
-Object::Object(uint64_t id, const Element& element, const std::string& name)
-: element(element)
-, name(name)
-, id(id)
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Object::~Object()
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-FileGlobalSettings::FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props)
-: props(props)
-, doc(doc)
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-FileGlobalSettings::~FileGlobalSettings()
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Document::Document(const Parser& parser, const ImportSettings& settings)
-: settings(settings)
-, parser(parser)
-{
- // Cannot use array default initialization syntax because vc8 fails on it
- for (auto &timeStamp : creationTimeStamp) {
- timeStamp = 0;
- }
-
- ReadHeader();
- ReadPropertyTemplates();
-
- 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();
-}
-
-// ------------------------------------------------------------------------------------------------
-Document::~Document()
-{
- 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 unsigned int LowerSupportedVersion = 7100;
-static const unsigned 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 may 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 ( nullptr == ehead || !ehead->Compound() ) {
- DOMWarning( "no GlobalSettings dictionary found" );
- globals.reset(new FileGlobalSettings(*this, std::make_shared<const PropertyTable>()));
- return;
- }
-
- std::shared_ptr<const PropertyTable> props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true );
-
- //double v = PropertyGet<float>( *props.get(), std::string("UnitScaleFactor"), 1.0 );
-
- if(!props) {
- DOMError("GlobalSettings dictionary contains no property table");
- }
-
- 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();
- 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) {
- 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;
- }
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-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));
-
- // 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.empty()) {
- 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() ? nullptr : (*it).second;
-}
-
-#define MAX_CLASSNAMES 6
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const
-{
- std::vector<const Connection*> temp;
-
- 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);
- }
-
- std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
-
- 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
-
-{
- ai_assert(classnames);
- ai_assert( count != 0 );
- ai_assert( count <= MAX_CLASSNAMES);
-
- size_t lengths[MAX_CLASSNAMES];
-
- const size_t c = count;
- for (size_t i = 0; i < c; ++i) {
- lengths[ i ] = strlen(classnames[i]);
- }
-
- std::vector<const Connection*> temp;
- 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();
-
- 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())) == lengths[i] && !strncmp(classnames[i],obtype,lengths[i])) {
- obtype = nullptr;
- break;
- }
- }
-
- if(obtype) {
- continue;
- }
-
- temp.push_back((*it).second);
- }
-
- std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
- return temp; // NRVO should handle this
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const
-{
- return GetConnectionsSequenced(source, ConnectionsBySource());
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t src, const char* classname) const
-{
- const char* arr[] = {classname};
- return GetConnectionsBySourceSequenced(src, arr,1);
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source,
- const char* const* classnames, size_t count) const
-{
- return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
- const char* classname) const
-{
- const char* arr[] = {classname};
- return GetConnectionsByDestinationSequenced(dest, arr,1);
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const
-{
- return GetConnectionsSequenced(dest, ConnectionsByDestination());
-}
-
-// ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest,
- const char* const* classnames, size_t count) const
-
-{
- 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)
-
-: insertionOrder(insertionOrder)
-, prop(prop)
-, src(src)
-, 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());
-}
-
-// ------------------------------------------------------------------------------------------------
-Connection::~Connection()
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-LazyObject& Connection::LazySourceObject() const
-{
- 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;
-}
-
-// ------------------------------------------------------------------------------------------------
-const Object* Connection::SourceObject() const
-{
- 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();
-}
-
-} // !FBX
-} // !Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXDocument.h b/thirdparty/assimp/code/FBX/FBXDocument.h
deleted file mode 100644
index a60d7d9efa..0000000000
--- a/thirdparty/assimp/code/FBX/FBXDocument.h
+++ /dev/null
@@ -1,1215 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXDocument.h
- * @brief FBX DOM
- */
-#ifndef INCLUDED_AI_FBX_DOCUMENT_H
-#define INCLUDED_AI_FBX_DOCUMENT_H
-
-#include <numeric>
-#include <stdint.h>
-#include <assimp/mesh.h>
-#include "FBXProperties.h"
-#include "FBXParser.h"
-
-#define _AI_CONCAT(a,b) a ## b
-#define AI_CONCAT(a,b) _AI_CONCAT(a,b)
-
-namespace Assimp {
-namespace FBX {
-
-class Parser;
-class Object;
-struct ImportSettings;
-
-class PropertyTable;
-class Document;
-class Material;
-class ShapeGeometry;
-class LineGeometry;
-class Geometry;
-
-class Video;
-
-class AnimationCurve;
-class AnimationCurveNode;
-class AnimationLayer;
-class AnimationStack;
-
-class BlendShapeChannel;
-class BlendShape;
-class Skin;
-class Cluster;
-
-
-/** Represents a delay-parsed FBX objects. Many objects in the scene
- * are not needed by assimp, so it makes no sense to parse them
- * upfront. */
-class LazyObject {
-public:
- LazyObject(uint64_t id, const Element& element, const Document& doc);
-
- ~LazyObject();
-
- const Object* Get(bool dieOnError = false);
-
- template <typename T>
- const T* Get(bool dieOnError = false) {
- const Object* const ob = Get(dieOnError);
- return ob ? dynamic_cast<const T*>(ob) : NULL;
- }
-
- uint64_t ID() const {
- return id;
- }
-
- bool IsBeingConstructed() const {
- return (flags & BEING_CONSTRUCTED) != 0;
- }
-
- bool FailedToConstruct() const {
- return (flags & FAILED_TO_CONSTRUCT) != 0;
- }
-
- const Element& GetElement() const {
- return element;
- }
-
- const Document& GetDocument() const {
- return doc;
- }
-
-private:
- const Document& doc;
- const Element& element;
- std::unique_ptr<const Object> object;
-
- const uint64_t id;
-
- enum Flags {
- BEING_CONSTRUCTED = 0x1,
- FAILED_TO_CONSTRUCT = 0x2
- };
-
- unsigned int flags;
-};
-
-/** Base class for in-memory (DOM) representations of FBX objects */
-class Object {
-public:
- Object(uint64_t id, const Element& element, const std::string& name);
-
- virtual ~Object();
-
- const Element& SourceElement() const {
- return element;
- }
-
- const std::string& Name() const {
- return name;
- }
-
- uint64_t ID() const {
- return id;
- }
-
-protected:
- const Element& element;
- const std::string name;
- const uint64_t id;
-};
-
-/** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table,
- * fixed members are added by deriving classes. */
-class NodeAttribute : public Object {
-public:
- NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~NodeAttribute();
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
-private:
- std::shared_ptr<const PropertyTable> props;
-};
-
-/** DOM base class for FBX camera settings attached to a node */
-class CameraSwitcher : public NodeAttribute {
-public:
- CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~CameraSwitcher();
-
- int CameraID() const {
- return cameraId;
- }
-
- const std::string& CameraName() const {
- return cameraName;
- }
-
- const std::string& CameraIndexName() const {
- return cameraIndexName;
- }
-
-private:
- int cameraId;
- std::string cameraName;
- std::string cameraIndexName;
-};
-
-#define fbx_stringize(a) #a
-
-#define fbx_simple_property(name, type, default_value) \
- type name() const { \
- return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
- }
-
-// XXX improve logging
-#define fbx_simple_enum_property(name, type, default_value) \
- type name() const { \
- const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \
- if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
- ai_assert(static_cast<int>(default_value) >= 0 && static_cast<int>(default_value) < AI_CONCAT(type, _MAX)); \
- return static_cast<type>(default_value); \
- } \
- return static_cast<type>(ival); \
-}
-
-
-/** DOM base class for FBX cameras attached to a node */
-class Camera : public NodeAttribute {
-public:
- Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~Camera();
-
- fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0))
- fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0))
- fbx_simple_property(InterestPosition, aiVector3D, aiVector3D(0,0,0))
-
- fbx_simple_property(AspectWidth, float, 1.0f)
- fbx_simple_property(AspectHeight, float, 1.0f)
- fbx_simple_property(FilmWidth, float, 1.0f)
- fbx_simple_property(FilmHeight, float, 1.0f)
-
- fbx_simple_property(NearPlane, float, 0.1f)
- fbx_simple_property(FarPlane, float, 100.0f)
-
- fbx_simple_property(FilmAspectRatio, float, 1.0f)
- fbx_simple_property(ApertureMode, int, 0)
-
- fbx_simple_property(FieldOfView, float, 1.0f)
- fbx_simple_property(FocalLength, float, 1.0f)
-};
-
-/** DOM base class for FBX null markers attached to a node */
-class Null : public NodeAttribute {
-public:
- Null(uint64_t id, const Element& element, const Document& doc, const std::string& name);
- virtual ~Null();
-};
-
-/** DOM base class for FBX limb node markers attached to a node */
-class LimbNode : public NodeAttribute {
-public:
- LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name);
- virtual ~LimbNode();
-};
-
-/** DOM base class for FBX lights attached to a node */
-class Light : public NodeAttribute {
-public:
- Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
- virtual ~Light();
-
- enum Type
- {
- Type_Point,
- Type_Directional,
- Type_Spot,
- Type_Area,
- Type_Volume,
-
- Type_MAX // end-of-enum sentinel
- };
-
- enum Decay
- {
- Decay_None,
- Decay_Linear,
- Decay_Quadratic,
- Decay_Cubic,
-
- Decay_MAX // end-of-enum sentinel
- };
-
- fbx_simple_property(Color, aiVector3D, aiVector3D(1,1,1))
- fbx_simple_enum_property(LightType, Type, 0)
- fbx_simple_property(CastLightOnObject, bool, false)
- fbx_simple_property(DrawVolumetricLight, bool, true)
- fbx_simple_property(DrawGroundProjection, bool, true)
- fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false)
- fbx_simple_property(Intensity, float, 100.0f)
- fbx_simple_property(InnerAngle, float, 0.0f)
- fbx_simple_property(OuterAngle, float, 45.0f)
- fbx_simple_property(Fog, int, 50)
- fbx_simple_enum_property(DecayType, Decay, 2)
- fbx_simple_property(DecayStart, float, 1.0f)
- fbx_simple_property(FileName, std::string, "")
-
- fbx_simple_property(EnableNearAttenuation, bool, false)
- fbx_simple_property(NearAttenuationStart, float, 0.0f)
- fbx_simple_property(NearAttenuationEnd, float, 0.0f)
- fbx_simple_property(EnableFarAttenuation, bool, false)
- fbx_simple_property(FarAttenuationStart, float, 0.0f)
- fbx_simple_property(FarAttenuationEnd, float, 0.0f)
-
- fbx_simple_property(CastShadows, bool, true)
- fbx_simple_property(ShadowColor, aiVector3D, aiVector3D(0,0,0))
-
- fbx_simple_property(AreaLightShape, int, 0)
-
- fbx_simple_property(LeftBarnDoor, float, 20.0f)
- fbx_simple_property(RightBarnDoor, float, 20.0f)
- fbx_simple_property(TopBarnDoor, float, 20.0f)
- fbx_simple_property(BottomBarnDoor, float, 20.0f)
- fbx_simple_property(EnableBarnDoor, bool, true)
-};
-
-/** DOM base class for FBX models (even though its semantics are more "node" than "model" */
-class Model : public Object {
-public:
- enum RotOrder {
- RotOrder_EulerXYZ = 0,
- RotOrder_EulerXZY,
- RotOrder_EulerYZX,
- RotOrder_EulerYXZ,
- RotOrder_EulerZXY,
- RotOrder_EulerZYX,
-
- RotOrder_SphericXYZ,
-
- RotOrder_MAX // end-of-enum sentinel
- };
-
- enum TransformInheritance {
- TransformInheritance_RrSs = 0,
- TransformInheritance_RSrs,
- TransformInheritance_Rrs,
-
- TransformInheritance_MAX // end-of-enum sentinel
- };
-
- Model(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~Model();
-
- fbx_simple_property(QuaternionInterpolate, int, 0)
-
- fbx_simple_property(RotationOffset, aiVector3D, aiVector3D())
- fbx_simple_property(RotationPivot, aiVector3D, aiVector3D())
- fbx_simple_property(ScalingOffset, aiVector3D, aiVector3D())
- fbx_simple_property(ScalingPivot, aiVector3D, aiVector3D())
- fbx_simple_property(TranslationActive, bool, false)
-
- fbx_simple_property(TranslationMin, aiVector3D, aiVector3D())
- fbx_simple_property(TranslationMax, aiVector3D, aiVector3D())
-
- fbx_simple_property(TranslationMinX, bool, false)
- fbx_simple_property(TranslationMaxX, bool, false)
- fbx_simple_property(TranslationMinY, bool, false)
- fbx_simple_property(TranslationMaxY, bool, false)
- fbx_simple_property(TranslationMinZ, bool, false)
- fbx_simple_property(TranslationMaxZ, bool, false)
-
- fbx_simple_enum_property(RotationOrder, RotOrder, 0)
- fbx_simple_property(RotationSpaceForLimitOnly, bool, false)
- fbx_simple_property(RotationStiffnessX, float, 0.0f)
- fbx_simple_property(RotationStiffnessY, float, 0.0f)
- fbx_simple_property(RotationStiffnessZ, float, 0.0f)
- fbx_simple_property(AxisLen, float, 0.0f)
-
- fbx_simple_property(PreRotation, aiVector3D, aiVector3D())
- fbx_simple_property(PostRotation, aiVector3D, aiVector3D())
- fbx_simple_property(RotationActive, bool, false)
-
- fbx_simple_property(RotationMin, aiVector3D, aiVector3D())
- fbx_simple_property(RotationMax, aiVector3D, aiVector3D())
-
- fbx_simple_property(RotationMinX, bool, false)
- fbx_simple_property(RotationMaxX, bool, false)
- fbx_simple_property(RotationMinY, bool, false)
- fbx_simple_property(RotationMaxY, bool, false)
- fbx_simple_property(RotationMinZ, bool, false)
- fbx_simple_property(RotationMaxZ, bool, false)
- fbx_simple_enum_property(InheritType, TransformInheritance, 0)
-
- fbx_simple_property(ScalingActive, bool, false)
- fbx_simple_property(ScalingMin, aiVector3D, aiVector3D())
- fbx_simple_property(ScalingMax, aiVector3D, aiVector3D(1.f,1.f,1.f))
- fbx_simple_property(ScalingMinX, bool, false)
- fbx_simple_property(ScalingMaxX, bool, false)
- fbx_simple_property(ScalingMinY, bool, false)
- fbx_simple_property(ScalingMaxY, bool, false)
- fbx_simple_property(ScalingMinZ, bool, false)
- fbx_simple_property(ScalingMaxZ, bool, false)
-
- fbx_simple_property(GeometricTranslation, aiVector3D, aiVector3D())
- fbx_simple_property(GeometricRotation, aiVector3D, aiVector3D())
- fbx_simple_property(GeometricScaling, aiVector3D, aiVector3D(1.f, 1.f, 1.f))
-
- fbx_simple_property(MinDampRangeX, float, 0.0f)
- fbx_simple_property(MinDampRangeY, float, 0.0f)
- fbx_simple_property(MinDampRangeZ, float, 0.0f)
- fbx_simple_property(MaxDampRangeX, float, 0.0f)
- fbx_simple_property(MaxDampRangeY, float, 0.0f)
- fbx_simple_property(MaxDampRangeZ, float, 0.0f)
-
- fbx_simple_property(MinDampStrengthX, float, 0.0f)
- fbx_simple_property(MinDampStrengthY, float, 0.0f)
- fbx_simple_property(MinDampStrengthZ, float, 0.0f)
- fbx_simple_property(MaxDampStrengthX, float, 0.0f)
- fbx_simple_property(MaxDampStrengthY, float, 0.0f)
- fbx_simple_property(MaxDampStrengthZ, float, 0.0f)
-
- fbx_simple_property(PreferredAngleX, float, 0.0f)
- fbx_simple_property(PreferredAngleY, float, 0.0f)
- fbx_simple_property(PreferredAngleZ, float, 0.0f)
-
- fbx_simple_property(Show, bool, true)
- fbx_simple_property(LODBox, bool, false)
- fbx_simple_property(Freeze, bool, false)
-
- const std::string& Shading() const {
- return shading;
- }
-
- const std::string& Culling() const {
- return culling;
- }
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
- /** Get material links */
- const std::vector<const Material*>& GetMaterials() const {
- return materials;
- }
-
- /** Get geometry links */
- const std::vector<const Geometry*>& GetGeometry() const {
- return geometry;
- }
-
- /** Get node attachments */
- const std::vector<const NodeAttribute*>& GetAttributes() const {
- return attributes;
- }
-
- /** convenience method to check if the node has a Null node marker */
- bool IsNull() const;
-
-private:
- void ResolveLinks(const Element& element, const Document& doc);
-
-private:
- std::vector<const Material*> materials;
- std::vector<const Geometry*> geometry;
- std::vector<const NodeAttribute*> attributes;
-
- std::string shading;
- std::string culling;
- std::shared_ptr<const PropertyTable> props;
-};
-
-/** DOM class for generic FBX textures */
-class Texture : public Object {
-public:
- Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~Texture();
-
- const std::string& Type() const {
- return type;
- }
-
- const std::string& FileName() const {
- return fileName;
- }
-
- const std::string& RelativeFilename() const {
- return relativeFileName;
- }
-
- const std::string& AlphaSource() const {
- return alphaSource;
- }
-
- const aiVector2D& UVTranslation() const {
- return uvTrans;
- }
-
- const aiVector2D& UVScaling() const {
- return uvScaling;
- }
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
- // return a 4-tuple
- const unsigned int* Crop() const {
- return crop;
- }
-
- const Video* Media() const {
- return media;
- }
-
-private:
- aiVector2D uvTrans;
- aiVector2D uvScaling;
-
- std::string type;
- std::string relativeFileName;
- std::string fileName;
- std::string alphaSource;
- std::shared_ptr<const PropertyTable> props;
-
- unsigned int crop[4];
-
- const Video* media;
-};
-
-/** DOM class for layered FBX textures */
-class LayeredTexture : public Object {
-public:
- LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name);
- virtual ~LayeredTexture();
-
- // Can only be called after construction of the layered texture object due to construction flag.
- void fillTexture(const Document& doc);
-
- enum BlendMode {
- BlendMode_Translucent,
- BlendMode_Additive,
- BlendMode_Modulate,
- BlendMode_Modulate2,
- BlendMode_Over,
- BlendMode_Normal,
- BlendMode_Dissolve,
- BlendMode_Darken,
- BlendMode_ColorBurn,
- BlendMode_LinearBurn,
- BlendMode_DarkerColor,
- BlendMode_Lighten,
- BlendMode_Screen,
- BlendMode_ColorDodge,
- BlendMode_LinearDodge,
- BlendMode_LighterColor,
- BlendMode_SoftLight,
- BlendMode_HardLight,
- BlendMode_VividLight,
- BlendMode_LinearLight,
- BlendMode_PinLight,
- BlendMode_HardMix,
- BlendMode_Difference,
- BlendMode_Exclusion,
- BlendMode_Subtract,
- BlendMode_Divide,
- BlendMode_Hue,
- BlendMode_Saturation,
- BlendMode_Color,
- BlendMode_Luminosity,
- BlendMode_Overlay,
- BlendMode_BlendModeCount
- };
-
- const Texture* getTexture(int index=0) const
- {
- return textures[index];
-
- }
- int textureCount() const {
- return static_cast<int>(textures.size());
- }
- BlendMode GetBlendMode() const
- {
- return blendMode;
- }
- float Alpha()
- {
- return alpha;
- }
-private:
- std::vector<const Texture*> textures;
- BlendMode blendMode;
- float alpha;
-};
-
-typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap;
-typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap;
-
-
-/** DOM class for generic FBX videos */
-class Video : public Object {
-public:
- Video(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~Video();
-
- const std::string& Type() const {
- return type;
- }
-
- const std::string& FileName() const {
- return fileName;
- }
-
- const std::string& RelativeFilename() const {
- return relativeFileName;
- }
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
- const uint8_t* Content() const {
- ai_assert(content);
- return content;
- }
-
- uint64_t ContentLength() const {
- return contentLength;
- }
-
- uint8_t* RelinquishContent() {
- uint8_t* ptr = content;
- content = 0;
- return ptr;
- }
-
- bool operator==(const Video& other) const
- {
- return (
- type == other.type
- && relativeFileName == other.relativeFileName
- && fileName == other.fileName
- );
- }
-
- bool operator<(const Video& other) const
- {
- return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName);
- }
-
-private:
- std::string type;
- std::string relativeFileName;
- std::string fileName;
- std::shared_ptr<const PropertyTable> props;
-
- uint64_t contentLength;
- uint8_t* content;
-};
-
-/** DOM class for generic FBX materials */
-class Material : public Object {
-public:
- Material(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~Material();
-
- const std::string& GetShadingModel() const {
- return shading;
- }
-
- bool IsMultilayer() const {
- return multilayer;
- }
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
- const TextureMap& Textures() const {
- return textures;
- }
-
- const LayeredTextureMap& LayeredTextures() const {
- return layeredTextures;
- }
-
-private:
- std::string shading;
- bool multilayer;
- std::shared_ptr<const PropertyTable> props;
-
- TextureMap textures;
- LayeredTextureMap layeredTextures;
-};
-
-typedef std::vector<int64_t> KeyTimeList;
-typedef std::vector<float> KeyValueList;
-
-/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */
-class AnimationCurve : public Object {
-public:
- AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc);
- virtual ~AnimationCurve();
-
- /** get list of keyframe positions (time).
- * Invariant: |GetKeys()| > 0 */
- const KeyTimeList& GetKeys() const {
- return keys;
- }
-
- /** get list of keyframe values.
- * Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/
- const KeyValueList& GetValues() const {
- return values;
- }
-
- const std::vector<float>& GetAttributes() const {
- return attributes;
- }
-
- const std::vector<unsigned int>& GetFlags() const {
- return flags;
- }
-
-private:
- KeyTimeList keys;
- KeyValueList values;
- std::vector<float> attributes;
- std::vector<unsigned int> flags;
-};
-
-// property-name -> animation curve
-typedef std::map<std::string, const AnimationCurve*> AnimationCurveMap;
-
-/** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */
-class AnimationCurveNode : public Object {
-public:
- /* the optional white list specifies a list of property names for which the caller
- wants animations for. If the curve node does not match one of these, std::range_error
- will be thrown. */
- 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);
-
- virtual ~AnimationCurveNode();
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
-
- const AnimationCurveMap& Curves() const;
-
- /** Object the curve is assigned to, this can be NULL if the
- * target object has no DOM representation or could not
- * be read for other reasons.*/
- const Object* Target() const {
- return target;
- }
-
- const Model* TargetAsModel() const {
- return dynamic_cast<const Model*>(target);
- }
-
- const NodeAttribute* TargetAsNodeAttribute() const {
- return dynamic_cast<const NodeAttribute*>(target);
- }
-
- /** Property of Target() that is being animated*/
- const std::string& TargetProperty() const {
- return prop;
- }
-
-private:
- const Object* target;
- std::shared_ptr<const PropertyTable> props;
- mutable AnimationCurveMap curves;
-
- std::string prop;
- const Document& doc;
-};
-
-typedef std::vector<const AnimationCurveNode*> AnimationCurveNodeList;
-
-/** Represents a FBX animation layer (i.e. a list of node animations) */
-class AnimationLayer : public Object {
-public:
- AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc);
- virtual ~AnimationLayer();
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
- /* the optional white list specifies a list of property names for which the caller
- wants animations for. Curves not matching this list will not be added to the
- animation layer. */
- AnimationCurveNodeList Nodes(const char* const * target_prop_whitelist = nullptr, size_t whitelist_size = 0) const;
-
-private:
- std::shared_ptr<const PropertyTable> props;
- const Document& doc;
-};
-
-typedef std::vector<const AnimationLayer*> AnimationLayerList;
-
-/** Represents a FBX animation stack (i.e. a list of animation layers) */
-class AnimationStack : public Object {
-public:
- AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc);
- virtual ~AnimationStack();
-
- fbx_simple_property(LocalStart, int64_t, 0L)
- fbx_simple_property(LocalStop, int64_t, 0L)
- fbx_simple_property(ReferenceStart, int64_t, 0L)
- fbx_simple_property(ReferenceStop, int64_t, 0L)
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
- const AnimationLayerList& Layers() const {
- return layers;
- }
-
-private:
- std::shared_ptr<const PropertyTable> props;
- AnimationLayerList layers;
-};
-
-
-/** DOM class for deformers */
-class Deformer : public Object {
-public:
- Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name);
- virtual ~Deformer();
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
-private:
- std::shared_ptr<const PropertyTable> props;
-};
-
-typedef std::vector<float> WeightArray;
-typedef std::vector<unsigned int> WeightIndexArray;
-
-
-/** DOM class for BlendShapeChannel deformers */
-class BlendShapeChannel : public Deformer {
-public:
- BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~BlendShapeChannel();
-
- float DeformPercent() const {
- return percent;
- }
-
- const WeightArray& GetFullWeights() const {
- return fullWeights;
- }
-
- const std::vector<const ShapeGeometry*>& GetShapeGeometries() const {
- return shapeGeometries;
- }
-
-private:
- float percent;
- WeightArray fullWeights;
- std::vector<const ShapeGeometry*> shapeGeometries;
-};
-
-/** DOM class for BlendShape deformers */
-class BlendShape : public Deformer {
-public:
- BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~BlendShape();
-
- const std::vector<const BlendShapeChannel*>& BlendShapeChannels() const {
- return blendShapeChannels;
- }
-
-private:
- std::vector<const BlendShapeChannel*> blendShapeChannels;
-};
-
-/** DOM class for skin deformer clusters (aka sub-deformers) */
-class Cluster : public Deformer {
-public:
- Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~Cluster();
-
- /** get the list of deformer weights associated with this cluster.
- * Use #GetIndices() to get the associated vertices. Both arrays
- * have the same size (and may also be empty). */
- const WeightArray& GetWeights() const {
- return weights;
- }
-
- /** get indices into the vertex data of the geometry associated
- * with this cluster. Use #GetWeights() to get the associated weights.
- * Both arrays have the same size (and may also be empty). */
- const WeightIndexArray& GetIndices() const {
- return indices;
- }
-
- /** */
- const aiMatrix4x4& Transform() const {
- return transform;
- }
-
- const aiMatrix4x4& TransformLink() const {
- return transformLink;
- }
-
- const Model* TargetNode() const {
- return node;
- }
-
-private:
- WeightArray weights;
- WeightIndexArray indices;
-
- aiMatrix4x4 transform;
- aiMatrix4x4 transformLink;
-
- const Model* node;
-};
-
-/** DOM class for skin deformers */
-class Skin : public Deformer {
-public:
- Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-
- virtual ~Skin();
-
- float DeformAccuracy() const {
- return accuracy;
- }
-
- const std::vector<const Cluster*>& Clusters() const {
- return clusters;
- }
-
-private:
- float accuracy;
- std::vector<const Cluster*> clusters;
-};
-
-/** Represents a link between two FBX objects. */
-class Connection {
-public:
- Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, const Document& doc);
-
- ~Connection();
-
- // note: a connection ensures that the source and dest objects exist, but
- // not that they have DOM representations, so the return value of one of
- // these functions can still be NULL.
- const Object* SourceObject() const;
- const Object* DestinationObject() const;
-
- // these, however, are always guaranteed to be valid
- LazyObject& LazySourceObject() const;
- LazyObject& LazyDestinationObject() const;
-
-
- /** return the name of the property the connection is attached to.
- * this is an empty string for object to object (OO) connections. */
- const std::string& PropertyName() const {
- return prop;
- }
-
- uint64_t InsertionOrder() const {
- return insertionOrder;
- }
-
- int CompareTo(const Connection* c) const {
- ai_assert( nullptr != c );
-
- // note: can't subtract because this would overflow uint64_t
- if(InsertionOrder() > c->InsertionOrder()) {
- return 1;
- }
- else if(InsertionOrder() < c->InsertionOrder()) {
- return -1;
- }
- return 0;
- }
-
- bool Compare(const Connection* c) const {
- ai_assert( nullptr != c );
-
- return InsertionOrder() < c->InsertionOrder();
- }
-
-public:
- uint64_t insertionOrder;
- const std::string prop;
-
- uint64_t src, dest;
- const Document& doc;
-};
-
-// XXX again, unique_ptr would be useful. shared_ptr is too
-// bloated since the objects have a well-defined single owner
-// during their entire lifetime (Document). FBX files have
-// up to many thousands of objects (most of which we never use),
-// so the memory overhead for them should be kept at a minimum.
-typedef std::fbx_unordered_map<uint64_t, LazyObject*> ObjectMap;
-typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap;
-
-typedef std::fbx_unordered_multimap<uint64_t, const Connection*> ConnectionMap;
-
-/** DOM class for global document settings, a single instance per document can
- * be accessed via Document.Globals(). */
-class FileGlobalSettings {
-public:
- FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props);
-
- ~FileGlobalSettings();
-
- const PropertyTable& Props() const {
- ai_assert(props.get());
- return *props.get();
- }
-
- const Document& GetDocument() const {
- return doc;
- }
-
- fbx_simple_property(UpAxis, int, 1)
- fbx_simple_property(UpAxisSign, int, 1)
- fbx_simple_property(FrontAxis, int, 2)
- fbx_simple_property(FrontAxisSign, int, 1)
- fbx_simple_property(CoordAxis, int, 0)
- fbx_simple_property(CoordAxisSign, int, 1)
- fbx_simple_property(OriginalUpAxis, int, 0)
- fbx_simple_property(OriginalUpAxisSign, int, 1)
- fbx_simple_property(UnitScaleFactor, float, 1)
- fbx_simple_property(OriginalUnitScaleFactor, float, 1)
- fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0))
- fbx_simple_property(DefaultCamera, std::string, "")
-
-
- enum FrameRate {
- FrameRate_DEFAULT = 0,
- FrameRate_120 = 1,
- FrameRate_100 = 2,
- FrameRate_60 = 3,
- FrameRate_50 = 4,
- FrameRate_48 = 5,
- FrameRate_30 = 6,
- FrameRate_30_DROP = 7,
- FrameRate_NTSC_DROP_FRAME = 8,
- FrameRate_NTSC_FULL_FRAME = 9,
- FrameRate_PAL = 10,
- FrameRate_CINEMA = 11,
- FrameRate_1000 = 12,
- FrameRate_CINEMA_ND = 13,
- FrameRate_CUSTOM = 14,
-
- FrameRate_MAX// end-of-enum sentinel
- };
-
- fbx_simple_enum_property(TimeMode, FrameRate, FrameRate_DEFAULT)
- fbx_simple_property(TimeSpanStart, uint64_t, 0L)
- fbx_simple_property(TimeSpanStop, uint64_t, 0L)
- fbx_simple_property(CustomFrameRate, float, -1.0f)
-
-private:
- std::shared_ptr<const PropertyTable> props;
- const Document& doc;
-};
-
-/** DOM root for a FBX file */
-class Document {
-public:
- Document(const Parser& parser, const ImportSettings& settings);
-
- ~Document();
-
- LazyObject* GetObject(uint64_t id) const;
-
- bool IsBinary() const {
- return parser.IsBinary();
- }
-
- unsigned int FBXVersion() const {
- return fbxVersion;
- }
-
- const std::string& Creator() const {
- return creator;
- }
-
- // elements (in this order): Year, Month, Day, Hour, Second, Millisecond
- const unsigned int* CreationTimeStamp() const {
- return creationTimeStamp;
- }
-
- const FileGlobalSettings& GlobalSettings() const {
- ai_assert(globals.get());
- return *globals.get();
- }
-
- const PropertyTemplateMap& Templates() const {
- return templates;
- }
-
- const ObjectMap& Objects() const {
- return objects;
- }
-
- const ImportSettings& Settings() const {
- return settings;
- }
-
- const ConnectionMap& ConnectionsBySource() const {
- return src_connections;
- }
-
- const ConnectionMap& ConnectionsByDestination() const {
- return dest_connections;
- }
-
- // note: the implicit rule in all DOM classes is to always resolve
- // from destination to source (since the FBX object hierarchy is,
- // with very few exceptions, a DAG, this avoids cycles). In all
- // cases that may involve back-facing edges in the object graph,
- // use LazyObject::IsBeingConstructed() to check.
-
- std::vector<const Connection*> GetConnectionsBySourceSequenced(uint64_t source) const;
- std::vector<const Connection*> GetConnectionsByDestinationSequenced(uint64_t dest) const;
-
- std::vector<const Connection*> GetConnectionsBySourceSequenced(uint64_t source, const char* classname) const;
- std::vector<const Connection*> GetConnectionsByDestinationSequenced(uint64_t dest, const char* classname) const;
-
- std::vector<const Connection*> GetConnectionsBySourceSequenced(uint64_t source,
- const char* const* classnames, size_t count) const;
- std::vector<const Connection*> GetConnectionsByDestinationSequenced(uint64_t dest,
- const char* const* classnames,
- size_t count) const;
-
- const std::vector<const AnimationStack*>& AnimationStacks() const;
-
-private:
- std::vector<const Connection*> GetConnectionsSequenced(uint64_t id, const ConnectionMap&) const;
- std::vector<const Connection*> GetConnectionsSequenced(uint64_t id, bool is_src,
- const ConnectionMap&,
- const char* const* classnames,
- size_t count) const;
- void ReadHeader();
- void ReadObjects();
- void ReadPropertyTemplates();
- void ReadConnections();
- void ReadGlobalSettings();
-
-private:
- const ImportSettings& settings;
-
- ObjectMap objects;
- const Parser& parser;
-
- PropertyTemplateMap templates;
- ConnectionMap src_connections;
- ConnectionMap dest_connections;
-
- unsigned int fbxVersion;
- std::string creator;
- unsigned int creationTimeStamp[7];
-
- std::vector<uint64_t> animationStacks;
- mutable std::vector<const AnimationStack*> animationStacksResolved;
-
- std::unique_ptr<FileGlobalSettings> globals;
-};
-
-} // Namespace FBX
-} // Namespace Assimp
-
-namespace std
-{
- template <>
- struct hash<const Assimp::FBX::Video>
- {
- std::size_t operator()(const Assimp::FBX::Video& video) const
- {
- using std::size_t;
- using std::hash;
- using std::string;
-
- size_t res = 17;
- res = res * 31 + hash<string>()(video.Name());
- res = res * 31 + hash<string>()(video.RelativeFilename());
- res = res * 31 + hash<string>()(video.Type());
-
- return res;
- }
- };
-}
-
-#endif // INCLUDED_AI_FBX_DOCUMENT_H
diff --git a/thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp b/thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp
deleted file mode 100644
index f84691479a..0000000000
--- a/thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXDocumentUtil.cpp
- * @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include "FBXParser.h"
-#include "FBXDocument.h"
-#include "FBXUtil.h"
-#include "FBXDocumentUtil.h"
-#include "FBXProperties.h"
-
-
-namespace Assimp {
-namespace FBX {
-namespace Util {
-
-// ------------------------------------------------------------------------------------------------
-// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
-void DOMError(const std::string& message, const Token& token)
-{
- throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token));
-}
-
-// ------------------------------------------------------------------------------------------------
-void DOMError(const std::string& message, const Element* element /*= NULL*/)
-{
- if(element) {
- DOMError(message,element->KeyToken());
- }
- throw DeadlyImportError("FBX-DOM " + message);
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// print warning, do return
-void DOMWarning(const std::string& message, const Token& token)
-{
- if(DefaultLogger::get()) {
- ASSIMP_LOG_WARN(Util::AddTokenText("FBX-DOM",message,&token));
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
-{
- if(element) {
- DOMWarning(message,element->KeyToken());
- return;
- }
- if(DefaultLogger::get()) {
- ASSIMP_LOG_WARN("FBX-DOM: " + message);
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// fetch a property table and the corresponding property template
-std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
- const std::string& templateName,
- const Element &element,
- const Scope& sc,
- bool no_warn /*= false*/)
-{
- const Element* const Properties70 = sc["Properties70"];
- std::shared_ptr<const PropertyTable> templateProps = std::shared_ptr<const PropertyTable>(
- static_cast<const PropertyTable*>(NULL));
-
- if(templateName.length()) {
- PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
- if(it != doc.Templates().end()) {
- templateProps = (*it).second;
- }
- }
-
- if(!Properties70 || !Properties70->Compound()) {
- if(!no_warn) {
- DOMWarning("property table (Properties70) not found",&element);
- }
- if(templateProps) {
- return templateProps;
- }
- else {
- return std::make_shared<const PropertyTable>();
- }
- }
- return std::make_shared<const PropertyTable>(*Properties70,templateProps);
-}
-} // !Util
-} // !FBX
-} // !Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXDocumentUtil.h b/thirdparty/assimp/code/FBX/FBXDocumentUtil.h
deleted file mode 100644
index 2450109e59..0000000000
--- a/thirdparty/assimp/code/FBX/FBXDocumentUtil.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2012, 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 FBXDocumentUtil.h
- * @brief FBX internal utilities used by the DOM reading code
- */
-#ifndef INCLUDED_AI_FBX_DOCUMENT_UTIL_H
-#define INCLUDED_AI_FBX_DOCUMENT_UTIL_H
-
-#include <assimp/defs.h>
-#include <string>
-#include <memory>
-#include "FBXDocument.h"
-
-struct Token;
-struct Element;
-
-namespace Assimp {
-namespace FBX {
-namespace Util {
-
-/* DOM/Parse error reporting - does not return */
-AI_WONT_RETURN void DOMError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
-AI_WONT_RETURN void DOMError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX;
-
-// does return
-void DOMWarning(const std::string& message, const Token& token);
-void DOMWarning(const std::string& message, const Element* element = NULL);
-
-
-// fetch a property table and the corresponding property template
-std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
- const std::string& templateName,
- const Element &element,
- const Scope& sc,
- bool no_warn = false);
-
-// ------------------------------------------------------------------------------------------------
-template <typename T>
-inline
-const T* ProcessSimpleConnection(const Connection& con,
- bool is_object_property_conn,
- const char* name,
- const Element& element,
- const char** propNameOut = nullptr)
-{
- if (is_object_property_conn && !con.PropertyName().length()) {
- DOMWarning("expected incoming " + std::string(name) +
- " link to be an object-object connection, ignoring",
- &element
- );
- return nullptr;
- }
- else if (!is_object_property_conn && con.PropertyName().length()) {
- DOMWarning("expected incoming " + std::string(name) +
- " link to be an object-property connection, ignoring",
- &element
- );
- return nullptr;
- }
-
- if(is_object_property_conn && propNameOut) {
- // note: this is ok, the return value of PropertyValue() is guaranteed to
- // remain valid and unchanged as long as the document exists.
- *propNameOut = con.PropertyName().c_str();
- }
-
- const Object* const ob = con.SourceObject();
- if(!ob) {
- DOMWarning("failed to read source object for incoming " + std::string(name) +
- " link, ignoring",
- &element);
- return nullptr;
- }
-
- return dynamic_cast<const T*>(ob);
-}
-
-} //!Util
-} //!FBX
-} //!Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXExportNode.cpp b/thirdparty/assimp/code/FBX/FBXExportNode.cpp
deleted file mode 100644
index 06c89cee46..0000000000
--- a/thirdparty/assimp/code/FBX/FBXExportNode.cpp
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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.
-
-----------------------------------------------------------------------
-*/
-#ifndef ASSIMP_BUILD_NO_EXPORT
-#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#include "FBXExportNode.h"
-#include "FBXCommon.h"
-
-#include <assimp/StreamWriter.h> // StreamWriterLE
-#include <assimp/Exceptional.h> // DeadlyExportError
-#include <assimp/ai_assert.h>
-#include <assimp/StringUtils.h> // ai_snprintf
-
-#include <string>
-#include <ostream>
-#include <sstream> // ostringstream
-#include <memory> // shared_ptr
-
-namespace Assimp {
-// AddP70<type> helpers... there's no usable pattern here,
-// so all are defined as separate functions.
-// Even "animatable" properties are often completely different
-// from the standard (nonanimated) property definition,
-// so they are specified with an 'A' suffix.
-
-void FBX::Node::AddP70int(
- const std::string& name, int32_t value
-) {
- FBX::Node n("P");
- n.AddProperties(name, "int", "Integer", "", value);
- AddChild(n);
-}
-
-void FBX::Node::AddP70bool(
- const std::string& name, bool value
-) {
- FBX::Node n("P");
- n.AddProperties(name, "bool", "", "", int32_t(value));
- AddChild(n);
-}
-
-void FBX::Node::AddP70double(
- const std::string& name, double value
-) {
- FBX::Node n("P");
- n.AddProperties(name, "double", "Number", "", value);
- AddChild(n);
-}
-
-void FBX::Node::AddP70numberA(
- const std::string& name, double value
-) {
- FBX::Node n("P");
- n.AddProperties(name, "Number", "", "A", value);
- AddChild(n);
-}
-
-void FBX::Node::AddP70color(
- const std::string& name, double r, double g, double b
-) {
- FBX::Node n("P");
- n.AddProperties(name, "ColorRGB", "Color", "", r, g, b);
- AddChild(n);
-}
-
-void FBX::Node::AddP70colorA(
- const std::string& name, double r, double g, double b
-) {
- FBX::Node n("P");
- n.AddProperties(name, "Color", "", "A", r, g, b);
- AddChild(n);
-}
-
-void FBX::Node::AddP70vector(
- const std::string& name, double x, double y, double z
-) {
- FBX::Node n("P");
- n.AddProperties(name, "Vector3D", "Vector", "", x, y, z);
- AddChild(n);
-}
-
-void FBX::Node::AddP70vectorA(
- const std::string& name, double x, double y, double z
-) {
- FBX::Node n("P");
- n.AddProperties(name, "Vector", "", "A", x, y, z);
- AddChild(n);
-}
-
-void FBX::Node::AddP70string(
- const std::string& name, const std::string& value
-) {
- FBX::Node n("P");
- n.AddProperties(name, "KString", "", "", value);
- AddChild(n);
-}
-
-void FBX::Node::AddP70enum(
- const std::string& name, int32_t value
-) {
- FBX::Node n("P");
- n.AddProperties(name, "enum", "", "", value);
- AddChild(n);
-}
-
-void FBX::Node::AddP70time(
- const std::string& name, int64_t value
-) {
- FBX::Node n("P");
- n.AddProperties(name, "KTime", "Time", "", value);
- AddChild(n);
-}
-
-
-// public member functions for writing nodes to stream
-
-void FBX::Node::Dump(
- std::shared_ptr<Assimp::IOStream> outfile,
- bool binary, int indent
-) {
- if (binary) {
- Assimp::StreamWriterLE outstream(outfile);
- DumpBinary(outstream);
- } else {
- std::ostringstream ss;
- DumpAscii(ss, indent);
- std::string s = ss.str();
- outfile->Write(s.c_str(), s.size(), 1);
- }
-}
-
-void FBX::Node::Dump(
- Assimp::StreamWriterLE &outstream,
- bool binary, int indent
-) {
- if (binary) {
- DumpBinary(outstream);
- } else {
- std::ostringstream ss;
- DumpAscii(ss, indent);
- outstream.PutString(ss.str());
- }
-}
-
-
-// public member functions for low-level writing
-
-void FBX::Node::Begin(
- Assimp::StreamWriterLE &s,
- bool binary, int indent
-) {
- if (binary) {
- BeginBinary(s);
- } else {
- // assume we're at the correct place to start already
- (void)indent;
- std::ostringstream ss;
- BeginAscii(ss, indent);
- s.PutString(ss.str());
- }
-}
-
-void FBX::Node::DumpProperties(
- Assimp::StreamWriterLE& s,
- bool binary, int indent
-) {
- if (binary) {
- DumpPropertiesBinary(s);
- } else {
- std::ostringstream ss;
- DumpPropertiesAscii(ss, indent);
- s.PutString(ss.str());
- }
-}
-
-void FBX::Node::EndProperties(
- Assimp::StreamWriterLE &s,
- bool binary, int indent
-) {
- EndProperties(s, binary, indent, properties.size());
-}
-
-void FBX::Node::EndProperties(
- Assimp::StreamWriterLE &s,
- bool binary, int indent,
- size_t num_properties
-) {
- if (binary) {
- EndPropertiesBinary(s, num_properties);
- } else {
- // nothing to do
- (void)indent;
- }
-}
-
-void FBX::Node::BeginChildren(
- Assimp::StreamWriterLE &s,
- bool binary, int indent
-) {
- if (binary) {
- // nothing to do
- } else {
- std::ostringstream ss;
- BeginChildrenAscii(ss, indent);
- s.PutString(ss.str());
- }
-}
-
-void FBX::Node::DumpChildren(
- Assimp::StreamWriterLE& s,
- bool binary, int indent
-) {
- if (binary) {
- DumpChildrenBinary(s);
- } else {
- std::ostringstream ss;
- DumpChildrenAscii(ss, indent);
- if (ss.tellp() > 0)
- s.PutString(ss.str());
- }
-}
-
-void FBX::Node::End(
- Assimp::StreamWriterLE &s,
- bool binary, int indent,
- bool has_children
-) {
- if (binary) {
- EndBinary(s, has_children);
- } else {
- std::ostringstream ss;
- EndAscii(ss, indent, has_children);
- if (ss.tellp() > 0)
- s.PutString(ss.str());
- }
-}
-
-
-// public member functions for writing to binary fbx
-
-void FBX::Node::DumpBinary(Assimp::StreamWriterLE &s)
-{
- // write header section (with placeholders for some things)
- BeginBinary(s);
-
- // write properties
- DumpPropertiesBinary(s);
-
- // go back and fill in property related placeholders
- EndPropertiesBinary(s, properties.size());
-
- // write children
- DumpChildrenBinary(s);
-
- // finish, filling in end offset placeholder
- EndBinary(s, force_has_children || !children.empty());
-}
-
-
-// public member functions for writing to ascii fbx
-
-void FBX::Node::DumpAscii(std::ostream &s, int indent)
-{
- // write name
- BeginAscii(s, indent);
-
- // write properties
- DumpPropertiesAscii(s, indent);
-
- if (force_has_children || !children.empty()) {
- // begin children (with a '{')
- BeginChildrenAscii(s, indent + 1);
- // write children
- DumpChildrenAscii(s, indent + 1);
- }
-
- // finish (also closing the children bracket '}')
- EndAscii(s, indent, force_has_children || !children.empty());
-}
-
-
-// private member functions for low-level writing to fbx
-
-void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s)
-{
- // remember start pos so we can come back and write the end pos
- this->start_pos = s.Tell();
-
- // placeholders for end pos and property section info
- s.PutU4(0); // end pos
- s.PutU4(0); // number of properties
- s.PutU4(0); // total property section length
-
- // node name
- s.PutU1(uint8_t(name.size())); // length of node name
- s.PutString(name); // node name as raw bytes
-
- // property data comes after here
- this->property_start = s.Tell();
-}
-
-void FBX::Node::DumpPropertiesBinary(Assimp::StreamWriterLE& s)
-{
- for (auto &p : properties) {
- p.DumpBinary(s);
- }
-}
-
-void FBX::Node::EndPropertiesBinary(
- Assimp::StreamWriterLE &s,
- size_t num_properties
-) {
- if (num_properties == 0) { return; }
- size_t pos = s.Tell();
- ai_assert(pos > property_start);
- size_t property_section_size = pos - property_start;
- s.Seek(start_pos + 4);
- s.PutU4(uint32_t(num_properties));
- s.PutU4(uint32_t(property_section_size));
- s.Seek(pos);
-}
-
-void FBX::Node::DumpChildrenBinary(Assimp::StreamWriterLE& s)
-{
- for (FBX::Node& child : children) {
- child.DumpBinary(s);
- }
-}
-
-void FBX::Node::EndBinary(
- Assimp::StreamWriterLE &s,
- bool has_children
-) {
- // if there were children, add a null record
- if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); }
-
- // now go back and write initial pos
- this->end_pos = s.Tell();
- s.Seek(start_pos);
- s.PutU4(uint32_t(end_pos));
- s.Seek(end_pos);
-}
-
-
-void FBX::Node::BeginAscii(std::ostream& s, int indent)
-{
- s << '\n';
- for (int i = 0; i < indent; ++i) { s << '\t'; }
- s << name << ": ";
-}
-
-void FBX::Node::DumpPropertiesAscii(std::ostream &s, int indent)
-{
- for (size_t i = 0; i < properties.size(); ++i) {
- if (i > 0) { s << ", "; }
- properties[i].DumpAscii(s, indent);
- }
-}
-
-void FBX::Node::BeginChildrenAscii(std::ostream& s, int indent)
-{
- // only call this if there are actually children
- s << " {";
- (void)indent;
-}
-
-void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent)
-{
- // children will need a lot of padding and corralling
- if (children.size() || force_has_children) {
- for (size_t i = 0; i < children.size(); ++i) {
- // no compression in ascii files, so skip this node if it exists
- if (children[i].name == "EncryptionType") { continue; }
- // the child can dump itself
- children[i].DumpAscii(s, indent);
- }
- }
-}
-
-void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children)
-{
- if (!has_children) { return; } // nothing to do
- s << '\n';
- for (int i = 0; i < indent; ++i) { s << '\t'; }
- s << "}";
-}
-
-// private helpers for static member functions
-
-// ascii property node from vector of doubles
-void FBX::Node::WritePropertyNodeAscii(
- const std::string& name,
- const std::vector<double>& v,
- Assimp::StreamWriterLE& s,
- int indent
-){
- char buffer[32];
- FBX::Node node(name);
- node.Begin(s, false, indent);
- std::string vsize = to_string(v.size());
- // *<size> {
- s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n");
- // indent + 1
- for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); }
- // a: value,value,value,...
- s.PutString("a: ");
- int count = 0;
- for (size_t i = 0; i < v.size(); ++i) {
- if (i > 0) { s.PutChar(','); }
- int len = ai_snprintf(buffer, sizeof(buffer), "%f", v[i]);
- count += len;
- if (count > 2048) { s.PutChar('\n'); count = 0; }
- if (len < 0 || len > 31) {
- // this should never happen
- throw DeadlyExportError("failed to convert double to string");
- }
- for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); }
- }
- // }
- s.PutChar('\n');
- for (int i = 0; i < indent; ++i) { s.PutChar('\t'); }
- s.PutChar('}'); s.PutChar(' ');
- node.End(s, false, indent, false);
-}
-
-// ascii property node from vector of int32_t
-void FBX::Node::WritePropertyNodeAscii(
- const std::string& name,
- const std::vector<int32_t>& v,
- Assimp::StreamWriterLE& s,
- int indent
-){
- char buffer[32];
- FBX::Node node(name);
- node.Begin(s, false, indent);
- std::string vsize = to_string(v.size());
- // *<size> {
- s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n");
- // indent + 1
- for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); }
- // a: value,value,value,...
- s.PutString("a: ");
- int count = 0;
- for (size_t i = 0; i < v.size(); ++i) {
- if (i > 0) { s.PutChar(','); }
- int len = ai_snprintf(buffer, sizeof(buffer), "%d", v[i]);
- count += len;
- if (count > 2048) { s.PutChar('\n'); count = 0; }
- if (len < 0 || len > 31) {
- // this should never happen
- throw DeadlyExportError("failed to convert double to string");
- }
- for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); }
- }
- // }
- s.PutChar('\n');
- for (int i = 0; i < indent; ++i) { s.PutChar('\t'); }
- s.PutChar('}'); s.PutChar(' ');
- node.End(s, false, indent, false);
-}
-
-// binary property node from vector of doubles
-// TODO: optional zip compression!
-void FBX::Node::WritePropertyNodeBinary(
- const std::string& name,
- const std::vector<double>& v,
- Assimp::StreamWriterLE& s
-){
- FBX::Node node(name);
- node.BeginBinary(s);
- s.PutU1('d');
- s.PutU4(uint32_t(v.size())); // number of elements
- s.PutU4(0); // no encoding (1 would be zip-compressed)
- s.PutU4(uint32_t(v.size()) * 8); // data size
- for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
- node.EndPropertiesBinary(s, 1);
- node.EndBinary(s, false);
-}
-
-// binary property node from vector of int32_t
-// TODO: optional zip compression!
-void FBX::Node::WritePropertyNodeBinary(
- const std::string& name,
- const std::vector<int32_t>& v,
- Assimp::StreamWriterLE& s
-){
- FBX::Node node(name);
- node.BeginBinary(s);
- s.PutU1('i');
- s.PutU4(uint32_t(v.size())); // number of elements
- s.PutU4(0); // no encoding (1 would be zip-compressed)
- s.PutU4(uint32_t(v.size()) * 4); // data size
- for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
- node.EndPropertiesBinary(s, 1);
- node.EndBinary(s, false);
-}
-
-// public static member functions
-
-// convenience function to create and write a property node,
-// holding a single property which is an array of values.
-// does not copy the data, so is efficient for large arrays.
-void FBX::Node::WritePropertyNode(
- const std::string& name,
- const std::vector<double>& v,
- Assimp::StreamWriterLE& s,
- bool binary, int indent
-){
- if (binary) {
- FBX::Node::WritePropertyNodeBinary(name, v, s);
- } else {
- FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
- }
-}
-
-// convenience function to create and write a property node,
-// holding a single property which is an array of values.
-// does not copy the data, so is efficient for large arrays.
-void FBX::Node::WritePropertyNode(
- const std::string& name,
- const std::vector<int32_t>& v,
- Assimp::StreamWriterLE& s,
- bool binary, int indent
-){
- if (binary) {
- FBX::Node::WritePropertyNodeBinary(name, v, s);
- } else {
- FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
- }
-}
-}
-#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
-#endif // ASSIMP_BUILD_NO_EXPORT
diff --git a/thirdparty/assimp/code/FBX/FBXExportNode.h b/thirdparty/assimp/code/FBX/FBXExportNode.h
deleted file mode 100644
index ef3bc781a4..0000000000
--- a/thirdparty/assimp/code/FBX/FBXExportNode.h
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXExportNode.h
-* Declares the FBX::Node helper class for fbx export.
-*/
-#ifndef AI_FBXEXPORTNODE_H_INC
-#define AI_FBXEXPORTNODE_H_INC
-
-#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#include "FBXExportProperty.h"
-
-#include <assimp/StreamWriter.h> // StreamWriterLE
-
-#include <string>
-#include <vector>
-
-namespace Assimp {
-namespace FBX {
- class Node;
-}
-
-class FBX::Node {
-public:
- // TODO: accessors
- std::string name; // node name
- std::vector<FBX::FBXExportProperty> properties; // node properties
- std::vector<FBX::Node> children; // child nodes
-
- // some nodes always pretend they have children...
- bool force_has_children = false;
-
-public: // constructors
- /// The default class constructor.
- Node() = default;
-
- /// The class constructor with the name.
- Node(const std::string& n)
- : name(n)
- , properties()
- , children()
- , force_has_children( false ) {
- // empty
- }
-
- // convenience template to construct with properties directly
- template <typename... More>
- Node(const std::string& n, const More... more)
- : name(n)
- , properties()
- , children()
- , force_has_children(false) {
- AddProperties(more...);
- }
-
-public: // functions to add properties or children
- // add a single property to the node
- template <typename T>
- void AddProperty(T value) {
- properties.emplace_back(value);
- }
-
- // convenience function to add multiple properties at once
- template <typename T, typename... More>
- void AddProperties(T value, More... more) {
- properties.emplace_back(value);
- AddProperties(more...);
- }
- void AddProperties() {}
-
- // add a child node directly
- void AddChild(const Node& node) { children.push_back(node); }
-
- // convenience function to add a child node with a single property
- template <typename... More>
- void AddChild(
- const std::string& name,
- More... more
- ) {
- FBX::Node c(name);
- c.AddProperties(more...);
- children.push_back(c);
- }
-
-public: // support specifically for dealing with Properties70 nodes
-
- // it really is simpler to make these all separate functions.
- // the versions with 'A' suffixes are for animatable properties.
- // those often follow a completely different format internally in FBX.
- void AddP70int(const std::string& name, int32_t value);
- void AddP70bool(const std::string& name, bool value);
- void AddP70double(const std::string& name, double value);
- void AddP70numberA(const std::string& name, double value);
- void AddP70color(const std::string& name, double r, double g, double b);
- void AddP70colorA(const std::string& name, double r, double g, double b);
- void AddP70vector(const std::string& name, double x, double y, double z);
- void AddP70vectorA(const std::string& name, double x, double y, double z);
- void AddP70string(const std::string& name, const std::string& value);
- void AddP70enum(const std::string& name, int32_t value);
- void AddP70time(const std::string& name, int64_t value);
-
- // template for custom P70 nodes.
- // anything that doesn't fit in the above can be created manually.
- template <typename... More>
- void AddP70(
- const std::string& name,
- const std::string& type,
- const std::string& type2,
- const std::string& flags,
- More... more
- ) {
- Node n("P");
- n.AddProperties(name, type, type2, flags, more...);
- AddChild(n);
- }
-
-public: // member functions for writing data to a file or stream
-
- // write the full node to the given file or stream
- void Dump(
- std::shared_ptr<Assimp::IOStream> outfile,
- bool binary, int indent
- );
- void Dump(Assimp::StreamWriterLE &s, bool binary, int indent);
-
- // these other functions are for writing data piece by piece.
- // they must be used carefully.
- // for usage examples see FBXExporter.cpp.
- void Begin(Assimp::StreamWriterLE &s, bool binary, int indent);
- void DumpProperties(Assimp::StreamWriterLE& s, bool binary, int indent);
- void EndProperties(Assimp::StreamWriterLE &s, bool binary, int indent);
- void EndProperties(
- Assimp::StreamWriterLE &s, bool binary, int indent,
- size_t num_properties
- );
- void BeginChildren(Assimp::StreamWriterLE &s, bool binary, int indent);
- void DumpChildren(Assimp::StreamWriterLE& s, bool binary, int indent);
- void End(
- Assimp::StreamWriterLE &s, bool binary, int indent,
- bool has_children
- );
-
-private: // internal functions used for writing
-
- void DumpBinary(Assimp::StreamWriterLE &s);
- void DumpAscii(Assimp::StreamWriterLE &s, int indent);
- void DumpAscii(std::ostream &s, int indent);
-
- void BeginBinary(Assimp::StreamWriterLE &s);
- void DumpPropertiesBinary(Assimp::StreamWriterLE& s);
- void EndPropertiesBinary(Assimp::StreamWriterLE &s);
- void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties);
- void DumpChildrenBinary(Assimp::StreamWriterLE& s);
- void EndBinary(Assimp::StreamWriterLE &s, bool has_children);
-
- void BeginAscii(std::ostream &s, int indent);
- void DumpPropertiesAscii(std::ostream &s, int indent);
- void BeginChildrenAscii(std::ostream &s, int indent);
- void DumpChildrenAscii(std::ostream &s, int indent);
- void EndAscii(std::ostream &s, int indent, bool has_children);
-
-private: // data used for binary dumps
- size_t start_pos; // starting position in stream
- size_t end_pos; // ending position in stream
- size_t property_start; // starting position of property section
-
-public: // static member functions
-
- // convenience function to create a node with a single property,
- // and write it to the stream.
- template <typename T>
- static void WritePropertyNode(
- const std::string& name,
- const T value,
- Assimp::StreamWriterLE& s,
- bool binary, int indent
- ) {
- FBX::FBXExportProperty p(value);
- FBX::Node node(name, p);
- node.Dump(s, binary, indent);
- }
-
- // convenience function to create and write a property node,
- // holding a single property which is an array of values.
- // does not copy the data, so is efficient for large arrays.
- static void WritePropertyNode(
- const std::string& name,
- const std::vector<double>& v,
- Assimp::StreamWriterLE& s,
- bool binary, int indent
- );
-
- // convenience function to create and write a property node,
- // holding a single property which is an array of values.
- // does not copy the data, so is efficient for large arrays.
- static void WritePropertyNode(
- const std::string& name,
- const std::vector<int32_t>& v,
- Assimp::StreamWriterLE& s,
- bool binary, int indent
- );
-
-private: // static helper functions
- static void WritePropertyNodeAscii(
- const std::string& name,
- const std::vector<double>& v,
- Assimp::StreamWriterLE& s,
- int indent
- );
- static void WritePropertyNodeAscii(
- const std::string& name,
- const std::vector<int32_t>& v,
- Assimp::StreamWriterLE& s,
- int indent
- );
- static void WritePropertyNodeBinary(
- const std::string& name,
- const std::vector<double>& v,
- Assimp::StreamWriterLE& s
- );
- static void WritePropertyNodeBinary(
- const std::string& name,
- const std::vector<int32_t>& v,
- Assimp::StreamWriterLE& s
- );
-
-};
-}
-
-#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#endif // AI_FBXEXPORTNODE_H_INC
diff --git a/thirdparty/assimp/code/FBX/FBXExportProperty.cpp b/thirdparty/assimp/code/FBX/FBXExportProperty.cpp
deleted file mode 100644
index f2a63b72b9..0000000000
--- a/thirdparty/assimp/code/FBX/FBXExportProperty.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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.
-
-----------------------------------------------------------------------
-*/
-#ifndef ASSIMP_BUILD_NO_EXPORT
-#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#include "FBXExportProperty.h"
-
-#include <assimp/StreamWriter.h> // StreamWriterLE
-#include <assimp/Exceptional.h> // DeadlyExportError
-
-#include <string>
-#include <vector>
-#include <ostream>
-#include <locale>
-#include <sstream> // ostringstream
-
-namespace Assimp {
-namespace FBX {
-
-// constructors for single element properties
-
-FBXExportProperty::FBXExportProperty(bool v)
-: type('C')
-, data(1, uint8_t(v)) {}
-
-FBXExportProperty::FBXExportProperty(int16_t v)
-: type('Y')
-, data(2) {
- uint8_t* d = data.data();
- (reinterpret_cast<int16_t*>(d))[0] = v;
-}
-
-FBXExportProperty::FBXExportProperty(int32_t v)
-: type('I')
-, data(4) {
- uint8_t* d = data.data();
- (reinterpret_cast<int32_t*>(d))[0] = v;
-}
-
-FBXExportProperty::FBXExportProperty(float v)
-: type('F')
-, data(4) {
- uint8_t* d = data.data();
- (reinterpret_cast<float*>(d))[0] = v;
-}
-
-FBXExportProperty::FBXExportProperty(double v)
-: type('D')
-, data(8) {
- uint8_t* d = data.data();
- (reinterpret_cast<double*>(d))[0] = v;
-}
-
-FBXExportProperty::FBXExportProperty(int64_t v)
-: type('L')
-, data(8) {
- uint8_t* d = data.data();
- (reinterpret_cast<int64_t*>(d))[0] = v;
-}
-
-// constructors for array-type properties
-
-FBXExportProperty::FBXExportProperty(const char* c, bool raw)
-: FBXExportProperty(std::string(c), raw) {
- // empty
-}
-
-// strings can either be saved as "raw" (R) data, or "string" (S) data
-FBXExportProperty::FBXExportProperty(const std::string& s, bool raw)
-: type(raw ? 'R' : 'S')
-, data(s.size()) {
- for (size_t i = 0; i < s.size(); ++i) {
- data[i] = uint8_t(s[i]);
- }
-}
-
-FBXExportProperty::FBXExportProperty(const std::vector<uint8_t>& r)
-: type('R')
-, data(r) {
- // empty
-}
-
-FBXExportProperty::FBXExportProperty(const std::vector<int32_t>& va)
-: type('i')
-, data(4 * va.size() ) {
- int32_t* d = reinterpret_cast<int32_t*>(data.data());
- for (size_t i = 0; i < va.size(); ++i) {
- d[i] = va[i];
- }
-}
-
-FBXExportProperty::FBXExportProperty(const std::vector<int64_t>& va)
-: type('l')
-, data(8 * va.size()) {
- int64_t* d = reinterpret_cast<int64_t*>(data.data());
- for (size_t i = 0; i < va.size(); ++i) {
- d[i] = va[i];
- }
-}
-
-FBXExportProperty::FBXExportProperty(const std::vector<float>& va)
-: type('f')
-, data(4 * va.size()) {
- float* d = reinterpret_cast<float*>(data.data());
- for (size_t i = 0; i < va.size(); ++i) {
- d[i] = va[i];
- }
-}
-
-FBXExportProperty::FBXExportProperty(const std::vector<double>& va)
-: type('d')
-, data(8 * va.size()) {
- double* d = reinterpret_cast<double*>(data.data());
- for (size_t i = 0; i < va.size(); ++i) {
- d[i] = va[i];
- }
-}
-
-FBXExportProperty::FBXExportProperty(const aiMatrix4x4& vm)
-: type('d')
-, data(8 * 16) {
- double* d = reinterpret_cast<double*>(data.data());
- for (unsigned int c = 0; c < 4; ++c) {
- for (unsigned int r = 0; r < 4; ++r) {
- d[4 * c + r] = vm[r][c];
- }
- }
-}
-
-// public member functions
-
-size_t FBXExportProperty::size() {
- switch (type) {
- case 'C':
- case 'Y':
- case 'I':
- case 'F':
- case 'D':
- case 'L':
- return data.size() + 1;
- case 'S':
- case 'R':
- return data.size() + 5;
- case 'i':
- case 'd':
- return data.size() + 13;
- default:
- throw DeadlyExportError("Requested size on property of unknown type");
- }
-}
-
-void FBXExportProperty::DumpBinary(Assimp::StreamWriterLE& s) {
- s.PutU1(type);
- uint8_t* d = data.data();
- size_t N;
- switch (type) {
- case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return;
- case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
- case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
- case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
- case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
- case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return;
- case 'S':
- case 'R':
- s.PutU4(uint32_t(data.size()));
- for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
- return;
- case 'i':
- N = data.size() / 4;
- s.PutU4(uint32_t(N)); // number of elements
- s.PutU4(0); // no encoding (1 would be zip-compressed)
- // TODO: compress if large?
- s.PutU4(uint32_t(data.size())); // data size
- for (size_t i = 0; i < N; ++i) {
- s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
- }
- return;
- case 'l':
- N = data.size() / 8;
- s.PutU4(uint32_t(N)); // number of elements
- s.PutU4(0); // no encoding (1 would be zip-compressed)
- // TODO: compress if large?
- s.PutU4(uint32_t(data.size())); // data size
- for (size_t i = 0; i < N; ++i) {
- s.PutI8((reinterpret_cast<int64_t*>(d))[i]);
- }
- return;
- case 'f':
- N = data.size() / 4;
- s.PutU4(uint32_t(N)); // number of elements
- s.PutU4(0); // no encoding (1 would be zip-compressed)
- // TODO: compress if large?
- s.PutU4(uint32_t(data.size())); // data size
- for (size_t i = 0; i < N; ++i) {
- s.PutF4((reinterpret_cast<float*>(d))[i]);
- }
- return;
- case 'd':
- N = data.size() / 8;
- s.PutU4(uint32_t(N)); // number of elements
- s.PutU4(0); // no encoding (1 would be zip-compressed)
- // TODO: compress if large?
- s.PutU4(uint32_t(data.size())); // data size
- for (size_t i = 0; i < N; ++i) {
- s.PutF8((reinterpret_cast<double*>(d))[i]);
- }
- return;
- default:
- std::ostringstream err;
- err << "Tried to dump property with invalid type '";
- err << type << "'!";
- throw DeadlyExportError(err.str());
- }
-}
-
-void FBXExportProperty::DumpAscii(Assimp::StreamWriterLE& outstream, int indent) {
- std::ostringstream ss;
- ss.imbue(std::locale::classic());
- ss.precision(15); // this seems to match official FBX SDK exports
- DumpAscii(ss, indent);
- outstream.PutString(ss.str());
-}
-
-void FBXExportProperty::DumpAscii(std::ostream& s, int indent) {
- // no writing type... or anything. just shove it into the stream.
- uint8_t* d = data.data();
- size_t N;
- size_t swap = data.size();
- size_t count = 0;
- switch (type) {
- case 'C':
- if (*(reinterpret_cast<uint8_t*>(d))) { s << 'T'; }
- else { s << 'F'; }
- return;
- case 'Y': s << *(reinterpret_cast<int16_t*>(d)); return;
- case 'I': s << *(reinterpret_cast<int32_t*>(d)); return;
- case 'F': s << *(reinterpret_cast<float*>(d)); return;
- case 'D': s << *(reinterpret_cast<double*>(d)); return;
- case 'L': s << *(reinterpret_cast<int64_t*>(d)); return;
- case 'S':
- // first search to see if it has "\x00\x01" in it -
- // which separates fields which are reversed in the ascii version.
- // yeah.
- // FBX, yeah.
- for (size_t i = 0; i < data.size(); ++i) {
- if (data[i] == '\0') {
- swap = i;
- break;
- }
- }
- case 'R':
- s << '"';
- // we might as well check this now,
- // probably it will never happen
- for (size_t i = 0; i < data.size(); ++i) {
- char c = data[i];
- if (c == '"') {
- throw runtime_error("can't handle quotes in property string");
- }
- }
- // first write the SWAPPED member (if any)
- for (size_t i = swap + 2; i < data.size(); ++i) {
- char c = data[i];
- s << c;
- }
- // then a separator
- if (swap != data.size()) {
- s << "::";
- }
- // then the initial member
- for (size_t i = 0; i < swap; ++i) {
- char c = data[i];
- s << c;
- }
- s << '"';
- return;
- case 'i':
- N = data.size() / 4; // number of elements
- s << '*' << N << " {\n";
- for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
- s << "a: ";
- for (size_t i = 0; i < N; ++i) {
- if (i > 0) { s << ','; }
- if (count++ > 120) { s << '\n'; count = 0; }
- s << (reinterpret_cast<int32_t*>(d))[i];
- }
- s << '\n';
- for (int i = 0; i < indent; ++i) { s << '\t'; }
- s << "} ";
- return;
- case 'l':
- N = data.size() / 8;
- s << '*' << N << " {\n";
- for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
- s << "a: ";
- for (size_t i = 0; i < N; ++i) {
- if (i > 0) { s << ','; }
- if (count++ > 120) { s << '\n'; count = 0; }
- s << (reinterpret_cast<int64_t*>(d))[i];
- }
- s << '\n';
- for (int i = 0; i < indent; ++i) { s << '\t'; }
- s << "} ";
- return;
- case 'f':
- N = data.size() / 4;
- s << '*' << N << " {\n";
- for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
- s << "a: ";
- for (size_t i = 0; i < N; ++i) {
- if (i > 0) { s << ','; }
- if (count++ > 120) { s << '\n'; count = 0; }
- s << (reinterpret_cast<float*>(d))[i];
- }
- s << '\n';
- for (int i = 0; i < indent; ++i) { s << '\t'; }
- s << "} ";
- return;
- case 'd':
- N = data.size() / 8;
- s << '*' << N << " {\n";
- for (int i = 0; i < indent + 1; ++i) { s << '\t'; }
- s << "a: ";
- // set precision to something that can handle doubles
- s.precision(15);
- for (size_t i = 0; i < N; ++i) {
- if (i > 0) { s << ','; }
- if (count++ > 120) { s << '\n'; count = 0; }
- s << (reinterpret_cast<double*>(d))[i];
- }
- s << '\n';
- for (int i = 0; i < indent; ++i) { s << '\t'; }
- s << "} ";
- return;
- default:
- std::ostringstream err;
- err << "Tried to dump property with invalid type '";
- err << type << "'!";
- throw runtime_error(err.str());
- }
-}
-
-} // Namespace FBX
-} // Namespace Assimp
-
-#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
-#endif // ASSIMP_BUILD_NO_EXPORT
diff --git a/thirdparty/assimp/code/FBX/FBXExportProperty.h b/thirdparty/assimp/code/FBX/FBXExportProperty.h
deleted file mode 100644
index d692fe6ee3..0000000000
--- a/thirdparty/assimp/code/FBX/FBXExportProperty.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXExportProperty.h
-* Declares the FBX::Property helper class for fbx export.
-*/
-#ifndef AI_FBXEXPORTPROPERTY_H_INC
-#define AI_FBXEXPORTPROPERTY_H_INC
-
-#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#include <assimp/types.h> // aiMatrix4x4
-#include <assimp/StreamWriter.h> // StreamWriterLE
-
-#include <string>
-#include <vector>
-#include <ostream>
-#include <type_traits> // is_void
-
-namespace Assimp {
-namespace FBX {
-
-/** @brief FBX::Property
- *
- * Holds a value of any of FBX's recognized types,
- * each represented by a particular one-character code.
- * C : 1-byte uint8, usually 0x00 or 0x01 to represent boolean false and true
- * Y : 2-byte int16
- * I : 4-byte int32
- * F : 4-byte float
- * D : 8-byte double
- * L : 8-byte int64
- * i : array of int32
- * f : array of float
- * d : array of double
- * l : array of int64
- * b : array of 1-byte booleans (0x00 or 0x01)
- * S : string (array of 1-byte char)
- * R : raw data (array of bytes)
- */
-class FBXExportProperty {
-public:
- // constructors for basic types.
- // all explicit to avoid accidental typecasting
- explicit FBXExportProperty(bool v);
- // TODO: determine if there is actually a byte type,
- // or if this always means <bool>. 'C' seems to imply <char>,
- // so possibly the above was intended to represent both.
- explicit FBXExportProperty(int16_t v);
- explicit FBXExportProperty(int32_t v);
- explicit FBXExportProperty(float v);
- explicit FBXExportProperty(double v);
- explicit FBXExportProperty(int64_t v);
- // strings can either be stored as 'R' (raw) or 'S' (string) type
- explicit FBXExportProperty(const char* c, bool raw = false);
- explicit FBXExportProperty(const std::string& s, bool raw = false);
- explicit FBXExportProperty(const std::vector<uint8_t>& r);
- explicit FBXExportProperty(const std::vector<int32_t>& va);
- explicit FBXExportProperty(const std::vector<int64_t>& va);
- explicit FBXExportProperty(const std::vector<double>& va);
- explicit FBXExportProperty(const std::vector<float>& va);
- explicit FBXExportProperty(const aiMatrix4x4& vm);
-
- // this will catch any type not defined above,
- // so that we don't accidentally convert something we don't want.
- // for example (const char*) --> (bool)... seriously wtf C++
- template <class T>
- explicit FBXExportProperty(T v) : type('X') {
- static_assert(std::is_void<T>::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION");
- } // note: no line wrap so it appears verbatim on the compiler error
-
- // the size of this property node in a binary file, in bytes
- size_t size();
-
- // write this property node as binary data to the given stream
- void DumpBinary(Assimp::StreamWriterLE& s);
- void DumpAscii(Assimp::StreamWriterLE& s, int indent = 0);
- void DumpAscii(std::ostream& s, int indent = 0);
- // note: make sure the ostream is in classic "C" locale
-
-private:
- char type;
- std::vector<uint8_t> data;
-};
-
-} // Namespace FBX
-} // Namespace Assimp
-
-#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#endif // AI_FBXEXPORTPROPERTY_H_INC
diff --git a/thirdparty/assimp/code/FBX/FBXExporter.cpp b/thirdparty/assimp/code/FBX/FBXExporter.cpp
deleted file mode 100644
index 9316dc4f02..0000000000
--- a/thirdparty/assimp/code/FBX/FBXExporter.cpp
+++ /dev/null
@@ -1,2556 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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.
-
-----------------------------------------------------------------------
-*/
-#ifndef ASSIMP_BUILD_NO_EXPORT
-#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#include "FBXExporter.h"
-#include "FBXExportNode.h"
-#include "FBXExportProperty.h"
-#include "FBXCommon.h"
-#include "FBXUtil.h"
-
-#include <assimp/version.h> // aiGetVersion
-#include <assimp/IOSystem.hpp>
-#include <assimp/Exporter.hpp>
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/StreamWriter.h> // StreamWriterLE
-#include <assimp/Exceptional.h> // DeadlyExportError
-#include <assimp/material.h> // aiTextureType
-#include <assimp/scene.h>
-#include <assimp/mesh.h>
-
-// Header files, standard library.
-#include <memory> // shared_ptr
-#include <string>
-#include <sstream> // stringstream
-#include <ctime> // localtime, tm_*
-#include <map>
-#include <set>
-#include <vector>
-#include <array>
-#include <unordered_set>
-#include <numeric>
-
-// RESOURCES:
-// https://code.blender.org/2013/08/fbx-binary-file-format-specification/
-// https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure
-
-const ai_real DEG = ai_real( 57.29577951308232087679815481 ); // degrees per radian
-
-using namespace Assimp;
-using namespace Assimp::FBX;
-
-// some constants that we'll use for writing metadata
-namespace Assimp {
-namespace FBX {
- const std::string EXPORT_VERSION_STR = "7.4.0";
- const uint32_t EXPORT_VERSION_INT = 7400; // 7.4 == 2014/2015
- // FBX files have some hashed values that depend on the creation time field,
- // but for now we don't actually know how to generate these.
- // what we can do is set them to a known-working version.
- // this is the data that Blender uses in their FBX export process.
- const std::string GENERIC_CTIME = "1970-01-01 10:00:00:000";
- const std::string GENERIC_FILEID =
- "\x28\xb3\x2a\xeb\xb6\x24\xcc\xc2\xbf\xc8\xb0\x2a\xa9\x2b\xfc\xf1";
- const std::string GENERIC_FOOTID =
- "\xfa\xbc\xab\x09\xd0\xc8\xd4\x66\xb1\x76\xfb\x83\x1c\xf7\x26\x7e";
- const std::string FOOT_MAGIC =
- "\xf8\x5a\x8c\x6a\xde\xf5\xd9\x7e\xec\xe9\x0c\xe3\x75\x8f\x29\x0b";
- const std::string COMMENT_UNDERLINE =
- ";------------------------------------------------------------------";
-}
-
- // ---------------------------------------------------------------------
- // Worker function for exporting a scene to binary FBX.
- // Prototyped and registered in Exporter.cpp
- void ExportSceneFBX (
- const char* pFile,
- IOSystem* pIOSystem,
- const aiScene* pScene,
- const ExportProperties* pProperties
- ){
- // initialize the exporter
- FBXExporter exporter(pScene, pProperties);
-
- // perform binary export
- exporter.ExportBinary(pFile, pIOSystem);
- }
-
- // ---------------------------------------------------------------------
- // Worker function for exporting a scene to ASCII FBX.
- // Prototyped and registered in Exporter.cpp
- void ExportSceneFBXA (
- const char* pFile,
- IOSystem* pIOSystem,
- const aiScene* pScene,
- const ExportProperties* pProperties
-
- ){
- // initialize the exporter
- FBXExporter exporter(pScene, pProperties);
-
- // perform ascii export
- exporter.ExportAscii(pFile, pIOSystem);
- }
-
-} // end of namespace Assimp
-
-FBXExporter::FBXExporter ( const aiScene* pScene, const ExportProperties* pProperties )
-: binary(false)
-, mScene(pScene)
-, mProperties(pProperties)
-, outfile()
-, connections()
-, mesh_uids()
-, material_uids()
-, node_uids() {
- // will probably need to determine UIDs, connections, etc here.
- // basically anything that needs to be known
- // before we start writing sections to the stream.
-}
-
-void FBXExporter::ExportBinary (
- const char* pFile,
- IOSystem* pIOSystem
-){
- // remember that we're exporting in binary mode
- binary = true;
-
- // we're not currently using these preferences,
- // but clang will cry about it if we never touch it.
- // TODO: some of these might be relevant to export
- (void)mProperties;
-
- // open the indicated file for writing (in binary mode)
- outfile.reset(pIOSystem->Open(pFile,"wb"));
- if (!outfile) {
- throw DeadlyExportError(
- "could not open output .fbx file: " + std::string(pFile)
- );
- }
-
- // first a binary-specific file header
- WriteBinaryHeader();
-
- // the rest of the file is in node entries.
- // we have to serialize each entry before we write to the output,
- // as the first thing we write is the byte offset of the _next_ entry.
- // Either that or we can skip back to write the offset when we finish.
- WriteAllNodes();
-
- // finally we have a binary footer to the file
- WriteBinaryFooter();
-
- // explicitly release file pointer,
- // so we don't have to rely on class destruction.
- outfile.reset();
-}
-
-void FBXExporter::ExportAscii (
- const char* pFile,
- IOSystem* pIOSystem
-){
- // remember that we're exporting in ascii mode
- binary = false;
-
- // open the indicated file for writing in text mode
- outfile.reset(pIOSystem->Open(pFile,"wt"));
- if (!outfile) {
- throw DeadlyExportError(
- "could not open output .fbx file: " + std::string(pFile)
- );
- }
-
- // write the ascii header
- WriteAsciiHeader();
-
- // write all the sections
- WriteAllNodes();
-
- // make sure the file ends with a newline.
- // note: if the file is opened in text mode,
- // this should do the right cross-platform thing.
- outfile->Write("\n", 1, 1);
-
- // explicitly release file pointer,
- // so we don't have to rely on class destruction.
- outfile.reset();
-}
-
-void FBXExporter::WriteAsciiHeader()
-{
- // basically just a comment at the top of the file
- std::stringstream head;
- head << "; FBX " << EXPORT_VERSION_STR << " project file\n";
- head << "; Created by the Open Asset Import Library (Assimp)\n";
- head << "; http://assimp.org\n";
- head << "; -------------------------------------------------\n";
- const std::string ascii_header = head.str();
- outfile->Write(ascii_header.c_str(), ascii_header.size(), 1);
-}
-
-void FBXExporter::WriteAsciiSectionHeader(const std::string& title)
-{
- StreamWriterLE outstream(outfile);
- std::stringstream s;
- s << "\n\n; " << title << '\n';
- s << FBX::COMMENT_UNDERLINE << "\n";
- outstream.PutString(s.str());
-}
-
-void FBXExporter::WriteBinaryHeader()
-{
- // first a specific sequence of 23 bytes, always the same
- const char binary_header[24] = "Kaydara FBX Binary\x20\x20\x00\x1a\x00";
- outfile->Write(binary_header, 1, 23);
-
- // then FBX version number, "multiplied" by 1000, as little-endian uint32.
- // so 7.3 becomes 7300 == 0x841C0000, 7.4 becomes 7400 == 0xE81C0000, etc
- {
- StreamWriterLE outstream(outfile);
- outstream.PutU4(EXPORT_VERSION_INT);
- } // StreamWriter destructor writes the data to the file
-
- // after this the node data starts immediately
- // (probably with the FBXHEaderExtension node)
-}
-
-void FBXExporter::WriteBinaryFooter()
-{
- outfile->Write(NULL_RECORD.c_str(), NULL_RECORD.size(), 1);
-
- outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);
-
- // here some padding is added for alignment to 16 bytes.
- // if already aligned, the full 16 bytes is added.
- size_t pos = outfile->Tell();
- size_t pad = 16 - (pos % 16);
- for (size_t i = 0; i < pad; ++i) {
- outfile->Write("\x00", 1, 1);
- }
-
- // not sure what this is, but it seems to always be 0 in modern files
- for (size_t i = 0; i < 4; ++i) {
- outfile->Write("\x00", 1, 1);
- }
-
- // now the file version again
- {
- StreamWriterLE outstream(outfile);
- outstream.PutU4(EXPORT_VERSION_INT);
- } // StreamWriter destructor writes the data to the file
-
- // and finally some binary footer added to all files
- for (size_t i = 0; i < 120; ++i) {
- outfile->Write("\x00", 1, 1);
- }
- outfile->Write(FOOT_MAGIC.c_str(), FOOT_MAGIC.size(), 1);
-}
-
-void FBXExporter::WriteAllNodes ()
-{
- // header
- // (and fileid, creation time, creator, if binary)
- WriteHeaderExtension();
-
- // global settings
- WriteGlobalSettings();
-
- // documents
- WriteDocuments();
-
- // references
- WriteReferences();
-
- // definitions
- WriteDefinitions();
-
- // objects
- WriteObjects();
-
- // connections
- WriteConnections();
-
- // WriteTakes? (deprecated since at least 2015 (fbx 7.4))
-}
-
-//FBXHeaderExtension top-level node
-void FBXExporter::WriteHeaderExtension ()
-{
- if (!binary) {
- // no title, follows directly from the top comment
- }
- FBX::Node n("FBXHeaderExtension");
- StreamWriterLE outstream(outfile);
- int indent = 0;
-
- // begin node
- n.Begin(outstream, binary, indent);
-
- // write properties
- // (none)
-
- // finish properties
- n.EndProperties(outstream, binary, indent, 0);
-
- // begin children
- n.BeginChildren(outstream, binary, indent);
-
- indent = 1;
-
- // write child nodes
- FBX::Node::WritePropertyNode(
- "FBXHeaderVersion", int32_t(1003), outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "FBXVersion", int32_t(EXPORT_VERSION_INT), outstream, binary, indent
- );
- if (binary) {
- FBX::Node::WritePropertyNode(
- "EncryptionType", int32_t(0), outstream, binary, indent
- );
- }
-
- FBX::Node CreationTimeStamp("CreationTimeStamp");
- time_t rawtime;
- time(&rawtime);
- struct tm * now = localtime(&rawtime);
- CreationTimeStamp.AddChild("Version", int32_t(1000));
- CreationTimeStamp.AddChild("Year", int32_t(now->tm_year + 1900));
- CreationTimeStamp.AddChild("Month", int32_t(now->tm_mon + 1));
- CreationTimeStamp.AddChild("Day", int32_t(now->tm_mday));
- CreationTimeStamp.AddChild("Hour", int32_t(now->tm_hour));
- CreationTimeStamp.AddChild("Minute", int32_t(now->tm_min));
- CreationTimeStamp.AddChild("Second", int32_t(now->tm_sec));
- CreationTimeStamp.AddChild("Millisecond", int32_t(0));
- CreationTimeStamp.Dump(outstream, binary, indent);
-
- std::stringstream creator;
- creator << "Open Asset Import Library (Assimp) " << aiGetVersionMajor()
- << "." << aiGetVersionMinor() << "." << aiGetVersionRevision();
- FBX::Node::WritePropertyNode(
- "Creator", creator.str(), outstream, binary, indent
- );
-
- //FBX::Node sceneinfo("SceneInfo");
- //sceneinfo.AddProperty("GlobalInfo" + FBX::SEPARATOR + "SceneInfo");
- // not sure if any of this is actually needed,
- // so just write an empty node for now.
- //sceneinfo.Dump(outstream, binary, indent);
-
- indent = 0;
-
- // finish node
- n.End(outstream, binary, indent, true);
-
- // that's it for FBXHeaderExtension...
- if (!binary) { return; }
-
- // but binary files also need top-level FileID, CreationTime, Creator:
- std::vector<uint8_t> raw(GENERIC_FILEID.size());
- for (size_t i = 0; i < GENERIC_FILEID.size(); ++i) {
- raw[i] = uint8_t(GENERIC_FILEID[i]);
- }
- FBX::Node::WritePropertyNode(
- "FileId", raw, outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "CreationTime", GENERIC_CTIME, outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "Creator", creator.str(), outstream, binary, indent
- );
-}
-
-void FBXExporter::WriteGlobalSettings ()
-{
- if (!binary) {
- // no title, follows directly from the header extension
- }
- FBX::Node gs("GlobalSettings");
- gs.AddChild("Version", int32_t(1000));
-
- FBX::Node p("Properties70");
- p.AddP70int("UpAxis", 1);
- p.AddP70int("UpAxisSign", 1);
- p.AddP70int("FrontAxis", 2);
- p.AddP70int("FrontAxisSign", 1);
- p.AddP70int("CoordAxis", 0);
- p.AddP70int("CoordAxisSign", 1);
- p.AddP70int("OriginalUpAxis", 1);
- p.AddP70int("OriginalUpAxisSign", 1);
- p.AddP70double("UnitScaleFactor", 1.0);
- p.AddP70double("OriginalUnitScaleFactor", 1.0);
- p.AddP70color("AmbientColor", 0.0, 0.0, 0.0);
- p.AddP70string("DefaultCamera", "Producer Perspective");
- p.AddP70enum("TimeMode", 11);
- p.AddP70enum("TimeProtocol", 2);
- p.AddP70enum("SnapOnFrameMode", 0);
- p.AddP70time("TimeSpanStart", 0); // TODO: animation support
- p.AddP70time("TimeSpanStop", FBX::SECOND); // TODO: animation support
- p.AddP70double("CustomFrameRate", -1.0);
- p.AddP70("TimeMarker", "Compound", "", ""); // not sure what this is
- p.AddP70int("CurrentTimeMarker", -1);
- gs.AddChild(p);
-
- gs.Dump(outfile, binary, 0);
-}
-
-void FBXExporter::WriteDocuments ()
-{
- if (!binary) {
- WriteAsciiSectionHeader("Documents Description");
- }
-
- // not sure what the use of multiple documents would be,
- // or whether any end-application supports it
- FBX::Node docs("Documents");
- docs.AddChild("Count", int32_t(1));
- FBX::Node doc("Document");
-
- // generate uid
- int64_t uid = generate_uid();
- doc.AddProperties(uid, "", "Scene");
- FBX::Node p("Properties70");
- p.AddP70("SourceObject", "object", "", ""); // what is this even for?
- p.AddP70string("ActiveAnimStackName", ""); // should do this properly?
- doc.AddChild(p);
-
- // UID for root node in scene hierarchy.
- // always set to 0 in the case of a single document.
- // not sure what happens if more than one document exists,
- // but that won't matter to us as we're exporting a single scene.
- doc.AddChild("RootNode", int64_t(0));
-
- docs.AddChild(doc);
- docs.Dump(outfile, binary, 0);
-}
-
-void FBXExporter::WriteReferences ()
-{
- if (!binary) {
- WriteAsciiSectionHeader("Document References");
- }
- // always empty for now.
- // not really sure what this is for.
- FBX::Node n("References");
- n.force_has_children = true;
- n.Dump(outfile, binary, 0);
-}
-
-
-// ---------------------------------------------------------------
-// some internal helper functions used for writing the definitions
-// (before any actual data is written)
-// ---------------------------------------------------------------
-
-size_t count_nodes(const aiNode* n) {
- size_t count = 1;
- for (size_t i = 0; i < n->mNumChildren; ++i) {
- count += count_nodes(n->mChildren[i]);
- }
- return count;
-}
-
-bool has_phong_mat(const aiScene* scene)
-{
- // just search for any material with a shininess exponent
- for (size_t i = 0; i < scene->mNumMaterials; ++i) {
- aiMaterial* mat = scene->mMaterials[i];
- float shininess = 0;
- mat->Get(AI_MATKEY_SHININESS, shininess);
- if (shininess > 0) {
- return true;
- }
- }
- return false;
-}
-
-size_t count_images(const aiScene* scene) {
- std::unordered_set<std::string> images;
- aiString texpath;
- for (size_t i = 0; i < scene->mNumMaterials; ++i) {
- aiMaterial* mat = scene->mMaterials[i];
- for (
- size_t tt = aiTextureType_DIFFUSE;
- tt < aiTextureType_UNKNOWN;
- ++tt
- ){
- const aiTextureType textype = static_cast<aiTextureType>(tt);
- const size_t texcount = mat->GetTextureCount(textype);
- for (unsigned int j = 0; j < texcount; ++j) {
- mat->GetTexture(textype, j, &texpath);
- images.insert(std::string(texpath.C_Str()));
- }
- }
- }
- return images.size();
-}
-
-size_t count_textures(const aiScene* scene) {
- size_t count = 0;
- for (size_t i = 0; i < scene->mNumMaterials; ++i) {
- aiMaterial* mat = scene->mMaterials[i];
- for (
- size_t tt = aiTextureType_DIFFUSE;
- tt < aiTextureType_UNKNOWN;
- ++tt
- ){
- // TODO: handle layered textures
- if (mat->GetTextureCount(static_cast<aiTextureType>(tt)) > 0) {
- count += 1;
- }
- }
- }
- return count;
-}
-
-size_t count_deformers(const aiScene* scene) {
- size_t count = 0;
- for (size_t i = 0; i < scene->mNumMeshes; ++i) {
- const size_t n = scene->mMeshes[i]->mNumBones;
- if (n) {
- // 1 main deformer, 1 subdeformer per bone
- count += n + 1;
- }
- }
- return count;
-}
-
-void FBXExporter::WriteDefinitions ()
-{
- // basically this is just bookkeeping:
- // determining how many of each type of object there are
- // and specifying the base properties to use when otherwise unspecified.
-
- // ascii section header
- if (!binary) {
- WriteAsciiSectionHeader("Object definitions");
- }
-
- // we need to count the objects
- int32_t count;
- int32_t total_count = 0;
-
- // and store them
- std::vector<FBX::Node> object_nodes;
- FBX::Node n, pt, p;
-
- // GlobalSettings
- // this seems to always be here in Maya exports
- n = FBX::Node("ObjectType", "GlobalSettings");
- count = 1;
- n.AddChild("Count", count);
- object_nodes.push_back(n);
- total_count += count;
-
- // AnimationStack / FbxAnimStack
- // this seems to always be here in Maya exports,
- // but no harm seems to come of leaving it out.
- count = mScene->mNumAnimations;
- if (count) {
- n = FBX::Node("ObjectType", "AnimationStack");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "FbxAnimStack");
- p = FBX::Node("Properties70");
- p.AddP70string("Description", "");
- p.AddP70time("LocalStart", 0);
- p.AddP70time("LocalStop", 0);
- p.AddP70time("ReferenceStart", 0);
- p.AddP70time("ReferenceStop", 0);
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // AnimationLayer / FbxAnimLayer
- // this seems to always be here in Maya exports,
- // but no harm seems to come of leaving it out.
- // Assimp doesn't support animation layers,
- // so there will be one per aiAnimation
- count = mScene->mNumAnimations;
- if (count) {
- n = FBX::Node("ObjectType", "AnimationLayer");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "FBXAnimLayer");
- p = FBX::Node("Properties70");
- p.AddP70("Weight", "Number", "", "A", double(100));
- p.AddP70bool("Mute", 0);
- p.AddP70bool("Solo", 0);
- p.AddP70bool("Lock", 0);
- p.AddP70color("Color", 0.8, 0.8, 0.8);
- p.AddP70("BlendMode", "enum", "", "", int32_t(0));
- p.AddP70("RotationAccumulationMode", "enum", "", "", int32_t(0));
- p.AddP70("ScaleAccumulationMode", "enum", "", "", int32_t(0));
- p.AddP70("BlendModeBypass", "ULongLong", "", "", int64_t(0));
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // NodeAttribute
- // this is completely absurd.
- // there can only be one "NodeAttribute" template,
- // but FbxSkeleton, FbxCamera, FbxLight all are "NodeAttributes".
- // so if only one exists we should set the template for that,
- // otherwise... we just pick one :/.
- // the others have to set all their properties every instance,
- // because there's no template.
- count = 1; // TODO: select properly
- if (count) {
- // FbxSkeleton
- n = FBX::Node("ObjectType", "NodeAttribute");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "FbxSkeleton");
- p = FBX::Node("Properties70");
- p.AddP70color("Color", 0.8, 0.8, 0.8);
- p.AddP70double("Size", 33.333333333333);
- p.AddP70("LimbLength", "double", "Number", "H", double(1));
- // note: not sure what the "H" flag is for - hidden?
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // Model / FbxNode
- // <~~ node hierarchy
- count = int32_t(count_nodes(mScene->mRootNode)) - 1; // (not counting root node)
- if (count) {
- n = FBX::Node("ObjectType", "Model");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "FbxNode");
- p = FBX::Node("Properties70");
- p.AddP70enum("QuaternionInterpolate", 0);
- p.AddP70vector("RotationOffset", 0.0, 0.0, 0.0);
- p.AddP70vector("RotationPivot", 0.0, 0.0, 0.0);
- p.AddP70vector("ScalingOffset", 0.0, 0.0, 0.0);
- p.AddP70vector("ScalingPivot", 0.0, 0.0, 0.0);
- p.AddP70bool("TranslationActive", 0);
- p.AddP70vector("TranslationMin", 0.0, 0.0, 0.0);
- p.AddP70vector("TranslationMax", 0.0, 0.0, 0.0);
- p.AddP70bool("TranslationMinX", 0);
- p.AddP70bool("TranslationMinY", 0);
- p.AddP70bool("TranslationMinZ", 0);
- p.AddP70bool("TranslationMaxX", 0);
- p.AddP70bool("TranslationMaxY", 0);
- p.AddP70bool("TranslationMaxZ", 0);
- p.AddP70enum("RotationOrder", 0);
- p.AddP70bool("RotationSpaceForLimitOnly", 0);
- p.AddP70double("RotationStiffnessX", 0.0);
- p.AddP70double("RotationStiffnessY", 0.0);
- p.AddP70double("RotationStiffnessZ", 0.0);
- p.AddP70double("AxisLen", 10.0);
- p.AddP70vector("PreRotation", 0.0, 0.0, 0.0);
- p.AddP70vector("PostRotation", 0.0, 0.0, 0.0);
- p.AddP70bool("RotationActive", 0);
- p.AddP70vector("RotationMin", 0.0, 0.0, 0.0);
- p.AddP70vector("RotationMax", 0.0, 0.0, 0.0);
- p.AddP70bool("RotationMinX", 0);
- p.AddP70bool("RotationMinY", 0);
- p.AddP70bool("RotationMinZ", 0);
- p.AddP70bool("RotationMaxX", 0);
- p.AddP70bool("RotationMaxY", 0);
- p.AddP70bool("RotationMaxZ", 0);
- p.AddP70enum("InheritType", 0);
- p.AddP70bool("ScalingActive", 0);
- p.AddP70vector("ScalingMin", 0.0, 0.0, 0.0);
- p.AddP70vector("ScalingMax", 1.0, 1.0, 1.0);
- p.AddP70bool("ScalingMinX", 0);
- p.AddP70bool("ScalingMinY", 0);
- p.AddP70bool("ScalingMinZ", 0);
- p.AddP70bool("ScalingMaxX", 0);
- p.AddP70bool("ScalingMaxY", 0);
- p.AddP70bool("ScalingMaxZ", 0);
- p.AddP70vector("GeometricTranslation", 0.0, 0.0, 0.0);
- p.AddP70vector("GeometricRotation", 0.0, 0.0, 0.0);
- p.AddP70vector("GeometricScaling", 1.0, 1.0, 1.0);
- p.AddP70double("MinDampRangeX", 0.0);
- p.AddP70double("MinDampRangeY", 0.0);
- p.AddP70double("MinDampRangeZ", 0.0);
- p.AddP70double("MaxDampRangeX", 0.0);
- p.AddP70double("MaxDampRangeY", 0.0);
- p.AddP70double("MaxDampRangeZ", 0.0);
- p.AddP70double("MinDampStrengthX", 0.0);
- p.AddP70double("MinDampStrengthY", 0.0);
- p.AddP70double("MinDampStrengthZ", 0.0);
- p.AddP70double("MaxDampStrengthX", 0.0);
- p.AddP70double("MaxDampStrengthY", 0.0);
- p.AddP70double("MaxDampStrengthZ", 0.0);
- p.AddP70double("PreferedAngleX", 0.0);
- p.AddP70double("PreferedAngleY", 0.0);
- p.AddP70double("PreferedAngleZ", 0.0);
- p.AddP70("LookAtProperty", "object", "", "");
- p.AddP70("UpVectorProperty", "object", "", "");
- p.AddP70bool("Show", 1);
- p.AddP70bool("NegativePercentShapeSupport", 1);
- p.AddP70int("DefaultAttributeIndex", -1);
- p.AddP70bool("Freeze", 0);
- p.AddP70bool("LODBox", 0);
- p.AddP70(
- "Lcl Translation", "Lcl Translation", "", "A",
- double(0), double(0), double(0)
- );
- p.AddP70(
- "Lcl Rotation", "Lcl Rotation", "", "A",
- double(0), double(0), double(0)
- );
- p.AddP70(
- "Lcl Scaling", "Lcl Scaling", "", "A",
- double(1), double(1), double(1)
- );
- p.AddP70("Visibility", "Visibility", "", "A", double(1));
- p.AddP70(
- "Visibility Inheritance", "Visibility Inheritance", "", "",
- int32_t(1)
- );
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // Geometry / FbxMesh
- // <~~ aiMesh
- count = mScene->mNumMeshes;
- if (count) {
- n = FBX::Node("ObjectType", "Geometry");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "FbxMesh");
- p = FBX::Node("Properties70");
- p.AddP70color("Color", 0, 0, 0);
- p.AddP70vector("BBoxMin", 0, 0, 0);
- p.AddP70vector("BBoxMax", 0, 0, 0);
- p.AddP70bool("Primary Visibility", 1);
- p.AddP70bool("Casts Shadows", 1);
- p.AddP70bool("Receive Shadows", 1);
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // Material / FbxSurfacePhong, FbxSurfaceLambert, FbxSurfaceMaterial
- // <~~ aiMaterial
- // basically if there's any phong material this is defined as phong,
- // and otherwise lambert.
- // More complex materials cause a bare-bones FbxSurfaceMaterial definition
- // and are treated specially, as they're not really supported by FBX.
- // TODO: support Maya's Stingray PBS material
- count = mScene->mNumMaterials;
- if (count) {
- bool has_phong = has_phong_mat(mScene);
- n = FBX::Node("ObjectType", "Material");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate");
- if (has_phong) {
- pt.AddProperty("FbxSurfacePhong");
- } else {
- pt.AddProperty("FbxSurfaceLambert");
- }
- p = FBX::Node("Properties70");
- if (has_phong) {
- p.AddP70string("ShadingModel", "Phong");
- } else {
- p.AddP70string("ShadingModel", "Lambert");
- }
- p.AddP70bool("MultiLayer", 0);
- p.AddP70colorA("EmissiveColor", 0.0, 0.0, 0.0);
- p.AddP70numberA("EmissiveFactor", 1.0);
- p.AddP70colorA("AmbientColor", 0.2, 0.2, 0.2);
- p.AddP70numberA("AmbientFactor", 1.0);
- p.AddP70colorA("DiffuseColor", 0.8, 0.8, 0.8);
- p.AddP70numberA("DiffuseFactor", 1.0);
- p.AddP70vector("Bump", 0.0, 0.0, 0.0);
- p.AddP70vector("NormalMap", 0.0, 0.0, 0.0);
- p.AddP70double("BumpFactor", 1.0);
- p.AddP70colorA("TransparentColor", 0.0, 0.0, 0.0);
- p.AddP70numberA("TransparencyFactor", 0.0);
- p.AddP70color("DisplacementColor", 0.0, 0.0, 0.0);
- p.AddP70double("DisplacementFactor", 1.0);
- p.AddP70color("VectorDisplacementColor", 0.0, 0.0, 0.0);
- p.AddP70double("VectorDisplacementFactor", 1.0);
- if (has_phong) {
- p.AddP70colorA("SpecularColor", 0.2, 0.2, 0.2);
- p.AddP70numberA("SpecularFactor", 1.0);
- p.AddP70numberA("ShininessExponent", 20.0);
- p.AddP70colorA("ReflectionColor", 0.0, 0.0, 0.0);
- p.AddP70numberA("ReflectionFactor", 1.0);
- }
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // Video / FbxVideo
- // one for each image file.
- count = int32_t(count_images(mScene));
- if (count) {
- n = FBX::Node("ObjectType", "Video");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "FbxVideo");
- p = FBX::Node("Properties70");
- p.AddP70bool("ImageSequence", 0);
- p.AddP70int("ImageSequenceOffset", 0);
- p.AddP70double("FrameRate", 0.0);
- p.AddP70int("LastFrame", 0);
- p.AddP70int("Width", 0);
- p.AddP70int("Height", 0);
- p.AddP70("Path", "KString", "XRefUrl", "", "");
- p.AddP70int("StartFrame", 0);
- p.AddP70int("StopFrame", 0);
- p.AddP70double("PlaySpeed", 0.0);
- p.AddP70time("Offset", 0);
- p.AddP70enum("InterlaceMode", 0);
- p.AddP70bool("FreeRunning", 0);
- p.AddP70bool("Loop", 0);
- p.AddP70enum("AccessMode", 0);
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // Texture / FbxFileTexture
- // <~~ aiTexture
- count = int32_t(count_textures(mScene));
- if (count) {
- n = FBX::Node("ObjectType", "Texture");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "FbxFileTexture");
- p = FBX::Node("Properties70");
- p.AddP70enum("TextureTypeUse", 0);
- p.AddP70numberA("Texture alpha", 1.0);
- p.AddP70enum("CurrentMappingType", 0);
- p.AddP70enum("WrapModeU", 0);
- p.AddP70enum("WrapModeV", 0);
- p.AddP70bool("UVSwap", 0);
- p.AddP70bool("PremultiplyAlpha", 1);
- p.AddP70vectorA("Translation", 0.0, 0.0, 0.0);
- p.AddP70vectorA("Rotation", 0.0, 0.0, 0.0);
- p.AddP70vectorA("Scaling", 1.0, 1.0, 1.0);
- p.AddP70vector("TextureRotationPivot", 0.0, 0.0, 0.0);
- p.AddP70vector("TextureScalingPivot", 0.0, 0.0, 0.0);
- p.AddP70enum("CurrentTextureBlendMode", 1);
- p.AddP70string("UVSet", "default");
- p.AddP70bool("UseMaterial", 0);
- p.AddP70bool("UseMipMap", 0);
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // AnimationCurveNode / FbxAnimCurveNode
- count = mScene->mNumAnimations * 3;
- if (count) {
- n = FBX::Node("ObjectType", "AnimationCurveNode");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "FbxAnimCurveNode");
- p = FBX::Node("Properties70");
- p.AddP70("d", "Compound", "", "");
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // AnimationCurve / FbxAnimCurve
- count = mScene->mNumAnimations * 9;
- if (count) {
- n = FBX::Node("ObjectType", "AnimationCurve");
- n.AddChild("Count", count);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // Pose
- count = 0;
- for (size_t i = 0; i < mScene->mNumMeshes; ++i) {
- aiMesh* mesh = mScene->mMeshes[i];
- if (mesh->HasBones()) { ++count; }
- }
- if (count) {
- n = FBX::Node("ObjectType", "Pose");
- n.AddChild("Count", count);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // Deformer
- count = int32_t(count_deformers(mScene));
- if (count) {
- n = FBX::Node("ObjectType", "Deformer");
- n.AddChild("Count", count);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // (template)
- count = 0;
- if (count) {
- n = FBX::Node("ObjectType", "");
- n.AddChild("Count", count);
- pt = FBX::Node("PropertyTemplate", "");
- p = FBX::Node("Properties70");
- pt.AddChild(p);
- n.AddChild(pt);
- object_nodes.push_back(n);
- total_count += count;
- }
-
- // now write it all
- FBX::Node defs("Definitions");
- defs.AddChild("Version", int32_t(100));
- defs.AddChild("Count", int32_t(total_count));
- for (auto &n : object_nodes) { defs.AddChild(n); }
- defs.Dump(outfile, binary, 0);
-}
-
-
-// -------------------------------------------------------------------
-// some internal helper functions used for writing the objects section
-// (which holds the actual data)
-// -------------------------------------------------------------------
-
-aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node)
-{
- for (size_t i = 0; i < node->mNumMeshes; ++i) {
- if (node->mMeshes[i] == meshIndex) {
- return node;
- }
- }
- for (size_t i = 0; i < node->mNumChildren; ++i) {
- aiNode* ret = get_node_for_mesh(meshIndex, node->mChildren[i]);
- if (ret) { return ret; }
- }
- return nullptr;
-}
-
-aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene)
-{
- std::vector<const aiNode*> node_chain;
- while (node != scene->mRootNode) {
- node_chain.push_back(node);
- node = node->mParent;
- }
- aiMatrix4x4 transform;
- for (auto n = node_chain.rbegin(); n != node_chain.rend(); ++n) {
- transform *= (*n)->mTransformation;
- }
- return transform;
-}
-
-int64_t to_ktime(double ticks, const aiAnimation* anim) {
- if (anim->mTicksPerSecond <= 0) {
- return static_cast<int64_t>(ticks) * FBX::SECOND;
- }
- return (static_cast<int64_t>(ticks) / static_cast<int64_t>(anim->mTicksPerSecond)) * FBX::SECOND;
-}
-
-int64_t to_ktime(double time) {
- return (static_cast<int64_t>(time * FBX::SECOND));
-}
-
-void FBXExporter::WriteObjects ()
-{
- if (!binary) {
- WriteAsciiSectionHeader("Object properties");
- }
- // numbers should match those given in definitions! make sure to check
- StreamWriterLE outstream(outfile);
- FBX::Node object_node("Objects");
- int indent = 0;
- object_node.Begin(outstream, binary, indent);
- object_node.EndProperties(outstream, binary, indent);
- object_node.BeginChildren(outstream, binary, indent);
-
- bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true);
- std::vector<std::vector<int32_t>> vVertexIndice;//save vertex_indices as it is needed later
-
- // geometry (aiMesh)
- mesh_uids.clear();
- indent = 1;
- for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
- // it's all about this mesh
- aiMesh* m = mScene->mMeshes[mi];
-
- // start the node record
- FBX::Node n("Geometry");
- int64_t uid = generate_uid();
- mesh_uids.push_back(uid);
- n.AddProperty(uid);
- n.AddProperty(FBX::SEPARATOR + "Geometry");
- n.AddProperty("Mesh");
- n.Begin(outstream, binary, indent);
- n.DumpProperties(outstream, binary, indent);
- n.EndProperties(outstream, binary, indent);
- n.BeginChildren(outstream, binary, indent);
- indent = 2;
-
- // output vertex data - each vertex should be unique (probably)
- std::vector<double> flattened_vertices;
- // index of original vertex in vertex data vector
- std::vector<int32_t> vertex_indices;
- // map of vertex value to its index in the data vector
- std::map<aiVector3D,size_t> index_by_vertex_value;
- if(bJoinIdenticalVertices){
- int32_t index = 0;
- for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
- aiVector3D vtx = m->mVertices[vi];
- auto elem = index_by_vertex_value.find(vtx);
- if (elem == index_by_vertex_value.end()) {
- vertex_indices.push_back(index);
- index_by_vertex_value[vtx] = index;
- flattened_vertices.push_back(vtx[0]);
- flattened_vertices.push_back(vtx[1]);
- flattened_vertices.push_back(vtx[2]);
- ++index;
- } else {
- vertex_indices.push_back(int32_t(elem->second));
- }
- }
- }
- else { // do not join vertex, respect the export flag
- vertex_indices.resize(m->mNumVertices);
- std::iota(vertex_indices.begin(), vertex_indices.end(), 0);
- for(unsigned int v = 0; v < m->mNumVertices; ++ v) {
- aiVector3D vtx = m->mVertices[v];
- flattened_vertices.push_back(vtx.x);
- flattened_vertices.push_back(vtx.y);
- flattened_vertices.push_back(vtx.z);
- }
- }
- vVertexIndice.push_back(vertex_indices);
-
- FBX::Node::WritePropertyNode(
- "Vertices", flattened_vertices, outstream, binary, indent
- );
-
- // output polygon data as a flattened array of vertex indices.
- // the last vertex index of each polygon is negated and - 1
- std::vector<int32_t> polygon_data;
- for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
- const aiFace &f = m->mFaces[fi];
- for (size_t pvi = 0; pvi < f.mNumIndices - 1; ++pvi) {
- polygon_data.push_back(vertex_indices[f.mIndices[pvi]]);
- }
- polygon_data.push_back(
- -1 - vertex_indices[f.mIndices[f.mNumIndices-1]]
- );
- }
- FBX::Node::WritePropertyNode(
- "PolygonVertexIndex", polygon_data, outstream, binary, indent
- );
-
- // here could be edges but they're insane.
- // it's optional anyway, so let's ignore it.
-
- FBX::Node::WritePropertyNode(
- "GeometryVersion", int32_t(124), outstream, binary, indent
- );
-
- // normals, if any
- if (m->HasNormals()) {
- FBX::Node normals("LayerElementNormal", int32_t(0));
- normals.Begin(outstream, binary, indent);
- normals.DumpProperties(outstream, binary, indent);
- normals.EndProperties(outstream, binary, indent);
- normals.BeginChildren(outstream, binary, indent);
- indent = 3;
- FBX::Node::WritePropertyNode(
- "Version", int32_t(101), outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "Name", "", outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "MappingInformationType", "ByPolygonVertex",
- outstream, binary, indent
- );
- // TODO: vertex-normals or indexed normals when appropriate
- FBX::Node::WritePropertyNode(
- "ReferenceInformationType", "Direct",
- outstream, binary, indent
- );
- std::vector<double> normal_data;
- normal_data.reserve(3 * polygon_data.size());
- for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
- const aiFace &f = m->mFaces[fi];
- for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
- const aiVector3D &n = m->mNormals[f.mIndices[pvi]];
- normal_data.push_back(n.x);
- normal_data.push_back(n.y);
- normal_data.push_back(n.z);
- }
- }
- FBX::Node::WritePropertyNode(
- "Normals", normal_data, outstream, binary, indent
- );
- // note: version 102 has a NormalsW also... not sure what it is,
- // so we can stick with version 101 for now.
- indent = 2;
- normals.End(outstream, binary, indent, true);
- }
-
- // colors, if any
- // TODO only one color channel currently
- const int32_t colorChannelIndex = 0;
- if (m->HasVertexColors(colorChannelIndex)) {
- FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex));
- vertexcolors.Begin(outstream, binary, indent);
- vertexcolors.DumpProperties(outstream, binary, indent);
- vertexcolors.EndProperties(outstream, binary, indent);
- vertexcolors.BeginChildren(outstream, binary, indent);
- indent = 3;
- FBX::Node::WritePropertyNode(
- "Version", int32_t(101), outstream, binary, indent
- );
- char layerName[8];
- sprintf(layerName, "COLOR_%d", colorChannelIndex);
- FBX::Node::WritePropertyNode(
- "Name", (const char*)layerName, outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "MappingInformationType", "ByPolygonVertex",
- outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "ReferenceInformationType", "Direct",
- outstream, binary, indent
- );
- std::vector<double> color_data;
- color_data.reserve(4 * polygon_data.size());
- for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
- const aiFace &f = m->mFaces[fi];
- for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
- const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]];
- color_data.push_back(c.r);
- color_data.push_back(c.g);
- color_data.push_back(c.b);
- color_data.push_back(c.a);
- }
- }
- FBX::Node::WritePropertyNode(
- "Colors", color_data, outstream, binary, indent
- );
- indent = 2;
- vertexcolors.End(outstream, binary, indent, true);
- }
-
- // uvs, if any
- for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) {
- if (m->mNumUVComponents[uvi] > 2) {
- // FBX only supports 2-channel UV maps...
- // or at least i'm not sure how to indicate a different number
- std::stringstream err;
- err << "Only 2-channel UV maps supported by FBX,";
- err << " but mesh " << mi;
- if (m->mName.length) {
- err << " (" << m->mName.C_Str() << ")";
- }
- err << " UV map " << uvi;
- err << " has " << m->mNumUVComponents[uvi];
- err << " components! Data will be preserved,";
- err << " but may be incorrectly interpreted on load.";
- ASSIMP_LOG_WARN(err.str());
- }
- FBX::Node uv("LayerElementUV", int32_t(uvi));
- uv.Begin(outstream, binary, indent);
- uv.DumpProperties(outstream, binary, indent);
- uv.EndProperties(outstream, binary, indent);
- uv.BeginChildren(outstream, binary, indent);
- indent = 3;
- FBX::Node::WritePropertyNode(
- "Version", int32_t(101), outstream, binary, indent
- );
- // it doesn't seem like assimp keeps the uv map name,
- // so just leave it blank.
- FBX::Node::WritePropertyNode(
- "Name", "", outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "MappingInformationType", "ByPolygonVertex",
- outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "ReferenceInformationType", "IndexToDirect",
- outstream, binary, indent
- );
-
- std::vector<double> uv_data;
- std::vector<int32_t> uv_indices;
- std::map<aiVector3D,int32_t> index_by_uv;
- int32_t index = 0;
- for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
- const aiFace &f = m->mFaces[fi];
- for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
- const aiVector3D &uv =
- m->mTextureCoords[uvi][f.mIndices[pvi]];
- auto elem = index_by_uv.find(uv);
- if (elem == index_by_uv.end()) {
- index_by_uv[uv] = index;
- uv_indices.push_back(index);
- for (unsigned int x = 0; x < m->mNumUVComponents[uvi]; ++x) {
- uv_data.push_back(uv[x]);
- }
- ++index;
- } else {
- uv_indices.push_back(elem->second);
- }
- }
- }
- FBX::Node::WritePropertyNode(
- "UV", uv_data, outstream, binary, indent
- );
- FBX::Node::WritePropertyNode(
- "UVIndex", uv_indices, outstream, binary, indent
- );
- indent = 2;
- uv.End(outstream, binary, indent, true);
- }
-
- // i'm not really sure why this material section exists,
- // as the material is linked via "Connections".
- // it seems to always have the same "0" value.
- FBX::Node mat("LayerElementMaterial", int32_t(0));
- mat.AddChild("Version", int32_t(101));
- mat.AddChild("Name", "");
- mat.AddChild("MappingInformationType", "AllSame");
- mat.AddChild("ReferenceInformationType", "IndexToDirect");
- std::vector<int32_t> mat_indices = {0};
- mat.AddChild("Materials", mat_indices);
- mat.Dump(outstream, binary, indent);
-
- // finally we have the layer specifications,
- // which select the normals / UV set / etc to use.
- // TODO: handle multiple uv sets correctly?
- FBX::Node layer("Layer", int32_t(0));
- layer.AddChild("Version", int32_t(100));
- FBX::Node le("LayerElement");
- le.AddChild("Type", "LayerElementNormal");
- le.AddChild("TypedIndex", int32_t(0));
- layer.AddChild(le);
- // TODO only 1 color channel currently
- le = FBX::Node("LayerElement");
- le.AddChild("Type", "LayerElementColor");
- le.AddChild("TypedIndex", int32_t(0));
- layer.AddChild(le);
- le = FBX::Node("LayerElement");
- le.AddChild("Type", "LayerElementMaterial");
- le.AddChild("TypedIndex", int32_t(0));
- layer.AddChild(le);
- le = FBX::Node("LayerElement");
- le.AddChild("Type", "LayerElementUV");
- le.AddChild("TypedIndex", int32_t(0));
- layer.AddChild(le);
- layer.Dump(outstream, binary, indent);
-
- for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr)
- {
- FBX::Node layerExtra("Layer", int32_t(lr));
- layerExtra.AddChild("Version", int32_t(100));
- FBX::Node leExtra("LayerElement");
- leExtra.AddChild("Type", "LayerElementUV");
- leExtra.AddChild("TypedIndex", int32_t(lr));
- layerExtra.AddChild(leExtra);
- layerExtra.Dump(outstream, binary, indent);
- }
- // finish the node record
- indent = 1;
- n.End(outstream, binary, indent, true);
- }
-
- // aiMaterial
- material_uids.clear();
- for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
- // it's all about this material
- aiMaterial* m = mScene->mMaterials[i];
-
- // these are used to receive material data
- float f; aiColor3D c;
-
- // start the node record
- FBX::Node n("Material");
-
- int64_t uid = generate_uid();
- material_uids.push_back(uid);
- n.AddProperty(uid);
-
- aiString name;
- m->Get(AI_MATKEY_NAME, name);
- n.AddProperty(name.C_Str() + FBX::SEPARATOR + "Material");
-
- n.AddProperty("");
-
- n.AddChild("Version", int32_t(102));
- f = 0;
- m->Get(AI_MATKEY_SHININESS, f);
- bool phong = (f > 0);
- if (phong) {
- n.AddChild("ShadingModel", "phong");
- } else {
- n.AddChild("ShadingModel", "lambert");
- }
- n.AddChild("MultiLayer", int32_t(0));
-
- FBX::Node p("Properties70");
-
- // materials exported using the FBX SDK have two sets of fields.
- // there are the properties specified in the PropertyTemplate,
- // which are those supported by the modernFBX SDK,
- // and an extra set of properties with simpler names.
- // The extra properties are a legacy material system from pre-2009.
- //
- // In the modern system, each property has "color" and "factor".
- // Generally the interpretation of these seems to be
- // that the colour is multiplied by the factor before use,
- // but this is not always clear-cut.
- //
- // Usually assimp only stores the colour,
- // so we can just leave the factors at the default "1.0".
-
- // first we can export the "standard" properties
- if (m->Get(AI_MATKEY_COLOR_AMBIENT, c) == aiReturn_SUCCESS) {
- p.AddP70colorA("AmbientColor", c.r, c.g, c.b);
- //p.AddP70numberA("AmbientFactor", 1.0);
- }
- if (m->Get(AI_MATKEY_COLOR_DIFFUSE, c) == aiReturn_SUCCESS) {
- p.AddP70colorA("DiffuseColor", c.r, c.g, c.b);
- //p.AddP70numberA("DiffuseFactor", 1.0);
- }
- if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) {
- // "TransparentColor" / "TransparencyFactor"...
- // thanks FBX, for your insightful interpretation of consistency
- p.AddP70colorA("TransparentColor", c.r, c.g, c.b);
- // TransparencyFactor defaults to 0.0, so set it to 1.0.
- // note: Maya always sets this to 1.0,
- // so we can't use it sensibly as "Opacity".
- // In stead we rely on the legacy "Opacity" value, below.
- // Blender also relies on "Opacity" not "TransparencyFactor",
- // probably for a similar reason.
- p.AddP70numberA("TransparencyFactor", 1.0);
- }
- if (m->Get(AI_MATKEY_COLOR_REFLECTIVE, c) == aiReturn_SUCCESS) {
- p.AddP70colorA("ReflectionColor", c.r, c.g, c.b);
- }
- if (m->Get(AI_MATKEY_REFLECTIVITY, f) == aiReturn_SUCCESS) {
- p.AddP70numberA("ReflectionFactor", f);
- }
- if (phong) {
- if (m->Get(AI_MATKEY_COLOR_SPECULAR, c) == aiReturn_SUCCESS) {
- p.AddP70colorA("SpecularColor", c.r, c.g, c.b);
- }
- if (m->Get(AI_MATKEY_SHININESS_STRENGTH, f) == aiReturn_SUCCESS) {
- p.AddP70numberA("ShininessFactor", f);
- }
- if (m->Get(AI_MATKEY_SHININESS, f) == aiReturn_SUCCESS) {
- p.AddP70numberA("ShininessExponent", f);
- }
- if (m->Get(AI_MATKEY_REFLECTIVITY, f) == aiReturn_SUCCESS) {
- p.AddP70numberA("ReflectionFactor", f);
- }
- }
-
- // Now the legacy system.
- // For safety let's include it.
- // thrse values don't exist in the property template,
- // and usually are completely ignored when loading.
- // One notable exception is the "Opacity" property,
- // which Blender uses as (1.0 - alpha).
- c.r = 0.0f; c.g = 0.0f; c.b = 0.0f;
- m->Get(AI_MATKEY_COLOR_EMISSIVE, c);
- p.AddP70vector("Emissive", c.r, c.g, c.b);
- c.r = 0.2f; c.g = 0.2f; c.b = 0.2f;
- m->Get(AI_MATKEY_COLOR_AMBIENT, c);
- p.AddP70vector("Ambient", c.r, c.g, c.b);
- c.r = 0.8f; c.g = 0.8f; c.b = 0.8f;
- m->Get(AI_MATKEY_COLOR_DIFFUSE, c);
- p.AddP70vector("Diffuse", c.r, c.g, c.b);
- // The FBX SDK determines "Opacity" from transparency colour (RGB)
- // and factor (F) as: O = (1.0 - F * ((R + G + B) / 3)).
- // However we actually have an opacity value,
- // so we should take it from AI_MATKEY_OPACITY if possible.
- // It might make more sense to use TransparencyFactor,
- // but Blender actually loads "Opacity" correctly, so let's use it.
- f = 1.0f;
- if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) {
- f = 1.0f - ((c.r + c.g + c.b) / 3.0f);
- }
- m->Get(AI_MATKEY_OPACITY, f);
- p.AddP70double("Opacity", f);
- if (phong) {
- // specular color is multiplied by shininess_strength
- c.r = 0.2f; c.g = 0.2f; c.b = 0.2f;
- m->Get(AI_MATKEY_COLOR_SPECULAR, c);
- f = 1.0f;
- m->Get(AI_MATKEY_SHININESS_STRENGTH, f);
- p.AddP70vector("Specular", f*c.r, f*c.g, f*c.b);
- f = 20.0f;
- m->Get(AI_MATKEY_SHININESS, f);
- p.AddP70double("Shininess", f);
- // Legacy "Reflectivity" is F*F*((R+G+B)/3),
- // where F is the proportion of light reflected (AKA reflectivity),
- // and RGB is the reflective colour of the material.
- // No idea why, but we might as well set it the same way.
- f = 0.0f;
- m->Get(AI_MATKEY_REFLECTIVITY, f);
- c.r = 1.0f, c.g = 1.0f, c.b = 1.0f;
- m->Get(AI_MATKEY_COLOR_REFLECTIVE, c);
- p.AddP70double("Reflectivity", f*f*((c.r+c.g+c.b)/3.0));
- }
-
- n.AddChild(p);
-
- n.Dump(outstream, binary, indent);
- }
-
- // we need to look up all the images we're using,
- // so we can generate uids, and eliminate duplicates.
- std::map<std::string, int64_t> uid_by_image;
- for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
- aiString texpath;
- aiMaterial* mat = mScene->mMaterials[i];
- for (
- size_t tt = aiTextureType_DIFFUSE;
- tt < aiTextureType_UNKNOWN;
- ++tt
- ){
- const aiTextureType textype = static_cast<aiTextureType>(tt);
- const size_t texcount = mat->GetTextureCount(textype);
- for (size_t j = 0; j < texcount; ++j) {
- mat->GetTexture(textype, (unsigned int)j, &texpath);
- const std::string texstring = texpath.C_Str();
- auto elem = uid_by_image.find(texstring);
- if (elem == uid_by_image.end()) {
- uid_by_image[texstring] = generate_uid();
- }
- }
- }
- }
-
- // FbxVideo - stores images used by textures.
- for (const auto &it : uid_by_image) {
- FBX::Node n("Video");
- const int64_t& uid = it.second;
- const std::string name = ""; // TODO: ... name???
- n.AddProperties(uid, name + FBX::SEPARATOR + "Video", "Clip");
- n.AddChild("Type", "Clip");
- FBX::Node p("Properties70");
- // TODO: get full path... relative path... etc... ugh...
- // for now just use the same path for everything,
- // and hopefully one of them will work out.
- std::string path = it.first;
- // try get embedded texture
- const aiTexture* embedded_texture = mScene->GetEmbeddedTexture(it.first.c_str());
- if (embedded_texture != nullptr) {
- // change the path (use original filename, if available. If name is empty, concatenate texture index with file extension)
- std::stringstream newPath;
- if (embedded_texture->mFilename.length > 0) {
- newPath << embedded_texture->mFilename.C_Str();
- } else if (embedded_texture->achFormatHint[0]) {
- int texture_index = std::stoi(path.substr(1, path.size() - 1));
- newPath << texture_index << "." << embedded_texture->achFormatHint;
- }
- path = newPath.str();
- // embed the texture
- size_t texture_size = static_cast<size_t>(embedded_texture->mWidth * std::max(embedded_texture->mHeight, 1u));
- if (binary) {
- // embed texture as binary data
- std::vector<uint8_t> tex_data;
- tex_data.resize(texture_size);
- memcpy(&tex_data[0], (char*)embedded_texture->pcData, texture_size);
- n.AddChild("Content", tex_data);
- } else {
- // embed texture in base64 encoding
- std::string encoded_texture = FBX::Util::EncodeBase64((char*)embedded_texture->pcData, texture_size);
- n.AddChild("Content", encoded_texture);
- }
- }
- p.AddP70("Path", "KString", "XRefUrl", "", path);
- n.AddChild(p);
- n.AddChild("UseMipMap", int32_t(0));
- n.AddChild("Filename", path);
- n.AddChild("RelativeFilename", path);
- n.Dump(outstream, binary, indent);
- }
-
- // Textures
- // referenced by material_index/texture_type pairs.
- std::map<std::pair<size_t,size_t>,int64_t> texture_uids;
- const std::map<aiTextureType,std::string> prop_name_by_tt = {
- {aiTextureType_DIFFUSE, "DiffuseColor"},
- {aiTextureType_SPECULAR, "SpecularColor"},
- {aiTextureType_AMBIENT, "AmbientColor"},
- {aiTextureType_EMISSIVE, "EmissiveColor"},
- {aiTextureType_HEIGHT, "Bump"},
- {aiTextureType_NORMALS, "NormalMap"},
- {aiTextureType_SHININESS, "ShininessExponent"},
- {aiTextureType_OPACITY, "TransparentColor"},
- {aiTextureType_DISPLACEMENT, "DisplacementColor"},
- //{aiTextureType_LIGHTMAP, "???"},
- {aiTextureType_REFLECTION, "ReflectionColor"}
- //{aiTextureType_UNKNOWN, ""}
- };
- for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
- // textures are attached to materials
- aiMaterial* mat = mScene->mMaterials[i];
- int64_t material_uid = material_uids[i];
-
- for (
- size_t j = aiTextureType_DIFFUSE;
- j < aiTextureType_UNKNOWN;
- ++j
- ) {
- const aiTextureType tt = static_cast<aiTextureType>(j);
- size_t n = mat->GetTextureCount(tt);
-
- if (n < 1) { // no texture of this type
- continue;
- }
-
- if (n > 1) {
- // TODO: multilayer textures
- std::stringstream err;
- err << "Multilayer textures not supported (for now),";
- err << " skipping texture type " << j;
- err << " of material " << i;
- ASSIMP_LOG_WARN(err.str());
- }
-
- // get image path for this (single-image) texture
- aiString tpath;
- if (mat->GetTexture(tt, 0, &tpath) != aiReturn_SUCCESS) {
- std::stringstream err;
- err << "Failed to get texture 0 for texture of type " << tt;
- err << " on material " << i;
- err << ", however GetTextureCount returned 1.";
- throw DeadlyExportError(err.str());
- }
- const std::string texture_path(tpath.C_Str());
-
- // get connected image uid
- auto elem = uid_by_image.find(texture_path);
- if (elem == uid_by_image.end()) {
- // this should never happen
- std::stringstream err;
- err << "Failed to find video element for texture with path";
- err << " \"" << texture_path << "\"";
- err << ", type " << j << ", material " << i;
- throw DeadlyExportError(err.str());
- }
- const int64_t image_uid = elem->second;
-
- // get the name of the material property to connect to
- auto elem2 = prop_name_by_tt.find(tt);
- if (elem2 == prop_name_by_tt.end()) {
- // don't know how to handle this type of texture,
- // so skip it.
- std::stringstream err;
- err << "Not sure how to handle texture of type " << j;
- err << " on material " << i;
- err << ", skipping...";
- ASSIMP_LOG_WARN(err.str());
- continue;
- }
- const std::string& prop_name = elem2->second;
-
- // generate a uid for this texture
- const int64_t texture_uid = generate_uid();
-
- // link the texture to the material
- connections.emplace_back(
- "C", "OP", texture_uid, material_uid, prop_name
- );
-
- // link the image data to the texture
- connections.emplace_back("C", "OO", image_uid, texture_uid);
-
- // now write the actual texture node
- FBX::Node tnode("Texture");
- // TODO: some way to determine texture name?
- const std::string texture_name = "" + FBX::SEPARATOR + "Texture";
- tnode.AddProperties(texture_uid, texture_name, "");
- // there really doesn't seem to be a better type than this:
- tnode.AddChild("Type", "TextureVideoClip");
- tnode.AddChild("Version", int32_t(202));
- tnode.AddChild("TextureName", texture_name);
- FBX::Node p("Properties70");
- p.AddP70enum("CurrentTextureBlendMode", 0); // TODO: verify
- //p.AddP70string("UVSet", ""); // TODO: how should this work?
- p.AddP70bool("UseMaterial", 1);
- tnode.AddChild(p);
- // can't easily detrmine which texture path will be correct,
- // so just store what we have in every field.
- // these being incorrect is a common problem with FBX anyway.
- tnode.AddChild("FileName", texture_path);
- tnode.AddChild("RelativeFilename", texture_path);
- tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0));
- tnode.AddChild("ModelUVScaling", double(1.0), double(1.0));
- tnode.AddChild("Texture_Alpha_Source", "None");
- tnode.AddChild(
- "Cropping", int32_t(0), int32_t(0), int32_t(0), int32_t(0)
- );
- tnode.Dump(outstream, binary, indent);
- }
- }
-
- // bones.
- //
- // output structure:
- // subset of node hierarchy that are "skeleton",
- // i.e. do not have meshes but only bones.
- // but.. i'm not sure how anyone could guarantee that...
- //
- // input...
- // well, for each mesh it has "bones",
- // and the bone names correspond to nodes.
- // of course we also need the parent nodes,
- // as they give some of the transform........
- //
- // well. we can assume a sane input, i suppose.
- //
- // so input is the bone node hierarchy,
- // with an extra thing for the transformation of the MESH in BONE space.
- //
- // output is a set of bone nodes,
- // a "bindpose" which indicates the default local transform of all bones,
- // and a set of "deformers".
- // each deformer is parented to a mesh geometry,
- // and has one or more "subdeformer"s as children.
- // each subdeformer has one bone node as a child,
- // and represents the influence of that bone on the grandparent mesh.
- // the subdeformer has a list of indices, and weights,
- // with indices specifying vertex indices,
- // and weights specifying the corresponding influence of this bone.
- // it also has Transform and TransformLink elements,
- // specifying the transform of the MESH in BONE space,
- // and the transformation of the BONE in WORLD space,
- // likely in the bindpose.
- //
- // the input bone structure is different but similar,
- // storing the number of weights for this bone,
- // and an array of (vertex index, weight) pairs.
- //
- // one sticky point is that the number of vertices may not match,
- // because assimp splits vertices by normal, uv, etc.
-
- // functor for aiNode sorting
- struct SortNodeByName
- {
- bool operator()(const aiNode *lhs, const aiNode *rhs) const
- {
- return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0;
- }
- };
-
- // first we should mark the skeleton for each mesh.
- // the skeleton must include not only the aiBones,
- // but also all their parent nodes.
- // anything that affects the position of any bone node must be included.
- // Use SorNodeByName to make sure the exported result will be the same across all systems
- // Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent
- std::vector<std::set<const aiNode*, SortNodeByName>> skeleton_by_mesh(mScene->mNumMeshes);
- // at the same time we can build a list of all the skeleton nodes,
- // which will be used later to mark them as type "limbNode".
- std::unordered_set<const aiNode*> limbnodes;
-
- //actual bone nodes in fbx, without parenting-up
- std::unordered_set<std::string> setAllBoneNamesInScene;
- for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
- {
- aiMesh* pMesh = mScene->mMeshes[m];
- for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
- setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data);
- }
- aiMatrix4x4 mxTransIdentity;
-
- // and a map of nodes by bone name, as finding them is annoying.
- std::map<std::string,aiNode*> node_by_bone;
- for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
- const aiMesh* m = mScene->mMeshes[mi];
- std::set<const aiNode*, SortNodeByName> skeleton;
- for (size_t bi =0; bi < m->mNumBones; ++bi) {
- const aiBone* b = m->mBones[bi];
- const std::string name(b->mName.C_Str());
- auto elem = node_by_bone.find(name);
- aiNode* n;
- if (elem != node_by_bone.end()) {
- n = elem->second;
- } else {
- n = mScene->mRootNode->FindNode(b->mName);
- if (!n) {
- // this should never happen
- std::stringstream err;
- err << "Failed to find node for bone: \"" << name << "\"";
- throw DeadlyExportError(err.str());
- }
- node_by_bone[name] = n;
- limbnodes.insert(n);
- }
- skeleton.insert(n);
- // mark all parent nodes as skeleton as well,
- // up until we find the root node,
- // or else the node containing the mesh,
- // or else the parent of a node containig the mesh.
- for (
- const aiNode* parent = n->mParent;
- parent && parent != mScene->mRootNode;
- parent = parent->mParent
- ) {
- // if we've already done this node we can skip it all
- if (skeleton.count(parent)) {
- break;
- }
- // ignore fbx transform nodes as these will be collapsed later
- // TODO: cache this by aiNode*
- const std::string node_name(parent->mName.C_Str());
- if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
- continue;
- }
- //not a bone in scene && no effect in transform
- if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end()
- && parent->mTransformation == mxTransIdentity) {
- continue;
- }
- // otherwise check if this is the root of the skeleton
- bool end = false;
- // is the mesh part of this node?
- for (size_t i = 0; i < parent->mNumMeshes; ++i) {
- if (parent->mMeshes[i] == mi) {
- end = true;
- break;
- }
- }
- // is the mesh in one of the children of this node?
- for (size_t j = 0; j < parent->mNumChildren; ++j) {
- aiNode* child = parent->mChildren[j];
- for (size_t i = 0; i < child->mNumMeshes; ++i) {
- if (child->mMeshes[i] == mi) {
- end = true;
- break;
- }
- }
- if (end) { break; }
- }
-
- // if it was the skeleton root we can finish here
- if (end) { break; }
- }
- }
- skeleton_by_mesh[mi] = skeleton;
- }
-
- // we'll need the uids for the bone nodes, so generate them now
- for (size_t i = 0; i < mScene->mNumMeshes; ++i) {
- auto &s = skeleton_by_mesh[i];
- for (const aiNode* n : s) {
- auto elem = node_uids.find(n);
- if (elem == node_uids.end()) {
- node_uids[n] = generate_uid();
- }
- }
- }
-
- // now, for each aiMesh, we need to export a deformer,
- // and for each aiBone a subdeformer,
- // which should have all the skinning info.
- // these will need to be connected properly to the mesh,
- // and we can do that all now.
- for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
- const aiMesh* m = mScene->mMeshes[mi];
- if (!m->HasBones()) {
- continue;
- }
- // make a deformer for this mesh
- int64_t deformer_uid = generate_uid();
- FBX::Node dnode("Deformer");
- dnode.AddProperties(deformer_uid, FBX::SEPARATOR + "Deformer", "Skin");
- dnode.AddChild("Version", int32_t(101));
- // "acuracy"... this is not a typo....
- dnode.AddChild("Link_DeformAcuracy", double(50));
- dnode.AddChild("SkinningType", "Linear"); // TODO: other modes?
- dnode.Dump(outstream, binary, indent);
-
- // connect it
- connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]);
-
- //computed before
- std::vector<int32_t>& vertex_indices = vVertexIndice[mi];
-
- // TODO, FIXME: this won't work if anything is not in the bind pose.
- // for now if such a situation is detected, we throw an exception.
- std::set<const aiBone*> not_in_bind_pose;
- std::set<const aiNode*> no_offset_matrix;
-
- // first get this mesh's position in world space,
- // as we'll need it for each subdeformer.
- //
- // ...of course taking the position of the MESH doesn't make sense,
- // as it can be instanced to many nodes.
- // All we can do is assume no instancing,
- // and take the first node we find that contains the mesh.
- aiNode* mesh_node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode);
- aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
-
- // now make a subdeformer for each bone in the skeleton
- const std::set<const aiNode*, SortNodeByName> skeleton= skeleton_by_mesh[mi];
- for (const aiNode* bone_node : skeleton) {
- // if there's a bone for this node, find it
- const aiBone* b = nullptr;
- for (size_t bi = 0; bi < m->mNumBones; ++bi) {
- // TODO: this probably should index by something else
- const std::string name(m->mBones[bi]->mName.C_Str());
- if (node_by_bone[name] == bone_node) {
- b = m->mBones[bi];
- break;
- }
- }
- if (!b) {
- no_offset_matrix.insert(bone_node);
- }
-
- // start the subdeformer node
- const int64_t subdeformer_uid = generate_uid();
- FBX::Node sdnode("Deformer");
- sdnode.AddProperties(
- subdeformer_uid, FBX::SEPARATOR + "SubDeformer", "Cluster"
- );
- sdnode.AddChild("Version", int32_t(100));
- sdnode.AddChild("UserData", "", "");
-
- // add indices and weights, if any
- if (b) {
- std::vector<int32_t> subdef_indices;
- std::vector<double> subdef_weights;
- int32_t last_index = -1;
- for (size_t wi = 0; wi < b->mNumWeights; ++wi) {
- int32_t vi = vertex_indices[b->mWeights[wi].mVertexId];
- if (vi == last_index) {
- // only for vertices we exported to fbx
- // TODO, FIXME: this assumes identically-located vertices
- // will always deform in the same way.
- // as assimp doesn't store a separate list of "positions",
- // there's not much that can be done about this
- // other than assuming that identical position means
- // identical vertex.
- continue;
- }
- subdef_indices.push_back(vi);
- subdef_weights.push_back(b->mWeights[wi].mWeight);
- last_index = vi;
- }
- // yes, "indexes"
- sdnode.AddChild("Indexes", subdef_indices);
- sdnode.AddChild("Weights", subdef_weights);
- }
-
- // transform is the transform of the mesh, but in bone space.
- // if the skeleton is in the bind pose,
- // we can take the inverse of the world-space bone transform
- // and multiply by the world-space transform of the mesh.
- aiMatrix4x4 bone_xform = get_world_transform(bone_node, mScene);
- aiMatrix4x4 inverse_bone_xform = bone_xform;
- inverse_bone_xform.Inverse();
- aiMatrix4x4 tr = inverse_bone_xform * mesh_xform;
-
- sdnode.AddChild("Transform", tr);
-
-
- sdnode.AddChild("TransformLink", bone_xform);
- // note: this means we ALWAYS rely on the mesh node transform
- // being unchanged from the time the skeleton was bound.
- // there's not really any way around this at the moment.
-
- // done
- sdnode.Dump(outstream, binary, indent);
-
- // lastly, connect to the parent deformer
- connections.emplace_back(
- "C", "OO", subdeformer_uid, deformer_uid
- );
-
- // we also need to connect the limb node to the subdeformer.
- connections.emplace_back(
- "C", "OO", node_uids[bone_node], subdeformer_uid
- );
- }
-
- // if we cannot create a valid FBX file, simply die.
- // this will both prevent unnecessary bug reports,
- // and tell the user what they can do to fix the situation
- // (i.e. export their model in the bind pose).
- if (no_offset_matrix.size() && not_in_bind_pose.size()) {
- std::stringstream err;
- err << "Not enough information to construct bind pose";
- err << " for mesh " << mi << "!";
- err << " Transform matrix for bone \"";
- err << (*not_in_bind_pose.begin())->mName.C_Str() << "\"";
- if (not_in_bind_pose.size() > 1) {
- err << " (and " << not_in_bind_pose.size() - 1 << " more)";
- }
- err << " does not match mOffsetMatrix,";
- err << " and node \"";
- err << (*no_offset_matrix.begin())->mName.C_Str() << "\"";
- if (no_offset_matrix.size() > 1) {
- err << " (and " << no_offset_matrix.size() - 1 << " more)";
- }
- err << " has no offset matrix to rely on.";
- err << " Please ensure bones are in the bind pose to export.";
- throw DeadlyExportError(err.str());
- }
-
- }
-
- // BindPose
- //
- // This is a legacy system, which should be unnecessary.
- //
- // Somehow including it slows file loading by the official FBX SDK,
- // and as it can reconstruct it from the deformers anyway,
- // this is not currently included.
- //
- // The code is kept here in case it's useful in the future,
- // but it's pretty much a hack anyway,
- // as assimp doesn't store bindpose information for full skeletons.
- //
- /*for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
- aiMesh* mesh = mScene->mMeshes[mi];
- if (! mesh->HasBones()) { continue; }
- int64_t bindpose_uid = generate_uid();
- FBX::Node bpnode("Pose");
- bpnode.AddProperty(bindpose_uid);
- // note: this uid is never linked or connected to anything.
- bpnode.AddProperty(FBX::SEPARATOR + "Pose"); // blank name
- bpnode.AddProperty("BindPose");
-
- bpnode.AddChild("Type", "BindPose");
- bpnode.AddChild("Version", int32_t(100));
-
- aiNode* mesh_node = get_node_for_mesh(mi, mScene->mRootNode);
-
- // next get the whole skeleton for this mesh.
- // we need it all to define the bindpose section.
- // the FBX SDK will complain if it's missing,
- // and also if parents of used bones don't have a subdeformer.
- // order shouldn't matter.
- std::set<aiNode*> skeleton;
- for (size_t bi = 0; bi < mesh->mNumBones; ++bi) {
- // bone node should have already been indexed
- const aiBone* b = mesh->mBones[bi];
- const std::string bone_name(b->mName.C_Str());
- aiNode* parent = node_by_bone[bone_name];
- // insert all nodes down to the root or mesh node
- while (
- parent
- && parent != mScene->mRootNode
- && parent != mesh_node
- ) {
- skeleton.insert(parent);
- parent = parent->mParent;
- }
- }
-
- // number of pose nodes. includes one for the mesh itself.
- bpnode.AddChild("NbPoseNodes", int32_t(1 + skeleton.size()));
-
- // the first pose node is always the mesh itself
- FBX::Node pose("PoseNode");
- pose.AddChild("Node", mesh_uids[mi]);
- aiMatrix4x4 mesh_node_xform = get_world_transform(mesh_node, mScene);
- pose.AddChild("Matrix", mesh_node_xform);
- bpnode.AddChild(pose);
-
- for (aiNode* bonenode : skeleton) {
- // does this node have a uid yet?
- int64_t node_uid;
- auto node_uid_iter = node_uids.find(bonenode);
- if (node_uid_iter != node_uids.end()) {
- node_uid = node_uid_iter->second;
- } else {
- node_uid = generate_uid();
- node_uids[bonenode] = node_uid;
- }
-
- // make a pose thingy
- pose = FBX::Node("PoseNode");
- pose.AddChild("Node", node_uid);
- aiMatrix4x4 node_xform = get_world_transform(bonenode, mScene);
- pose.AddChild("Matrix", node_xform);
- bpnode.AddChild(pose);
- }
-
- // now write it
- bpnode.Dump(outstream, binary, indent);
- }*/
-
- // TODO: cameras, lights
-
- // write nodes (i.e. model hierarchy)
- // start at root node
- WriteModelNodes(
- outstream, mScene->mRootNode, 0, limbnodes
- );
-
- // animations
- //
- // in FBX there are:
- // * AnimationStack - corresponds to an aiAnimation
- // * AnimationLayer - a combinable animation component
- // * AnimationCurveNode - links the property to be animated
- // * AnimationCurve - defines animation data for a single property value
- //
- // the CurveNode also provides the default value for a property,
- // such as the X, Y, Z coordinates for animatable translation.
- //
- // the Curve only specifies values for one component of the property,
- // so there will be a separate AnimationCurve for X, Y, and Z.
- //
- // Assimp has:
- // * aiAnimation - basically corresponds to an AnimationStack
- // * aiNodeAnim - defines all animation for one aiNode
- // * aiVectorKey/aiQuatKey - define the keyframe data for T/R/S
- //
- // assimp has no equivalent for AnimationLayer,
- // and these are flattened on FBX import.
- // we can assume there will be one per AnimationStack.
- //
- // the aiNodeAnim contains all animation data for a single aiNode,
- // which will correspond to three AnimationCurveNode's:
- // one each for translation, rotation and scale.
- // The data for each of these will be put in 9 AnimationCurve's,
- // T.X, T.Y, T.Z, R.X, R.Y, R.Z, etc.
-
- // AnimationStack / aiAnimation
- std::vector<int64_t> animation_stack_uids(mScene->mNumAnimations);
- for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) {
- int64_t animstack_uid = generate_uid();
- animation_stack_uids[ai] = animstack_uid;
- const aiAnimation* anim = mScene->mAnimations[ai];
-
- FBX::Node asnode("AnimationStack");
- std::string name = anim->mName.C_Str() + FBX::SEPARATOR + "AnimStack";
- asnode.AddProperties(animstack_uid, name, "");
- FBX::Node p("Properties70");
- p.AddP70time("LocalStart", 0); // assimp doesn't store this
- p.AddP70time("LocalStop", to_ktime(anim->mDuration, anim));
- p.AddP70time("ReferenceStart", 0);
- p.AddP70time("ReferenceStop", to_ktime(anim->mDuration, anim));
- asnode.AddChild(p);
-
- // this node absurdly always pretends it has children
- // (in this case it does, but just in case...)
- asnode.force_has_children = true;
- asnode.Dump(outstream, binary, indent);
-
- // note: animation stacks are not connected to anything
- }
-
- // AnimationLayer - one per aiAnimation
- std::vector<int64_t> animation_layer_uids(mScene->mNumAnimations);
- for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) {
- int64_t animlayer_uid = generate_uid();
- animation_layer_uids[ai] = animlayer_uid;
- FBX::Node alnode("AnimationLayer");
- alnode.AddProperties(animlayer_uid, FBX::SEPARATOR + "AnimLayer", "");
-
- // this node absurdly always pretends it has children
- alnode.force_has_children = true;
- alnode.Dump(outstream, binary, indent);
-
- // connect to the relevant animstack
- connections.emplace_back(
- "C", "OO", animlayer_uid, animation_stack_uids[ai]
- );
- }
-
- // AnimCurveNode - three per aiNodeAnim
- std::vector<std::vector<std::array<int64_t,3>>> curve_node_uids;
- for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) {
- const aiAnimation* anim = mScene->mAnimations[ai];
- const int64_t layer_uid = animation_layer_uids[ai];
- std::vector<std::array<int64_t,3>> nodeanim_uids;
- for (size_t nai = 0; nai < anim->mNumChannels; ++nai) {
- const aiNodeAnim* na = anim->mChannels[nai];
- // get the corresponding aiNode
- const aiNode* node = mScene->mRootNode->FindNode(na->mNodeName);
- // and its transform
- const aiMatrix4x4 node_xfm = get_world_transform(node, mScene);
- aiVector3D T, R, S;
- node_xfm.Decompose(S, R, T);
-
- // AnimationCurveNode uids
- std::array<int64_t,3> ids;
- ids[0] = generate_uid(); // T
- ids[1] = generate_uid(); // R
- ids[2] = generate_uid(); // S
-
- // translation
- WriteAnimationCurveNode(outstream,
- ids[0], "T", T, "Lcl Translation",
- layer_uid, node_uids[node]
- );
-
- // rotation
- WriteAnimationCurveNode(outstream,
- ids[1], "R", R, "Lcl Rotation",
- layer_uid, node_uids[node]
- );
-
- // scale
- WriteAnimationCurveNode(outstream,
- ids[2], "S", S, "Lcl Scale",
- layer_uid, node_uids[node]
- );
-
- // store the uids for later use
- nodeanim_uids.push_back(ids);
- }
- curve_node_uids.push_back(nodeanim_uids);
- }
-
- // AnimCurve - defines actual keyframe data.
- // there's a separate curve for every component of every vector,
- // for example a transform curvenode will have separate X/Y/Z AnimCurve's
- for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) {
- const aiAnimation* anim = mScene->mAnimations[ai];
- for (size_t nai = 0; nai < anim->mNumChannels; ++nai) {
- const aiNodeAnim* na = anim->mChannels[nai];
- // get the corresponding aiNode
- const aiNode* node = mScene->mRootNode->FindNode(na->mNodeName);
- // and its transform
- const aiMatrix4x4 node_xfm = get_world_transform(node, mScene);
- aiVector3D T, R, S;
- node_xfm.Decompose(S, R, T);
- const std::array<int64_t,3>& ids = curve_node_uids[ai][nai];
-
- std::vector<int64_t> times;
- std::vector<float> xval, yval, zval;
-
- // position/translation
- for (size_t ki = 0; ki < na->mNumPositionKeys; ++ki) {
- const aiVectorKey& k = na->mPositionKeys[ki];
- times.push_back(to_ktime(k.mTime));
- xval.push_back(k.mValue.x);
- yval.push_back(k.mValue.y);
- zval.push_back(k.mValue.z);
- }
- // one curve each for X, Y, Z
- WriteAnimationCurve(outstream, T.x, times, xval, ids[0], "d|X");
- WriteAnimationCurve(outstream, T.y, times, yval, ids[0], "d|Y");
- WriteAnimationCurve(outstream, T.z, times, zval, ids[0], "d|Z");
-
- // rotation
- times.clear(); xval.clear(); yval.clear(); zval.clear();
- for (size_t ki = 0; ki < na->mNumRotationKeys; ++ki) {
- const aiQuatKey& k = na->mRotationKeys[ki];
- times.push_back(to_ktime(k.mTime));
- // TODO: aiQuaternion method to convert to Euler...
- aiMatrix4x4 m(k.mValue.GetMatrix());
- aiVector3D qs, qr, qt;
- m.Decompose(qs, qr, qt);
- qr *= DEG;
- xval.push_back(qr.x);
- yval.push_back(qr.y);
- zval.push_back(qr.z);
- }
- WriteAnimationCurve(outstream, R.x, times, xval, ids[1], "d|X");
- WriteAnimationCurve(outstream, R.y, times, yval, ids[1], "d|Y");
- WriteAnimationCurve(outstream, R.z, times, zval, ids[1], "d|Z");
-
- // scaling/scale
- times.clear(); xval.clear(); yval.clear(); zval.clear();
- for (size_t ki = 0; ki < na->mNumScalingKeys; ++ki) {
- const aiVectorKey& k = na->mScalingKeys[ki];
- times.push_back(to_ktime(k.mTime));
- xval.push_back(k.mValue.x);
- yval.push_back(k.mValue.y);
- zval.push_back(k.mValue.z);
- }
- WriteAnimationCurve(outstream, S.x, times, xval, ids[2], "d|X");
- WriteAnimationCurve(outstream, S.y, times, yval, ids[2], "d|Y");
- WriteAnimationCurve(outstream, S.z, times, zval, ids[2], "d|Z");
- }
- }
-
- indent = 0;
- object_node.End(outstream, binary, indent, true);
-}
-
-// convenience map of magic node name strings to FBX properties,
-// including the expected type of transform.
-const std::map<std::string,std::pair<std::string,char>> transform_types = {
- {"Translation", {"Lcl Translation", 't'}},
- {"RotationOffset", {"RotationOffset", 't'}},
- {"RotationPivot", {"RotationPivot", 't'}},
- {"PreRotation", {"PreRotation", 'r'}},
- {"Rotation", {"Lcl Rotation", 'r'}},
- {"PostRotation", {"PostRotation", 'r'}},
- {"RotationPivotInverse", {"RotationPivotInverse", 'i'}},
- {"ScalingOffset", {"ScalingOffset", 't'}},
- {"ScalingPivot", {"ScalingPivot", 't'}},
- {"Scaling", {"Lcl Scaling", 's'}},
- {"ScalingPivotInverse", {"ScalingPivotInverse", 'i'}},
- {"GeometricScaling", {"GeometricScaling", 's'}},
- {"GeometricRotation", {"GeometricRotation", 'r'}},
- {"GeometricTranslation", {"GeometricTranslation", 't'}},
- {"GeometricTranslationInverse", {"GeometricTranslationInverse", 'i'}},
- {"GeometricRotationInverse", {"GeometricRotationInverse", 'i'}},
- {"GeometricScalingInverse", {"GeometricScalingInverse", 'i'}}
-};
-
-// write a single model node to the stream
-void FBXExporter::WriteModelNode(
- StreamWriterLE& outstream,
- bool binary,
- const aiNode* node,
- int64_t node_uid,
- const std::string& type,
- const std::vector<std::pair<std::string,aiVector3D>>& transform_chain,
- TransformInheritance inherit_type
-){
- const aiVector3D zero = {0, 0, 0};
- const aiVector3D one = {1, 1, 1};
- FBX::Node m("Model");
- std::string name = node->mName.C_Str() + FBX::SEPARATOR + "Model";
- m.AddProperties(node_uid, name, type);
- m.AddChild("Version", int32_t(232));
- FBX::Node p("Properties70");
- p.AddP70bool("RotationActive", 1);
- p.AddP70int("DefaultAttributeIndex", 0);
- p.AddP70enum("InheritType", inherit_type);
- if (transform_chain.empty()) {
- // decompose 4x4 transform matrix into TRS
- aiVector3D t, r, s;
- node->mTransformation.Decompose(s, r, t);
- if (t != zero) {
- p.AddP70(
- "Lcl Translation", "Lcl Translation", "", "A",
- double(t.x), double(t.y), double(t.z)
- );
- }
- if (r != zero) {
- p.AddP70(
- "Lcl Rotation", "Lcl Rotation", "", "A",
- double(DEG*r.x), double(DEG*r.y), double(DEG*r.z)
- );
- }
- if (s != one) {
- p.AddP70(
- "Lcl Scaling", "Lcl Scaling", "", "A",
- double(s.x), double(s.y), double(s.z)
- );
- }
- } else {
- // apply the transformation chain.
- // these transformation elements are created when importing FBX,
- // which has a complex transformation hierarchy for each node.
- // as such we can bake the hierarchy back into the node on export.
- for (auto &item : transform_chain) {
- auto elem = transform_types.find(item.first);
- if (elem == transform_types.end()) {
- // then this is a bug
- std::stringstream err;
- err << "unrecognized FBX transformation type: ";
- err << item.first;
- throw DeadlyExportError(err.str());
- }
- const std::string &name = elem->second.first;
- const aiVector3D &v = item.second;
- if (name.compare(0, 4, "Lcl ") == 0) {
- // special handling for animatable properties
- p.AddP70(
- name, name, "", "A",
- double(v.x), double(v.y), double(v.z)
- );
- } else {
- p.AddP70vector(name, v.x, v.y, v.z);
- }
- }
- }
- m.AddChild(p);
-
- // not sure what these are for,
- // but they seem to be omnipresent
- m.AddChild("Shading", FBXExportProperty(true));
- m.AddChild("Culling", FBXExportProperty("CullingOff"));
-
- m.Dump(outstream, binary, 1);
-}
-
-// wrapper for WriteModelNodes to create and pass a blank transform chain
-void FBXExporter::WriteModelNodes(
- StreamWriterLE& s,
- const aiNode* node,
- int64_t parent_uid,
- const std::unordered_set<const aiNode*>& limbnodes
-) {
- std::vector<std::pair<std::string,aiVector3D>> chain;
- WriteModelNodes(s, node, parent_uid, limbnodes, chain);
-}
-
-void FBXExporter::WriteModelNodes(
- StreamWriterLE& outstream,
- const aiNode* node,
- int64_t parent_uid,
- const std::unordered_set<const aiNode*>& limbnodes,
- std::vector<std::pair<std::string,aiVector3D>>& transform_chain
-) {
- // first collapse any expanded transformation chains created by FBX import.
- std::string node_name(node->mName.C_Str());
- if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
- auto pos = node_name.find(MAGIC_NODE_TAG) + MAGIC_NODE_TAG.size() + 1;
- std::string type_name = node_name.substr(pos);
- auto elem = transform_types.find(type_name);
- if (elem == transform_types.end()) {
- // then this is a bug and should be fixed
- std::stringstream err;
- err << "unrecognized FBX transformation node";
- err << " of type " << type_name << " in node " << node_name;
- throw DeadlyExportError(err.str());
- }
- aiVector3D t, r, s;
- node->mTransformation.Decompose(s, r, t);
- switch (elem->second.second) {
- case 'i': // inverse
- // we don't need to worry about the inverse matrices
- break;
- case 't': // translation
- transform_chain.emplace_back(elem->first, t);
- break;
- case 'r': // rotation
- r *= float(DEG);
- transform_chain.emplace_back(elem->first, r);
- break;
- case 's': // scale
- transform_chain.emplace_back(elem->first, s);
- break;
- default:
- // this should never happen
- std::stringstream err;
- err << "unrecognized FBX transformation type code: ";
- err << elem->second.second;
- throw DeadlyExportError(err.str());
- }
- // now continue on to any child nodes
- for (unsigned i = 0; i < node->mNumChildren; ++i) {
- WriteModelNodes(
- outstream,
- node->mChildren[i],
- parent_uid,
- limbnodes,
- transform_chain
- );
- }
- return;
- }
-
- int64_t node_uid = 0;
- // generate uid and connect to parent, if not the root node,
- if (node != mScene->mRootNode) {
- auto elem = node_uids.find(node);
- if (elem != node_uids.end()) {
- node_uid = elem->second;
- } else {
- node_uid = generate_uid();
- node_uids[node] = node_uid;
- }
- connections.emplace_back("C", "OO", node_uid, parent_uid);
- }
-
- // what type of node is this?
- if (node == mScene->mRootNode) {
- // handled later
- } else if (node->mNumMeshes == 1) {
- // connect to child mesh, which should have been written previously
- connections.emplace_back(
- "C", "OO", mesh_uids[node->mMeshes[0]], node_uid
- );
- // also connect to the material for the child mesh
- connections.emplace_back(
- "C", "OO",
- material_uids[mScene->mMeshes[node->mMeshes[0]]->mMaterialIndex],
- node_uid
- );
- // write model node
- WriteModelNode(
- outstream, binary, node, node_uid, "Mesh", transform_chain
- );
- } else if (limbnodes.count(node)) {
- WriteModelNode(
- outstream, binary, node, node_uid, "LimbNode", transform_chain
- );
- // we also need to write a nodeattribute to mark it as a skeleton
- int64_t node_attribute_uid = generate_uid();
- FBX::Node na("NodeAttribute");
- na.AddProperties(
- node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode"
- );
- na.AddChild("TypeFlags", FBXExportProperty("Skeleton"));
- na.Dump(outstream, binary, 1);
- // and connect them
- connections.emplace_back("C", "OO", node_attribute_uid, node_uid);
- } else {
- // generate a null node so we can add children to it
- WriteModelNode(
- outstream, binary, node, node_uid, "Null", transform_chain
- );
- }
-
- // if more than one child mesh, make nodes for each mesh
- if (node->mNumMeshes > 1 || node == mScene->mRootNode) {
- for (size_t i = 0; i < node->mNumMeshes; ++i) {
- // make a new model node
- int64_t new_node_uid = generate_uid();
- // connect to parent node
- connections.emplace_back("C", "OO", new_node_uid, node_uid);
- // connect to child mesh, which should have been written previously
- connections.emplace_back(
- "C", "OO", mesh_uids[node->mMeshes[i]], new_node_uid
- );
- // also connect to the material for the child mesh
- connections.emplace_back(
- "C", "OO",
- material_uids[
- mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex
- ],
- new_node_uid
- );
- // write model node
- FBX::Node m("Model");
- // take name from mesh name, if it exists
- std::string name = mScene->mMeshes[node->mMeshes[i]]->mName.C_Str();
- name += FBX::SEPARATOR + "Model";
- m.AddProperties(new_node_uid, name, "Mesh");
- m.AddChild("Version", int32_t(232));
- FBX::Node p("Properties70");
- p.AddP70enum("InheritType", 1);
- m.AddChild(p);
- m.Dump(outstream, binary, 1);
- }
- }
-
- // now recurse into children
- for (size_t i = 0; i < node->mNumChildren; ++i) {
- WriteModelNodes(
- outstream, node->mChildren[i], node_uid, limbnodes
- );
- }
-}
-
-
-void FBXExporter::WriteAnimationCurveNode(
- StreamWriterLE& outstream,
- int64_t uid,
- const std::string& name, // "T", "R", or "S"
- aiVector3D default_value,
- std::string property_name, // "Lcl Translation" etc
- int64_t layer_uid,
- int64_t node_uid
-) {
- FBX::Node n("AnimationCurveNode");
- n.AddProperties(uid, name + FBX::SEPARATOR + "AnimCurveNode", "");
- FBX::Node p("Properties70");
- p.AddP70numberA("d|X", default_value.x);
- p.AddP70numberA("d|Y", default_value.y);
- p.AddP70numberA("d|Z", default_value.z);
- n.AddChild(p);
- n.Dump(outstream, binary, 1);
- // connect to layer
- this->connections.emplace_back("C", "OO", uid, layer_uid);
- // connect to bone
- this->connections.emplace_back("C", "OP", uid, node_uid, property_name);
-}
-
-
-void FBXExporter::WriteAnimationCurve(
- StreamWriterLE& outstream,
- double default_value,
- const std::vector<int64_t>& times,
- const std::vector<float>& values,
- int64_t curvenode_uid,
- const std::string& property_link // "d|X", "d|Y", etc
-) {
- FBX::Node n("AnimationCurve");
- int64_t curve_uid = generate_uid();
- n.AddProperties(curve_uid, FBX::SEPARATOR + "AnimCurve", "");
- n.AddChild("Default", default_value);
- n.AddChild("KeyVer", int32_t(4009));
- n.AddChild("KeyTime", times);
- n.AddChild("KeyValueFloat", values);
- // TODO: keyattr flags and data (STUB for now)
- n.AddChild("KeyAttrFlags", std::vector<int32_t>{0});
- n.AddChild("KeyAttrDataFloat", std::vector<float>{0,0,0,0});
- n.AddChild(
- "KeyAttrRefCount",
- std::vector<int32_t>{static_cast<int32_t>(times.size())}
- );
- n.Dump(outstream, binary, 1);
- this->connections.emplace_back(
- "C", "OP", curve_uid, curvenode_uid, property_link
- );
-}
-
-
-void FBXExporter::WriteConnections ()
-{
- // we should have completed the connection graph already,
- // so basically just dump it here
- if (!binary) {
- WriteAsciiSectionHeader("Object connections");
- }
- // TODO: comments with names in the ascii version
- FBX::Node conn("Connections");
- StreamWriterLE outstream(outfile);
- conn.Begin(outstream, binary, 0);
- conn.BeginChildren(outstream, binary, 0);
- for (auto &n : connections) {
- n.Dump(outstream, binary, 1);
- }
- conn.End(outstream, binary, 0, !connections.empty());
- connections.clear();
-}
-
-#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
-#endif // ASSIMP_BUILD_NO_EXPORT
diff --git a/thirdparty/assimp/code/FBX/FBXExporter.h b/thirdparty/assimp/code/FBX/FBXExporter.h
deleted file mode 100644
index 1ae727eda9..0000000000
--- a/thirdparty/assimp/code/FBX/FBXExporter.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXExporter.h
-* Declares the exporter class to write a scene to an fbx file
-*/
-#ifndef AI_FBXEXPORTER_H_INC
-#define AI_FBXEXPORTER_H_INC
-
-#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#include "FBXExportNode.h" // FBX::Node
-#include "FBXCommon.h" // FBX::TransformInheritance
-
-#include <assimp/types.h>
-//#include <assimp/material.h>
-#include <assimp/StreamWriter.h> // StreamWriterLE
-#include <assimp/Exceptional.h> // DeadlyExportError
-
-#include <vector>
-#include <map>
-#include <unordered_set>
-#include <memory> // shared_ptr
-#include <sstream> // stringstream
-
-struct aiScene;
-struct aiNode;
-//struct aiMaterial;
-
-namespace Assimp
-{
- class IOSystem;
- class IOStream;
- class ExportProperties;
-
- // ---------------------------------------------------------------------
- /** Helper class to export a given scene to an FBX file. */
- // ---------------------------------------------------------------------
- class FBXExporter
- {
- public:
- /// Constructor for a specific scene to export
- FBXExporter(const aiScene* pScene, const ExportProperties* pProperties);
-
- // call one of these methods to export
- void ExportBinary(const char* pFile, IOSystem* pIOSystem);
- void ExportAscii(const char* pFile, IOSystem* pIOSystem);
-
- private:
- bool binary; // whether current export is in binary or ascii format
- const aiScene* mScene; // the scene to export
- const ExportProperties* mProperties; // currently unused
- std::shared_ptr<IOStream> outfile; // file to write to
-
- std::vector<FBX::Node> connections; // connection storage
-
- std::vector<int64_t> mesh_uids;
- std::vector<int64_t> material_uids;
- std::map<const aiNode*,int64_t> node_uids;
-
- // this crude unique-ID system is actually fine
- int64_t last_uid = 999999;
- int64_t generate_uid() { return ++last_uid; }
-
- // binary files have a specific header and footer,
- // in addition to the actual data
- void WriteBinaryHeader();
- void WriteBinaryFooter();
-
- // ascii files have a comment at the top
- void WriteAsciiHeader();
-
- // WriteAllNodes does the actual export.
- // It just calls all the Write<Section> methods below in order.
- void WriteAllNodes();
-
- // Methods to write individual sections.
- // The order here matches the order inside an FBX file.
- // Each method corresponds to a top-level FBX section,
- // except WriteHeader which also includes some binary-only sections
- // and WriteFooter which is binary data only.
- void WriteHeaderExtension();
- // WriteFileId(); // binary-only, included in WriteHeader
- // WriteCreationTime(); // binary-only, included in WriteHeader
- // WriteCreator(); // binary-only, included in WriteHeader
- void WriteGlobalSettings();
- void WriteDocuments();
- void WriteReferences();
- void WriteDefinitions();
- void WriteObjects();
- void WriteConnections();
- // WriteTakes(); // deprecated since at least 2015 (fbx 7.4)
-
- // helpers
- void WriteAsciiSectionHeader(const std::string& title);
- void WriteModelNodes(
- Assimp::StreamWriterLE& s,
- const aiNode* node,
- int64_t parent_uid,
- const std::unordered_set<const aiNode*>& limbnodes
- );
- void WriteModelNodes( // usually don't call this directly
- StreamWriterLE& s,
- const aiNode* node,
- int64_t parent_uid,
- const std::unordered_set<const aiNode*>& limbnodes,
- std::vector<std::pair<std::string,aiVector3D>>& transform_chain
- );
- void WriteModelNode( // nor this
- StreamWriterLE& s,
- bool binary,
- const aiNode* node,
- int64_t node_uid,
- const std::string& type,
- const std::vector<std::pair<std::string,aiVector3D>>& xfm_chain,
- FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs
- );
- void WriteAnimationCurveNode(
- StreamWriterLE& outstream,
- int64_t uid,
- const std::string& name, // "T", "R", or "S"
- aiVector3D default_value,
- std::string property_name, // "Lcl Translation" etc
- int64_t animation_layer_uid,
- int64_t node_uid
- );
- void WriteAnimationCurve(
- StreamWriterLE& outstream,
- double default_value,
- const std::vector<int64_t>& times,
- const std::vector<float>& values,
- int64_t curvenode_id,
- const std::string& property_link // "d|X", "d|Y", etc
- );
- };
-}
-
-#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
-
-#endif // AI_FBXEXPORTER_H_INC
diff --git a/thirdparty/assimp/code/FBX/FBXImportSettings.h b/thirdparty/assimp/code/FBX/FBXImportSettings.h
deleted file mode 100644
index 1a4c80f8b2..0000000000
--- a/thirdparty/assimp/code/FBX/FBXImportSettings.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXImportSettings.h
- * @brief FBX importer runtime configuration
- */
-#ifndef INCLUDED_AI_FBX_IMPORTSETTINGS_H
-#define INCLUDED_AI_FBX_IMPORTSETTINGS_H
-
-namespace Assimp {
-namespace FBX {
-
-/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
-struct ImportSettings
-{
- ImportSettings()
- : strictMode(true)
- , readAllLayers(true)
- , readAllMaterials(false)
- , readMaterials(true)
- , readTextures(true)
- , readCameras(true)
- , readLights(true)
- , readAnimations(true)
- , readWeights(true)
- , preservePivots(true)
- , optimizeEmptyAnimationCurves(true)
- , useLegacyEmbeddedTextureNaming(false)
- , removeEmptyBones( true )
- , convertToMeters( false ) {
- // empty
- }
-
-
- /** enable strict mode:
- * - only accept fbx 2012, 2013 files
- * - on the slightest error, give up.
- *
- * Basically, strict mode means that the fbx file will actually
- * be validated. Strict mode is off by default. */
- bool strictMode;
-
- /** specifies whether all geometry layers are read and scanned for
- * usable data channels. The FBX spec indicates that many readers
- * will only read the first channel and that this is in some way
- * the recommended way- in reality, however, it happens a lot that
- * vertex data is spread among multiple layers. The default
- * value for this option is true.*/
- bool readAllLayers;
-
- /** specifies whether all materials are read, or only those that
- * are referenced by at least one mesh. Reading all materials
- * may make FBX reading a lot slower since all objects
- * need to be processed .
- * This bit is ignored unless readMaterials=true*/
- bool readAllMaterials;
-
-
- /** import materials (true) or skip them and assign a default
- * material. The default value is true.*/
- bool readMaterials;
-
- /** import embedded textures? Default value is true.*/
- bool readTextures;
-
- /** import cameras? Default value is true.*/
- bool readCameras;
-
- /** import light sources? Default value is true.*/
- bool readLights;
-
- /** import animations (i.e. animation curves, the node
- * skeleton is always imported). Default value is true. */
- bool readAnimations;
-
- /** read bones (vertex weights and deform info).
- * Default value is true. */
- bool readWeights;
-
- /** preserve transformation pivots and offsets. Since these can
- * not directly be represented in assimp, additional dummy
- * nodes will be generated. Note that settings this to false
- * can make animation import a lot slower. The default value
- * is true.
- *
- * The naming scheme for the generated nodes is:
- * <OriginalName>_$AssimpFbx$_<TransformName>
- *
- * where <TransformName> is one of
- * RotationPivot
- * RotationOffset
- * PreRotation
- * PostRotation
- * ScalingPivot
- * ScalingOffset
- * Translation
- * Scaling
- * Rotation
- **/
- bool preservePivots;
-
- /** do not import animation curves that specify a constant
- * values matching the corresponding node transformation.
- * The default value is true. */
- bool optimizeEmptyAnimationCurves;
-
- /** use legacy naming for embedded textures eg: (*0, *1, *2)
- */
- bool useLegacyEmbeddedTextureNaming;
-
- /** Empty bones shall be removed
- */
- bool removeEmptyBones;
-
- /** Set to true to perform a conversion from cm to meter after the import
- */
- bool convertToMeters;
-};
-
-
-} // !FBX
-} // !Assimp
-
-#endif
-
diff --git a/thirdparty/assimp/code/FBX/FBXImporter.cpp b/thirdparty/assimp/code/FBX/FBXImporter.cpp
deleted file mode 100644
index afcc1ddc78..0000000000
--- a/thirdparty/assimp/code/FBX/FBXImporter.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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.
-r
-* 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 FBXImporter.cpp
- * @brief Implementation of the FBX importer.
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include "FBXImporter.h"
-
-#include "FBXConverter.h"
-#include "FBXDocument.h"
-#include "FBXParser.h"
-#include "FBXTokenizer.h"
-#include "FBXUtil.h"
-
-#include <assimp/MemoryIOWrapper.h>
-#include <assimp/StreamReader.h>
-#include <assimp/importerdesc.h>
-#include <assimp/Importer.hpp>
-
-namespace Assimp {
-
-template <>
-const char *LogFunctions<FBXImporter>::Prefix() {
- static auto prefix = "FBX: ";
- return prefix;
-}
-
-} // namespace Assimp
-
-using namespace Assimp;
-using namespace Assimp::Formatter;
-using namespace Assimp::FBX;
-
-namespace {
-
-static const aiImporterDesc desc = {
- "Autodesk FBX Importer",
- "",
- "",
- "",
- aiImporterFlags_SupportTextFlavour,
- 0,
- 0,
- 0,
- 0,
- "fbx"
-};
-}
-
-// ------------------------------------------------------------------------------------------------
-// Constructor to be privately used by #Importer
-FBXImporter::FBXImporter() {
-}
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-FBXImporter::~FBXImporter() {
-}
-
-// ------------------------------------------------------------------------------------------------
-// Returns whether the class can handle the format of the given file.
-bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
- const std::string &extension = GetExtension(pFile);
- if (extension == std::string(desc.mFileExtensions)) {
- return true;
- }
-
- else if ((!extension.length() || checkSig) && pIOHandler) {
- // at least ASCII-FBX files usually have a 'FBX' somewhere in their head
- const char *tokens[] = { "fbx" };
- return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
- }
- return false;
-}
-
-// ------------------------------------------------------------------------------------------------
-// List all extensions handled by this loader
-const aiImporterDesc *FBXImporter::GetInfo() const {
- return &desc;
-}
-
-// ------------------------------------------------------------------------------------------------
-// Setup configuration properties for the loader
-void FBXImporter::SetupProperties(const Importer *pImp) {
- settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
- settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
- settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
- settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
- settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
- settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
- settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
- settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
- settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
- settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
- settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
- settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
- settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
-}
-
-// ------------------------------------------------------------------------------------------------
-// Imports the given file into the given scene structure.
-void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
- std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
- if (!stream) {
- ThrowException("Could not open file for reading");
- }
-
- // read entire file into memory - no streaming for this, fbx
- // files can grow large, but the assimp output data structure
- // then becomes very large, too. Assimp doesn't support
- // streaming for its output data structures so the net win with
- // streaming input data would be very low.
- std::vector<char> contents;
- contents.resize(stream->FileSize() + 1);
- stream->Read(&*contents.begin(), 1, contents.size() - 1);
- contents[contents.size() - 1] = 0;
- const char *const begin = &*contents.begin();
-
- // broadphase tokenizing pass in which we identify the core
- // syntax elements of FBX (brackets, commas, key:value mappings)
- TokenList tokens;
- try {
-
- bool is_binary = false;
- if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
- is_binary = true;
- TokenizeBinary(tokens, begin, contents.size());
- } else {
- Tokenize(tokens, begin);
- }
-
- // use this information to construct a very rudimentary
- // parse-tree representing the FBX scope structure
- Parser parser(tokens, is_binary);
-
- // take the raw parse-tree and convert it to a FBX DOM
- Document doc(parser, settings);
-
- // convert the FBX DOM to aiScene
- ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
-
- // size relative to cm
- float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
-
- // Set FBX file scale is relative to CM must be converted to M for
- // assimp universal format (M)
- SetFileScale(size_relative_to_cm * 0.01f);
-
- std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
- } catch (std::exception &) {
- std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
- throw;
- }
-}
-
-#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER
diff --git a/thirdparty/assimp/code/FBX/FBXImporter.h b/thirdparty/assimp/code/FBX/FBXImporter.h
deleted file mode 100644
index c365b2cddf..0000000000
--- a/thirdparty/assimp/code/FBX/FBXImporter.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXImporter.h
- * @brief Declaration of the FBX main importer class
- */
-#ifndef INCLUDED_AI_FBX_IMPORTER_H
-#define INCLUDED_AI_FBX_IMPORTER_H
-
-#include <assimp/BaseImporter.h>
-#include <assimp/LogAux.h>
-
-#include "FBXImportSettings.h"
-
-namespace Assimp {
-
-// TinyFormatter.h
-namespace Formatter {
- template <typename T,typename TR, typename A> class basic_formatter;
- typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format;
-}
-
-// -------------------------------------------------------------------------------------------
-/** Load the Autodesk FBX file format.
-
- See http://en.wikipedia.org/wiki/FBX
-*/
-// -------------------------------------------------------------------------------------------
-class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter>
-{
-public:
- FBXImporter();
- virtual ~FBXImporter();
-
- // --------------------
- bool CanRead( const std::string& pFile,
- IOSystem* pIOHandler,
- bool checkSig
- ) const;
-
-protected:
-
- // --------------------
- const aiImporterDesc* GetInfo () const;
-
- // --------------------
- void SetupProperties(const Importer* pImp);
-
- // --------------------
- void InternReadFile( const std::string& pFile,
- aiScene* pScene,
- IOSystem* pIOHandler
- );
-
-private:
- FBX::ImportSettings settings;
-}; // !class FBXImporter
-
-} // end of namespace Assimp
-#endif // !INCLUDED_AI_FBX_IMPORTER_H
-
diff --git a/thirdparty/assimp/code/FBX/FBXMaterial.cpp b/thirdparty/assimp/code/FBX/FBXMaterial.cpp
deleted file mode 100644
index f43a8b84b0..0000000000
--- a/thirdparty/assimp/code/FBX/FBXMaterial.cpp
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXMaterial.cpp
- * @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include "FBXParser.h"
-#include "FBXDocument.h"
-#include "FBXImporter.h"
-#include "FBXImportSettings.h"
-#include "FBXDocumentUtil.h"
-#include "FBXProperties.h"
-#include <assimp/ByteSwapper.h>
-
-#include <algorithm> // std::transform
-#include "FBXUtil.h"
-
-namespace Assimp {
-namespace FBX {
-
- using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Material::Material(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: Object(id,element,name)
-{
- const Scope& sc = GetRequiredScope(element);
-
- const Element* const ShadingModel = sc["ShadingModel"];
- const Element* const MultiLayer = sc["MultiLayer"];
-
- if(MultiLayer) {
- multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
- }
-
- if(ShadingModel) {
- shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
- }
- else {
- DOMWarning("shading mode not specified, assuming phong",&element);
- shading = "phong";
- }
-
- std::string templateName;
-
- // lower-case shading because Blender (for example) writes "Phong"
- std::transform(shading.begin(), shading.end(), shading.begin(), ::tolower);
- if(shading == "phong") {
- templateName = "Material.FbxSurfacePhong";
- }
- else if(shading == "lambert") {
- templateName = "Material.FbxSurfaceLambert";
- }
- else {
- DOMWarning("shading mode not recognized: " + shading,&element);
- }
-
- props = GetPropertyTable(doc,templateName,element,sc);
-
- // resolve texture links
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
- for(const Connection* con : conns) {
-
- // texture link to properties, not objects
- if (!con->PropertyName().length()) {
- continue;
- }
-
- const Object* const ob = con->SourceObject();
- if(!ob) {
- DOMWarning("failed to read source object for texture link, ignoring",&element);
- continue;
- }
-
- const Texture* const tex = dynamic_cast<const Texture*>(ob);
- if(!tex) {
- const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
- if(!layeredTexture) {
- DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
- continue;
- }
- const std::string& prop = con->PropertyName();
- if (layeredTextures.find(prop) != layeredTextures.end()) {
- DOMWarning("duplicate layered texture link: " + prop,&element);
- }
-
- layeredTextures[prop] = layeredTexture;
- ((LayeredTexture*)layeredTexture)->fillTexture(doc);
- }
- else
- {
- const std::string& prop = con->PropertyName();
- if (textures.find(prop) != textures.end()) {
- DOMWarning("duplicate texture link: " + prop,&element);
- }
-
- textures[prop] = tex;
- }
-
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Material::~Material()
-{
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: Object(id,element,name)
-, uvScaling(1.0f,1.0f)
-, media(0)
-{
- const Scope& sc = GetRequiredScope(element);
-
- const Element* const Type = sc["Type"];
- const Element* const FileName = sc["FileName"];
- const Element* const RelativeFilename = sc["RelativeFilename"];
- const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
- const Element* const ModelUVScaling = sc["ModelUVScaling"];
- const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
- const Element* const Cropping = sc["Cropping"];
-
- if(Type) {
- type = ParseTokenAsString(GetRequiredToken(*Type,0));
- }
-
- if(FileName) {
- fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
- }
-
- if(RelativeFilename) {
- relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
- }
-
- if(ModelUVTranslation) {
- uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
- ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
- );
- }
-
- if(ModelUVScaling) {
- uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
- ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
- );
- }
-
- if(Cropping) {
- crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
- crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
- crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
- crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
- }
- else {
- // vc8 doesn't support the crop() syntax in initialization lists
- // (and vc9 WARNS about the new (i.e. compliant) behaviour).
- crop[0] = crop[1] = crop[2] = crop[3] = 0;
- }
-
- if(Texture_Alpha_Source) {
- alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
- }
-
- props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
-
- // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
- bool ok;
- const aiVector3D& scaling = PropertyGet<aiVector3D>(*props, "Scaling", ok);
- if (ok) {
- uvScaling.x = scaling.x;
- uvScaling.y = scaling.y;
- }
-
- const aiVector3D& trans = PropertyGet<aiVector3D>(*props, "Translation", ok);
- if (ok) {
- uvTrans.x = trans.x;
- uvTrans.y = trans.y;
- }
-
- // resolve video links
- if(doc.Settings().readTextures) {
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
- for(const Connection* con : conns) {
- const Object* const ob = con->SourceObject();
- if(!ob) {
- DOMWarning("failed to read source object for texture link, ignoring",&element);
- continue;
- }
-
- const Video* const video = dynamic_cast<const Video*>(ob);
- if(video) {
- media = video;
- }
- }
- }
-}
-
-
-Texture::~Texture()
-{
-
-}
-
-LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& /*doc*/, const std::string& name)
-: Object(id,element,name)
-,blendMode(BlendMode_Modulate)
-,alpha(1)
-{
- const Scope& sc = GetRequiredScope(element);
-
- const Element* const BlendModes = sc["BlendModes"];
- const Element* const Alphas = sc["Alphas"];
-
-
- if(BlendModes!=0)
- {
- blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
- }
- if(Alphas!=0)
- {
- alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
- }
-}
-
-LayeredTexture::~LayeredTexture()
-{
-
-}
-
-void LayeredTexture::fillTexture(const Document& doc)
-{
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
- for(size_t i = 0; i < conns.size();++i)
- {
- const Connection* con = conns.at(i);
-
- const Object* const ob = con->SourceObject();
- if(!ob) {
- DOMWarning("failed to read source object for texture link, ignoring",&element);
- continue;
- }
-
- const Texture* const tex = dynamic_cast<const Texture*>(ob);
-
- textures.push_back(tex);
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: Object(id,element,name)
-, contentLength(0)
-, content(0)
-{
- const Scope& sc = GetRequiredScope(element);
-
- const Element* const Type = sc["Type"];
- const Element* const FileName = sc.FindElementCaseInsensitive("FileName"); //some files retain the information as "Filename", others "FileName", who knows
- const Element* const RelativeFilename = sc["RelativeFilename"];
- const Element* const Content = sc["Content"];
-
- if(Type) {
- type = ParseTokenAsString(GetRequiredToken(*Type,0));
- }
-
- if(FileName) {
- fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
- }
-
- if(RelativeFilename) {
- relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
- }
-
- if(Content && !Content->Tokens().empty()) {
- //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
- try {
- const Token& token = GetRequiredToken(*Content, 0);
- const char* data = token.begin();
- if (!token.IsBinary()) {
- if (*data != '"') {
- DOMError("embedded content is not surrounded by quotation marks", &element);
- }
- else {
- size_t targetLength = 0;
- auto numTokens = Content->Tokens().size();
- // First time compute size (it could be large like 64Gb and it is good to allocate it once)
- for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx)
- {
- const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
- size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
- const char* base64data = dataToken.begin() + 1;
- const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
- if (outLength == 0)
- {
- DOMError("Corrupted embedded content found", &element);
- }
- targetLength += outLength;
- }
- if (targetLength == 0)
- {
- DOMError("Corrupted embedded content found", &element);
- }
- content = new uint8_t[targetLength];
- contentLength = static_cast<uint64_t>(targetLength);
- size_t dst_offset = 0;
- for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx)
- {
- const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
- size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
- const char* base64data = dataToken.begin() + 1;
- dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
- }
- if (targetLength != dst_offset)
- {
- delete[] content;
- contentLength = 0;
- DOMError("Corrupted embedded content found", &element);
- }
- }
- }
- else if (static_cast<size_t>(token.end() - data) < 5) {
- DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
- }
- else if (*data != 'R') {
- DOMWarning("video content is not raw binary data, ignoring", &element);
- }
- else {
- // read number of elements
- uint32_t len = 0;
- ::memcpy(&len, data + 1, sizeof(len));
- AI_SWAP4(len);
-
- contentLength = len;
-
- content = new uint8_t[len];
- ::memcpy(content, data + 5, len);
- }
- } catch (const runtime_error& runtimeError)
- {
- //we don't need the content data for contents that has already been loaded
- ASSIMP_LOG_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ",
- runtimeError.what());
- }
- }
-
- props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
-}
-
-
-Video::~Video()
-{
- if(content) {
- delete[] content;
- }
-}
-
-} //!FBX
-} //!Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp b/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp
deleted file mode 100644
index 1386e2383c..0000000000
--- a/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXMeshGeometry.cpp
- * @brief Assimp::FBX::MeshGeometry implementation
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include <functional>
-
-#include "FBXMeshGeometry.h"
-#include "FBXDocument.h"
-#include "FBXImporter.h"
-#include "FBXImportSettings.h"
-#include "FBXDocumentUtil.h"
-
-
-namespace Assimp {
-namespace FBX {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
- : Object(id, element, name)
- , skin()
-{
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
- for(const Connection* con : conns) {
- const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
- if(sk) {
- skin = sk;
- }
- const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
- if (bsp) {
- blendShapes.push_back(bsp);
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Geometry::~Geometry()
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
- return blendShapes;
-}
-
-// ------------------------------------------------------------------------------------------------
-const Skin* Geometry::DeformerSkin() const {
- return skin;
-}
-
-// ------------------------------------------------------------------------------------------------
-MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
-: Geometry(id, element,name, doc)
-{
- const Scope* sc = element.Compound();
- if (!sc) {
- DOMError("failed to read Geometry object (class: Mesh), no data scope found");
- }
-
- // must have Mesh elements:
- const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
- const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
-
- // optional Mesh elements:
- const ElementCollection& Layer = sc->GetCollection("Layer");
-
- std::vector<aiVector3D> tempVerts;
- ParseVectorDataArray(tempVerts,Vertices);
-
- if(tempVerts.empty()) {
- FBXImporter::LogWarn("encountered mesh with no vertices");
- }
-
- std::vector<int> tempFaces;
- ParseVectorDataArray(tempFaces,PolygonVertexIndex);
-
- if(tempFaces.empty()) {
- FBXImporter::LogWarn("encountered mesh with no faces");
- }
-
- m_vertices.reserve(tempFaces.size());
- m_faces.reserve(tempFaces.size() / 3);
-
- m_mapping_offsets.resize(tempVerts.size());
- m_mapping_counts.resize(tempVerts.size(),0);
- m_mappings.resize(tempFaces.size());
-
- const size_t vertex_count = tempVerts.size();
-
- // generate output vertices, computing an adjacency table to
- // preserve the mapping from fbx indices to *this* indexing.
- unsigned int count = 0;
- for(int index : tempFaces) {
- const int absi = index < 0 ? (-index - 1) : index;
- if(static_cast<size_t>(absi) >= vertex_count) {
- DOMError("polygon vertex index out of range",&PolygonVertexIndex);
- }
-
- m_vertices.push_back(tempVerts[absi]);
- ++count;
-
- ++m_mapping_counts[absi];
-
- if (index < 0) {
- m_faces.push_back(count);
- count = 0;
- }
- }
-
- unsigned int cursor = 0;
- for (size_t i = 0, e = tempVerts.size(); i < e; ++i) {
- m_mapping_offsets[i] = cursor;
- cursor += m_mapping_counts[i];
-
- m_mapping_counts[i] = 0;
- }
-
- cursor = 0;
- for(int index : tempFaces) {
- const int absi = index < 0 ? (-index - 1) : index;
- m_mappings[m_mapping_offsets[absi] + m_mapping_counts[absi]++] = cursor++;
- }
-
- // if settings.readAllLayers is true:
- // * read all layers, try to load as many vertex channels as possible
- // if settings.readAllLayers is false:
- // * read only the layer with index 0, but warn about any further layers
- for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
- const TokenList& tokens = (*it).second->Tokens();
-
- const char* err;
- const int index = ParseTokenAsInt(*tokens[0], err);
- if(err) {
- DOMError(err,&element);
- }
-
- if(doc.Settings().readAllLayers || index == 0) {
- const Scope& layer = GetRequiredScope(*(*it).second);
- ReadLayer(layer);
- }
- else {
- FBXImporter::LogWarn("ignoring additional geometry layers");
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-MeshGeometry::~MeshGeometry() {
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
- return m_vertices;
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<aiVector3D>& MeshGeometry::GetNormals() const {
- return m_normals;
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<aiVector3D>& MeshGeometry::GetTangents() const {
- return m_tangents;
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<aiVector3D>& MeshGeometry::GetBinormals() const {
- return m_binormals;
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<unsigned int>& MeshGeometry::GetFaceIndexCounts() const {
- return m_faces;
-}
-
-// ------------------------------------------------------------------------------------------------
-const std::vector<aiVector2D>& MeshGeometry::GetTextureCoords( unsigned int index ) const {
- static const std::vector<aiVector2D> empty;
- return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[ index ];
-}
-
-std::string MeshGeometry::GetTextureCoordChannelName( unsigned int index ) const {
- return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[ index ];
-}
-
-const std::vector<aiColor4D>& MeshGeometry::GetVertexColors( unsigned int index ) const {
- static const std::vector<aiColor4D> empty;
- return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[ index ];
-}
-
-const MatIndexArray& MeshGeometry::GetMaterialIndices() const {
- return m_materials;
-}
-// ------------------------------------------------------------------------------------------------
-const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const {
- if ( in_index >= m_mapping_counts.size() ) {
- return NULL;
- }
-
- ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() );
- count = m_mapping_counts[ in_index ];
-
- ai_assert( m_mapping_offsets[ in_index ] + count <= m_mappings.size() );
-
- return &m_mappings[ m_mapping_offsets[ in_index ] ];
-}
-
-// ------------------------------------------------------------------------------------------------
-unsigned int MeshGeometry::FaceForVertexIndex( unsigned int in_index ) const {
- ai_assert( in_index < m_vertices.size() );
-
- // in the current conversion pattern this will only be needed if
- // weights are present, so no need to always pre-compute this table
- if ( m_facesVertexStartIndices.empty() ) {
- m_facesVertexStartIndices.resize( m_faces.size() + 1, 0 );
-
- std::partial_sum( m_faces.begin(), m_faces.end(), m_facesVertexStartIndices.begin() + 1 );
- m_facesVertexStartIndices.pop_back();
- }
-
- ai_assert( m_facesVertexStartIndices.size() == m_faces.size() );
- const std::vector<unsigned int>::iterator it = std::upper_bound(
- m_facesVertexStartIndices.begin(),
- m_facesVertexStartIndices.end(),
- in_index
- );
-
- return static_cast< unsigned int >( std::distance( m_facesVertexStartIndices.begin(), it - 1 ) );
-}
-
-// ------------------------------------------------------------------------------------------------
-void MeshGeometry::ReadLayer(const Scope& layer)
-{
- const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
- for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
- const Scope& elayer = GetRequiredScope(*(*eit).second);
-
- ReadLayerElement(elayer);
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-void MeshGeometry::ReadLayerElement(const Scope& layerElement)
-{
- const Element& Type = GetRequiredElement(layerElement,"Type");
- const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
-
- const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
- const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
-
- const Scope& top = GetRequiredScope(element);
- const ElementCollection candidates = top.GetCollection(type);
-
- for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
- const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
- if(index == typedIndex) {
- ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
- return;
- }
- }
-
- FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ")
- << type << ", index: " << typedIndex);
-}
-
-// ------------------------------------------------------------------------------------------------
-void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source)
-{
- const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
- GetRequiredElement(source,"MappingInformationType"),0)
- );
-
- const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
- GetRequiredElement(source,"ReferenceInformationType"),0)
- );
-
- if (type == "LayerElementUV") {
- if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
- FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ")
- << index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" );
- return;
- }
-
- const Element* Name = source["Name"];
- m_uvNames[index] = "";
- if(Name) {
- m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
- }
-
- ReadVertexDataUV(m_uvs[index],source,
- MappingInformationType,
- ReferenceInformationType
- );
- }
- else if (type == "LayerElementMaterial") {
- if (m_materials.size() > 0) {
- FBXImporter::LogError("ignoring additional material layer");
- return;
- }
-
- std::vector<int> temp_materials;
-
- ReadVertexDataMaterials(temp_materials,source,
- MappingInformationType,
- ReferenceInformationType
- );
-
- // sometimes, there will be only negative entries. Drop the material
- // layer in such a case (I guess it means a default material should
- // be used). This is what the converter would do anyway, and it
- // avoids losing the material if there are more material layers
- // coming of which at least one contains actual data (did observe
- // that with one test file).
- const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; });
- if(count_neg == temp_materials.size()) {
- FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
- return;
- }
-
- std::swap(temp_materials, m_materials);
- }
- else if (type == "LayerElementNormal") {
- if (m_normals.size() > 0) {
- FBXImporter::LogError("ignoring additional normal layer");
- return;
- }
-
- ReadVertexDataNormals(m_normals,source,
- MappingInformationType,
- ReferenceInformationType
- );
- }
- else if (type == "LayerElementTangent") {
- if (m_tangents.size() > 0) {
- FBXImporter::LogError("ignoring additional tangent layer");
- return;
- }
-
- ReadVertexDataTangents(m_tangents,source,
- MappingInformationType,
- ReferenceInformationType
- );
- }
- else if (type == "LayerElementBinormal") {
- if (m_binormals.size() > 0) {
- FBXImporter::LogError("ignoring additional binormal layer");
- return;
- }
-
- ReadVertexDataBinormals(m_binormals,source,
- MappingInformationType,
- ReferenceInformationType
- );
- }
- else if (type == "LayerElementColor") {
- if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
- FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ")
- << index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" );
- return;
- }
-
- ReadVertexDataColors(m_colors[index],source,
- MappingInformationType,
- ReferenceInformationType
- );
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// Lengthy utility function to read and resolve a FBX vertex data array - that is, the
-// output is in polygon vertex order. This logic is used for reading normals, UVs, colors,
-// tangents ..
-template <typename T>
-void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType,
- const char* dataElementName,
- const char* indexDataElementName,
- size_t vertex_count,
- const std::vector<unsigned int>& mapping_counts,
- const std::vector<unsigned int>& mapping_offsets,
- const std::vector<unsigned int>& mappings)
-{
- bool isDirect = ReferenceInformationType == "Direct";
- bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
-
- // fall-back to direct data if there is no index data element
- if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
- isDirect = true;
- isIndexToDirect = false;
- }
-
- // handle permutations of Mapping and Reference type - it would be nice to
- // deal with this more elegantly and with less redundancy, but right
- // now it seems unavoidable.
- if (MappingInformationType == "ByVertice" && isDirect) {
- if (!HasElement(source, dataElementName)) {
- return;
- }
- std::vector<T> tempData;
- ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
-
- data_out.resize(vertex_count);
- for (size_t i = 0, e = tempData.size(); i < e; ++i) {
-
- const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
- for (unsigned int j = istart; j < iend; ++j) {
- data_out[mappings[j]] = tempData[i];
- }
- }
- }
- else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
- std::vector<T> tempData;
- ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
-
- data_out.resize(vertex_count);
-
- std::vector<int> uvIndices;
- ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
- for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
-
- const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
- for (unsigned int j = istart; j < iend; ++j) {
- if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) {
- DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
- }
- data_out[mappings[j]] = tempData[uvIndices[i]];
- }
- }
- }
- else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
- std::vector<T> tempData;
- ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
-
- if (tempData.size() != vertex_count) {
- FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
- << tempData.size() << ", expected " << vertex_count
- );
- return;
- }
-
- data_out.swap(tempData);
- }
- else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
- std::vector<T> tempData;
- ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
-
- data_out.resize(vertex_count);
-
- std::vector<int> uvIndices;
- ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
-
- if (uvIndices.size() != vertex_count) {
- FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping");
- return;
- }
-
- const T empty;
- unsigned int next = 0;
- for(int i : uvIndices) {
- if ( -1 == i ) {
- data_out[ next++ ] = empty;
- continue;
- }
- if (static_cast<size_t>(i) >= tempData.size()) {
- DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
- }
-
- data_out[next++] = tempData[i];
- }
- }
- else {
- FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ")
- << MappingInformationType << "," << ReferenceInformationType);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType)
-{
- ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
- "Normals",
- "NormalsIndex",
- m_vertices.size(),
- m_mapping_counts,
- m_mapping_offsets,
- m_mappings);
-}
-
-// ------------------------------------------------------------------------------------------------
-void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType)
-{
- ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
- "UV",
- "UVIndex",
- m_vertices.size(),
- m_mapping_counts,
- m_mapping_offsets,
- m_mappings);
-}
-
-// ------------------------------------------------------------------------------------------------
-void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType)
-{
- ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType,
- "Colors",
- "ColorIndex",
- m_vertices.size(),
- m_mapping_counts,
- m_mapping_offsets,
- m_mappings);
-}
-
-// ------------------------------------------------------------------------------------------------
-static const char *TangentIndexToken = "TangentIndex";
-static const char *TangentsIndexToken = "TangentsIndex";
-
-void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType)
-{
- const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
- const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken;
- ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
- str,
- strIdx,
- m_vertices.size(),
- m_mapping_counts,
- m_mapping_offsets,
- m_mappings);
-}
-
-// ------------------------------------------------------------------------------------------------
-static const std::string BinormalIndexToken = "BinormalIndex";
-static const std::string BinormalsIndexToken = "BinormalsIndex";
-
-void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType)
-{
- const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
- const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str();
- ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
- str,
- strIdx,
- m_vertices.size(),
- m_mapping_counts,
- m_mapping_offsets,
- m_mappings);
-}
-
-
-// ------------------------------------------------------------------------------------------------
-void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType)
-{
- const size_t face_count = m_faces.size();
- if( 0 == face_count )
- {
- return;
- }
-
- // materials are handled separately. First of all, they are assigned per-face
- // and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
- // has a slightly different meaning for materials.
- ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials"));
-
- if (MappingInformationType == "AllSame") {
- // easy - same material for all faces
- if (materials_out.empty()) {
- FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
- return;
- } else if (materials_out.size() > 1) {
- FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
- materials_out.clear();
- }
-
- materials_out.resize(m_vertices.size());
- std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0));
- } else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
- materials_out.resize(face_count);
-
- if(materials_out.size() != face_count) {
- FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")
- << materials_out.size() << ", expected " << face_count
- );
- return;
- }
- } else {
- FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
- << MappingInformationType << "," << ReferenceInformationType);
- }
-}
-// ------------------------------------------------------------------------------------------------
-ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
-: Geometry(id, element, name, doc) {
- const Scope *sc = element.Compound();
- if (nullptr == sc) {
- DOMError("failed to read Geometry object (class: Shape), no data scope found");
- }
- const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element);
- const Element& Normals = GetRequiredElement(*sc, "Normals", &element);
- const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element);
- ParseVectorDataArray(m_indices, Indexes);
- ParseVectorDataArray(m_vertices, Vertices);
- ParseVectorDataArray(m_normals, Normals);
-}
-
-// ------------------------------------------------------------------------------------------------
-ShapeGeometry::~ShapeGeometry() {
- // empty
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<aiVector3D>& ShapeGeometry::GetVertices() const {
- return m_vertices;
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<aiVector3D>& ShapeGeometry::GetNormals() const {
- return m_normals;
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<unsigned int>& ShapeGeometry::GetIndices() const {
- return m_indices;
-}
-// ------------------------------------------------------------------------------------------------
-LineGeometry::LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
- : Geometry(id, element, name, doc)
-{
- const Scope* sc = element.Compound();
- if (!sc) {
- DOMError("failed to read Geometry object (class: Line), no data scope found");
- }
- const Element& Points = GetRequiredElement(*sc, "Points", &element);
- const Element& PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element);
- ParseVectorDataArray(m_vertices, Points);
- ParseVectorDataArray(m_indices, PointsIndex);
-}
-
-// ------------------------------------------------------------------------------------------------
-LineGeometry::~LineGeometry() {
- // empty
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<aiVector3D>& LineGeometry::GetVertices() const {
- return m_vertices;
-}
-// ------------------------------------------------------------------------------------------------
-const std::vector<int>& LineGeometry::GetIndices() const {
- return m_indices;
-}
-} // !FBX
-} // !Assimp
-#endif
-
diff --git a/thirdparty/assimp/code/FBX/FBXMeshGeometry.h b/thirdparty/assimp/code/FBX/FBXMeshGeometry.h
deleted file mode 100644
index d6d4512177..0000000000
--- a/thirdparty/assimp/code/FBX/FBXMeshGeometry.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXImporter.h
-* @brief Declaration of the FBX main importer class
-*/
-#ifndef INCLUDED_AI_FBX_MESHGEOMETRY_H
-#define INCLUDED_AI_FBX_MESHGEOMETRY_H
-
-#include "FBXParser.h"
-#include "FBXDocument.h"
-
-namespace Assimp {
-namespace FBX {
-
-/**
- * DOM base class for all kinds of FBX geometry
- */
-class Geometry : public Object
-{
-public:
- Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
- virtual ~Geometry();
-
- /** Get the Skin attached to this geometry or NULL */
- const Skin* DeformerSkin() const;
-
- /** Get the BlendShape attached to this geometry or NULL */
- const std::vector<const BlendShape*>& GetBlendShapes() const;
-
-private:
- const Skin* skin;
- std::vector<const BlendShape*> blendShapes;
-
-};
-
-typedef std::vector<int> MatIndexArray;
-
-
-/**
- * DOM class for FBX geometry of type "Mesh"
- */
-class MeshGeometry : public Geometry
-{
-public:
- /** The class constructor */
- MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
-
- /** The class destructor */
- virtual ~MeshGeometry();
-
- /** Get a list of all vertex points, non-unique*/
- const std::vector<aiVector3D>& GetVertices() const;
-
- /** Get a list of all vertex normals or an empty array if
- * no normals are specified. */
- const std::vector<aiVector3D>& GetNormals() const;
-
- /** Get a list of all vertex tangents or an empty array
- * if no tangents are specified */
- const std::vector<aiVector3D>& GetTangents() const;
-
- /** Get a list of all vertex bi-normals or an empty array
- * if no bi-normals are specified */
- const std::vector<aiVector3D>& GetBinormals() const;
-
- /** Return list of faces - each entry denotes a face and specifies
- * how many vertices it has. Vertices are taken from the
- * vertex data arrays in sequential order. */
- const std::vector<unsigned int>& GetFaceIndexCounts() const;
-
- /** Get a UV coordinate slot, returns an empty array if
- * the requested slot does not exist. */
- const std::vector<aiVector2D>& GetTextureCoords( unsigned int index ) const;
-
- /** Get a UV coordinate slot, returns an empty array if
- * the requested slot does not exist. */
- std::string GetTextureCoordChannelName( unsigned int index ) const;
-
- /** Get a vertex color coordinate slot, returns an empty array if
- * the requested slot does not exist. */
- const std::vector<aiColor4D>& GetVertexColors( unsigned int index ) const;
-
- /** Get per-face-vertex material assignments */
- const MatIndexArray& GetMaterialIndices() const;
-
- /** Convert from a fbx file vertex index (for example from a #Cluster weight) or NULL
- * if the vertex index is not valid. */
- const unsigned int* ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const;
-
- /** Determine the face to which a particular output vertex index belongs.
- * This mapping is always unique. */
- unsigned int FaceForVertexIndex( unsigned int in_index ) const;
-private:
- void ReadLayer( const Scope& layer );
- void ReadLayerElement( const Scope& layerElement );
- void ReadVertexData( const std::string& type, int index, const Scope& source );
-
- void ReadVertexDataUV( std::vector<aiVector2D>& uv_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType );
-
- void ReadVertexDataNormals( std::vector<aiVector3D>& normals_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType );
-
- void ReadVertexDataColors( std::vector<aiColor4D>& colors_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType );
-
- void ReadVertexDataTangents( std::vector<aiVector3D>& tangents_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType );
-
- void ReadVertexDataBinormals( std::vector<aiVector3D>& binormals_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType );
-
- void ReadVertexDataMaterials( MatIndexArray& materials_out, const Scope& source,
- const std::string& MappingInformationType,
- const std::string& ReferenceInformationType );
-
-private:
- // cached data arrays
- MatIndexArray m_materials;
- std::vector<aiVector3D> m_vertices;
- std::vector<unsigned int> m_faces;
- mutable std::vector<unsigned int> m_facesVertexStartIndices;
- std::vector<aiVector3D> m_tangents;
- std::vector<aiVector3D> m_binormals;
- std::vector<aiVector3D> m_normals;
-
- std::string m_uvNames[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
- std::vector<aiVector2D> m_uvs[ AI_MAX_NUMBER_OF_TEXTURECOORDS ];
- std::vector<aiColor4D> m_colors[ AI_MAX_NUMBER_OF_COLOR_SETS ];
-
- std::vector<unsigned int> m_mapping_counts;
- std::vector<unsigned int> m_mapping_offsets;
- std::vector<unsigned int> m_mappings;
-};
-
-/**
-* DOM class for FBX geometry of type "Shape"
-*/
-class ShapeGeometry : public Geometry
-{
-public:
- /** The class constructor */
- ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc);
-
- /** The class destructor */
- virtual ~ShapeGeometry();
-
- /** Get a list of all vertex points, non-unique*/
- const std::vector<aiVector3D>& GetVertices() const;
-
- /** Get a list of all vertex normals or an empty array if
- * no normals are specified. */
- const std::vector<aiVector3D>& GetNormals() const;
-
- /** Return list of vertex indices. */
- const std::vector<unsigned int>& GetIndices() const;
-
-private:
- std::vector<aiVector3D> m_vertices;
- std::vector<aiVector3D> m_normals;
- std::vector<unsigned int> m_indices;
-};
-/**
-* DOM class for FBX geometry of type "Line"
-*/
-class LineGeometry : public Geometry
-{
-public:
- /** The class constructor */
- LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc);
-
- /** The class destructor */
- virtual ~LineGeometry();
-
- /** Get a list of all vertex points, non-unique*/
- const std::vector<aiVector3D>& GetVertices() const;
-
- /** Return list of vertex indices. */
- const std::vector<int>& GetIndices() const;
-
-private:
- std::vector<aiVector3D> m_vertices;
- std::vector<int> m_indices;
-};
-
-}
-}
-
-#endif // INCLUDED_AI_FBX_MESHGEOMETRY_H
-
diff --git a/thirdparty/assimp/code/FBX/FBXModel.cpp b/thirdparty/assimp/code/FBX/FBXModel.cpp
deleted file mode 100644
index 589af36ac7..0000000000
--- a/thirdparty/assimp/code/FBX/FBXModel.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXModel.cpp
- * @brief Assimp::FBX::Model implementation
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include "FBXParser.h"
-#include "FBXMeshGeometry.h"
-#include "FBXDocument.h"
-#include "FBXImporter.h"
-#include "FBXDocumentUtil.h"
-
-namespace Assimp {
-namespace FBX {
-
-using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Model::Model(uint64_t id, const Element& element, const Document& doc, const std::string& name)
- : Object(id,element,name)
- , shading("Y")
-{
- const Scope& sc = GetRequiredScope(element);
- const Element* const Shading = sc["Shading"];
- const Element* const Culling = sc["Culling"];
-
- if(Shading) {
- shading = GetRequiredToken(*Shading,0).StringContents();
- }
-
- if (Culling) {
- culling = ParseTokenAsString(GetRequiredToken(*Culling,0));
- }
-
- props = GetPropertyTable(doc,"Model.FbxNode",element,sc);
- ResolveLinks(element,doc);
-}
-
-// ------------------------------------------------------------------------------------------------
-Model::~Model()
-{
-
-}
-
-// ------------------------------------------------------------------------------------------------
-void Model::ResolveLinks(const Element& element, const Document& doc)
-{
- const char* const arr[] = {"Geometry","Material","NodeAttribute"};
-
- // resolve material
- const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3);
-
- materials.reserve(conns.size());
- geometry.reserve(conns.size());
- attributes.reserve(conns.size());
- for(const Connection* con : conns) {
-
- // material and geometry links should be Object-Object connections
- if (con->PropertyName().length()) {
- continue;
- }
-
- const Object* const ob = con->SourceObject();
- if(!ob) {
- DOMWarning("failed to read source object for incoming Model link, ignoring",&element);
- continue;
- }
-
- const Material* const mat = dynamic_cast<const Material*>(ob);
- if(mat) {
- materials.push_back(mat);
- continue;
- }
-
- const Geometry* const geo = dynamic_cast<const Geometry*>(ob);
- if(geo) {
- geometry.push_back(geo);
- continue;
- }
-
- const NodeAttribute* const att = dynamic_cast<const NodeAttribute*>(ob);
- if(att) {
- attributes.push_back(att);
- continue;
- }
-
- DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring",&element);
- continue;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-bool Model::IsNull() const
-{
- const std::vector<const NodeAttribute*>& attrs = GetAttributes();
- for(const NodeAttribute* att : attrs) {
-
- const Null* null_tag = dynamic_cast<const Null*>(att);
- if(null_tag) {
- return true;
- }
- }
-
- return false;
-}
-
-
-} //!FBX
-} //!Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp b/thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp
deleted file mode 100644
index b72e5637ee..0000000000
--- a/thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXNoteAttribute.cpp
- * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation
- */
-
-#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;
-
-// ------------------------------------------------------------------------------------------------
-NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: Object(id,element,name)
-, props()
-{
- const Scope& sc = GetRequiredScope(element);
-
- const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
-
- // hack on the deriving type but Null/LimbNode attributes are the only case in which
- // the property table is by design absent and no warning should be generated
- // for it.
- const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
- props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
-}
-
-
-// ------------------------------------------------------------------------------------------------
-NodeAttribute::~NodeAttribute()
-{
- // empty
-}
-
-
-// ------------------------------------------------------------------------------------------------
-CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
- : NodeAttribute(id,element,doc,name)
-{
- const Scope& sc = GetRequiredScope(element);
- const Element* const CameraId = sc["CameraId"];
- const Element* const CameraName = sc["CameraName"];
- const Element* const CameraIndexName = sc["CameraIndexName"];
-
- if(CameraId) {
- cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
- }
-
- if(CameraName) {
- cameraName = GetRequiredToken(*CameraName,0).StringContents();
- }
-
- if(CameraIndexName && CameraIndexName->Tokens().size()) {
- cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-CameraSwitcher::~CameraSwitcher()
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: NodeAttribute(id,element,doc,name)
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Camera::~Camera()
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: NodeAttribute(id,element,doc,name)
-{
- // empty
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Light::~Light()
-{
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Null::Null(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: NodeAttribute(id,element,doc,name)
-{
-
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Null::~Null()
-{
-
-}
-
-
-// ------------------------------------------------------------------------------------------------
-LimbNode::LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: NodeAttribute(id,element,doc,name)
-{
-
-}
-
-
-// ------------------------------------------------------------------------------------------------
-LimbNode::~LimbNode()
-{
-
-}
-
-}
-}
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXParser.cpp b/thirdparty/assimp/code/FBX/FBXParser.cpp
deleted file mode 100644
index 4a9346040d..0000000000
--- a/thirdparty/assimp/code/FBX/FBXParser.cpp
+++ /dev/null
@@ -1,1309 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXParser.cpp
- * @brief Implementation of the FBX parser and the rudimentary DOM that we use
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-# include <zlib.h>
-#else
-# include "../contrib/zlib/zlib.h"
-#endif
-
-#include "FBXTokenizer.h"
-#include "FBXParser.h"
-#include "FBXUtil.h"
-
-#include <assimp/ParsingUtils.h>
-#include <assimp/fast_atof.h>
-#include <assimp/ByteSwapper.h>
-
-#include <iostream>
-
-using namespace Assimp;
-using namespace Assimp::FBX;
-
-namespace {
-
- // ------------------------------------------------------------------------------------------------
- // signal parse error, this is always unrecoverable. Throws DeadlyImportError.
- AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
- AI_WONT_RETURN void ParseError(const std::string& message, const Token& token)
- {
- throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token));
- }
-
- // ------------------------------------------------------------------------------------------------
- AI_WONT_RETURN void ParseError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX;
- AI_WONT_RETURN void ParseError(const std::string& message, const Element* element)
- {
- if(element) {
- ParseError(message,element->KeyToken());
- }
- throw DeadlyImportError("FBX-Parser " + message);
- }
-
-
- // ------------------------------------------------------------------------------------------------
- void ParseError(const std::string& message, TokenPtr token)
- {
- if(token) {
- ParseError(message, *token);
- }
- ParseError(message);
- }
-
- // Initially, we did reinterpret_cast, breaking strict aliasing rules.
- // This actually caused trouble on Android, so let's be safe this time.
- // https://github.com/assimp/assimp/issues/24
- template <typename T>
- T SafeParse(const char* data, const char* end) {
- // Actual size validation happens during Tokenization so
- // this is valid as an assertion.
- (void)(end);
- ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
- T result = static_cast<T>(0);
- ::memcpy(&result, data, sizeof(T));
- return result;
- }
-}
-
-namespace Assimp {
-namespace FBX {
-
-// ------------------------------------------------------------------------------------------------
-Element::Element(const Token& key_token, Parser& parser)
-: key_token(key_token)
-{
- TokenPtr n = nullptr;
- do {
- n = parser.AdvanceToNextToken();
- if(!n) {
- ParseError("unexpected end of file, expected closing bracket",parser.LastToken());
- }
-
- if (n->Type() == TokenType_DATA) {
- tokens.push_back(n);
- TokenPtr prev = n;
- n = parser.AdvanceToNextToken();
- if(!n) {
- ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken());
- }
-
- const TokenType ty = n->Type();
-
- // some exporters are missing a comma on the next line
- if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) {
- tokens.push_back(n);
- continue;
- }
-
- if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
- ParseError("unexpected token; expected bracket, comma or key",n);
- }
- }
-
- if (n->Type() == TokenType_OPEN_BRACKET) {
- compound.reset(new Scope(parser));
-
- // current token should be a TOK_CLOSE_BRACKET
- n = parser.CurrentToken();
- ai_assert(n);
-
- if (n->Type() != TokenType_CLOSE_BRACKET) {
- ParseError("expected closing bracket",n);
- }
-
- parser.AdvanceToNextToken();
- return;
- }
- }
- while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
-}
-
-// ------------------------------------------------------------------------------------------------
-Element::~Element()
-{
- // no need to delete tokens, they are owned by the parser
-}
-
-// ------------------------------------------------------------------------------------------------
-Scope::Scope(Parser& parser,bool topLevel)
-{
- if(!topLevel) {
- TokenPtr t = parser.CurrentToken();
- if (t->Type() != TokenType_OPEN_BRACKET) {
- ParseError("expected open bracket",t);
- }
- }
-
- TokenPtr n = parser.AdvanceToNextToken();
- if(n == NULL) {
- ParseError("unexpected end of file");
- }
-
- // note: empty scopes are allowed
- while(n->Type() != TokenType_CLOSE_BRACKET) {
- if (n->Type() != TokenType_KEY) {
- ParseError("unexpected token, expected TOK_KEY",n);
- }
-
- const std::string& str = n->StringContents();
- elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
-
- // Element() should stop at the next Key token (or right after a Close token)
- n = parser.CurrentToken();
- if(n == NULL) {
- if (topLevel) {
- return;
- }
- ParseError("unexpected end of file",parser.LastToken());
- }
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Scope::~Scope()
-{
- for(ElementMap::value_type& v : elements) {
- delete v.second;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-Parser::Parser (const TokenList& tokens, bool is_binary)
-: tokens(tokens)
-, last()
-, current()
-, cursor(tokens.begin())
-, is_binary(is_binary)
-{
- root.reset(new Scope(*this,true));
-}
-
-// ------------------------------------------------------------------------------------------------
-Parser::~Parser()
-{
- // empty
-}
-
-// ------------------------------------------------------------------------------------------------
-TokenPtr Parser::AdvanceToNextToken()
-{
- last = current;
- if (cursor == tokens.end()) {
- current = NULL;
- } else {
- current = *cursor++;
- }
- return current;
-}
-
-// ------------------------------------------------------------------------------------------------
-TokenPtr Parser::CurrentToken() const
-{
- return current;
-}
-
-// ------------------------------------------------------------------------------------------------
-TokenPtr Parser::LastToken() const
-{
- return last;
-}
-
-// ------------------------------------------------------------------------------------------------
-uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
-{
- err_out = NULL;
-
- if (t.Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0L;
- }
-
- if(t.IsBinary())
- {
- const char* data = t.begin();
- if (data[0] != 'L') {
- err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
- return 0L;
- }
-
- BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
- AI_SWAP8(id);
- return id;
- }
-
- // XXX: should use size_t here
- unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
- ai_assert(length > 0);
-
- const char* out = nullptr;
- const uint64_t id = strtoul10_64(t.begin(),&out,&length);
- if (out > t.end()) {
- err_out = "failed to parse ID (text)";
- return 0L;
- }
-
- return id;
-}
-
-// ------------------------------------------------------------------------------------------------
-size_t ParseTokenAsDim(const Token& t, const char*& err_out)
-{
- // same as ID parsing, except there is a trailing asterisk
- err_out = NULL;
-
- if (t.Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0;
- }
-
- if(t.IsBinary())
- {
- const char* data = t.begin();
- if (data[0] != 'L') {
- err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
- return 0;
- }
-
- BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
- AI_SWAP8(id);
- return static_cast<size_t>(id);
- }
-
- if(*t.begin() != '*') {
- err_out = "expected asterisk before array dimension";
- return 0;
- }
-
- // XXX: should use size_t here
- unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
- if(length == 0) {
- err_out = "expected valid integer number after asterisk";
- return 0;
- }
-
- const char* out = nullptr;
- const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length));
- if (out > t.end()) {
- err_out = "failed to parse ID";
- return 0;
- }
-
- return id;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-float ParseTokenAsFloat(const Token& t, const char*& err_out)
-{
- err_out = NULL;
-
- if (t.Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0.0f;
- }
-
- if(t.IsBinary())
- {
- const char* data = t.begin();
- if (data[0] != 'F' && data[0] != 'D') {
- err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
- return 0.0f;
- }
-
- if (data[0] == 'F') {
- return SafeParse<float>(data+1, t.end());
- }
- else {
- return static_cast<float>( SafeParse<double>(data+1, t.end()) );
- }
- }
-
- // need to copy the input string to a temporary buffer
- // first - next in the fbx token stream comes ',',
- // which fast_atof could interpret as decimal point.
-#define MAX_FLOAT_LENGTH 31
- char temp[MAX_FLOAT_LENGTH + 1];
- const size_t length = static_cast<size_t>(t.end()-t.begin());
- std::copy(t.begin(),t.end(),temp);
- temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0';
-
- return fast_atof(temp);
-}
-
-
-// ------------------------------------------------------------------------------------------------
-int ParseTokenAsInt(const Token& t, const char*& err_out)
-{
- err_out = NULL;
-
- if (t.Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0;
- }
-
- if(t.IsBinary())
- {
- const char* data = t.begin();
- if (data[0] != 'I') {
- err_out = "failed to parse I(nt), unexpected data type (binary)";
- return 0;
- }
-
- BE_NCONST int32_t ival = SafeParse<int32_t>(data+1, t.end());
- AI_SWAP4(ival);
- return static_cast<int>(ival);
- }
-
- ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0);
-
- const char* out;
- const int intval = strtol10(t.begin(),&out);
- if (out != t.end()) {
- err_out = "failed to parse ID";
- return 0;
- }
-
- return intval;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-int64_t ParseTokenAsInt64(const Token& t, const char*& err_out)
-{
- err_out = NULL;
-
- if (t.Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return 0L;
- }
-
- if (t.IsBinary())
- {
- const char* data = t.begin();
- if (data[0] != 'L') {
- err_out = "failed to parse Int64, unexpected data type";
- return 0L;
- }
-
- BE_NCONST int64_t id = SafeParse<int64_t>(data + 1, t.end());
- AI_SWAP8(id);
- return id;
- }
-
- // XXX: should use size_t here
- unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
- ai_assert(length > 0);
-
- const char* out = nullptr;
- const int64_t id = strtol10_64(t.begin(), &out, &length);
- if (out > t.end()) {
- err_out = "failed to parse Int64 (text)";
- return 0L;
- }
-
- return id;
-}
-
-// ------------------------------------------------------------------------------------------------
-std::string ParseTokenAsString(const Token& t, const char*& err_out)
-{
- err_out = NULL;
-
- if (t.Type() != TokenType_DATA) {
- err_out = "expected TOK_DATA token";
- return "";
- }
-
- if(t.IsBinary())
- {
- const char* data = t.begin();
- if (data[0] != 'S') {
- err_out = "failed to parse S(tring), unexpected data type (binary)";
- return "";
- }
-
- // read string length
- BE_NCONST int32_t len = SafeParse<int32_t>(data+1, t.end());
- AI_SWAP4(len);
-
- ai_assert(t.end() - data == 5 + len);
- return std::string(data + 5, len);
- }
-
- const size_t length = static_cast<size_t>(t.end() - t.begin());
- if(length < 2) {
- err_out = "token is too short to hold a string";
- return "";
- }
-
- const char* s = t.begin(), *e = t.end() - 1;
- if (*s != '\"' || *e != '\"') {
- err_out = "expected double quoted string";
- return "";
- }
-
- return std::string(s+1,length-2);
-}
-
-
-namespace {
-
-// ------------------------------------------------------------------------------------------------
-// read the type code and element count of a binary data array and stop there
-void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uint32_t& count,
- const Element& el)
-{
- if (static_cast<size_t>(end-data) < 5) {
- ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el);
- }
-
- // data type
- type = *data;
-
- // read number of elements
- BE_NCONST uint32_t len = SafeParse<uint32_t>(data+1, end);
- AI_SWAP4(len);
-
- count = len;
- data += 5;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
-void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end,
- std::vector<char>& buff,
- const Element& /*el*/)
-{
- BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
- AI_SWAP4(encmode);
- data += 4;
-
- // next comes the compressed length
- BE_NCONST uint32_t comp_len = SafeParse<uint32_t>(data, end);
- AI_SWAP4(comp_len);
- data += 4;
-
- ai_assert(data + comp_len == end);
-
- // determine the length of the uncompressed data by looking at the type signature
- uint32_t stride = 0;
- switch(type)
- {
- case 'f':
- case 'i':
- stride = 4;
- break;
-
- case 'd':
- case 'l':
- stride = 8;
- break;
-
- default:
- ai_assert(false);
- };
-
- const uint32_t full_length = stride * count;
- buff.resize(full_length);
-
- if(encmode == 0) {
- ai_assert(full_length == comp_len);
-
- // plain data, no compression
- std::copy(data, end, buff.begin());
- }
- else if(encmode == 1) {
- // zlib/deflate, next comes ZIP head (0x78 0x01)
- // see http://www.ietf.org/rfc/rfc1950.txt
-
- z_stream zstream;
- zstream.opaque = Z_NULL;
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.data_type = Z_BINARY;
-
- // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
- if(Z_OK != inflateInit(&zstream)) {
- ParseError("failure initializing zlib");
- }
-
- zstream.next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data) );
- zstream.avail_in = comp_len;
-
- zstream.avail_out = static_cast<uInt>(buff.size());
- zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin());
- const int ret = inflate(&zstream, Z_FINISH);
-
- if (ret != Z_STREAM_END && ret != Z_OK) {
- ParseError("failure decompressing compressed data section");
- }
-
- // terminate zlib
- inflateEnd(&zstream);
- }
-#ifdef ASSIMP_BUILD_DEBUG
- else {
- // runtime check for this happens at tokenization stage
- ai_assert(false);
- }
-#endif
-
- data += comp_len;
- ai_assert(data == end);
-}
-
-} // !anon
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of float3 tuples
-void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
-{
- out.resize( 0 );
-
- const TokenList& tok = el.Tokens();
- if(tok.empty()) {
- ParseError("unexpected empty element",&el);
- }
-
- if(tok[0]->IsBinary()) {
- const char* data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if(count % 3 != 0) {
- ParseError("number of floats is not a multiple of three (3) (binary)",&el);
- }
-
- if(!count) {
- return;
- }
-
- if (type != 'd' && type != 'f') {
- ParseError("expected float or double array (binary)",&el);
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- ai_assert(data == end);
- ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
-
- const uint32_t count3 = count / 3;
- out.reserve(count3);
-
- if (type == 'd') {
- const double* d = reinterpret_cast<const double*>(&buff[0]);
- for (unsigned int i = 0; i < count3; ++i, d += 3) {
- out.push_back(aiVector3D(static_cast<ai_real>(d[0]),
- static_cast<ai_real>(d[1]),
- static_cast<ai_real>(d[2])));
- }
- // for debugging
- /*for ( size_t i = 0; i < out.size(); i++ ) {
- aiVector3D vec3( out[ i ] );
- std::stringstream stream;
- stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl;
- DefaultLogger::get()->info( stream.str() );
- }*/
- }
- else if (type == 'f') {
- const float* f = reinterpret_cast<const float*>(&buff[0]);
- for (unsigned int i = 0; i < count3; ++i, f += 3) {
- out.push_back(aiVector3D(f[0],f[1],f[2]));
- }
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(*tok[0]);
-
- // may throw bad_alloc if the input is rubbish, but this need
- // not to be prevented - importing would fail but we wouldn't
- // crash since assimp handles this case properly.
- out.reserve(dim);
-
- const Scope& scope = GetRequiredScope(el);
- const Element& a = GetRequiredElement(scope,"a",&el);
-
- if (a.Tokens().size() % 3 != 0) {
- ParseError("number of floats is not a multiple of three (3)",&el);
- }
- for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
- aiVector3D v;
- v.x = ParseTokenAsFloat(**it++);
- v.y = ParseTokenAsFloat(**it++);
- v.z = ParseTokenAsFloat(**it++);
-
- out.push_back(v);
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of color4 tuples
-void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
-{
- out.resize( 0 );
- const TokenList& tok = el.Tokens();
- if(tok.empty()) {
- ParseError("unexpected empty element",&el);
- }
-
- if(tok[0]->IsBinary()) {
- const char* data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if(count % 4 != 0) {
- ParseError("number of floats is not a multiple of four (4) (binary)",&el);
- }
-
- if(!count) {
- return;
- }
-
- if (type != 'd' && type != 'f') {
- ParseError("expected float or double array (binary)",&el);
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- ai_assert(data == end);
- ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
-
- const uint32_t count4 = count / 4;
- out.reserve(count4);
-
- if (type == 'd') {
- const double* d = reinterpret_cast<const double*>(&buff[0]);
- for (unsigned int i = 0; i < count4; ++i, d += 4) {
- out.push_back(aiColor4D(static_cast<float>(d[0]),
- static_cast<float>(d[1]),
- static_cast<float>(d[2]),
- static_cast<float>(d[3])));
- }
- }
- else if (type == 'f') {
- const float* f = reinterpret_cast<const float*>(&buff[0]);
- for (unsigned int i = 0; i < count4; ++i, f += 4) {
- out.push_back(aiColor4D(f[0],f[1],f[2],f[3]));
- }
- }
- return;
- }
-
- const size_t dim = ParseTokenAsDim(*tok[0]);
-
- // see notes in ParseVectorDataArray() above
- out.reserve(dim);
-
- const Scope& scope = GetRequiredScope(el);
- const Element& a = GetRequiredElement(scope,"a",&el);
-
- if (a.Tokens().size() % 4 != 0) {
- ParseError("number of floats is not a multiple of four (4)",&el);
- }
- for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
- aiColor4D v;
- v.r = ParseTokenAsFloat(**it++);
- v.g = ParseTokenAsFloat(**it++);
- v.b = ParseTokenAsFloat(**it++);
- v.a = ParseTokenAsFloat(**it++);
-
- out.push_back(v);
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of float2 tuples
-void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
-{
- out.resize( 0 );
- const TokenList& tok = el.Tokens();
- if(tok.empty()) {
- ParseError("unexpected empty element",&el);
- }
-
- if(tok[0]->IsBinary()) {
- const char* data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if(count % 2 != 0) {
- ParseError("number of floats is not a multiple of two (2) (binary)",&el);
- }
-
- if(!count) {
- return;
- }
-
- if (type != 'd' && type != 'f') {
- ParseError("expected float or double array (binary)",&el);
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- ai_assert(data == end);
- ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
-
- const uint32_t count2 = count / 2;
- out.reserve(count2);
-
- if (type == 'd') {
- const double* d = reinterpret_cast<const double*>(&buff[0]);
- for (unsigned int i = 0; i < count2; ++i, d += 2) {
- out.push_back(aiVector2D(static_cast<float>(d[0]),
- static_cast<float>(d[1])));
- }
- }
- else if (type == 'f') {
- const float* f = reinterpret_cast<const float*>(&buff[0]);
- for (unsigned int i = 0; i < count2; ++i, f += 2) {
- out.push_back(aiVector2D(f[0],f[1]));
- }
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(*tok[0]);
-
- // see notes in ParseVectorDataArray() above
- out.reserve(dim);
-
- const Scope& scope = GetRequiredScope(el);
- const Element& a = GetRequiredElement(scope,"a",&el);
-
- if (a.Tokens().size() % 2 != 0) {
- ParseError("number of floats is not a multiple of two (2)",&el);
- }
- for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
- aiVector2D v;
- v.x = ParseTokenAsFloat(**it++);
- v.y = ParseTokenAsFloat(**it++);
-
- out.push_back(v);
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of ints
-void ParseVectorDataArray(std::vector<int>& out, const Element& el)
-{
- out.resize( 0 );
- const TokenList& tok = el.Tokens();
- if(tok.empty()) {
- ParseError("unexpected empty element",&el);
- }
-
- if(tok[0]->IsBinary()) {
- const char* data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if(!count) {
- return;
- }
-
- if (type != 'i') {
- ParseError("expected int array (binary)",&el);
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- ai_assert(data == end);
- ai_assert(buff.size() == count * 4);
-
- out.reserve(count);
-
- const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++ip) {
- BE_NCONST int32_t val = *ip;
- AI_SWAP4(val);
- out.push_back(val);
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(*tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const Scope& scope = GetRequiredScope(el);
- const Element& a = GetRequiredElement(scope,"a",&el);
-
- for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
- const int ival = ParseTokenAsInt(**it++);
- out.push_back(ival);
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of floats
-void ParseVectorDataArray(std::vector<float>& out, const Element& el)
-{
- out.resize( 0 );
- const TokenList& tok = el.Tokens();
- if(tok.empty()) {
- ParseError("unexpected empty element",&el);
- }
-
- if(tok[0]->IsBinary()) {
- const char* data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if(!count) {
- return;
- }
-
- if (type != 'd' && type != 'f') {
- ParseError("expected float or double array (binary)",&el);
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- ai_assert(data == end);
- ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
-
- if (type == 'd') {
- const double* d = reinterpret_cast<const double*>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++d) {
- out.push_back(static_cast<float>(*d));
- }
- }
- else if (type == 'f') {
- const float* f = reinterpret_cast<const float*>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++f) {
- out.push_back(*f);
- }
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(*tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const Scope& scope = GetRequiredScope(el);
- const Element& a = GetRequiredElement(scope,"a",&el);
-
- for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
- const float ival = ParseTokenAsFloat(**it++);
- out.push_back(ival);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of uints
-void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
-{
- out.resize( 0 );
- const TokenList& tok = el.Tokens();
- if(tok.empty()) {
- ParseError("unexpected empty element",&el);
- }
-
- if(tok[0]->IsBinary()) {
- const char* data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if(!count) {
- return;
- }
-
- if (type != 'i') {
- ParseError("expected (u)int array (binary)",&el);
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- ai_assert(data == end);
- ai_assert(buff.size() == count * 4);
-
- out.reserve(count);
-
- const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++ip) {
- BE_NCONST int32_t val = *ip;
- if(val < 0) {
- ParseError("encountered negative integer index (binary)");
- }
-
- AI_SWAP4(val);
- out.push_back(val);
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(*tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const Scope& scope = GetRequiredScope(el);
- const Element& a = GetRequiredElement(scope,"a",&el);
-
- for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
- const int ival = ParseTokenAsInt(**it++);
- if(ival < 0) {
- ParseError("encountered negative integer index");
- }
- out.push_back(static_cast<unsigned int>(ival));
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// read an array of uint64_ts
-void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
-{
- out.resize( 0 );
- const TokenList& tok = el.Tokens();
- if(tok.empty()) {
- ParseError("unexpected empty element",&el);
- }
-
- if(tok[0]->IsBinary()) {
- const char* data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if(!count) {
- return;
- }
-
- if (type != 'l') {
- ParseError("expected long array (binary)",&el);
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- ai_assert(data == end);
- ai_assert(buff.size() == count * 8);
-
- out.reserve(count);
-
- const uint64_t* ip = reinterpret_cast<const uint64_t*>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++ip) {
- BE_NCONST uint64_t val = *ip;
- AI_SWAP8(val);
- out.push_back(val);
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(*tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const Scope& scope = GetRequiredScope(el);
- const Element& a = GetRequiredElement(scope,"a",&el);
-
- for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
- const uint64_t ival = ParseTokenAsID(**it++);
-
- out.push_back(ival);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-// read an array of int64_ts
-void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
-{
- out.resize( 0 );
- const TokenList& tok = el.Tokens();
- if (tok.empty()) {
- ParseError("unexpected empty element", &el);
- }
-
- if (tok[0]->IsBinary()) {
- const char* data = tok[0]->begin(), *end = tok[0]->end();
-
- char type;
- uint32_t count;
- ReadBinaryDataArrayHead(data, end, type, count, el);
-
- if (!count) {
- return;
- }
-
- if (type != 'l') {
- ParseError("expected long array (binary)", &el);
- }
-
- std::vector<char> buff;
- ReadBinaryDataArray(type, count, data, end, buff, el);
-
- ai_assert(data == end);
- ai_assert(buff.size() == count * 8);
-
- out.reserve(count);
-
- const int64_t* ip = reinterpret_cast<const int64_t*>(&buff[0]);
- for (unsigned int i = 0; i < count; ++i, ++ip) {
- BE_NCONST int64_t val = *ip;
- AI_SWAP8(val);
- out.push_back(val);
- }
-
- return;
- }
-
- const size_t dim = ParseTokenAsDim(*tok[0]);
-
- // see notes in ParseVectorDataArray()
- out.reserve(dim);
-
- const Scope& scope = GetRequiredScope(el);
- const Element& a = GetRequiredElement(scope, "a", &el);
-
- for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end;) {
- const int64_t ival = ParseTokenAsInt64(**it++);
-
- out.push_back(ival);
- }
-}
-
-// ------------------------------------------------------------------------------------------------
-aiMatrix4x4 ReadMatrix(const Element& element)
-{
- std::vector<float> values;
- ParseVectorDataArray(values,element);
-
- if(values.size() != 16) {
- ParseError("expected 16 matrix elements");
- }
-
- aiMatrix4x4 result;
-
-
- result.a1 = values[0];
- result.a2 = values[1];
- result.a3 = values[2];
- result.a4 = values[3];
-
- result.b1 = values[4];
- result.b2 = values[5];
- result.b3 = values[6];
- result.b4 = values[7];
-
- result.c1 = values[8];
- result.c2 = values[9];
- result.c3 = values[10];
- result.c4 = values[11];
-
- result.d1 = values[12];
- result.d2 = values[13];
- result.d3 = values[14];
- result.d4 = values[15];
-
- result.Transpose();
- return result;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsString() with ParseError handling
-std::string ParseTokenAsString(const Token& t)
-{
- const char* err;
- const std::string& i = ParseTokenAsString(t,err);
- if(err) {
- ParseError(err,t);
- }
- return i;
-}
-
-bool HasElement( const Scope& sc, const std::string& index ) {
- const Element* el = sc[ index ];
- if ( nullptr == el ) {
- return false;
- }
-
- return true;
-}
-
-// ------------------------------------------------------------------------------------------------
-// extract a required element from a scope, abort if the element cannot be found
-const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/)
-{
- const Element* el = sc[index];
- if(!el) {
- ParseError("did not find required element \"" + index + "\"",element);
- }
- return *el;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// extract required compound scope
-const Scope& GetRequiredScope(const Element& el)
-{
- const Scope* const s = el.Compound();
- if(!s) {
- ParseError("expected compound scope",&el);
- }
-
- return *s;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// get token at a particular index
-const Token& GetRequiredToken(const Element& el, unsigned int index)
-{
- const TokenList& t = el.Tokens();
- if(index >= t.size()) {
- ParseError(Formatter::format( "missing token at index " ) << index,&el);
- }
-
- return *t[index];
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsID() with ParseError handling
-uint64_t ParseTokenAsID(const Token& t)
-{
- const char* err;
- const uint64_t i = ParseTokenAsID(t,err);
- if(err) {
- ParseError(err,t);
- }
- return i;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsDim() with ParseError handling
-size_t ParseTokenAsDim(const Token& t)
-{
- const char* err;
- const size_t i = ParseTokenAsDim(t,err);
- if(err) {
- ParseError(err,t);
- }
- return i;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsFloat() with ParseError handling
-float ParseTokenAsFloat(const Token& t)
-{
- const char* err;
- const float i = ParseTokenAsFloat(t,err);
- if(err) {
- ParseError(err,t);
- }
- return i;
-}
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsInt() with ParseError handling
-int ParseTokenAsInt(const Token& t)
-{
- const char* err;
- const int i = ParseTokenAsInt(t,err);
- if(err) {
- ParseError(err,t);
- }
- return i;
-}
-
-// ------------------------------------------------------------------------------------------------
-// wrapper around ParseTokenAsInt64() with ParseError handling
-int64_t ParseTokenAsInt64(const Token& t)
-{
- const char* err;
- const int64_t i = ParseTokenAsInt64(t, err);
- if (err) {
- ParseError(err, t);
- }
- return i;
-}
-
-} // !FBX
-} // !Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXParser.h b/thirdparty/assimp/code/FBX/FBXParser.h
deleted file mode 100644
index 7b0cf72039..0000000000
--- a/thirdparty/assimp/code/FBX/FBXParser.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXParser.h
- * @brief FBX parsing code
- */
-#ifndef INCLUDED_AI_FBX_PARSER_H
-#define INCLUDED_AI_FBX_PARSER_H
-
-#include <stdint.h>
-#include <map>
-#include <memory>
-#include <assimp/LogAux.h>
-#include <assimp/fast_atof.h>
-
-#include "FBXCompileConfig.h"
-#include "FBXTokenizer.h"
-
-namespace Assimp {
-namespace FBX {
-
-class Scope;
-class Parser;
-class Element;
-
-// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
-typedef std::vector< Scope* > ScopeList;
-typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap;
-
-typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection;
-
-# define new_Scope new Scope
-# define new_Element new Element
-
-
-/** FBX data entity that consists of a key:value tuple.
- *
- * Example:
- * @verbatim
- * AnimationCurve: 23, "AnimCurve::", "" {
- * [..]
- * }
- * @endverbatim
- *
- * As can be seen in this sample, elements can contain nested #Scope
- * as their trailing member. **/
-class Element
-{
-public:
- Element(const Token& key_token, Parser& parser);
- ~Element();
-
- const Scope* Compound() const {
- return compound.get();
- }
-
- const Token& KeyToken() const {
- return key_token;
- }
-
- const TokenList& Tokens() const {
- return tokens;
- }
-
-private:
- const Token& key_token;
- TokenList tokens;
- std::unique_ptr<Scope> compound;
-};
-
-/** FBX data entity that consists of a 'scope', a collection
- * of not necessarily unique #Element instances.
- *
- * Example:
- * @verbatim
- * GlobalSettings: {
- * Version: 1000
- * Properties70:
- * [...]
- * }
- * @endverbatim */
-class Scope
-{
-public:
- Scope(Parser& parser, bool topLevel = false);
- ~Scope();
-
- const Element* operator[] (const std::string& index) const {
- ElementMap::const_iterator it = elements.find(index);
- return it == elements.end() ? NULL : (*it).second;
- }
-
- const Element* FindElementCaseInsensitive(const std::string& elementName) const {
- const char* elementNameCStr = elementName.c_str();
- for (auto element = elements.begin(); element != elements.end(); ++element)
- {
- if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) {
- return element->second;
- }
- }
- return NULL;
- }
-
- ElementCollection GetCollection(const std::string& index) const {
- return elements.equal_range(index);
- }
-
- const ElementMap& Elements() const {
- return elements;
- }
-
-private:
- ElementMap elements;
-};
-
-/** FBX parsing class, takes a list of input tokens and generates a hierarchy
- * of nested #Scope instances, representing the fbx DOM.*/
-class Parser
-{
-public:
- /** Parse given a token list. Does not take ownership of the tokens -
- * the objects must persist during the entire parser lifetime */
- Parser (const TokenList& tokens,bool is_binary);
- ~Parser();
-
- const Scope& GetRootScope() const {
- return *root.get();
- }
-
- bool IsBinary() const {
- return is_binary;
- }
-
-private:
- friend class Scope;
- friend class Element;
-
- TokenPtr AdvanceToNextToken();
- TokenPtr LastToken() const;
- TokenPtr CurrentToken() const;
-
-private:
- const TokenList& tokens;
-
- TokenPtr last, current;
- TokenList::const_iterator cursor;
- std::unique_ptr<Scope> root;
-
- const bool is_binary;
-};
-
-
-/* token parsing - this happens when building the DOM out of the parse-tree*/
-uint64_t ParseTokenAsID(const Token& t, const char*& err_out);
-size_t ParseTokenAsDim(const Token& t, const char*& err_out);
-
-float ParseTokenAsFloat(const Token& t, const char*& err_out);
-int ParseTokenAsInt(const Token& t, const char*& err_out);
-int64_t ParseTokenAsInt64(const Token& t, const char*& err_out);
-std::string ParseTokenAsString(const Token& t, const char*& err_out);
-
-/* wrapper around ParseTokenAsXXX() with DOMError handling */
-uint64_t ParseTokenAsID(const Token& t);
-size_t ParseTokenAsDim(const Token& t);
-float ParseTokenAsFloat(const Token& t);
-int ParseTokenAsInt(const Token& t);
-int64_t ParseTokenAsInt64(const Token& t);
-std::string ParseTokenAsString(const Token& t);
-
-/* read data arrays */
-void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el);
-void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el);
-void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el);
-void ParseVectorDataArray(std::vector<int>& out, const Element& el);
-void ParseVectorDataArray(std::vector<float>& out, const Element& el);
-void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
-void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
-void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el);
-
-bool HasElement( const Scope& sc, const std::string& index );
-
-// extract a required element from a scope, abort if the element cannot be found
-const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
-
-// extract required compound scope
-const Scope& GetRequiredScope(const Element& el);
-// get token at a particular index
-const Token& GetRequiredToken(const Element& el, unsigned int index);
-
-// read a 4x4 matrix from an array of 16 floats
-aiMatrix4x4 ReadMatrix(const Element& element);
-
-} // ! FBX
-} // ! Assimp
-
-#endif // ! INCLUDED_AI_FBX_PARSER_H
diff --git a/thirdparty/assimp/code/FBX/FBXProperties.cpp b/thirdparty/assimp/code/FBX/FBXProperties.cpp
deleted file mode 100644
index 8d7036b6a9..0000000000
--- a/thirdparty/assimp/code/FBX/FBXProperties.cpp
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXProperties.cpp
- * @brief Implementation of the FBX dynamic properties system
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-#include "FBXTokenizer.h"
-#include "FBXParser.h"
-#include "FBXDocument.h"
-#include "FBXDocumentUtil.h"
-#include "FBXProperties.h"
-
-namespace Assimp {
-namespace FBX {
-
- using namespace Util;
-
-// ------------------------------------------------------------------------------------------------
-Property::Property()
-{
-}
-
-// ------------------------------------------------------------------------------------------------
-Property::~Property()
-{
-}
-
-namespace {
-
-// ------------------------------------------------------------------------------------------------
-// read a typed property out of a FBX element. The return value is NULL if the property cannot be read.
-Property* ReadTypedProperty(const Element& element)
-{
- ai_assert(element.KeyToken().StringContents() == "P");
-
- const TokenList& tok = element.Tokens();
- ai_assert(tok.size() >= 5);
-
- const std::string& s = ParseTokenAsString(*tok[1]);
- const char* const cs = s.c_str();
- if (!strcmp(cs,"KString")) {
- return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
- }
- else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
- return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
- }
- else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
- return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
- }
- else if (!strcmp(cs, "ULongLong")) {
- return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
- }
- else if (!strcmp(cs, "KTime")) {
- return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
- }
- else if (!strcmp(cs,"Vector3D") ||
- !strcmp(cs,"ColorRGB") ||
- !strcmp(cs,"Vector") ||
- !strcmp(cs,"Color") ||
- !strcmp(cs,"Lcl Translation") ||
- !strcmp(cs,"Lcl Rotation") ||
- !strcmp(cs,"Lcl Scaling")
- ) {
- return new TypedProperty<aiVector3D>(aiVector3D(
- ParseTokenAsFloat(*tok[4]),
- ParseTokenAsFloat(*tok[5]),
- ParseTokenAsFloat(*tok[6]))
- );
- }
- else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) {
- return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
- }
- return NULL;
-}
-
-
-// ------------------------------------------------------------------------------------------------
-// peek into an element and check if it contains a FBX property, if so return its name.
-std::string PeekPropertyName(const Element& element)
-{
- ai_assert(element.KeyToken().StringContents() == "P");
- const TokenList& tok = element.Tokens();
- if(tok.size() < 4) {
- return "";
- }
-
- return ParseTokenAsString(*tok[0]);
-}
-
-} //! anon
-
-
-// ------------------------------------------------------------------------------------------------
-PropertyTable::PropertyTable()
-: templateProps()
-, element()
-{
-}
-
-// ------------------------------------------------------------------------------------------------
-PropertyTable::PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps)
-: templateProps(templateProps)
-, element(&element)
-{
- const Scope& scope = GetRequiredScope(element);
- for(const ElementMap::value_type& v : scope.Elements()) {
- if(v.first != "P") {
- DOMWarning("expected only P elements in property table",v.second);
- continue;
- }
-
- const std::string& name = PeekPropertyName(*v.second);
- if(!name.length()) {
- DOMWarning("could not read property name",v.second);
- continue;
- }
-
- LazyPropertyMap::const_iterator it = lazyProps.find(name);
- if (it != lazyProps.end()) {
- DOMWarning("duplicate property name, will hide previous value: " + name,v.second);
- continue;
- }
-
- lazyProps[name] = v.second;
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-PropertyTable::~PropertyTable()
-{
- for(PropertyMap::value_type& v : props) {
- delete v.second;
- }
-}
-
-
-// ------------------------------------------------------------------------------------------------
-const Property* PropertyTable::Get(const std::string& name) const
-{
- PropertyMap::const_iterator it = props.find(name);
- if (it == props.end()) {
- // hasn't been parsed yet?
- LazyPropertyMap::const_iterator lit = lazyProps.find(name);
- if(lit != lazyProps.end()) {
- props[name] = ReadTypedProperty(*(*lit).second);
- it = props.find(name);
-
- ai_assert(it != props.end());
- }
-
- if (it == props.end()) {
- // check property template
- if(templateProps) {
- return templateProps->Get(name);
- }
-
- return NULL;
- }
- }
-
- return (*it).second;
-}
-
-DirectPropertyMap PropertyTable::GetUnparsedProperties() const
-{
- DirectPropertyMap result;
-
- // Loop through all the lazy properties (which is all the properties)
- for(const LazyPropertyMap::value_type& element : lazyProps) {
-
- // Skip parsed properties
- if (props.end() != props.find(element.first)) continue;
-
- // Read the element's value.
- // Wrap the naked pointer (since the call site is required to acquire ownership)
- // std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
- std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*element.second));
-
- // Element could not be read. Skip it.
- if (!prop) continue;
-
- // Add to result
- result[element.first] = prop;
- }
-
- return result;
-}
-
-} //! FBX
-} //! Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXProperties.h b/thirdparty/assimp/code/FBX/FBXProperties.h
deleted file mode 100644
index 58755542fc..0000000000
--- a/thirdparty/assimp/code/FBX/FBXProperties.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXProperties.h
- * @brief FBX dynamic properties
- */
-#ifndef INCLUDED_AI_FBX_PROPERTIES_H
-#define INCLUDED_AI_FBX_PROPERTIES_H
-
-#include "FBXCompileConfig.h"
-#include <memory>
-#include <string>
-
-namespace Assimp {
-namespace FBX {
-
-// Forward declarations
-class Element;
-
-/** Represents a dynamic property. Type info added by deriving classes,
- * see #TypedProperty.
- Example:
- @verbatim
- P: "ShininessExponent", "double", "Number", "",0.5
- @endvebatim
-*/
-class Property {
-protected:
- Property();
-
-public:
- virtual ~Property();
-
-public:
- template <typename T>
- const T* As() const {
- return dynamic_cast<const T*>(this);
- }
-};
-
-template<typename T>
-class TypedProperty : public Property {
-public:
- explicit TypedProperty(const T& value)
- : value(value) {
- // empty
- }
-
- const T& Value() const {
- return value;
- }
-
-private:
- T value;
-};
-
-
-typedef std::fbx_unordered_map<std::string,std::shared_ptr<Property> > DirectPropertyMap;
-typedef std::fbx_unordered_map<std::string,const Property*> PropertyMap;
-typedef std::fbx_unordered_map<std::string,const Element*> LazyPropertyMap;
-
-/**
- * Represents a property table as can be found in the newer FBX files (Properties60, Properties70)
- */
-class PropertyTable {
-public:
- // in-memory property table with no source element
- PropertyTable();
- PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps);
- ~PropertyTable();
-
- const Property* Get(const std::string& name) const;
-
- // PropertyTable's need not be coupled with FBX elements so this can be NULL
- const Element* GetElement() const {
- return element;
- }
-
- const PropertyTable* TemplateProps() const {
- return templateProps.get();
- }
-
- DirectPropertyMap GetUnparsedProperties() const;
-
-private:
- LazyPropertyMap lazyProps;
- mutable PropertyMap props;
- const std::shared_ptr<const PropertyTable> templateProps;
- const Element* const element;
-};
-
-// ------------------------------------------------------------------------------------------------
-template <typename T>
-inline
-T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
- const Property* const prop = in.Get(name);
- if( nullptr == prop) {
- return defaultValue;
- }
-
- // strong typing, no need to be lenient
- const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
- if( nullptr == tprop) {
- return defaultValue;
- }
-
- return tprop->Value();
-}
-
-// ------------------------------------------------------------------------------------------------
-template <typename T>
-inline
-T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
- const Property* prop = in.Get(name);
- if( nullptr == prop) {
- if ( ! useTemplate ) {
- result = false;
- return T();
- }
- const PropertyTable* templ = in.TemplateProps();
- if ( nullptr == templ ) {
- result = false;
- return T();
- }
- prop = templ->Get(name);
- if ( nullptr == prop ) {
- result = false;
- return T();
- }
- }
-
- // strong typing, no need to be lenient
- const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
- if( nullptr == tprop) {
- result = false;
- return T();
- }
-
- result = true;
- return tprop->Value();
-}
-
-} //! FBX
-} //! Assimp
-
-#endif // INCLUDED_AI_FBX_PROPERTIES_H
diff --git a/thirdparty/assimp/code/FBX/FBXTokenizer.cpp b/thirdparty/assimp/code/FBX/FBXTokenizer.cpp
deleted file mode 100644
index 252cce3557..0000000000
--- a/thirdparty/assimp/code/FBX/FBXTokenizer.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXTokenizer.cpp
- * @brief Implementation of the FBX broadphase lexer
- */
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-// tab width for logging columns
-#define ASSIMP_FBX_TAB_WIDTH 4
-
-#include <assimp/ParsingUtils.h>
-
-#include "FBXTokenizer.h"
-#include "FBXUtil.h"
-#include <assimp/Exceptional.h>
-
-namespace Assimp {
-namespace FBX {
-
-// ------------------------------------------------------------------------------------------------
-Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column)
- :
-#ifdef DEBUG
- contents(sbegin, static_cast<size_t>(send-sbegin)),
-#endif
- sbegin(sbegin)
- , send(send)
- , type(type)
- , line(line)
- , column(column)
-{
- ai_assert(sbegin);
- ai_assert(send);
-
- // tokens must be of non-zero length
- ai_assert(static_cast<size_t>(send-sbegin) > 0);
-}
-
-// ------------------------------------------------------------------------------------------------
-Token::~Token()
-{
-}
-
-namespace {
-
-// ------------------------------------------------------------------------------------------------
-// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError.
-AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX;
-AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column)
-{
- throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,column));
-}
-
-
-// process a potential data token up to 'cur', adding it to 'output_tokens'.
-// ------------------------------------------------------------------------------------------------
-void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*& end,
- unsigned int line,
- unsigned int column,
- TokenType type = TokenType_DATA,
- bool must_have_token = false)
-{
- if (start && end) {
- // sanity check:
- // tokens should have no whitespace outside quoted text and [start,end] should
- // properly delimit the valid range.
- bool in_double_quotes = false;
- for (const char* c = start; c != end + 1; ++c) {
- if (*c == '\"') {
- in_double_quotes = !in_double_quotes;
- }
-
- if (!in_double_quotes && IsSpaceOrNewLine(*c)) {
- TokenizeError("unexpected whitespace in token", line, column);
- }
- }
-
- if (in_double_quotes) {
- TokenizeError("non-terminated double quotes", line, column);
- }
-
- output_tokens.push_back(new_Token(start,end + 1,type,line,column));
- }
- else if (must_have_token) {
- TokenizeError("unexpected character, expected data token", line, column);
- }
-
- start = end = NULL;
-}
-
-}
-
-// ------------------------------------------------------------------------------------------------
-void Tokenize(TokenList& output_tokens, const char* input)
-{
- ai_assert(input);
-
- // line and column numbers numbers are one-based
- unsigned int line = 1;
- unsigned int column = 1;
-
- bool comment = false;
- bool in_double_quotes = false;
- bool pending_data_token = false;
-
- const char* token_begin = NULL, *token_end = NULL;
- for (const char* cur = input;*cur;column += (*cur == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1), ++cur) {
- const char c = *cur;
-
- if (IsLineEnd(c)) {
- comment = false;
-
- column = 0;
- ++line;
- }
-
- if(comment) {
- continue;
- }
-
- if(in_double_quotes) {
- if (c == '\"') {
- in_double_quotes = false;
- token_end = cur;
-
- ProcessDataToken(output_tokens,token_begin,token_end,line,column);
- pending_data_token = false;
- }
- continue;
- }
-
- switch(c)
- {
- case '\"':
- if (token_begin) {
- TokenizeError("unexpected double-quote", line, column);
- }
- token_begin = cur;
- in_double_quotes = true;
- continue;
-
- case ';':
- ProcessDataToken(output_tokens,token_begin,token_end,line,column);
- comment = true;
- continue;
-
- case '{':
- ProcessDataToken(output_tokens,token_begin,token_end, line, column);
- output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
- continue;
-
- case '}':
- ProcessDataToken(output_tokens,token_begin,token_end,line,column);
- output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
- continue;
-
- case ',':
- if (pending_data_token) {
- ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true);
- }
- output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
- continue;
-
- case ':':
- if (pending_data_token) {
- ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true);
- }
- else {
- TokenizeError("unexpected colon", line, column);
- }
- continue;
- }
-
- if (IsSpaceOrNewLine(c)) {
-
- if (token_begin) {
- // peek ahead and check if the next token is a colon in which
- // case this counts as KEY token.
- TokenType type = TokenType_DATA;
- for (const char* peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) {
- if (*peek == ':') {
- type = TokenType_KEY;
- cur = peek;
- break;
- }
- }
-
- ProcessDataToken(output_tokens,token_begin,token_end,line,column,type);
- }
-
- pending_data_token = false;
- }
- else {
- token_end = cur;
- if (!token_begin) {
- token_begin = cur;
- }
-
- pending_data_token = true;
- }
- }
-}
-
-} // !FBX
-} // !Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXTokenizer.h b/thirdparty/assimp/code/FBX/FBXTokenizer.h
deleted file mode 100644
index afa588a470..0000000000
--- a/thirdparty/assimp/code/FBX/FBXTokenizer.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXTokenizer.h
- * @brief FBX lexer
- */
-#ifndef INCLUDED_AI_FBX_TOKENIZER_H
-#define INCLUDED_AI_FBX_TOKENIZER_H
-
-#include "FBXCompileConfig.h"
-#include <assimp/ai_assert.h>
-#include <vector>
-#include <string>
-
-namespace Assimp {
-namespace FBX {
-
-/** Rough classification for text FBX tokens used for constructing the
- * basic scope hierarchy. */
-enum TokenType
-{
- // {
- TokenType_OPEN_BRACKET = 0,
-
- // }
- TokenType_CLOSE_BRACKET,
-
- // '"blablubb"', '2', '*14' - very general token class,
- // further processing happens at a later stage.
- TokenType_DATA,
-
- //
- TokenType_BINARY_DATA,
-
- // ,
- TokenType_COMMA,
-
- // blubb:
- TokenType_KEY
-};
-
-
-/** Represents a single token in a FBX file. Tokens are
- * classified by the #TokenType enumerated types.
- *
- * Offers iterator protocol. Tokens are immutable. */
-class Token
-{
-private:
- static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1);
-
-public:
- /** construct a textual token */
- Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column);
-
- /** construct a binary token */
- Token(const char* sbegin, const char* send, TokenType type, size_t offset);
-
- ~Token();
-
-public:
- std::string StringContents() const {
- return std::string(begin(),end());
- }
-
- bool IsBinary() const {
- return column == BINARY_MARKER;
- }
-
- const char* begin() const {
- return sbegin;
- }
-
- const char* end() const {
- return send;
- }
-
- TokenType Type() const {
- return type;
- }
-
- size_t Offset() const {
- ai_assert(IsBinary());
- return offset;
- }
-
- unsigned int Line() const {
- ai_assert(!IsBinary());
- return static_cast<unsigned int>(line);
- }
-
- unsigned int Column() const {
- ai_assert(!IsBinary());
- return column;
- }
-
-private:
-
-#ifdef DEBUG
- // full string copy for the sole purpose that it nicely appears
- // in msvc's debugger window.
- const std::string contents;
-#endif
-
-
- const char* const sbegin;
- const char* const send;
- const TokenType type;
-
- union {
- size_t line;
- size_t offset;
- };
- const unsigned int column;
-};
-
-// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
-typedef const Token* TokenPtr;
-typedef std::vector< TokenPtr > TokenList;
-
-#define new_Token new Token
-
-
-/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens.
- *
- * Skips over comments and generates line and column numbers.
- *
- * @param output_tokens Receives a list of all tokens in the input data.
- * @param input_buffer Textual input buffer to be processed, 0-terminated.
- * @throw DeadlyImportError if something goes wrong */
-void Tokenize(TokenList& output_tokens, const char* input);
-
-
-/** Tokenizer function for binary FBX files.
- *
- * Emits a token list suitable for direct parsing.
- *
- * @param output_tokens Receives a list of all tokens in the input data.
- * @param input_buffer Binary input buffer to be processed.
- * @param length Length of input buffer, in bytes. There is no 0-terminal.
- * @throw DeadlyImportError if something goes wrong */
-void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length);
-
-
-} // ! FBX
-} // ! Assimp
-
-#endif // ! INCLUDED_AI_FBX_PARSER_H
diff --git a/thirdparty/assimp/code/FBX/FBXUtil.cpp b/thirdparty/assimp/code/FBX/FBXUtil.cpp
deleted file mode 100644
index c10e057c8c..0000000000
--- a/thirdparty/assimp/code/FBX/FBXUtil.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXUtil.cpp
- * @brief Implementation of internal FBX utility functions
- */
-
-#include "FBXUtil.h"
-#include "FBXTokenizer.h"
-
-#include <assimp/TinyFormatter.h>
-#include <string>
-#include <cstring>
-
-#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-
-namespace Assimp {
-namespace FBX {
-namespace Util {
-
-// ------------------------------------------------------------------------------------------------
-const char* TokenTypeString(TokenType t)
-{
- switch(t) {
- case TokenType_OPEN_BRACKET:
- return "TOK_OPEN_BRACKET";
-
- case TokenType_CLOSE_BRACKET:
- return "TOK_CLOSE_BRACKET";
-
- case TokenType_DATA:
- return "TOK_DATA";
-
- case TokenType_COMMA:
- return "TOK_COMMA";
-
- case TokenType_KEY:
- return "TOK_KEY";
-
- case TokenType_BINARY_DATA:
- return "TOK_BINARY_DATA";
- }
-
- ai_assert(false);
- return "";
-}
-
-
-// ------------------------------------------------------------------------------------------------
-std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset)
-{
- return static_cast<std::string>( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) );
-}
-
-// ------------------------------------------------------------------------------------------------
-std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column)
-{
- return static_cast<std::string>( (Formatter::format() << prefix << " (line " << line << " << col " << column << ") " << text) );
-}
-
-// ------------------------------------------------------------------------------------------------
-std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok)
-{
- if(tok->IsBinary()) {
- return static_cast<std::string>( (Formatter::format() << prefix <<
- " (" << TokenTypeString(tok->Type()) <<
- ", offset 0x" << std::hex << tok->Offset() << ") " <<
- text) );
- }
-
- return static_cast<std::string>( (Formatter::format() << prefix <<
- " (" << TokenTypeString(tok->Type()) <<
- ", line " << tok->Line() <<
- ", col " << tok->Column() << ") " <<
- text) );
-}
-
-// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
-static const uint8_t base64DecodeTable[128] = {
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
- 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
- 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
-};
-
-uint8_t DecodeBase64(char ch)
-{
- const auto idx = static_cast<uint8_t>(ch);
- if (idx > 127)
- return 255;
- return base64DecodeTable[idx];
-}
-
-size_t ComputeDecodedSizeBase64(const char* in, size_t inLength)
-{
- if (inLength < 2)
- {
- return 0;
- }
- const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
- const size_t full_length = (inLength * 3) >> 2; // div by 4
- if (full_length < equals)
- {
- return 0;
- }
- return full_length - equals;
-}
-
-size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength)
-{
- if (maxOutLength == 0 || inLength < 2) {
- return 0;
- }
- const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
- size_t dst_offset = 0;
- int val = 0, valb = -8;
- for (size_t src_offset = 0; src_offset < realLength; ++src_offset)
- {
- const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
- if (table_value == 255)
- {
- return 0;
- }
- val = (val << 6) + table_value;
- valb += 6;
- if (valb >= 0)
- {
- out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
- valb -= 8;
- val &= 0xFFF;
- }
- }
- return dst_offset;
-}
-
-static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-char EncodeBase64(char byte)
-{
- return to_base64_string[(size_t)byte];
-}
-
-/** Encodes a block of 4 bytes to base64 encoding
-*
-* @param bytes Bytes to encode.
-* @param out_string String to write encoded values to.
-* @param string_pos Position in out_string.*/
-void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos)
-{
- char b0 = (bytes[0] & 0xFC) >> 2;
- char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4);
- char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6);
- char b3 = (bytes[2] & 0x3F);
-
- out_string[string_pos + 0] = EncodeBase64(b0);
- out_string[string_pos + 1] = EncodeBase64(b1);
- out_string[string_pos + 2] = EncodeBase64(b2);
- out_string[string_pos + 3] = EncodeBase64(b3);
-}
-
-std::string EncodeBase64(const char* data, size_t length)
-{
- // calculate extra bytes needed to get a multiple of 3
- size_t extraBytes = 3 - length % 3;
-
- // number of base64 bytes
- size_t encodedBytes = 4 * (length + extraBytes) / 3;
-
- std::string encoded_string(encodedBytes, '=');
-
- // read blocks of 3 bytes
- for (size_t ib3 = 0; ib3 < length / 3; ib3++)
- {
- const size_t iByte = ib3 * 3;
- const size_t iEncodedByte = ib3 * 4;
- const char* currData = &data[iByte];
-
- EncodeByteBlock(currData, encoded_string, iEncodedByte);
- }
-
- // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed)
- if (extraBytes > 0)
- {
- char finalBytes[4] = { 0,0,0,0 };
- memcpy(&finalBytes[0], &data[length - length % 3], length % 3);
-
- const size_t iEncodedByte = encodedBytes - 4;
- EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
-
- // add '=' at the end
- for (size_t i = 0; i < 4 * extraBytes / 3; i++)
- encoded_string[encodedBytes - i - 1] = '=';
- }
- return encoded_string;
-}
-
-} // !Util
-} // !FBX
-} // !Assimp
-
-#endif
diff --git a/thirdparty/assimp/code/FBX/FBXUtil.h b/thirdparty/assimp/code/FBX/FBXUtil.h
deleted file mode 100644
index b634418858..0000000000
--- a/thirdparty/assimp/code/FBX/FBXUtil.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, 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 FBXUtil.h
- * @brief FBX utility functions for internal use
- */
-#ifndef INCLUDED_AI_FBX_UTIL_H
-#define INCLUDED_AI_FBX_UTIL_H
-
-#include "FBXCompileConfig.h"
-#include "FBXTokenizer.h"
-#include <stdint.h>
-
-namespace Assimp {
-namespace FBX {
-
-
-namespace Util {
-
-
-/** helper for std::for_each to delete all heap-allocated items in a container */
-template<typename T>
-struct delete_fun
-{
- void operator()(const volatile T* del) {
- delete del;
- }
-};
-
-/** Get a string representation for a #TokenType. */
-const char* TokenTypeString(TokenType t);
-
-
-
-/** Format log/error messages using a given offset in the source binary file
- *
- * @param prefix Message prefix to be preprended to the location info.
- * @param text Message text
- * @param line Line index, 1-based
- * @param column Column index, 1-based
- * @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/
-std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset);
-
-
-/** Format log/error messages using a given line location in the source file.
- *
- * @param prefix Message prefix to be preprended to the location info.
- * @param text Message text
- * @param line Line index, 1-based
- * @param column Column index, 1-based
- * @return A string of the following format: {prefix} (line {line}, col {column}) {text}*/
-std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column);
-
-
-/** Format log/error messages using a given cursor token.
- *
- * @param prefix Message prefix to be preprended to the location info.
- * @param text Message text
- * @param tok Token where parsing/processing stopped
- * @return A string of the following format: {prefix} ({token-type}, line {line}, col {column}) {text}*/
-std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok);
-
-/** Decode a single Base64-encoded character.
-*
-* @param ch Character to decode (from base64 to binary).
-* @return decoded byte value*/
-uint8_t DecodeBase64(char ch);
-
-/** Compute decoded size of a Base64-encoded string
-*
-* @param in Characters to decode.
-* @param inLength Number of characters to decode.
-* @return size of the decoded data (number of bytes)*/
-size_t ComputeDecodedSizeBase64(const char* in, size_t inLength);
-
-/** Decode a Base64-encoded string
-*
-* @param in Characters to decode.
-* @param inLength Number of characters to decode.
-* @param out Pointer where we will store the decoded data.
-* @param maxOutLength Size of output buffer.
-* @return size of the decoded data (number of bytes)*/
-size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength);
-
-char EncodeBase64(char byte);
-
-/** Encode bytes in base64-encoding
-*
-* @param data Binary data to encode.
-* @param inLength Number of bytes to encode.
-* @return base64-encoded string*/
-std::string EncodeBase64(const char* data, size_t length);
-
-}
-}
-}
-
-#endif // ! INCLUDED_AI_FBX_UTIL_H