_ZN6Assimp19Discreet3DSImporterC2Ev:
  104|    297|        mStream(nullptr), mLastNodeIndex(), mCurrentNode(), mRootNode(), mScene(), mMasterScale(), bHasBG(), bIsPrj() {
  105|       |    // empty
  106|    297|}
_ZNK6Assimp19Discreet3DSImporter7GetInfoEv:
  117|    297|const aiImporterDesc *Discreet3DSImporter::GetInfo() const {
  118|    297|    return &desc;
  119|    297|}

_ZN6Assimp19Discreet3DSImporterD2Ev:
   65|    297|    ~Discreet3DSImporter() override = default;

_ZNK6Assimp12D3MFImporter7GetInfoEv:
  101|    297|const aiImporterDesc *D3MFImporter::GetInfo() const {
  102|    297|    return &desc;
  103|    297|}

_ZN6Assimp12D3MFImporterC2Ev:
   59|    297|    D3MFImporter() = default;

_ZN6Assimp12AC3DImporterC2Ev:
  161|    297|        mBuffer(),
  162|       |        configSplitBFCull(),
  163|       |        configEvalSubdivision(),
  164|       |        mNumMeshes(),
  165|       |        mLights(),
  166|    297|        mLightsCounter(0),
  167|    297|        mGroupsCounter(0),
  168|    297|        mPolysCounter(0),
  169|    297|        mWorldsCounter(0) {
  170|       |    // nothing to be done here
  171|    297|}
_ZNK6Assimp12AC3DImporter7GetInfoEv:
  182|    297|const aiImporterDesc *AC3DImporter::GetInfo() const {
  183|    297|    return &desc;
  184|    297|}

_ZN6Assimp11AMFImporter5ClearEv:
   69|    297|void AMFImporter::Clear() {
   70|    297|    mNodeElement_Cur = nullptr;
   71|    297|    mUnit.clear();
   72|    297|    mMaterial_Converted.clear();
   73|    297|    mTexture_Converted.clear();
   74|       |    // Delete all elements
   75|    297|    if (!mNodeElement_List.empty()) {
  ------------------
  |  Branch (75:9): [True: 0, False: 297]
  ------------------
   76|      0|        for (AMFNodeElementBase *ne : mNodeElement_List) {
  ------------------
  |  Branch (76:37): [True: 0, False: 0]
  ------------------
   77|      0|            delete ne;
   78|      0|        }
   79|       |
   80|      0|        mNodeElement_List.clear();
   81|      0|    }
   82|    297|}
_ZN6Assimp11AMFImporterC2Ev:
   85|    297|        mNodeElement_Cur(nullptr),
   86|    297|        mXmlParser(nullptr) {
   87|       |    // empty
   88|    297|}
_ZN6Assimp11AMFImporterD2Ev:
   90|    297|AMFImporter::~AMFImporter() {
   91|    297|    delete mXmlParser;
   92|       |    // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
   93|    297|    Clear();
   94|    297|}
_ZNK6Assimp11AMFImporter7GetInfoEv:
  487|    297|const aiImporterDesc *AMFImporter::GetInfo() const {
  488|    297|    return &Description;
  489|    297|}

_ZN6Assimp11ASEImporterC2Ev:
   85|    297|        mParser(), mBuffer(), pcScene(), configRecomputeNormals(), noSkeletonMesh() {
   86|       |    // empty
   87|    297|}
_ZNK6Assimp11ASEImporter7GetInfoEv:
   98|    297|const aiImporterDesc *ASEImporter::GetInfo() const {
   99|    297|    return &desc;
  100|    297|}

_ZNK6Assimp14AssbinImporter7GetInfoEv:
   82|    297|const aiImporterDesc *AssbinImporter::GetInfo() const {
   83|    297|    return &desc;
   84|    297|}

_ZN6Assimp11B3DImporterD2Ev:
   91|    297|B3DImporter::~B3DImporter() = default;
_ZNK6Assimp11B3DImporter7GetInfoEv:
  110|    297|const aiImporterDesc *B3DImporter::GetInfo() const {
  111|    297|    return &desc;
  112|    297|}

_ZN6Assimp11B3DImporterC2Ev:
   66|    297|    B3DImporter() = default;

_ZN6Assimp9BVHLoaderC2Ev:
   86|    297|        noSkeletonMesh() {
   87|       |    // empty
   88|    297|}
_ZNK6Assimp9BVHLoader7GetInfoEv:
  104|    297|const aiImporterDesc *BVHLoader::GetInfo() const {
  105|    297|    return &desc;
  106|    297|}

_ZN6Assimp9BVHLoaderD2Ev:
   88|    297|    ~BVHLoader() override = default;

_ZN6Assimp7Blender25CustomDataTypeDescriptionC2EPFbPNS0_8ElemBaseEmRKNS0_12FileDatabaseEEPFS3_mEPFvS3_E:
   77|     84|            Read(read), Create(create), Destroy(destroy) {}

_ZN6Assimp7Blender9TempArrayINSt3__16vectorENS0_15BlenderModifierEEC2Ev:
   67|    297|        TempArray() = default;
_ZN6Assimp7Blender9TempArrayINSt3__16vectorENS0_15BlenderModifierEED2Ev:
   69|    297|        ~TempArray () {
   70|    297|            for(T* elem : arr) {
  ------------------
  |  Branch (70:25): [True: 0, False: 297]
  ------------------
   71|      0|                delete elem;
   72|      0|            }
   73|    297|        }

_ZN6Assimp15BlenderImporterC2Ev:
  101|    297|        modifier_cache(new BlenderModifierShowcase()) {
  102|       |    // empty
  103|    297|}
_ZN6Assimp15BlenderImporterD2Ev:
  107|    297|BlenderImporter::~BlenderImporter() {
  108|    297|    delete modifier_cache;
  109|    297|}
_ZNK6Assimp15BlenderImporter7GetInfoEv:
  121|    297|const aiImporterDesc *BlenderImporter::GetInfo() const {
  122|    297|    return &blenderDesc;
  123|    297|}

_ZNK6Assimp11COBImporter7GetInfoEv:
  102|    297|const aiImporterDesc *COBImporter::GetInfo() const {
  103|    297|    return &desc;
  104|    297|}

_ZN6Assimp11COBImporterC2Ev:
   77|    297|    COBImporter() = default;

_ZN6Assimp11CSMImporterC2Ev:
   76|    297|CSMImporter::CSMImporter() : noSkeletonMesh() {
   77|       |    // empty
   78|    297|}
_ZNK6Assimp11CSMImporter7GetInfoEv:
   89|    297|const aiImporterDesc* CSMImporter::GetInfo () const {
   90|    297|    return &desc;
   91|    297|}

_ZN6Assimp13ColladaLoaderC2Ev:
  103|    297|        noSkeletonMesh(false),
  104|    297|        removeEmptyBones(false),
  105|    297|        ignoreUpDirection(false),
  106|    297|        ignoreUnitSize(false),
  107|    297|        useColladaName(false),
  108|    297|        mNodeNameCounter(0) {
  109|       |    // empty
  110|    297|}
_ZNK6Assimp13ColladaLoader7GetInfoEv:
  136|    297|const aiImporterDesc *ColladaLoader::GetInfo() const {
  137|    297|    return &desc;
  138|    297|}

_ZN6Assimp13ColladaLoaderD2Ev:
   91|    297|    ~ColladaLoader() override = default;

_ZNK6Assimp11DXFImporter7GetInfoEv:
  363|    297|const aiImporterDesc* DXFImporter::GetInfo () const {
  364|    297|    return &desc;
  365|    297|}

_ZN6Assimp11DXFImporterC2Ev:
   71|    297|    DXFImporter() = default;

_ZN6Assimp3FBX14AnimationCurveC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentE:
   61|  28.0k|        Object(id, element, name) {
   62|  28.0k|    const Scope &sc = GetRequiredScope(element);
   63|  28.0k|    const Element &KeyTime = GetRequiredElement(sc, "KeyTime");
   64|  28.0k|    const Element &KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat");
   65|       |
   66|  28.0k|    ParseVectorDataArray(keys, KeyTime);
   67|  28.0k|    ParseVectorDataArray(values, KeyValueFloat);
   68|       |
   69|  28.0k|    if (keys.size() != values.size()) {
  ------------------
  |  Branch (69:9): [True: 0, False: 28.0k]
  ------------------
   70|      0|        DOMError("the number of key times does not match the number of keyframe values", &KeyTime);
   71|      0|    }
   72|       |
   73|       |    // check if the key times are well-ordered
   74|  28.0k|    if (!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
  ------------------
  |  Branch (74:9): [True: 114, False: 27.9k]
  ------------------
   75|    114|        DOMError("the keyframes are not in ascending order", &KeyTime);
   76|    114|    }
   77|       |
   78|  27.9k|    const Element *KeyAttrDataFloat = sc["KeyAttrDataFloat"];
   79|  27.9k|    if (KeyAttrDataFloat) {
  ------------------
  |  Branch (79:9): [True: 27.6k, False: 327]
  ------------------
   80|  27.6k|        ParseVectorDataArray(attributes, *KeyAttrDataFloat);
   81|  27.6k|    }
   82|       |
   83|  27.9k|    const Element *KeyAttrFlags = sc["KeyAttrFlags"];
   84|  27.9k|    if (KeyAttrFlags) {
  ------------------
  |  Branch (84:9): [True: 27.6k, False: 316]
  ------------------
   85|  27.6k|        ParseVectorDataArray(flags, *KeyAttrFlags);
   86|  27.6k|    }
   87|  27.9k|}
_ZN6Assimp3FBX18AnimationCurveNodeC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentEPKPKcm:
   93|  10.8k|        Object(id, element, name), target(), doc(doc) {
   94|  10.8k|    const Scope &sc = GetRequiredScope(element);
   95|       |
   96|       |    // find target node
   97|  10.8k|    const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
   98|  10.8k|    const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
   99|       |
  100|  10.8k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (100:32): [True: 10.4k, False: 382]
  ------------------
  101|       |
  102|       |        // link should go for a property
  103|  10.4k|        if (!con->PropertyName().length()) {
  ------------------
  |  Branch (103:13): [True: 8, False: 10.4k]
  ------------------
  104|      8|            continue;
  105|      8|        }
  106|       |
  107|  10.4k|        if (target_prop_whitelist) {
  ------------------
  |  Branch (107:13): [True: 0, False: 10.4k]
  ------------------
  108|      0|            const char *const s = con->PropertyName().c_str();
  109|      0|            bool ok = false;
  110|      0|            for (size_t i = 0; i < whitelist_size; ++i) {
  ------------------
  |  Branch (110:32): [True: 0, False: 0]
  ------------------
  111|      0|                if (!strcmp(s, target_prop_whitelist[i])) {
  ------------------
  |  Branch (111:21): [True: 0, False: 0]
  ------------------
  112|      0|                    ok = true;
  113|      0|                    break;
  114|      0|                }
  115|      0|            }
  116|       |
  117|      0|            if (!ok) {
  ------------------
  |  Branch (117:17): [True: 0, False: 0]
  ------------------
  118|      0|                throw std::range_error("AnimationCurveNode target property is not in whitelist");
  119|      0|            }
  120|      0|        }
  121|       |
  122|  10.4k|        const Object *const ob = con->DestinationObject();
  123|  10.4k|        if (!ob) {
  ------------------
  |  Branch (123:13): [True: 6, False: 10.4k]
  ------------------
  124|      6|            DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", &element);
  125|      6|            continue;
  126|      6|        }
  127|       |
  128|  10.4k|        target = ob;
  129|  10.4k|        if (!target) {
  ------------------
  |  Branch (129:13): [True: 0, False: 10.4k]
  ------------------
  130|      0|            continue;
  131|      0|        }
  132|       |
  133|  10.4k|        prop = con->PropertyName();
  134|  10.4k|        break;
  135|  10.4k|    }
  136|       |
  137|  10.8k|    if (!target) {
  ------------------
  |  Branch (137:9): [True: 382, False: 10.4k]
  ------------------
  138|    382|        DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode", &element);
  139|    382|    }
  140|       |
  141|  10.8k|    props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
  142|  10.8k|}
_ZNK6Assimp3FBX18AnimationCurveNode6CurvesEv:
  145|  28.3k|const AnimationCurveMap &AnimationCurveNode::Curves() const {
  146|  28.3k|    if (!curves.empty()) {
  ------------------
  |  Branch (146:9): [True: 18.7k, False: 9.53k]
  ------------------
  147|  18.7k|        return curves;
  148|  18.7k|    }
  149|       |
  150|       |    // resolve attached animation curves
  151|  9.53k|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
  152|       |
  153|  28.0k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (153:32): [True: 28.0k, False: 9.53k]
  ------------------
  154|       |
  155|       |        // link should go for a property
  156|  28.0k|        if (!con->PropertyName().length()) {
  ------------------
  |  Branch (156:13): [True: 19, False: 28.0k]
  ------------------
  157|     19|            continue;
  158|     19|        }
  159|       |
  160|  28.0k|        const Object *const ob = con->SourceObject();
  161|  28.0k|        if (nullptr == ob) {
  ------------------
  |  Branch (161:13): [True: 366, False: 27.6k]
  ------------------
  162|    366|            DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring", &element);
  163|    366|            continue;
  164|    366|        }
  165|       |
  166|  27.6k|        const AnimationCurve *const anim = dynamic_cast<const AnimationCurve *>(ob);
  167|  27.6k|        if (nullptr == anim) {
  ------------------
  |  Branch (167:13): [True: 0, False: 27.6k]
  ------------------
  168|      0|            DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element);
  169|      0|            continue;
  170|      0|        }
  171|       |
  172|  27.6k|        curves[con->PropertyName()] = anim;
  173|  27.6k|    }
  174|       |
  175|  9.53k|    return curves;
  176|  28.3k|}
_ZN6Assimp3FBX14AnimationLayerC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentE:
  180|    250|        Object(id, element, name), doc(doc) {
  181|    250|    const Scope &sc = GetRequiredScope(element);
  182|       |
  183|       |    // note: the props table here bears little importance and is usually absent
  184|    250|    props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
  185|    250|}
_ZNK6Assimp3FBX14AnimationLayer5NodesEPKPKcm:
  189|    250|        size_t whitelist_size /*= 0*/) const {
  190|    250|    AnimationCurveNodeList nodes;
  191|       |
  192|       |    // resolve attached animation nodes
  193|    250|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode");
  194|    250|    nodes.reserve(conns.size());
  195|       |
  196|  10.8k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (196:32): [True: 10.8k, False: 250]
  ------------------
  197|       |
  198|       |        // link should not go to a property
  199|  10.8k|        if (con->PropertyName().length()) {
  ------------------
  |  Branch (199:13): [True: 0, False: 10.8k]
  ------------------
  200|      0|            continue;
  201|      0|        }
  202|       |
  203|  10.8k|        const Object *const ob = con->SourceObject();
  204|  10.8k|        if (!ob) {
  ------------------
  |  Branch (204:13): [True: 3, False: 10.8k]
  ------------------
  205|      3|            DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", &element);
  206|      3|            continue;
  207|      3|        }
  208|       |
  209|  10.8k|        const AnimationCurveNode *const anim = dynamic_cast<const AnimationCurveNode *>(ob);
  210|  10.8k|        if (!anim) {
  ------------------
  |  Branch (210:13): [True: 0, False: 10.8k]
  ------------------
  211|      0|            DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", &element);
  212|      0|            continue;
  213|      0|        }
  214|       |
  215|  10.8k|        if (target_prop_whitelist) {
  ------------------
  |  Branch (215:13): [True: 10.8k, False: 5]
  ------------------
  216|  10.8k|            const char *s = anim->TargetProperty().c_str();
  217|  10.8k|            bool ok = false;
  218|  23.7k|            for (size_t i = 0; i < whitelist_size; ++i) {
  ------------------
  |  Branch (218:32): [True: 23.0k, False: 667]
  ------------------
  219|  23.0k|                if (!strcmp(s, target_prop_whitelist[i])) {
  ------------------
  |  Branch (219:21): [True: 10.1k, False: 12.8k]
  ------------------
  220|  10.1k|                    ok = true;
  221|  10.1k|                    break;
  222|  10.1k|                }
  223|  23.0k|            }
  224|  10.8k|            if (!ok) {
  ------------------
  |  Branch (224:17): [True: 667, False: 10.1k]
  ------------------
  225|    667|                continue;
  226|    667|            }
  227|  10.8k|        }
  228|  10.1k|        nodes.push_back(anim);
  229|  10.1k|    }
  230|       |
  231|    250|    return nodes; // pray for NRVO
  232|    250|}
_ZN6Assimp3FBX14AnimationStackC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentE:
  236|    256|        Object(id, element, name) {
  237|    256|    const Scope &sc = GetRequiredScope(element);
  238|       |
  239|       |    // note: we don't currently use any of these properties so we shouldn't bother if it is missing
  240|    256|    props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
  241|       |
  242|       |    // resolve attached animation layers
  243|    256|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
  244|    256|    layers.reserve(conns.size());
  245|       |
  246|    256|    for (const Connection *con : conns) {
  ------------------
  |  Branch (246:32): [True: 250, False: 256]
  ------------------
  247|       |
  248|       |        // link should not go to a property
  249|    250|        if (con->PropertyName().length()) {
  ------------------
  |  Branch (249:13): [True: 0, False: 250]
  ------------------
  250|      0|            continue;
  251|      0|        }
  252|       |
  253|    250|        const Object *const ob = con->SourceObject();
  254|    250|        if (!ob) {
  ------------------
  |  Branch (254:13): [True: 0, False: 250]
  ------------------
  255|      0|            DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", &element);
  256|      0|            continue;
  257|      0|        }
  258|       |
  259|    250|        const AnimationLayer *const anim = dynamic_cast<const AnimationLayer *>(ob);
  260|    250|        if (!anim) {
  ------------------
  |  Branch (260:13): [True: 0, False: 250]
  ------------------
  261|      0|            DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", &element);
  262|      0|            continue;
  263|      0|        }
  264|    250|        layers.push_back(anim);
  265|    250|    }
  266|    256|}

_ZN6Assimp3FBX5TokenC2EPKcS3_NS0_9TokenTypeEm:
   67|  3.24M|        sbegin(sbegin),
   68|  3.24M|        send(send),
   69|  3.24M|        type(type),
   70|  3.24M|        line(offset),
   71|  3.24M|        column(BINARY_MARKER) {
   72|  3.24M|    ai_assert(sbegin);
  ------------------
  |  |   67|  3.24M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 3.24M, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   73|  3.24M|    ai_assert(send);
  ------------------
  |  |   67|  3.24M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 3.24M, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   74|       |
   75|       |    // binary tokens may have zero length because they are sometimes dummies
   76|       |    // inserted by TokenizeBinary()
   77|  3.24M|    ai_assert(send >= sbegin);
  ------------------
  |  |   67|  3.24M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 3.24M, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   78|  3.24M|}
_ZN6Assimp3FBX14TokenizeBinaryERNSt3__16vectorIPKNS0_5TokenENS1_9allocatorIS5_EEEEPKcmRNS_14StackAllocatorE:
  394|    258|void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &token_allocator) {
  395|    258|	ai_assert(input);
  ------------------
  |  |   67|    258|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 258, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  396|    258|	ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
  397|       |
  398|    258|    if(length < 0x1b) {
  ------------------
  |  Branch (398:8): [True: 0, False: 258]
  ------------------
  399|      0|        TokenizeError("file is too short",0);
  400|      0|    }
  401|       |
  402|       |    //uint32_t offset = 0x15;
  403|       |/*    const char* cursor = input + 0x15;
  404|       |
  405|       |    const uint32_t flags = ReadWord(input, cursor, input + length);
  406|       |
  407|       |    const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused
  408|       |    const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused*/
  409|       |
  410|    258|    if (strncmp(input,"Kaydara FBX Binary",18)) {
  ------------------
  |  Branch (410:9): [True: 0, False: 258]
  ------------------
  411|      0|        TokenizeError("magic bytes not found",0);
  412|      0|    }
  413|       |
  414|    258|    const char* cursor = input + 18;
  415|    258|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  416|    258|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  417|    258|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  418|    258|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  419|    258|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  420|    258|	const uint32_t version = ReadWord(input, cursor, input + length);
  421|    258|	ASSIMP_LOG_DEBUG("FBX version: ", version);
  422|    258|	const bool is64bits = version >= 7500;
  423|    258|    const char *end = input + length;
  424|    258|    try
  425|    258|    {
  426|  3.04k|        while (cursor < end ) {
  ------------------
  |  Branch (426:16): [True: 3.03k, False: 8]
  ------------------
  427|  3.03k|            if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) {
  ------------------
  |  Branch (427:17): [True: 250, False: 2.78k]
  ------------------
  428|    250|                break;
  429|    250|            }
  430|  3.03k|        }
  431|    258|    }
  432|    258|    catch (const DeadlyImportError& e)
  433|    258|    {
  434|      8|        if (!is64bits && (length > std::numeric_limits<uint32_t>::max())) {
  ------------------
  |  Branch (434:13): [True: 7, False: 1]
  |  Branch (434:26): [True: 0, False: 7]
  ------------------
  435|      0|            throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", ai_to_string(version), ") of the FBX format. (", e.what(), ")");
  436|      0|        }
  437|      8|        throw;
  438|      8|    }
  439|    258|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_113TokenizeErrorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEm:
   87|      8|{
   88|      8|    throw DeadlyImportError("FBX-Tokenize", Util::GetOffsetText(offset), message);
   89|      8|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_18ReadByteEPKcRS3_S3_:
  140|   632k|uint8_t ReadByte(const char* input, const char*& cursor, const char* end) {
  141|   632k|    if(Offset(cursor, end) < sizeof( uint8_t ) ) {
  ------------------
  |  Branch (141:8): [True: 0, False: 632k]
  ------------------
  142|      0|        TokenizeError("cannot ReadByte, out of bounds",input, cursor);
  143|      0|    }
  144|       |
  145|   632k|    uint8_t word;/* = *reinterpret_cast< const uint8_t* >( cursor )*/
  146|   632k|    ::memcpy( &word, cursor, sizeof( uint8_t ) );
  147|   632k|    ++cursor;
  148|       |
  149|   632k|    return word;
  150|   632k|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_16OffsetEPKcS3_:
   93|  15.5M|size_t Offset(const char* begin, const char* cursor) {
   94|  15.5M|    if (begin > cursor) {
  ------------------
  |  Branch (94:9): [True: 0, False: 15.5M]
  ------------------
   95|      0|		return 0;
   96|      0|	}
   97|       |
   98|  15.5M|    return cursor - begin;
   99|  15.5M|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_113TokenizeErrorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKcSC_:
  103|      8|void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
  104|      8|    TokenizeError(message, Offset(begin, cursor));
  105|      8|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_18ReadWordEPKcRS3_S3_:
  108|  3.28M|uint32_t ReadWord(const char* input, const char*& cursor, const char* end) {
  109|  3.28M|    const size_t k_to_read = sizeof( uint32_t );
  110|  3.28M|    if(Offset(cursor, end) < k_to_read ) {
  ------------------
  |  Branch (110:8): [True: 0, False: 3.28M]
  ------------------
  111|      0|        TokenizeError("cannot ReadWord, out of bounds",input, cursor);
  112|      0|    }
  113|       |
  114|  3.28M|    uint32_t word;
  115|  3.28M|    ::memcpy(&word, cursor, 4);
  116|  3.28M|    AI_SWAP4(word);
  117|       |
  118|  3.28M|    cursor += k_to_read;
  119|       |
  120|  3.28M|    return word;
  121|  3.28M|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_19ReadScopeERNSt3__16vectorIPKNS0_5TokenENS2_9allocatorIS6_EEEERNS_14StackAllocatorEPKcRSE_SE_b:
  305|   631k|bool ReadScope(TokenList &output_tokens, StackAllocator &token_allocator, const char *input, const char *&cursor, const char *end, bool const is64bits) {
  306|       |    // the first word contains the offset at which this block ends
  307|   631k|	const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
  ------------------
  |  Branch (307:30): [True: 1, False: 631k]
  ------------------
  308|       |
  309|       |    // we may get 0 if reading reached the end of the file -
  310|       |    // fbx files have a mysterious extra footer which I don't know
  311|       |    // how to extract any information from, but at least it always
  312|       |    // starts with a 0.
  313|   631k|    if(!end_offset) {
  ------------------
  |  Branch (313:8): [True: 250, False: 630k]
  ------------------
  314|    250|        return false;
  315|    250|    }
  316|       |
  317|   630k|    if(end_offset > Offset(input, end)) {
  ------------------
  |  Branch (317:8): [True: 1, False: 630k]
  ------------------
  318|      1|        TokenizeError("block offset is out of range",input, cursor);
  319|      1|    }
  320|   630k|    else if(end_offset < Offset(input, cursor)) {
  ------------------
  |  Branch (320:13): [True: 1, False: 630k]
  ------------------
  321|      1|        TokenizeError("block offset is negative out of range",input, cursor);
  322|      1|    }
  323|       |
  324|       |    // the second data word contains the number of properties in the scope
  325|   630k|	const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
  ------------------
  |  Branch (325:30): [True: 1, False: 630k]
  ------------------
  326|       |
  327|       |    // the third data word contains the length of the property list
  328|   630k|	const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
  ------------------
  |  Branch (328:31): [True: 1, False: 630k]
  ------------------
  329|       |
  330|       |    // now comes the name of the scope/key
  331|   630k|    const char* sbeg, *send;
  332|   630k|    ReadString(sbeg, send, input, cursor, end);
  333|       |
  334|   630k|    output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) ));
  ------------------
  |  |  160|  1.26M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  335|       |
  336|       |    // now come the individual properties
  337|   630k|    const char* begin_cursor = cursor;
  338|       |
  339|   630k|    if ((begin_cursor + prop_length) > end) {
  ------------------
  |  Branch (339:9): [True: 0, False: 630k]
  ------------------
  340|      0|        TokenizeError("property length out of bounds reading length ", input, cursor);
  341|      0|    }
  342|       |
  343|  2.13M|    for (unsigned int i = 0; i < prop_count; ++i) {
  ------------------
  |  Branch (343:30): [True: 1.50M, False: 630k]
  ------------------
  344|  1.50M|        ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
  345|       |
  346|  1.50M|        output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) ));
  ------------------
  |  |  160|  3.01M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  347|       |
  348|  1.50M|        if(i != prop_count-1) {
  ------------------
  |  Branch (348:12): [True: 908k, False: 599k]
  ------------------
  349|   908k|            output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) ));
  ------------------
  |  |  160|  1.81M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  350|   908k|        }
  351|  1.50M|    }
  352|       |
  353|   630k|    if (Offset(begin_cursor, cursor) != prop_length) {
  ------------------
  |  Branch (353:9): [True: 0, False: 630k]
  ------------------
  354|      0|        TokenizeError("property length not reached, something is wrong",input, cursor);
  355|      0|    }
  356|       |
  357|       |    // at the end of each nested block, there is a NUL record to indicate
  358|       |    // that the sub-scope exists (i.e. to distinguish between P: and P : {})
  359|       |    // this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit.
  360|   630k|	const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1);
  ------------------
  |  Branch (360:39): [True: 0, False: 630k]
  ------------------
  361|       |
  362|   630k|    if (Offset(input, cursor) < end_offset) {
  ------------------
  |  Branch (362:9): [True: 98.3k, False: 532k]
  ------------------
  363|  98.3k|        if (end_offset - Offset(input, cursor) < sentinel_block_length) {
  ------------------
  |  Branch (363:13): [True: 0, False: 98.3k]
  ------------------
  364|      0|            TokenizeError("insufficient padding bytes at block end",input, cursor);
  365|      0|        }
  366|       |
  367|  98.3k|        output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) ));
  ------------------
  |  |  160|   196k|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  368|       |
  369|       |        // XXX this is vulnerable to stack overflowing ..
  370|   726k|        while(Offset(input, cursor) < end_offset - sentinel_block_length) {
  ------------------
  |  Branch (370:15): [True: 628k, False: 98.3k]
  ------------------
  371|   628k|            ReadScope(output_tokens, token_allocator, input, cursor, input + end_offset - sentinel_block_length, is64bits);
  372|   628k|        }
  373|  98.3k|        output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
  ------------------
  |  |  160|   196k|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  374|       |
  375|  1.37M|        for (unsigned int i = 0; i < sentinel_block_length; ++i) {
  ------------------
  |  Branch (375:34): [True: 1.27M, False: 98.3k]
  ------------------
  376|  1.27M|            if(cursor[i] != '\0') {
  ------------------
  |  Branch (376:16): [True: 0, False: 1.27M]
  ------------------
  377|      0|                TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor);
  378|      0|            }
  379|  1.27M|        }
  380|  98.3k|        cursor += sentinel_block_length;
  381|  98.3k|    }
  382|       |
  383|   630k|    if (Offset(input, cursor) != end_offset) {
  ------------------
  |  Branch (383:9): [True: 0, False: 630k]
  ------------------
  384|      0|        TokenizeError("scope length not reached, something is wrong",input, cursor);
  385|      0|    }
  386|       |
  387|   630k|    return true;
  388|   630k|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_114ReadDoubleWordEPKcRS3_S3_:
  124|      3|uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) {
  125|      3|    const size_t k_to_read = sizeof(uint64_t);
  126|      3|    if(Offset(cursor, end) < k_to_read) {
  ------------------
  |  Branch (126:8): [True: 0, False: 3]
  ------------------
  127|      0|        TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor);
  128|      0|    }
  129|       |
  130|      3|    uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
  131|      3|    ::memcpy( &dword, cursor, sizeof( uint64_t ) );
  132|      3|    AI_SWAP8(dword);
  133|       |
  134|      3|    cursor += k_to_read;
  135|       |
  136|      3|    return dword;
  137|      3|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_110ReadStringERPKcS4_S3_S4_S3_bb:
  154|  1.44M|        const char*& cursor, const char* end, bool long_length = false, bool allow_null = false) {
  155|  1.44M|    const uint32_t len_len = long_length ? 4 : 1;
  ------------------
  |  Branch (155:30): [True: 809k, False: 630k]
  ------------------
  156|  1.44M|    if(Offset(cursor, end) < len_len) {
  ------------------
  |  Branch (156:8): [True: 0, False: 1.44M]
  ------------------
  157|      0|        TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
  158|      0|    }
  159|       |
  160|  1.44M|    const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
  ------------------
  |  Branch (160:29): [True: 809k, False: 630k]
  ------------------
  161|       |
  162|  1.44M|    if (Offset(cursor, end) < length) {
  ------------------
  |  Branch (162:9): [True: 0, False: 1.44M]
  ------------------
  163|      0|        TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
  164|      0|    }
  165|       |
  166|  1.44M|    sbegin_out = cursor;
  167|  1.44M|    cursor += length;
  168|       |
  169|  1.44M|    send_out = cursor;
  170|       |
  171|  1.44M|    if(!allow_null) {
  ------------------
  |  Branch (171:8): [True: 630k, False: 809k]
  ------------------
  172|  5.42M|        for (unsigned int i = 0; i < length; ++i) {
  ------------------
  |  Branch (172:34): [True: 4.79M, False: 630k]
  ------------------
  173|  4.79M|            if(sbegin_out[i] == '\0') {
  ------------------
  |  Branch (173:16): [True: 5, False: 4.79M]
  ------------------
  174|      5|                TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
  175|      5|            }
  176|  4.79M|        }
  177|   630k|    }
  178|       |
  179|  1.44M|    return length;
  180|  1.44M|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_18ReadDataERPKcS4_S3_S4_S3_:
  183|  1.50M|void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) {
  184|  1.50M|    if(Offset(cursor, end) < 1) {
  ------------------
  |  Branch (184:8): [True: 0, False: 1.50M]
  ------------------
  185|      0|        TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
  186|      0|    }
  187|       |
  188|  1.50M|    const char type = *cursor;
  189|  1.50M|    sbegin_out = cursor++;
  190|       |
  191|  1.50M|    switch(type)
  192|  1.50M|    {
  193|       |        // 16 bit int
  194|      0|    case 'Y':
  ------------------
  |  Branch (194:5): [True: 0, False: 1.50M]
  ------------------
  195|      0|        cursor += 2;
  196|      0|        break;
  197|       |
  198|       |        // 1 bit bool flag (yes/no)
  199|  5.04k|    case 'C':
  ------------------
  |  Branch (199:5): [True: 5.04k, False: 1.50M]
  ------------------
  200|  5.04k|        cursor += 1;
  201|  5.04k|        break;
  202|       |
  203|       |        // 32 bit int
  204|   102k|    case 'I':
  ------------------
  |  Branch (204:5): [True: 102k, False: 1.40M]
  ------------------
  205|       |        // <- fall through
  206|       |
  207|       |        // float
  208|   102k|    case 'F':
  ------------------
  |  Branch (208:5): [True: 0, False: 1.50M]
  ------------------
  209|   102k|        cursor += 4;
  210|   102k|        break;
  211|       |
  212|       |        // double
  213|   177k|    case 'D':
  ------------------
  |  Branch (213:5): [True: 177k, False: 1.32M]
  ------------------
  214|   177k|        cursor += 8;
  215|   177k|        break;
  216|       |
  217|       |        // 64 bit int
  218|   218k|    case 'L':
  ------------------
  |  Branch (218:5): [True: 218k, False: 1.28M]
  ------------------
  219|   218k|        cursor += 8;
  220|   218k|        break;
  221|       |
  222|       |        // note: do not write cursor += ReadWord(...cursor) as this would be UB
  223|       |
  224|       |        // raw binary data
  225|    262|    case 'R':
  ------------------
  |  Branch (225:5): [True: 262, False: 1.50M]
  ------------------
  226|    262|    {
  227|    262|        const uint32_t length = ReadWord(input, cursor, end);
  228|    262|        cursor += length;
  229|    262|        break;
  230|   102k|    }
  231|       |
  232|     36|    case 'b':
  ------------------
  |  Branch (232:5): [True: 36, False: 1.50M]
  ------------------
  233|       |        // TODO: what is the 'b' type code? Right now we just skip over it /
  234|       |        // take the full range we could get
  235|     36|        cursor = end;
  236|     36|        break;
  237|       |
  238|       |        // array of *
  239|  68.3k|    case 'f':
  ------------------
  |  Branch (239:5): [True: 68.3k, False: 1.43M]
  ------------------
  240|  87.2k|    case 'd':
  ------------------
  |  Branch (240:5): [True: 18.9k, False: 1.48M]
  ------------------
  241|   121k|    case 'l':
  ------------------
  |  Branch (241:5): [True: 34.1k, False: 1.47M]
  ------------------
  242|   194k|    case 'i':
  ------------------
  |  Branch (242:5): [True: 72.8k, False: 1.43M]
  ------------------
  243|   194k|    case 'c':   {
  ------------------
  |  Branch (243:5): [True: 1, False: 1.50M]
  ------------------
  244|   194k|        const uint32_t length = ReadWord(input, cursor, end);
  245|   194k|        const uint32_t encoding = ReadWord(input, cursor, end);
  246|       |
  247|   194k|        const uint32_t comp_len = ReadWord(input, cursor, end);
  248|       |
  249|       |        // compute length based on type and check against the stored value
  250|   194k|        if(encoding == 0) {
  ------------------
  |  Branch (250:12): [True: 185k, False: 8.57k]
  ------------------
  251|   185k|            uint32_t stride = 0;
  252|   185k|            switch(type)
  253|   185k|            {
  254|  68.3k|            case 'f':
  ------------------
  |  Branch (254:13): [True: 68.3k, False: 117k]
  ------------------
  255|   136k|            case 'i':
  ------------------
  |  Branch (255:13): [True: 68.5k, False: 117k]
  ------------------
  256|   136k|                stride = 4;
  257|   136k|                break;
  258|       |
  259|  14.6k|            case 'd':
  ------------------
  |  Branch (259:13): [True: 14.6k, False: 171k]
  ------------------
  260|  48.7k|            case 'l':
  ------------------
  |  Branch (260:13): [True: 34.1k, False: 151k]
  ------------------
  261|  48.7k|                stride = 8;
  262|  48.7k|                break;
  263|       |
  264|      0|            case 'c':
  ------------------
  |  Branch (264:13): [True: 0, False: 185k]
  ------------------
  265|      0|                stride = 1;
  266|      0|                break;
  267|       |
  268|      0|            default:
  ------------------
  |  Branch (268:13): [True: 0, False: 185k]
  ------------------
  269|      0|                ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  270|   185k|            };
  271|   185k|            ai_assert(stride > 0);
  ------------------
  |  |   67|   185k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 185k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  272|   185k|            if(length * stride != comp_len) {
  ------------------
  |  Branch (272:16): [True: 0, False: 185k]
  ------------------
  273|      0|                TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor);
  274|      0|            }
  275|   185k|        }
  276|       |        // zip/deflate algorithm (encoding==1)? take given length. anything else? die
  277|  8.57k|        else if (encoding != 1) {
  ------------------
  |  Branch (277:18): [True: 0, False: 8.57k]
  ------------------
  278|      0|            TokenizeError("cannot ReadData, unknown encoding",input, cursor);
  279|      0|        }
  280|   194k|        cursor += comp_len;
  281|   194k|        break;
  282|   194k|    }
  283|       |
  284|       |        // string
  285|   809k|    case 'S': {
  ------------------
  |  Branch (285:5): [True: 809k, False: 698k]
  ------------------
  286|   809k|        const char* sb, *se;
  287|       |        // 0 characters can legally happen in such strings
  288|   809k|        ReadString(sb, se, input, cursor, end, true, true);
  289|   809k|        break;
  290|   194k|    }
  291|      1|    default:
  ------------------
  |  Branch (291:5): [True: 1, False: 1.50M]
  ------------------
  292|      1|        TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor);
  293|  1.50M|    }
  294|       |
  295|  1.50M|    if(cursor > end) {
  ------------------
  |  Branch (295:8): [True: 0, False: 1.50M]
  ------------------
  296|      0|        TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor);
  297|      0|    }
  298|       |
  299|       |    // the type code is contained in the returned range
  300|  1.50M|    send_out = cursor;
  301|  1.50M|}

_ZN6Assimp3FBX12FBXConverterC2EP7aiSceneRKNS0_8DocumentEb:
  128|    271|        mMeshes(),
  129|    271|        lights(),
  130|    271|        cameras(),
  131|    271|        textures(),
  132|    271|        materials_converted(),
  133|    271|        textures_converted(),
  134|    271|        meshes_converted(),
  135|    271|        node_anim_chain_bits(),
  136|    271|        mNodeNames(),
  137|       |        anim_fps(),
  138|    271|        mSceneOut(out),
  139|    271|        doc(doc),
  140|    271|        mRemoveEmptyBones(removeEmptyBones) {
  141|       |
  142|       |
  143|       |    // animations need to be converted first since this will
  144|       |    // populate the node_anim_chain_bits map, which is needed
  145|       |    // to determine which nodes need to be generated.
  146|    271|    ConvertAnimations();
  147|       |    // Embedded textures in FBX could be connected to nothing but to itself,
  148|       |    // for instance Texture -> Video connection only but not to the main graph,
  149|       |    // The idea here is to traverse all objects to find these Textures and convert them,
  150|       |    // so later during material conversion it will find converted texture in the textures_converted array.
  151|    271|    if (doc.Settings().readTextures) {
  ------------------
  |  Branch (151:9): [True: 249, False: 22]
  ------------------
  152|    249|        ConvertOrphanedEmbeddedTextures();
  153|    249|    }
  154|    271|    ConvertRootNode();
  155|       |
  156|    271|    if (doc.Settings().readAllMaterials) {
  ------------------
  |  Branch (156:9): [True: 0, False: 271]
  ------------------
  157|       |        // unfortunately this means we have to evaluate all objects
  158|      0|        for (const ObjectMap::value_type &v : doc.Objects()) {
  ------------------
  |  Branch (158:45): [True: 0, False: 0]
  ------------------
  159|       |
  160|      0|            const Object *ob = v.second->Get();
  161|      0|            if (!ob) {
  ------------------
  |  Branch (161:17): [True: 0, False: 0]
  ------------------
  162|      0|                continue;
  163|      0|            }
  164|       |
  165|      0|            const Material *mat = dynamic_cast<const Material *>(ob);
  166|      0|            if (mat) {
  ------------------
  |  Branch (166:17): [True: 0, False: 0]
  ------------------
  167|       |
  168|      0|                if (materials_converted.find(mat) == materials_converted.end()) {
  ------------------
  |  Branch (168:21): [True: 0, False: 0]
  ------------------
  169|      0|                    ConvertMaterial(*mat, nullptr);
  170|      0|                }
  171|      0|            }
  172|      0|        }
  173|      0|    }
  174|       |
  175|    271|    ConvertGlobalSettings();
  176|    271|    TransferDataToScene();
  177|       |
  178|       |    // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE
  179|       |    // to make sure the scene passes assimp's validation. FBX files
  180|       |    // need not contain geometry (i.e. camera animations, raw armatures).
  181|    271|    if (out->mNumMeshes == 0) {
  ------------------
  |  Branch (181:9): [True: 135, False: 136]
  ------------------
  182|    135|        out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  183|    136|    } else {
  184|       |        // Apply the FBX axis metadata unless requested not to
  185|    136|        if (!doc.Settings().ignoreUpDirection)
  ------------------
  |  Branch (185:13): [True: 92, False: 44]
  ------------------
  186|     92|            correctRootTransform(mSceneOut);
  187|    136|    }
  188|    271|}
_ZN6Assimp3FBX12FBXConverterD2Ev:
  190|    227|FBXConverter::~FBXConverter() {
  191|    227|    std::for_each(mMeshes.begin(), mMeshes.end(), Util::delete_fun<aiMesh>());
  192|    227|    std::for_each(materials.begin(), materials.end(), Util::delete_fun<aiMaterial>());
  193|    227|    std::for_each(animations.begin(), animations.end(), Util::delete_fun<aiAnimation>());
  194|    227|    std::for_each(lights.begin(), lights.end(), Util::delete_fun<aiLight>());
  195|    227|    std::for_each(cameras.begin(), cameras.end(), Util::delete_fun<aiCamera>());
  196|    227|    std::for_each(textures.begin(), textures.end(), Util::delete_fun<aiTexture>());
  197|    227|}
_ZN6Assimp3FBX12FBXConverter15ConvertRootNodeEv:
  199|    249|void FBXConverter::ConvertRootNode() {
  200|    249|    mSceneOut->mRootNode = new aiNode();
  201|    249|    std::string unique_name;
  202|    249|    GetUniqueName("RootNode", unique_name);
  203|    249|    mSceneOut->mRootNode->mName.Set(unique_name);
  204|       |
  205|       |    // root has ID 0
  206|    249|    ConvertNodes(0L, mSceneOut->mRootNode, mSceneOut->mRootNode);
  207|    249|}
_ZN6Assimp3FBX12FBXConverter12ConvertNodesEmP6aiNodeS3_RK12aiMatrix4x4tIfE:
  250|  3.81k|void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node, const aiMatrix4x4& parent_transform) {
  251|  3.81k|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
  252|       |
  253|  3.81k|    std::vector<PotentialNode> nodes;
  254|  3.81k|    nodes.reserve(conns.size());
  255|       |
  256|  3.81k|    std::vector<PotentialNode> nodes_chain;
  257|  3.81k|    std::vector<PotentialNode> post_nodes_chain;
  258|       |
  259|  3.81k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (259:32): [True: 3.59k, False: 3.81k]
  ------------------
  260|       |        // ignore object-property links
  261|  3.59k|        if (con->PropertyName().length()) {
  ------------------
  |  Branch (261:13): [True: 0, False: 3.59k]
  ------------------
  262|       |            // really important we document why this is ignored.
  263|      0|            FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
  264|      0|            continue; //?
  265|      0|        }
  266|       |
  267|       |        // convert connection source object into Object base class
  268|  3.59k|        const Object *const object = con->SourceObject();
  269|  3.59k|        if (nullptr == object) {
  ------------------
  |  Branch (269:13): [True: 2, False: 3.58k]
  ------------------
  270|      2|            FBXImporter::LogError("failed to convert source object for Model link");
  271|      2|            continue;
  272|      2|        }
  273|       |
  274|       |        // FBX Model::Cube, Model::Bone001, etc elements
  275|       |        // This detects if we can cast the object into this model structure.
  276|  3.58k|        const Model *const model = dynamic_cast<const Model *>(object);
  277|       |
  278|  3.58k|        if (nullptr != model) {
  ------------------
  |  Branch (278:13): [True: 3.58k, False: 0]
  ------------------
  279|  3.58k|            nodes_chain.clear();
  280|  3.58k|            post_nodes_chain.clear();
  281|  3.58k|            aiMatrix4x4 new_abs_transform = parent_transform;
  282|  3.58k|            std::string node_name = FixNodeName(model->Name());
  283|       |            // even though there is only a single input node, the design of
  284|       |            // assimp (or rather: the complicated transformation chain that
  285|       |            // is employed by fbx) means that we may need multiple aiNode's
  286|       |            // to represent a fbx node's transformation.
  287|       |
  288|       |            // generate node transforms - this includes pivot data
  289|       |            // if need_additional_node is true then you t
  290|  3.58k|            const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
  291|       |
  292|       |            // assert that for the current node we must have at least a single transform
  293|  3.58k|            ai_assert(nodes_chain.size());
  294|       |
  295|  3.58k|            if (need_additional_node) {
  ------------------
  |  Branch (295:17): [True: 356, False: 3.23k]
  ------------------
  296|    356|                nodes_chain.emplace_back(node_name);
  297|    356|            }
  298|       |
  299|       |            //setup metadata on newest node
  300|  3.58k|            SetupNodeMetadata(*model, *nodes_chain.back().mNode);
  301|       |
  302|       |            // link all nodes in a row
  303|  3.58k|            aiNode *last_parent = parent;
  304|  4.89k|            for (PotentialNode& child : nodes_chain) {
  ------------------
  |  Branch (304:39): [True: 4.89k, False: 3.58k]
  ------------------
  305|  4.89k|                ai_assert(child.mNode);
  306|       |
  307|  4.89k|                if (last_parent != parent) {
  ------------------
  |  Branch (307:21): [True: 1.32k, False: 3.56k]
  ------------------
  308|  1.32k|                    last_parent->mNumChildren = 1;
  309|  1.32k|                    last_parent->mChildren = new aiNode *[1];
  310|  1.32k|                    last_parent->mChildren[0] = child.mOwnership.release();
  311|  1.32k|                }
  312|       |
  313|  4.89k|                child->mParent = last_parent;
  314|  4.89k|                last_parent = child.mNode;
  315|       |
  316|  4.89k|                new_abs_transform *= child->mTransformation;
  317|  4.89k|            }
  318|       |
  319|       |            // attach geometry
  320|  3.58k|            ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);
  321|       |
  322|       |            // check if there will be any child nodes
  323|  3.58k|            const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
  324|       |
  325|       |            // if so, link the geometric transform inverse nodes
  326|       |            // before we attach any child nodes
  327|  3.58k|            if (child_conns.size()) {
  ------------------
  |  Branch (327:17): [True: 2.50k, False: 1.08k]
  ------------------
  328|  2.50k|                for (PotentialNode& postnode : post_nodes_chain) {
  ------------------
  |  Branch (328:46): [True: 141, False: 2.50k]
  ------------------
  329|    141|                    ai_assert(postnode.mNode);
  330|       |
  331|    141|                    if (last_parent != parent) {
  ------------------
  |  Branch (331:25): [True: 141, False: 0]
  ------------------
  332|    141|                        last_parent->mNumChildren = 1;
  333|    141|                        last_parent->mChildren = new aiNode *[1];
  334|    141|                        last_parent->mChildren[0] = postnode.mOwnership.release();
  335|    141|                    }
  336|       |
  337|    141|                    postnode->mParent = last_parent;
  338|    141|                    last_parent = postnode.mNode;
  339|       |
  340|    141|                    new_abs_transform *= postnode->mTransformation;
  341|    141|                }
  342|  2.50k|            } else {
  343|       |                // free the nodes we allocated as we don't need them
  344|  1.08k|                post_nodes_chain.clear();
  345|  1.08k|            }
  346|       |
  347|       |            // recursion call - child nodes
  348|  3.58k|            ConvertNodes(model->ID(), last_parent, root_node, new_abs_transform);
  349|       |
  350|  3.58k|            if (doc.Settings().readLights) {
  ------------------
  |  Branch (350:17): [True: 3.55k, False: 32]
  ------------------
  351|  3.55k|                ConvertLights(*model, node_name);
  352|  3.55k|            }
  353|       |
  354|  3.58k|            if (doc.Settings().readCameras) {
  ------------------
  |  Branch (354:17): [True: 3.55k, False: 32]
  ------------------
  355|  3.55k|                ConvertCameras(*model, node_name);
  356|  3.55k|            }
  357|       |
  358|  3.58k|            nodes.push_back(std::move(nodes_chain.front()));
  359|  3.58k|            nodes_chain.clear();
  360|  3.58k|        }
  361|  3.58k|    }
  362|       |
  363|  3.81k|    if (nodes.empty()) {
  ------------------
  |  Branch (363:9): [True: 1.06k, False: 2.75k]
  ------------------
  364|  1.06k|        parent->mNumChildren = 0;
  365|  1.06k|        parent->mChildren = nullptr;
  366|  2.75k|    } else {
  367|  2.75k|        parent->mChildren = new aiNode *[nodes.size()]();
  368|  2.75k|        parent->mNumChildren = static_cast<unsigned int>(nodes.size());
  369|  6.25k|        for (unsigned int i = 0; i < nodes.size(); ++i) {
  ------------------
  |  Branch (369:34): [True: 3.50k, False: 2.75k]
  ------------------
  370|  3.50k|            parent->mChildren[i] = nodes[i].mOwnership.release();
  371|  3.50k|        }
  372|  2.75k|    }
  373|  3.81k|}
_ZN6Assimp3FBX12FBXConverter13ConvertLightsERKNS0_5ModelERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  375|  3.55k|void FBXConverter::ConvertLights(const Model &model, const std::string &orig_name) {
  376|  3.55k|    const std::vector<const NodeAttribute *> &node_attrs = model.GetAttributes();
  377|  3.55k|    for (const NodeAttribute *attr : node_attrs) {
  ------------------
  |  Branch (377:36): [True: 3.23k, False: 3.55k]
  ------------------
  378|  3.23k|        const Light *const light = dynamic_cast<const Light *>(attr);
  379|  3.23k|        if (light) {
  ------------------
  |  Branch (379:13): [True: 215, False: 3.02k]
  ------------------
  380|    215|            ConvertLight(*light, orig_name);
  381|    215|        }
  382|  3.23k|    }
  383|  3.55k|}
_ZN6Assimp3FBX12FBXConverter14ConvertCamerasERKNS0_5ModelERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  385|  3.55k|void FBXConverter::ConvertCameras(const Model &model, const std::string &orig_name) {
  386|  3.55k|    const std::vector<const NodeAttribute *> &node_attrs = model.GetAttributes();
  387|  3.55k|    for (const NodeAttribute *attr : node_attrs) {
  ------------------
  |  Branch (387:36): [True: 3.23k, False: 3.55k]
  ------------------
  388|  3.23k|        const Camera *const cam = dynamic_cast<const Camera *>(attr);
  389|  3.23k|        if (cam) {
  ------------------
  |  Branch (389:13): [True: 221, False: 3.01k]
  ------------------
  390|    221|            ConvertCamera(*cam, orig_name);
  391|    221|        }
  392|  3.23k|    }
  393|  3.55k|}
_ZN6Assimp3FBX12FBXConverter12ConvertLightERKNS0_5LightERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  395|    215|void FBXConverter::ConvertLight(const Light &light, const std::string &orig_name) {
  396|    215|    lights.push_back(new aiLight());
  397|    215|    aiLight *const out_light = lights.back();
  398|       |
  399|    215|    out_light->mName.Set(orig_name);
  400|       |
  401|    215|    const float intensity = light.Intensity() / 100.0f;
  402|    215|    const aiVector3D &col = light.Color();
  403|       |
  404|    215|    out_light->mColorDiffuse = aiColor3D(col.x, col.y, col.z);
  405|    215|    out_light->mColorDiffuse.r *= intensity;
  406|    215|    out_light->mColorDiffuse.g *= intensity;
  407|    215|    out_light->mColorDiffuse.b *= intensity;
  408|       |
  409|    215|    out_light->mColorSpecular = out_light->mColorDiffuse;
  410|       |
  411|       |    //lights are defined along negative y direction
  412|    215|    out_light->mPosition = aiVector3D(0.0f);
  413|    215|    out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f);
  414|    215|    out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f);
  415|       |
  416|    215|    switch (light.LightType()) {
  417|    215|        case Light::Type_Point:
  ------------------
  |  Branch (417:9): [True: 215, False: 0]
  ------------------
  418|    215|            out_light->mType = aiLightSource_POINT;
  419|    215|            break;
  420|       |
  421|      0|        case Light::Type_Directional:
  ------------------
  |  Branch (421:9): [True: 0, False: 215]
  ------------------
  422|      0|            out_light->mType = aiLightSource_DIRECTIONAL;
  423|      0|            break;
  424|       |
  425|      0|        case Light::Type_Spot:
  ------------------
  |  Branch (425:9): [True: 0, False: 215]
  ------------------
  426|      0|            out_light->mType = aiLightSource_SPOT;
  427|      0|            out_light->mAngleOuterCone = AI_DEG_TO_RAD(light.OuterAngle());
  428|      0|            out_light->mAngleInnerCone = AI_DEG_TO_RAD(light.InnerAngle());
  429|      0|            break;
  430|       |
  431|      0|        case Light::Type_Area:
  ------------------
  |  Branch (431:9): [True: 0, False: 215]
  ------------------
  432|      0|            FBXImporter::LogWarn("cannot represent area light, set to UNDEFINED");
  433|      0|            out_light->mType = aiLightSource_UNDEFINED;
  434|      0|            break;
  435|       |
  436|      0|        case Light::Type_Volume:
  ------------------
  |  Branch (436:9): [True: 0, False: 215]
  ------------------
  437|      0|            FBXImporter::LogWarn("cannot represent volume light, set to UNDEFINED");
  438|      0|            out_light->mType = aiLightSource_UNDEFINED;
  439|      0|            break;
  440|      0|        default:
  ------------------
  |  Branch (440:9): [True: 0, False: 215]
  ------------------
  441|      0|            FBXImporter::LogError("Not handled light type: ", light.LightType());
  442|      0|            break;
  443|    215|    }
  444|       |
  445|    215|    float decay = light.DecayStart();
  446|    215|    switch (light.DecayType()) {
  447|      0|        case Light::Decay_None:
  ------------------
  |  Branch (447:9): [True: 0, False: 215]
  ------------------
  448|      0|            out_light->mAttenuationConstant = decay;
  449|      0|            out_light->mAttenuationLinear = 0.0f;
  450|      0|            out_light->mAttenuationQuadratic = 0.0f;
  451|      0|            break;
  452|      0|        case Light::Decay_Linear:
  ------------------
  |  Branch (452:9): [True: 0, False: 215]
  ------------------
  453|      0|            out_light->mAttenuationConstant = 0.0f;
  454|      0|            out_light->mAttenuationLinear = 2.0f / decay;
  455|      0|            out_light->mAttenuationQuadratic = 0.0f;
  456|      0|            break;
  457|    215|        case Light::Decay_Quadratic:
  ------------------
  |  Branch (457:9): [True: 215, False: 0]
  ------------------
  458|    215|            out_light->mAttenuationConstant = 0.0f;
  459|    215|            out_light->mAttenuationLinear = 0.0f;
  460|    215|            out_light->mAttenuationQuadratic = 2.0f / (decay * decay);
  461|    215|            break;
  462|      0|        case Light::Decay_Cubic:
  ------------------
  |  Branch (462:9): [True: 0, False: 215]
  ------------------
  463|      0|            FBXImporter::LogWarn("cannot represent cubic attenuation, set to Quadratic");
  464|      0|            out_light->mAttenuationQuadratic = 1.0f;
  465|      0|            break;
  466|      0|        default:
  ------------------
  |  Branch (466:9): [True: 0, False: 215]
  ------------------
  467|      0|            FBXImporter::LogError("Not handled light decay type: ", light.DecayType());
  468|      0|            break;
  469|    215|    }
  470|    215|}
_ZN6Assimp3FBX12FBXConverter13ConvertCameraERKNS0_6CameraERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  472|    221|void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name) {
  473|    221|    cameras.push_back(new aiCamera());
  474|    221|    aiCamera *const out_camera = cameras.back();
  475|       |
  476|    221|    out_camera->mName.Set(orig_name);
  477|       |
  478|    221|    out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
  479|       |
  480|       |    // NOTE: Camera mPosition, mLookAt and mUp must be set to default here.
  481|       |    // All transformations to the camera will be handled by its node in the scenegraph.
  482|    221|    out_camera->mPosition = aiVector3D(0.0f);
  483|    221|    out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
  484|    221|    out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
  485|       |
  486|       |    // NOTE: Some software (maya) does not put FieldOfView in FBX, so we compute
  487|       |    // mHorizontalFOV from FocalLength and FilmWidth with unit conversion.
  488|       |
  489|       |    // TODO: This is not a complete solution for how FBX cameras can be stored.
  490|       |    // TODO: Incorporate non-square pixel aspect ratio.
  491|       |    // TODO: FBX aperture mode might be storing vertical FOV in need of conversion with aspect ratio.
  492|       |
  493|    221|    float fov_deg = cam.FieldOfView();
  494|       |    // If FOV not specified in file, compute using FilmWidth and FocalLength.
  495|    221|    if (fov_deg == kFovUnknown) {
  ------------------
  |  Branch (495:9): [True: 4, False: 217]
  ------------------
  496|      4|        float film_width_inches = cam.FilmWidth();
  497|      4|        float focal_length_mm = cam.FocalLength();
  498|      4|        ASSIMP_LOG_VERBOSE_DEBUG("FBX FOV unspecified. Computing from FilmWidth (", film_width_inches, "inches) and FocalLength (", focal_length_mm, "mm).");
  499|      4|        double half_fov_rad = std::atan2(film_width_inches * 25.4 * 0.5, focal_length_mm);
  500|      4|        out_camera->mHorizontalFOV = static_cast<float>(half_fov_rad);
  501|    217|    } else {
  502|       |        // FBX fov is full-view degrees. We want half-view radians.
  503|    217|        out_camera->mHorizontalFOV = AI_DEG_TO_RAD(fov_deg) * 0.5f;
  504|    217|    }
  505|       |
  506|    221|    out_camera->mClipPlaneNear = cam.NearPlane();
  507|    221|    out_camera->mClipPlaneFar = cam.FarPlane();
  508|    221|}
_ZN6Assimp3FBX12FBXConverter13GetUniqueNameERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERS8_:
  510|    249|void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName) {
  511|    249|    uniqueName = name;
  512|    249|    auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
  513|    249|    unsigned int &i = it_pair.first->second;
  514|    249|    while (!it_pair.second) {
  ------------------
  |  Branch (514:12): [True: 0, False: 249]
  ------------------
  515|      0|        ++i;
  516|      0|        std::ostringstream ext;
  517|      0|        ext << name << std::setfill('0') << std::setw(3) << i;
  518|      0|        uniqueName = ext.str();
  519|      0|        it_pair = mNodeNames.insert({ uniqueName, 0 });
  520|      0|    }
  521|    249|}
_ZN6Assimp3FBX12FBXConverter22NameTransformationCompENS1_18TransformationCompE:
  523|  2.99k|const char *FBXConverter::NameTransformationComp(TransformationComp comp) {
  524|  2.99k|    switch (comp) {
  525|    832|        case TransformationComp_Translation:
  ------------------
  |  Branch (525:9): [True: 832, False: 2.16k]
  ------------------
  526|    832|            return "Translation";
  527|      0|        case TransformationComp_RotationOffset:
  ------------------
  |  Branch (527:9): [True: 0, False: 2.99k]
  ------------------
  528|      0|            return "RotationOffset";
  529|     35|        case TransformationComp_RotationPivot:
  ------------------
  |  Branch (529:9): [True: 35, False: 2.96k]
  ------------------
  530|     35|            return "RotationPivot";
  531|     57|        case TransformationComp_PreRotation:
  ------------------
  |  Branch (531:9): [True: 57, False: 2.94k]
  ------------------
  532|     57|            return "PreRotation";
  533|    802|        case TransformationComp_Rotation:
  ------------------
  |  Branch (533:9): [True: 802, False: 2.19k]
  ------------------
  534|    802|            return "Rotation";
  535|      0|        case TransformationComp_PostRotation:
  ------------------
  |  Branch (535:9): [True: 0, False: 2.99k]
  ------------------
  536|      0|            return "PostRotation";
  537|     35|        case TransformationComp_RotationPivotInverse:
  ------------------
  |  Branch (537:9): [True: 35, False: 2.96k]
  ------------------
  538|     35|            return "RotationPivotInverse";
  539|      0|        case TransformationComp_ScalingOffset:
  ------------------
  |  Branch (539:9): [True: 0, False: 2.99k]
  ------------------
  540|      0|            return "ScalingOffset";
  541|      0|        case TransformationComp_ScalingPivot:
  ------------------
  |  Branch (541:9): [True: 0, False: 2.99k]
  ------------------
  542|      0|            return "ScalingPivot";
  543|    749|        case TransformationComp_Scaling:
  ------------------
  |  Branch (543:9): [True: 749, False: 2.24k]
  ------------------
  544|    749|            return "Scaling";
  545|      0|        case TransformationComp_ScalingPivotInverse:
  ------------------
  |  Branch (545:9): [True: 0, False: 2.99k]
  ------------------
  546|      0|            return "ScalingPivotInverse";
  547|    264|        case TransformationComp_GeometricScaling:
  ------------------
  |  Branch (547:9): [True: 264, False: 2.73k]
  ------------------
  548|    264|            return "GeometricScaling";
  549|      0|        case TransformationComp_GeometricRotation:
  ------------------
  |  Branch (549:9): [True: 0, False: 2.99k]
  ------------------
  550|      0|            return "GeometricRotation";
  551|      0|        case TransformationComp_GeometricTranslation:
  ------------------
  |  Branch (551:9): [True: 0, False: 2.99k]
  ------------------
  552|      0|            return "GeometricTranslation";
  553|    224|        case TransformationComp_GeometricScalingInverse:
  ------------------
  |  Branch (553:9): [True: 224, False: 2.77k]
  ------------------
  554|    224|            return "GeometricScalingInverse";
  555|      0|        case TransformationComp_GeometricRotationInverse:
  ------------------
  |  Branch (555:9): [True: 0, False: 2.99k]
  ------------------
  556|      0|            return "GeometricRotationInverse";
  557|      0|        case TransformationComp_GeometricTranslationInverse:
  ------------------
  |  Branch (557:9): [True: 0, False: 2.99k]
  ------------------
  558|      0|            return "GeometricTranslationInverse";
  559|      0|        case TransformationComp_MAXIMUM: // this is to silence compiler warnings
  ------------------
  |  Branch (559:9): [True: 0, False: 2.99k]
  ------------------
  560|      0|        default:
  ------------------
  |  Branch (560:9): [True: 0, False: 2.99k]
  ------------------
  561|      0|            break;
  562|  2.99k|    }
  563|       |
  564|  2.99k|    ai_assert(false);
  565|       |
  566|      0|    return nullptr;
  567|  2.99k|}
_ZN6Assimp3FBX12FBXConverter30NameTransformationCompPropertyENS1_18TransformationCompE:
  569|  92.1k|const char *FBXConverter::NameTransformationCompProperty(TransformationComp comp) {
  570|  92.1k|    switch (comp) {
  ------------------
  |  Branch (570:13): [True: 92.1k, False: 0]
  ------------------
  571|  3.25k|        case TransformationComp_Translation:
  ------------------
  |  Branch (571:9): [True: 3.25k, False: 88.9k]
  ------------------
  572|  3.25k|            return "Lcl Translation";
  573|  6.51k|        case TransformationComp_RotationOffset:
  ------------------
  |  Branch (573:9): [True: 6.51k, False: 85.6k]
  ------------------
  574|  6.51k|            return "RotationOffset";
  575|  6.50k|        case TransformationComp_RotationPivot:
  ------------------
  |  Branch (575:9): [True: 6.50k, False: 85.6k]
  ------------------
  576|  6.50k|            return "RotationPivot";
  577|  6.45k|        case TransformationComp_PreRotation:
  ------------------
  |  Branch (577:9): [True: 6.45k, False: 85.7k]
  ------------------
  578|  6.45k|            return "PreRotation";
  579|  3.25k|        case TransformationComp_Rotation:
  ------------------
  |  Branch (579:9): [True: 3.25k, False: 88.9k]
  ------------------
  580|  3.25k|            return "Lcl Rotation";
  581|  6.23k|        case TransformationComp_PostRotation:
  ------------------
  |  Branch (581:9): [True: 6.23k, False: 85.9k]
  ------------------
  582|  6.23k|            return "PostRotation";
  583|  2.98k|        case TransformationComp_RotationPivotInverse:
  ------------------
  |  Branch (583:9): [True: 2.98k, False: 89.2k]
  ------------------
  584|  2.98k|            return "RotationPivotInverse";
  585|  6.23k|        case TransformationComp_ScalingOffset:
  ------------------
  |  Branch (585:9): [True: 6.23k, False: 85.9k]
  ------------------
  586|  6.23k|            return "ScalingOffset";
  587|  6.23k|        case TransformationComp_ScalingPivot:
  ------------------
  |  Branch (587:9): [True: 6.23k, False: 85.9k]
  ------------------
  588|  6.23k|            return "ScalingPivot";
  589|  3.25k|        case TransformationComp_Scaling:
  ------------------
  |  Branch (589:9): [True: 3.25k, False: 88.9k]
  ------------------
  590|  3.25k|            return "Lcl Scaling";
  591|  2.98k|        case TransformationComp_ScalingPivotInverse:
  ------------------
  |  Branch (591:9): [True: 2.98k, False: 89.2k]
  ------------------
  592|  2.98k|            return "ScalingPivotInverse";
  593|  6.23k|        case TransformationComp_GeometricScaling:
  ------------------
  |  Branch (593:9): [True: 6.23k, False: 85.9k]
  ------------------
  594|  6.23k|            return "GeometricScaling";
  595|  6.23k|        case TransformationComp_GeometricRotation:
  ------------------
  |  Branch (595:9): [True: 6.23k, False: 85.9k]
  ------------------
  596|  6.23k|            return "GeometricRotation";
  597|  6.23k|        case TransformationComp_GeometricTranslation:
  ------------------
  |  Branch (597:9): [True: 6.23k, False: 85.9k]
  ------------------
  598|  6.23k|            return "GeometricTranslation";
  599|  6.51k|        case TransformationComp_GeometricScalingInverse:
  ------------------
  |  Branch (599:9): [True: 6.51k, False: 85.6k]
  ------------------
  600|  6.51k|            return "GeometricScalingInverse";
  601|  6.51k|        case TransformationComp_GeometricRotationInverse:
  ------------------
  |  Branch (601:9): [True: 6.51k, False: 85.6k]
  ------------------
  602|  6.51k|            return "GeometricRotationInverse";
  603|  6.51k|        case TransformationComp_GeometricTranslationInverse:
  ------------------
  |  Branch (603:9): [True: 6.51k, False: 85.6k]
  ------------------
  604|  6.51k|            return "GeometricTranslationInverse";
  605|      0|        case TransformationComp_MAXIMUM:
  ------------------
  |  Branch (605:9): [True: 0, False: 92.1k]
  ------------------
  606|      0|            break;
  607|  92.1k|    }
  608|       |
  609|  92.1k|    ai_assert(false);
  610|       |
  611|      0|    return nullptr;
  612|  92.1k|}
_ZN6Assimp3FBX12FBXConverter17GetRotationMatrixENS0_5Model8RotOrderERK10aiVector3tIfER12aiMatrix4x4tIfE:
  620|  4.88M|void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rotation, aiMatrix4x4 &out) {
  621|  4.88M|    if (mode == Model::RotOrder_SphericXYZ) {
  ------------------
  |  Branch (621:9): [True: 0, False: 4.88M]
  ------------------
  622|      0|        FBXImporter::LogError("Unsupported RotationMode: SphericXYZ");
  623|      0|        out = aiMatrix4x4();
  624|      0|        return;
  625|      0|    }
  626|       |
  627|  4.88M|    const float angle_epsilon = Math::getEpsilon<float>();
  628|       |
  629|  4.88M|    out = aiMatrix4x4();
  630|       |
  631|  4.88M|    bool is_id[3] = { true, true, true };
  632|       |
  633|  4.88M|    aiMatrix4x4 temp[3];
  634|  4.88M|    const auto rot = AI_DEG_TO_RAD(rotation);
  635|  4.88M|    if (std::fabs(rot.z) > angle_epsilon) {
  ------------------
  |  Branch (635:9): [True: 1.28M, False: 3.59M]
  ------------------
  636|  1.28M|        aiMatrix4x4::RotationZ(rot.z, temp[2]);
  637|  1.28M|        is_id[2] = false;
  638|  1.28M|    }
  639|  4.88M|    if (std::fabs(rot.y) > angle_epsilon) {
  ------------------
  |  Branch (639:9): [True: 1.05M, False: 3.82M]
  ------------------
  640|  1.05M|        aiMatrix4x4::RotationY(rot.y, temp[1]);
  641|  1.05M|        is_id[1] = false;
  642|  1.05M|    }
  643|  4.88M|    if (std::fabs(rot.x) > angle_epsilon) {
  ------------------
  |  Branch (643:9): [True: 4.64M, False: 235k]
  ------------------
  644|  4.64M|        aiMatrix4x4::RotationX(rot.x, temp[0]);
  645|  4.64M|        is_id[0] = false;
  646|  4.64M|    }
  647|       |
  648|  4.88M|    int order[3] = { -1, -1, -1 };
  649|       |
  650|       |    // note: rotation order is inverted since we're left multiplying as is usual in assimp
  651|  4.88M|    switch (mode) {
  652|  4.88M|        case Model::RotOrder_EulerXYZ:
  ------------------
  |  Branch (652:9): [True: 4.88M, False: 0]
  ------------------
  653|  4.88M|            order[0] = 2;
  654|  4.88M|            order[1] = 1;
  655|  4.88M|            order[2] = 0;
  656|  4.88M|            break;
  657|       |
  658|      0|        case Model::RotOrder_EulerXZY:
  ------------------
  |  Branch (658:9): [True: 0, False: 4.88M]
  ------------------
  659|      0|            order[0] = 1;
  660|      0|            order[1] = 2;
  661|      0|            order[2] = 0;
  662|      0|            break;
  663|       |
  664|      0|        case Model::RotOrder_EulerYZX:
  ------------------
  |  Branch (664:9): [True: 0, False: 4.88M]
  ------------------
  665|      0|            order[0] = 0;
  666|      0|            order[1] = 2;
  667|      0|            order[2] = 1;
  668|      0|            break;
  669|       |
  670|      0|        case Model::RotOrder_EulerYXZ:
  ------------------
  |  Branch (670:9): [True: 0, False: 4.88M]
  ------------------
  671|      0|            order[0] = 2;
  672|      0|            order[1] = 0;
  673|      0|            order[2] = 1;
  674|      0|            break;
  675|       |
  676|      0|        case Model::RotOrder_EulerZXY:
  ------------------
  |  Branch (676:9): [True: 0, False: 4.88M]
  ------------------
  677|      0|            order[0] = 1;
  678|      0|            order[1] = 0;
  679|      0|            order[2] = 2;
  680|      0|            break;
  681|       |
  682|      0|        case Model::RotOrder_EulerZYX:
  ------------------
  |  Branch (682:9): [True: 0, False: 4.88M]
  ------------------
  683|      0|            order[0] = 0;
  684|      0|            order[1] = 1;
  685|      0|            order[2] = 2;
  686|      0|            break;
  687|       |
  688|      0|        default:
  ------------------
  |  Branch (688:9): [True: 0, False: 4.88M]
  ------------------
  689|      0|            ai_assert(false);
  690|      0|            break;
  691|  4.88M|    }
  692|       |
  693|  4.88M|    ai_assert(order[0] >= 0);
  694|  4.88M|    ai_assert(order[0] <= 2);
  695|  4.88M|    ai_assert(order[1] >= 0);
  696|  4.88M|    ai_assert(order[1] <= 2);
  697|  4.88M|    ai_assert(order[2] >= 0);
  698|  4.88M|    ai_assert(order[2] <= 2);
  699|       |
  700|  4.88M|    if (!is_id[order[0]]) {
  ------------------
  |  Branch (700:9): [True: 1.28M, False: 3.59M]
  ------------------
  701|  1.28M|        out = temp[order[0]];
  702|  1.28M|    }
  703|       |
  704|  4.88M|    if (!is_id[order[1]]) {
  ------------------
  |  Branch (704:9): [True: 1.05M, False: 3.82M]
  ------------------
  705|  1.05M|        out = out * temp[order[1]];
  706|  1.05M|    }
  707|       |
  708|  4.88M|    if (!is_id[order[2]]) {
  ------------------
  |  Branch (708:9): [True: 4.64M, False: 235k]
  ------------------
  709|  4.64M|        out = out * temp[order[2]];
  710|  4.64M|    }
  711|  4.88M|}
_ZN6Assimp3FBX12FBXConverter31NeedsComplexTransformationChainERKNS0_5ModelE:
  713|  3.25k|bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
  714|  3.25k|    const PropertyTable &props = model.Props();
  715|       |
  716|  3.25k|    const auto zero_epsilon = Math::getEpsilon<ai_real>();
  717|  3.25k|    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
  718|  55.2k|    for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
  ------------------
  |  Branch (718:24): [True: 52.5k, False: 2.72k]
  ------------------
  719|  52.5k|        const TransformationComp comp = static_cast<TransformationComp>(i);
  720|       |
  721|  52.5k|        if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) {
  ------------------
  |  Branch (721:13): [True: 2.98k, False: 49.5k]
  |  Branch (721:52): [True: 2.98k, False: 46.5k]
  |  Branch (721:90): [True: 3.25k, False: 43.3k]
  ------------------
  722|  9.22k|            continue;
  723|  9.22k|        }
  724|       |
  725|  43.3k|        bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
  ------------------
  |  Branch (725:31): [True: 2.98k, False: 40.3k]
  |  Branch (725:78): [True: 0, False: 40.3k]
  ------------------
  726|       |
  727|  43.3k|        bool ok = true;
  728|  43.3k|        const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
  729|  43.3k|        if (ok && scale_compare) {
  ------------------
  |  Branch (729:13): [True: 26.2k, False: 17.1k]
  |  Branch (729:19): [True: 2.84k, False: 23.3k]
  ------------------
  730|  2.84k|            if ((v - all_ones).SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (730:17): [True: 260, False: 2.58k]
  ------------------
  731|    260|                return true;
  732|    260|            }
  733|  40.4k|        } else if (ok) {
  ------------------
  |  Branch (733:20): [True: 23.3k, False: 17.1k]
  ------------------
  734|  23.3k|            if (v.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (734:17): [True: 274, False: 23.0k]
  ------------------
  735|    274|                return true;
  736|    274|            }
  737|  23.3k|        }
  738|  43.3k|    }
  739|       |
  740|  2.72k|    return false;
  741|  3.25k|}
_ZN6Assimp3FBX12FBXConverter27NameTransformationChainNodeERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS1_18TransformationCompE:
  743|  2.99k|std::string FBXConverter::NameTransformationChainNode(const std::string &name, TransformationComp comp) {
  744|  2.99k|    return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
  ------------------
  |  |   75|  2.99k|#define MAGIC_NODE_TAG "_$AssimpFbx$"
  ------------------
  745|  2.99k|}
_ZN6Assimp3FBX12FBXConverter31GenerateTransformationNodeChainERKNS0_5ModelERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERNS5_6vectorINS1_13PotentialNodeENS9_ISF_EEEESI_:
  748|  3.58k|        std::vector<PotentialNode> &post_output_nodes) {
  749|  3.58k|    const PropertyTable &props = model.Props();
  750|  3.58k|    const Model::RotOrder rot = model.RotationOrder();
  751|       |
  752|  3.58k|    bool ok;
  753|       |
  754|  3.58k|    aiMatrix4x4 chain[TransformationComp_MAXIMUM];
  755|       |
  756|  3.58k|    ai_assert(TransformationComp_MAXIMUM < 32);
  757|  3.58k|    std::uint32_t chainBits = 0;
  758|       |    // A node won't need a node chain if it only has these.
  759|  3.58k|    const std::uint32_t chainMaskSimple = (1 << TransformationComp_Translation) + (1 << TransformationComp_Scaling) + (1 << TransformationComp_Rotation);
  760|       |    // A node will need a node chain if it has any of these.
  761|  3.58k|    const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple;
  762|       |
  763|  3.58k|    std::fill_n(chain, static_cast<unsigned int>(TransformationComp_MAXIMUM), aiMatrix4x4());
  764|       |
  765|       |    // generate transformation matrices for all the different transformation components
  766|  3.58k|    const float zero_epsilon = Math::getEpsilon<float>();
  767|  3.58k|    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
  768|       |
  769|  3.58k|    const aiVector3D &PreRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
  770|  3.58k|    if (ok && PreRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (770:9): [True: 3.40k, False: 187]
  |  Branch (770:15): [True: 70, False: 3.33k]
  ------------------
  771|     70|        chainBits = chainBits | (1 << TransformationComp_PreRotation);
  772|       |
  773|     70|        GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]);
  774|     70|    }
  775|       |
  776|  3.58k|    const aiVector3D &PostRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok);
  777|  3.58k|    if (ok && PostRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (777:9): [True: 3.38k, False: 208]
  |  Branch (777:15): [True: 0, False: 3.38k]
  ------------------
  778|      0|        chainBits = chainBits | (1 << TransformationComp_PostRotation);
  779|       |
  780|      0|        GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]);
  781|      0|    }
  782|       |
  783|  3.58k|    const aiVector3D &RotationPivot = PropertyGet<aiVector3D>(props, "RotationPivot", ok);
  784|  3.58k|    if (ok && RotationPivot.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (784:9): [True: 3.38k, False: 204]
  |  Branch (784:15): [True: 35, False: 3.35k]
  ------------------
  785|     35|        chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse);
  786|       |
  787|     35|        aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]);
  788|     35|        aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]);
  789|     35|    }
  790|       |
  791|  3.58k|    const aiVector3D &RotationOffset = PropertyGet<aiVector3D>(props, "RotationOffset", ok);
  792|  3.58k|    if (ok && RotationOffset.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (792:9): [True: 3.36k, False: 224]
  |  Branch (792:15): [True: 0, False: 3.36k]
  ------------------
  793|      0|        chainBits = chainBits | (1 << TransformationComp_RotationOffset);
  794|       |
  795|      0|        aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]);
  796|      0|    }
  797|       |
  798|  3.58k|    const aiVector3D &ScalingOffset = PropertyGet<aiVector3D>(props, "ScalingOffset", ok);
  799|  3.58k|    if (ok && ScalingOffset.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (799:9): [True: 3.37k, False: 212]
  |  Branch (799:15): [True: 0, False: 3.37k]
  ------------------
  800|      0|        chainBits = chainBits | (1 << TransformationComp_ScalingOffset);
  801|       |
  802|      0|        aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]);
  803|      0|    }
  804|       |
  805|  3.58k|    const aiVector3D &ScalingPivot = PropertyGet<aiVector3D>(props, "ScalingPivot", ok);
  806|  3.58k|    if (ok && ScalingPivot.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (806:9): [True: 3.39k, False: 197]
  |  Branch (806:15): [True: 0, False: 3.39k]
  ------------------
  807|      0|        chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse);
  808|       |
  809|      0|        aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]);
  810|      0|        aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]);
  811|      0|    }
  812|       |
  813|  3.58k|    const aiVector3D &Translation = PropertyGet<aiVector3D>(props, "Lcl Translation", ok);
  814|  3.58k|    if (ok && Translation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (814:9): [True: 3.54k, False: 47]
  |  Branch (814:15): [True: 3.49k, False: 50]
  ------------------
  815|  3.49k|        chainBits = chainBits | (1 << TransformationComp_Translation);
  816|       |
  817|  3.49k|        aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]);
  818|  3.49k|    }
  819|       |
  820|  3.58k|    const aiVector3D &Scaling = PropertyGet<aiVector3D>(props, "Lcl Scaling", ok);
  821|  3.58k|    if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (821:9): [True: 3.52k, False: 65]
  |  Branch (821:9): [True: 861, False: 2.72k]
  |  Branch (821:15): [True: 861, False: 2.66k]
  ------------------
  822|    861|        chainBits = chainBits | (1 << TransformationComp_Scaling);
  823|       |
  824|    861|        aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]);
  825|    861|    }
  826|       |
  827|  3.58k|    const aiVector3D &Rotation = PropertyGet<aiVector3D>(props, "Lcl Rotation", ok);
  828|  3.58k|    if (ok && Rotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (828:9): [True: 3.52k, False: 69]
  |  Branch (828:15): [True: 2.84k, False: 676]
  ------------------
  829|  2.84k|        chainBits = chainBits | (1 << TransformationComp_Rotation);
  830|       |
  831|  2.84k|        GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]);
  832|  2.84k|    }
  833|       |
  834|  3.58k|    const aiVector3D &GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok);
  835|  3.58k|    if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (835:9): [True: 3.39k, False: 198]
  |  Branch (835:9): [True: 264, False: 3.32k]
  |  Branch (835:15): [True: 264, False: 3.12k]
  ------------------
  836|    264|        chainBits = chainBits | (1 << TransformationComp_GeometricScaling);
  837|    264|        aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]);
  838|    264|        aiVector3D GeometricScalingInverse = GeometricScaling;
  839|    264|        bool canscale = true;
  840|  1.01k|        for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (840:34): [True: 792, False: 224]
  ------------------
  841|    792|            if (std::fabs(GeometricScalingInverse[i]) > zero_epsilon) {
  ------------------
  |  Branch (841:17): [True: 752, False: 40]
  ------------------
  842|    752|                GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
  843|    752|            } else {
  844|     40|                FBXImporter::LogError("cannot invert geometric scaling matrix with a 0.0 scale component");
  845|     40|                canscale = false;
  846|     40|                break;
  847|     40|            }
  848|    792|        }
  849|    264|        if (canscale) {
  ------------------
  |  Branch (849:13): [True: 224, False: 40]
  ------------------
  850|    224|            chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse);
  851|    224|            aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]);
  852|    224|        }
  853|    264|    }
  854|       |
  855|  3.58k|    const aiVector3D &GeometricRotation = PropertyGet<aiVector3D>(props, "GeometricRotation", ok);
  856|  3.58k|    if (ok && GeometricRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (856:9): [True: 3.37k, False: 218]
  |  Branch (856:15): [True: 0, False: 3.37k]
  ------------------
  857|      0|        chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse);
  858|      0|        GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]);
  859|      0|        GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]);
  860|      0|        chain[TransformationComp_GeometricRotationInverse].Inverse();
  861|      0|    }
  862|       |
  863|  3.58k|    const aiVector3D &GeometricTranslation = PropertyGet<aiVector3D>(props, "GeometricTranslation", ok);
  864|  3.58k|    if (ok && GeometricTranslation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (864:9): [True: 3.31k, False: 278]
  |  Branch (864:15): [True: 0, False: 3.31k]
  ------------------
  865|      0|        chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse);
  866|      0|        aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]);
  867|      0|        aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]);
  868|      0|    }
  869|       |
  870|       |    // now, if we have more than just Translation, Scaling and Rotation,
  871|       |    // we need to generate a full node chain to accommodate for assimp's
  872|       |    // lack to express pivots and offsets.
  873|  3.58k|    if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) {
  ------------------
  |  Branch (873:9): [True: 356, False: 3.23k]
  |  Branch (873:43): [True: 356, False: 0]
  ------------------
  874|    356|        FBXImporter::LogInfo("generating full transformation chain for node: ", name);
  875|       |
  876|       |        // query the anim_chain_bits dictionary to find out which chain elements
  877|       |        // have associated node animation channels. These can not be dropped
  878|       |        // even if they have identity transform in bind pose.
  879|    356|        NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find(name);
  880|    356|        const unsigned int anim_chain_bitmask = (it == node_anim_chain_bits.end() ? 0 : (*it).second);
  ------------------
  |  Branch (880:50): [True: 144, False: 212]
  ------------------
  881|       |
  882|    356|        unsigned int bit = 0x1;
  883|  6.40k|        for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) {
  ------------------
  |  Branch (883:28): [True: 6.05k, False: 356]
  ------------------
  884|  6.05k|            const TransformationComp comp = static_cast<TransformationComp>(i);
  885|       |
  886|  6.05k|            if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) {
  ------------------
  |  Branch (886:17): [True: 4.70k, False: 1.34k]
  |  Branch (886:43): [True: 4.50k, False: 207]
  ------------------
  887|  4.50k|                continue;
  888|  4.50k|            }
  889|       |
  890|  1.55k|            if (comp == TransformationComp_PostRotation) {
  ------------------
  |  Branch (890:17): [True: 0, False: 1.55k]
  ------------------
  891|      0|                chain[i] = chain[i].Inverse();
  892|      0|            }
  893|       |
  894|  1.55k|            PotentialNode nd;
  895|  1.55k|            nd->mName.Set(NameTransformationChainNode(name, comp));
  896|  1.55k|            nd->mTransformation = chain[i];
  897|       |
  898|       |            // geometric inverses go in a post-node chain
  899|  1.55k|            if (comp == TransformationComp_GeometricScalingInverse ||
  ------------------
  |  Branch (899:17): [True: 224, False: 1.32k]
  ------------------
  900|  1.32k|                    comp == TransformationComp_GeometricRotationInverse ||
  ------------------
  |  Branch (900:21): [True: 0, False: 1.32k]
  ------------------
  901|  1.32k|                    comp == TransformationComp_GeometricTranslationInverse) {
  ------------------
  |  Branch (901:21): [True: 0, False: 1.32k]
  ------------------
  902|    224|                post_output_nodes.emplace_back(std::move(nd));
  903|  1.32k|            } else {
  904|  1.32k|                output_nodes.emplace_back(std::move(nd));
  905|  1.32k|            }
  906|  1.55k|        }
  907|       |
  908|    356|        ai_assert(output_nodes.size());
  909|    356|        return true;
  910|    356|    }
  911|       |
  912|       |    // else, we can just multiply the matrices together
  913|  3.23k|    PotentialNode nd;
  914|       |
  915|       |    // name passed to the method is already unique
  916|  3.23k|    nd->mName.Set(name);
  917|       |    // for (const auto &transform : chain) {
  918|       |    // skip inverse chain for no preservePivots
  919|  48.2k|    for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
  ------------------
  |  Branch (919:59): [True: 45.0k, False: 3.23k]
  ------------------
  920|  45.0k|      nd->mTransformation = nd->mTransformation * chain[i];
  921|  45.0k|    }
  922|  3.23k|    output_nodes.push_back(std::move(nd));
  923|  3.23k|    return false;
  924|  3.58k|}
_ZN6Assimp3FBX12FBXConverter17SetupNodeMetadataERKNS0_5ModelER6aiNode:
  926|  3.57k|void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
  927|  3.57k|    const PropertyTable &props = model.Props();
  928|  3.57k|    DirectPropertyMap unparsedProperties = props.GetUnparsedProperties();
  929|       |
  930|       |    // create metadata on node
  931|  3.57k|    const std::size_t numStaticMetaData = 2;
  932|  3.57k|    aiMetadata *data = aiMetadata::Alloc(static_cast<unsigned int>(unparsedProperties.size() + numStaticMetaData));
  933|  3.57k|    nd.mMetaData = data;
  934|  3.57k|    int index = 0;
  935|       |
  936|       |    // find user defined properties (3ds Max)
  937|  3.57k|    data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", "")));
  938|       |    // preserve the info that a node was marked as Null node in the original file.
  939|  3.57k|    data->Set(index++, "IsNull", model.IsNull() ? true : false);
  ------------------
  |  Branch (939:34): [True: 185, False: 3.39k]
  ------------------
  940|       |
  941|       |    // add unparsed properties to the node's metadata
  942|  10.3k|    for (const DirectPropertyMap::value_type &prop : unparsedProperties) {
  ------------------
  |  Branch (942:52): [True: 10.3k, False: 3.57k]
  ------------------
  943|       |        // Interpret the property as a concrete type
  944|  10.3k|        if (const TypedProperty<bool> *interpretedBool = prop.second->As<TypedProperty<bool>>()) {
  ------------------
  |  Branch (944:40): [True: 1.37k, False: 8.92k]
  ------------------
  945|  1.37k|            data->Set(index++, prop.first, interpretedBool->Value());
  946|  8.92k|        } else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
  ------------------
  |  Branch (946:46): [True: 7.56k, False: 1.36k]
  ------------------
  947|  7.56k|            data->Set(index++, prop.first, interpretedInt->Value());
  948|  7.56k|        } else if (const TypedProperty<uint32_t> *interpretedUInt = prop.second->As<TypedProperty<uint32_t>>()) {
  ------------------
  |  Branch (948:51): [True: 0, False: 1.36k]
  ------------------
  949|      0|            data->Set(index++, prop.first, interpretedUInt->Value());
  950|  1.36k|        } else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) {
  ------------------
  |  Branch (950:51): [True: 0, False: 1.36k]
  ------------------
  951|      0|            data->Set(index++, prop.first, interpretedUint64->Value());
  952|  1.36k|        } else if (const TypedProperty<int64_t> *interpretedint64 = prop.second->As<TypedProperty<int64_t>>()) {
  ------------------
  |  Branch (952:50): [True: 0, False: 1.36k]
  ------------------
  953|      0|            data->Set(index++, prop.first, interpretedint64->Value());
  954|  1.36k|        } else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
  ------------------
  |  Branch (954:48): [True: 1.11k, False: 250]
  ------------------
  955|  1.11k|            data->Set(index++, prop.first, interpretedFloat->Value());
  956|  1.11k|        } else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
  ------------------
  |  Branch (956:54): [True: 10, False: 240]
  ------------------
  957|     10|            data->Set(index++, prop.first, aiString(interpretedString->Value()));
  958|    240|        } else if (const TypedProperty<aiVector3D> *interpretedVec3 = prop.second->As<TypedProperty<aiVector3D>>()) {
  ------------------
  |  Branch (958:53): [True: 240, False: 0]
  ------------------
  959|    240|            data->Set(index++, prop.first, interpretedVec3->Value());
  960|    240|        } else {
  961|       |            ai_assert(false);
  962|      0|        }
  963|  10.3k|    }
  964|  3.57k|}
_ZN6Assimp3FBX12FBXConverter12ConvertModelERKNS0_5ModelEP6aiNodeS6_RK12aiMatrix4x4tIfE:
  966|  3.56k|void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
  967|  3.56k|    const std::vector<const Geometry *> &geos = model.GetGeometry();
  968|       |
  969|  3.56k|    std::vector<unsigned int> meshes;
  970|  3.56k|    meshes.reserve(geos.size());
  971|       |
  972|  3.56k|    for (const Geometry *geo : geos) {
  ------------------
  |  Branch (972:30): [True: 100, False: 3.56k]
  ------------------
  973|    100|        const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
  974|    100|        const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
  975|    100|        if (mesh) {
  ------------------
  |  Branch (975:13): [True: 100, False: 0]
  ------------------
  976|    100|            const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node, absolute_transform);
  977|    100|            std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
  978|    100|        } else if (line) {
  ------------------
  |  Branch (978:20): [True: 0, False: 0]
  ------------------
  979|      0|            const std::vector<unsigned int> &indices = ConvertLine(*line, root_node);
  980|      0|            std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
  981|      0|        } else if (geo) {
  ------------------
  |  Branch (981:20): [True: 0, False: 0]
  ------------------
  982|      0|            FBXImporter::LogWarn("ignoring unrecognized geometry: ", geo->Name());
  983|      0|        } else {
  984|      0|            FBXImporter::LogWarn("skipping null geometry");
  985|      0|        }
  986|    100|    }
  987|       |
  988|  3.56k|    if (meshes.size()) {
  ------------------
  |  Branch (988:9): [True: 100, False: 3.46k]
  ------------------
  989|    100|        parent->mMeshes = new unsigned int[meshes.size()]();
  990|    100|        parent->mNumMeshes = static_cast<unsigned int>(meshes.size());
  991|       |
  992|    100|        std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes);
  993|    100|    }
  994|  3.56k|}
_ZN6Assimp3FBX12FBXConverter11ConvertMeshERKNS0_12MeshGeometryERKNS0_5ModelEP6aiNodeS9_RK12aiMatrix4x4tIfE:
  997|    100|FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
  998|    100|    std::vector<unsigned int> temp;
  999|       |
 1000|    100|    MeshMap::const_iterator it = meshes_converted.find(&mesh);
 1001|    100|    if (it != meshes_converted.end()) {
  ------------------
  |  Branch (1001:9): [True: 5, False: 95]
  ------------------
 1002|      5|        std::copy((*it).second.begin(), (*it).second.end(), std::back_inserter(temp));
 1003|      5|        return temp;
 1004|      5|    }
 1005|       |
 1006|     95|    const std::vector<aiVector3D> &vertices = mesh.GetVertices();
 1007|     95|    const std::vector<unsigned int> &faces = mesh.GetFaceIndexCounts();
 1008|     95|    if (vertices.empty() || faces.empty()) {
  ------------------
  |  Branch (1008:9): [True: 0, False: 95]
  |  Branch (1008:29): [True: 0, False: 95]
  ------------------
 1009|      0|        FBXImporter::LogWarn("ignoring empty geometry: ", mesh.Name());
 1010|      0|        return temp;
 1011|      0|    }
 1012|       |
 1013|       |    // one material per mesh maps easily to aiMesh. Multiple material
 1014|       |    // meshes need to be split.
 1015|     95|    const MatIndexArray &mindices = mesh.GetMaterialIndices();
 1016|     95|    if (doc.Settings().readMaterials && !mindices.empty()) {
  ------------------
  |  Branch (1016:9): [True: 95, False: 0]
  |  Branch (1016:41): [True: 89, False: 6]
  ------------------
 1017|     89|        const MatIndexArray::value_type base = mindices[0];
 1018|   347k|        for (MatIndexArray::value_type index : mindices) {
  ------------------
  |  Branch (1018:46): [True: 347k, False: 89]
  ------------------
 1019|   347k|            if (index != base) {
  ------------------
  |  Branch (1019:17): [True: 0, False: 347k]
  ------------------
 1020|      0|                return ConvertMeshMultiMaterial(mesh, model, absolute_transform, parent, root_node);
 1021|      0|            }
 1022|   347k|        }
 1023|     89|    }
 1024|       |
 1025|       |    // faster code-path, just copy the data
 1026|     95|    temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
 1027|     95|    return temp;
 1028|     95|}
_ZN6Assimp3FBX12FBXConverter14SetupEmptyMeshERKNS0_8GeometryEP6aiNode:
 1074|     95|aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) {
 1075|     95|    aiMesh *const out_mesh = new aiMesh();
 1076|     95|    mMeshes.push_back(out_mesh);
 1077|     95|    meshes_converted[&mesh].push_back(static_cast<unsigned int>(mMeshes.size() - 1));
 1078|       |
 1079|       |    // set name
 1080|     95|    std::string name = mesh.Name();
 1081|     95|    if (name.substr(0, 10) == "Geometry::") {
  ------------------
  |  Branch (1081:9): [True: 93, False: 2]
  ------------------
 1082|     93|        name = name.substr(10);
 1083|     93|    }
 1084|       |
 1085|     95|    if (name.length()) {
  ------------------
  |  Branch (1085:9): [True: 86, False: 9]
  ------------------
 1086|     86|        out_mesh->mName.Set(name);
 1087|     86|    } else {
 1088|      9|        out_mesh->mName = parent->mName;
 1089|      9|    }
 1090|       |
 1091|     95|    return out_mesh;
 1092|     95|}
_ZN6Assimp3FBX12FBXConverter25ConvertMeshSingleMaterialERKNS0_12MeshGeometryERKNS0_5ModelERK12aiMatrix4x4tIfEP6aiNodeSD_:
 1123|     95|        aiNode *parent, aiNode *) {
 1124|     95|    const MatIndexArray &mindices = mesh.GetMaterialIndices();
 1125|     95|    aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
 1126|       |
 1127|     95|    const std::vector<aiVector3D> &vertices = mesh.GetVertices();
 1128|     95|    const std::vector<unsigned int> &faces = mesh.GetFaceIndexCounts();
 1129|       |
 1130|       |    // copy vertices
 1131|     95|    out_mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
 1132|     95|    out_mesh->mVertices = new aiVector3D[vertices.size()];
 1133|       |
 1134|     95|    std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices);
 1135|       |
 1136|       |    // generate dummy faces
 1137|     95|    out_mesh->mNumFaces = static_cast<unsigned int>(faces.size());
 1138|     95|    aiFace *fac = out_mesh->mFaces = new aiFace[faces.size()]();
 1139|       |
 1140|     95|    unsigned int cursor = 0;
 1141|  90.8k|    for (unsigned int pcount : faces) {
  ------------------
  |  Branch (1141:30): [True: 90.8k, False: 95]
  ------------------
 1142|  90.8k|        aiFace &f = *fac++;
 1143|  90.8k|        f.mNumIndices = pcount;
 1144|  90.8k|        f.mIndices = new unsigned int[pcount];
 1145|  90.8k|        switch (pcount) {
 1146|      0|            case 1:
  ------------------
  |  Branch (1146:13): [True: 0, False: 90.8k]
  ------------------
 1147|      0|                out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
 1148|      0|                break;
 1149|     21|            case 2:
  ------------------
  |  Branch (1149:13): [True: 21, False: 90.8k]
  ------------------
 1150|     21|                out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
 1151|     21|                break;
 1152|     11|            case 3:
  ------------------
  |  Branch (1152:13): [True: 11, False: 90.8k]
  ------------------
 1153|     11|                out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
 1154|     11|                break;
 1155|  90.8k|            default:
  ------------------
  |  Branch (1155:13): [True: 90.8k, False: 32]
  ------------------
 1156|  90.8k|                out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
 1157|  90.8k|                break;
 1158|  90.8k|        }
 1159|   615k|        for (unsigned int i = 0; i < pcount; ++i) {
  ------------------
  |  Branch (1159:34): [True: 524k, False: 90.8k]
  ------------------
 1160|   524k|            f.mIndices[i] = cursor++;
 1161|   524k|        }
 1162|  90.8k|    }
 1163|       |
 1164|       |    // copy normals
 1165|     95|    const std::vector<aiVector3D> &normals = mesh.GetNormals();
 1166|     95|    if (normals.size()) {
  ------------------
  |  Branch (1166:9): [True: 24, False: 71]
  ------------------
 1167|     24|        ai_assert(normals.size() == vertices.size());
 1168|       |
 1169|     24|        out_mesh->mNormals = new aiVector3D[vertices.size()];
 1170|     24|        std::copy(normals.begin(), normals.end(), out_mesh->mNormals);
 1171|     24|    }
 1172|       |
 1173|       |    // copy tangents - assimp requires both tangents and bitangents (binormals)
 1174|       |    // to be present, or neither of them. Compute binormals from normals
 1175|       |    // and tangents if needed.
 1176|     95|    const std::vector<aiVector3D> &tangents = mesh.GetTangents();
 1177|     95|    const std::vector<aiVector3D> *binormals = &mesh.GetBinormals();
 1178|       |
 1179|     95|    if (tangents.size()) {
  ------------------
  |  Branch (1179:9): [True: 5, False: 90]
  ------------------
 1180|      5|        std::vector<aiVector3D> tempBinormals;
 1181|      5|        if (!binormals->size()) {
  ------------------
  |  Branch (1181:13): [True: 1, False: 4]
  ------------------
 1182|      1|            if (normals.size()) {
  ------------------
  |  Branch (1182:17): [True: 0, False: 1]
  ------------------
 1183|      0|                tempBinormals.resize(normals.size());
 1184|      0|                for (unsigned int i = 0; i < tangents.size(); ++i) {
  ------------------
  |  Branch (1184:42): [True: 0, False: 0]
  ------------------
 1185|      0|                    tempBinormals[i] = normals[i] ^ tangents[i];
 1186|      0|                }
 1187|       |
 1188|      0|                binormals = &tempBinormals;
 1189|      1|            } else {
 1190|      1|                binormals = nullptr;
 1191|      1|            }
 1192|      1|        }
 1193|       |
 1194|      5|        if (binormals) {
  ------------------
  |  Branch (1194:13): [True: 4, False: 1]
  ------------------
 1195|      4|            ai_assert(tangents.size() == vertices.size());
 1196|      4|            ai_assert(binormals->size() == vertices.size());
 1197|       |
 1198|      4|            out_mesh->mTangents = new aiVector3D[vertices.size()];
 1199|      4|            std::copy(tangents.begin(), tangents.end(), out_mesh->mTangents);
 1200|       |
 1201|      4|            out_mesh->mBitangents = new aiVector3D[vertices.size()];
 1202|      4|            std::copy(binormals->begin(), binormals->end(), out_mesh->mBitangents);
 1203|      4|        }
 1204|      5|    }
 1205|       |
 1206|       |    // copy texture coords
 1207|    173|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (1207:30): [True: 173, False: 0]
  ------------------
 1208|    173|        const std::vector<aiVector2D> &uvs = mesh.GetTextureCoords(i);
 1209|    173|        if (uvs.empty()) {
  ------------------
  |  Branch (1209:13): [True: 95, False: 78]
  ------------------
 1210|     95|            break;
 1211|     95|        }
 1212|       |
 1213|     78|        aiVector3D *out_uv = out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()];
 1214|   305k|        for (const aiVector2D &v : uvs) {
  ------------------
  |  Branch (1214:34): [True: 305k, False: 78]
  ------------------
 1215|   305k|            *out_uv++ = aiVector3D(v.x, v.y, 0.0f);
 1216|   305k|        }
 1217|       |
 1218|     78|        out_mesh->SetTextureCoordsName(i, aiString(mesh.GetTextureCoordChannelName(i)));
 1219|       |
 1220|     78|        out_mesh->mNumUVComponents[i] = 2;
 1221|     78|    }
 1222|       |
 1223|       |    // copy vertex colors
 1224|     95|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
  ------------------
  |  Branch (1224:30): [True: 95, False: 0]
  ------------------
 1225|     95|        const std::vector<aiColor4D> &colors = mesh.GetVertexColors(i);
 1226|     95|        if (colors.empty()) {
  ------------------
  |  Branch (1226:13): [True: 95, False: 0]
  ------------------
 1227|     95|            break;
 1228|     95|        }
 1229|       |
 1230|      0|        out_mesh->mColors[i] = new aiColor4D[vertices.size()];
 1231|      0|        std::copy(colors.begin(), colors.end(), out_mesh->mColors[i]);
 1232|      0|    }
 1233|       |
 1234|     95|    if (!doc.Settings().readMaterials || mindices.empty()) {
  ------------------
  |  Branch (1234:9): [True: 0, False: 95]
  |  Branch (1234:42): [True: 6, False: 89]
  ------------------
 1235|      6|        FBXImporter::LogError("no material assigned to mesh, setting default material");
 1236|      6|        out_mesh->mMaterialIndex = GetDefaultMaterial();
 1237|     89|    } else {
 1238|     89|        ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
 1239|     89|    }
 1240|       |
 1241|     95|    if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && !doc.Settings().useSkeleton) {
  ------------------
  |  Branch (1241:9): [True: 95, False: 0]
  |  Branch (1241:39): [True: 84, False: 11]
  |  Branch (1241:73): [True: 84, False: 0]
  ------------------
 1242|     84|        ConvertWeights(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr);
 1243|     84|    } else if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && doc.Settings().useSkeleton) {
  ------------------
  |  Branch (1243:16): [True: 11, False: 0]
  |  Branch (1243:46): [True: 0, False: 11]
  |  Branch (1243:80): [True: 0, False: 0]
  ------------------
 1244|      0|        SkeletonBoneContainer sbc;
 1245|      0|        ConvertWeightsToSkeleton(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr, sbc);
 1246|      0|        aiSkeleton *skeleton = createAiSkeleton(sbc);
 1247|      0|        if (skeleton != nullptr) {
  ------------------
  |  Branch (1247:13): [True: 0, False: 0]
  ------------------
 1248|      0|            mSkeletons.emplace_back(skeleton);
 1249|      0|        }
 1250|      0|    }
 1251|       |
 1252|     95|    std::vector<aiAnimMesh *> animMeshes;
 1253|     95|    for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
  ------------------
  |  Branch (1253:39): [True: 0, False: 95]
  ------------------
 1254|      0|        for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) {
  ------------------
  |  Branch (1254:57): [True: 0, False: 0]
  ------------------
 1255|      0|            const auto& shapeGeometries = blendShapeChannel->GetShapeGeometries();
 1256|      0|            for (const ShapeGeometry *shapeGeometry : shapeGeometries) {
  ------------------
  |  Branch (1256:53): [True: 0, False: 0]
  ------------------
 1257|      0|                const auto &curNormals = shapeGeometry->GetNormals();
 1258|      0|                aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh, true, !curNormals.empty());
 1259|      0|                const auto &curVertices = shapeGeometry->GetVertices();
 1260|      0|                const auto &curIndices = shapeGeometry->GetIndices();
 1261|       |                //losing channel name if using shapeGeometry->Name()
 1262|       |                // if blendShapeChannel Name is empty or doesn't have a ".", add geoMetryName;
 1263|      0|                auto aniName = FixAnimMeshName(blendShapeChannel->Name());
 1264|      0|                auto geoMetryName = FixAnimMeshName(shapeGeometry->Name());
 1265|      0|                if (aniName.empty()) {
  ------------------
  |  Branch (1265:21): [True: 0, False: 0]
  ------------------
 1266|      0|                    aniName = geoMetryName;
 1267|      0|                }
 1268|      0|                else if (aniName.find('.') == aniName.npos) {
  ------------------
  |  Branch (1268:26): [True: 0, False: 0]
  ------------------
 1269|      0|                    aniName += "." + geoMetryName;
 1270|      0|                }
 1271|      0|                animMesh->mName.Set(aniName);
 1272|      0|                for (size_t j = 0; j < curIndices.size(); j++) {
  ------------------
  |  Branch (1272:36): [True: 0, False: 0]
  ------------------
 1273|      0|                    const unsigned int curIndex = curIndices.at(j);
 1274|      0|                    aiVector3D vertex = curVertices.at(j);
 1275|      0|                    aiVector3D normal = curNormals.empty() ? aiVector3D() : curNormals.at(j);
  ------------------
  |  Branch (1275:41): [True: 0, False: 0]
  ------------------
 1276|      0|                    unsigned int count = 0;
 1277|      0|                    const unsigned int *outIndices = mesh.ToOutputVertexIndex(curIndex, count);
 1278|      0|                    for (unsigned int k = 0; k < count; k++) {
  ------------------
  |  Branch (1278:46): [True: 0, False: 0]
  ------------------
 1279|      0|                        unsigned int index = outIndices[k];
 1280|      0|                        animMesh->mVertices[index] += vertex;
 1281|      0|                        if (animMesh->mNormals != nullptr) {
  ------------------
  |  Branch (1281:29): [True: 0, False: 0]
  ------------------
 1282|      0|                            animMesh->mNormals[index] += normal;
 1283|      0|                            animMesh->mNormals[index].NormalizeSafe();
 1284|      0|                        }
 1285|      0|                    }
 1286|      0|                }
 1287|      0|                animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f;
  ------------------
  |  Branch (1287:37): [True: 0, False: 0]
  ------------------
 1288|      0|                animMeshes.push_back(animMesh);
 1289|      0|            }
 1290|      0|        }
 1291|      0|    }
 1292|     95|    const size_t numAnimMeshes = animMeshes.size();
 1293|     95|    if (numAnimMeshes > 0) {
  ------------------
  |  Branch (1293:9): [True: 0, False: 95]
  ------------------
 1294|      0|        out_mesh->mNumAnimMeshes = static_cast<unsigned int>(numAnimMeshes);
 1295|      0|        out_mesh->mAnimMeshes = new aiAnimMesh *[numAnimMeshes];
 1296|      0|        for (size_t i = 0; i < numAnimMeshes; i++) {
  ------------------
  |  Branch (1296:28): [True: 0, False: 0]
  ------------------
 1297|      0|            out_mesh->mAnimMeshes[i] = animMeshes.at(i);
 1298|      0|        }
 1299|      0|    }
 1300|     95|    return static_cast<unsigned int>(mMeshes.size() - 1);
 1301|     95|}
_ZN6Assimp3FBX12FBXConverter14ConvertWeightsEP6aiMeshRKNS0_12MeshGeometryERK12aiMatrix4x4tIfEP6aiNodejPNSt3__16vectorIjNSD_9allocatorIjEEEE:
 1571|     84|        std::vector<unsigned int> *outputVertStartIndices) {
 1572|     84|    ai_assert(geo.DeformerSkin());
 1573|       |
 1574|     84|    std::vector<size_t> out_indices, index_out_indices, count_out_indices;
 1575|       |
 1576|     84|    const Skin &sk = *geo.DeformerSkin();
 1577|       |
 1578|     84|    std::vector<aiBone*> bones;
 1579|     84|    const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
 1580|     84|    ai_assert(no_mat_check || outputVertStartIndices);
 1581|       |
 1582|     84|    try {
 1583|       |        // iterate over the sub deformers
 1584|    699|        for (const Cluster *cluster : sk.Clusters()) {
  ------------------
  |  Branch (1584:37): [True: 699, False: 84]
  ------------------
 1585|    699|            ai_assert(cluster);
 1586|       |
 1587|    699|            const WeightIndexArray &indices = cluster->GetIndices();
 1588|       |
 1589|    699|            const MatIndexArray &mats = geo.GetMaterialIndices();
 1590|       |
 1591|    699|            const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
 1592|       |
 1593|    699|            count_out_indices.clear();
 1594|    699|            index_out_indices.clear();
 1595|    699|            out_indices.clear();
 1596|       |
 1597|       |            // now check if *any* of these weights is contained in the output mesh,
 1598|       |            // taking notes so we don't need to do it twice.
 1599|   243k|            for (WeightIndexArray::value_type index : indices) {
  ------------------
  |  Branch (1599:53): [True: 243k, False: 699]
  ------------------
 1600|       |
 1601|   243k|                unsigned int count = 0;
 1602|   243k|                const unsigned int *const out_idx = geo.ToOutputVertexIndex(index, count);
 1603|       |                // ToOutputVertexIndex only returns nullptr if index is out of bounds
 1604|       |                // which should never happen
 1605|   243k|                ai_assert(out_idx != nullptr);
 1606|       |
 1607|   243k|                index_out_indices.push_back(no_index_sentinel);
 1608|   243k|                count_out_indices.push_back(0);
 1609|       |
 1610|  1.21M|                for (unsigned int i = 0; i < count; ++i) {
  ------------------
  |  Branch (1610:42): [True: 974k, False: 243k]
  ------------------
 1611|   974k|                    if (no_mat_check || static_cast<size_t>(mats[geo.FaceForVertexIndex(out_idx[i])]) == materialIndex) {
  ------------------
  |  Branch (1611:25): [True: 974k, False: 0]
  |  Branch (1611:41): [True: 0, False: 0]
  ------------------
 1612|       |
 1613|   974k|                        if (index_out_indices.back() == no_index_sentinel) {
  ------------------
  |  Branch (1613:29): [True: 243k, False: 730k]
  ------------------
 1614|   243k|                            index_out_indices.back() = out_indices.size();
 1615|   243k|                        }
 1616|       |
 1617|   974k|                        if (no_mat_check) {
  ------------------
  |  Branch (1617:29): [True: 974k, False: 0]
  ------------------
 1618|   974k|                            out_indices.push_back(out_idx[i]);
 1619|   974k|                        } else {
 1620|       |                            // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn)
 1621|      0|                            const std::vector<unsigned int>::iterator it = std::lower_bound(
 1622|      0|                                    outputVertStartIndices->begin(),
 1623|      0|                                    outputVertStartIndices->end(),
 1624|      0|                                    out_idx[i]);
 1625|       |
 1626|      0|                            out_indices.push_back(std::distance(outputVertStartIndices->begin(), it));
 1627|      0|                        }
 1628|       |
 1629|   974k|                        ++count_out_indices.back();
 1630|   974k|                    }
 1631|   974k|                }
 1632|   243k|            }
 1633|       |
 1634|       |            // if we found at least one, generate the output bones
 1635|       |            // XXX this could be heavily simplified by collecting the bone
 1636|       |            // data in a single step.
 1637|    699|            ConvertCluster(bones, cluster, out_indices, index_out_indices,
 1638|    699|                    count_out_indices, absolute_transform, parent);
 1639|    699|        }
 1640|       |
 1641|     84|        bone_map.clear();
 1642|     84|    } catch (std::exception &) {
 1643|      0|        std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>());
 1644|      0|        throw;
 1645|      0|    }
 1646|       |
 1647|     84|    if (bones.empty()) {
  ------------------
  |  Branch (1647:9): [True: 1, False: 83]
  ------------------
 1648|      1|        out->mBones = nullptr;
 1649|      1|        out->mNumBones = 0;
 1650|      1|        return;
 1651|      1|    }
 1652|       |
 1653|     83|    out->mBones = new aiBone *[bones.size()]();
 1654|     83|    out->mNumBones = static_cast<unsigned int>(bones.size());
 1655|     83|    std::swap_ranges(bones.begin(), bones.end(), out->mBones);
 1656|     83|}
_ZN6Assimp3FBX12FBXConverter14ConvertClusterERNSt3__16vectorIP6aiBoneNS2_9allocatorIS5_EEEEPKNS0_7ClusterERNS3_ImNS6_ImEEEESF_SF_RK12aiMatrix4x4tIfEP6aiNode:
 1661|    699|        aiNode *) {
 1662|    699|    ai_assert(cluster != nullptr); // make sure cluster valid
 1663|       |
 1664|    699|    std::string deformer_name = cluster->TargetNode()->Name();
 1665|    699|    aiString bone_name = aiString(FixNodeName(deformer_name));
 1666|       |
 1667|    699|    aiBone *bone = nullptr;
 1668|       |
 1669|    699|    if (bone_map.count(deformer_name)) {
  ------------------
  |  Branch (1669:9): [True: 0, False: 699]
  ------------------
 1670|      0|        ASSIMP_LOG_VERBOSE_DEBUG("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name);
 1671|      0|        bone = bone_map[deformer_name];
 1672|    699|    } else {
 1673|    699|        ASSIMP_LOG_VERBOSE_DEBUG("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
 1674|    699|        bone = new aiBone();
 1675|    699|        bone->mName = bone_name;
 1676|       |
 1677|       |        //bone->mOffsetMatrix = cluster->Transform();
 1678|       |        // store local transform link for post processing
 1679|       |
 1680|    699|        bone->mOffsetMatrix = cluster->TransformLink();
 1681|    699|        bone->mOffsetMatrix.Inverse();
 1682|       |
 1683|    699|        const aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
 1684|       |
 1685|    699|        bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
 1686|       |
 1687|       |        //
 1688|       |        // Now calculate the aiVertexWeights
 1689|       |        //
 1690|       |
 1691|    699|        aiVertexWeight *cursor = nullptr;
 1692|       |
 1693|    699|        bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
 1694|    699|        cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
 1695|       |
 1696|    699|        const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
 1697|    699|        const WeightArray &weights = cluster->GetWeights();
 1698|       |
 1699|    699|        const size_t c = index_out_indices.size();
 1700|   244k|        for (size_t i = 0; i < c; ++i) {
  ------------------
  |  Branch (1700:28): [True: 243k, False: 699]
  ------------------
 1701|   243k|            const size_t index_index = index_out_indices[i];
 1702|       |
 1703|   243k|            if (index_index == no_index_sentinel) {
  ------------------
  |  Branch (1703:17): [True: 0, False: 243k]
  ------------------
 1704|      0|                continue;
 1705|      0|            }
 1706|       |
 1707|   243k|            const size_t cc = count_out_indices[i];
 1708|  1.21M|            for (size_t j = 0; j < cc; ++j) {
  ------------------
  |  Branch (1708:32): [True: 974k, False: 243k]
  ------------------
 1709|       |                // cursor runs from first element relative to the start
 1710|       |                // or relative to the start of the next indexes.
 1711|   974k|                aiVertexWeight &out_weight = *cursor++;
 1712|       |
 1713|   974k|                out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]);
 1714|   974k|                out_weight.mWeight = weights[i];
 1715|   974k|            }
 1716|   243k|        }
 1717|       |
 1718|    699|        bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone));
 1719|    699|    }
 1720|       |
 1721|    699|    ASSIMP_LOG_DEBUG("bone research: Indices size: ", out_indices.size());
 1722|       |
 1723|       |    // lookup must be populated in case something goes wrong
 1724|       |    // this also allocates bones to mesh instance outside
 1725|    699|    local_mesh_bones.push_back(bone);
 1726|    699|}
_ZN6Assimp3FBX12FBXConverter22ConvertMaterialForMeshEP6aiMeshRKNS0_5ModelERKNS0_12MeshGeometryEi:
 1729|     89|        MatIndexArray::value_type materialIndex) {
 1730|       |    // locate source materials for this mesh
 1731|     89|    const std::vector<const Material *> &mats = model.GetMaterials();
 1732|     89|    if (static_cast<unsigned int>(materialIndex) >= mats.size() || materialIndex < 0) {
  ------------------
  |  Branch (1732:9): [True: 2, False: 87]
  |  Branch (1732:68): [True: 0, False: 87]
  ------------------
 1733|      2|        FBXImporter::LogError("material index out of bounds, setting default material");
 1734|      2|        out->mMaterialIndex = GetDefaultMaterial();
 1735|      2|        return;
 1736|      2|    }
 1737|       |
 1738|     87|    const Material *const mat = mats[materialIndex];
 1739|     87|    MaterialMap::const_iterator it = materials_converted.find(mat);
 1740|     87|    if (it != materials_converted.end()) {
  ------------------
  |  Branch (1740:9): [True: 1, False: 86]
  ------------------
 1741|      1|        out->mMaterialIndex = (*it).second;
 1742|      1|        return;
 1743|      1|    }
 1744|       |
 1745|     86|    out->mMaterialIndex = ConvertMaterial(*mat, &geo);
 1746|     86|    materials_converted[mat] = out->mMaterialIndex;
 1747|     86|}
_ZN6Assimp3FBX12FBXConverter18GetDefaultMaterialEv:
 1749|      8|unsigned int FBXConverter::GetDefaultMaterial() {
 1750|      8|    if (defaultMaterialIndex) {
  ------------------
  |  Branch (1750:9): [True: 1, False: 7]
  ------------------
 1751|      1|        return defaultMaterialIndex - 1;
 1752|      1|    }
 1753|       |
 1754|      7|    aiMaterial *out_mat = new aiMaterial();
 1755|      7|    materials.push_back(out_mat);
 1756|       |
 1757|      7|    const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f);
 1758|      7|    out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
 1759|       |
 1760|      7|    aiString s;
 1761|      7|    s.Set(AI_DEFAULT_MATERIAL_NAME);
 1762|       |
 1763|      7|    out_mat->AddProperty(&s, AI_MATKEY_NAME);
 1764|       |
 1765|      7|    defaultMaterialIndex = static_cast<unsigned int>(materials.size());
 1766|      7|    return defaultMaterialIndex - 1;
 1767|      8|}
_ZN6Assimp3FBX12FBXConverter15ConvertMaterialERKNS0_8MaterialEPKNS0_12MeshGeometryE:
 1769|     86|unsigned int FBXConverter::ConvertMaterial(const Material &material, const MeshGeometry *const mesh) {
 1770|     86|    const PropertyTable &props = material.Props();
 1771|       |
 1772|       |    // generate empty output material
 1773|     86|    aiMaterial *out_mat = new aiMaterial();
 1774|     86|    materials_converted[&material] = static_cast<unsigned int>(materials.size());
 1775|       |
 1776|     86|    materials.push_back(out_mat);
 1777|       |
 1778|     86|    aiString str;
 1779|       |
 1780|       |    // strip Material:: prefix
 1781|     86|    std::string name = material.Name();
 1782|     86|    if (name.substr(0, 10) == "Material::") {
  ------------------
  |  Branch (1782:9): [True: 86, False: 0]
  ------------------
 1783|     86|        name = name.substr(10);
 1784|     86|    }
 1785|       |
 1786|       |    // set material name if not empty - this could happen
 1787|       |    // and there should be no key for it in this case.
 1788|     86|    if (name.length()) {
  ------------------
  |  Branch (1788:9): [True: 86, False: 0]
  ------------------
 1789|     86|        str.Set(name);
 1790|     86|        out_mat->AddProperty(&str, AI_MATKEY_NAME);
 1791|     86|    }
 1792|       |
 1793|       |    // 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.
 1794|     86|    if (material.GetShadingModel() == "phong") {
  ------------------
  |  Branch (1794:9): [True: 85, False: 1]
  ------------------
 1795|     85|        aiShadingMode shadingMode = aiShadingMode_Phong;
 1796|     85|        out_mat->AddProperty<aiShadingMode>(&shadingMode, 1, AI_MATKEY_SHADING_MODEL);
 1797|     85|    }
 1798|       |
 1799|       |    // shading stuff and colors
 1800|     86|    SetShadingPropertiesCommon(out_mat, props);
 1801|     86|    SetShadingPropertiesRaw(out_mat, props, material.Textures(), mesh);
 1802|       |
 1803|       |    // texture assignments
 1804|     86|    SetTextureProperties(out_mat, material.Textures(), mesh);
 1805|     86|    SetTextureProperties(out_mat, material.LayeredTextures(), mesh);
 1806|       |
 1807|     86|    return static_cast<unsigned int>(materials.size() - 1);
 1808|     86|}
_ZN6Assimp3FBX12FBXConverter12ConvertVideoERKNS0_5VideoE:
 1810|      1|unsigned int FBXConverter::ConvertVideo(const Video &video) {
 1811|       |    // generate empty output texture
 1812|      1|    aiTexture *out_tex = new aiTexture();
 1813|      1|    textures.push_back(out_tex);
 1814|       |
 1815|       |    // assuming the texture is compressed
 1816|      1|    out_tex->mWidth = static_cast<unsigned int>(video.ContentLength()); // total data size
 1817|      1|    out_tex->mHeight = 0; // fixed to 0
 1818|       |
 1819|       |    // steal the data from the Video to avoid an additional copy
 1820|      1|    out_tex->pcData = reinterpret_cast<aiTexel *>(const_cast<Video &>(video).RelinquishContent());
 1821|       |
 1822|       |    // try to extract a hint from the file extension
 1823|      1|    const std::string &filename = video.RelativeFilename().empty() ? video.FileName() : video.RelativeFilename();
  ------------------
  |  Branch (1823:35): [True: 0, False: 1]
  ------------------
 1824|      1|    std::string ext = BaseImporter::GetExtension(filename);
 1825|       |
 1826|      1|    if (ext == "jpeg") {
  ------------------
  |  Branch (1826:9): [True: 0, False: 1]
  ------------------
 1827|      0|        ext = "jpg";
 1828|      0|    }
 1829|       |
 1830|      1|    if (ext.size() <= 3) {
  ------------------
  |  Branch (1830:9): [True: 1, False: 0]
  ------------------
 1831|      1|        memcpy(out_tex->achFormatHint, ext.c_str(), ext.size());
 1832|      1|    }
 1833|       |
 1834|      1|    out_tex->mFilename.Set(filename.c_str());
 1835|       |
 1836|      1|    return static_cast<unsigned int>(textures.size() - 1);
 1837|      1|}
_ZN6Assimp3FBX12FBXConverter14GetTexturePathEPKNS0_7TextureE:
 1839|      3|aiString FBXConverter::GetTexturePath(const Texture *tex) {
 1840|      3|    aiString path;
 1841|      3|    path.Set(tex->RelativeFilename());
 1842|       |
 1843|      3|    const Video *media = tex->Media();
 1844|      3|    if (media != nullptr) {
  ------------------
  |  Branch (1844:9): [True: 3, False: 0]
  ------------------
 1845|      3|        bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
 1846|      3|        unsigned int index=0;
 1847|       |
 1848|      3|        VideoMap::const_iterator it = textures_converted.find(media);
 1849|      3|        if (it != textures_converted.end()) {
  ------------------
  |  Branch (1849:13): [True: 1, False: 2]
  ------------------
 1850|      1|            index = (*it).second;
 1851|      1|            textureReady = true;
 1852|      2|        } else {
 1853|      2|            if (media->ContentLength() > 0) {
  ------------------
  |  Branch (1853:17): [True: 0, False: 2]
  ------------------
 1854|      0|                index = ConvertVideo(*media);
 1855|      0|                textures_converted[media] = index;
 1856|      0|                textureReady = true;
 1857|      0|            }
 1858|      2|        }
 1859|       |
 1860|       |        // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
 1861|      3|        if (doc.Settings().useLegacyEmbeddedTextureNaming) {
  ------------------
  |  Branch (1861:13): [True: 0, False: 3]
  ------------------
 1862|      0|            if (textureReady) {
  ------------------
  |  Branch (1862:17): [True: 0, False: 0]
  ------------------
 1863|       |                // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
 1864|       |                // In FBX files textures are now stored internally by Assimp with their filename included
 1865|       |                // Now Assimp can lookup through the loaded textures after all data is processed
 1866|       |                // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
 1867|       |                // This may occur on this case too, it has to be studied
 1868|      0|                path.data[0] = '*';
 1869|      0|                path.length = 1 + ASSIMP_itoa10(path.data + 1, AI_MAXLEN - 1, index);
 1870|      0|            }
 1871|      0|        }
 1872|      3|    }
 1873|       |
 1874|      3|    return path;
 1875|      3|}
_ZN6Assimp3FBX12FBXConverter23TrySetTexturePropertiesEP10aiMaterialRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_7TextureENS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SE_EEEEEERSK_13aiTextureTypePKNS0_12MeshGeometryE:
 1879|  3.95k|        aiTextureType target, const MeshGeometry *const mesh) {
 1880|  3.95k|    TextureMap::const_iterator it = _textures.find(propName);
 1881|  3.95k|    if (it == _textures.end()) {
  ------------------
  |  Branch (1881:9): [True: 3.95k, False: 3]
  ------------------
 1882|  3.95k|        return;
 1883|  3.95k|    }
 1884|       |
 1885|      3|    const Texture *const tex = (*it).second;
 1886|      3|    if (tex != nullptr) {
  ------------------
  |  Branch (1886:9): [True: 3, False: 0]
  ------------------
 1887|      3|        aiString path = GetTexturePath(tex);
 1888|      3|        out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, 0);
 1889|       |
 1890|      3|        aiUVTransform uvTrafo;
 1891|       |        // XXX handle all kinds of UV transformations
 1892|      3|        uvTrafo.mScaling = tex->UVScaling();
 1893|      3|        uvTrafo.mTranslation = tex->UVTranslation();
 1894|      3|        uvTrafo.mRotation = tex->UVRotation();
 1895|      3|        out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0);
 1896|       |
 1897|      3|        const PropertyTable &props = tex->Props();
 1898|       |
 1899|      3|        int uvIndex = 0;
 1900|       |
 1901|      3|        bool ok;
 1902|      3|        const std::string &uvSet = PropertyGet<std::string>(props, "UVSet", ok);
 1903|      3|        if (ok) {
  ------------------
  |  Branch (1903:13): [True: 3, False: 0]
  ------------------
 1904|       |            // "default" is the name which usually appears in the FbxFileTexture template
 1905|      3|            if (uvSet != "default" && uvSet.length()) {
  ------------------
  |  Branch (1905:17): [True: 3, False: 0]
  |  Branch (1905:39): [True: 3, False: 0]
  ------------------
 1906|       |                // this is a bit awkward - we need to find a mesh that uses this
 1907|       |                // material and scan its UV channels for the given UV name because
 1908|       |                // assimp references UV channels by index, not by name.
 1909|       |
 1910|       |                // XXX: the case that UV channels may appear in different orders
 1911|       |                // in meshes is unhandled. A possible solution would be to sort
 1912|       |                // the UV channels alphabetically, but this would have the side
 1913|       |                // effect that the primary (first) UV channel would sometimes
 1914|       |                // be moved, causing trouble when users read only the first
 1915|       |                // UV channel and ignore UV channel assignments altogether.
 1916|       |
 1917|      3|                const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(),
 1918|      3|                        std::find(materials.begin(), materials.end(), out_mat)));
 1919|       |
 1920|      3|                uvIndex = -1;
 1921|      3|                if (!mesh) {
  ------------------
  |  Branch (1921:21): [True: 0, False: 3]
  ------------------
 1922|      0|                    for (const MeshMap::value_type &v : meshes_converted) {
  ------------------
  |  Branch (1922:55): [True: 0, False: 0]
  ------------------
 1923|      0|                        const MeshGeometry *const meshGeom = dynamic_cast<const MeshGeometry *>(v.first);
 1924|      0|                        if (!meshGeom) {
  ------------------
  |  Branch (1924:29): [True: 0, False: 0]
  ------------------
 1925|      0|                            continue;
 1926|      0|                        }
 1927|       |
 1928|      0|                        const MatIndexArray &mats = meshGeom->GetMaterialIndices();
 1929|      0|                        MatIndexArray::const_iterator curIt = std::find(mats.begin(), mats.end(), (int) matIndex);
 1930|      0|                        if (curIt == mats.end()) {
  ------------------
  |  Branch (1930:29): [True: 0, False: 0]
  ------------------
 1931|      0|                            continue;
 1932|      0|                        }
 1933|       |
 1934|      0|                        int index = -1;
 1935|      0|                        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (1935:50): [True: 0, False: 0]
  ------------------
 1936|      0|                            if (meshGeom->GetTextureCoords(i).empty()) {
  ------------------
  |  Branch (1936:33): [True: 0, False: 0]
  ------------------
 1937|      0|                                break;
 1938|      0|                            }
 1939|      0|                            const std::string &name = meshGeom->GetTextureCoordChannelName(i);
 1940|      0|                            if (name == uvSet) {
  ------------------
  |  Branch (1940:33): [True: 0, False: 0]
  ------------------
 1941|      0|                                index = static_cast<int>(i);
 1942|      0|                                break;
 1943|      0|                            }
 1944|      0|                        }
 1945|      0|                        if (index == -1) {
  ------------------
  |  Branch (1945:29): [True: 0, False: 0]
  ------------------
 1946|      0|                            FBXImporter::LogWarn("did not find UV channel named ", uvSet, " in a mesh using this material");
 1947|      0|                            continue;
 1948|      0|                        }
 1949|       |
 1950|      0|                        if (uvIndex == -1) {
  ------------------
  |  Branch (1950:29): [True: 0, False: 0]
  ------------------
 1951|      0|                            uvIndex = index;
 1952|      0|                        } else {
 1953|      0|                            FBXImporter::LogWarn("the UV channel named ", uvSet,
 1954|      0|                                                 " appears at different positions in meshes, results will be wrong");
 1955|      0|                        }
 1956|      0|                    }
 1957|      3|                } else {
 1958|      3|                    int index = -1;
 1959|      3|                    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (1959:46): [True: 3, False: 0]
  ------------------
 1960|      3|                        if (mesh->GetTextureCoords(i).empty()) {
  ------------------
  |  Branch (1960:29): [True: 0, False: 3]
  ------------------
 1961|      0|                            break;
 1962|      0|                        }
 1963|      3|                        const std::string &name = mesh->GetTextureCoordChannelName(i);
 1964|      3|                        if (name == uvSet) {
  ------------------
  |  Branch (1964:29): [True: 3, False: 0]
  ------------------
 1965|      3|                            index = static_cast<int>(i);
 1966|      3|                            break;
 1967|      3|                        }
 1968|      3|                    }
 1969|      3|                    if (index == -1) {
  ------------------
  |  Branch (1969:25): [True: 0, False: 3]
  ------------------
 1970|      0|                        FBXImporter::LogWarn("did not find UV channel named ", uvSet, " in a mesh using this material");
 1971|      0|                    }
 1972|       |
 1973|      3|                    if (uvIndex == -1) {
  ------------------
  |  Branch (1973:25): [True: 3, False: 0]
  ------------------
 1974|      3|                        uvIndex = index;
 1975|      3|                    }
 1976|      3|                }
 1977|       |
 1978|      3|                if (uvIndex == -1) {
  ------------------
  |  Branch (1978:21): [True: 0, False: 3]
  ------------------
 1979|      0|                    FBXImporter::LogWarn("failed to resolve UV channel ", uvSet, ", using first UV channel");
 1980|      0|                    uvIndex = 0;
 1981|      0|                }
 1982|      3|            }
 1983|      3|        }
 1984|       |
 1985|       |        out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0);
 1986|      3|    }
 1987|      3|}
_ZN6Assimp3FBX12FBXConverter23TrySetTexturePropertiesEP10aiMaterialRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_14LayeredTextureENS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SE_EEEEEERSK_13aiTextureTypePKNS0_12MeshGeometryE:
 1991|  1.20k|        aiTextureType target, const MeshGeometry *const mesh) {
 1992|  1.20k|    LayeredTextureMap::const_iterator it = layeredTextures.find(propName);
 1993|  1.20k|    if (it == layeredTextures.end()) {
  ------------------
  |  Branch (1993:9): [True: 1.20k, False: 0]
  ------------------
 1994|  1.20k|        return;
 1995|  1.20k|    }
 1996|       |
 1997|      0|    int texCount = (*it).second->textureCount();
 1998|       |
 1999|       |    // Set the blend mode for layered textures
 2000|      0|    int blendmode = (*it).second->GetBlendMode();
 2001|      0|    out_mat->AddProperty(&blendmode, 1, _AI_MATKEY_TEXOP_BASE, target, 0);
 2002|       |
 2003|      0|    for (int texIndex = 0; texIndex < texCount; texIndex++) {
  ------------------
  |  Branch (2003:28): [True: 0, False: 0]
  ------------------
 2004|       |
 2005|      0|        const Texture *const tex = (*it).second->getTexture(texIndex);
 2006|       |
 2007|      0|        aiString path = GetTexturePath(tex);
 2008|      0|        out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, texIndex);
 2009|       |
 2010|      0|        aiUVTransform uvTrafo;
 2011|       |        // XXX handle all kinds of UV transformations
 2012|      0|        uvTrafo.mScaling = tex->UVScaling();
 2013|      0|        uvTrafo.mTranslation = tex->UVTranslation();
 2014|      0|        uvTrafo.mRotation = tex->UVRotation();
 2015|      0|        out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex);
 2016|       |
 2017|      0|        const PropertyTable &props = tex->Props();
 2018|       |
 2019|      0|        int uvIndex = 0;
 2020|       |
 2021|      0|        bool ok;
 2022|      0|        const std::string &uvSet = PropertyGet<std::string>(props, "UVSet", ok);
 2023|      0|        if (ok) {
  ------------------
  |  Branch (2023:13): [True: 0, False: 0]
  ------------------
 2024|       |            // "default" is the name which usually appears in the FbxFileTexture template
 2025|      0|            if (uvSet != "default" && uvSet.length()) {
  ------------------
  |  Branch (2025:17): [True: 0, False: 0]
  |  Branch (2025:39): [True: 0, False: 0]
  ------------------
 2026|       |                // this is a bit awkward - we need to find a mesh that uses this
 2027|       |                // material and scan its UV channels for the given UV name because
 2028|       |                // assimp references UV channels by index, not by name.
 2029|       |
 2030|       |                // XXX: the case that UV channels may appear in different orders
 2031|       |                // in meshes is unhandled. A possible solution would be to sort
 2032|       |                // the UV channels alphabetically, but this would have the side
 2033|       |                // effect that the primary (first) UV channel would sometimes
 2034|       |                // be moved, causing trouble when users read only the first
 2035|       |                // UV channel and ignore UV channel assignments altogether.
 2036|       |
 2037|      0|                const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(),
 2038|      0|                        std::find(materials.begin(), materials.end(), out_mat)));
 2039|       |
 2040|      0|                uvIndex = -1;
 2041|      0|                if (!mesh) {
  ------------------
  |  Branch (2041:21): [True: 0, False: 0]
  ------------------
 2042|      0|                    for (const MeshMap::value_type &v : meshes_converted) {
  ------------------
  |  Branch (2042:55): [True: 0, False: 0]
  ------------------
 2043|      0|                        const MeshGeometry *const meshGeom = dynamic_cast<const MeshGeometry *>(v.first);
 2044|      0|                        if (!meshGeom) {
  ------------------
  |  Branch (2044:29): [True: 0, False: 0]
  ------------------
 2045|      0|                            continue;
 2046|      0|                        }
 2047|       |
 2048|      0|                        const MatIndexArray &mats = meshGeom->GetMaterialIndices();
 2049|      0|                        MatIndexArray::const_iterator curIt = std::find(mats.begin(), mats.end(), (int) matIndex);
 2050|      0|                        if ( curIt == mats.end()) {
  ------------------
  |  Branch (2050:30): [True: 0, False: 0]
  ------------------
 2051|      0|                            continue;
 2052|      0|                        }
 2053|       |
 2054|      0|                        int index = -1;
 2055|      0|                        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (2055:50): [True: 0, False: 0]
  ------------------
 2056|      0|                            if (meshGeom->GetTextureCoords(i).empty()) {
  ------------------
  |  Branch (2056:33): [True: 0, False: 0]
  ------------------
 2057|      0|                                break;
 2058|      0|                            }
 2059|      0|                            const std::string &name = meshGeom->GetTextureCoordChannelName(i);
 2060|      0|                            if (name == uvSet) {
  ------------------
  |  Branch (2060:33): [True: 0, False: 0]
  ------------------
 2061|      0|                                index = static_cast<int>(i);
 2062|      0|                                break;
 2063|      0|                            }
 2064|      0|                        }
 2065|      0|                        if (index == -1) {
  ------------------
  |  Branch (2065:29): [True: 0, False: 0]
  ------------------
 2066|      0|                            FBXImporter::LogWarn("did not find UV channel named ", uvSet, " in a mesh using this material");
 2067|      0|                            continue;
 2068|      0|                        }
 2069|       |
 2070|      0|                        if (uvIndex == -1) {
  ------------------
  |  Branch (2070:29): [True: 0, False: 0]
  ------------------
 2071|      0|                            uvIndex = index;
 2072|      0|                        } else {
 2073|      0|                            FBXImporter::LogWarn("the UV channel named ", uvSet,
 2074|      0|                                                 " appears at different positions in meshes, results will be wrong");
 2075|      0|                        }
 2076|      0|                    }
 2077|      0|                } else {
 2078|      0|                    int index = -1;
 2079|      0|                    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (2079:46): [True: 0, False: 0]
  ------------------
 2080|      0|                        if (mesh->GetTextureCoords(i).empty()) {
  ------------------
  |  Branch (2080:29): [True: 0, False: 0]
  ------------------
 2081|      0|                            break;
 2082|      0|                        }
 2083|      0|                        const std::string &name = mesh->GetTextureCoordChannelName(i);
 2084|      0|                        if (name == uvSet) {
  ------------------
  |  Branch (2084:29): [True: 0, False: 0]
  ------------------
 2085|      0|                            index = static_cast<int>(i);
 2086|      0|                            break;
 2087|      0|                        }
 2088|      0|                    }
 2089|      0|                    if (index == -1) {
  ------------------
  |  Branch (2089:25): [True: 0, False: 0]
  ------------------
 2090|      0|                        FBXImporter::LogWarn("did not find UV channel named ", uvSet, " in a mesh using this material");
 2091|      0|                    }
 2092|       |
 2093|      0|                    if (uvIndex == -1) {
  ------------------
  |  Branch (2093:25): [True: 0, False: 0]
  ------------------
 2094|      0|                        uvIndex = index;
 2095|      0|                    }
 2096|      0|                }
 2097|       |
 2098|      0|                if (uvIndex == -1) {
  ------------------
  |  Branch (2098:21): [True: 0, False: 0]
  ------------------
 2099|      0|                    FBXImporter::LogWarn("failed to resolve UV channel ", uvSet, ", using first UV channel");
 2100|      0|                    uvIndex = 0;
 2101|      0|                }
 2102|      0|            }
 2103|      0|        }
 2104|       |
 2105|       |        out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, texIndex);
 2106|      0|    }
 2107|      0|}
_ZN6Assimp3FBX12FBXConverter20SetTexturePropertiesEP10aiMaterialRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_7TextureENS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SE_EEEEEEPKNS0_12MeshGeometryE:
 2109|     86|void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const TextureMap &_textures, const MeshGeometry *const mesh) {
 2110|     86|    TrySetTextureProperties(out_mat, _textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
 2111|     86|    TrySetTextureProperties(out_mat, _textures, "AmbientColor", aiTextureType_AMBIENT, mesh);
 2112|     86|    TrySetTextureProperties(out_mat, _textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
 2113|     86|    TrySetTextureProperties(out_mat, _textures, "SpecularColor", aiTextureType_SPECULAR, mesh);
 2114|     86|    TrySetTextureProperties(out_mat, _textures, "SpecularFactor", aiTextureType_SPECULAR, mesh);
 2115|     86|    TrySetTextureProperties(out_mat, _textures, "TransparentColor", aiTextureType_OPACITY, mesh);
 2116|     86|    TrySetTextureProperties(out_mat, _textures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
 2117|     86|    TrySetTextureProperties(out_mat, _textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
 2118|     86|    TrySetTextureProperties(out_mat, _textures, "NormalMap", aiTextureType_NORMALS, mesh);
 2119|     86|    TrySetTextureProperties(out_mat, _textures, "Bump", aiTextureType_HEIGHT, mesh);
 2120|     86|    TrySetTextureProperties(out_mat, _textures, "ShininessExponent", aiTextureType_SHININESS, mesh);
 2121|     86|    TrySetTextureProperties(out_mat, _textures, "TransparencyFactor", aiTextureType_OPACITY, mesh);
 2122|     86|    TrySetTextureProperties(out_mat, _textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh);
 2123|     86|    TrySetTextureProperties(out_mat, _textures, "ReflectionFactor", aiTextureType_METALNESS, mesh);
 2124|       |    //Maya counterparts
 2125|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh);
 2126|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh);
 2127|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh);
 2128|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh);
 2129|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh);
 2130|       |
 2131|       |    // Maya PBR
 2132|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|baseColor", aiTextureType_BASE_COLOR, mesh);
 2133|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|normalCamera", aiTextureType_NORMAL_CAMERA, mesh);
 2134|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|emissionColor", aiTextureType_EMISSION_COLOR, mesh);
 2135|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|metalness", aiTextureType_METALNESS, mesh);
 2136|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|diffuseRoughness", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2137|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|base", aiTextureType_MAYA_BASE, mesh);
 2138|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|specular", aiTextureType_MAYA_SPECULAR, mesh);
 2139|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|specularColor", aiTextureType_MAYA_SPECULAR_COLOR, mesh);
 2140|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|specularRoughness", aiTextureType_MAYA_SPECULAR_ROUGHNESS, mesh);
 2141|       |
 2142|       |    // Maya stingray
 2143|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_color_map", aiTextureType_BASE_COLOR, mesh);
 2144|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_normal_map", aiTextureType_NORMAL_CAMERA, mesh);
 2145|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_emissive_map", aiTextureType_EMISSION_COLOR, mesh);
 2146|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_metallic_map", aiTextureType_METALNESS, mesh);
 2147|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2148|     86|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh);
 2149|       |
 2150|       |    // 3DSMax Physical material
 2151|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh);
 2152|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh);
 2153|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh);
 2154|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh);
 2155|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2156|       |
 2157|       |    // 3DSMax PBR materials
 2158|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|base_color_map", aiTextureType_BASE_COLOR, mesh);
 2159|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|norm_map", aiTextureType_NORMAL_CAMERA, mesh);
 2160|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|emit_color_map", aiTextureType_EMISSION_COLOR, mesh);
 2161|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh);
 2162|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|opacity_map", aiTextureType_OPACITY, mesh);
 2163|       |    // Metalness/Roughness material type
 2164|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|metalness_map", aiTextureType_METALNESS, mesh);
 2165|       |    // Specular/Gloss material type
 2166|     86|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|specular_map", aiTextureType_SPECULAR, mesh);
 2167|       |
 2168|       |    // Glossiness vs roughness in 3ds Max Pbr Materials
 2169|     86|    int useGlossiness;
 2170|     86|    if (out_mat->Get("$raw.3dsMax|main|useGlossiness", aiTextureType_NONE, 0, useGlossiness) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (2170:9): [True: 0, False: 86]
  ------------------
 2171|       |        // These textures swap meaning if ((useGlossiness == 1) != (material type is Specular/Gloss))
 2172|      0|        if (useGlossiness == 1) {
  ------------------
  |  Branch (2172:13): [True: 0, False: 0]
  ------------------
 2173|      0|            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|roughness_map", aiTextureType_SHININESS, mesh);
 2174|      0|            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|glossiness_map", aiTextureType_SHININESS, mesh);
 2175|      0|        }
 2176|      0|        else if (useGlossiness == 2) {
  ------------------
  |  Branch (2176:18): [True: 0, False: 0]
  ------------------
 2177|      0|            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2178|      0|            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|glossiness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2179|      0|        }
 2180|      0|        else {
 2181|      0|            FBXImporter::LogWarn("A 3dsMax Pbr Material must have a useGlossiness value to correctly interpret roughness and glossiness textures.");
 2182|      0|        }
 2183|      0|    }
 2184|     86|}
_ZN6Assimp3FBX12FBXConverter20SetTexturePropertiesEP10aiMaterialRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_14LayeredTextureENS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SE_EEEEEEPKNS0_12MeshGeometryE:
 2186|     86|void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const LayeredTextureMap &layeredTextures, const MeshGeometry *const mesh) {
 2187|     86|    TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
 2188|     86|    TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh);
 2189|     86|    TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
 2190|     86|    TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh);
 2191|     86|    TrySetTextureProperties(out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh);
 2192|     86|    TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh);
 2193|     86|    TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
 2194|     86|    TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
 2195|     86|    TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh);
 2196|     86|    TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh);
 2197|     86|    TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh);
 2198|     86|    TrySetTextureProperties(out_mat, layeredTextures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh);
 2199|     86|    TrySetTextureProperties(out_mat, layeredTextures, "TransparencyFactor", aiTextureType_OPACITY, mesh);
 2200|     86|    TrySetTextureProperties(out_mat, layeredTextures, "ReflectionFactor", aiTextureType_METALNESS, mesh);
 2201|     86|}
_ZN6Assimp3FBX12FBXConverter24GetColorPropertyFactoredERKNS0_13PropertyTableERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEESD_Rbb:
 2204|    344|        const std::string &factorName, bool &result, bool useTemplate) {
 2205|    344|    result = true;
 2206|       |
 2207|    344|    bool ok;
 2208|    344|    aiVector3D BaseColor = PropertyGet<aiVector3D>(props, colorName, ok, useTemplate);
 2209|    344|    if (!ok) {
  ------------------
  |  Branch (2209:9): [True: 8, False: 336]
  ------------------
 2210|      8|        result = false;
 2211|      8|        return aiColor3D(0.0f, 0.0f, 0.0f);
 2212|      8|    }
 2213|       |
 2214|       |    // if no factor name, return the colour as is
 2215|    336|    if (factorName.empty()) {
  ------------------
  |  Branch (2215:9): [True: 0, False: 336]
  ------------------
 2216|      0|        return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z);
 2217|      0|    }
 2218|       |
 2219|       |    // otherwise it should be multiplied by the factor, if found.
 2220|    336|    float factor = PropertyGet<float>(props, factorName, ok, useTemplate);
 2221|    336|    if (ok) {
  ------------------
  |  Branch (2221:9): [True: 331, False: 5]
  ------------------
 2222|    331|        BaseColor *= factor;
 2223|    331|    }
 2224|    336|    return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z);
 2225|    336|}
_ZN6Assimp3FBX12FBXConverter28GetColorPropertyFromMaterialERKNS0_13PropertyTableERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERb:
 2228|    258|        bool &result) {
 2229|    258|    return GetColorPropertyFactored(props, baseName + "Color", baseName + "Factor", result, true);
 2230|    258|}
_ZN6Assimp3FBX12FBXConverter16GetColorPropertyERKNS0_13PropertyTableERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERbb:
 2233|    262|        bool &result, bool useTemplate) {
 2234|    262|    result = true;
 2235|    262|    bool ok;
 2236|    262|    const aiVector3D &ColorVec = PropertyGet<aiVector3D>(props, colorName, ok, useTemplate);
 2237|    262|    if (!ok) {
  ------------------
  |  Branch (2237:9): [True: 92, False: 170]
  ------------------
 2238|     92|        result = false;
 2239|     92|        return aiColor3D(0.0f, 0.0f, 0.0f);
 2240|     92|    }
 2241|    170|    return aiColor3D(ColorVec.x, ColorVec.y, ColorVec.z);
 2242|    262|}
_ZN6Assimp3FBX12FBXConverter26SetShadingPropertiesCommonEP10aiMaterialRKNS0_13PropertyTableE:
 2244|     86|void FBXConverter::SetShadingPropertiesCommon(aiMaterial *out_mat, const PropertyTable &props) {
 2245|       |    // Set shading properties.
 2246|       |    // Modern FBX Files have two separate systems for defining these,
 2247|       |    // with only the more comprehensive one described in the property template.
 2248|       |    // Likely the other values are a legacy system,
 2249|       |    // which is still always exported by the official FBX SDK.
 2250|       |    //
 2251|       |    // Blender's FBX import and export mostly ignore this legacy system,
 2252|       |    // and as we only support recent versions of FBX anyway, we can do the same.
 2253|     86|    bool ok;
 2254|       |
 2255|     86|    const aiColor3D &Diffuse = GetColorPropertyFromMaterial(props, "Diffuse", ok);
 2256|     86|    if (ok) {
  ------------------
  |  Branch (2256:9): [True: 86, False: 0]
  ------------------
 2257|     86|        out_mat->AddProperty(&Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
 2258|     86|    }
 2259|       |
 2260|     86|    const aiColor3D &Emissive = GetColorPropertyFromMaterial(props, "Emissive", ok);
 2261|     86|    if (ok) {
  ------------------
  |  Branch (2261:9): [True: 82, False: 4]
  ------------------
 2262|     82|        out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE);
 2263|     82|    } else {
 2264|      4|        const aiColor3D &emissiveColor = GetColorProperty(props, "Maya|emissive", ok);
 2265|      4|        if (ok) {
  ------------------
  |  Branch (2265:13): [True: 0, False: 4]
  ------------------
 2266|      0|            out_mat->AddProperty(&emissiveColor, 1, AI_MATKEY_COLOR_EMISSIVE);
 2267|      0|        }
 2268|      4|     }
 2269|       |
 2270|     86|    const aiColor3D &Ambient = GetColorPropertyFromMaterial(props, "Ambient", ok);
 2271|     86|    if (ok) {
  ------------------
  |  Branch (2271:9): [True: 86, False: 0]
  ------------------
 2272|     86|        out_mat->AddProperty(&Ambient, 1, AI_MATKEY_COLOR_AMBIENT);
 2273|     86|    }
 2274|       |
 2275|       |    // we store specular factor as SHININESS_STRENGTH, so just get the color
 2276|     86|    const aiColor3D &Specular = GetColorProperty(props, "SpecularColor", ok, true);
 2277|     86|    if (ok) {
  ------------------
  |  Branch (2277:9): [True: 85, False: 1]
  ------------------
 2278|     85|        out_mat->AddProperty(&Specular, 1, AI_MATKEY_COLOR_SPECULAR);
 2279|     85|    }
 2280|       |
 2281|       |    // and also try to get SHININESS_STRENGTH
 2282|     86|    const float SpecularFactor = PropertyGet<float>(props, "SpecularFactor", ok, true);
 2283|     86|    if (ok) {
  ------------------
  |  Branch (2283:9): [True: 85, False: 1]
  ------------------
 2284|     85|        out_mat->AddProperty(&SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH);
 2285|     85|    }
 2286|       |
 2287|       |    // and the specular exponent
 2288|     86|    const float ShininessExponent = PropertyGet<float>(props, "ShininessExponent", ok);
 2289|     86|    if (ok) {
  ------------------
  |  Branch (2289:9): [True: 85, False: 1]
  ------------------
 2290|     85|        out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS);
 2291|       |         // Match Blender behavior to extract roughness when only shininess is present
 2292|     85|        const float roughness = 1.0f - (sqrt(ShininessExponent) / 10.0f);
 2293|     85|        out_mat->AddProperty(&roughness, 1, AI_MATKEY_ROUGHNESS_FACTOR);
 2294|     85|    }
 2295|       |
 2296|       |    // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
 2297|     86|    const aiColor3D &Transparent = GetColorPropertyFactored(props, "TransparentColor", "TransparencyFactor", ok);
 2298|     86|    float CalculatedOpacity = 1.0f;
 2299|     86|    if (ok) {
  ------------------
  |  Branch (2299:9): [True: 82, False: 4]
  ------------------
 2300|     82|        out_mat->AddProperty(&Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
 2301|       |        // as calculated by FBX SDK 2017:
 2302|     82|        CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f);
 2303|     82|    }
 2304|       |
 2305|       |    // try to get the transparency factor
 2306|     86|    const float TransparencyFactor = PropertyGet<float>(props, "TransparencyFactor", ok);
 2307|     86|    if (ok) {
  ------------------
  |  Branch (2307:9): [True: 83, False: 3]
  ------------------
 2308|     83|        out_mat->AddProperty(&TransparencyFactor, 1, AI_MATKEY_TRANSPARENCYFACTOR);
 2309|     83|    }
 2310|       |
 2311|       |    // use of TransparencyFactor is inconsistent.
 2312|       |    // Maya always stores it as 1.0,
 2313|       |    // so we can't use it to set AI_MATKEY_OPACITY.
 2314|       |    // Blender is more sensible and stores it as the alpha value.
 2315|       |    // However both the FBX SDK and Blender always write an additional
 2316|       |    // legacy "Opacity" field, so we can try to use that.
 2317|       |    //
 2318|       |    // If we can't find it,
 2319|       |    // we can fall back to the value which the FBX SDK calculates
 2320|       |    // from transparency colour (RGB) and factor (F) as
 2321|       |    // 1.0 - F*((R+G+B)/3).
 2322|       |    //
 2323|       |    // There's no consistent way to interpret this opacity value,
 2324|       |    // so it's up to clients to do the correct thing.
 2325|     86|    const float Opacity = PropertyGet<float>(props, "Opacity", ok);
 2326|     86|    if (ok) {
  ------------------
  |  Branch (2326:9): [True: 83, False: 3]
  ------------------
 2327|     83|        out_mat->AddProperty(&Opacity, 1, AI_MATKEY_OPACITY);
 2328|     83|    } else if (CalculatedOpacity != 1.0) {
  ------------------
  |  Branch (2328:16): [True: 0, False: 3]
  ------------------
 2329|      0|        out_mat->AddProperty(&CalculatedOpacity, 1, AI_MATKEY_OPACITY);
 2330|      0|    }
 2331|       |
 2332|       |    // reflection color and factor are stored separately
 2333|     86|    const aiColor3D &Reflection = GetColorProperty(props, "ReflectionColor", ok, true);
 2334|     86|    if (ok) {
  ------------------
  |  Branch (2334:9): [True: 85, False: 1]
  ------------------
 2335|     85|        out_mat->AddProperty(&Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE);
 2336|     85|    }
 2337|       |
 2338|     86|    float ReflectionFactor = PropertyGet<float>(props, "ReflectionFactor", ok, true);
 2339|     86|    if (ok) {
  ------------------
  |  Branch (2339:9): [True: 85, False: 1]
  ------------------
 2340|     85|        out_mat->AddProperty(&ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY);
 2341|     85|    }
 2342|       |
 2343|     86|    const float BumpFactor = PropertyGet<float>(props, "BumpFactor", ok);
 2344|     86|    if (ok) {
  ------------------
  |  Branch (2344:9): [True: 85, False: 1]
  ------------------
 2345|     85|        out_mat->AddProperty(&BumpFactor, 1, AI_MATKEY_BUMPSCALING);
 2346|     85|    }
 2347|       |
 2348|     86|    const float DispFactor = PropertyGet<float>(props, "DisplacementFactor", ok);
 2349|     86|    if (ok) {
  ------------------
  |  Branch (2349:9): [True: 82, False: 4]
  ------------------
 2350|     82|        out_mat->AddProperty(&DispFactor, 1, "$mat.displacementscaling", 0, 0);
 2351|     82|    }
 2352|       |
 2353|       |    // PBR material information
 2354|     86|    const aiColor3D &baseColor = GetColorProperty(props, "Maya|base_color", ok);
 2355|     86|    if (ok) {
  ------------------
  |  Branch (2355:9): [True: 0, False: 86]
  ------------------
 2356|      0|        out_mat->AddProperty(&baseColor, 1, AI_MATKEY_BASE_COLOR);
 2357|      0|    }
 2358|       |
 2359|     86|    const float useColorMap = PropertyGet<float>(props, "Maya|use_color_map", ok);
 2360|     86|    if (ok) {
  ------------------
  |  Branch (2360:9): [True: 0, False: 86]
  ------------------
 2361|      0|        out_mat->AddProperty(&useColorMap, 1, AI_MATKEY_USE_COLOR_MAP);
 2362|      0|    }
 2363|       |
 2364|     86|    const float useMetallicMap = PropertyGet<float>(props, "Maya|use_metallic_map", ok);
 2365|     86|    if (ok) {
  ------------------
  |  Branch (2365:9): [True: 0, False: 86]
  ------------------
 2366|      0|        out_mat->AddProperty(&useMetallicMap, 1, AI_MATKEY_USE_METALLIC_MAP);
 2367|      0|    }
 2368|       |
 2369|     86|    const float metallicFactor = PropertyGet<float>(props, "Maya|metallic", ok);
 2370|     86|    if (ok) {
  ------------------
  |  Branch (2370:9): [True: 0, False: 86]
  ------------------
 2371|      0|        out_mat->AddProperty(&metallicFactor, 1, AI_MATKEY_METALLIC_FACTOR);
 2372|      0|    }
 2373|       |
 2374|     86|    const float useRoughnessMap = PropertyGet<float>(props, "Maya|use_roughness_map", ok);
 2375|     86|    if (ok) {
  ------------------
  |  Branch (2375:9): [True: 0, False: 86]
  ------------------
 2376|      0|        out_mat->AddProperty(&useRoughnessMap, 1, AI_MATKEY_USE_ROUGHNESS_MAP);
 2377|      0|    }
 2378|       |
 2379|     86|    const float roughnessFactor = PropertyGet<float>(props, "Maya|roughness", ok);
 2380|     86|    if (ok) {
  ------------------
  |  Branch (2380:9): [True: 0, False: 86]
  ------------------
 2381|      0|        out_mat->AddProperty(&roughnessFactor, 1, AI_MATKEY_ROUGHNESS_FACTOR);
 2382|      0|    }
 2383|       |
 2384|     86|    const float useEmissiveMap = PropertyGet<float>(props, "Maya|use_emissive_map", ok);
 2385|     86|    if (ok) {
  ------------------
  |  Branch (2385:9): [True: 0, False: 86]
  ------------------
 2386|      0|        out_mat->AddProperty(&useEmissiveMap, 1, AI_MATKEY_USE_EMISSIVE_MAP);
 2387|      0|    }
 2388|       |
 2389|     86|    const float emissiveIntensity = PropertyGet<float>(props, "Maya|emissive_intensity", ok);
 2390|     86|    if (ok) {
  ------------------
  |  Branch (2390:9): [True: 0, False: 86]
  ------------------
 2391|      0|        out_mat->AddProperty(&emissiveIntensity, 1, AI_MATKEY_EMISSIVE_INTENSITY);
 2392|      0|    }
 2393|       |
 2394|     86|    const float useAOMap = PropertyGet<float>(props, "Maya|use_ao_map", ok);
 2395|     86|    if (ok) {
  ------------------
  |  Branch (2395:9): [True: 0, False: 86]
  ------------------
 2396|       |        out_mat->AddProperty(&useAOMap, 1, AI_MATKEY_USE_AO_MAP);
 2397|      0|    }
 2398|     86|}
_ZN6Assimp3FBX12FBXConverter23SetShadingPropertiesRawEP10aiMaterialRKNS0_13PropertyTableERKNSt3__113unordered_mapINS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEPKNS0_7TextureENS7_4hashISE_EENS7_8equal_toISE_EENSC_INS7_4pairIKSE_SH_EEEEEEPKNS0_12MeshGeometryE:
 2400|     86|void FBXConverter::SetShadingPropertiesRaw(aiMaterial *out_mat, const PropertyTable &props, const TextureMap &_textures, const MeshGeometry *const mesh) {
 2401|       |    // Add all the unparsed properties with a "$raw." prefix
 2402|       |
 2403|     86|    const std::string prefix = "$raw.";
 2404|       |
 2405|    142|    for (const DirectPropertyMap::value_type &prop : props.GetUnparsedProperties()) {
  ------------------
  |  Branch (2405:52): [True: 142, False: 86]
  ------------------
 2406|       |
 2407|    142|        std::string name = prefix + prop.first;
 2408|       |
 2409|    142|        if (const TypedProperty<aiVector3D> *interpretedVec3 = prop.second->As<TypedProperty<aiVector3D>>()) {
  ------------------
  |  Branch (2409:46): [True: 36, False: 106]
  ------------------
 2410|     36|            out_mat->AddProperty(&interpretedVec3->Value(), 1, name.c_str(), 0, 0);
 2411|    106|        } else if (const TypedProperty<aiColor3D> *interpretedCol3 = prop.second->As<TypedProperty<aiColor3D>>()) {
  ------------------
  |  Branch (2411:52): [True: 0, False: 106]
  ------------------
 2412|      0|            out_mat->AddProperty(&interpretedCol3->Value(), 1, name.c_str(), 0, 0);
 2413|    106|        } else if (const TypedProperty<aiColor4D> *interpretedCol4 = prop.second->As<TypedProperty<aiColor4D>>()) {
  ------------------
  |  Branch (2413:52): [True: 0, False: 106]
  ------------------
 2414|      0|            out_mat->AddProperty(&interpretedCol4->Value(), 1, name.c_str(), 0, 0);
 2415|    106|        } else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
  ------------------
  |  Branch (2415:48): [True: 93, False: 13]
  ------------------
 2416|     93|            out_mat->AddProperty(&interpretedFloat->Value(), 1, name.c_str(), 0, 0);
 2417|     93|        } else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
  ------------------
  |  Branch (2417:46): [True: 0, False: 13]
  ------------------
 2418|      0|            out_mat->AddProperty(&interpretedInt->Value(), 1, name.c_str(), 0, 0);
 2419|     13|        } else if (const TypedProperty<bool> *interpretedBool = prop.second->As<TypedProperty<bool>>()) {
  ------------------
  |  Branch (2419:47): [True: 5, False: 8]
  ------------------
 2420|      5|            int value = interpretedBool->Value() ? 1 : 0;
  ------------------
  |  Branch (2420:25): [True: 0, False: 5]
  ------------------
 2421|      5|            out_mat->AddProperty(&value, 1, name.c_str(), 0, 0);
 2422|      8|        } else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
  ------------------
  |  Branch (2422:54): [True: 8, False: 0]
  ------------------
 2423|      8|            const aiString value = aiString(interpretedString->Value());
 2424|      8|            out_mat->AddProperty(&value, name.c_str(), 0, 0);
 2425|      8|        }
 2426|    142|    }
 2427|       |
 2428|       |    // Add the textures' properties
 2429|       |
 2430|     89|    for (TextureMap::const_iterator it = _textures.begin(); it != _textures.end(); ++it) {
  ------------------
  |  Branch (2430:61): [True: 3, False: 86]
  ------------------
 2431|       |
 2432|      3|        std::string name = prefix + it->first;
 2433|       |
 2434|      3|        const Texture *const tex = it->second;
 2435|      3|        if (tex != nullptr) {
  ------------------
  |  Branch (2435:13): [True: 3, False: 0]
  ------------------
 2436|      3|            aiString path;
 2437|      3|            path.Set(tex->RelativeFilename());
 2438|       |
 2439|      3|            const Video *media = tex->Media();
 2440|      3|            if (media != nullptr && media->ContentLength() > 0) {
  ------------------
  |  Branch (2440:17): [True: 3, False: 0]
  |  Branch (2440:37): [True: 1, False: 2]
  ------------------
 2441|      1|                unsigned int index;
 2442|       |
 2443|      1|                VideoMap::const_iterator videoIt = textures_converted.find(media);
 2444|      1|                if (videoIt != textures_converted.end()) {
  ------------------
  |  Branch (2444:21): [True: 0, False: 1]
  ------------------
 2445|      0|                    index = videoIt->second;
 2446|      1|                } else {
 2447|      1|                    index = ConvertVideo(*media);
 2448|      1|                    textures_converted[media] = index;
 2449|      1|                }
 2450|       |
 2451|       |                // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
 2452|      1|                path.data[0] = '*';
 2453|      1|                path.length = 1 + ASSIMP_itoa10(path.data + 1, AI_MAXLEN - 1, index);
 2454|      1|            }
 2455|       |
 2456|      3|            out_mat->AddProperty(&path, (name + "|file").c_str(), aiTextureType_UNKNOWN, 0);
 2457|       |
 2458|      3|            aiUVTransform uvTrafo;
 2459|       |            // XXX handle all kinds of UV transformations
 2460|      3|            uvTrafo.mScaling = tex->UVScaling();
 2461|      3|            uvTrafo.mTranslation = tex->UVTranslation();
 2462|      3|            uvTrafo.mRotation = tex->UVRotation();
 2463|      3|            out_mat->AddProperty(&uvTrafo, 1, (name + "|uvtrafo").c_str(), aiTextureType_UNKNOWN, 0);
 2464|       |
 2465|      3|            int uvIndex = 0;
 2466|       |
 2467|      3|            bool uvFound = false;
 2468|      3|            const std::string &uvSet = PropertyGet<std::string>(tex->Props(), "UVSet", uvFound);
 2469|      3|            if (uvFound) {
  ------------------
  |  Branch (2469:17): [True: 3, False: 0]
  ------------------
 2470|       |                // "default" is the name which usually appears in the FbxFileTexture template
 2471|      3|                if (uvSet != "default" && uvSet.length()) {
  ------------------
  |  Branch (2471:21): [True: 3, False: 0]
  |  Branch (2471:43): [True: 3, False: 0]
  ------------------
 2472|       |                    // this is a bit awkward - we need to find a mesh that uses this
 2473|       |                    // material and scan its UV channels for the given UV name because
 2474|       |                    // assimp references UV channels by index, not by name.
 2475|       |
 2476|       |                    // XXX: the case that UV channels may appear in different orders
 2477|       |                    // in meshes is unhandled. A possible solution would be to sort
 2478|       |                    // the UV channels alphabetically, but this would have the side
 2479|       |                    // effect that the primary (first) UV channel would sometimes
 2480|       |                    // be moved, causing trouble when users read only the first
 2481|       |                    // UV channel and ignore UV channel assignments altogether.
 2482|       |
 2483|      3|                    std::vector<aiMaterial *>::iterator materialIt = std::find(materials.begin(), materials.end(), out_mat);
 2484|      3|                    const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), materialIt));
 2485|       |
 2486|      3|                    uvIndex = -1;
 2487|      3|                    if (!mesh) {
  ------------------
  |  Branch (2487:25): [True: 0, False: 3]
  ------------------
 2488|      0|                        for (const MeshMap::value_type &v : meshes_converted) {
  ------------------
  |  Branch (2488:59): [True: 0, False: 0]
  ------------------
 2489|      0|                            const MeshGeometry *const meshGeom = dynamic_cast<const MeshGeometry *>(v.first);
 2490|      0|                            if (!meshGeom) {
  ------------------
  |  Branch (2490:33): [True: 0, False: 0]
  ------------------
 2491|      0|                                continue;
 2492|      0|                            }
 2493|       |
 2494|      0|                            const MatIndexArray &mats = meshGeom->GetMaterialIndices();
 2495|      0|                            if (std::find(mats.begin(), mats.end(), (int)matIndex) == mats.end()) {
  ------------------
  |  Branch (2495:33): [True: 0, False: 0]
  ------------------
 2496|      0|                                continue;
 2497|      0|                            }
 2498|       |
 2499|      0|                            int index = -1;
 2500|      0|                            for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (2500:54): [True: 0, False: 0]
  ------------------
 2501|      0|                                if (meshGeom->GetTextureCoords(i).empty()) {
  ------------------
  |  Branch (2501:37): [True: 0, False: 0]
  ------------------
 2502|      0|                                    break;
 2503|      0|                                }
 2504|      0|                                const std::string &curName = meshGeom->GetTextureCoordChannelName(i);
 2505|      0|                                if (curName == uvSet) {
  ------------------
  |  Branch (2505:37): [True: 0, False: 0]
  ------------------
 2506|      0|                                    index = static_cast<int>(i);
 2507|      0|                                    break;
 2508|      0|                                }
 2509|      0|                            }
 2510|      0|                            if (index == -1) {
  ------------------
  |  Branch (2510:33): [True: 0, False: 0]
  ------------------
 2511|      0|                                FBXImporter::LogWarn("did not find UV channel named ", uvSet, " in a mesh using this material");
 2512|      0|                                continue;
 2513|      0|                            }
 2514|       |
 2515|      0|                            if (uvIndex == -1) {
  ------------------
  |  Branch (2515:33): [True: 0, False: 0]
  ------------------
 2516|      0|                                uvIndex = index;
 2517|      0|                            } else {
 2518|      0|                                FBXImporter::LogWarn("the UV channel named ", uvSet, " appears at different positions in meshes, results will be wrong");
 2519|      0|                            }
 2520|      0|                        }
 2521|      3|                    } else {
 2522|      3|                        int index = -1;
 2523|      3|                        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (2523:50): [True: 3, False: 0]
  ------------------
 2524|      3|                            if (mesh->GetTextureCoords(i).empty()) {
  ------------------
  |  Branch (2524:33): [True: 0, False: 3]
  ------------------
 2525|      0|                                break;
 2526|      0|                            }
 2527|      3|                            const std::string &curName = mesh->GetTextureCoordChannelName(i);
 2528|      3|                            if (curName == uvSet) {
  ------------------
  |  Branch (2528:33): [True: 3, False: 0]
  ------------------
 2529|      3|                                index = static_cast<int>(i);
 2530|      3|                                break;
 2531|      3|                            }
 2532|      3|                        }
 2533|      3|                        if (index == -1) {
  ------------------
  |  Branch (2533:29): [True: 0, False: 3]
  ------------------
 2534|      0|                            FBXImporter::LogWarn("did not find UV channel named ", uvSet, " in a mesh using this material");
 2535|      0|                        }
 2536|       |
 2537|      3|                        if (uvIndex == -1) {
  ------------------
  |  Branch (2537:29): [True: 3, False: 0]
  ------------------
 2538|      3|                            uvIndex = index;
 2539|      3|                        }
 2540|      3|                    }
 2541|       |
 2542|      3|                    if (uvIndex == -1) {
  ------------------
  |  Branch (2542:25): [True: 0, False: 3]
  ------------------
 2543|      0|                        FBXImporter::LogWarn("failed to resolve UV channel ", uvSet, ", using first UV channel");
 2544|      0|                        uvIndex = 0;
 2545|      0|                    }
 2546|      3|                }
 2547|      3|            }
 2548|       |
 2549|      3|            out_mat->AddProperty(&uvIndex, 1, (name + "|uvwsrc").c_str(), aiTextureType_UNKNOWN, 0);
 2550|      3|        }
 2551|      3|    }
 2552|     86|}
_ZN6Assimp3FBX12FBXConverter17FrameRateToDoubleENS0_18FileGlobalSettings9FrameRateEd:
 2554|    271|double FBXConverter::FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal) {
 2555|    271|    switch (fp) {
  ------------------
  |  Branch (2555:13): [True: 271, False: 0]
  ------------------
 2556|     30|        case FileGlobalSettings::FrameRate_DEFAULT:
  ------------------
  |  Branch (2556:9): [True: 30, False: 241]
  ------------------
 2557|     30|            return 1.0;
 2558|       |
 2559|      0|        case FileGlobalSettings::FrameRate_120:
  ------------------
  |  Branch (2559:9): [True: 0, False: 271]
  ------------------
 2560|      0|            return 120.0;
 2561|       |
 2562|      0|        case FileGlobalSettings::FrameRate_100:
  ------------------
  |  Branch (2562:9): [True: 0, False: 271]
  ------------------
 2563|      0|            return 100.0;
 2564|       |
 2565|      0|        case FileGlobalSettings::FrameRate_60:
  ------------------
  |  Branch (2565:9): [True: 0, False: 271]
  ------------------
 2566|      0|            return 60.0;
 2567|       |
 2568|      0|        case FileGlobalSettings::FrameRate_50:
  ------------------
  |  Branch (2568:9): [True: 0, False: 271]
  ------------------
 2569|      0|            return 50.0;
 2570|       |
 2571|      0|        case FileGlobalSettings::FrameRate_48:
  ------------------
  |  Branch (2571:9): [True: 0, False: 271]
  ------------------
 2572|      0|            return 48.0;
 2573|       |
 2574|      5|        case FileGlobalSettings::FrameRate_30:
  ------------------
  |  Branch (2574:9): [True: 5, False: 266]
  ------------------
 2575|      5|        case FileGlobalSettings::FrameRate_30_DROP:
  ------------------
  |  Branch (2575:9): [True: 0, False: 271]
  ------------------
 2576|      5|            return 30.0;
 2577|       |
 2578|      0|        case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME:
  ------------------
  |  Branch (2578:9): [True: 0, False: 271]
  ------------------
 2579|      0|        case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME:
  ------------------
  |  Branch (2579:9): [True: 0, False: 271]
  ------------------
 2580|      0|            return 29.9700262;
 2581|       |
 2582|      0|        case FileGlobalSettings::FrameRate_PAL:
  ------------------
  |  Branch (2582:9): [True: 0, False: 271]
  ------------------
 2583|      0|            return 25.0;
 2584|       |
 2585|    236|        case FileGlobalSettings::FrameRate_CINEMA:
  ------------------
  |  Branch (2585:9): [True: 236, False: 35]
  ------------------
 2586|    236|            return 24.0;
 2587|       |
 2588|      0|        case FileGlobalSettings::FrameRate_1000:
  ------------------
  |  Branch (2588:9): [True: 0, False: 271]
  ------------------
 2589|      0|            return 1000.0;
 2590|       |
 2591|      0|        case FileGlobalSettings::FrameRate_CINEMA_ND:
  ------------------
  |  Branch (2591:9): [True: 0, False: 271]
  ------------------
 2592|      0|            return 23.976;
 2593|       |
 2594|      0|        case FileGlobalSettings::FrameRate_CUSTOM:
  ------------------
  |  Branch (2594:9): [True: 0, False: 271]
  ------------------
 2595|      0|            return customFPSVal;
 2596|       |
 2597|      0|        case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings
  ------------------
  |  Branch (2597:9): [True: 0, False: 271]
  ------------------
 2598|      0|            break;
 2599|    271|    }
 2600|       |
 2601|    271|    ai_assert(false);
 2602|       |
 2603|      0|    return -1.0f;
 2604|    271|}
_ZN6Assimp3FBX12FBXConverter17ConvertAnimationsEv:
 2606|    271|void FBXConverter::ConvertAnimations() {
 2607|       |    // first of all determine framerate
 2608|    271|    const FileGlobalSettings::FrameRate fps = doc.GlobalSettings().TimeMode();
 2609|    271|    const float custom = doc.GlobalSettings().CustomFrameRate();
 2610|    271|    anim_fps = FrameRateToDouble(fps, custom);
 2611|       |
 2612|    271|    const std::vector<const AnimationStack *> &curAnimations = doc.AnimationStacks();
 2613|    271|    for (const AnimationStack *stack : curAnimations) {
  ------------------
  |  Branch (2613:38): [True: 256, False: 271]
  ------------------
 2614|    256|        ConvertAnimationStack(*stack);
 2615|    256|    }
 2616|    271|}
_ZN6Assimp3FBX12FBXConverter11FixNodeNameERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
 2618|  14.3k|std::string FBXConverter::FixNodeName(const std::string &name) {
 2619|       |    // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
 2620|       |    // this causes ambiguities, well possible between empty identifiers,
 2621|       |    // such as "Model::" and ""). Make sure the behaviour is consistent
 2622|       |    // across multiple calls to FixNodeName().
 2623|  14.3k|    if (name.substr(0, 7) == "Model::") {
  ------------------
  |  Branch (2623:9): [True: 14.3k, False: 66]
  ------------------
 2624|  14.3k|        std::string temp = name.substr(7);
 2625|  14.3k|        return temp;
 2626|  14.3k|    }
 2627|       |
 2628|     66|    return name;
 2629|  14.3k|}
_ZN6Assimp3FBX12FBXConverter21ConvertAnimationStackERKNS0_14AnimationStackE:
 2641|    256|void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
 2642|    256|    const AnimationLayerList &layers = st.Layers();
 2643|    256|    if (layers.empty()) {
  ------------------
  |  Branch (2643:9): [True: 6, False: 250]
  ------------------
 2644|      6|        return;
 2645|      6|    }
 2646|       |
 2647|    250|    aiAnimation *const anim = new aiAnimation();
 2648|    250|    animations.push_back(anim);
 2649|       |
 2650|       |    // strip AnimationStack:: prefix
 2651|    250|    std::string name = st.Name();
 2652|    250|    if (name.substr(0, 16) == "AnimationStack::") {
  ------------------
  |  Branch (2652:9): [True: 0, False: 250]
  ------------------
 2653|      0|        name = name.substr(16);
 2654|    250|    } else if (name.substr(0, 11) == "AnimStack::") {
  ------------------
  |  Branch (2654:16): [True: 244, False: 6]
  ------------------
 2655|    244|        name = name.substr(11);
 2656|    244|    }
 2657|       |
 2658|    250|    anim->mName.Set(name);
 2659|       |
 2660|       |    // need to find all nodes for which we need to generate node animations -
 2661|       |    // it may happen that we need to merge multiple layers, though.
 2662|    250|    NodeMap node_map;
 2663|       |
 2664|       |    // reverse mapping from curves to layers, much faster than querying
 2665|       |    // the FBX DOM for it.
 2666|    250|    LayerMap layer_map;
 2667|       |
 2668|    250|    const char *prop_whitelist[] = {
 2669|    250|        "Lcl Scaling",
 2670|    250|        "Lcl Rotation",
 2671|    250|        "Lcl Translation",
 2672|    250|        "DeformPercent"
 2673|    250|    };
 2674|       |
 2675|    250|    std::map<std::string, morphAnimData *> morphAnimDatas;
 2676|       |
 2677|    250|    for (const AnimationLayer *layer : layers) {
  ------------------
  |  Branch (2677:38): [True: 250, False: 250]
  ------------------
 2678|    250|        ai_assert(layer);
 2679|    250|        const AnimationCurveNodeList &nodes = layer->Nodes(prop_whitelist, 4);
 2680|  10.1k|        for (const AnimationCurveNode *node : nodes) {
  ------------------
  |  Branch (2680:45): [True: 10.1k, False: 250]
  ------------------
 2681|  10.1k|            ai_assert(node);
 2682|  10.1k|            const Model *const model = dynamic_cast<const Model *>(node->Target());
 2683|  10.1k|            if (model) {
  ------------------
  |  Branch (2683:17): [True: 10.1k, False: 0]
  ------------------
 2684|  10.1k|                const std::string &curName = FixNodeName(model->Name());
 2685|  10.1k|                node_map[curName].push_back(node);
 2686|  10.1k|                layer_map[node] = layer;
 2687|  10.1k|                continue;
 2688|  10.1k|            }
 2689|      0|            const BlendShapeChannel *const bsc = dynamic_cast<const BlendShapeChannel *>(node->Target());
 2690|      0|            if (bsc) {
  ------------------
  |  Branch (2690:17): [True: 0, False: 0]
  ------------------
 2691|      0|                ProcessMorphAnimDatas(&morphAnimDatas, bsc, node);
 2692|      0|            }
 2693|      0|        }
 2694|    250|    }
 2695|       |
 2696|       |    // generate node animations
 2697|    250|    std::vector<aiNodeAnim *> node_anims;
 2698|       |
 2699|    250|    double min_time = 1e10;
 2700|    250|    double max_time = -1e10;
 2701|       |
 2702|    250|    int64_t start_time = st.LocalStart();
 2703|    250|    int64_t stop_time = st.LocalStop();
 2704|    250|    bool has_local_startstop = start_time != 0 || stop_time != 0;
  ------------------
  |  Branch (2704:32): [True: 48, False: 202]
  |  Branch (2704:51): [True: 197, False: 5]
  ------------------
 2705|    250|    if (!has_local_startstop) {
  ------------------
  |  Branch (2705:9): [True: 5, False: 245]
  ------------------
 2706|       |        // no time range given, so accept every keyframe and use the actual min/max time
 2707|       |        // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000
 2708|      5|        start_time = -9223372036854775807ll + 20000;
 2709|      5|        stop_time = 9223372036854775807ll - 20000;
 2710|      5|    }
 2711|       |
 2712|    250|    try {
 2713|  3.26k|        for (const NodeMap::value_type &kv : node_map) {
  ------------------
  |  Branch (2713:44): [True: 3.26k, False: 250]
  ------------------
 2714|  3.26k|            GenerateNodeAnimations(node_anims,
 2715|  3.26k|                    kv.first,
 2716|  3.26k|                    kv.second,
 2717|  3.26k|                    layer_map,
 2718|  3.26k|                    start_time, stop_time,
 2719|  3.26k|                    max_time,
 2720|  3.26k|                    min_time);
 2721|  3.26k|        }
 2722|    250|    } catch (std::exception &) {
 2723|     17|        std::for_each(node_anims.begin(), node_anims.end(), Util::delete_fun<aiNodeAnim>());
 2724|     17|        throw;
 2725|     17|    }
 2726|       |
 2727|    228|    if (node_anims.size() || morphAnimDatas.size()) {
  ------------------
  |  Branch (2727:9): [True: 225, False: 3]
  |  Branch (2727:30): [True: 0, False: 3]
  ------------------
 2728|    225|        if (node_anims.size()) {
  ------------------
  |  Branch (2728:13): [True: 225, False: 0]
  ------------------
 2729|    225|            anim->mChannels = new aiNodeAnim *[node_anims.size()]();
 2730|    225|            anim->mNumChannels = static_cast<unsigned int>(node_anims.size());
 2731|    225|            std::swap_ranges(node_anims.begin(), node_anims.end(), anim->mChannels);
 2732|    225|        }
 2733|    225|        if (morphAnimDatas.size()) {
  ------------------
  |  Branch (2733:13): [True: 0, False: 225]
  ------------------
 2734|      0|            unsigned int numMorphMeshChannels = static_cast<unsigned int>(morphAnimDatas.size());
 2735|      0|            anim->mMorphMeshChannels = new aiMeshMorphAnim *[numMorphMeshChannels];
 2736|      0|            anim->mNumMorphMeshChannels = numMorphMeshChannels;
 2737|      0|            unsigned int i = 0;
 2738|      0|            for (const auto &morphAnimIt : morphAnimDatas) {
  ------------------
  |  Branch (2738:42): [True: 0, False: 0]
  ------------------
 2739|      0|                morphAnimData *animData = morphAnimIt.second;
 2740|      0|                unsigned int numKeys = static_cast<unsigned int>(animData->size());
 2741|      0|                aiMeshMorphAnim *meshMorphAnim = new aiMeshMorphAnim();
 2742|      0|                meshMorphAnim->mName.Set(morphAnimIt.first);
 2743|      0|                meshMorphAnim->mNumKeys = numKeys;
 2744|      0|                meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
 2745|      0|                unsigned int j = 0;
 2746|      0|                for (auto &animIt : *animData) {
  ------------------
  |  Branch (2746:35): [True: 0, False: 0]
  ------------------
 2747|      0|                    morphKeyData *keyData = animIt.second;
 2748|      0|                    unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
 2749|      0|                    meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
 2750|      0|                    meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights];
 2751|      0|                    meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights];
 2752|      0|                    meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first) * anim_fps;
  ------------------
  |  |   77|      0|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 2753|      0|                    for (unsigned int k = 0; k < numValuesAndWeights; k++) {
  ------------------
  |  Branch (2753:46): [True: 0, False: 0]
  ------------------
 2754|      0|                        meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k);
 2755|      0|                        meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k);
 2756|      0|                    }
 2757|      0|                    j++;
 2758|      0|                }
 2759|      0|                anim->mMorphMeshChannels[i++] = meshMorphAnim;
 2760|      0|            }
 2761|      0|        }
 2762|    225|    } else {
 2763|       |        // empty animations would fail validation, so drop them
 2764|      3|        delete anim;
 2765|      3|        animations.pop_back();
 2766|      3|        FBXImporter::LogInfo("ignoring empty AnimationStack (using IK?): ", name);
 2767|      3|        return;
 2768|      3|    }
 2769|       |
 2770|    225|    double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time;
  ------------------
  |  |   77|    221|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
  |  Branch (2770:29): [True: 221, False: 4]
  ------------------
 2771|    225|    double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time;
  ------------------
  |  |   77|    221|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
  |  Branch (2771:28): [True: 221, False: 4]
  ------------------
 2772|       |
 2773|       |    // adjust relative timing for animation
 2774|  4.32k|    for (unsigned int c = 0; c < anim->mNumChannels; c++) {
  ------------------
  |  Branch (2774:30): [True: 4.09k, False: 225]
  ------------------
 2775|  4.09k|        aiNodeAnim *channel = anim->mChannels[c];
 2776|  4.15M|        for (uint32_t i = 0; i < channel->mNumPositionKeys; i++) {
  ------------------
  |  Branch (2776:30): [True: 4.14M, False: 4.09k]
  ------------------
 2777|  4.14M|            channel->mPositionKeys[i].mTime -= start_time_fps;
 2778|  4.14M|        }
 2779|  4.88M|        for (uint32_t i = 0; i < channel->mNumRotationKeys; i++) {
  ------------------
  |  Branch (2779:30): [True: 4.88M, False: 4.09k]
  ------------------
 2780|  4.88M|            channel->mRotationKeys[i].mTime -= start_time_fps;
 2781|  4.88M|        }
 2782|  4.15M|        for (uint32_t i = 0; i < channel->mNumScalingKeys; i++) {
  ------------------
  |  Branch (2782:30): [True: 4.14M, False: 4.09k]
  ------------------
 2783|  4.14M|            channel->mScalingKeys[i].mTime -= start_time_fps;
 2784|  4.14M|        }
 2785|  4.09k|    }
 2786|    225|    for (unsigned int c = 0; c < anim->mNumMorphMeshChannels; c++) {
  ------------------
  |  Branch (2786:30): [True: 0, False: 225]
  ------------------
 2787|      0|        aiMeshMorphAnim *channel = anim->mMorphMeshChannels[c];
 2788|      0|        for (uint32_t i = 0; i < channel->mNumKeys; i++) {
  ------------------
  |  Branch (2788:30): [True: 0, False: 0]
  ------------------
 2789|      0|            channel->mKeys[i].mTime -= start_time_fps;
 2790|      0|        }
 2791|      0|    }
 2792|       |
 2793|       |    // for some mysterious reason, mDuration is simply the maximum key -- the
 2794|       |    // validator always assumes animations to start at zero.
 2795|    225|    anim->mDuration = stop_time_fps - start_time_fps;
 2796|    225|    anim->mTicksPerSecond = anim_fps;
 2797|    225|}
_ZN6Assimp3FBX12FBXConverter22GenerateNodeAnimationsERNSt3__16vectorIP10aiNodeAnimNS2_9allocatorIS5_EEEERKNS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEERKNS3_IPKNS0_18AnimationCurveNodeENS6_ISJ_EEEERKNS2_3mapISJ_PKNS0_14AnimationLayerENS2_4lessISJ_EENS6_INS2_4pairIKSJ_SR_EEEEEEllRdS11_:
 2886|  3.26k|        double &min_time) {
 2887|       |
 2888|  3.26k|    NodeMap node_property_map;
 2889|  3.26k|    ai_assert(curves.size());
 2890|       |
 2891|  3.26k|#ifdef ASSIMP_BUILD_DEBUG
 2892|  3.26k|    validateAnimCurveNodes(curves, doc.Settings().strictMode);
 2893|  3.26k|#endif
 2894|  3.26k|    const AnimationCurveNode *curve_node = nullptr;
 2895|  9.53k|    for (const AnimationCurveNode *node : curves) {
  ------------------
  |  Branch (2895:41): [True: 9.53k, False: 3.26k]
  ------------------
 2896|  9.53k|        ai_assert(node);
 2897|       |
 2898|  9.53k|        if (node->TargetProperty().empty()) {
  ------------------
  |  Branch (2898:13): [True: 0, False: 9.53k]
  ------------------
 2899|      0|            FBXImporter::LogWarn("target property for animation curve not set: ", node->Name());
 2900|      0|            continue;
 2901|      0|        }
 2902|       |
 2903|  9.53k|        curve_node = node;
 2904|  9.53k|        if (node->Curves().empty()) {
  ------------------
  |  Branch (2904:13): [True: 0, False: 9.53k]
  ------------------
 2905|      0|            FBXImporter::LogWarn("no animation curves assigned to AnimationCurveNode: ", node->Name());
 2906|      0|            continue;
 2907|      0|        }
 2908|       |
 2909|  9.53k|        node_property_map[node->TargetProperty()].push_back(node);
 2910|  9.53k|    }
 2911|       |
 2912|  3.26k|    ai_assert(curve_node);
 2913|  3.26k|    ai_assert(curve_node->TargetAsModel());
 2914|       |
 2915|  3.26k|    const Model &target = *curve_node->TargetAsModel();
 2916|       |
 2917|       |    // check for all possible transformation components
 2918|  3.26k|    NodeMap::const_iterator chain[TransformationComp_MAXIMUM];
 2919|       |
 2920|  3.26k|    bool has_any = false;
 2921|  3.26k|    bool has_complex = false;
 2922|       |
 2923|  58.6k|    for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
  ------------------
  |  Branch (2923:24): [True: 55.3k, False: 3.26k]
  ------------------
 2924|  55.3k|        const TransformationComp comp = static_cast<TransformationComp>(i);
 2925|       |
 2926|       |        // inverse pivots don't exist in the input, we just generate them
 2927|  55.3k|        if (comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse) {
  ------------------
  |  Branch (2927:13): [True: 3.25k, False: 52.1k]
  |  Branch (2927:64): [True: 3.25k, False: 48.8k]
  ------------------
 2928|  6.51k|            chain[i] = node_property_map.end();
 2929|  6.51k|            continue;
 2930|  6.51k|        }
 2931|       |
 2932|  48.8k|        chain[i] = node_property_map.find(NameTransformationCompProperty(comp));
 2933|  48.8k|        if (chain[i] != node_property_map.end()) {
  ------------------
  |  Branch (2933:13): [True: 9.38k, False: 39.4k]
  ------------------
 2934|       |
 2935|       |            // check if this curves contains redundant information by looking
 2936|       |            // up the corresponding node's transformation chain.
 2937|  9.38k|            if (doc.Settings().optimizeEmptyAnimationCurves &&
  ------------------
  |  Branch (2937:17): [True: 9.38k, False: 0]
  ------------------
 2938|  9.38k|                    IsRedundantAnimationData(target, comp, (chain[i]->second))) {
  ------------------
  |  Branch (2938:21): [True: 0, False: 9.38k]
  ------------------
 2939|       |
 2940|      0|                FBXImporter::LogVerboseDebug("dropping redundant animation channel for node ", target.Name());
 2941|      0|                continue;
 2942|      0|            }
 2943|       |
 2944|  9.38k|            has_any = true;
 2945|       |
 2946|  9.38k|            if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation) {
  ------------------
  |  Branch (2946:17): [True: 6.25k, False: 3.13k]
  |  Branch (2946:56): [True: 3.14k, False: 3.11k]
  |  Branch (2946:94): [True: 0, False: 3.14k]
  ------------------
 2947|      0|                has_complex = true;
 2948|      0|            }
 2949|  9.38k|        }
 2950|  48.8k|    }
 2951|       |
 2952|  3.26k|    if (!has_any) {
  ------------------
  |  Branch (2952:9): [True: 0, False: 3.26k]
  ------------------
 2953|      0|        FBXImporter::LogWarn("ignoring node animation, did not find any transformation key frames");
 2954|      0|        return;
 2955|      0|    }
 2956|       |
 2957|       |    // this needs to play nicely with GenerateTransformationNodeChain() which will
 2958|       |    // be invoked _later_ (animations come first). If this node has only rotation,
 2959|       |    // scaling and translation _and_ there are no animated other components either,
 2960|       |    // we can use a single node and also a single node animation channel.
 2961|  3.26k|    if (!doc.Settings().preservePivots || (!has_complex && !NeedsComplexTransformationChain(target))) {
  ------------------
  |  Branch (2961:9): [True: 4, False: 3.25k]
  |  Branch (2961:44): [True: 3.25k, False: 0]
  |  Branch (2961:60): [True: 2.72k, False: 535]
  ------------------
 2962|  2.72k|        aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain,
 2963|  2.72k|                node_property_map.end(),
 2964|  2.72k|                start, stop,
 2965|  2.72k|                max_time,
 2966|  2.72k|                min_time
 2967|  2.72k|        );
 2968|       |
 2969|  2.72k|        ai_assert(nd);
 2970|  2.72k|        if (nd->mNumPositionKeys == 0 && nd->mNumRotationKeys == 0 && nd->mNumScalingKeys == 0) {
  ------------------
  |  Branch (2970:13): [True: 1, False: 2.72k]
  |  Branch (2970:42): [True: 1, False: 0]
  |  Branch (2970:71): [True: 1, False: 0]
  ------------------
 2971|      1|            delete nd;
 2972|  2.72k|        } else {
 2973|  2.72k|            node_anims.push_back(nd);
 2974|  2.72k|        }
 2975|  2.72k|        return;
 2976|  2.72k|    }
 2977|       |
 2978|       |    // otherwise, things get gruesome and we need separate animation channels
 2979|       |    // for each part of the transformation chain. Remember which channels
 2980|       |    // we generated and pass this information to the node conversion
 2981|       |    // code to avoid nodes that have identity transform, but non-identity
 2982|       |    // animations, being dropped.
 2983|    539|    unsigned int flags = 0, bit = 0x1;
 2984|  9.61k|    for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) {
  ------------------
  |  Branch (2984:24): [True: 9.07k, False: 539]
  ------------------
 2985|  9.07k|        const TransformationComp comp = static_cast<TransformationComp>(i);
 2986|       |
 2987|  9.07k|        if (chain[i] != node_property_map.end()) {
  ------------------
  |  Branch (2987:13): [True: 1.44k, False: 7.63k]
  ------------------
 2988|  1.44k|            flags |= bit;
 2989|       |
 2990|  1.44k|            ai_assert(comp != TransformationComp_RotationPivotInverse);
 2991|  1.44k|            ai_assert(comp != TransformationComp_ScalingPivotInverse);
 2992|       |
 2993|  1.44k|            const std::string &chain_name = NameTransformationChainNode(fixed_name, comp);
 2994|       |
 2995|  1.44k|            aiNodeAnim *na = nullptr;
 2996|  1.44k|            switch (comp) {
 2997|    490|                case TransformationComp_Rotation:
  ------------------
  |  Branch (2997:17): [True: 490, False: 956]
  ------------------
 2998|    490|                case TransformationComp_PreRotation:
  ------------------
  |  Branch (2998:17): [True: 0, False: 1.44k]
  ------------------
 2999|    490|                case TransformationComp_PostRotation:
  ------------------
  |  Branch (2999:17): [True: 0, False: 1.44k]
  ------------------
 3000|    490|                case TransformationComp_GeometricRotation:
  ------------------
  |  Branch (3000:17): [True: 0, False: 1.44k]
  ------------------
 3001|    490|                    na = GenerateRotationNodeAnim(chain_name,
 3002|    490|                            target,
 3003|    490|                            (*chain[i]).second,
 3004|    490|                            layer_map,
 3005|    490|                            start, stop,
 3006|    490|                            max_time,
 3007|    490|                            min_time);
 3008|       |
 3009|    490|                    break;
 3010|       |
 3011|      0|                case TransformationComp_RotationOffset:
  ------------------
  |  Branch (3011:17): [True: 0, False: 1.44k]
  ------------------
 3012|      0|                case TransformationComp_RotationPivot:
  ------------------
  |  Branch (3012:17): [True: 0, False: 1.44k]
  ------------------
 3013|      0|                case TransformationComp_ScalingOffset:
  ------------------
  |  Branch (3013:17): [True: 0, False: 1.44k]
  ------------------
 3014|      0|                case TransformationComp_ScalingPivot:
  ------------------
  |  Branch (3014:17): [True: 0, False: 1.44k]
  ------------------
 3015|    494|                case TransformationComp_Translation:
  ------------------
  |  Branch (3015:17): [True: 494, False: 952]
  ------------------
 3016|    494|                case TransformationComp_GeometricTranslation:
  ------------------
  |  Branch (3016:17): [True: 0, False: 1.44k]
  ------------------
 3017|    494|                    na = GenerateTranslationNodeAnim(chain_name,
 3018|    494|                            target,
 3019|    494|                            (*chain[i]).second,
 3020|    494|                            layer_map,
 3021|    494|                            start, stop,
 3022|    494|                            max_time,
 3023|    494|                            min_time);
 3024|       |
 3025|       |                    // pivoting requires us to generate an implicit inverse channel to undo the pivot translation
 3026|    494|                    if (comp == TransformationComp_RotationPivot) {
  ------------------
  |  Branch (3026:25): [True: 0, False: 494]
  ------------------
 3027|      0|                        const std::string &invName = NameTransformationChainNode(fixed_name,
 3028|      0|                                TransformationComp_RotationPivotInverse);
 3029|       |
 3030|      0|                        aiNodeAnim *const inv = GenerateTranslationNodeAnim(invName,
 3031|      0|                                target,
 3032|      0|                                (*chain[i]).second,
 3033|      0|                                layer_map,
 3034|      0|                                start, stop,
 3035|      0|                                max_time,
 3036|      0|                                min_time,
 3037|      0|                                true);
 3038|       |
 3039|      0|                        ai_assert(inv);
 3040|      0|                        if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) {
  ------------------
  |  Branch (3040:29): [True: 0, False: 0]
  |  Branch (3040:59): [True: 0, False: 0]
  |  Branch (3040:89): [True: 0, False: 0]
  ------------------
 3041|      0|                            delete inv;
 3042|      0|                        } else {
 3043|      0|                            node_anims.push_back(inv);
 3044|      0|                        }
 3045|       |
 3046|      0|                        ai_assert(TransformationComp_RotationPivotInverse > i);
 3047|      0|                        flags |= bit << (TransformationComp_RotationPivotInverse - i);
 3048|    494|                    } else if (comp == TransformationComp_ScalingPivot) {
  ------------------
  |  Branch (3048:32): [True: 0, False: 494]
  ------------------
 3049|      0|                        const std::string &invName = NameTransformationChainNode(fixed_name,
 3050|      0|                                TransformationComp_ScalingPivotInverse);
 3051|       |
 3052|      0|                        aiNodeAnim *const inv = GenerateTranslationNodeAnim(invName,
 3053|      0|                                target,
 3054|      0|                                (*chain[i]).second,
 3055|      0|                                layer_map,
 3056|      0|                                start, stop,
 3057|      0|                                max_time,
 3058|      0|                                min_time,
 3059|      0|                                true);
 3060|       |
 3061|      0|                        ai_assert(inv);
 3062|      0|                        if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) {
  ------------------
  |  Branch (3062:29): [True: 0, False: 0]
  |  Branch (3062:59): [True: 0, False: 0]
  |  Branch (3062:89): [True: 0, False: 0]
  ------------------
 3063|      0|                            delete inv;
 3064|      0|                        } else {
 3065|      0|                            node_anims.push_back(inv);
 3066|      0|                        }
 3067|       |
 3068|      0|                        ai_assert(TransformationComp_RotationPivotInverse > i);
 3069|      0|                        flags |= bit << (TransformationComp_RotationPivotInverse - i);
 3070|      0|                    }
 3071|       |
 3072|    494|                    break;
 3073|       |
 3074|    462|                case TransformationComp_Scaling:
  ------------------
  |  Branch (3074:17): [True: 462, False: 984]
  ------------------
 3075|    462|                case TransformationComp_GeometricScaling:
  ------------------
  |  Branch (3075:17): [True: 0, False: 1.44k]
  ------------------
 3076|    462|                    na = GenerateScalingNodeAnim(chain_name,
 3077|    462|                            target,
 3078|    462|                            (*chain[i]).second,
 3079|    462|                            layer_map,
 3080|    462|                            start, stop,
 3081|    462|                            max_time,
 3082|    462|                            min_time);
 3083|       |
 3084|    462|                    break;
 3085|       |
 3086|      0|                default:
  ------------------
  |  Branch (3086:17): [True: 0, False: 1.44k]
  ------------------
 3087|      0|                    ai_assert(false);
 3088|  1.44k|            }
 3089|       |
 3090|  1.44k|            ai_assert(na);
 3091|  1.44k|            if (na->mNumPositionKeys == 0 && na->mNumRotationKeys == 0 && na->mNumScalingKeys == 0) {
  ------------------
  |  Branch (3091:17): [True: 64, False: 1.38k]
  |  Branch (3091:46): [True: 0, False: 64]
  |  Branch (3091:75): [True: 0, False: 0]
  ------------------
 3092|      0|                delete na;
 3093|  1.44k|            } else {
 3094|  1.44k|                node_anims.push_back(na);
 3095|  1.44k|            }
 3096|  1.44k|            continue;
 3097|  1.44k|        }
 3098|  9.07k|    }
 3099|       |
 3100|    539|    node_anim_chain_bits[fixed_name] = flags;
 3101|    539|}
_ZN6Assimp3FBX12FBXConverter24IsRedundantAnimationDataERKNS0_5ModelENS1_18TransformationCompERKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS6_9allocatorISA_EEEE:
 3105|  9.38k|        const std::vector<const AnimationCurveNode *> &curves) {
 3106|  9.38k|    ai_assert(curves.size());
 3107|       |
 3108|       |    // look for animation nodes with
 3109|       |    //  * sub channels for all relevant components set
 3110|       |    //  * one key/value pair per component
 3111|       |    //  * combined values match up the corresponding value in the bind pose node transformation
 3112|       |    // only such nodes are 'redundant' for this function.
 3113|       |
 3114|  9.38k|    if (curves.size() > 1) {
  ------------------
  |  Branch (3114:9): [True: 126, False: 9.26k]
  ------------------
 3115|    126|        return false;
 3116|    126|    }
 3117|       |
 3118|  9.26k|    const AnimationCurveNode &nd = *curves.front();
 3119|  9.26k|    const AnimationCurveMap &sub_curves = nd.Curves();
 3120|       |
 3121|  9.26k|    const AnimationCurveMap::const_iterator dx = sub_curves.find("d|X");
 3122|  9.26k|    const AnimationCurveMap::const_iterator dy = sub_curves.find("d|Y");
 3123|  9.26k|    const AnimationCurveMap::const_iterator dz = sub_curves.find("d|Z");
 3124|       |
 3125|  9.26k|    if (dx == sub_curves.end() || dy == sub_curves.end() || dz == sub_curves.end()) {
  ------------------
  |  Branch (3125:9): [True: 432, False: 8.83k]
  |  Branch (3125:9): [True: 1.02k, False: 8.24k]
  |  Branch (3125:35): [True: 261, False: 8.57k]
  |  Branch (3125:61): [True: 328, False: 8.24k]
  ------------------
 3126|  1.02k|        return false;
 3127|  1.02k|    }
 3128|       |
 3129|  8.24k|    const KeyValueList &vx = (*dx).second->GetValues();
 3130|  8.24k|    const KeyValueList &vy = (*dy).second->GetValues();
 3131|  8.24k|    const KeyValueList &vz = (*dz).second->GetValues();
 3132|       |
 3133|  8.24k|    if (vx.size() != 1 || vy.size() != 1 || vz.size() != 1) {
  ------------------
  |  Branch (3133:9): [True: 8.24k, False: 0]
  |  Branch (3133:27): [True: 0, False: 0]
  |  Branch (3133:45): [True: 0, False: 0]
  ------------------
 3134|  8.24k|        return false;
 3135|  8.24k|    }
 3136|       |
 3137|      0|    const aiVector3D dyn_val = aiVector3D(vx[0], vy[0], vz[0]);
 3138|      0|    const aiVector3D &static_val = PropertyGet<aiVector3D>(target.Props(),
 3139|      0|            NameTransformationCompProperty(comp),
 3140|      0|            TransformationCompDefaultValue(comp));
 3141|       |
 3142|      0|    const float epsilon = Math::getEpsilon<float>();
 3143|      0|    return (dyn_val - static_val).SquareLength() < epsilon;
 3144|  8.24k|}
_ZN6Assimp3FBX12FBXConverter24GenerateRotationNodeAnimERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5ModelERKNS2_6vectorIPKNS0_18AnimationCurveNodeENS6_ISH_EEEERKNS2_3mapISH_PKNS0_14AnimationLayerENS2_4lessISH_EENS6_INS2_4pairIKSH_SP_EEEEEEllRdSZ_:
 3152|    490|        double &min_time) {
 3153|    490|    std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
 3154|    490|    na->mNodeName.Set(name);
 3155|       |
 3156|    490|    ConvertRotationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time, target.RotationOrder());
 3157|       |
 3158|       |    // dummy scaling key
 3159|    490|    na->mScalingKeys = new aiVectorKey[1];
 3160|    490|    na->mNumScalingKeys = 1;
 3161|       |
 3162|    490|    na->mScalingKeys[0].mTime = 0.;
 3163|    490|    na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f);
 3164|       |
 3165|       |    // dummy position key
 3166|    490|    na->mPositionKeys = new aiVectorKey[1];
 3167|    490|    na->mNumPositionKeys = 1;
 3168|       |
 3169|    490|    na->mPositionKeys[0].mTime = 0.;
 3170|    490|    na->mPositionKeys[0].mValue = aiVector3D();
 3171|       |
 3172|    490|    return na.release();
 3173|    490|}
_ZN6Assimp3FBX12FBXConverter23GenerateScalingNodeAnimERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5ModelERKNS2_6vectorIPKNS0_18AnimationCurveNodeENS6_ISH_EEEERKNS2_3mapISH_PKNS0_14AnimationLayerENS2_4lessISH_EENS6_INS2_4pairIKSH_SP_EEEEEEllRdSZ_:
 3181|    462|        double &min_time) {
 3182|    462|    std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
 3183|    462|    na->mNodeName.Set(name);
 3184|       |
 3185|    462|    ConvertScaleKeys(na.get(), curves, layer_map, start, stop, max_time, min_time);
 3186|       |
 3187|       |    // dummy rotation key
 3188|    462|    na->mRotationKeys = new aiQuatKey[1];
 3189|    462|    na->mNumRotationKeys = 1;
 3190|       |
 3191|    462|    na->mRotationKeys[0].mTime = 0.;
 3192|    462|    na->mRotationKeys[0].mValue = aiQuaternion();
 3193|       |
 3194|       |    // dummy position key
 3195|    462|    na->mPositionKeys = new aiVectorKey[1];
 3196|    462|    na->mNumPositionKeys = 1;
 3197|       |
 3198|    462|    na->mPositionKeys[0].mTime = 0.;
 3199|    462|    na->mPositionKeys[0].mValue = aiVector3D();
 3200|       |
 3201|    462|    return na.release();
 3202|    462|}
_ZN6Assimp3FBX12FBXConverter27GenerateTranslationNodeAnimERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5ModelERKNS2_6vectorIPKNS0_18AnimationCurveNodeENS6_ISH_EEEERKNS2_3mapISH_PKNS0_14AnimationLayerENS2_4lessISH_EENS6_INS2_4pairIKSH_SP_EEEEEEllRdSZ_b:
 3211|    494|        bool inverse) {
 3212|    494|    std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
 3213|    494|    na->mNodeName.Set(name);
 3214|       |
 3215|    494|    ConvertTranslationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time);
 3216|       |
 3217|    494|    if (inverse) {
  ------------------
  |  Branch (3217:9): [True: 0, False: 494]
  ------------------
 3218|      0|        for (unsigned int i = 0; i < na->mNumPositionKeys; ++i) {
  ------------------
  |  Branch (3218:34): [True: 0, False: 0]
  ------------------
 3219|      0|            na->mPositionKeys[i].mValue *= -1.0f;
 3220|      0|        }
 3221|      0|    }
 3222|       |
 3223|       |    // dummy scaling key
 3224|    494|    na->mScalingKeys = new aiVectorKey[1];
 3225|    494|    na->mNumScalingKeys = 1;
 3226|       |
 3227|    494|    na->mScalingKeys[0].mTime = 0.;
 3228|    494|    na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f);
 3229|       |
 3230|       |    // dummy rotation key
 3231|    494|    na->mRotationKeys = new aiQuatKey[1];
 3232|    494|    na->mNumRotationKeys = 1;
 3233|       |
 3234|    494|    na->mRotationKeys[0].mTime = 0.;
 3235|    494|    na->mRotationKeys[0].mValue = aiQuaternion();
 3236|       |
 3237|    494|    return na.release();
 3238|    494|}
_ZN6Assimp3FBX12FBXConverter22GenerateSimpleNodeAnimERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5ModelEPNS2_20__map_const_iteratorINS2_21__tree_const_iteratorINS2_12__value_typeIS8_NS2_6vectorIPKNS0_18AnimationCurveNodeENS6_ISK_EEEEEEPNS2_11__tree_nodeISN_PvEElEEEEST_llRdSV_:
 3247|  2.72k|{
 3248|  2.72k|    std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
 3249|  2.72k|    na->mNodeName.Set(name);
 3250|       |
 3251|  2.72k|    const PropertyTable &props = target.Props();
 3252|       |
 3253|       |    // collect unique times and keyframe lists
 3254|  2.72k|    KeyFrameListList keyframeLists[TransformationComp_MAXIMUM];
 3255|  2.72k|    KeyTimeList keytimes;
 3256|       |
 3257|  48.9k|    for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
  ------------------
  |  Branch (3257:24): [True: 46.2k, False: 2.72k]
  ------------------
 3258|  46.2k|        if (chain[i] == iterEnd)
  ------------------
  |  Branch (3258:13): [True: 38.3k, False: 7.94k]
  ------------------
 3259|  38.3k|            continue;
 3260|       |
 3261|  7.94k|        if (i == TransformationComp_Rotation || i == TransformationComp_PreRotation
  ------------------
  |  Branch (3261:13): [True: 2.64k, False: 5.29k]
  |  Branch (3261:49): [True: 0, False: 5.29k]
  ------------------
 3262|  5.29k|                || i == TransformationComp_PostRotation || i == TransformationComp_GeometricRotation) {
  ------------------
  |  Branch (3262:20): [True: 0, False: 5.29k]
  |  Branch (3262:60): [True: 0, False: 5.29k]
  ------------------
 3263|  2.64k|            keyframeLists[i] = GetRotationKeyframeList((*chain[i]).second, start, stop);
 3264|  5.29k|        } else {
 3265|  5.29k|            keyframeLists[i] = GetKeyframeList((*chain[i]).second, start, stop);
 3266|  5.29k|        }
 3267|       |
 3268|  31.3k|        for (KeyFrameListList::const_iterator it = keyframeLists[i].begin(); it != keyframeLists[i].end(); ++it) {
  ------------------
  |  Branch (3268:78): [True: 23.3k, False: 7.94k]
  ------------------
 3269|  23.3k|            const KeyTimeList& times = *std::get<0>(*it);
 3270|  23.3k|            keytimes.insert(keytimes.end(), times.begin(), times.end());
 3271|  23.3k|        }
 3272|       |
 3273|       |        // remove duplicates
 3274|  7.94k|        std::sort(keytimes.begin(), keytimes.end());
 3275|       |
 3276|  7.94k|        auto last = std::unique(keytimes.begin(), keytimes.end());
 3277|  7.94k|        keytimes.erase(last, keytimes.end());
 3278|  7.94k|    }
 3279|       |
 3280|  2.72k|    const Model::RotOrder rotOrder = target.RotationOrder();
 3281|  2.72k|    const size_t keyCount = keytimes.size();
 3282|       |
 3283|  2.72k|    aiVector3D defTranslate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f));
 3284|  2.72k|    aiVector3D defRotation = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f));
 3285|  2.72k|    aiVector3D defScale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f));
 3286|       |
 3287|  2.72k|    aiVectorKey* outTranslations = new aiVectorKey[keyCount];
 3288|  2.72k|    aiQuatKey* outRotations = new aiQuatKey[keyCount];
 3289|  2.72k|    aiVectorKey* outScales = new aiVectorKey[keyCount];
 3290|       |
 3291|  2.72k|    if (keyframeLists[TransformationComp_Translation].size() > 0) {
  ------------------
  |  Branch (3291:9): [True: 2.63k, False: 87]
  ------------------
 3292|  2.63k|        InterpolateKeys(outTranslations, keytimes, keyframeLists[TransformationComp_Translation], defTranslate, maxTime, minTime);
 3293|  2.63k|    } else {
 3294|    276|        for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3294:28): [True: 189, False: 87]
  ------------------
 3295|    189|            outTranslations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
  ------------------
  |  |   77|    189|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 3296|    189|            outTranslations[i].mValue = defTranslate;
 3297|    189|        }
 3298|     87|    }
 3299|       |
 3300|  2.72k|    if (keyframeLists[TransformationComp_Rotation].size() > 0) {
  ------------------
  |  Branch (3300:9): [True: 2.63k, False: 89]
  ------------------
 3301|  2.63k|        InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder);
 3302|  2.63k|    } else {
 3303|     89|        aiQuaternion defQuat = EulerToQuaternion(defRotation, rotOrder);
 3304|    236|        for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3304:28): [True: 147, False: 89]
  ------------------
 3305|    147|            outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
  ------------------
  |  |   77|    147|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 3306|    147|            outRotations[i].mValue = defQuat;
 3307|    147|        }
 3308|     89|    }
 3309|       |
 3310|  2.72k|    if (keyframeLists[TransformationComp_Scaling].size() > 0) {
  ------------------
  |  Branch (3310:9): [True: 2.63k, False: 83]
  ------------------
 3311|  2.63k|        InterpolateKeys(outScales, keytimes, keyframeLists[TransformationComp_Scaling], defScale, maxTime, minTime);
 3312|  2.63k|    } else {
 3313|    249|        for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3313:28): [True: 166, False: 83]
  ------------------
 3314|    166|            outScales[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
  ------------------
  |  |   77|    166|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 3315|    166|            outScales[i].mValue = defScale;
 3316|    166|        }
 3317|     83|    }
 3318|       |
 3319|  2.72k|    bool ok = false;
 3320|       |
 3321|  2.72k|    const auto zero_epsilon = ai_epsilon;
 3322|       |
 3323|  2.72k|    const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
 3324|  2.72k|    if (ok && preRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (3324:9): [True: 2.57k, False: 147]
  |  Branch (3324:15): [True: 0, False: 2.57k]
  ------------------
 3325|      0|        const aiQuaternion preQuat = EulerToQuaternion(preRotation, Model::RotOrder_EulerXYZ);
 3326|      0|        for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3326:28): [True: 0, False: 0]
  ------------------
 3327|      0|            outRotations[i].mValue = preQuat * outRotations[i].mValue;
 3328|      0|        }
 3329|      0|    }
 3330|       |
 3331|  2.72k|    const aiVector3D& postRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok);
 3332|  2.72k|    if (ok && postRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (3332:9): [True: 2.56k, False: 159]
  |  Branch (3332:15): [True: 0, False: 2.56k]
  ------------------
 3333|      0|        const aiQuaternion postQuat = EulerToQuaternion(postRotation, Model::RotOrder_EulerXYZ);
 3334|      0|        for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3334:28): [True: 0, False: 0]
  ------------------
 3335|      0|            outRotations[i].mValue = outRotations[i].mValue * postQuat;
 3336|      0|        }
 3337|      0|    }
 3338|       |
 3339|       |    // convert TRS to SRT
 3340|  4.15M|    for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3340:24): [True: 4.14M, False: 2.72k]
  ------------------
 3341|  4.14M|        aiQuaternion& r = outRotations[i].mValue;
 3342|  4.14M|        aiVector3D& s = outScales[i].mValue;
 3343|  4.14M|        aiVector3D& t = outTranslations[i].mValue;
 3344|       |
 3345|  4.14M|        aiMatrix4x4 mat, temp;
 3346|  4.14M|        aiMatrix4x4::Translation(t, mat);
 3347|  4.14M|        mat *= aiMatrix4x4(r.GetMatrix());
 3348|  4.14M|        mat *= aiMatrix4x4::Scaling(s, temp);
 3349|       |
 3350|  4.14M|        mat.Decompose(s, r, t);
 3351|  4.14M|    }
 3352|       |
 3353|  2.72k|    na->mNumScalingKeys = static_cast<unsigned int>(keyCount);
 3354|  2.72k|    na->mNumRotationKeys = na->mNumScalingKeys;
 3355|  2.72k|    na->mNumPositionKeys = na->mNumScalingKeys;
 3356|       |
 3357|  2.72k|    na->mScalingKeys = outScales;
 3358|  2.72k|    na->mRotationKeys = outRotations;
 3359|  2.72k|    na->mPositionKeys = outTranslations;
 3360|       |
 3361|  2.72k|    return na.release();
 3362|  2.72k|}
_ZN6Assimp3FBX12FBXConverter15GetKeyframeListERKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS2_9allocatorIS6_EEEEll:
 3364|  6.25k|FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector<const AnimationCurveNode *> &nodes, int64_t start, int64_t stop) {
 3365|  6.25k|    KeyFrameListList inputs;
 3366|  6.25k|    inputs.reserve(nodes.size() * 3);
 3367|       |
 3368|       |    //give some breathing room for rounding errors
 3369|  6.25k|    int64_t adj_start = start - 10000;
 3370|  6.25k|    int64_t adj_stop = stop + 10000;
 3371|       |
 3372|  6.34k|    for (const AnimationCurveNode *node : nodes) {
  ------------------
  |  Branch (3372:41): [True: 6.34k, False: 6.25k]
  ------------------
 3373|  6.34k|        ai_assert(node);
 3374|       |
 3375|  6.34k|        const AnimationCurveMap &curves = node->Curves();
 3376|  18.4k|        for (const AnimationCurveMap::value_type &kv : curves) {
  ------------------
  |  Branch (3376:54): [True: 18.4k, False: 6.34k]
  ------------------
 3377|       |
 3378|  18.4k|            unsigned int mapto;
 3379|  18.4k|            if (kv.first == "d|X") {
  ------------------
  |  Branch (3379:17): [True: 6.08k, False: 12.3k]
  ------------------
 3380|  6.08k|                mapto = 0;
 3381|  12.3k|            } else if (kv.first == "d|Y") {
  ------------------
  |  Branch (3381:24): [True: 6.18k, False: 6.18k]
  ------------------
 3382|  6.18k|                mapto = 1;
 3383|  6.18k|            } else if (kv.first == "d|Z") {
  ------------------
  |  Branch (3383:24): [True: 6.14k, False: 49]
  ------------------
 3384|  6.14k|                mapto = 2;
 3385|  6.14k|            } else {
 3386|     49|                FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component");
 3387|     49|                continue;
 3388|     49|            }
 3389|       |
 3390|  18.4k|            const AnimationCurve *const curve = kv.second;
 3391|  18.4k|            ai_assert(curve->GetKeys().size() == curve->GetValues().size());
 3392|  18.4k|            ai_assert(curve->GetKeys().size());
 3393|       |
 3394|       |            //get values within the start/stop time window
 3395|  18.4k|            std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
 3396|  18.4k|            std::shared_ptr<KeyValueList> Values(new KeyValueList());
 3397|  18.4k|            const size_t count = curve->GetKeys().size();
 3398|  18.4k|            Keys->reserve(count);
 3399|  18.4k|            Values->reserve(count);
 3400|  55.2k|            for (size_t n = 0; n < count; n++) {
  ------------------
  |  Branch (3400:32): [True: 36.8k, False: 18.4k]
  ------------------
 3401|  36.8k|                int64_t k = curve->GetKeys().at(n);
 3402|  36.8k|                if (k >= adj_start && k <= adj_stop) {
  ------------------
  |  Branch (3402:21): [True: 34.3k, False: 2.44k]
  |  Branch (3402:39): [True: 34.2k, False: 144]
  ------------------
 3403|  34.2k|                    Keys->push_back(k);
 3404|  34.2k|                    Values->push_back(curve->GetValues().at(n));
 3405|  34.2k|                }
 3406|  36.8k|            }
 3407|       |
 3408|  18.4k|            inputs.emplace_back(Keys, Values, mapto);
 3409|  18.4k|        }
 3410|  6.34k|    }
 3411|  6.25k|    return inputs; // pray for NRVO :-)
 3412|  6.25k|}
_ZN6Assimp3FBX12FBXConverter23GetRotationKeyframeListERKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS2_9allocatorIS6_EEEEll:
 3415|  3.13k|                                                                     int64_t start, int64_t stop) {
 3416|  3.13k|    KeyFrameListList inputs;
 3417|  3.13k|    inputs.reserve(nodes.size() * 3);
 3418|       |
 3419|       |    // give some breathing room for rounding errors
 3420|  3.13k|    const int64_t adj_start = start - 10000;
 3421|  3.13k|    const int64_t adj_stop = stop + 10000;
 3422|       |
 3423|  3.17k|    for (const AnimationCurveNode *node : nodes) {
  ------------------
  |  Branch (3423:41): [True: 3.17k, False: 3.13k]
  ------------------
 3424|  3.17k|        ai_assert(node);
 3425|       |
 3426|  3.17k|        const AnimationCurveMap &curves = node->Curves();
 3427|  9.20k|        for (const AnimationCurveMap::value_type &kv : curves) {
  ------------------
  |  Branch (3427:54): [True: 9.20k, False: 3.17k]
  ------------------
 3428|       |
 3429|  9.20k|            unsigned int mapto;
 3430|  9.20k|            if (kv.first == "d|X") {
  ------------------
  |  Branch (3430:17): [True: 2.99k, False: 6.20k]
  ------------------
 3431|  2.99k|                mapto = 0;
 3432|  6.20k|            } else if (kv.first == "d|Y") {
  ------------------
  |  Branch (3432:24): [True: 3.04k, False: 3.15k]
  ------------------
 3433|  3.04k|                mapto = 1;
 3434|  3.15k|            } else if (kv.first == "d|Z") {
  ------------------
  |  Branch (3434:24): [True: 3.01k, False: 137]
  ------------------
 3435|  3.01k|                mapto = 2;
 3436|  3.01k|            } else {
 3437|    137|                FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component");
 3438|    137|                continue;
 3439|    137|            }
 3440|       |
 3441|  9.06k|            const AnimationCurve *const curve = kv.second;
 3442|  9.06k|            ai_assert(curve->GetKeys().size() == curve->GetValues().size());
 3443|  9.06k|            ai_assert(curve->GetKeys().size());
 3444|       |
 3445|       |            // get values within the start/stop time window
 3446|  9.06k|            std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
 3447|  9.06k|            std::shared_ptr<KeyValueList> Values(new KeyValueList());
 3448|  9.06k|            const size_t count = curve->GetKeys().size();
 3449|       |
 3450|  9.06k|            int64_t tp = curve->GetKeys().at(0);
 3451|  9.06k|            float vp = curve->GetValues().at(0);
 3452|  9.06k|            Keys->push_back(tp);
 3453|  9.06k|            Values->push_back(vp);
 3454|  9.06k|            if (count > 1) {
  ------------------
  |  Branch (3454:17): [True: 9.06k, False: 0]
  ------------------
 3455|  9.06k|                int64_t tc = curve->GetKeys().at(1);
 3456|  9.06k|                float vc = curve->GetValues().at(1);
 3457|  20.3k|                for (size_t n = 1; n < count; n++) {
  ------------------
  |  Branch (3457:36): [True: 11.2k, False: 9.06k]
  ------------------
 3458|  4.88M|                    while (std::abs(vc - vp) >= 180.0f) {
  ------------------
  |  Branch (3458:28): [True: 4.87M, False: 11.2k]
  ------------------
 3459|  4.87M|                        double step = std::floor(double(tc - tp) / std::abs(vc - vp) * 179.0f);
 3460|  4.87M|                        int64_t tnew = tp + int64_t(step);
 3461|  4.87M|                        float vnew = vp + (vc - vp) * float(step / (tc - tp));
 3462|  4.87M|                        if (tnew >= adj_start && tnew <= adj_stop) {
  ------------------
  |  Branch (3462:29): [True: 4.87M, False: 3]
  |  Branch (3462:50): [True: 4.87M, False: 1]
  ------------------
 3463|  4.87M|                            Keys->push_back(tnew);
 3464|  4.87M|                            Values->push_back(vnew);
 3465|  4.87M|                        } else {
 3466|       |                            // Something broke
 3467|      4|                            break;
 3468|      4|                        }
 3469|  4.87M|                        tp = tnew;
 3470|  4.87M|                        vp = vnew;
 3471|  4.87M|                    }
 3472|  11.2k|                    if (tc >= adj_start && tc <= adj_stop) {
  ------------------
  |  Branch (3472:25): [True: 10.9k, False: 279]
  |  Branch (3472:44): [True: 10.9k, False: 84]
  ------------------
 3473|  10.9k|                        Keys->push_back(tc);
 3474|  10.9k|                        Values->push_back(vc);
 3475|  10.9k|                    }
 3476|  11.2k|                    if (n + 1 < count) {
  ------------------
  |  Branch (3476:25): [True: 2.20k, False: 9.06k]
  ------------------
 3477|  2.20k|                        tp = tc;
 3478|  2.20k|                        vp = vc;
 3479|  2.20k|                        tc = curve->GetKeys().at(n + 1);
 3480|  2.20k|                        vc = curve->GetValues().at(n + 1);
 3481|  2.20k|                    }
 3482|  11.2k|                }
 3483|  9.06k|            }
 3484|  9.06k|            inputs.emplace_back(Keys, Values, mapto);
 3485|  9.06k|        }
 3486|  3.17k|    }
 3487|  3.13k|    return inputs;
 3488|  3.13k|}
_ZN6Assimp3FBX12FBXConverter14GetKeyTimeListERKNSt3__16vectorINS2_5tupleIJNS2_10shared_ptrINS3_IlNS2_9allocatorIlEEEEEENS5_INS3_IfNS6_IfEEEEEEjEEENS6_ISD_EEEE:
 3490|  1.44k|KeyTimeList FBXConverter::GetKeyTimeList(const KeyFrameListList &inputs) {
 3491|  1.44k|    ai_assert(!inputs.empty());
 3492|       |
 3493|       |    // reserve some space upfront - it is likely that the key-frame lists
 3494|       |    // have matching time values, so max(of all key-frame lists) should
 3495|       |    // be a good estimate.
 3496|  1.44k|    KeyTimeList keys;
 3497|       |
 3498|  1.44k|    size_t estimate = 0;
 3499|  4.08k|    for (const KeyFrameList &kfl : inputs) {
  ------------------
  |  Branch (3499:34): [True: 4.08k, False: 1.44k]
  ------------------
 3500|  4.08k|        estimate = std::max(estimate, std::get<0>(kfl)->size());
 3501|  4.08k|    }
 3502|       |
 3503|  1.44k|    keys.reserve(estimate);
 3504|       |
 3505|  1.44k|    std::vector<unsigned int> next_pos;
 3506|  1.44k|    next_pos.resize(inputs.size(), 0);
 3507|       |
 3508|  1.44k|    const size_t count = inputs.size();
 3509|   736k|    while (true) {
  ------------------
  |  Branch (3509:12): [True: 736k, Folded]
  ------------------
 3510|       |
 3511|   736k|        int64_t min_tick = std::numeric_limits<int64_t>::max();
 3512|  2.94M|        for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (3512:28): [True: 2.20M, False: 736k]
  ------------------
 3513|  2.20M|            const KeyFrameList &kfl = inputs[i];
 3514|       |
 3515|  2.20M|            if (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) < min_tick) {
  ------------------
  |  Branch (3515:17): [True: 2.20M, False: 4.13k]
  |  Branch (3515:59): [True: 1.03M, False: 1.16M]
  ------------------
 3516|  1.03M|                min_tick = std::get<0>(kfl)->at(next_pos[i]);
 3517|  1.03M|            }
 3518|  2.20M|        }
 3519|       |
 3520|   736k|        if (min_tick == std::numeric_limits<int64_t>::max()) {
  ------------------
  |  Branch (3520:13): [True: 1.44k, False: 735k]
  ------------------
 3521|  1.44k|            break;
 3522|  1.44k|        }
 3523|   735k|        keys.push_back(min_tick);
 3524|       |
 3525|  2.94M|        for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (3525:28): [True: 2.20M, False: 735k]
  ------------------
 3526|  2.20M|            const KeyFrameList &kfl = inputs[i];
 3527|       |
 3528|  2.94M|            while (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == min_tick) {
  ------------------
  |  Branch (3528:20): [True: 2.94M, False: 3.79k]
  |  Branch (3528:62): [True: 739k, False: 2.20M]
  ------------------
 3529|   739k|                ++next_pos[i];
 3530|   739k|            }
 3531|  2.20M|        }
 3532|   735k|    }
 3533|       |
 3534|  1.44k|    return keys;
 3535|  1.44k|}
_ZN6Assimp3FBX12FBXConverter15InterpolateKeysEP11aiVectorKeyRKNSt3__16vectorIlNS4_9allocatorIlEEEERKNS5_INS4_5tupleIJNS4_10shared_ptrIS8_EENSC_INS5_IfNS6_IfEEEEEEjEEENS6_ISH_EEEERK10aiVector3tIfERdSQ_:
 3540|  9.23k|        double &min_time) {
 3541|  9.23k|    ai_assert(!keys.empty());
 3542|  9.23k|    ai_assert(nullptr != valOut);
 3543|       |
 3544|  9.23k|    std::vector<unsigned int> next_pos;
 3545|  9.23k|    const size_t count(inputs.size());
 3546|       |
 3547|  9.23k|    next_pos.resize(inputs.size(), 0);
 3548|       |
 3549|  13.1M|    for (KeyTimeList::value_type time : keys) {
  ------------------
  |  Branch (3549:39): [True: 13.1M, False: 9.23k]
  ------------------
 3550|  13.1M|        ai_real result[3] = { def_value.x, def_value.y, def_value.z };
 3551|       |
 3552|  52.4M|        for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (3552:28): [True: 39.2M, False: 13.1M]
  ------------------
 3553|  39.2M|            const KeyFrameList &kfl = inputs[i];
 3554|       |
 3555|  39.2M|            const size_t ksize = std::get<0>(kfl)->size();
 3556|  39.2M|            if (ksize == 0) {
  ------------------
  |  Branch (3556:17): [True: 178, False: 39.2M]
  ------------------
 3557|    178|                continue;
 3558|    178|            }
 3559|  39.2M|            if (ksize > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == time) {
  ------------------
  |  Branch (3559:17): [True: 39.2M, False: 417]
  |  Branch (3559:40): [True: 4.92M, False: 34.2M]
  ------------------
 3560|  4.92M|                ++next_pos[i];
 3561|  4.92M|            }
 3562|       |
 3563|  39.2M|            const size_t id0 = next_pos[i] > 0 ? next_pos[i] - 1 : 0;
  ------------------
  |  Branch (3563:32): [True: 39.2M, False: 913]
  ------------------
 3564|  39.2M|            const size_t id1 = next_pos[i] == ksize ? ksize - 1 : next_pos[i];
  ------------------
  |  Branch (3564:32): [True: 27.3k, False: 39.1M]
  ------------------
 3565|       |
 3566|       |            // use lerp for interpolation
 3567|  39.2M|            const KeyValueList::value_type valueA = std::get<1>(kfl)->at(id0);
 3568|  39.2M|            const KeyValueList::value_type valueB = std::get<1>(kfl)->at(id1);
 3569|       |
 3570|  39.2M|            const KeyTimeList::value_type timeA = std::get<0>(kfl)->at(id0);
 3571|  39.2M|            const KeyTimeList::value_type timeB = std::get<0>(kfl)->at(id1);
 3572|       |
 3573|  39.2M|            const ai_real factor = timeB == timeA ? ai_real(0.) : static_cast<ai_real>((time - timeA)) / (timeB - timeA);
  ------------------
  |  Branch (3573:36): [True: 28.2k, False: 39.1M]
  ------------------
 3574|  39.2M|            const ai_real interpValue = static_cast<ai_real>(valueA + (valueB - valueA) * factor);
 3575|       |
 3576|  39.2M|            result[std::get<2>(kfl)] = interpValue;
 3577|  39.2M|        }
 3578|       |
 3579|       |        // magic value to convert fbx times to seconds
 3580|  13.1M|        valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps;
  ------------------
  |  |   77|  13.1M|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 3581|       |
 3582|  13.1M|        min_time = std::min(min_time, valOut->mTime);
 3583|  13.1M|        max_time = std::max(max_time, valOut->mTime);
 3584|       |
 3585|  13.1M|        valOut->mValue.x = result[0];
 3586|  13.1M|        valOut->mValue.y = result[1];
 3587|  13.1M|        valOut->mValue.z = result[2];
 3588|       |
 3589|  13.1M|        ++valOut;
 3590|  13.1M|    }
 3591|  9.23k|}
_ZN6Assimp3FBX12FBXConverter15InterpolateKeysEP9aiQuatKeyRKNSt3__16vectorIlNS4_9allocatorIlEEEERKNS5_INS4_5tupleIJNS4_10shared_ptrIS8_EENSC_INS5_IfNS6_IfEEEEEEjEEENS6_ISH_EEEERK10aiVector3tIfERdSQ_NS0_5Model8RotOrderE:
 3597|  3.12k|        Model::RotOrder order) {
 3598|  3.12k|    ai_assert(!keys.empty());
 3599|  3.12k|    ai_assert(nullptr != valOut);
 3600|       |
 3601|  3.12k|    std::unique_ptr<aiVectorKey[]> temp(new aiVectorKey[keys.size()]);
 3602|  3.12k|    InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime);
 3603|       |
 3604|  3.12k|    aiMatrix4x4 m;
 3605|       |
 3606|  3.12k|    aiQuaternion lastq;
 3607|       |
 3608|  4.88M|    for (size_t i = 0, c = keys.size(); i < c; ++i) {
  ------------------
  |  Branch (3608:41): [True: 4.88M, False: 3.12k]
  ------------------
 3609|       |
 3610|  4.88M|        valOut[i].mTime = temp[i].mTime;
 3611|       |
 3612|  4.88M|        GetRotationMatrix(order, temp[i].mValue, m);
 3613|  4.88M|        aiQuaternion quat = aiQuaternion(aiMatrix3x3(m));
 3614|       |
 3615|       |        // take shortest path by checking the inner product
 3616|       |        // http://www.3dkingdoms.com/weekly/weekly.php?a=36
 3617|  4.88M|        if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) {
  ------------------
  |  Branch (3617:13): [True: 2.43M, False: 2.44M]
  ------------------
 3618|  2.43M|            quat.Conjugate();
 3619|  2.43M|            quat.w = -quat.w;
 3620|  2.43M|        }
 3621|  4.88M|        lastq = quat;
 3622|       |
 3623|  4.88M|        valOut[i].mValue = quat;
 3624|  4.88M|    }
 3625|  3.12k|}
_ZN6Assimp3FBX12FBXConverter17EulerToQuaternionERK10aiVector3tIfENS0_5Model8RotOrderE:
 3627|     77|aiQuaternion FBXConverter::EulerToQuaternion(const aiVector3D &rot, Model::RotOrder order) {
 3628|     77|    aiMatrix4x4 m;
 3629|     77|    GetRotationMatrix(order, rot, m);
 3630|       |
 3631|     77|    return aiQuaternion(aiMatrix3x3(m));
 3632|     77|}
_ZN6Assimp3FBX12FBXConverter16ConvertScaleKeysEP10aiNodeAnimRKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS4_9allocatorIS8_EEEERKNS4_3mapIS8_PKNS0_14AnimationLayerENS4_4lessIS8_EENS9_INS4_4pairIKS8_SH_EEEEEEllRdSR_:
 3637|    462|        double &minTime) {
 3638|    462|    ai_assert(nodes.size());
 3639|       |
 3640|       |    // XXX for now, assume scale should be blended geometrically (i.e. two
 3641|       |    // layers should be multiplied with each other). There is a FBX
 3642|       |    // property in the layer to specify the behaviour, though.
 3643|       |
 3644|    462|    const KeyFrameListList &inputs = GetKeyframeList(nodes, start, stop);
 3645|    462|    const KeyTimeList &keys = GetKeyTimeList(inputs);
 3646|       |
 3647|    462|    na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
 3648|    462|    na->mScalingKeys = new aiVectorKey[keys.size()];
 3649|    462|    if (keys.size() > 0) {
  ------------------
  |  Branch (3649:9): [True: 406, False: 56]
  ------------------
 3650|    406|        InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime);
 3651|    406|    }
 3652|    462|}
_ZN6Assimp3FBX12FBXConverter22ConvertTranslationKeysEP10aiNodeAnimRKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS4_9allocatorIS8_EEEERKNS4_3mapIS8_PKNS0_14AnimationLayerENS4_4lessIS8_EENS9_INS4_4pairIKS8_SH_EEEEEEllRdSR_:
 3658|    494|        double &minTime) {
 3659|    494|    ai_assert(nodes.size());
 3660|       |
 3661|       |    // XXX see notes in ConvertScaleKeys()
 3662|    494|    const KeyFrameListList &inputs = GetKeyframeList(nodes, start, stop);
 3663|    494|    const KeyTimeList &keys = GetKeyTimeList(inputs);
 3664|       |
 3665|    494|    na->mNumPositionKeys = static_cast<unsigned int>(keys.size());
 3666|    494|    na->mPositionKeys = new aiVectorKey[keys.size()];
 3667|    494|    if (keys.size() > 0)
  ------------------
  |  Branch (3667:9): [True: 430, False: 64]
  ------------------
 3668|    430|        InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime);
 3669|    494|}
_ZN6Assimp3FBX12FBXConverter19ConvertRotationKeysEP10aiNodeAnimRKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS4_9allocatorIS8_EEEERKNS4_3mapIS8_PKNS0_14AnimationLayerENS4_4lessIS8_EENS9_INS4_4pairIKS8_SH_EEEEEEllRdSR_NS0_5Model8RotOrderE:
 3676|    490|        Model::RotOrder order) {
 3677|    490|    ai_assert(nodes.size());
 3678|       |
 3679|       |    // XXX see notes in ConvertScaleKeys()
 3680|    490|    const std::vector<KeyFrameList> &inputs = GetRotationKeyframeList(nodes, start, stop);
 3681|    490|    const KeyTimeList &keys = GetKeyTimeList(inputs);
 3682|       |
 3683|    490|    na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
 3684|    490|    na->mRotationKeys = new aiQuatKey[keys.size()];
 3685|    490|    if (!keys.empty()) {
  ------------------
  |  Branch (3685:9): [True: 490, False: 0]
  ------------------
 3686|    490|        InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order);
 3687|    490|    }
 3688|    490|}
_ZN6Assimp3FBX12FBXConverter21ConvertGlobalSettingsEv:
 3690|    227|void FBXConverter::ConvertGlobalSettings() {
 3691|    227|    if (nullptr == mSceneOut) {
  ------------------
  |  Branch (3691:9): [True: 0, False: 227]
  ------------------
 3692|      0|        return;
 3693|      0|    }
 3694|       |
 3695|    227|    const bool hasGenerator = !doc.Creator().empty();
 3696|       |
 3697|    227|    mSceneOut->mMetaData = aiMetadata::Alloc(16 + (hasGenerator ? 1 : 0));
  ------------------
  |  Branch (3697:52): [True: 217, False: 10]
  ------------------
 3698|    227|    mSceneOut->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis());
 3699|    227|    mSceneOut->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign());
 3700|    227|    mSceneOut->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis());
 3701|    227|    mSceneOut->mMetaData->Set(3, "FrontAxisSign", doc.GlobalSettings().FrontAxisSign());
 3702|    227|    mSceneOut->mMetaData->Set(4, "CoordAxis", doc.GlobalSettings().CoordAxis());
 3703|    227|    mSceneOut->mMetaData->Set(5, "CoordAxisSign", doc.GlobalSettings().CoordAxisSign());
 3704|    227|    mSceneOut->mMetaData->Set(6, "OriginalUpAxis", doc.GlobalSettings().OriginalUpAxis());
 3705|    227|    mSceneOut->mMetaData->Set(7, "OriginalUpAxisSign", doc.GlobalSettings().OriginalUpAxisSign());
 3706|       |    //const double unitScaleFactor = (double)doc.GlobalSettings().UnitScaleFactor();
 3707|    227|    mSceneOut->mMetaData->Set(8, "UnitScaleFactor", doc.GlobalSettings().UnitScaleFactor());
 3708|    227|    mSceneOut->mMetaData->Set(9, "OriginalUnitScaleFactor", doc.GlobalSettings().OriginalUnitScaleFactor());
 3709|    227|    mSceneOut->mMetaData->Set(10, "AmbientColor", doc.GlobalSettings().AmbientColor());
 3710|    227|    mSceneOut->mMetaData->Set(11, "FrameRate", (int)doc.GlobalSettings().TimeMode());
 3711|    227|    mSceneOut->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart());
 3712|    227|    mSceneOut->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop());
 3713|    227|    mSceneOut->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate());
 3714|    227|    mSceneOut->mMetaData->Set(15, AI_METADATA_SOURCE_FORMAT_VERSION, aiString(ai_to_string(doc.FBXVersion())));
 3715|    227|    if (hasGenerator) {
  ------------------
  |  Branch (3715:9): [True: 217, False: 10]
  ------------------
 3716|       |        mSceneOut->mMetaData->Set(16, AI_METADATA_SOURCE_GENERATOR, aiString(doc.Creator()));
 3717|    217|    }
 3718|    227|}
_ZN6Assimp3FBX12FBXConverter19TransferDataToSceneEv:
 3720|    227|void FBXConverter::TransferDataToScene() {
 3721|    227|    ai_assert(!mSceneOut->mMeshes);
 3722|    227|    ai_assert(!mSceneOut->mNumMeshes);
 3723|       |
 3724|       |    // note: the trailing () ensures initialization with nullptr - not
 3725|       |    // many C++ users seem to know this, so pointing it out to avoid
 3726|       |    // confusion why this code works.
 3727|       |
 3728|    227|    if (!mMeshes.empty()) {
  ------------------
  |  Branch (3728:9): [True: 92, False: 135]
  ------------------
 3729|     92|        mSceneOut->mMeshes = new aiMesh *[mMeshes.size()]();
 3730|     92|        mSceneOut->mNumMeshes = static_cast<unsigned int>(mMeshes.size());
 3731|       |
 3732|     92|        std::swap_ranges(mMeshes.begin(), mMeshes.end(), mSceneOut->mMeshes);
 3733|     92|    }
 3734|       |
 3735|    227|    if (!materials.empty()) {
  ------------------
  |  Branch (3735:9): [True: 92, False: 135]
  ------------------
 3736|     92|        mSceneOut->mMaterials = new aiMaterial *[materials.size()]();
 3737|     92|        mSceneOut->mNumMaterials = static_cast<unsigned int>(materials.size());
 3738|       |
 3739|     92|        std::swap_ranges(materials.begin(), materials.end(), mSceneOut->mMaterials);
 3740|     92|    }
 3741|       |
 3742|    227|    if (!animations.empty()) {
  ------------------
  |  Branch (3742:9): [True: 208, False: 19]
  ------------------
 3743|    208|        mSceneOut->mAnimations = new aiAnimation *[animations.size()]();
 3744|    208|        mSceneOut->mNumAnimations = static_cast<unsigned int>(animations.size());
 3745|       |
 3746|    208|        std::swap_ranges(animations.begin(), animations.end(), mSceneOut->mAnimations);
 3747|    208|    }
 3748|       |
 3749|    227|    if (!lights.empty()) {
  ------------------
  |  Branch (3749:9): [True: 198, False: 29]
  ------------------
 3750|    198|        mSceneOut->mLights = new aiLight *[lights.size()]();
 3751|    198|        mSceneOut->mNumLights = static_cast<unsigned int>(lights.size());
 3752|       |
 3753|    198|        std::swap_ranges(lights.begin(), lights.end(), mSceneOut->mLights);
 3754|    198|    }
 3755|       |
 3756|    227|    if (!cameras.empty()) {
  ------------------
  |  Branch (3756:9): [True: 206, False: 21]
  ------------------
 3757|    206|        mSceneOut->mCameras = new aiCamera *[cameras.size()]();
 3758|    206|        mSceneOut->mNumCameras = static_cast<unsigned int>(cameras.size());
 3759|       |
 3760|    206|        std::swap_ranges(cameras.begin(), cameras.end(), mSceneOut->mCameras);
 3761|    206|    }
 3762|       |
 3763|    227|    if (!textures.empty()) {
  ------------------
  |  Branch (3763:9): [True: 1, False: 226]
  ------------------
 3764|      1|        mSceneOut->mTextures = new aiTexture *[textures.size()]();
 3765|      1|        mSceneOut->mNumTextures = static_cast<unsigned int>(textures.size());
 3766|       |
 3767|      1|        std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures);
 3768|      1|    }
 3769|       |
 3770|    227|    if (!mSkeletons.empty()) {
  ------------------
  |  Branch (3770:9): [True: 0, False: 227]
  ------------------
 3771|      0|        mSceneOut->mSkeletons = new aiSkeleton *[mSkeletons.size()];
 3772|      0|        mSceneOut->mNumSkeletons = static_cast<unsigned int>(mSkeletons.size());
 3773|      0|        std::swap_ranges(mSkeletons.begin(), mSkeletons.end(), mSceneOut->mSkeletons);
 3774|      0|    }
 3775|    227|}
_ZN6Assimp3FBX12FBXConverter31ConvertOrphanedEmbeddedTexturesEv:
 3777|    249|void FBXConverter::ConvertOrphanedEmbeddedTextures() {
 3778|       |    // in C++14 it could be:
 3779|       |    // for (auto&& [id, object] : objects)
 3780|  55.3k|    for (auto &&id_and_object : doc.Objects()) {
  ------------------
  |  Branch (3780:31): [True: 55.3k, False: 249]
  ------------------
 3781|  55.3k|        auto &&id = std::get<0>(id_and_object);
 3782|  55.3k|        auto &&object = std::get<1>(id_and_object);
 3783|       |        // If an object doesn't have parent
 3784|  55.3k|        if (doc.ConnectionsBySource().count(id) == 0) {
  ------------------
  |  Branch (3784:13): [True: 2.31k, False: 52.9k]
  ------------------
 3785|  2.31k|            const Texture *realTexture = nullptr;
 3786|  2.31k|            try {
 3787|  2.31k|                const auto &element = object->GetElement();
 3788|  2.31k|                const Token &key = element.KeyToken();
 3789|  2.31k|                const char *obtype = key.begin();
 3790|  2.31k|                const size_t length = static_cast<size_t>(key.end() - key.begin());
 3791|  2.31k|                if (strncmp(obtype, "Texture", length) == 0) {
  ------------------
  |  Branch (3791:21): [True: 3, False: 2.31k]
  ------------------
 3792|      3|                    if (const Texture *texture = static_cast<const Texture *>(object->Get())) {
  ------------------
  |  Branch (3792:40): [True: 3, False: 0]
  ------------------
 3793|      3|                        if (texture->Media() && texture->Media()->ContentLength() > 0) {
  ------------------
  |  Branch (3793:29): [True: 3, False: 0]
  |  Branch (3793:49): [True: 0, False: 3]
  ------------------
 3794|      0|                            realTexture = texture;
 3795|      0|                        }
 3796|      3|                    }
 3797|      3|                }
 3798|  2.31k|            } catch (...) {
 3799|       |                // do nothing
 3800|      0|            }
 3801|  2.31k|            if (realTexture) {
  ------------------
  |  Branch (3801:17): [True: 0, False: 2.31k]
  ------------------
 3802|      0|                const Video *media = realTexture->Media();
 3803|      0|                unsigned int index = ConvertVideo(*media);
 3804|      0|                textures_converted[media] = index;
 3805|      0|            }
 3806|  2.31k|        }
 3807|  55.3k|    }
 3808|    249|}
_ZN6Assimp3FBX20ConvertToAssimpSceneEP7aiSceneRKNS0_8DocumentEb:
 3811|    271|void ConvertToAssimpScene(aiScene *out, const Document &doc, bool removeEmptyBones) {
 3812|    271|    FBXConverter converter(out, doc, removeEmptyBones);
 3813|    271|}
FBXConverter.cpp:_ZN6Assimp3FBXL20correctRootTransformEPK7aiScene:
   79|     92|static void correctRootTransform(const aiScene *scene) {
   80|     92|    if (scene == nullptr) {
  ------------------
  |  Branch (80:9): [True: 0, False: 92]
  ------------------
   81|      0|        return;
   82|      0|    }
   83|       |
   84|     92|    if (scene->mMetaData == nullptr) {
  ------------------
  |  Branch (84:9): [True: 0, False: 92]
  ------------------
   85|      0|        return;
   86|      0|    }
   87|       |
   88|     92|    int32_t UpAxis = 1, UpAxisSign = 1, FrontAxis = 2, FrontAxisSign = 1, CoordAxis = 0, CoordAxisSign = 1;
   89|     92|    double UnitScaleFactor = 1.0;
   90|  1.65k|    for (unsigned MetadataIndex = 0; MetadataIndex < scene->mMetaData->mNumProperties; ++MetadataIndex) {
  ------------------
  |  Branch (90:38): [True: 1.56k, False: 92]
  ------------------
   91|  1.56k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UpAxis") == 0) {
  ------------------
  |  Branch (91:13): [True: 92, False: 1.46k]
  ------------------
   92|     92|            scene->mMetaData->Get<int32_t>(MetadataIndex, UpAxis);
   93|     92|        }
   94|  1.56k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UpAxisSign") == 0) {
  ------------------
  |  Branch (94:13): [True: 92, False: 1.46k]
  ------------------
   95|     92|            scene->mMetaData->Get<int32_t>(MetadataIndex, UpAxisSign);
   96|     92|        }
   97|  1.56k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "FrontAxis") == 0) {
  ------------------
  |  Branch (97:13): [True: 92, False: 1.46k]
  ------------------
   98|     92|            scene->mMetaData->Get<int32_t>(MetadataIndex, FrontAxis);
   99|     92|        }
  100|  1.56k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "FrontAxisSign") == 0) {
  ------------------
  |  Branch (100:13): [True: 92, False: 1.46k]
  ------------------
  101|     92|            scene->mMetaData->Get<int32_t>(MetadataIndex, FrontAxisSign);
  102|     92|        }
  103|  1.56k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "CoordAxis") == 0) {
  ------------------
  |  Branch (103:13): [True: 92, False: 1.46k]
  ------------------
  104|     92|            scene->mMetaData->Get<int32_t>(MetadataIndex, CoordAxis);
  105|     92|        }
  106|  1.56k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "CoordAxisSign") == 0) {
  ------------------
  |  Branch (106:13): [True: 92, False: 1.46k]
  ------------------
  107|     92|            scene->mMetaData->Get<int32_t>(MetadataIndex, CoordAxisSign);
  108|     92|        }
  109|  1.56k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UnitScaleFactor") == 0) {
  ------------------
  |  Branch (109:13): [True: 92, False: 1.46k]
  ------------------
  110|     92|            scene->mMetaData->Get<double>(MetadataIndex, UnitScaleFactor);
  111|     92|        }
  112|  1.56k|    }
  113|       |
  114|     92|    aiVector3D upVec, forwardVec, rightVec;
  115|     92|    upVec[UpAxis] = UpAxisSign * static_cast<float>(UnitScaleFactor);
  116|     92|    forwardVec[FrontAxis] = FrontAxisSign * static_cast<float>(UnitScaleFactor);
  117|     92|    rightVec[CoordAxis] = CoordAxisSign * (float)UnitScaleFactor;
  118|       |
  119|     92|    aiMatrix4x4 mat(rightVec.x, rightVec.y, rightVec.z, 0.0f,
  120|     92|                    upVec.x, upVec.y, upVec.z, 0.0f,
  121|     92|                    forwardVec.x, forwardVec.y, forwardVec.z, 0.0f,
  122|     92|                    0.0f, 0.0f, 0.0f, 1.0f);
  123|     92|    scene->mRootNode->mTransformation *= mat;
  124|     92|}
_ZN6Assimp3FBX12FBXConverter13PotentialNodeptEv:
  241|   106k|    aiNode* operator->() { return mNode; }
_ZN6Assimp3FBX12FBXConverter13PotentialNodeC2Ev:
  239|  4.77k|    PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
FBXConverter.cpp:_ZN6Assimp3FBXL22validateAnimCurveNodesERKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS1_9allocatorIS5_EEEEb:
 2863|  3.26k|        bool strictMode) {
 2864|  3.26k|    const Object *target(nullptr);
 2865|  9.53k|    for (const AnimationCurveNode *node : curves) {
  ------------------
  |  Branch (2865:41): [True: 9.53k, False: 3.26k]
  ------------------
 2866|  9.53k|        if (!target) {
  ------------------
  |  Branch (2866:13): [True: 3.26k, False: 6.27k]
  ------------------
 2867|  3.26k|            target = node->Target();
 2868|  3.26k|        }
 2869|  9.53k|        if (node->Target() != target) {
  ------------------
  |  Branch (2869:13): [True: 150, False: 9.38k]
  ------------------
 2870|    150|            FBXImporter::LogWarn("Node target is nullptr type.");
 2871|    150|        }
 2872|  9.53k|        if (strictMode) {
  ------------------
  |  Branch (2872:13): [True: 0, False: 9.53k]
  ------------------
 2873|       |            ai_assert(node->Target() == target);
 2874|      0|        }
 2875|  9.53k|    }
 2876|  3.26k|}
_ZN6Assimp3FBX12FBXConverter13PotentialNodeC2ERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  240|    356|    explicit PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}

_ZN6Assimp3FBX8DeformerC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   63|  3.13k|        Object(id,element,name) {
   64|  3.13k|    const Scope& sc = GetRequiredScope(element);
   65|       |
   66|  3.13k|    const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
   67|  3.13k|    props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
   68|  3.13k|}
_ZN6Assimp3FBX7ClusterC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   72|  2.92k|: Deformer(id,element,doc,name)
   73|       |, node()
   74|  2.92k|{
   75|  2.92k|    const Scope& sc = GetRequiredScope(element);
   76|       |
   77|  2.92k|    const Element* const Indexes = sc["Indexes"];
   78|  2.92k|    const Element* const Weights = sc["Weights"];
   79|       |
   80|  2.92k|    const Element& Transform = GetRequiredElement(sc,"Transform",&element);
   81|  2.92k|    const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&element);
   82|       |
   83|  2.92k|    transform = ReadMatrix(Transform);
   84|  2.92k|    transformLink = ReadMatrix(TransformLink);
   85|       |
   86|       |    // it is actually possible that there are Deformer's with no weights
   87|  2.92k|    if (!!Indexes != !!Weights) {
  ------------------
  |  Branch (87:9): [True: 14, False: 2.90k]
  ------------------
   88|     14|        DOMError("either Indexes or Weights are missing from Cluster",&element);
   89|     14|    }
   90|       |
   91|  2.90k|    if(Indexes) {
  ------------------
  |  Branch (91:8): [True: 2.86k, False: 40]
  ------------------
   92|  2.86k|        ParseVectorDataArray(indices,*Indexes);
   93|  2.86k|        ParseVectorDataArray(weights,*Weights);
   94|  2.86k|    }
   95|       |
   96|  2.90k|    if(indices.size() != weights.size()) {
  ------------------
  |  Branch (96:8): [True: 6, False: 2.90k]
  ------------------
   97|      6|        DOMError("sizes of index and weight array don't match up",&element);
   98|      6|    }
   99|       |
  100|       |    // read assigned node
  101|  2.90k|    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model");
  102|  2.90k|    for(const Connection* con : conns) {
  ------------------
  |  Branch (102:31): [True: 1.32k, False: 1.57k]
  ------------------
  103|  1.32k|        const Model* const mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element);
  104|  1.32k|        if(mod) {
  ------------------
  |  Branch (104:12): [True: 1.32k, False: 1]
  ------------------
  105|  1.32k|            node = mod;
  106|  1.32k|            break;
  107|  1.32k|        }
  108|  1.32k|    }
  109|       |
  110|  2.90k|    if (!node) {
  ------------------
  |  Branch (110:9): [True: 29, False: 2.87k]
  ------------------
  111|     29|        DOMError("failed to read target Node for Cluster",&element);
  112|     29|    }
  113|  2.90k|}
_ZN6Assimp3FBX4SkinC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  117|    215|: Deformer(id,element,doc,name)
  118|    215|, accuracy( 0.0f ) {
  119|    215|    const Scope& sc = GetRequiredScope(element);
  120|       |
  121|    215|    const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"];
  122|    215|    if(Link_DeformAcuracy) {
  ------------------
  |  Branch (122:8): [True: 215, False: 0]
  ------------------
  123|    215|        accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0));
  124|    215|    }
  125|       |
  126|       |    // resolve assigned clusters
  127|    215|    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
  128|       |
  129|    215|    clusters.reserve(conns.size());
  130|  2.92k|    for(const Connection* con : conns) {
  ------------------
  |  Branch (130:31): [True: 2.92k, False: 215]
  ------------------
  131|       |
  132|  2.92k|        const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element);
  133|  2.92k|        if(cluster) {
  ------------------
  |  Branch (133:12): [True: 1.32k, False: 1.59k]
  ------------------
  134|  1.32k|            clusters.push_back(cluster);
  135|  1.32k|            continue;
  136|  1.32k|        }
  137|  2.92k|    }
  138|    215|}

_ZN6Assimp3FBX10LazyObjectC2EmRKNS0_7ElementERKNS0_8DocumentE:
   71|  60.6k|        doc(doc), element(element), id(id), flags() {
   72|       |    // empty
   73|  60.6k|}
_ZN6Assimp3FBX10LazyObject3GetEb:
   76|   135k|const Object* LazyObject::Get(bool dieOnError) {
   77|   135k|    if(IsBeingConstructed() || FailedToConstruct()) {
  ------------------
  |  Branch (77:8): [True: 68.9k, False: 66.4k]
  |  Branch (77:32): [True: 6, False: 66.4k]
  ------------------
   78|  68.9k|        return nullptr;
   79|  68.9k|    }
   80|       |
   81|  66.4k|    if (object) {
  ------------------
  |  Branch (81:9): [True: 14.5k, False: 51.9k]
  ------------------
   82|  14.5k|        return object.get();
   83|  14.5k|    }
   84|       |
   85|  51.9k|    const Token& key = element.KeyToken();
   86|  51.9k|    const TokenList& tokens = element.Tokens();
   87|       |
   88|  51.9k|    if(tokens.size() < 3) {
  ------------------
  |  Branch (88:8): [True: 0, False: 51.9k]
  ------------------
   89|      0|        DOMError("expected at least 3 tokens: id, name and class tag",&element);
   90|      0|    }
   91|       |
   92|  51.9k|    const char* err;
   93|  51.9k|    std::string name = ParseTokenAsString(*tokens[1],err);
   94|  51.9k|    if (err) {
  ------------------
  |  Branch (94:9): [True: 8, False: 51.9k]
  ------------------
   95|      8|        DOMError(err,&element);
   96|      8|    }
   97|       |
   98|       |    // small fix for binary reading: binary fbx files don't use
   99|       |    // prefixes such as Model:: in front of their names. The
  100|       |    // loading code expects this at many places, though!
  101|       |    // so convert the binary representation (a 0x0001) to the
  102|       |    // double colon notation.
  103|  51.9k|    if(tokens[1]->IsBinary()) {
  ------------------
  |  Branch (103:8): [True: 51.8k, False: 93]
  ------------------
  104|   790k|        for (size_t i = 0; i < name.length(); ++i) {
  ------------------
  |  Branch (104:28): [True: 738k, False: 51.8k]
  ------------------
  105|   738k|            if (name[i] == 0x0 && name[i+1] == 0x1) {
  ------------------
  |  Branch (105:17): [True: 51.8k, False: 686k]
  |  Branch (105:35): [True: 51.7k, False: 60]
  ------------------
  106|  51.7k|                name = name.substr(i+2) + "::" + name.substr(0,i);
  107|  51.7k|            }
  108|   738k|        }
  109|  51.8k|    }
  110|       |
  111|  51.9k|    const std::string classtag = ParseTokenAsString(*tokens[2],err);
  112|  51.9k|    if (err) {
  ------------------
  |  Branch (112:9): [True: 5, False: 51.9k]
  ------------------
  113|      5|        DOMError(err,&element);
  114|      5|    }
  115|       |
  116|       |    // prevent recursive calls
  117|  51.9k|    flags |= BEING_CONSTRUCTED;
  118|       |
  119|  51.9k|    try {
  120|       |        // this needs to be relatively fast since it happens a lot,
  121|       |        // so avoid constructing strings all the time.
  122|  51.9k|        const char* obtype = key.begin();
  123|  51.9k|        const size_t length = static_cast<size_t>(key.end()-key.begin());
  124|       |
  125|       |        // For debugging
  126|       |        //dumpObjectClassInfo( objtype, classtag );
  127|       |
  128|  51.9k|        if (!strncmp(obtype,"Geometry",length)) {
  ------------------
  |  Branch (128:13): [True: 243, False: 51.6k]
  ------------------
  129|    243|            if (!strcmp(classtag.c_str(),"Mesh")) {
  ------------------
  |  Branch (129:17): [True: 243, False: 0]
  ------------------
  130|    243|                object.reset(new MeshGeometry(id,element,name,doc));
  131|    243|            }
  132|    243|            if (!strcmp(classtag.c_str(), "Shape")) {
  ------------------
  |  Branch (132:17): [True: 0, False: 243]
  ------------------
  133|      0|                object.reset(new ShapeGeometry(id, element, name, doc));
  134|      0|            }
  135|    243|            if (!strcmp(classtag.c_str(), "Line")) {
  ------------------
  |  Branch (135:17): [True: 0, False: 243]
  ------------------
  136|      0|                object.reset(new LineGeometry(id, element, name, doc));
  137|      0|            }
  138|    243|        }
  139|  51.6k|        else if (!strncmp(obtype,"NodeAttribute",length)) {
  ------------------
  |  Branch (139:18): [True: 4.31k, False: 47.3k]
  ------------------
  140|  4.31k|            if (!strcmp(classtag.c_str(),"Camera")) {
  ------------------
  |  Branch (140:17): [True: 243, False: 4.07k]
  ------------------
  141|    243|                object.reset(new Camera(id,element,doc,name));
  142|    243|            }
  143|  4.07k|            else if (!strcmp(classtag.c_str(),"CameraSwitcher")) {
  ------------------
  |  Branch (143:22): [True: 0, False: 4.07k]
  ------------------
  144|      0|                object.reset(new CameraSwitcher(id,element,doc,name));
  145|      0|            }
  146|  4.07k|            else if (!strcmp(classtag.c_str(),"Light")) {
  ------------------
  |  Branch (146:22): [True: 215, False: 3.85k]
  ------------------
  147|    215|                object.reset(new Light(id,element,doc,name));
  148|    215|            }
  149|  3.85k|            else if (!strcmp(classtag.c_str(),"Null")) {
  ------------------
  |  Branch (149:22): [True: 219, False: 3.64k]
  ------------------
  150|    219|                object.reset(new Null(id,element,doc,name));
  151|    219|            }
  152|  3.64k|            else if (!strcmp(classtag.c_str(),"LimbNode")) {
  ------------------
  |  Branch (152:22): [True: 3.60k, False: 38]
  ------------------
  153|  3.60k|                object.reset(new LimbNode(id,element,doc,name));
  154|  3.60k|            }
  155|  4.31k|        }
  156|  47.3k|        else if (!strncmp(obtype,"Deformer",length)) {
  ------------------
  |  Branch (156:18): [True: 3.13k, False: 44.2k]
  ------------------
  157|  3.13k|            if (!strcmp(classtag.c_str(),"Cluster")) {
  ------------------
  |  Branch (157:17): [True: 2.92k, False: 218]
  ------------------
  158|  2.92k|                object.reset(new Cluster(id,element,doc,name));
  159|  2.92k|            }
  160|    218|            else if (!strcmp(classtag.c_str(),"Skin")) {
  ------------------
  |  Branch (160:22): [True: 215, False: 3]
  ------------------
  161|    215|                object.reset(new Skin(id,element,doc,name));
  162|    215|            }
  163|      3|            else if (!strcmp(classtag.c_str(), "BlendShape")) {
  ------------------
  |  Branch (163:22): [True: 0, False: 3]
  ------------------
  164|      0|                object.reset(new BlendShape(id, element, doc, name));
  165|      0|            }
  166|      3|            else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) {
  ------------------
  |  Branch (166:22): [True: 0, False: 3]
  ------------------
  167|      0|                object.reset(new BlendShapeChannel(id, element, doc, name));
  168|      0|            }
  169|  3.13k|        }
  170|  44.2k|        else if ( !strncmp( obtype, "Model", length ) ) {
  ------------------
  |  Branch (170:19): [True: 4.60k, False: 39.6k]
  ------------------
  171|       |            // FK and IK effectors are not supported
  172|  4.60k|            if ( strcmp( classtag.c_str(), "IKEffector" ) && strcmp( classtag.c_str(), "FKEffector" ) ) {
  ------------------
  |  Branch (172:18): [True: 4.60k, False: 0]
  |  Branch (172:62): [True: 4.60k, False: 0]
  ------------------
  173|  4.60k|                object.reset( new Model( id, element, doc, name ) );
  174|  4.60k|            }
  175|  4.60k|        }
  176|  39.6k|        else if (!strncmp(obtype,"Material",length)) {
  ------------------
  |  Branch (176:18): [True: 231, False: 39.4k]
  ------------------
  177|    231|            object.reset(new Material(id,element,doc,name));
  178|    231|        }
  179|  39.4k|        else if (!strncmp(obtype,"Texture",length)) {
  ------------------
  |  Branch (179:18): [True: 11, False: 39.3k]
  ------------------
  180|     11|            object.reset(new Texture(id,element,doc,name));
  181|     11|        }
  182|  39.3k|        else if (!strncmp(obtype,"LayeredTexture",length)) {
  ------------------
  |  Branch (182:18): [True: 1, False: 39.3k]
  ------------------
  183|      1|            object.reset(new LayeredTexture(id,element,doc,name));
  184|      1|        }
  185|  39.3k|        else if (!strncmp(obtype,"Video",length)) {
  ------------------
  |  Branch (185:18): [True: 10, False: 39.3k]
  ------------------
  186|     10|            object.reset(new Video(id,element,doc,name));
  187|     10|        }
  188|  39.3k|        else if (!strncmp(obtype,"AnimationStack",length)) {
  ------------------
  |  Branch (188:18): [True: 256, False: 39.1k]
  ------------------
  189|    256|            object.reset(new AnimationStack(id,element,name,doc));
  190|    256|        }
  191|  39.1k|        else if (!strncmp(obtype,"AnimationLayer",length)) {
  ------------------
  |  Branch (191:18): [True: 250, False: 38.8k]
  ------------------
  192|    250|            object.reset(new AnimationLayer(id,element,name,doc));
  193|    250|        }
  194|       |        // note: order matters for these two
  195|  38.8k|        else if (!strncmp(obtype,"AnimationCurve",length)) {
  ------------------
  |  Branch (195:18): [True: 28.0k, False: 10.8k]
  ------------------
  196|  28.0k|            object.reset(new AnimationCurve(id,element,name,doc));
  197|  28.0k|        }
  198|  10.8k|        else if (!strncmp(obtype,"AnimationCurveNode",length)) {
  ------------------
  |  Branch (198:18): [True: 10.8k, False: 0]
  ------------------
  199|  10.8k|            object.reset(new AnimationCurveNode(id,element,name,doc));
  200|  10.8k|        }
  201|  51.9k|    }
  202|  51.9k|    catch (std::bad_alloc&) {
  203|       |        // out-of-memory is unrecoverable and should always lead to a failure
  204|       |
  205|      0|        flags &= ~BEING_CONSTRUCTED;
  206|      0|        flags |= FAILED_TO_CONSTRUCT;
  207|       |
  208|      0|        throw;
  209|      0|    }
  210|  51.9k|    catch(std::exception& ex) {
  211|  2.11k|        flags &= ~BEING_CONSTRUCTED;
  212|  2.11k|        flags |= FAILED_TO_CONSTRUCT;
  213|       |
  214|  2.11k|        if(dieOnError || doc.Settings().strictMode) {
  ------------------
  |  Branch (214:12): [True: 0, False: 2.11k]
  |  Branch (214:26): [True: 0, False: 2.11k]
  ------------------
  215|      0|            throw;
  216|      0|        }
  217|       |
  218|       |        // note: the error message is already formatted, so raw logging is ok
  219|  2.11k|        if(!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (219:12): [True: 0, False: 2.11k]
  ------------------
  220|      0|            ASSIMP_LOG_ERROR(ex.what());
  221|      0|        }
  222|  2.11k|        return nullptr;
  223|  2.11k|    }
  224|       |
  225|  49.8k|    if (!object) {
  ------------------
  |  Branch (225:9): [True: 41, False: 49.7k]
  ------------------
  226|       |        //DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
  227|     41|    }
  228|       |
  229|  49.8k|    flags &= ~BEING_CONSTRUCTED;
  230|  49.8k|    return object.get();
  231|  51.9k|}
_ZN6Assimp3FBX6ObjectC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  235|  51.8k|        element(element), name(name), id(id) {
  236|       |    // empty
  237|  51.8k|}
_ZN6Assimp3FBX18FileGlobalSettingsC2ERKNS0_8DocumentENSt3__110shared_ptrIKNS0_13PropertyTableEEE:
  241|    278|        props(std::move(props)), doc(doc) {
  242|       |    // empty
  243|    278|}
_ZN6Assimp3FBX8DocumentC2ERNS0_6ParserERKNS0_14ImportSettingsE:
  247|    282|     settings(settings), parser(parser) {
  248|    282|	ASSIMP_LOG_DEBUG("Creating FBX Document");
  249|       |
  250|       |    // Cannot use array default initialization syntax because vc8 fails on it
  251|  1.97k|    for (auto &timeStamp : creationTimeStamp) {
  ------------------
  |  Branch (251:26): [True: 1.97k, False: 282]
  ------------------
  252|  1.97k|        timeStamp = 0;
  253|  1.97k|    }
  254|       |
  255|    282|    ReadHeader();
  256|    282|    ReadPropertyTemplates();
  257|       |
  258|    282|    ReadGlobalSettings();
  259|       |
  260|       |    // This order is important, connections need parsed objects to check
  261|       |    // whether connections are ok or not. Objects may not be evaluated yet,
  262|       |    // though, since this may require valid connections.
  263|    282|    ReadObjects();
  264|    282|    ReadConnections();
  265|    282|}
_ZN6Assimp3FBX8DocumentD2Ev:
  269|    271|{
  270|       |	// The document does not own the memory for the following objects, but we need to call their d'tor
  271|       |	// so they can properly free memory like string members:
  272|       |
  273|  60.6k|    for (ObjectMap::value_type &v : objects) {
  ------------------
  |  Branch (273:35): [True: 60.6k, False: 271]
  ------------------
  274|  60.6k|        delete_LazyObject(v.second);
  ------------------
  |  |   91|  60.6k|#define delete_LazyObject(_p) (_p)->~LazyObject()
  ------------------
  275|  60.6k|    }
  276|       |
  277|  76.2k|    for (ConnectionMap::value_type &v : src_connections) {
  ------------------
  |  Branch (277:39): [True: 76.2k, False: 271]
  ------------------
  278|  76.2k|        delete_Connection(v.second);
  ------------------
  |  |   92|  76.2k|#define delete_Connection(_p) (_p)->~Connection()
  ------------------
  279|  76.2k|    }
  280|       |    // |dest_connections| contain the same Connection objects as the |src_connections|
  281|    271|}
_ZN6Assimp3FBX8Document10ReadHeaderEv:
  287|    282|void Document::ReadHeader() {
  288|       |    // Read ID objects from "Objects" section
  289|    282|    const Scope& sc = parser.GetRootScope();
  290|    282|    const Element* const ehead = sc["FBXHeaderExtension"];
  291|    282|    if(!ehead || !ehead->Compound()) {
  ------------------
  |  Branch (291:8): [True: 3, False: 279]
  |  Branch (291:18): [True: 0, False: 279]
  ------------------
  292|      3|        DOMError("no FBXHeaderExtension dictionary found");
  293|      3|    }
  294|       |
  295|    279|    const Scope& shead = *ehead->Compound();
  296|    279|    fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
  297|    279|	ASSIMP_LOG_DEBUG("FBX Version: ", fbxVersion);
  298|       |
  299|       |    // While we may have some success with newer files, we don't support
  300|       |    // the older 6.n fbx format
  301|    279|    if(fbxVersion < LowerSupportedVersion ) {
  ------------------
  |  Branch (301:8): [True: 0, False: 279]
  ------------------
  302|      0|        DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");
  303|      0|    }
  304|    279|    if(fbxVersion > UpperSupportedVersion ) {
  ------------------
  |  Branch (304:8): [True: 26, False: 253]
  ------------------
  305|     26|        if(Settings().strictMode) {
  ------------------
  |  Branch (305:12): [True: 0, False: 26]
  ------------------
  306|      0|            DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013"
  307|      0|                " (turn off strict mode to try anyhow) ");
  308|      0|        }
  309|     26|        else {
  310|     26|            DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013,"
  311|     26|                " trying to read it nevertheless");
  312|     26|        }
  313|     26|    }
  314|       |
  315|    279|    const Element* const ecreator = shead["Creator"];
  316|    279|    if(ecreator) {
  ------------------
  |  Branch (316:8): [True: 258, False: 21]
  ------------------
  317|    258|        creator = ParseTokenAsString(GetRequiredToken(*ecreator,0));
  318|    258|    }
  319|       |
  320|    279|    const Element* const etimestamp = shead["CreationTimeStamp"];
  321|    279|    if(etimestamp && etimestamp->Compound()) {
  ------------------
  |  Branch (321:8): [True: 262, False: 17]
  |  Branch (321:22): [True: 262, False: 0]
  ------------------
  322|    262|        const Scope& stimestamp = *etimestamp->Compound();
  323|    262|        creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0));
  324|    262|        creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0));
  325|    262|        creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0));
  326|    262|        creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0));
  327|    262|        creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0));
  328|    262|        creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0));
  329|    262|        creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0));
  330|    262|    }
  331|    279|}
_ZN6Assimp3FBX8Document18ReadGlobalSettingsEv:
  334|    278|void Document::ReadGlobalSettings() {
  335|    278|    const Scope& sc = parser.GetRootScope();
  336|    278|    const Element* const ehead = sc["GlobalSettings"];
  337|    278|    if ( nullptr == ehead || !ehead->Compound() ) {
  ------------------
  |  Branch (337:10): [True: 29, False: 249]
  |  Branch (337:30): [True: 0, False: 249]
  ------------------
  338|     29|        DOMWarning( "no GlobalSettings dictionary found" );
  339|     29|        globals.reset(new FileGlobalSettings(*this, std::make_shared<const PropertyTable>()));
  340|     29|        return;
  341|     29|    }
  342|       |
  343|    249|    std::shared_ptr<const PropertyTable> props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true );
  344|       |
  345|       |    //double v = PropertyGet<float>( *props.get(), std::string("UnitScaleFactor"), 1.0 );
  346|       |
  347|    249|    if(!props) {
  ------------------
  |  Branch (347:8): [True: 0, False: 249]
  ------------------
  348|      0|        DOMError("GlobalSettings dictionary contains no property table");
  349|      0|    }
  350|       |
  351|    249|    globals.reset(new FileGlobalSettings(*this, std::move(props)));
  352|    249|}
_ZN6Assimp3FBX8Document11ReadObjectsEv:
  355|    278|void Document::ReadObjects() {
  356|       |    // read ID objects from "Objects" section
  357|    278|    const Scope& sc = parser.GetRootScope();
  358|    278|    const Element* const eobjects = sc["Objects"];
  359|    278|    if(!eobjects || !eobjects->Compound()) {
  ------------------
  |  Branch (359:8): [True: 6, False: 272]
  |  Branch (359:21): [True: 0, False: 272]
  ------------------
  360|      6|        DOMError("no Objects dictionary found");
  361|      6|    }
  362|       |
  363|    272|    StackAllocator &allocator = parser.GetAllocator();
  364|       |
  365|       |    // add a dummy entry to represent the Model::RootNode object (id 0),
  366|       |    // which is only indirectly defined in the input file
  367|    272|    objects[0] = new_LazyObject(0L, *eobjects, *this);
  ------------------
  |  |   89|    544|#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject
  ------------------
  368|       |
  369|    272|    const Scope& sobjects = *eobjects->Compound();
  370|  60.3k|    for(const ElementMap::value_type& el : sobjects.Elements()) {
  ------------------
  |  Branch (370:42): [True: 60.3k, False: 272]
  ------------------
  371|       |
  372|       |        // extract ID
  373|  60.3k|        const TokenList& tok = el.second->Tokens();
  374|       |
  375|  60.3k|        if (tok.empty()) {
  ------------------
  |  Branch (375:13): [True: 0, False: 60.3k]
  ------------------
  376|      0|            DOMError("expected ID after object key",el.second);
  377|      0|        }
  378|       |
  379|  60.3k|        const char* err;
  380|  60.3k|        const uint64_t id = ParseTokenAsID(*tok[0], err);
  381|  60.3k|        if(err) {
  ------------------
  |  Branch (381:12): [True: 0, False: 60.3k]
  ------------------
  382|      0|            DOMError(err,el.second);
  383|      0|        }
  384|       |
  385|       |        // id=0 is normally implicit
  386|  60.3k|        if(id == 0L) {
  ------------------
  |  Branch (386:12): [True: 0, False: 60.3k]
  ------------------
  387|      0|            DOMError("encountered object with implicitly defined id 0",el.second);
  388|      0|        }
  389|       |
  390|  60.3k|        const auto foundObject = objects.find(id);
  391|  60.3k|        if(foundObject != objects.end()) {
  ------------------
  |  Branch (391:12): [True: 3, False: 60.3k]
  ------------------
  392|      3|            DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
  393|      3|            delete_LazyObject(foundObject->second);
  ------------------
  |  |   91|      3|#define delete_LazyObject(_p) (_p)->~LazyObject()
  ------------------
  394|      3|        }
  395|       |
  396|  60.3k|        objects[id] = new_LazyObject(id, *el.second, *this);
  ------------------
  |  |   89|   120k|#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject
  ------------------
  397|       |
  398|       |        // grab all animation stacks upfront since there is no listing of them
  399|  60.3k|        if(!strcmp(el.first.c_str(),"AnimationStack")) {
  ------------------
  |  Branch (399:12): [True: 256, False: 60.1k]
  ------------------
  400|    256|            animationStacks.push_back(id);
  401|    256|        }
  402|  60.3k|    }
  403|    272|}
_ZN6Assimp3FBX8Document21ReadPropertyTemplatesEv:
  406|    278|void Document::ReadPropertyTemplates() {
  407|    278|    const Scope& sc = parser.GetRootScope();
  408|       |    // read property templates from "Definitions" section
  409|    278|    const Element* const edefs = sc["Definitions"];
  410|    278|    if(!edefs || !edefs->Compound()) {
  ------------------
  |  Branch (410:8): [True: 14, False: 264]
  |  Branch (410:18): [True: 0, False: 264]
  ------------------
  411|     14|        DOMWarning("no Definitions dictionary found");
  412|     14|        return;
  413|     14|    }
  414|       |
  415|    264|    const Scope& sdefs = *edefs->Compound();
  416|    264|    const ElementCollection otypes = sdefs.GetCollection("ObjectType");
  417|  3.11k|    for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
  ------------------
  |  Branch (417:55): [True: 2.85k, False: 264]
  ------------------
  418|  2.85k|        const Element& el = *(*it).second;
  419|  2.85k|        const Scope* curSc = el.Compound();
  420|  2.85k|        if (!curSc) {
  ------------------
  |  Branch (420:13): [True: 0, False: 2.85k]
  ------------------
  421|      0|            DOMWarning("expected nested scope in ObjectType, ignoring",&el);
  422|      0|            continue;
  423|      0|        }
  424|       |
  425|  2.85k|        const TokenList& tok = el.Tokens();
  426|  2.85k|        if(tok.empty()) {
  ------------------
  |  Branch (426:12): [True: 0, False: 2.85k]
  ------------------
  427|      0|            DOMWarning("expected name for ObjectType element, ignoring",&el);
  428|      0|            continue;
  429|      0|        }
  430|       |
  431|  2.85k|        const std::string& oname = ParseTokenAsString(*tok[0]);
  432|       |
  433|  2.85k|        const ElementCollection templs = curSc->GetCollection("PropertyTemplate");
  434|  4.42k|        for (ElementMap::const_iterator elemIt = templs.first; elemIt != templs.second; ++elemIt) {
  ------------------
  |  Branch (434:64): [True: 1.57k, False: 2.85k]
  ------------------
  435|  1.57k|            const Element &innerEl = *(*elemIt).second;
  436|  1.57k|            const Scope *innerSc = innerEl.Compound();
  437|  1.57k|            if (!innerSc) {
  ------------------
  |  Branch (437:17): [True: 0, False: 1.57k]
  ------------------
  438|      0|                DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
  439|      0|                continue;
  440|      0|            }
  441|       |
  442|  1.57k|            const TokenList &curTok = innerEl.Tokens();
  443|  1.57k|            if (curTok.empty()) {
  ------------------
  |  Branch (443:17): [True: 0, False: 1.57k]
  ------------------
  444|      0|                DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
  445|      0|                continue;
  446|      0|            }
  447|       |
  448|  1.57k|            const std::string &pname = ParseTokenAsString(*curTok[0]);
  449|       |
  450|  1.57k|            const Element *Properties70 = (*innerSc)["Properties70"];
  451|  1.57k|            if(Properties70) {
  ------------------
  |  Branch (451:16): [True: 1.55k, False: 24]
  ------------------
  452|  1.55k|                std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>(
  453|  1.55k|                        *Properties70, std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable *>(nullptr))
  454|  1.55k|                );
  455|       |
  456|  1.55k|                templates[oname+"."+pname] = props;
  457|  1.55k|            }
  458|  1.57k|        }
  459|  2.85k|    }
  460|    264|}
_ZN6Assimp3FBX8Document15ReadConnectionsEv:
  464|    272|{
  465|    272|    StackAllocator &allocator = parser.GetAllocator();
  466|    272|    const Scope &sc = parser.GetRootScope();
  467|       |    // read property templates from "Definitions" section
  468|    272|    const Element* const econns = sc["Connections"];
  469|    272|    if(!econns || !econns->Compound()) {
  ------------------
  |  Branch (469:8): [True: 0, False: 272]
  |  Branch (469:19): [True: 0, False: 272]
  ------------------
  470|      0|        DOMError("no Connections dictionary found");
  471|      0|    }
  472|       |
  473|    272|    uint64_t insertionOrder = 0l;
  474|    272|    const Scope& sconns = *econns->Compound();
  475|    272|    const ElementCollection conns = sconns.GetCollection("C");
  476|  86.9k|    for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
  ------------------
  |  Branch (476:54): [True: 86.6k, False: 272]
  ------------------
  477|  86.6k|        const Element& el = *(*it).second;
  478|  86.6k|        const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
  479|       |
  480|       |        // PP = property-property connection, ignored for now
  481|       |        // (tokens: "PP", ID1, "Property1", ID2, "Property2")
  482|  86.6k|        if ( type == "PP" ) {
  ------------------
  |  Branch (482:14): [True: 1, False: 86.6k]
  ------------------
  483|      1|            continue;
  484|      1|        }
  485|       |
  486|  86.6k|        const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
  487|  86.6k|        const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
  488|       |
  489|       |        // OO = object-object connection
  490|       |        // OP = object-property connection, in which case the destination property follows the object ID
  491|  86.6k|        const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : "");
  ------------------
  |  Branch (491:36): [True: 47.3k, False: 39.3k]
  ------------------
  492|       |
  493|  86.6k|        if(objects.find(src) == objects.end()) {
  ------------------
  |  Branch (493:12): [True: 1.80k, False: 84.8k]
  ------------------
  494|  1.80k|            DOMWarning("source object for connection does not exist",&el);
  495|  1.80k|            continue;
  496|  1.80k|        }
  497|       |
  498|       |        // dest may be 0 (root node) but we added a dummy object before
  499|  84.8k|        if(objects.find(dest) == objects.end()) {
  ------------------
  |  Branch (499:12): [True: 2.03k, False: 82.8k]
  ------------------
  500|  2.03k|            DOMWarning("destination object for connection does not exist",&el);
  501|  2.03k|            continue;
  502|  2.03k|        }
  503|       |
  504|       |        // add new connection
  505|  82.8k|        const Connection* const c = new_Connection(insertionOrder++,src,dest,prop,*this);
  ------------------
  |  |   90|   165k|#define new_Connection new (allocator.Allocate(sizeof(Connection))) Connection
  ------------------
  506|  82.8k|        src_connections.insert(ConnectionMap::value_type(src,c));
  507|  82.8k|        dest_connections.insert(ConnectionMap::value_type(dest,c));
  508|  82.8k|    }
  509|    272|}
_ZNK6Assimp3FBX8Document15AnimationStacksEv:
  512|    271|const std::vector<const AnimationStack*>& Document::AnimationStacks() const {
  513|    271|    if (!animationStacksResolved.empty() || animationStacks.empty()) {
  ------------------
  |  Branch (513:9): [True: 0, False: 271]
  |  Branch (513:45): [True: 15, False: 256]
  ------------------
  514|     15|        return animationStacksResolved;
  515|     15|    }
  516|       |
  517|    256|    animationStacksResolved.reserve(animationStacks.size());
  518|    256|    for(uint64_t id : animationStacks) {
  ------------------
  |  Branch (518:21): [True: 256, False: 256]
  ------------------
  519|    256|        LazyObject* const lazy = GetObject(id);
  520|    256|        const AnimationStack *stack = lazy->Get<AnimationStack>();
  521|    256|        if(!lazy || nullptr == stack ) {
  ------------------
  |  Branch (521:12): [True: 0, False: 256]
  |  Branch (521:21): [True: 0, False: 256]
  ------------------
  522|      0|            DOMWarning("failed to read AnimationStack object");
  523|      0|            continue;
  524|      0|        }
  525|    256|        animationStacksResolved.push_back(stack);
  526|    256|    }
  527|       |
  528|    256|    return animationStacksResolved;
  529|    271|}
_ZNK6Assimp3FBX8Document9GetObjectEm:
  532|   249k|LazyObject* Document::GetObject(uint64_t id) const {
  533|   249k|    ObjectMap::const_iterator it = objects.find(id);
  534|   249k|    return it == objects.end() ? nullptr : (*it).second;
  ------------------
  |  Branch (534:12): [True: 0, False: 249k]
  ------------------
  535|   249k|}
_ZNK6Assimp3FBX8Document23GetConnectionsSequencedEmRKNSt3__118unordered_multimapImPKNS0_10ConnectionENS2_4hashImEENS2_8equal_toImEENS2_9allocatorINS2_4pairIKmS6_EEEEEE:
  540|    505|std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const {
  541|    505|    std::vector<const Connection*> temp;
  542|       |
  543|    505|    const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
  544|    505|        conns.equal_range(id);
  545|       |
  546|    505|    temp.reserve(std::distance(range.first,range.second));
  547|  72.7k|    for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
  ------------------
  |  Branch (547:58): [True: 72.2k, False: 505]
  ------------------
  548|  72.2k|        temp.push_back((*it).second);
  549|  72.2k|    }
  550|       |
  551|    505|    std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
  552|       |
  553|    505|    return temp; // NRVO should handle this
  554|    505|}
_ZNK6Assimp3FBX8Document23GetConnectionsSequencedEmbRKNSt3__118unordered_multimapImPKNS0_10ConnectionENS2_4hashImEENS2_8equal_toImEENS2_9allocatorINS2_4pairIKmS6_EEEEEEPKPKcm:
  560|  34.6k|        size_t count) const {
  561|  34.6k|    ai_assert(classnames);
  562|  34.6k|    ai_assert( count != 0 );
  563|  34.6k|    ai_assert( count <= MAX_CLASSNAMES);
  564|       |
  565|  34.6k|    size_t lengths[MAX_CLASSNAMES] = {};
  566|       |
  567|  34.6k|    const size_t c = count;
  568|   100k|    for (size_t i = 0; i < c; ++i) {
  ------------------
  |  Branch (568:24): [True: 65.5k, False: 34.6k]
  ------------------
  569|  65.5k|        lengths[ i ] = strlen(classnames[i]);
  570|  65.5k|    }
  571|       |
  572|  34.6k|    std::vector<const Connection*> temp;
  573|  34.6k|    const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
  574|  34.6k|        conns.equal_range(id);
  575|       |
  576|  34.6k|    temp.reserve(std::distance(range.first,range.second));
  577|   148k|    for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
  ------------------
  |  Branch (577:58): [True: 113k, False: 34.6k]
  ------------------
  578|   113k|        const Token& key = (is_src
  ------------------
  |  Branch (578:29): [True: 21.2k, False: 92.4k]
  ------------------
  579|   113k|            ? (*it).second->LazyDestinationObject()
  580|   113k|            : (*it).second->LazySourceObject()
  581|   113k|        ).GetElement().KeyToken();
  582|       |
  583|   113k|        const char* obtype = key.begin();
  584|       |
  585|   221k|        for (size_t i = 0; i < c; ++i) {
  ------------------
  |  Branch (585:28): [True: 173k, False: 48.1k]
  ------------------
  586|   173k|            ai_assert(classnames[i]);
  587|   173k|            if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lengths[i] && !strncmp(classnames[i],obtype,lengths[i])) {
  ------------------
  |  Branch (587:16): [True: 66.6k, False: 106k]
  |  Branch (587:91): [True: 65.5k, False: 1.09k]
  ------------------
  588|  65.5k|                obtype = nullptr;
  589|  65.5k|                break;
  590|  65.5k|            }
  591|   173k|        }
  592|       |
  593|   113k|        if(obtype) {
  ------------------
  |  Branch (593:12): [True: 48.1k, False: 65.5k]
  ------------------
  594|  48.1k|            continue;
  595|  48.1k|        }
  596|       |
  597|  65.5k|        temp.push_back((*it).second);
  598|  65.5k|    }
  599|       |
  600|  34.6k|    std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
  601|  34.6k|    return temp; // NRVO should handle this
  602|  34.6k|}
_ZNK6Assimp3FBX8Document31GetConnectionsBySourceSequencedEmPKPKcm:
  617|  10.8k|        const char* const* classnames, size_t count) const {
  618|  10.8k|    return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
  619|  10.8k|}
_ZNK6Assimp3FBX8Document36GetConnectionsByDestinationSequencedEmPKc:
  623|  19.2k|        const char* classname) const {
  624|  19.2k|    const char* arr[] = {classname};
  625|  19.2k|    return GetConnectionsByDestinationSequenced(dest, arr,1);
  626|  19.2k|}
_ZNK6Assimp3FBX8Document36GetConnectionsByDestinationSequencedEm:
  629|    505|std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const {
  630|    505|    return GetConnectionsSequenced(dest, ConnectionsByDestination());
  631|    505|}
_ZNK6Assimp3FBX8Document36GetConnectionsByDestinationSequencedEmPKPKcm:
  635|  23.8k|        const char* const* classnames, size_t count) const {
  636|  23.8k|    return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
  637|  23.8k|}
_ZN6Assimp3FBX10ConnectionC2EmmmRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_8DocumentE:
  642|  82.8k|            insertionOrder(insertionOrder), prop(prop), src(src), dest(dest), doc(doc) {
  643|  82.8k|    ai_assert(doc.Objects().find(src) != doc.Objects().end());
  644|       |    // dest may be 0 (root node)
  645|       |    ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end());
  646|  82.8k|}
_ZNK6Assimp3FBX10Connection16LazySourceObjectEv:
  649|  92.4k|LazyObject& Connection::LazySourceObject() const {
  650|  92.4k|    LazyObject* const lazy = doc.GetObject(src);
  651|       |    ai_assert(lazy);
  652|  92.4k|    return *lazy;
  653|  92.4k|}
_ZNK6Assimp3FBX10Connection21LazyDestinationObjectEv:
  656|  21.2k|LazyObject& Connection::LazyDestinationObject() const {
  657|  21.2k|    LazyObject* const lazy = doc.GetObject(dest);
  658|       |    ai_assert(lazy);
  659|  21.2k|    return *lazy;
  660|  21.2k|}
_ZNK6Assimp3FBX10Connection12SourceObjectEv:
  663|   124k|const Object* Connection::SourceObject() const {
  664|   124k|    LazyObject* const lazy = doc.GetObject(src);
  665|   124k|    ai_assert(lazy);
  666|   124k|    if (lazy == nullptr) {
  ------------------
  |  Branch (666:9): [True: 0, False: 124k]
  ------------------
  667|      0|        return nullptr;
  668|      0|    }
  669|       |
  670|   124k|    return lazy->Get();
  671|   124k|}
_ZNK6Assimp3FBX10Connection17DestinationObjectEv:
  674|  10.4k|const Object* Connection::DestinationObject() const {
  675|  10.4k|    LazyObject* const lazy = doc.GetObject(dest);
  676|  10.4k|    ai_assert(lazy);
  677|  10.4k|    if (lazy == nullptr) {
  ------------------
  |  Branch (677:9): [True: 0, False: 10.4k]
  ------------------
  678|      0|        return nullptr;
  679|      0|    }
  680|       |
  681|  10.4k|    return lazy->Get();
  682|  10.4k|}

_ZNK6Assimp3FBX10LazyObject18IsBeingConstructedEv:
  115|   135k|    bool IsBeingConstructed() const {
  116|   135k|        return (flags & BEING_CONSTRUCTED) != 0;
  117|   135k|    }
_ZNK6Assimp3FBX10LazyObject17FailedToConstructEv:
  119|  66.4k|    bool FailedToConstruct() const {
  120|  66.4k|        return (flags & FAILED_TO_CONSTRUCT) != 0;
  121|  66.4k|    }
_ZNK6Assimp3FBX10LazyObject10GetElementEv:
  123|   116k|    const Element& GetElement() const {
  124|   116k|        return element;
  125|   116k|    }
_ZNK6Assimp3FBX6Object4NameEv:
  157|  14.8k|    const std::string& Name() const {
  158|  14.8k|        return name;
  159|  14.8k|    }
_ZNK6Assimp3FBX6Object2IDEv:
  161|  34.9k|    uint64_t ID() const {
  162|  34.9k|        return id;
  163|  34.9k|    }
_ZNK6Assimp3FBX13NodeAttribute5PropsEv:
  179|  2.18k|    const PropertyTable& Props() const {
  180|       |        ai_assert(props.get());
  181|  2.18k|        return *props;
  182|  2.18k|    }
_ZNK6Assimp3FBX6Camera11AspectWidthEv:
  216|    221|    type name() const { \
  217|    221|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    221|#define fbx_stringize(a) #a
  ------------------
  218|    221|    }
_ZNK6Assimp3FBX6Camera12AspectHeightEv:
  216|    221|    type name() const { \
  217|    221|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    221|#define fbx_stringize(a) #a
  ------------------
  218|    221|    }
_ZNK6Assimp3FBX6Camera9FilmWidthEv:
  216|      4|    type name() const { \
  217|      4|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|      4|#define fbx_stringize(a) #a
  ------------------
  218|      4|    }
_ZNK6Assimp3FBX6Camera9NearPlaneEv:
  216|    221|    type name() const { \
  217|    221|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    221|#define fbx_stringize(a) #a
  ------------------
  218|    221|    }
_ZNK6Assimp3FBX6Camera8FarPlaneEv:
  216|    221|    type name() const { \
  217|    221|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    221|#define fbx_stringize(a) #a
  ------------------
  218|    221|    }
_ZNK6Assimp3FBX6Camera11FieldOfViewEv:
  216|    221|    type name() const { \
  217|    221|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    221|#define fbx_stringize(a) #a
  ------------------
  218|    221|    }
_ZNK6Assimp3FBX6Camera11FocalLengthEv:
  216|      4|    type name() const { \
  217|      4|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|      4|#define fbx_stringize(a) #a
  ------------------
  218|      4|    }
_ZNK6Assimp3FBX5Light5ColorEv:
  216|    215|    type name() const { \
  217|    215|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    215|#define fbx_stringize(a) #a
  ------------------
  218|    215|    }
_ZNK6Assimp3FBX5Light9IntensityEv:
  216|    215|    type name() const { \
  217|    215|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    215|#define fbx_stringize(a) #a
  ------------------
  218|    215|    }
_ZNK6Assimp3FBX5Light10DecayStartEv:
  216|    215|    type name() const { \
  217|    215|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    215|#define fbx_stringize(a) #a
  ------------------
  218|    215|    }
_ZNK6Assimp3FBX5Model5PropsEv:
  443|  19.9k|    const PropertyTable& Props() const {
  444|       |        ai_assert(props.get());
  445|  19.9k|        return *props;
  446|  19.9k|    }
_ZNK6Assimp3FBX5Model12GetMaterialsEv:
  449|     89|    const std::vector<const Material*>& GetMaterials() const {
  450|     89|        return materials;
  451|     89|    }
_ZNK6Assimp3FBX5Model11GetGeometryEv:
  454|  3.56k|    const std::vector<const Geometry*>& GetGeometry() const {
  455|  3.56k|        return geometry;
  456|  3.56k|    }
_ZNK6Assimp3FBX5Model13GetAttributesEv:
  459|  10.6k|    const std::vector<const NodeAttribute*>& GetAttributes() const {
  460|  10.6k|        return attributes;
  461|  10.6k|    }
_ZNK6Assimp3FBX7Texture16RelativeFilenameEv:
  494|      6|    const std::string& RelativeFilename() const {
  495|      6|        return relativeFileName;
  496|      6|    }
_ZNK6Assimp3FBX7Texture13UVTranslationEv:
  502|      6|    const aiVector2D& UVTranslation() const {
  503|      6|        return uvTrans;
  504|      6|    }
_ZNK6Assimp3FBX7Texture9UVScalingEv:
  506|      6|    const aiVector2D& UVScaling() const {
  507|      6|        return uvScaling;
  508|      6|    }
_ZNK6Assimp3FBX7Texture10UVRotationEv:
  510|      6|    const ai_real &UVRotation() const {
  511|      6|        return uvRotation;
  512|      6|    }
_ZNK6Assimp3FBX7Texture5PropsEv:
  514|      6|    const PropertyTable& Props() const {
  515|       |        ai_assert(props.get());
  516|      6|        return *props;
  517|      6|    }
_ZNK6Assimp3FBX7Texture5MediaEv:
  524|     12|    const Video* Media() const {
  525|     12|        return media;
  526|     12|    }
_ZNK6Assimp3FBX5Video16RelativeFilenameEv:
  625|      2|    const std::string& RelativeFilename() const {
  626|      2|        return relativeFileName;
  627|      2|    }
_ZNK6Assimp3FBX5Video13ContentLengthEv:
  639|      9|    uint64_t ContentLength() const {
  640|      9|        return contentLength;
  641|      9|    }
_ZN6Assimp3FBX5Video17RelinquishContentEv:
  643|      1|    uint8_t* RelinquishContent() {
  644|      1|        uint8_t* ptr = content;
  645|      1|        content = nullptr;
  646|      1|        return ptr;
  647|      1|    }
_ZNK6Assimp3FBX8Material15GetShadingModelEv:
  666|     86|    const std::string& GetShadingModel() const {
  667|     86|        return shading;
  668|     86|    }
_ZNK6Assimp3FBX8Material5PropsEv:
  674|     86|    const PropertyTable& Props() const {
  675|       |        ai_assert(props.get());
  676|     86|        return *props;
  677|     86|    }
_ZNK6Assimp3FBX8Material8TexturesEv:
  679|    172|    const TextureMap& Textures() const {
  680|    172|        return textures;
  681|    172|    }
_ZNK6Assimp3FBX8Material15LayeredTexturesEv:
  683|     86|    const LayeredTextureMap& LayeredTextures() const {
  684|     86|        return layeredTextures;
  685|     86|    }
_ZNK6Assimp3FBX14AnimationCurve7GetKeysEv:
  707|   139k|    const KeyTimeList& GetKeys() const {
  708|   139k|        return keys;
  709|   139k|    }
_ZNK6Assimp3FBX14AnimationCurve9GetValuesEv:
  713|   106k|    const KeyValueList& GetValues() const {
  714|   106k|        return values;
  715|   106k|    }
_ZNK6Assimp3FBX18AnimationCurveNode6TargetEv:
  757|  22.9k|    const Object* Target() const {
  758|  22.9k|        return target;
  759|  22.9k|    }
_ZNK6Assimp3FBX18AnimationCurveNode13TargetAsModelEv:
  761|  6.51k|    const Model* TargetAsModel() const {
  762|  6.51k|        return dynamic_cast<const Model*>(target);
  763|  6.51k|    }
_ZNK6Assimp3FBX18AnimationCurveNode14TargetPropertyEv:
  770|  29.8k|    const std::string& TargetProperty() const {
  771|  29.8k|        return prop;
  772|  29.8k|    }
_ZNK6Assimp3FBX14AnimationStack10LocalStartEv:
  216|    245|    type name() const { \
  217|    245|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    245|#define fbx_stringize(a) #a
  ------------------
  218|    245|    }
_ZNK6Assimp3FBX14AnimationStack9LocalStopEv:
  216|    245|    type name() const { \
  217|    245|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    245|#define fbx_stringize(a) #a
  ------------------
  218|    245|    }
_ZNK6Assimp3FBX14AnimationStack5PropsEv:
  819|    490|    const PropertyTable& Props() const {
  820|       |        ai_assert(props.get());
  821|    490|        return *props;
  822|    490|    }
_ZNK6Assimp3FBX14AnimationStack6LayersEv:
  824|    256|    const AnimationLayerList& Layers() const {
  825|    256|        return layers;
  826|    256|    }
_ZNK6Assimp3FBX7Cluster10GetWeightsEv:
  903|    699|    const WeightArray& GetWeights() const {
  904|    699|        return weights;
  905|    699|    }
_ZNK6Assimp3FBX7Cluster10GetIndicesEv:
  910|    699|    const WeightIndexArray& GetIndices() const {
  911|    699|        return indices;
  912|    699|    }
_ZNK6Assimp3FBX7Cluster13TransformLinkEv:
  919|    699|    const aiMatrix4x4& TransformLink() const {
  920|    699|        return transformLink;
  921|    699|    }
_ZNK6Assimp3FBX7Cluster10TargetNodeEv:
  923|    699|    const Model* TargetNode() const {
  924|    699|        return node;
  925|    699|    }
_ZNK6Assimp3FBX4Skin8ClustersEv:
  948|     84|    const std::vector<const Cluster*>& Clusters() const {
  949|     84|        return clusters;
  950|     84|    }
_ZNK6Assimp3FBX10Connection12PropertyNameEv:
  977|   104k|    const std::string& PropertyName() const {
  978|   104k|        return prop;
  979|   104k|    }
_ZNK6Assimp3FBX10Connection14InsertionOrderEv:
  981|   382k|    uint64_t InsertionOrder() const {
  982|   382k|        return insertionOrder;
  983|   382k|    }
_ZNK6Assimp3FBX10Connection7CompareEPKS1_:
  998|   191k|    bool Compare(const Connection* c) const {
  999|   191k|        ai_assert( nullptr != c );
 1000|       |
 1001|   191k|        return InsertionOrder() < c->InsertionOrder();
 1002|   191k|    }
_ZNK6Assimp3FBX18FileGlobalSettings5PropsEv:
 1029|  4.17k|    const PropertyTable& Props() const {
 1030|       |        ai_assert(props.get());
 1031|  4.17k|        return *props;
 1032|  4.17k|    }
_ZNK6Assimp3FBX18FileGlobalSettings6UpAxisEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings10UpAxisSignEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings9FrontAxisEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings13FrontAxisSignEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings9CoordAxisEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings13CoordAxisSignEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings14OriginalUpAxisEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings18OriginalUpAxisSignEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings15UnitScaleFactorEv:
  216|    454|    type name() const { \
  217|    454|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    454|#define fbx_stringize(a) #a
  ------------------
  218|    454|    }
_ZNK6Assimp3FBX18FileGlobalSettings23OriginalUnitScaleFactorEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings12AmbientColorEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings13TimeSpanStartEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings12TimeSpanStopEv:
  216|    227|    type name() const { \
  217|    227|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    227|#define fbx_stringize(a) #a
  ------------------
  218|    227|    }
_ZNK6Assimp3FBX18FileGlobalSettings15CustomFrameRateEv:
  216|    498|    type name() const { \
  217|    498|        return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
  ------------------
  |  |  213|    498|#define fbx_stringize(a) #a
  ------------------
  218|    498|    }
_ZNK6Assimp3FBX8Document10FBXVersionEv:
 1095|    227|    unsigned int FBXVersion() const {
 1096|    227|        return fbxVersion;
 1097|    227|    }
_ZNK6Assimp3FBX8Document7CreatorEv:
 1099|    444|    const std::string& Creator() const {
 1100|    444|        return creator;
 1101|    444|    }
_ZNK6Assimp3FBX8Document14GlobalSettingsEv:
 1108|  4.17k|    const FileGlobalSettings& GlobalSettings() const {
 1109|       |        ai_assert(globals.get());
 1110|  4.17k|        return *globals;
 1111|  4.17k|    }
_ZNK6Assimp3FBX8Document9TemplatesEv:
 1113|  47.1k|    const PropertyTemplateMap& Templates() const {
 1114|  47.1k|        return templates;
 1115|  47.1k|    }
_ZNK6Assimp3FBX8Document7ObjectsEv:
 1117|   328k|    const ObjectMap& Objects() const {
 1118|   328k|        return objects;
 1119|   328k|    }
_ZNK6Assimp3FBX8Document8SettingsEv:
 1121|  26.5k|    const ImportSettings& Settings() const {
 1122|  26.5k|        return settings;
 1123|  26.5k|    }
_ZNK6Assimp3FBX8Document19ConnectionsBySourceEv:
 1125|  66.1k|    const ConnectionMap& ConnectionsBySource() const {
 1126|  66.1k|        return src_connections;
 1127|  66.1k|    }
_ZNK6Assimp3FBX8Document24ConnectionsByDestinationEv:
 1129|  24.3k|    const ConnectionMap& ConnectionsByDestination() const {
 1130|  24.3k|        return dest_connections;
 1131|  24.3k|    }
_ZN6Assimp3FBX10LazyObjectD2Ev:
  101|  60.6k|    ~LazyObject() = default;
_ZN6Assimp3FBX10ConnectionD2Ev:
  962|  76.2k|    ~Connection() = default;
_ZN6Assimp3FBX18FileGlobalSettingsD2Ev:
 1027|    278|    ~FileGlobalSettings() = default;
_ZN6Assimp3FBX10LazyObject3GetINS0_14AnimationStackEEEPKT_b:
  106|    256|    const T* Get(bool dieOnError = false) {
  107|    256|        const Object* const ob = Get(dieOnError);
  108|    256|        return ob ? dynamic_cast<const T *>(ob) : nullptr;
  ------------------
  |  Branch (108:16): [True: 256, False: 0]
  ------------------
  109|    256|    }
_ZN6Assimp3FBX6ObjectD2Ev:
  151|  51.8k|    virtual ~Object() = default;
_ZN6Assimp3FBX8MaterialD2Ev:
  664|    231|    ~Material() override = default;
_ZN6Assimp3FBX5ModelD2Ev:
  357|  4.59k|    ~Model() override = default;
_ZN6Assimp3FBX14AnimationCurveD2Ev:
  703|  27.6k|    ~AnimationCurve() override = default;
_ZN6Assimp3FBX18AnimationCurveNodeD2Ev:
  744|  10.8k|   ~AnimationCurveNode() override = default;
_ZN6Assimp3FBX14AnimationLayerD2Ev:
  789|    250|    virtual ~AnimationLayer() = default;
_ZN6Assimp3FBX14AnimationStackD2Ev:
  812|    256|    virtual ~AnimationStack() = default;
_ZN6Assimp3FBX13NodeAttributeD2Ev:
  177|  4.27k|    ~NodeAttribute() override = default;
_ZN6Assimp3FBX8DeformerD2Ev:
  838|  3.13k|    virtual ~Deformer() = default;
_ZN6Assimp3FBX7ClusterD2Ev:
  898|  1.32k|    virtual ~Cluster() = default;
_ZN6Assimp3FBX4SkinD2Ev:
  942|    215|    virtual ~Skin() = default;

_ZN6Assimp3FBX4Util8DOMErrorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5TokenE:
   60|    181|void DOMError(const std::string& message, const Token& token) {
   61|    181|    throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
   62|    181|}
_ZN6Assimp3FBX4Util8DOMErrorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKNS0_7ElementE:
   65|    190|void DOMError(const std::string& message, const Element* element /*= nullptr*/) {
   66|    190|    if(element) {
  ------------------
  |  Branch (66:8): [True: 181, False: 9]
  ------------------
   67|    181|        DOMError(message,element->KeyToken());
   68|    181|    }
   69|      9|    throw DeadlyImportError("FBX-DOM ", message);
   70|    190|}
_ZN6Assimp3FBX4Util10DOMWarningERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5TokenE:
   75|  77.5k|void DOMWarning(const std::string& message, const Token& token) {
   76|  77.5k|    if(DefaultLogger::get()) {
  ------------------
  |  Branch (76:8): [True: 77.5k, False: 0]
  ------------------
   77|       |        ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message);
   78|  77.5k|    }
   79|  77.5k|}
_ZN6Assimp3FBX4Util10DOMWarningERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKNS0_7ElementE:
   82|  77.5k|void DOMWarning(const std::string& message, const Element* element /*= nullptr*/) {
   83|  77.5k|    if(element) {
  ------------------
  |  Branch (83:8): [True: 77.5k, False: 69]
  ------------------
   84|  77.5k|        DOMWarning(message,element->KeyToken());
   85|  77.5k|        return;
   86|  77.5k|    }
   87|     69|    if(DefaultLogger::get()) {
  ------------------
  |  Branch (87:8): [True: 69, False: 0]
  ------------------
   88|       |        ASSIMP_LOG_WARN("FBX-DOM: ", message);
   89|     69|    }
   90|     69|}
_ZN6Assimp3FBX4Util16GetPropertyTableERKNS0_8DocumentERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_7ElementERKNS0_5ScopeEb:
   98|  23.8k|        bool no_warn /*= false*/) {
   99|  23.8k|    const Element* const Properties70 = sc["Properties70"];
  100|  23.8k|    std::shared_ptr<const PropertyTable> templateProps = std::shared_ptr<const PropertyTable>(
  101|  23.8k|            static_cast<const PropertyTable *>(nullptr));
  102|       |
  103|  23.8k|    if (templateName.length()) {
  ------------------
  |  Branch (103:9): [True: 23.5k, False: 251]
  ------------------
  104|  23.5k|        PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
  105|  23.5k|        if(it != doc.Templates().end()) {
  ------------------
  |  Branch (105:12): [True: 15.7k, False: 7.85k]
  ------------------
  106|  15.7k|            templateProps = (*it).second;
  107|  15.7k|        }
  108|  23.5k|    }
  109|       |
  110|  23.8k|    if (!Properties70 || !Properties70->Compound()) {
  ------------------
  |  Branch (110:9): [True: 3.95k, False: 19.8k]
  |  Branch (110:26): [True: 0, False: 19.8k]
  ------------------
  111|  3.95k|        if(!no_warn) {
  ------------------
  |  Branch (111:12): [True: 496, False: 3.46k]
  ------------------
  112|    496|            DOMWarning("property table (Properties70) not found",&element);
  113|    496|        }
  114|  3.95k|        if(templateProps) {
  ------------------
  |  Branch (114:12): [True: 713, False: 3.24k]
  ------------------
  115|    713|            return templateProps;
  116|  3.24k|        } else {
  117|  3.24k|            return std::make_shared<const PropertyTable>();
  118|  3.24k|        }
  119|  3.95k|    }
  120|  19.8k|    return std::make_shared<const PropertyTable>(*Properties70,templateProps);
  121|  23.8k|}

_ZN6Assimp3FBX4Util23ProcessSimpleConnectionINS0_4SkinEEEPKT_RKNS0_10ConnectionEbPKcRKNS0_7ElementEPSB_:
   80|    215|        const char** propNameOut = nullptr) {
   81|    215|    if (is_object_property_conn && !con.PropertyName().length()) {
  ------------------
  |  Branch (81:9): [True: 0, False: 215]
  |  Branch (81:36): [True: 0, False: 0]
  ------------------
   82|      0|        DOMWarning("expected incoming " + std::string(name) +
   83|      0|            " link to be an object-object connection, ignoring",
   84|      0|            &element
   85|      0|            );
   86|      0|        return nullptr;
   87|      0|    }
   88|    215|    else if (!is_object_property_conn && con.PropertyName().length()) {
  ------------------
  |  Branch (88:14): [True: 215, False: 0]
  |  Branch (88:42): [True: 0, False: 215]
  ------------------
   89|      0|        DOMWarning("expected incoming " + std::string(name) +
   90|      0|            " link to be an object-property connection, ignoring",
   91|      0|            &element
   92|      0|            );
   93|      0|        return nullptr;
   94|      0|    }
   95|       |
   96|    215|    if(is_object_property_conn && propNameOut) {
  ------------------
  |  Branch (96:8): [True: 0, False: 215]
  |  Branch (96:35): [True: 0, False: 0]
  ------------------
   97|       |        // note: this is ok, the return value of PropertyValue() is guaranteed to
   98|       |        // remain valid and unchanged as long as the document exists.
   99|      0|        *propNameOut = con.PropertyName().c_str();
  100|      0|    }
  101|       |
  102|    215|    const Object* const ob = con.SourceObject();
  103|    215|    if(!ob) {
  ------------------
  |  Branch (103:8): [True: 0, False: 215]
  ------------------
  104|      0|        DOMWarning("failed to read source object for incoming " + std::string(name) +
  105|      0|            " link, ignoring",
  106|      0|            &element);
  107|      0|        return nullptr;
  108|      0|    }
  109|       |
  110|    215|    return dynamic_cast<const T*>(ob);
  111|    215|}
_ZN6Assimp3FBX4Util23ProcessSimpleConnectionINS0_10BlendShapeEEEPKT_RKNS0_10ConnectionEbPKcRKNS0_7ElementEPSB_:
   80|    215|        const char** propNameOut = nullptr) {
   81|    215|    if (is_object_property_conn && !con.PropertyName().length()) {
  ------------------
  |  Branch (81:9): [True: 0, False: 215]
  |  Branch (81:36): [True: 0, False: 0]
  ------------------
   82|      0|        DOMWarning("expected incoming " + std::string(name) +
   83|      0|            " link to be an object-object connection, ignoring",
   84|      0|            &element
   85|      0|            );
   86|      0|        return nullptr;
   87|      0|    }
   88|    215|    else if (!is_object_property_conn && con.PropertyName().length()) {
  ------------------
  |  Branch (88:14): [True: 215, False: 0]
  |  Branch (88:42): [True: 0, False: 215]
  ------------------
   89|      0|        DOMWarning("expected incoming " + std::string(name) +
   90|      0|            " link to be an object-property connection, ignoring",
   91|      0|            &element
   92|      0|            );
   93|      0|        return nullptr;
   94|      0|    }
   95|       |
   96|    215|    if(is_object_property_conn && propNameOut) {
  ------------------
  |  Branch (96:8): [True: 0, False: 215]
  |  Branch (96:35): [True: 0, False: 0]
  ------------------
   97|       |        // note: this is ok, the return value of PropertyValue() is guaranteed to
   98|       |        // remain valid and unchanged as long as the document exists.
   99|      0|        *propNameOut = con.PropertyName().c_str();
  100|      0|    }
  101|       |
  102|    215|    const Object* const ob = con.SourceObject();
  103|    215|    if(!ob) {
  ------------------
  |  Branch (103:8): [True: 0, False: 215]
  ------------------
  104|      0|        DOMWarning("failed to read source object for incoming " + std::string(name) +
  105|      0|            " link, ignoring",
  106|      0|            &element);
  107|      0|        return nullptr;
  108|      0|    }
  109|       |
  110|    215|    return dynamic_cast<const T*>(ob);
  111|    215|}
_ZN6Assimp3FBX4Util23ProcessSimpleConnectionINS0_5ModelEEEPKT_RKNS0_10ConnectionEbPKcRKNS0_7ElementEPSB_:
   80|  1.32k|        const char** propNameOut = nullptr) {
   81|  1.32k|    if (is_object_property_conn && !con.PropertyName().length()) {
  ------------------
  |  Branch (81:9): [True: 0, False: 1.32k]
  |  Branch (81:36): [True: 0, False: 0]
  ------------------
   82|      0|        DOMWarning("expected incoming " + std::string(name) +
   83|      0|            " link to be an object-object connection, ignoring",
   84|      0|            &element
   85|      0|            );
   86|      0|        return nullptr;
   87|      0|    }
   88|  1.32k|    else if (!is_object_property_conn && con.PropertyName().length()) {
  ------------------
  |  Branch (88:14): [True: 1.32k, False: 0]
  |  Branch (88:42): [True: 0, False: 1.32k]
  ------------------
   89|      0|        DOMWarning("expected incoming " + std::string(name) +
   90|      0|            " link to be an object-property connection, ignoring",
   91|      0|            &element
   92|      0|            );
   93|      0|        return nullptr;
   94|      0|    }
   95|       |
   96|  1.32k|    if(is_object_property_conn && propNameOut) {
  ------------------
  |  Branch (96:8): [True: 0, False: 1.32k]
  |  Branch (96:35): [True: 0, False: 0]
  ------------------
   97|       |        // note: this is ok, the return value of PropertyValue() is guaranteed to
   98|       |        // remain valid and unchanged as long as the document exists.
   99|      0|        *propNameOut = con.PropertyName().c_str();
  100|      0|    }
  101|       |
  102|  1.32k|    const Object* const ob = con.SourceObject();
  103|  1.32k|    if(!ob) {
  ------------------
  |  Branch (103:8): [True: 0, False: 1.32k]
  ------------------
  104|      0|        DOMWarning("failed to read source object for incoming " + std::string(name) +
  105|      0|            " link, ignoring",
  106|      0|            &element);
  107|      0|        return nullptr;
  108|      0|    }
  109|       |
  110|  1.32k|    return dynamic_cast<const T*>(ob);
  111|  1.32k|}
_ZN6Assimp3FBX4Util23ProcessSimpleConnectionINS0_7ClusterEEEPKT_RKNS0_10ConnectionEbPKcRKNS0_7ElementEPSB_:
   80|  2.92k|        const char** propNameOut = nullptr) {
   81|  2.92k|    if (is_object_property_conn && !con.PropertyName().length()) {
  ------------------
  |  Branch (81:9): [True: 0, False: 2.92k]
  |  Branch (81:36): [True: 0, False: 0]
  ------------------
   82|      0|        DOMWarning("expected incoming " + std::string(name) +
   83|      0|            " link to be an object-object connection, ignoring",
   84|      0|            &element
   85|      0|            );
   86|      0|        return nullptr;
   87|      0|    }
   88|  2.92k|    else if (!is_object_property_conn && con.PropertyName().length()) {
  ------------------
  |  Branch (88:14): [True: 2.92k, False: 0]
  |  Branch (88:42): [True: 0, False: 2.92k]
  ------------------
   89|      0|        DOMWarning("expected incoming " + std::string(name) +
   90|      0|            " link to be an object-property connection, ignoring",
   91|      0|            &element
   92|      0|            );
   93|      0|        return nullptr;
   94|      0|    }
   95|       |
   96|  2.92k|    if(is_object_property_conn && propNameOut) {
  ------------------
  |  Branch (96:8): [True: 0, False: 2.92k]
  |  Branch (96:35): [True: 0, False: 0]
  ------------------
   97|       |        // note: this is ok, the return value of PropertyValue() is guaranteed to
   98|       |        // remain valid and unchanged as long as the document exists.
   99|      0|        *propNameOut = con.PropertyName().c_str();
  100|      0|    }
  101|       |
  102|  2.92k|    const Object* const ob = con.SourceObject();
  103|  2.92k|    if(!ob) {
  ------------------
  |  Branch (103:8): [True: 1.59k, False: 1.32k]
  ------------------
  104|  1.59k|        DOMWarning("failed to read source object for incoming " + std::string(name) +
  105|  1.59k|            " link, ignoring",
  106|  1.59k|            &element);
  107|  1.59k|        return nullptr;
  108|  1.59k|    }
  109|       |
  110|  1.32k|    return dynamic_cast<const T*>(ob);
  111|  2.92k|}

_ZN6Assimp3FBX14ImportSettingsC2Ev:
   54|    297|            strictMode(true),
   55|    297|            readAllLayers(true),
   56|    297|            readAllMaterials(false),
   57|    297|            readMaterials(true),
   58|    297|            readTextures(true),
   59|    297|            readCameras(true),
   60|    297|            readLights(true),
   61|    297|            readAnimations(true),
   62|    297|            readWeights(true),
   63|    297|            useSkeleton(false),
   64|    297|            preservePivots(true),
   65|    297|            optimizeEmptyAnimationCurves(true),
   66|    297|            useLegacyEmbeddedTextureNaming(false),
   67|    297|            removeEmptyBones(true),
   68|    297|            convertToMeters(false) {
   69|       |        // empty
   70|    297|    }

_ZNK6Assimp11FBXImporter7GetInfoEv:
   99|    891|const aiImporterDesc *FBXImporter::GetInfo() const {
  100|    891|	return &desc;
  101|    891|}
_ZN6Assimp11FBXImporter15SetupPropertiesEPKNS_8ImporterE:
  105|    297|void FBXImporter::SetupProperties(const Importer *pImp) {
  106|    297|    mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
  107|    297|    mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
  108|    297|    mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
  109|    297|    mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
  110|    297|    mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
  111|    297|    mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
  112|    297|    mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
  113|    297|    mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
  114|    297|    mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
  115|    297|    mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
  116|    297|    mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
  117|    297|    mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
  118|    297|    mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
  119|    297|    mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
  120|    297|    mSettings.ignoreUpDirection = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_IGNORE_UP_DIRECTION, false);
  121|       |    mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
  122|    297|}
_ZN6Assimp11FBXImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  126|    297|void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  127|    297|	auto streamCloser = [&](IOStream *pStream) {
  128|    297|		pIOHandler->Close(pStream);
  129|    297|	};
  130|    297|	std::unique_ptr<IOStream, decltype(streamCloser)> stream(pIOHandler->Open(pFile, "rb"), streamCloser);
  131|    297|	if (!stream) {
  ------------------
  |  Branch (131:6): [True: 0, False: 297]
  ------------------
  132|      0|		ThrowException("Could not open file for reading");
  133|      0|	}
  134|       |
  135|    297|    ASSIMP_LOG_DEBUG("Reading FBX file");
  136|       |
  137|       |	// read entire file into memory - no streaming for this, fbx
  138|       |	// files can grow large, but the assimp output data structure
  139|       |	// then becomes very large, too. Assimp doesn't support
  140|       |	// streaming for its output data structures so the net win with
  141|       |	// streaming input data would be very low.
  142|    297|	std::vector<char> contents;
  143|    297|	contents.resize(stream->FileSize() + 1);
  144|    297|	stream->Read(&*contents.begin(), 1, contents.size() - 1);
  145|    297|	contents[contents.size() - 1] = 0;
  146|    297|	const char *const begin = &*contents.begin();
  147|       |
  148|       |	// broad-phase tokenized pass in which we identify the core
  149|       |	// syntax elements of FBX (brackets, commas, key:value mappings)
  150|    297|	TokenList tokens;
  151|    297|    Assimp::StackAllocator tempAllocator;
  152|    297|    try {
  153|    297|		bool is_binary = false;
  154|    297|		if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
  ------------------
  |  Branch (154:7): [True: 258, False: 39]
  ------------------
  155|    258|			is_binary = true;
  156|    258|            TokenizeBinary(tokens, begin, contents.size(), tempAllocator);
  157|    258|		} else {
  158|     39|            Tokenize(tokens, begin, tempAllocator);
  159|     39|		}
  160|       |
  161|       |		// use this information to construct a very rudimentary
  162|       |		// parse-tree representing the FBX scope structure
  163|    297|        Parser parser(tokens, tempAllocator, is_binary);
  164|       |
  165|       |		// take the raw parse-tree and convert it to a FBX DOM
  166|    297|		Document doc(parser, mSettings);
  167|       |
  168|       |		// convert the FBX DOM to aiScene
  169|    297|		ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
  170|       |
  171|       |		// size relative to cm
  172|    297|		float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
  173|    297|        if (size_relative_to_cm == 0.0) {
  ------------------
  |  Branch (173:13): [True: 0, False: 297]
  ------------------
  174|       |			// BaseImporter later asserts that fileScale is non-zero.
  175|      0|			ThrowException("The UnitScaleFactor must be non-zero");
  176|      0|        }
  177|       |
  178|       |		// Set FBX file scale is relative to CM must be converted to M for
  179|       |		// assimp universal format (M)
  180|    297|		SetFileScale(size_relative_to_cm * 0.01f);
  181|       |
  182|       |		// This collection does not own the memory for the tokens, but we need to call their d'tor
  183|    297|        std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
  184|       |
  185|    297|    } catch (std::exception &) {
  186|     70|        std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
  187|     70|        throw;
  188|     70|	}
  189|    297|}
FBXImporter.cpp:_ZZN6Assimp11FBXImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemEENK3$_0clEPNS_8IOStreamE:
  127|    297|	auto streamCloser = [&](IOStream *pStream) {
  128|    297|		pIOHandler->Close(pStream);
  129|    297|	};

_ZN6Assimp11FBXImporterC2Ev:
   73|    297|    FBXImporter() = default;

_ZN6Assimp3FBX8MaterialC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   66|    231|        Object(id,element,name) {
   67|    231|    const Scope& sc = GetRequiredScope(element);
   68|       |
   69|    231|    const Element* const ShadingModel = sc["ShadingModel"];
   70|    231|    const Element* const MultiLayer = sc["MultiLayer"];
   71|       |
   72|    231|    if(MultiLayer) {
  ------------------
  |  Branch (72:8): [True: 229, False: 2]
  ------------------
   73|    229|        multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
   74|    229|    }
   75|       |
   76|    231|    if(ShadingModel) {
  ------------------
  |  Branch (76:8): [True: 230, False: 1]
  ------------------
   77|    230|        shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
   78|    230|    } else {
   79|      1|        DOMWarning("shading mode not specified, assuming phong",&element);
   80|      1|        shading = "phong";
   81|      1|    }
   82|       |
   83|       |    // lower-case shading because Blender (for example) writes "Phong"
   84|  1.40k|    for (size_t i = 0; i < shading.length(); ++i) {
  ------------------
  |  Branch (84:24): [True: 1.16k, False: 231]
  ------------------
   85|  1.16k|        shading[i] = static_cast<char>(tolower(static_cast<unsigned char>(shading[i])));
   86|  1.16k|    }
   87|    231|    std::string templateName;
   88|    231|    if(shading == "phong") {
  ------------------
  |  Branch (88:8): [True: 223, False: 8]
  ------------------
   89|    223|        templateName = "Material.FbxSurfacePhong";
   90|    223|    } else if(shading == "lambert") {
  ------------------
  |  Branch (90:15): [True: 6, False: 2]
  ------------------
   91|      6|        templateName = "Material.FbxSurfaceLambert";
   92|      6|    } else {
   93|      2|        DOMWarning("shading mode not recognized: " + shading,&element);
   94|      2|    }
   95|       |
   96|    231|    props = GetPropertyTable(doc,templateName,element,sc);
   97|       |
   98|       |    // resolve texture links
   99|    231|    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
  100|  1.62k|    for(const Connection* con : conns) {
  ------------------
  |  Branch (100:31): [True: 1.62k, False: 231]
  ------------------
  101|       |        // texture link to properties, not objects
  102|  1.62k|        if ( 0 == con->PropertyName().length()) {
  ------------------
  |  Branch (102:14): [True: 0, False: 1.62k]
  ------------------
  103|      0|            continue;
  104|      0|        }
  105|       |
  106|  1.62k|        const Object* const ob = con->SourceObject();
  107|  1.62k|        if(nullptr == ob) {
  ------------------
  |  Branch (107:12): [True: 0, False: 1.62k]
  ------------------
  108|      0|            DOMWarning("failed to read source object for texture link, ignoring",&element);
  109|      0|            continue;
  110|      0|        }
  111|       |
  112|  1.62k|        const Texture* const tex = dynamic_cast<const Texture*>(ob);
  113|  1.62k|        if(nullptr == tex) {
  ------------------
  |  Branch (113:12): [True: 266, False: 1.36k]
  ------------------
  114|    266|            const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
  115|    266|            if(!layeredTexture) {
  ------------------
  |  Branch (115:16): [True: 3, False: 263]
  ------------------
  116|      3|                DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
  117|      3|                continue;
  118|      3|            }
  119|    263|            const std::string& prop = con->PropertyName();
  120|    263|            if (layeredTextures.find(prop) != layeredTextures.end()) {
  ------------------
  |  Branch (120:17): [True: 261, False: 2]
  ------------------
  121|    261|                DOMWarning("duplicate layered texture link: " + prop,&element);
  122|    261|            }
  123|       |
  124|    263|            layeredTextures[prop] = layeredTexture;
  125|    263|            ((LayeredTexture*)layeredTexture)->fillTexture(doc);
  126|  1.36k|        } else {
  127|  1.36k|            const std::string& prop = con->PropertyName();
  128|  1.36k|            if (textures.find(prop) != textures.end()) {
  ------------------
  |  Branch (128:17): [True: 1.34k, False: 15]
  ------------------
  129|  1.34k|                DOMWarning("duplicate texture link: " + prop,&element);
  130|  1.34k|            }
  131|       |
  132|  1.36k|            textures[prop] = tex;
  133|  1.36k|        }
  134|  1.62k|    }
  135|    231|}
_ZN6Assimp3FBX7TextureC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  139|     11|        Object(id,element,name),
  140|     11|        uvTrans(0.0f, 0.0f),
  141|     11|        uvScaling(1.0f,1.0f),
  142|     11|        uvRotation(0.0f),
  143|     11|        type(),
  144|     11|        relativeFileName(),
  145|     11|        fileName(),
  146|     11|        alphaSource(),
  147|     11|        props(),
  148|     11|        media(nullptr) {
  149|     11|    const Scope& sc = GetRequiredScope(element);
  150|       |
  151|     11|    const Element* const Type = sc["Type"];
  152|     11|    const Element* const FileName = sc["FileName"];
  153|     11|    const Element* const RelativeFilename = sc["RelativeFilename"];
  154|     11|    const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
  155|     11|    const Element* const ModelUVScaling = sc["ModelUVScaling"];
  156|     11|    const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
  157|     11|    const Element* const Cropping = sc["Cropping"];
  158|       |
  159|     11|    if(Type) {
  ------------------
  |  Branch (159:8): [True: 11, False: 0]
  ------------------
  160|     11|        type = ParseTokenAsString(GetRequiredToken(*Type,0));
  161|     11|    }
  162|       |
  163|     11|    if(FileName) {
  ------------------
  |  Branch (163:8): [True: 11, False: 0]
  ------------------
  164|     11|        fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
  165|     11|    }
  166|       |
  167|     11|    if(RelativeFilename) {
  ------------------
  |  Branch (167:8): [True: 11, False: 0]
  ------------------
  168|     11|        relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
  169|     11|    }
  170|       |
  171|     11|    if(ModelUVTranslation) {
  ------------------
  |  Branch (171:8): [True: 11, False: 0]
  ------------------
  172|     11|        uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
  173|     11|            ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
  174|     11|        );
  175|     11|    }
  176|       |
  177|     11|    if(ModelUVScaling) {
  ------------------
  |  Branch (177:8): [True: 11, False: 0]
  ------------------
  178|     11|        uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
  179|     11|            ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
  180|     11|        );
  181|     11|    }
  182|       |
  183|     11|    if(Cropping) {
  ------------------
  |  Branch (183:8): [True: 11, False: 0]
  ------------------
  184|     11|        crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
  185|     11|        crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
  186|     11|        crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
  187|     11|        crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
  188|     11|    } else {
  189|       |        // vc8 doesn't support the crop() syntax in initialization lists
  190|       |        // (and vc9 WARNS about the new (i.e. compliant) behaviour).
  191|      0|        crop[0] = crop[1] = crop[2] = crop[3] = 0;
  192|      0|    }
  193|       |
  194|     11|    if(Texture_Alpha_Source) {
  ------------------
  |  Branch (194:8): [True: 11, False: 0]
  ------------------
  195|     11|        alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
  196|     11|    }
  197|       |
  198|     11|    props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
  199|       |
  200|       |    // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
  201|     11|    bool ok;
  202|     11|    const aiVector3D& scaling = PropertyGet<aiVector3D>(*props, "Scaling", ok);
  203|     11|    if (ok) {
  ------------------
  |  Branch (203:9): [True: 4, False: 7]
  ------------------
  204|      4|        uvScaling.x = scaling.x;
  205|      4|        uvScaling.y = scaling.y;
  206|      4|    }
  207|       |
  208|     11|    const aiVector3D& trans = PropertyGet<aiVector3D>(*props, "Translation", ok);
  209|     11|    if (ok) {
  ------------------
  |  Branch (209:9): [True: 4, False: 7]
  ------------------
  210|      4|        uvTrans.x = trans.x;
  211|      4|        uvTrans.y = trans.y;
  212|      4|    }
  213|       |
  214|     11|    const aiVector3D &rotation = PropertyGet<aiVector3D>(*props, "Rotation", ok);
  215|     11|    if (ok) {
  ------------------
  |  Branch (215:9): [True: 4, False: 7]
  ------------------
  216|      4|        uvRotation = rotation.z;
  217|      4|    }
  218|       |
  219|       |    // resolve video links
  220|     11|    if(doc.Settings().readTextures) {
  ------------------
  |  Branch (220:8): [True: 11, False: 0]
  ------------------
  221|     11|        const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
  222|  1.68k|        for(const Connection* con : conns) {
  ------------------
  |  Branch (222:35): [True: 1.68k, False: 11]
  ------------------
  223|  1.68k|            const Object* const ob = con->SourceObject();
  224|  1.68k|            if (nullptr == ob) {
  ------------------
  |  Branch (224:17): [True: 0, False: 1.68k]
  ------------------
  225|      0|                DOMWarning("failed to read source object for texture link, ignoring",&element);
  226|      0|                continue;
  227|      0|            }
  228|       |
  229|  1.68k|            const Video* const video = dynamic_cast<const Video*>(ob);
  230|  1.68k|            if(video) {
  ------------------
  |  Branch (230:16): [True: 1.68k, False: 0]
  ------------------
  231|  1.68k|                media = video;
  232|  1.68k|            }
  233|  1.68k|        }
  234|     11|    }
  235|     11|}
_ZN6Assimp3FBX7TextureD2Ev:
  238|     11|Texture::~Texture() = default;
_ZN6Assimp3FBX14LayeredTextureC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  241|      1|        Object(id,element,name),
  242|      1|        blendMode(BlendMode_Modulate),
  243|      1|        alpha(1) {
  244|      1|    const Scope& sc = GetRequiredScope(element);
  245|       |
  246|      1|    const Element* const BlendModes = sc["BlendModes"];
  247|      1|    const Element* const Alphas = sc["Alphas"];
  248|       |
  249|      1|    if (nullptr != BlendModes) {
  ------------------
  |  Branch (249:9): [True: 0, False: 1]
  ------------------
  250|      0|        blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
  251|      0|    }
  252|      1|    if (nullptr != Alphas) {
  ------------------
  |  Branch (252:9): [True: 0, False: 1]
  ------------------
  253|      0|        alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
  254|      0|    }
  255|      1|}
_ZN6Assimp3FBX14LayeredTextureD2Ev:
  257|      1|LayeredTexture::~LayeredTexture() = default;
_ZN6Assimp3FBX14LayeredTexture11fillTextureERKNS0_8DocumentE:
  259|    263|void LayeredTexture::fillTexture(const Document& doc) {
  260|    263|    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
  261|  69.1k|    for(size_t i = 0; i < conns.size();++i) {
  ------------------
  |  Branch (261:23): [True: 68.9k, False: 263]
  ------------------
  262|  68.9k|        const Connection* con = conns.at(i);
  263|       |
  264|  68.9k|        const Object* const ob = con->SourceObject();
  265|  68.9k|        if (nullptr == ob) {
  ------------------
  |  Branch (265:13): [True: 68.9k, False: 0]
  ------------------
  266|  68.9k|            DOMWarning("failed to read source object for texture link, ignoring",&element);
  267|  68.9k|            continue;
  268|  68.9k|        }
  269|       |
  270|      0|        const Texture* const tex = dynamic_cast<const Texture*>(ob);
  271|       |
  272|      0|        textures.push_back(tex);
  273|      0|    }
  274|    263|}
_ZN6Assimp3FBX5VideoC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  278|     10|        Object(id, element, name),
  279|     10|        contentLength(0),
  280|     10|        content(nullptr) {
  281|     10|    const Scope& sc = GetRequiredScope(element);
  282|       |
  283|     10|    const Element* const Type = sc["Type"];
  284|     10|    const Element* const FileName = sc.FindElementCaseInsensitive("FileName");  //some files retain the information as "Filename", others "FileName", who knows
  285|     10|    const Element* const RelativeFilename = sc["RelativeFilename"];
  286|     10|    const Element* const Content = sc["Content"];
  287|       |
  288|     10|    if(Type) {
  ------------------
  |  Branch (288:8): [True: 10, False: 0]
  ------------------
  289|     10|        type = ParseTokenAsString(GetRequiredToken(*Type,0));
  290|     10|    }
  291|       |
  292|     10|    if(FileName) {
  ------------------
  |  Branch (292:8): [True: 10, False: 0]
  ------------------
  293|     10|        fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
  294|     10|    }
  295|       |
  296|     10|    if(RelativeFilename) {
  ------------------
  |  Branch (296:8): [True: 10, False: 0]
  ------------------
  297|     10|        relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
  298|     10|    }
  299|       |
  300|     10|    if(Content && !Content->Tokens().empty()) {
  ------------------
  |  Branch (300:8): [True: 4, False: 6]
  |  Branch (300:19): [True: 4, False: 0]
  ------------------
  301|       |        //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
  302|      4|        try {
  303|      4|            const Token& token = GetRequiredToken(*Content, 0);
  304|      4|            const char* data = token.begin();
  305|      4|            if (!token.IsBinary()) {
  ------------------
  |  Branch (305:17): [True: 4, False: 0]
  ------------------
  306|      4|                if (*data != '"') {
  ------------------
  |  Branch (306:21): [True: 0, False: 4]
  ------------------
  307|      0|                    DOMError("embedded content is not surrounded by quotation marks", &element);
  308|      4|                } else {
  309|      4|                    size_t targetLength = 0;
  310|      4|                    auto numTokens = Content->Tokens().size();
  311|       |                    // First time compute size (it could be large like 64Gb and it is good to allocate it once)
  312|      8|                    for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
  ------------------
  |  Branch (312:49): [True: 4, False: 4]
  ------------------
  313|      4|                        const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
  314|      4|                        size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
  315|      4|                        const char* base64data = dataToken.begin() + 1;
  316|      4|                        const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
  317|      4|                        if (outLength == 0) {
  ------------------
  |  Branch (317:29): [True: 0, False: 4]
  ------------------
  318|      0|                            DOMError("Corrupted embedded content found", &element);
  319|      0|                        }
  320|      4|                        targetLength += outLength;
  321|      4|                    }
  322|      4|                    if (targetLength == 0) {
  ------------------
  |  Branch (322:25): [True: 0, False: 4]
  ------------------
  323|      0|                        DOMError("Corrupted embedded content found", &element);
  324|      0|                    }
  325|      4|                    content = new uint8_t[targetLength];
  326|      4|                    contentLength = static_cast<uint64_t>(targetLength);
  327|      4|                    size_t dst_offset = 0;
  328|      8|                    for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
  ------------------
  |  Branch (328:49): [True: 4, False: 4]
  ------------------
  329|      4|                        const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
  330|      4|                        size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
  331|      4|                        const char* base64data = dataToken.begin() + 1;
  332|      4|                        dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
  333|      4|                    }
  334|      4|                    if (targetLength != dst_offset) {
  ------------------
  |  Branch (334:25): [True: 3, False: 1]
  ------------------
  335|      3|                        delete[] content;
  336|      3|                        contentLength = 0;
  337|      3|                        DOMError("Corrupted embedded content found", &element);
  338|      3|                    }
  339|      4|                }
  340|      4|            } else if (static_cast<size_t>(token.end() - data) < 5) {
  ------------------
  |  Branch (340:24): [True: 0, False: 0]
  ------------------
  341|      0|                DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
  342|      0|            } else if (*data != 'R') {
  ------------------
  |  Branch (342:24): [True: 0, False: 0]
  ------------------
  343|      0|                DOMWarning("video content is not raw binary data, ignoring", &element);
  344|      0|            } else {
  345|       |                // read number of elements
  346|      0|                uint32_t len = 0;
  347|      0|                ::memcpy(&len, data + 1, sizeof(len));
  348|      0|                AI_SWAP4(len);
  349|       |
  350|      0|                contentLength = len;
  351|       |
  352|      0|                content = new uint8_t[len];
  353|      0|                ::memcpy(content, data + 5, len);
  354|      0|            }
  355|      4|        } catch (const runtime_error& runtimeError) {
  356|       |            //we don't need the content data for contents that has already been loaded
  357|      3|            ASSIMP_LOG_VERBOSE_DEBUG("Caught exception in FBXMaterial (likely because content was already loaded): ",
  358|      3|                    runtimeError.what());
  359|      3|        }
  360|      4|    }
  361|       |
  362|     10|    props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
  363|     10|}
_ZN6Assimp3FBX5VideoD2Ev:
  365|     10|Video::~Video() {
  366|     10|    if (contentLength > 0) {
  ------------------
  |  Branch (366:9): [True: 1, False: 9]
  ------------------
  367|      1|        delete[] content;
  368|      1|    }
  369|     10|}

_ZN6Assimp3FBX8GeometryC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentE:
   64|    243|        Object(id, element, name), skin() {
   65|    243|    const std::vector<const Connection*> &conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
   66|    243|    for(const Connection* con : conns) {
  ------------------
  |  Branch (66:31): [True: 215, False: 243]
  ------------------
   67|    215|        const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
   68|    215|        if(sk) {
  ------------------
  |  Branch (68:12): [True: 215, False: 0]
  ------------------
   69|    215|            skin = sk;
   70|    215|        }
   71|    215|        const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element);
   72|    215|        if (bsp) {
  ------------------
  |  Branch (72:13): [True: 0, False: 215]
  ------------------
   73|       |            // Only add a blendshape if it doesn't exist already
   74|      0|            if (std::find(blendShapes.begin(), blendShapes.end(), bsp) == blendShapes.end()) {
  ------------------
  |  Branch (74:17): [True: 0, False: 0]
  ------------------
   75|      0|                blendShapes.push_back(bsp);
   76|      0|            } else {
   77|      0|                FBXImporter::LogWarn("there is the same blendShape id ", bsp->ID());
   78|      0|            }
   79|      0|        }
   80|    215|    }
   81|    243|}
_ZNK6Assimp3FBX8Geometry14GetBlendShapesEv:
   84|     95|const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
   85|     95|    return blendShapes;
   86|     95|}
_ZNK6Assimp3FBX8Geometry12DeformerSkinEv:
   89|    274|const Skin* Geometry::DeformerSkin() const {
   90|    274|    return skin;
   91|    274|}
_ZN6Assimp3FBX12MeshGeometryC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentE:
   95|    243|: Geometry(id, element,name, doc)
   96|    243|{
   97|    243|    const Scope* sc = element.Compound();
   98|    243|    if (!sc) {
  ------------------
  |  Branch (98:9): [True: 0, False: 243]
  ------------------
   99|      0|        DOMError("failed to read Geometry object (class: Mesh), no data scope found");
  100|      0|    }
  101|       |
  102|       |    // must have Mesh elements:
  103|    243|    const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element);
  104|    243|    const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element);
  105|       |
  106|       |    // optional Mesh elements:
  107|    243|    const ElementCollection& Layer = sc->GetCollection("Layer");
  108|       |
  109|    243|    std::vector<aiVector3D> tempVerts;
  110|    243|    ParseVectorDataArray(tempVerts,Vertices);
  111|       |
  112|    243|    if(tempVerts.empty()) {
  ------------------
  |  Branch (112:8): [True: 0, False: 243]
  ------------------
  113|      0|        FBXImporter::LogWarn("encountered mesh with no vertices");
  114|      0|    }
  115|       |
  116|    243|    std::vector<int> tempFaces;
  117|    243|    ParseVectorDataArray(tempFaces,PolygonVertexIndex);
  118|       |
  119|    243|    if(tempFaces.empty()) {
  ------------------
  |  Branch (119:8): [True: 0, False: 243]
  ------------------
  120|      0|        FBXImporter::LogWarn("encountered mesh with no faces");
  121|      0|    }
  122|       |
  123|    243|    m_vertices.reserve(tempFaces.size());
  124|    243|    m_faces.reserve(tempFaces.size() / 3);
  125|       |
  126|    243|    m_mapping_offsets.resize(tempVerts.size());
  127|    243|    m_mapping_counts.resize(tempVerts.size(),0);
  128|    243|    m_mappings.resize(tempFaces.size());
  129|       |
  130|    243|    const size_t vertex_count = tempVerts.size();
  131|       |
  132|       |    // generate output vertices, computing an adjacency table to
  133|       |    // preserve the mapping from fbx indices to *this* indexing.
  134|    243|    unsigned int count = 0;
  135|   586k|    for(int index : tempFaces) {
  ------------------
  |  Branch (135:19): [True: 586k, False: 241]
  ------------------
  136|   586k|        const int absi = index < 0 ? (-index - 1) : index;
  ------------------
  |  Branch (136:26): [True: 105k, False: 480k]
  ------------------
  137|   586k|        if(static_cast<size_t>(absi) >= vertex_count) {
  ------------------
  |  Branch (137:12): [True: 2, False: 586k]
  ------------------
  138|      2|            DOMError("polygon vertex index out of range",&PolygonVertexIndex);
  139|      2|        }
  140|       |
  141|   586k|        m_vertices.push_back(tempVerts[absi]);
  142|   586k|        ++count;
  143|       |
  144|   586k|        ++m_mapping_counts[absi];
  145|       |
  146|   586k|        if (index < 0) {
  ------------------
  |  Branch (146:13): [True: 105k, False: 480k]
  ------------------
  147|   105k|            m_faces.push_back(count);
  148|   105k|            count = 0;
  149|   105k|        }
  150|   586k|    }
  151|       |
  152|    241|    unsigned int cursor = 0;
  153|   118k|    for (size_t i = 0, e = tempVerts.size(); i < e; ++i) {
  ------------------
  |  Branch (153:46): [True: 118k, False: 241]
  ------------------
  154|   118k|        m_mapping_offsets[i] = cursor;
  155|   118k|        cursor += m_mapping_counts[i];
  156|       |
  157|   118k|        m_mapping_counts[i] = 0;
  158|   118k|    }
  159|       |
  160|    241|    cursor = 0;
  161|   583k|    for(int index : tempFaces) {
  ------------------
  |  Branch (161:19): [True: 583k, False: 241]
  ------------------
  162|   583k|        const int absi = index < 0 ? (-index - 1) : index;
  ------------------
  |  Branch (162:26): [True: 105k, False: 477k]
  ------------------
  163|   583k|        m_mappings[m_mapping_offsets[absi] + m_mapping_counts[absi]++] = cursor++;
  164|   583k|    }
  165|       |
  166|       |    // if settings.readAllLayers is true:
  167|       |    //  * read all layers, try to load as many vertex channels as possible
  168|       |    // if settings.readAllLayers is false:
  169|       |    //  * read only the layer with index 0, but warn about any further layers
  170|    347|    for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) {
  ------------------
  |  Branch (170:55): [True: 106, False: 241]
  ------------------
  171|    106|        const TokenList& tokens = (*it).second->Tokens();
  172|       |
  173|    106|        const char* err;
  174|    106|        const int index = ParseTokenAsInt(*tokens[0], err);
  175|    106|        if(err) {
  ------------------
  |  Branch (175:12): [True: 0, False: 106]
  ------------------
  176|      0|            DOMError(err,&element);
  177|      0|        }
  178|       |
  179|    106|        if(doc.Settings().readAllLayers || index == 0) {
  ------------------
  |  Branch (179:12): [True: 106, False: 0]
  |  Branch (179:44): [True: 0, False: 0]
  ------------------
  180|    106|            const Scope& layer = GetRequiredScope(*(*it).second);
  181|    106|            ReadLayer(layer);
  182|    106|        } else {
  183|      0|            FBXImporter::LogWarn("ignoring additional geometry layers");
  184|      0|        }
  185|    106|    }
  186|    241|}
_ZNK6Assimp3FBX12MeshGeometry11GetVerticesEv:
  189|    190|const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
  190|    190|    return m_vertices;
  191|    190|}
_ZNK6Assimp3FBX12MeshGeometry10GetNormalsEv:
  194|     95|const std::vector<aiVector3D>& MeshGeometry::GetNormals() const {
  195|     95|    return m_normals;
  196|     95|}
_ZNK6Assimp3FBX12MeshGeometry11GetTangentsEv:
  199|     95|const std::vector<aiVector3D>& MeshGeometry::GetTangents() const {
  200|     95|    return m_tangents;
  201|     95|}
_ZNK6Assimp3FBX12MeshGeometry12GetBinormalsEv:
  204|     95|const std::vector<aiVector3D>& MeshGeometry::GetBinormals() const {
  205|     95|    return m_binormals;
  206|     95|}
_ZNK6Assimp3FBX12MeshGeometry18GetFaceIndexCountsEv:
  209|    190|const std::vector<unsigned int>& MeshGeometry::GetFaceIndexCounts() const {
  210|    190|    return m_faces;
  211|    190|}
_ZNK6Assimp3FBX12MeshGeometry16GetTextureCoordsEj:
  214|    179|const std::vector<aiVector2D>& MeshGeometry::GetTextureCoords( unsigned int index ) const {
  215|    179|    static const std::vector<aiVector2D> empty;
  216|    179|    return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[ index ];
  ------------------
  |  Branch (216:12): [True: 0, False: 179]
  ------------------
  217|    179|}
_ZNK6Assimp3FBX12MeshGeometry26GetTextureCoordChannelNameEj:
  219|     84|std::string MeshGeometry::GetTextureCoordChannelName( unsigned int index ) const {
  220|     84|    return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[ index ];
  ------------------
  |  Branch (220:12): [True: 0, False: 84]
  ------------------
  221|     84|}
_ZNK6Assimp3FBX12MeshGeometry15GetVertexColorsEj:
  223|     95|const std::vector<aiColor4D>& MeshGeometry::GetVertexColors( unsigned int index ) const {
  224|     95|    static const std::vector<aiColor4D> empty;
  225|     95|    return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[ index ];
  ------------------
  |  Branch (225:12): [True: 0, False: 95]
  ------------------
  226|     95|}
_ZNK6Assimp3FBX12MeshGeometry18GetMaterialIndicesEv:
  228|    889|const MatIndexArray& MeshGeometry::GetMaterialIndices() const {
  229|    889|    return m_materials;
  230|    889|}
_ZNK6Assimp3FBX12MeshGeometry19ToOutputVertexIndexEjRj:
  232|   243k|const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const {
  233|   243k|    if ( in_index >= m_mapping_counts.size() ) {
  ------------------
  |  Branch (233:10): [True: 0, False: 243k]
  ------------------
  234|      0|        return nullptr;
  235|      0|    }
  236|       |
  237|   243k|    ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() );
  238|   243k|    count = m_mapping_counts[ in_index ];
  239|       |
  240|   243k|    ai_assert( m_mapping_offsets[ in_index ] + count <= m_mappings.size() );
  241|       |
  242|   243k|    return &m_mappings[ m_mapping_offsets[ in_index ] ];
  243|   243k|}
_ZN6Assimp3FBX12MeshGeometry9ReadLayerERKNS0_5ScopeE:
  270|    106|{
  271|    106|    const ElementCollection& LayerElement = layer.GetCollection("LayerElement");
  272|    563|    for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) {
  ------------------
  |  Branch (272:63): [True: 457, False: 106]
  ------------------
  273|    457|        const Scope& elayer = GetRequiredScope(*(*eit).second);
  274|       |
  275|    457|        ReadLayerElement(elayer);
  276|    457|    }
  277|    106|}
_ZN6Assimp3FBX12MeshGeometry16ReadLayerElementERKNS0_5ScopeE:
  282|    457|{
  283|    457|    const Element& Type = GetRequiredElement(layerElement,"Type");
  284|    457|    const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex");
  285|       |
  286|    457|    const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0));
  287|    457|    const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0));
  288|       |
  289|    457|    const Scope& top = GetRequiredScope(element);
  290|    457|    const ElementCollection candidates = top.GetCollection(type);
  291|       |
  292|    460|    for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) {
  ------------------
  |  Branch (292:60): [True: 306, False: 154]
  ------------------
  293|    306|        const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0));
  294|    306|        if(index == typedIndex) {
  ------------------
  |  Branch (294:12): [True: 303, False: 3]
  ------------------
  295|    303|            ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second));
  296|    303|            return;
  297|    303|        }
  298|    306|    }
  299|       |
  300|    154|    FBXImporter::LogError("failed to resolve vertex layer element: ",
  301|    154|        type, ", index: ", typedIndex);
  302|    154|}
_ZN6Assimp3FBX12MeshGeometry14ReadVertexDataERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiRKNS0_5ScopeE:
  306|    303|{
  307|    303|    const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken(
  308|    303|        GetRequiredElement(source,"MappingInformationType"),0)
  309|    303|    );
  310|       |
  311|    303|    const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken(
  312|    303|        GetRequiredElement(source,"ReferenceInformationType"),0)
  313|    303|    );
  314|       |
  315|    303|    if (type == "LayerElementUV") {
  ------------------
  |  Branch (315:9): [True: 85, False: 218]
  ------------------
  316|     85|        if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
  ------------------
  |  Branch (316:12): [True: 0, False: 85]
  ------------------
  317|      0|            FBXImporter::LogError("ignoring UV layer, maximum number of UV channels exceeded: ",
  318|      0|                index, " (limit is ", AI_MAX_NUMBER_OF_TEXTURECOORDS, ")" );
  319|      0|            return;
  320|      0|        }
  321|       |
  322|     85|        const Element* Name = source["Name"];
  323|     85|        m_uvNames[index] = std::string();
  324|     85|        if(Name) {
  ------------------
  |  Branch (324:12): [True: 85, False: 0]
  ------------------
  325|     85|            m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0));
  326|     85|        }
  327|       |
  328|     85|        ReadVertexDataUV(m_uvs[index],source,
  329|     85|            MappingInformationType,
  330|     85|            ReferenceInformationType
  331|     85|        );
  332|     85|    }
  333|    218|    else if (type == "LayerElementMaterial") {
  ------------------
  |  Branch (333:14): [True: 91, False: 127]
  ------------------
  334|     91|        if (m_materials.size() > 0) {
  ------------------
  |  Branch (334:13): [True: 0, False: 91]
  ------------------
  335|      0|            FBXImporter::LogError("ignoring additional material layer");
  336|      0|            return;
  337|      0|        }
  338|       |
  339|     91|        std::vector<int> temp_materials;
  340|       |
  341|     91|        ReadVertexDataMaterials(temp_materials,source,
  342|     91|            MappingInformationType,
  343|     91|            ReferenceInformationType
  344|     91|        );
  345|       |
  346|       |        // sometimes, there will be only negative entries. Drop the material
  347|       |        // layer in such a case (I guess it means a default material should
  348|       |        // be used). This is what the converter would do anyway, and it
  349|       |        // avoids losing the material if there are more material layers
  350|       |        // coming of which at least one contains actual data (did observe
  351|       |        // that with one test file).
  352|     91|        const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; });
  353|     91|        if(count_neg == temp_materials.size()) {
  ------------------
  |  Branch (353:12): [True: 0, False: 91]
  ------------------
  354|      0|            FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)");
  355|      0|            return;
  356|      0|        }
  357|       |
  358|     91|        std::swap(temp_materials, m_materials);
  359|     91|    }
  360|    127|    else if (type == "LayerElementNormal") {
  ------------------
  |  Branch (360:14): [True: 40, False: 87]
  ------------------
  361|     40|        if (m_normals.size() > 0) {
  ------------------
  |  Branch (361:13): [True: 0, False: 40]
  ------------------
  362|      0|            FBXImporter::LogError("ignoring additional normal layer");
  363|      0|            return;
  364|      0|        }
  365|       |
  366|     40|        ReadVertexDataNormals(m_normals,source,
  367|     40|            MappingInformationType,
  368|     40|            ReferenceInformationType
  369|     40|        );
  370|     40|    }
  371|     87|    else if (type == "LayerElementTangent") {
  ------------------
  |  Branch (371:14): [True: 6, False: 81]
  ------------------
  372|      6|        if (m_tangents.size() > 0) {
  ------------------
  |  Branch (372:13): [True: 1, False: 5]
  ------------------
  373|      1|            FBXImporter::LogError("ignoring additional tangent layer");
  374|      1|            return;
  375|      1|        }
  376|       |
  377|      5|        ReadVertexDataTangents(m_tangents,source,
  378|      5|            MappingInformationType,
  379|      5|            ReferenceInformationType
  380|      5|        );
  381|      5|    }
  382|     81|    else if (type == "LayerElementBinormal") {
  ------------------
  |  Branch (382:14): [True: 74, False: 7]
  ------------------
  383|     74|        if (m_binormals.size() > 0) {
  ------------------
  |  Branch (383:13): [True: 1, False: 73]
  ------------------
  384|      1|            FBXImporter::LogError("ignoring additional binormal layer");
  385|      1|            return;
  386|      1|        }
  387|       |
  388|     73|        ReadVertexDataBinormals(m_binormals,source,
  389|     73|            MappingInformationType,
  390|     73|            ReferenceInformationType
  391|     73|        );
  392|     73|    }
  393|      7|    else if (type == "LayerElementColor") {
  ------------------
  |  Branch (393:14): [True: 0, False: 7]
  ------------------
  394|      0|        if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) {
  ------------------
  |  Branch (394:12): [True: 0, False: 0]
  ------------------
  395|      0|            FBXImporter::LogError("ignoring vertex color layer, maximum number of color sets exceeded: ",
  396|      0|                index, " (limit is ", AI_MAX_NUMBER_OF_COLOR_SETS, ")" );
  397|      0|            return;
  398|      0|        }
  399|       |
  400|      0|        ReadVertexDataColors(m_colors[index],source,
  401|      0|            MappingInformationType,
  402|      0|            ReferenceInformationType
  403|      0|        );
  404|      0|    }
  405|    303|}
_ZN6Assimp3FBX12MeshGeometry21ReadVertexDataNormalsERNSt3__16vectorI10aiVector3tIfENS2_9allocatorIS5_EEEERKNS0_5ScopeERKNS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEESJ_:
  562|     40|{
  563|     40|    ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType,
  564|     40|        "Normals",
  565|     40|        "NormalsIndex",
  566|     40|        m_vertices.size(),
  567|     40|        m_mapping_counts,
  568|     40|        m_mapping_offsets,
  569|     40|        m_mappings);
  570|     40|}
_ZN6Assimp3FBX12MeshGeometry16ReadVertexDataUVERNSt3__16vectorI10aiVector2tIfENS2_9allocatorIS5_EEEERKNS0_5ScopeERKNS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEESJ_:
  576|     85|{
  577|     85|    ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType,
  578|     85|        "UV",
  579|     85|        "UVIndex",
  580|     85|        m_vertices.size(),
  581|     85|        m_mapping_counts,
  582|     85|        m_mapping_offsets,
  583|     85|        m_mappings);
  584|     85|}
_ZN6Assimp3FBX12MeshGeometry22ReadVertexDataTangentsERNSt3__16vectorI10aiVector3tIfENS2_9allocatorIS5_EEEERKNS0_5ScopeERKNS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEESJ_:
  607|      5|{
  608|      5|    const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
  ------------------
  |  Branch (608:24): [True: 5, False: 0]
  ------------------
  609|      5|    const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken;
  ------------------
  |  Branch (609:27): [True: 5, False: 0]
  ------------------
  610|      5|    ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
  611|      5|        str,
  612|      5|        strIdx,
  613|      5|        m_vertices.size(),
  614|      5|        m_mapping_counts,
  615|      5|        m_mapping_offsets,
  616|      5|        m_mappings);
  617|      5|}
_ZN6Assimp3FBX12MeshGeometry23ReadVertexDataBinormalsERNSt3__16vectorI10aiVector3tIfENS2_9allocatorIS5_EEEERKNS0_5ScopeERKNS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEESJ_:
  626|     73|{
  627|     73|    const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal";
  ------------------
  |  Branch (627:24): [True: 73, False: 0]
  ------------------
  628|     73|    const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken : BinormalIndexToken;
  ------------------
  |  Branch (628:27): [True: 73, False: 0]
  ------------------
  629|     73|    ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType,
  630|     73|        str,
  631|     73|        strIdx,
  632|     73|        m_vertices.size(),
  633|     73|        m_mapping_counts,
  634|     73|        m_mapping_offsets,
  635|     73|        m_mappings);
  636|     73|}
_ZN6Assimp3FBX12MeshGeometry23ReadVertexDataMaterialsERNSt3__16vectorIiNS2_9allocatorIiEEEERKNS0_5ScopeERKNS2_12basic_stringIcNS2_11char_traitsIcEENS4_IcEEEESH_:
  643|     91|{
  644|     91|    const size_t face_count = m_faces.size();
  645|     91|    if( 0 == face_count )
  ------------------
  |  Branch (645:9): [True: 0, False: 91]
  ------------------
  646|      0|    {
  647|      0|        return;
  648|      0|    }
  649|       |
  650|     91|    if (source["Materials"]) {
  ------------------
  |  Branch (650:9): [True: 91, False: 0]
  ------------------
  651|       |        // materials are handled separately. First of all, they are assigned per-face
  652|       |        // and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
  653|       |        // has a slightly different meaning for materials.
  654|     91|        ParseVectorDataArray(materials_out, GetRequiredElement(source, "Materials"));
  655|     91|    }
  656|       |
  657|     91|    if (MappingInformationType == "AllSame") {
  ------------------
  |  Branch (657:9): [True: 91, False: 0]
  ------------------
  658|       |        // easy - same material for all faces
  659|     91|        if (materials_out.empty()) {
  ------------------
  |  Branch (659:13): [True: 0, False: 91]
  ------------------
  660|      0|            FBXImporter::LogError("expected material index, ignoring");
  661|      0|            return;
  662|     91|        } else if (materials_out.size() > 1) {
  ------------------
  |  Branch (662:20): [True: 0, False: 91]
  ------------------
  663|      0|            FBXImporter::LogWarn("expected only a single material index, ignoring all except the first one");
  664|      0|            materials_out.clear();
  665|      0|        }
  666|       |
  667|     91|        materials_out.resize(m_vertices.size());
  668|     91|        std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0));
  669|     91|    } else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
  ------------------
  |  Branch (669:16): [True: 0, False: 0]
  |  Branch (669:57): [True: 0, False: 0]
  ------------------
  670|      0|        materials_out.resize(face_count);
  671|       |
  672|      0|        if(materials_out.size() != face_count) {
  ------------------
  |  Branch (672:12): [True: 0, False: 0]
  ------------------
  673|      0|            FBXImporter::LogError("length of input data unexpected for ByPolygon mapping: ",
  674|      0|                materials_out.size(), ", expected ", face_count
  675|      0|            );
  676|      0|            return;
  677|      0|        }
  678|      0|    } else {
  679|      0|        FBXImporter::LogError("ignoring material assignments, access type not implemented: ",
  680|      0|            MappingInformationType, ",", ReferenceInformationType);
  681|      0|    }
  682|     91|}
FBXMeshGeometry.cpp:_ZZN6Assimp3FBX12MeshGeometry14ReadVertexDataERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEiRKNS0_5ScopeEENK3$_0clEi:
  352|   347k|        const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; });
_ZN6Assimp3FBX22ResolveVertexDataArrayI10aiVector3tIfEEEvRNSt3__16vectorIT_NS4_9allocatorIS6_EEEERKNS0_5ScopeERKNS4_12basic_stringIcNS4_11char_traitsIcEENS7_IcEEEESK_PKcSM_mRKNS5_IjNS7_IjEEEESQ_SQ_:
  421|    118|{
  422|    118|    bool isDirect = ReferenceInformationType == "Direct";
  423|    118|    bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
  424|    118|    const bool hasDataElement = HasElement(source, dataElementName);
  425|    118|    const bool hasIndexDataElement = HasElement(source, indexDataElementName);
  426|       |
  427|       |    // fall-back to direct data if there is no index data element
  428|    118|    if (isIndexToDirect && !hasIndexDataElement) {
  ------------------
  |  Branch (428:9): [True: 0, False: 118]
  |  Branch (428:28): [True: 0, False: 0]
  ------------------
  429|      0|        isDirect = true;
  430|      0|        isIndexToDirect = false;
  431|      0|    }
  432|       |
  433|       |    // handle permutations of Mapping and Reference type - it would be nice to
  434|       |    // deal with this more elegantly and with less redundancy, but right
  435|       |    // now it seems unavoidable.
  436|    118|    if (MappingInformationType == "ByVertice" && isDirect) {
  ------------------
  |  Branch (436:9): [True: 0, False: 118]
  |  Branch (436:50): [True: 0, False: 0]
  ------------------
  437|      0|        if (!hasDataElement) {
  ------------------
  |  Branch (437:13): [True: 0, False: 0]
  ------------------
  438|      0|            FBXImporter::LogWarn("missing data element: ", dataElementName);
  439|      0|            return;
  440|      0|        }
  441|      0|        std::vector<T> tempData;
  442|      0|        ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
  443|       |
  444|      0|        if (tempData.size() != mapping_offsets.size()) {
  ------------------
  |  Branch (444:13): [True: 0, False: 0]
  ------------------
  445|      0|            FBXImporter::LogError("length of input data unexpected for ByVertice mapping: ",
  446|      0|                                  tempData.size(), ", expected ", mapping_offsets.size());
  447|      0|            return;
  448|      0|        }
  449|       |
  450|      0|        data_out.resize(vertex_count);
  451|      0|        for (size_t i = 0, e = tempData.size(); i < e; ++i) {
  ------------------
  |  Branch (451:49): [True: 0, False: 0]
  ------------------
  452|      0|            const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
  453|      0|            for (unsigned int j = istart; j < iend; ++j) {
  ------------------
  |  Branch (453:43): [True: 0, False: 0]
  ------------------
  454|      0|                data_out[mappings[j]] = tempData[i];
  455|      0|            }
  456|      0|        }
  457|      0|    }
  458|    118|    else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
  ------------------
  |  Branch (458:14): [True: 0, False: 118]
  |  Branch (458:55): [True: 0, False: 0]
  ------------------
  459|      0|		std::vector<T> tempData;
  460|      0|        if (!hasDataElement || !hasIndexDataElement) {
  ------------------
  |  Branch (460:13): [True: 0, False: 0]
  |  Branch (460:32): [True: 0, False: 0]
  ------------------
  461|      0|            if (!hasDataElement)
  ------------------
  |  Branch (461:17): [True: 0, False: 0]
  ------------------
  462|      0|                FBXImporter::LogWarn("missing data element: ", dataElementName);
  463|      0|            if (!hasIndexDataElement)
  ------------------
  |  Branch (463:17): [True: 0, False: 0]
  ------------------
  464|      0|                FBXImporter::LogWarn("missing index data element: ", indexDataElementName);
  465|      0|            return;
  466|      0|        }
  467|       |
  468|      0|        ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
  469|       |
  470|      0|        std::vector<int> uvIndices;
  471|      0|        ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
  472|       |
  473|      0|        if (uvIndices.size() != mapping_offsets.size()) {
  ------------------
  |  Branch (473:13): [True: 0, False: 0]
  ------------------
  474|      0|            FBXImporter::LogError("length of input data unexpected for ByVertice mapping: ",
  475|      0|                                  uvIndices.size(), ", expected ", mapping_offsets.size());
  476|      0|            return;
  477|      0|        }
  478|       |
  479|      0|        data_out.resize(vertex_count);
  480|       |
  481|      0|        for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
  ------------------
  |  Branch (481:50): [True: 0, False: 0]
  ------------------
  482|       |
  483|      0|            const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
  484|      0|            for (unsigned int j = istart; j < iend; ++j) {
  ------------------
  |  Branch (484:43): [True: 0, False: 0]
  ------------------
  485|      0|				if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) {
  ------------------
  |  Branch (485:9): [True: 0, False: 0]
  ------------------
  486|      0|                    DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
  487|      0|                }
  488|      0|				data_out[mappings[j]] = tempData[uvIndices[i]];
  489|      0|            }
  490|      0|        }
  491|      0|    }
  492|    118|    else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
  ------------------
  |  Branch (492:14): [True: 118, False: 0]
  |  Branch (492:61): [True: 50, False: 68]
  ------------------
  493|     50|        if (!hasDataElement) {
  ------------------
  |  Branch (493:13): [True: 1, False: 49]
  ------------------
  494|      1|            FBXImporter::LogWarn("missing data element: ", dataElementName);
  495|      1|            return;
  496|      1|        }
  497|       |
  498|     49|		std::vector<T> tempData;
  499|     49|		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
  500|       |
  501|     49|		if (tempData.size() != vertex_count) {
  ------------------
  |  Branch (501:7): [True: 1, False: 48]
  ------------------
  502|      1|            FBXImporter::LogError("length of input data unexpected for ByPolygon mapping: ",
  503|      1|				tempData.size(), ", expected ", vertex_count
  504|      1|            );
  505|      1|            return;
  506|      1|        }
  507|       |
  508|     48|		data_out.swap(tempData);
  509|     48|    }
  510|     68|    else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
  ------------------
  |  Branch (510:14): [True: 68, False: 0]
  |  Branch (510:61): [True: 0, False: 68]
  ------------------
  511|      0|		std::vector<T> tempData;
  512|      0|        if (!hasDataElement || !hasIndexDataElement) {
  ------------------
  |  Branch (512:13): [True: 0, False: 0]
  |  Branch (512:32): [True: 0, False: 0]
  ------------------
  513|      0|            if (!hasDataElement)
  ------------------
  |  Branch (513:17): [True: 0, False: 0]
  ------------------
  514|      0|                FBXImporter::LogWarn("missing data element: ", dataElementName);
  515|      0|            if (!hasIndexDataElement)
  ------------------
  |  Branch (515:17): [True: 0, False: 0]
  ------------------
  516|      0|                FBXImporter::LogWarn("missing index data element: ", indexDataElementName);
  517|      0|            return;
  518|      0|        }
  519|      0|        ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
  520|       |
  521|      0|        std::vector<int> uvIndices;
  522|      0|        ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
  523|       |
  524|      0|        if (uvIndices.size() > vertex_count) {
  ------------------
  |  Branch (524:13): [True: 0, False: 0]
  ------------------
  525|      0|            FBXImporter::LogWarn("trimming length of input array for ByPolygonVertex mapping: ",
  526|      0|                                          uvIndices.size(), ", expected ", vertex_count);
  527|      0|            uvIndices.resize(vertex_count);
  528|      0|        }
  529|       |
  530|      0|        if (uvIndices.size() != vertex_count) {
  ------------------
  |  Branch (530:13): [True: 0, False: 0]
  ------------------
  531|      0|            FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping: ",
  532|      0|                                  uvIndices.size(), ", expected ", vertex_count);
  533|      0|            return;
  534|      0|        }
  535|       |
  536|      0|        data_out.resize(vertex_count);
  537|       |
  538|      0|        const T empty;
  539|      0|        unsigned int next = 0;
  540|      0|        for(int i : uvIndices) {
  ------------------
  |  Branch (540:19): [True: 0, False: 0]
  ------------------
  541|      0|            if ( -1 == i ) {
  ------------------
  |  Branch (541:18): [True: 0, False: 0]
  ------------------
  542|      0|                data_out[ next++ ] = empty;
  543|      0|                continue;
  544|      0|            }
  545|      0|            if (static_cast<size_t>(i) >= tempData.size()) {
  ------------------
  |  Branch (545:17): [True: 0, False: 0]
  ------------------
  546|      0|                DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
  547|      0|            }
  548|       |
  549|      0|			data_out[next++] = tempData[i];
  550|      0|        }
  551|      0|    }
  552|     68|    else {
  553|     68|        FBXImporter::LogError("ignoring vertex data channel, access type not implemented: ",
  554|     68|            MappingInformationType, ",", ReferenceInformationType);
  555|     68|    }
  556|    118|}
_ZN6Assimp3FBX22ResolveVertexDataArrayI10aiVector2tIfEEEvRNSt3__16vectorIT_NS4_9allocatorIS6_EEEERKNS0_5ScopeERKNS4_12basic_stringIcNS4_11char_traitsIcEENS7_IcEEEESK_PKcSM_mRKNS5_IjNS7_IjEEEESQ_SQ_:
  421|     85|{
  422|     85|    bool isDirect = ReferenceInformationType == "Direct";
  423|     85|    bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
  424|     85|    const bool hasDataElement = HasElement(source, dataElementName);
  425|     85|    const bool hasIndexDataElement = HasElement(source, indexDataElementName);
  426|       |
  427|       |    // fall-back to direct data if there is no index data element
  428|     85|    if (isIndexToDirect && !hasIndexDataElement) {
  ------------------
  |  Branch (428:9): [True: 85, False: 0]
  |  Branch (428:28): [True: 1, False: 84]
  ------------------
  429|      1|        isDirect = true;
  430|      1|        isIndexToDirect = false;
  431|      1|    }
  432|       |
  433|       |    // handle permutations of Mapping and Reference type - it would be nice to
  434|       |    // deal with this more elegantly and with less redundancy, but right
  435|       |    // now it seems unavoidable.
  436|     85|    if (MappingInformationType == "ByVertice" && isDirect) {
  ------------------
  |  Branch (436:9): [True: 0, False: 85]
  |  Branch (436:50): [True: 0, False: 0]
  ------------------
  437|      0|        if (!hasDataElement) {
  ------------------
  |  Branch (437:13): [True: 0, False: 0]
  ------------------
  438|      0|            FBXImporter::LogWarn("missing data element: ", dataElementName);
  439|      0|            return;
  440|      0|        }
  441|      0|        std::vector<T> tempData;
  442|      0|        ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
  443|       |
  444|      0|        if (tempData.size() != mapping_offsets.size()) {
  ------------------
  |  Branch (444:13): [True: 0, False: 0]
  ------------------
  445|      0|            FBXImporter::LogError("length of input data unexpected for ByVertice mapping: ",
  446|      0|                                  tempData.size(), ", expected ", mapping_offsets.size());
  447|      0|            return;
  448|      0|        }
  449|       |
  450|      0|        data_out.resize(vertex_count);
  451|      0|        for (size_t i = 0, e = tempData.size(); i < e; ++i) {
  ------------------
  |  Branch (451:49): [True: 0, False: 0]
  ------------------
  452|      0|            const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
  453|      0|            for (unsigned int j = istart; j < iend; ++j) {
  ------------------
  |  Branch (453:43): [True: 0, False: 0]
  ------------------
  454|      0|                data_out[mappings[j]] = tempData[i];
  455|      0|            }
  456|      0|        }
  457|      0|    }
  458|     85|    else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
  ------------------
  |  Branch (458:14): [True: 0, False: 85]
  |  Branch (458:55): [True: 0, False: 0]
  ------------------
  459|      0|		std::vector<T> tempData;
  460|      0|        if (!hasDataElement || !hasIndexDataElement) {
  ------------------
  |  Branch (460:13): [True: 0, False: 0]
  |  Branch (460:32): [True: 0, False: 0]
  ------------------
  461|      0|            if (!hasDataElement)
  ------------------
  |  Branch (461:17): [True: 0, False: 0]
  ------------------
  462|      0|                FBXImporter::LogWarn("missing data element: ", dataElementName);
  463|      0|            if (!hasIndexDataElement)
  ------------------
  |  Branch (463:17): [True: 0, False: 0]
  ------------------
  464|      0|                FBXImporter::LogWarn("missing index data element: ", indexDataElementName);
  465|      0|            return;
  466|      0|        }
  467|       |
  468|      0|        ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
  469|       |
  470|      0|        std::vector<int> uvIndices;
  471|      0|        ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
  472|       |
  473|      0|        if (uvIndices.size() != mapping_offsets.size()) {
  ------------------
  |  Branch (473:13): [True: 0, False: 0]
  ------------------
  474|      0|            FBXImporter::LogError("length of input data unexpected for ByVertice mapping: ",
  475|      0|                                  uvIndices.size(), ", expected ", mapping_offsets.size());
  476|      0|            return;
  477|      0|        }
  478|       |
  479|      0|        data_out.resize(vertex_count);
  480|       |
  481|      0|        for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
  ------------------
  |  Branch (481:50): [True: 0, False: 0]
  ------------------
  482|       |
  483|      0|            const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
  484|      0|            for (unsigned int j = istart; j < iend; ++j) {
  ------------------
  |  Branch (484:43): [True: 0, False: 0]
  ------------------
  485|      0|				if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) {
  ------------------
  |  Branch (485:9): [True: 0, False: 0]
  ------------------
  486|      0|                    DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
  487|      0|                }
  488|      0|				data_out[mappings[j]] = tempData[uvIndices[i]];
  489|      0|            }
  490|      0|        }
  491|      0|    }
  492|     85|    else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
  ------------------
  |  Branch (492:14): [True: 85, False: 0]
  |  Branch (492:61): [True: 1, False: 84]
  ------------------
  493|      1|        if (!hasDataElement) {
  ------------------
  |  Branch (493:13): [True: 0, False: 1]
  ------------------
  494|      0|            FBXImporter::LogWarn("missing data element: ", dataElementName);
  495|      0|            return;
  496|      0|        }
  497|       |
  498|      1|		std::vector<T> tempData;
  499|      1|		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
  500|       |
  501|      1|		if (tempData.size() != vertex_count) {
  ------------------
  |  Branch (501:7): [True: 1, False: 0]
  ------------------
  502|      1|            FBXImporter::LogError("length of input data unexpected for ByPolygon mapping: ",
  503|      1|				tempData.size(), ", expected ", vertex_count
  504|      1|            );
  505|      1|            return;
  506|      1|        }
  507|       |
  508|      0|		data_out.swap(tempData);
  509|      0|    }
  510|     84|    else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
  ------------------
  |  Branch (510:14): [True: 84, False: 0]
  |  Branch (510:61): [True: 84, False: 0]
  ------------------
  511|     84|		std::vector<T> tempData;
  512|     84|        if (!hasDataElement || !hasIndexDataElement) {
  ------------------
  |  Branch (512:13): [True: 0, False: 84]
  |  Branch (512:32): [True: 0, False: 84]
  ------------------
  513|      0|            if (!hasDataElement)
  ------------------
  |  Branch (513:17): [True: 0, False: 0]
  ------------------
  514|      0|                FBXImporter::LogWarn("missing data element: ", dataElementName);
  515|      0|            if (!hasIndexDataElement)
  ------------------
  |  Branch (515:17): [True: 0, False: 0]
  ------------------
  516|      0|                FBXImporter::LogWarn("missing index data element: ", indexDataElementName);
  517|      0|            return;
  518|      0|        }
  519|     84|        ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
  520|       |
  521|     84|        std::vector<int> uvIndices;
  522|     84|        ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
  523|       |
  524|     84|        if (uvIndices.size() > vertex_count) {
  ------------------
  |  Branch (524:13): [True: 1, False: 83]
  ------------------
  525|      1|            FBXImporter::LogWarn("trimming length of input array for ByPolygonVertex mapping: ",
  526|      1|                                          uvIndices.size(), ", expected ", vertex_count);
  527|      1|            uvIndices.resize(vertex_count);
  528|      1|        }
  529|       |
  530|     84|        if (uvIndices.size() != vertex_count) {
  ------------------
  |  Branch (530:13): [True: 0, False: 84]
  ------------------
  531|      0|            FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping: ",
  532|      0|                                  uvIndices.size(), ", expected ", vertex_count);
  533|      0|            return;
  534|      0|        }
  535|       |
  536|     84|        data_out.resize(vertex_count);
  537|       |
  538|     84|        const T empty;
  539|     84|        unsigned int next = 0;
  540|   305k|        for(int i : uvIndices) {
  ------------------
  |  Branch (540:19): [True: 305k, False: 84]
  ------------------
  541|   305k|            if ( -1 == i ) {
  ------------------
  |  Branch (541:18): [True: 0, False: 305k]
  ------------------
  542|      0|                data_out[ next++ ] = empty;
  543|      0|                continue;
  544|      0|            }
  545|   305k|            if (static_cast<size_t>(i) >= tempData.size()) {
  ------------------
  |  Branch (545:17): [True: 0, False: 305k]
  ------------------
  546|      0|                DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
  547|      0|            }
  548|       |
  549|   305k|			data_out[next++] = tempData[i];
  550|   305k|        }
  551|     84|    }
  552|      0|    else {
  553|      0|        FBXImporter::LogError("ignoring vertex data channel, access type not implemented: ",
  554|      0|            MappingInformationType, ",", ReferenceInformationType);
  555|      0|    }
  556|     85|}

_ZN6Assimp3FBX8GeometryD2Ev:
   67|    243|    virtual ~Geometry() = default;
_ZN6Assimp3FBX12MeshGeometryD2Ev:
   98|     96|    virtual ~MeshGeometry() = default;

_ZN6Assimp3FBX5ModelC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   61|  4.60k|        Object(id, element, name), shading("Y") {
   62|  4.60k|    const Scope &sc = GetRequiredScope(element);
   63|  4.60k|    const Element *const Shading = sc["Shading"];
   64|  4.60k|    const Element *const Culling = sc["Culling"];
   65|       |
   66|  4.60k|    if (Shading) {
  ------------------
  |  Branch (66:9): [True: 4.58k, False: 14]
  ------------------
   67|  4.58k|        shading = GetRequiredToken(*Shading, 0).StringContents();
   68|  4.58k|    }
   69|       |
   70|  4.60k|    if (Culling) {
  ------------------
  |  Branch (70:9): [True: 4.58k, False: 16]
  ------------------
   71|  4.58k|        culling = ParseTokenAsString(GetRequiredToken(*Culling, 0));
   72|  4.58k|    }
   73|       |
   74|  4.60k|    props = GetPropertyTable(doc, "Model.FbxNode", element, sc);
   75|  4.60k|    ResolveLinks(element, doc);
   76|  4.60k|}
_ZN6Assimp3FBX5Model12ResolveLinksERKNS0_7ElementERKNS0_8DocumentE:
   79|  4.59k|void Model::ResolveLinks(const Element&, const Document &doc) {
   80|  4.59k|    const char *const arr[] = { "Geometry", "Material", "NodeAttribute" };
   81|       |
   82|       |    // resolve material
   83|  4.59k|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), arr, 3);
   84|       |
   85|  4.59k|    materials.reserve(conns.size());
   86|  4.59k|    geometry.reserve(conns.size());
   87|  4.59k|    attributes.reserve(conns.size());
   88|  5.03k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (88:32): [True: 5.03k, False: 4.59k]
  ------------------
   89|       |
   90|       |        // material and geometry links should be Object-Object connections
   91|  5.03k|        if (con->PropertyName().length()) {
  ------------------
  |  Branch (91:13): [True: 0, False: 5.03k]
  ------------------
   92|      0|            continue;
   93|      0|        }
   94|       |
   95|  5.03k|        const Object *const ob = con->SourceObject();
   96|  5.03k|        if (!ob) {
  ------------------
  |  Branch (96:13): [True: 185, False: 4.84k]
  ------------------
   97|    185|            DOMWarning("failed to read source object for incoming Model link, ignoring", &element);
   98|    185|            continue;
   99|    185|        }
  100|       |
  101|  4.84k|        const Material *const mat = dynamic_cast<const Material *>(ob);
  102|  4.84k|        if (mat) {
  ------------------
  |  Branch (102:13): [True: 496, False: 4.35k]
  ------------------
  103|    496|            materials.push_back(mat);
  104|    496|            continue;
  105|    496|        }
  106|       |
  107|  4.35k|        const Geometry *const geo = dynamic_cast<const Geometry *>(ob);
  108|  4.35k|        if (geo) {
  ------------------
  |  Branch (108:13): [True: 95, False: 4.25k]
  ------------------
  109|     95|            geometry.push_back(geo);
  110|     95|            continue;
  111|     95|        }
  112|       |
  113|  4.25k|        const NodeAttribute *const att = dynamic_cast<const NodeAttribute *>(ob);
  114|  4.25k|        if (att) {
  ------------------
  |  Branch (114:13): [True: 4.25k, False: 0]
  ------------------
  115|  4.25k|            attributes.push_back(att);
  116|  4.25k|            continue;
  117|  4.25k|        }
  118|       |
  119|      0|        DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring", &element);
  120|      0|        continue;
  121|  4.25k|    }
  122|  4.59k|}
_ZNK6Assimp3FBX5Model6IsNullEv:
  125|  3.56k|bool Model::IsNull() const {
  126|  3.56k|    const std::vector<const NodeAttribute *> &attrs = GetAttributes();
  127|  3.56k|    for (const NodeAttribute *att : attrs) {
  ------------------
  |  Branch (127:35): [True: 3.24k, False: 3.38k]
  ------------------
  128|       |
  129|  3.24k|        const Null *null_tag = dynamic_cast<const Null *>(att);
  130|  3.24k|        if (null_tag) {
  ------------------
  |  Branch (130:13): [True: 185, False: 3.05k]
  ------------------
  131|    185|            return true;
  132|    185|        }
  133|  3.24k|    }
  134|       |
  135|  3.38k|    return false;
  136|  3.56k|}

_ZN6Assimp3FBX13NodeAttributeC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   60|  4.27k|        Object(id, element, name), props() {
   61|  4.27k|    const Scope &sc = GetRequiredScope(element);
   62|       |
   63|  4.27k|    const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
   64|       |
   65|       |    // hack on the deriving type but Null/LimbNode attributes are the only case in which
   66|       |    // the property table is by design absent and no warning should be generated
   67|       |    // for it.
   68|  4.27k|    const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
  ------------------
  |  Branch (68:34): [True: 219, False: 4.06k]
  |  Branch (68:72): [True: 3.60k, False: 458]
  ------------------
   69|  4.27k|    props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
   70|  4.27k|}
_ZN6Assimp3FBX6CameraC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   95|    243|        NodeAttribute(id, element, doc, name) {
   96|       |    // empty
   97|    243|}
_ZN6Assimp3FBX5LightC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  101|    215|        NodeAttribute(id, element, doc, name) {
  102|       |    // empty
  103|    215|}
_ZN6Assimp3FBX4NullC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  107|    219|        NodeAttribute(id, element, doc, name) {
  108|       |    // empty
  109|    219|}
_ZN6Assimp3FBX8LimbNodeC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  113|  3.60k|        NodeAttribute(id, element, doc, name) {
  114|       |    // empty
  115|  3.60k|}

_ZN6Assimp3FBX7ElementC2ERKNS0_5TokenERNS0_6ParserE:
  115|   644k|    key_token(key_token), compound(nullptr)
  116|   644k|{
  117|   644k|    TokenPtr n = nullptr;
  118|   644k|    StackAllocator &allocator = parser.GetAllocator();
  119|  2.33M|    do {
  120|  2.33M|        n = parser.AdvanceToNextToken();
  121|  2.33M|        if(!n) {
  ------------------
  |  Branch (121:12): [True: 1, False: 2.33M]
  ------------------
  122|      1|            ParseError("unexpected end of file, expected closing bracket",parser.LastToken());
  123|      1|        }
  124|       |
  125|  2.33M|        if (n->Type() == TokenType_DATA) {
  ------------------
  |  Branch (125:13): [True: 2.29M, False: 32.5k]
  ------------------
  126|  2.29M|            tokens.push_back(n);
  127|  2.29M|			TokenPtr prev = n;
  128|  2.29M|            n = parser.AdvanceToNextToken();
  129|  2.29M|            if(!n) {
  ------------------
  |  Branch (129:16): [True: 0, False: 2.29M]
  ------------------
  130|      0|                ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken());
  131|      0|            }
  132|       |
  133|  2.29M|			const TokenType ty = n->Type();
  134|       |
  135|       |			// some exporters are missing a comma on the next line
  136|  2.29M|			if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) {
  ------------------
  |  Branch (136:8): [True: 41, False: 2.29M]
  |  Branch (136:32): [True: 41, False: 0]
  |  Branch (136:66): [True: 41, False: 0]
  ------------------
  137|     41|				tokens.push_back(n);
  138|     41|				continue;
  139|     41|			}
  140|       |
  141|  2.29M|            if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
  ------------------
  |  Branch (141:17): [True: 2.23M, False: 66.9k]
  |  Branch (141:49): [True: 2.15M, False: 75.8k]
  |  Branch (141:82): [True: 469k, False: 1.68M]
  |  Branch (141:107): [True: 0, False: 469k]
  ------------------
  142|      0|                ParseError("unexpected token; expected bracket, comma or key",n);
  143|      0|            }
  144|  2.29M|        }
  145|       |
  146|  2.32M|        if (n->Type() == TokenType_OPEN_BRACKET) {
  ------------------
  |  Branch (146:13): [True: 99.0k, False: 2.23M]
  ------------------
  147|  99.0k|            compound = new_Scope(parser);
  ------------------
  |  |   70|   198k|#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope
  ------------------
  148|       |
  149|       |            // current token should be a TOK_CLOSE_BRACKET
  150|  99.0k|            n = parser.CurrentToken();
  151|  99.0k|            ai_assert(n);
  ------------------
  |  |   67|  99.0k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 99.0k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  152|       |
  153|  99.0k|            if (n->Type() != TokenType_CLOSE_BRACKET) {
  ------------------
  |  Branch (153:17): [True: 0, False: 99.0k]
  ------------------
  154|      0|                ParseError("expected closing bracket",n);
  155|      0|            }
  156|       |
  157|  99.0k|            parser.AdvanceToNextToken();
  158|  99.0k|            return;
  159|  99.0k|        }
  160|  2.32M|    }
  161|  2.23M|    while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
  ------------------
  |  Branch (161:11): [True: 1.76M, False: 469k]
  |  Branch (161:41): [True: 1.68M, False: 75.9k]
  ------------------
  162|   644k|}
_ZN6Assimp3FBX7ElementD2Ev:
  166|   644k|{
  167|   644k|    if (compound) {
  ------------------
  |  Branch (167:9): [True: 99.0k, False: 545k]
  ------------------
  168|  99.0k|        delete_Scope(compound);
  ------------------
  |  |   72|  99.0k|#define delete_Scope(_p) (_p)->~Scope()
  ------------------
  169|  99.0k|    }
  170|       |
  171|       |     // no need to delete tokens, they are owned by the parser
  172|   644k|}
_ZN6Assimp3FBX5ScopeC2ERNS0_6ParserEb:
  175|  99.3k|{
  176|  99.3k|    if(!topLevel) {
  ------------------
  |  Branch (176:8): [True: 99.0k, False: 288]
  ------------------
  177|  99.0k|        TokenPtr t = parser.CurrentToken();
  178|  99.0k|        if (t->Type() != TokenType_OPEN_BRACKET) {
  ------------------
  |  Branch (178:13): [True: 0, False: 99.0k]
  ------------------
  179|      0|            ParseError("expected open bracket",t);
  180|      0|        }
  181|  99.0k|    }
  182|       |
  183|  99.3k|    StackAllocator &allocator = parser.GetAllocator();
  184|  99.3k|    TokenPtr n = parser.AdvanceToNextToken();
  185|  99.3k|    if (n == nullptr) {
  ------------------
  |  Branch (185:9): [True: 1, False: 99.3k]
  ------------------
  186|      1|        ParseError("unexpected end of file");
  187|      1|    }
  188|       |
  189|       |    // note: empty scopes are allowed
  190|   743k|    while(n->Type() != TokenType_CLOSE_BRACKET) {
  ------------------
  |  Branch (190:11): [True: 644k, False: 99.0k]
  ------------------
  191|   644k|        if (n->Type() != TokenType_KEY) {
  ------------------
  |  Branch (191:13): [True: 4, False: 644k]
  ------------------
  192|      4|            ParseError("unexpected token, expected TOK_KEY",n);
  193|      4|        }
  194|       |
  195|   644k|        const std::string& str = n->StringContents();
  196|   644k|        if (str.empty()) {
  ------------------
  |  Branch (196:13): [True: 0, False: 644k]
  ------------------
  197|      0|            ParseError("unexpected content: empty string.");
  198|      0|        }
  199|       |
  200|   644k|        auto *element = new_Element(*n, parser);
  ------------------
  |  |   71|  1.28M|#define new_Element new (allocator.Allocate(sizeof(Element))) Element
  ------------------
  201|       |
  202|       |        // Element() should stop at the next Key token (or right after a Close token)
  203|   644k|        n = parser.CurrentToken();
  204|   644k|        if (n == nullptr) {
  ------------------
  |  Branch (204:13): [True: 271, False: 644k]
  ------------------
  205|    271|            if (topLevel) {
  ------------------
  |  Branch (205:17): [True: 271, False: 0]
  ------------------
  206|    271|                elements.insert(ElementMap::value_type(str, element));
  207|    271|                return;
  208|    271|            }
  209|      0|            delete_Element(element);
  ------------------
  |  |   73|      0|#define delete_Element(_p) (_p)->~Element()
  ------------------
  210|      0|            ParseError("unexpected end of file",parser.LastToken());
  211|   644k|        } else {
  212|   644k|            elements.insert(ElementMap::value_type(str, element));
  213|   644k|        }
  214|   644k|    }
  215|  99.3k|}
_ZN6Assimp3FBX5ScopeD2Ev:
  219|  99.3k|{
  220|       |	// This collection does not own the memory for the elements, but we need to call their d'tor:
  221|       |
  222|   644k|    for (ElementMap::value_type &v : elements) {
  ------------------
  |  Branch (222:36): [True: 644k, False: 99.3k]
  ------------------
  223|   644k|        delete_Element(v.second);
  ------------------
  |  |   73|   644k|#define delete_Element(_p) (_p)->~Element()
  ------------------
  224|   644k|    }
  225|  99.3k|}
_ZN6Assimp3FBX6ParserC2ERKNSt3__16vectorIPKNS0_5TokenENS2_9allocatorIS6_EEEERNS_14StackAllocatorEb:
  229|    288|        tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary)
  230|    288|{
  231|    288|    ASSIMP_LOG_DEBUG("Parsing FBX tokens");
  232|    288|    root = new_Scope(*this, true);
  ------------------
  |  |   70|    576|#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope
  ------------------
  233|    288|}
_ZN6Assimp3FBX6ParserD2Ev:
  237|    282|{
  238|    282|    delete_Scope(root);
  ------------------
  |  |   72|    282|#define delete_Scope(_p) (_p)->~Scope()
  ------------------
  239|    282|}
_ZN6Assimp3FBX6Parser18AdvanceToNextTokenEv:
  243|  4.82M|{
  244|  4.82M|    last = current;
  245|  4.82M|    if (cursor == tokens.end()) {
  ------------------
  |  Branch (245:9): [True: 273, False: 4.82M]
  ------------------
  246|    273|        current = nullptr;
  247|  4.82M|    } else {
  248|  4.82M|        current = *cursor++;
  249|  4.82M|    }
  250|  4.82M|    return current;
  251|  4.82M|}
_ZNK6Assimp3FBX6Parser12CurrentTokenEv:
  255|   842k|{
  256|   842k|    return current;
  257|   842k|}
_ZNK6Assimp3FBX6Parser9LastTokenEv:
  261|      1|{
  262|      1|    return last;
  263|      1|}
_ZN6Assimp3FBX14ParseTokenAsIDERKNS0_5TokenERPKc:
  267|   233k|{
  268|   233k|    err_out = nullptr;
  269|       |
  270|   233k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (270:9): [True: 0, False: 233k]
  ------------------
  271|      0|        err_out = "expected TOK_DATA token";
  272|      0|        return 0L;
  273|      0|    }
  274|       |
  275|   233k|    if(t.IsBinary())
  ------------------
  |  Branch (275:8): [True: 209k, False: 24.0k]
  ------------------
  276|   209k|    {
  277|   209k|        const char* data = t.begin();
  278|   209k|        if (data[0] != 'L') {
  ------------------
  |  Branch (278:13): [True: 0, False: 209k]
  ------------------
  279|      0|            err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
  280|      0|            return 0L;
  281|      0|        }
  282|       |
  283|   209k|        BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
  284|   209k|        AI_SWAP8(id);
  285|   209k|        return id;
  286|   209k|    }
  287|       |
  288|       |    // XXX: should use size_t here
  289|  24.0k|    unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
  290|  24.0k|    ai_assert(length > 0);
  ------------------
  |  |   67|  24.0k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 24.0k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  291|       |
  292|  24.0k|    const char* out = nullptr;
  293|  24.0k|    const uint64_t id = strtoul10_64(t.begin(),&out,&length);
  294|  24.0k|    if (out > t.end()) {
  ------------------
  |  Branch (294:9): [True: 0, False: 24.0k]
  ------------------
  295|      0|        err_out = "failed to parse ID (text)";
  296|      0|        return 0L;
  297|      0|    }
  298|       |
  299|  24.0k|    return id;
  300|  24.0k|}
_ZN6Assimp3FBX15ParseTokenAsDimERKNS0_5TokenERPKc:
  304|     78|{
  305|       |    // same as ID parsing, except there is a trailing asterisk
  306|     78|    err_out = nullptr;
  307|       |
  308|     78|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (308:9): [True: 0, False: 78]
  ------------------
  309|      0|        err_out = "expected TOK_DATA token";
  310|      0|        return 0;
  311|      0|    }
  312|       |
  313|     78|    if(t.IsBinary())
  ------------------
  |  Branch (313:8): [True: 0, False: 78]
  ------------------
  314|      0|    {
  315|      0|        const char* data = t.begin();
  316|      0|        if (data[0] != 'L') {
  ------------------
  |  Branch (316:13): [True: 0, False: 0]
  ------------------
  317|      0|            err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
  318|      0|            return 0;
  319|      0|        }
  320|       |
  321|      0|        BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
  322|      0|        AI_SWAP8(id);
  323|      0|        return static_cast<size_t>(id);
  324|      0|    }
  325|       |
  326|     78|    if(*t.begin() != '*') {
  ------------------
  |  Branch (326:8): [True: 0, False: 78]
  ------------------
  327|      0|        err_out = "expected asterisk before array dimension";
  328|      0|        return 0;
  329|      0|    }
  330|       |
  331|       |    // XXX: should use size_t here
  332|     78|    unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
  333|     78|    if(length == 0) {
  ------------------
  |  Branch (333:8): [True: 0, False: 78]
  ------------------
  334|      0|        err_out = "expected valid integer number after asterisk";
  335|      0|        return 0;
  336|      0|    }
  337|       |
  338|     78|    const char* out = nullptr;
  339|     78|    const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length));
  340|     78|    if (out > t.end()) {
  ------------------
  |  Branch (340:9): [True: 0, False: 78]
  ------------------
  341|      0|        err_out = "failed to parse ID";
  342|      0|        return 0;
  343|      0|    }
  344|       |
  345|     78|    return id;
  346|     78|}
_ZN6Assimp3FBX17ParseTokenAsFloatERKNS0_5TokenERPKc:
  351|  96.5k|{
  352|  96.5k|    err_out = nullptr;
  353|       |
  354|  96.5k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (354:9): [True: 0, False: 96.5k]
  ------------------
  355|      0|        err_out = "expected TOK_DATA token";
  356|      0|        return 0.0f;
  357|      0|    }
  358|       |
  359|  96.5k|    if(t.IsBinary())
  ------------------
  |  Branch (359:8): [True: 48.4k, False: 48.0k]
  ------------------
  360|  48.4k|    {
  361|  48.4k|        const char* data = t.begin();
  362|  48.4k|        if (data[0] != 'F' && data[0] != 'D') {
  ------------------
  |  Branch (362:13): [True: 48.4k, False: 0]
  |  Branch (362:31): [True: 29, False: 48.4k]
  ------------------
  363|     29|            err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
  364|     29|            return 0.0f;
  365|     29|        }
  366|       |
  367|  48.4k|        if (data[0] == 'F') {
  ------------------
  |  Branch (367:13): [True: 0, False: 48.4k]
  ------------------
  368|      0|            BE_NCONST float id = SafeParse<float>(data+1, t.end());
  369|      0|            AI_SWAP4(id);
  370|      0|            return id;
  371|      0|        }
  372|  48.4k|        else {
  373|  48.4k|            BE_NCONST double id = SafeParse<double>(data+1, t.end());
  374|  48.4k|            AI_SWAP8(id);
  375|  48.4k|            return static_cast<float>(id);
  376|  48.4k|        }
  377|  48.4k|    }
  378|       |
  379|       |    // need to copy the input string to a temporary buffer
  380|       |    // first - next in the fbx token stream comes ',',
  381|       |    // which fast_atof could interpret as decimal point.
  382|  48.0k|#define MAX_FLOAT_LENGTH 31
  383|  48.0k|    const size_t length = static_cast<size_t>(t.end()-t.begin());
  384|  48.0k|    if (length > MAX_FLOAT_LENGTH) {
  ------------------
  |  |  382|  48.0k|#define MAX_FLOAT_LENGTH 31
  ------------------
  |  Branch (384:9): [True: 426, False: 47.6k]
  ------------------
  385|    426|        return 0.f;
  386|    426|    }
  387|       |
  388|  47.6k|    char temp[MAX_FLOAT_LENGTH + 1];
  389|  47.6k|    std::copy(t.begin(), t.end(), temp);
  390|  47.6k|    temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0';
  ------------------
  |  |  382|  47.6k|#define MAX_FLOAT_LENGTH 31
  ------------------
  391|       |
  392|  47.6k|    return fast_atof(temp);
  393|  48.0k|}
_ZN6Assimp3FBX15ParseTokenAsIntERKNS0_5TokenERPKc:
  398|   580k|{
  399|   580k|    err_out = nullptr;
  400|       |
  401|   580k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (401:9): [True: 0, False: 580k]
  ------------------
  402|      0|        err_out = "expected TOK_DATA token";
  403|      0|        return 0;
  404|      0|    }
  405|       |
  406|   580k|    if(t.IsBinary())
  ------------------
  |  Branch (406:8): [True: 14.1k, False: 565k]
  ------------------
  407|  14.1k|    {
  408|  14.1k|        const char* data = t.begin();
  409|  14.1k|        if (data[0] != 'I') {
  ------------------
  |  Branch (409:13): [True: 1, False: 14.1k]
  ------------------
  410|      1|            err_out = "failed to parse I(nt), unexpected data type (binary)";
  411|      1|            return 0;
  412|      1|        }
  413|       |
  414|  14.1k|        BE_NCONST int32_t ival = SafeParse<int32_t>(data+1, t.end());
  415|  14.1k|        AI_SWAP4(ival);
  416|  14.1k|        return static_cast<int>(ival);
  417|  14.1k|    }
  418|       |
  419|   565k|    ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0);
  ------------------
  |  |   67|   565k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 565k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  420|       |
  421|   565k|    const char* out;
  422|   565k|    const int intval = strtol10(t.begin(),&out);
  423|   565k|    if (out != t.end()) {
  ------------------
  |  Branch (423:9): [True: 1, False: 565k]
  ------------------
  424|      1|        err_out = "failed to parse ID";
  425|      1|        return 0;
  426|      1|    }
  427|       |
  428|   565k|    return intval;
  429|   565k|}
_ZN6Assimp3FBX17ParseTokenAsInt64ERKNS0_5TokenERPKc:
  434|    893|{
  435|    893|    err_out = nullptr;
  436|       |
  437|    893|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (437:9): [True: 0, False: 893]
  ------------------
  438|      0|        err_out = "expected TOK_DATA token";
  439|      0|        return 0L;
  440|      0|    }
  441|       |
  442|    893|    if (t.IsBinary())
  ------------------
  |  Branch (442:9): [True: 874, False: 19]
  ------------------
  443|    874|    {
  444|    874|        const char* data = t.begin();
  445|    874|        if (data[0] != 'L') {
  ------------------
  |  Branch (445:13): [True: 0, False: 874]
  ------------------
  446|      0|            err_out = "failed to parse Int64, unexpected data type";
  447|      0|            return 0L;
  448|      0|        }
  449|       |
  450|    874|        BE_NCONST int64_t id = SafeParse<int64_t>(data + 1, t.end());
  451|    874|        AI_SWAP8(id);
  452|    874|        return id;
  453|    874|    }
  454|       |
  455|       |    // XXX: should use size_t here
  456|     19|    unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
  457|     19|    ai_assert(length > 0);
  ------------------
  |  |   67|     19|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 19, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  458|       |
  459|     19|    const char* out = nullptr;
  460|     19|    const int64_t id = strtol10_64(t.begin(), &out, &length);
  461|     19|    if (out > t.end()) {
  ------------------
  |  Branch (461:9): [True: 0, False: 19]
  ------------------
  462|      0|        err_out = "failed to parse Int64 (text)";
  463|      0|        return 0L;
  464|      0|    }
  465|       |
  466|     19|    return id;
  467|     19|}
_ZN6Assimp3FBX18ParseTokenAsStringERKNS0_5TokenERPKc:
  471|   409k|{
  472|   409k|    err_out = nullptr;
  473|       |
  474|   409k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (474:9): [True: 0, False: 409k]
  ------------------
  475|      0|        err_out = "expected TOK_DATA token";
  476|      0|        return std::string();
  477|      0|    }
  478|       |
  479|   409k|    if(t.IsBinary())
  ------------------
  |  Branch (479:8): [True: 392k, False: 16.4k]
  ------------------
  480|   392k|    {
  481|   392k|        const char* data = t.begin();
  482|   392k|        if (data[0] != 'S') {
  ------------------
  |  Branch (482:13): [True: 16, False: 392k]
  ------------------
  483|     16|            err_out = "failed to parse S(tring), unexpected data type (binary)";
  484|     16|            return std::string();
  485|     16|        }
  486|       |
  487|       |        // read string length
  488|   392k|        BE_NCONST int32_t len = SafeParse<int32_t>(data+1, t.end());
  489|   392k|        AI_SWAP4(len);
  490|       |
  491|   392k|        ai_assert(t.end() - data == 5 + len);
  ------------------
  |  |   67|   392k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 392k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  492|   392k|        return std::string(data + 5, len);
  493|   392k|    }
  494|       |
  495|  16.4k|    const size_t length = static_cast<size_t>(t.end() - t.begin());
  496|  16.4k|    if(length < 2) {
  ------------------
  |  Branch (496:8): [True: 0, False: 16.4k]
  ------------------
  497|      0|        err_out = "token is too short to hold a string";
  498|      0|        return std::string();
  499|      0|    }
  500|       |
  501|  16.4k|    const char* s = t.begin(), *e = t.end() - 1;
  502|  16.4k|    if (*s != '\"' || *e != '\"') {
  ------------------
  |  Branch (502:9): [True: 0, False: 16.4k]
  |  Branch (502:23): [True: 0, False: 16.4k]
  ------------------
  503|      0|        err_out = "expected double quoted string";
  504|      0|        return std::string();
  505|      0|    }
  506|       |
  507|  16.4k|    return std::string(s+1,length-2);
  508|  16.4k|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEERKNS0_7ElementE:
  602|    270|{
  603|    270|    out.resize( 0 );
  604|       |
  605|    270|    const TokenList& tok = el.Tokens();
  606|    270|    if(tok.empty()) {
  ------------------
  |  Branch (606:8): [True: 0, False: 270]
  ------------------
  607|      0|        ParseError("unexpected empty element",&el);
  608|      0|    }
  609|       |
  610|    270|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (610:8): [True: 232, False: 38]
  ------------------
  611|    232|        const char* data = tok[0]->begin(), *end = tok[0]->end();
  612|       |
  613|    232|        char type;
  614|    232|        uint32_t count;
  615|    232|        ReadBinaryDataArrayHead(data, end, type, count, el);
  616|       |
  617|    232|        if(count % 3 != 0) {
  ------------------
  |  Branch (617:12): [True: 0, False: 232]
  ------------------
  618|      0|            ParseError("number of floats is not a multiple of three (3) (binary)",&el);
  619|      0|        }
  620|       |
  621|    232|        if(!count) {
  ------------------
  |  Branch (621:12): [True: 0, False: 232]
  ------------------
  622|      0|            return;
  623|      0|        }
  624|       |
  625|    232|        if (type != 'd' && type != 'f') {
  ------------------
  |  Branch (625:13): [True: 0, False: 232]
  |  Branch (625:28): [True: 0, False: 0]
  ------------------
  626|      0|            ParseError("expected float or double array (binary)",&el);
  627|      0|        }
  628|       |
  629|    232|        std::vector<char> buff;
  630|    232|        ReadBinaryDataArray(type, count, data, end, buff, el);
  631|       |
  632|    232|        ai_assert(data == end);
  ------------------
  |  |   67|    232|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 232, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  633|    232|        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
  ------------------
  |  Branch (633:63): [True: 136, False: 96]
  ------------------
  634|    232|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (634:13): [True: 0, False: 232]
  ------------------
  635|      0|            ParseError("Invalid read size (binary)",&el);
  636|      0|        }
  637|       |
  638|    232|        const uint32_t count3 = count / 3;
  639|    232|        out.reserve(count3);
  640|       |
  641|    232|        if (type == 'd') {
  ------------------
  |  Branch (641:13): [True: 136, False: 96]
  ------------------
  642|    136|            const double* d = reinterpret_cast<const double*>(&buff[0]);
  643|   210k|            for (unsigned int i = 0; i < count3; ++i, d += 3) {
  ------------------
  |  Branch (643:38): [True: 210k, False: 136]
  ------------------
  644|   210k|                BE_NCONST double val1 = d[0];
  645|   210k|                BE_NCONST double val2 = d[1];
  646|   210k|                BE_NCONST double val3 = d[2];
  647|   210k|                AI_SWAP8(val1);
  648|   210k|                AI_SWAP8(val2);
  649|   210k|                AI_SWAP8(val3);
  650|   210k|                out.emplace_back(static_cast<ai_real>(val1),
  651|   210k|                    static_cast<ai_real>(val2),
  652|   210k|                    static_cast<ai_real>(val3));
  653|   210k|            }
  654|       |            // for debugging
  655|       |            /*for ( size_t i = 0; i < out.size(); i++ ) {
  656|       |                aiVector3D vec3( out[ i ] );
  657|       |                std::stringstream stream;
  658|       |                stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl;
  659|       |                DefaultLogger::get()->info( stream.str() );
  660|       |            }*/
  661|    136|        }
  662|     96|        else if (type == 'f') {
  ------------------
  |  Branch (662:18): [True: 0, False: 96]
  ------------------
  663|      0|            const float* f = reinterpret_cast<const float*>(&buff[0]);
  664|      0|            for (unsigned int i = 0; i < count3; ++i, f += 3) {
  ------------------
  |  Branch (664:38): [True: 0, False: 0]
  ------------------
  665|      0|                BE_NCONST float val1 = f[0];
  666|      0|                BE_NCONST float val2 = f[1];
  667|      0|                BE_NCONST float val3 = f[2];
  668|      0|                AI_SWAP4(val1);
  669|      0|                AI_SWAP4(val2);
  670|      0|                AI_SWAP4(val3);
  671|      0|                out.emplace_back(val1,val2,val3);
  672|      0|            }
  673|      0|        }
  674|       |
  675|    232|        return;
  676|    232|    }
  677|       |
  678|     38|    const size_t dim = ParseTokenAsDim(*tok[0]);
  679|       |
  680|       |    // may throw bad_alloc if the input is rubbish, but this need
  681|       |    // not to be prevented - importing would fail but we wouldn't
  682|       |    // crash since assimp handles this case properly.
  683|     38|    out.reserve(dim);
  684|       |
  685|     38|    const Scope& scope = GetRequiredScope(el);
  686|     38|    const Element& a = GetRequiredElement(scope,"a",&el);
  687|       |
  688|     38|    if (a.Tokens().size() % 3 != 0) {
  ------------------
  |  Branch (688:9): [True: 0, False: 38]
  ------------------
  689|      0|        ParseError("number of floats is not a multiple of three (3)",&el);
  690|      0|    }
  691|  15.6k|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
  ------------------
  |  Branch (691:85): [True: 15.5k, False: 38]
  ------------------
  692|  15.5k|        aiVector3D v;
  693|  15.5k|        v.x = ParseTokenAsFloat(**it++);
  694|  15.5k|        v.y = ParseTokenAsFloat(**it++);
  695|  15.5k|        v.z = ParseTokenAsFloat(**it++);
  696|       |
  697|  15.5k|        out.push_back(v);
  698|  15.5k|    }
  699|     38|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorI10aiVector2tIfENS1_9allocatorIS4_EEEERKNS0_7ElementE:
  801|     85|void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) {
  802|     85|    out.resize( 0 );
  803|     85|    const TokenList& tok = el.Tokens();
  804|     85|    if(tok.empty()) {
  ------------------
  |  Branch (804:8): [True: 0, False: 85]
  ------------------
  805|      0|        ParseError("unexpected empty element",&el);
  806|      0|    }
  807|       |
  808|     85|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (808:8): [True: 77, False: 8]
  ------------------
  809|     77|        const char* data = tok[0]->begin(), *end = tok[0]->end();
  810|       |
  811|     77|        char type;
  812|     77|        uint32_t count;
  813|     77|        ReadBinaryDataArrayHead(data, end, type, count, el);
  814|       |
  815|     77|        if(count % 2 != 0) {
  ------------------
  |  Branch (815:12): [True: 0, False: 77]
  ------------------
  816|      0|            ParseError("number of floats is not a multiple of two (2) (binary)",&el);
  817|      0|        }
  818|       |
  819|     77|        if(!count) {
  ------------------
  |  Branch (819:12): [True: 0, False: 77]
  ------------------
  820|      0|            return;
  821|      0|        }
  822|       |
  823|     77|        if (type != 'd' && type != 'f') {
  ------------------
  |  Branch (823:13): [True: 0, False: 77]
  |  Branch (823:28): [True: 0, False: 0]
  ------------------
  824|      0|            ParseError("expected float or double array (binary)",&el);
  825|      0|        }
  826|       |
  827|     77|        std::vector<char> buff;
  828|     77|        ReadBinaryDataArray(type, count, data, end, buff, el);
  829|       |
  830|     77|        ai_assert(data == end);
  ------------------
  |  |   67|     77|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 77, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  831|     77|        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
  ------------------
  |  Branch (831:63): [True: 75, False: 2]
  ------------------
  832|     77|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (832:13): [True: 0, False: 77]
  ------------------
  833|      0|            ParseError("Invalid read size (binary)",&el);
  834|      0|        }
  835|       |
  836|     77|        const uint32_t count2 = count / 2;
  837|     77|        out.reserve(count2);
  838|       |
  839|     77|        if (type == 'd') {
  ------------------
  |  Branch (839:13): [True: 75, False: 2]
  ------------------
  840|     75|            const double* d = reinterpret_cast<const double*>(&buff[0]);
  841|   101k|            for (unsigned int i = 0; i < count2; ++i, d += 2) {
  ------------------
  |  Branch (841:38): [True: 101k, False: 75]
  ------------------
  842|   101k|                BE_NCONST double val1 = d[0];
  843|   101k|                BE_NCONST double val2 = d[1];
  844|   101k|                AI_SWAP8(val1);
  845|   101k|                AI_SWAP8(val2);
  846|   101k|                out.emplace_back(static_cast<float>(val1),
  847|   101k|                    static_cast<float>(val2));
  848|   101k|            }
  849|     75|        } else if (type == 'f') {
  ------------------
  |  Branch (849:20): [True: 0, False: 2]
  ------------------
  850|      0|            const float* f = reinterpret_cast<const float*>(&buff[0]);
  851|      0|            for (unsigned int i = 0; i < count2; ++i, f += 2) {
  ------------------
  |  Branch (851:38): [True: 0, False: 0]
  ------------------
  852|      0|                BE_NCONST float val1 = f[0];
  853|      0|                BE_NCONST float val2 = f[1];
  854|      0|                AI_SWAP4(val1);
  855|      0|                AI_SWAP4(val2);
  856|      0|                out.emplace_back(val1,val2);
  857|      0|            }
  858|      0|        }
  859|       |
  860|     77|        return;
  861|     77|    }
  862|       |
  863|      8|    const size_t dim = ParseTokenAsDim(*tok[0]);
  864|       |
  865|       |    // see notes in ParseVectorDataArray() above
  866|      8|    out.reserve(dim);
  867|       |
  868|      8|    const Scope& scope = GetRequiredScope(el);
  869|      8|    const Element& a = GetRequiredElement(scope,"a",&el);
  870|       |
  871|      8|    if (a.Tokens().size() % 2 != 0) {
  ------------------
  |  Branch (871:9): [True: 0, False: 8]
  ------------------
  872|      0|        ParseError("number of floats is not a multiple of two (2)",&el);
  873|      0|    }
  874|    419|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
  ------------------
  |  Branch (874:85): [True: 411, False: 8]
  ------------------
  875|    411|        aiVector2D v;
  876|    411|        v.x = ParseTokenAsFloat(**it++);
  877|    411|        v.y = ParseTokenAsFloat(**it++);
  878|       |
  879|    411|        out.push_back(v);
  880|    411|    }
  881|      8|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorIiNS1_9allocatorIiEEEERKNS0_7ElementE:
  886|    303|void ParseVectorDataArray(std::vector<int>& out, const Element& el) {
  887|    303|    out.resize( 0 );
  888|    303|    const TokenList& tok = el.Tokens();
  889|    303|    if(tok.empty()) {
  ------------------
  |  Branch (889:8): [True: 0, False: 303]
  ------------------
  890|      0|        ParseError("unexpected empty element",&el);
  891|      0|    }
  892|       |
  893|    303|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (893:8): [True: 271, False: 32]
  ------------------
  894|    271|        const char* data = tok[0]->begin(), *end = tok[0]->end();
  895|       |
  896|    271|        char type;
  897|    271|        uint32_t count;
  898|    271|        ReadBinaryDataArrayHead(data, end, type, count, el);
  899|       |
  900|    271|        if(!count) {
  ------------------
  |  Branch (900:12): [True: 0, False: 271]
  ------------------
  901|      0|            return;
  902|      0|        }
  903|       |
  904|    271|        if (type != 'i') {
  ------------------
  |  Branch (904:13): [True: 0, False: 271]
  ------------------
  905|      0|            ParseError("expected int array (binary)",&el);
  906|      0|        }
  907|       |
  908|    271|        std::vector<char> buff;
  909|    271|        ReadBinaryDataArray(type, count, data, end, buff, el);
  910|       |
  911|    271|        ai_assert(data == end);
  ------------------
  |  |   67|    271|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 271, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  912|    271|        uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
  913|    271|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (913:13): [True: 0, False: 271]
  ------------------
  914|      0|            ParseError("Invalid read size (binary)",&el);
  915|      0|        }
  916|       |
  917|    271|        out.reserve(count);
  918|       |
  919|    271|        const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
  920|   718k|        for (unsigned int i = 0; i < count; ++i, ++ip) {
  ------------------
  |  Branch (920:34): [True: 718k, False: 271]
  ------------------
  921|   718k|            BE_NCONST int32_t val = *ip;
  922|   718k|            AI_SWAP4(val);
  923|   718k|            out.push_back(val);
  924|   718k|        }
  925|       |
  926|    271|        return;
  927|    271|    }
  928|       |
  929|     32|    const size_t dim = ParseTokenAsDim(*tok[0]);
  930|       |
  931|       |    // see notes in ParseVectorDataArray()
  932|     32|    out.reserve(dim);
  933|       |
  934|     32|    const Scope& scope = GetRequiredScope(el);
  935|     32|    const Element& a = GetRequiredElement(scope,"a",&el);
  936|       |
  937|   565k|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
  ------------------
  |  Branch (937:85): [True: 565k, False: 32]
  ------------------
  938|   565k|        const int ival = ParseTokenAsInt(**it++);
  939|   565k|        out.push_back(ival);
  940|   565k|    }
  941|     32|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorIfNS1_9allocatorIfEEEERKNS0_7ElementE:
  947|  63.3k|{
  948|  63.3k|    out.resize( 0 );
  949|  63.3k|    const TokenList& tok = el.Tokens();
  950|  63.3k|    if(tok.empty()) {
  ------------------
  |  Branch (950:8): [True: 0, False: 63.3k]
  ------------------
  951|      0|        ParseError("unexpected empty element",&el);
  952|      0|    }
  953|       |
  954|  63.3k|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (954:8): [True: 63.3k, False: 0]
  ------------------
  955|  63.3k|        const char* data = tok[0]->begin(), *end = tok[0]->end();
  956|       |
  957|  63.3k|        char type;
  958|  63.3k|        uint32_t count;
  959|  63.3k|        ReadBinaryDataArrayHead(data, end, type, count, el);
  960|       |
  961|  63.3k|        if(!count) {
  ------------------
  |  Branch (961:12): [True: 1, False: 63.3k]
  ------------------
  962|      1|            return;
  963|      1|        }
  964|       |
  965|  63.3k|        if (type != 'd' && type != 'f') {
  ------------------
  |  Branch (965:13): [True: 55.4k, False: 7.95k]
  |  Branch (965:28): [True: 0, False: 55.4k]
  ------------------
  966|      0|            ParseError("expected float or double array (binary)",&el);
  967|      0|        }
  968|       |
  969|  63.3k|        std::vector<char> buff;
  970|  63.3k|        ReadBinaryDataArray(type, count, data, end, buff, el);
  971|       |
  972|  63.3k|        ai_assert(data == end);
  ------------------
  |  |   67|  63.3k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 63.3k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  973|  63.3k|        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
  ------------------
  |  Branch (973:63): [True: 7.12k, False: 56.2k]
  ------------------
  974|  63.3k|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (974:13): [True: 0, False: 63.3k]
  ------------------
  975|      0|            ParseError("Invalid read size (binary)",&el);
  976|      0|        }
  977|       |
  978|  63.3k|        if (type == 'd') {
  ------------------
  |  Branch (978:13): [True: 7.12k, False: 56.2k]
  ------------------
  979|  7.12k|            const double* d = reinterpret_cast<const double*>(&buff[0]);
  980|  16.8M|            for (unsigned int i = 0; i < count; ++i, ++d) {
  ------------------
  |  Branch (980:38): [True: 16.8M, False: 7.12k]
  ------------------
  981|  16.8M|                BE_NCONST double val = *d;
  982|  16.8M|                AI_SWAP8(val);
  983|  16.8M|                out.push_back(static_cast<float>(val));
  984|  16.8M|            }
  985|  7.12k|        }
  986|  56.2k|        else if (type == 'f') {
  ------------------
  |  Branch (986:18): [True: 55.4k, False: 826]
  ------------------
  987|  55.4k|            const float* f = reinterpret_cast<const float*>(&buff[0]);
  988|   223k|            for (unsigned int i = 0; i < count; ++i, ++f) {
  ------------------
  |  Branch (988:38): [True: 168k, False: 55.4k]
  ------------------
  989|   168k|                BE_NCONST float val = *f;
  990|   168k|                AI_SWAP4(val);
  991|   168k|                out.push_back(val);
  992|   168k|            }
  993|  55.4k|        }
  994|       |
  995|  63.3k|        return;
  996|  63.3k|    }
  997|       |
  998|      0|    const size_t dim = ParseTokenAsDim(*tok[0]);
  999|       |
 1000|       |    // see notes in ParseVectorDataArray()
 1001|      0|    out.reserve(dim);
 1002|       |
 1003|      0|    const Scope& scope = GetRequiredScope(el);
 1004|      0|    const Element& a = GetRequiredElement(scope,"a",&el);
 1005|       |
 1006|      0|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
  ------------------
  |  Branch (1006:85): [True: 0, False: 0]
  ------------------
 1007|      0|        const float ival = ParseTokenAsFloat(**it++);
 1008|      0|        out.push_back(ival);
 1009|      0|    }
 1010|      0|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorIjNS1_9allocatorIjEEEERKNS0_7ElementE:
 1014|  30.4k|void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) {
 1015|  30.4k|    out.resize( 0 );
 1016|  30.4k|    const TokenList& tok = el.Tokens();
 1017|  30.4k|    if(tok.empty()) {
  ------------------
  |  Branch (1017:8): [True: 0, False: 30.4k]
  ------------------
 1018|      0|        ParseError("unexpected empty element",&el);
 1019|      0|    }
 1020|       |
 1021|  30.4k|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (1021:8): [True: 30.4k, False: 0]
  ------------------
 1022|  30.4k|        const char* data = tok[0]->begin(), *end = tok[0]->end();
 1023|       |
 1024|  30.4k|        char type;
 1025|  30.4k|        uint32_t count;
 1026|  30.4k|        ReadBinaryDataArrayHead(data, end, type, count, el);
 1027|       |
 1028|  30.4k|        if(!count) {
  ------------------
  |  Branch (1028:12): [True: 2, False: 30.4k]
  ------------------
 1029|      2|            return;
 1030|      2|        }
 1031|       |
 1032|  30.4k|        if (type != 'i') {
  ------------------
  |  Branch (1032:13): [True: 1, False: 30.4k]
  ------------------
 1033|      1|            ParseError("expected (u)int array (binary)",&el);
 1034|      1|        }
 1035|       |
 1036|  30.4k|        std::vector<char> buff;
 1037|  30.4k|        ReadBinaryDataArray(type, count, data, end, buff, el);
 1038|       |
 1039|  30.4k|        ai_assert(data == end);
  ------------------
  |  |   67|  30.4k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 30.4k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1040|  30.4k|        uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
 1041|  30.4k|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (1041:13): [True: 0, False: 30.4k]
  ------------------
 1042|      0|            ParseError("Invalid read size (binary)",&el);
 1043|      0|        }
 1044|       |
 1045|  30.4k|        out.reserve(count);
 1046|       |
 1047|  30.4k|        const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
 1048|  48.2M|        for (unsigned int i = 0; i < count; ++i, ++ip) {
  ------------------
  |  Branch (1048:34): [True: 48.2M, False: 30.4k]
  ------------------
 1049|  48.2M|            BE_NCONST int32_t val = *ip;
 1050|  48.2M|            if(val < 0) {
  ------------------
  |  Branch (1050:16): [True: 5, False: 48.2M]
  ------------------
 1051|      5|                ParseError("encountered negative integer index (binary)");
 1052|      5|            }
 1053|       |
 1054|  48.2M|            AI_SWAP4(val);
 1055|  48.2M|            out.push_back(val);
 1056|  48.2M|        }
 1057|       |
 1058|  30.4k|        return;
 1059|  30.4k|    }
 1060|       |
 1061|      0|    const size_t dim = ParseTokenAsDim(*tok[0]);
 1062|       |
 1063|       |    // see notes in ParseVectorDataArray()
 1064|      0|    out.reserve(dim);
 1065|       |
 1066|      0|    const Scope& scope = GetRequiredScope(el);
 1067|      0|    const Element& a = GetRequiredElement(scope,"a",&el);
 1068|       |
 1069|      0|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
  ------------------
  |  Branch (1069:85): [True: 0, False: 0]
  ------------------
 1070|      0|        const int ival = ParseTokenAsInt(**it++);
 1071|      0|        if(ival < 0) {
  ------------------
  |  Branch (1071:12): [True: 0, False: 0]
  ------------------
 1072|      0|            ParseError("encountered negative integer index");
 1073|      0|        }
 1074|      0|        out.push_back(static_cast<unsigned int>(ival));
 1075|      0|    }
 1076|      0|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorIlNS1_9allocatorIlEEEERKNS0_7ElementE:
 1143|  27.8k|{
 1144|  27.8k|    out.resize( 0 );
 1145|  27.8k|    const TokenList& tok = el.Tokens();
 1146|  27.8k|    if (tok.empty()) {
  ------------------
  |  Branch (1146:9): [True: 0, False: 27.8k]
  ------------------
 1147|      0|        ParseError("unexpected empty element", &el);
 1148|      0|    }
 1149|       |
 1150|  27.8k|    if (tok[0]->IsBinary()) {
  ------------------
  |  Branch (1150:9): [True: 27.8k, False: 0]
  ------------------
 1151|  27.8k|        const char* data = tok[0]->begin(), *end = tok[0]->end();
 1152|       |
 1153|  27.8k|        char type;
 1154|  27.8k|        uint32_t count;
 1155|  27.8k|        ReadBinaryDataArrayHead(data, end, type, count, el);
 1156|       |
 1157|  27.8k|        if (!count) {
  ------------------
  |  Branch (1157:13): [True: 0, False: 27.8k]
  ------------------
 1158|      0|            return;
 1159|      0|        }
 1160|       |
 1161|  27.8k|        if (type != 'l') {
  ------------------
  |  Branch (1161:13): [True: 5, False: 27.8k]
  ------------------
 1162|      5|            ParseError("expected long array (binary)", &el);
 1163|      5|        }
 1164|       |
 1165|  27.8k|        std::vector<char> buff;
 1166|  27.8k|        ReadBinaryDataArray(type, count, data, end, buff, el);
 1167|       |
 1168|  27.8k|        ai_assert(data == end);
  ------------------
  |  |   67|  27.8k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 27.8k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1169|  27.8k|        uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
 1170|  27.8k|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (1170:13): [True: 1, False: 27.8k]
  ------------------
 1171|      1|            ParseError("Invalid read size (binary)",&el);
 1172|      1|        }
 1173|       |
 1174|  27.8k|        out.reserve(count);
 1175|       |
 1176|  27.8k|        const int64_t* ip = reinterpret_cast<const int64_t*>(&buff[0]);
 1177|  85.7k|        for (unsigned int i = 0; i < count; ++i, ++ip) {
  ------------------
  |  Branch (1177:34): [True: 57.9k, False: 27.8k]
  ------------------
 1178|  57.9k|            BE_NCONST int64_t val = *ip;
 1179|  57.9k|            AI_SWAP8(val);
 1180|  57.9k|            out.push_back(val);
 1181|  57.9k|        }
 1182|       |
 1183|  27.8k|        return;
 1184|  27.8k|    }
 1185|       |
 1186|      0|    const size_t dim = ParseTokenAsDim(*tok[0]);
 1187|       |
 1188|       |    // see notes in ParseVectorDataArray()
 1189|      0|    out.reserve(dim);
 1190|       |
 1191|      0|    const Scope& scope = GetRequiredScope(el);
 1192|      0|    const Element& a = GetRequiredElement(scope, "a", &el);
 1193|       |
 1194|      0|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end;) {
  ------------------
  |  Branch (1194:85): [True: 0, False: 0]
  ------------------
 1195|      0|        const int64_t ival = ParseTokenAsInt64(**it++);
 1196|       |
 1197|      0|        out.push_back(ival);
 1198|      0|    }
 1199|      0|}
_ZN6Assimp3FBX10ReadMatrixERKNS0_7ElementE:
 1203|  5.76k|{
 1204|  5.76k|    std::vector<float> values;
 1205|  5.76k|    ParseVectorDataArray(values,element);
 1206|       |
 1207|  5.76k|    if(values.size() != 16) {
  ------------------
  |  Branch (1207:8): [True: 0, False: 5.76k]
  ------------------
 1208|      0|        ParseError("expected 16 matrix elements");
 1209|      0|    }
 1210|       |
 1211|  5.76k|    aiMatrix4x4 result;
 1212|       |
 1213|       |
 1214|  5.76k|    result.a1 = values[0];
 1215|  5.76k|    result.a2 = values[1];
 1216|  5.76k|    result.a3 = values[2];
 1217|  5.76k|    result.a4 = values[3];
 1218|       |
 1219|  5.76k|    result.b1 = values[4];
 1220|  5.76k|    result.b2 = values[5];
 1221|  5.76k|    result.b3 = values[6];
 1222|  5.76k|    result.b4 = values[7];
 1223|       |
 1224|  5.76k|    result.c1 = values[8];
 1225|  5.76k|    result.c2 = values[9];
 1226|  5.76k|    result.c3 = values[10];
 1227|  5.76k|    result.c4 = values[11];
 1228|       |
 1229|  5.76k|    result.d1 = values[12];
 1230|  5.76k|    result.d2 = values[13];
 1231|  5.76k|    result.d3 = values[14];
 1232|  5.76k|    result.d4 = values[15];
 1233|       |
 1234|  5.76k|    result.Transpose();
 1235|  5.76k|    return result;
 1236|  5.76k|}
_ZN6Assimp3FBX18ParseTokenAsStringERKNS0_5TokenE:
 1241|   305k|{
 1242|   305k|    const char* err;
 1243|   305k|    const std::string& i = ParseTokenAsString(t,err);
 1244|   305k|    if(err) {
  ------------------
  |  Branch (1244:8): [True: 3, False: 305k]
  ------------------
 1245|      3|        ParseError(err,t);
 1246|      3|    }
 1247|   305k|    return i;
 1248|   305k|}
_ZN6Assimp3FBX10HasElementERKNS0_5ScopeERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE:
 1250|    406|bool HasElement( const Scope& sc, const std::string& index ) {
 1251|    406|    const Element* el = sc[ index ];
 1252|    406|    if ( nullptr == el ) {
  ------------------
  |  Branch (1252:10): [True: 120, False: 286]
  ------------------
 1253|    120|        return false;
 1254|    120|    }
 1255|       |
 1256|    286|    return true;
 1257|    406|}
_ZN6Assimp3FBX18GetRequiredElementERKNS0_5ScopeERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_7ElementE:
 1262|  66.3k|{
 1263|  66.3k|    const Element* el = sc[index];
 1264|  66.3k|    if(!el) {
  ------------------
  |  Branch (1264:8): [True: 304, False: 66.0k]
  ------------------
 1265|    304|        ParseError("did not find required element \"" + index + "\"",element);
 1266|    304|    }
 1267|  66.0k|    return *el;
 1268|  66.3k|}
_ZN6Assimp3FBX16GetRequiredScopeERKNS0_7ElementE:
 1274|  77.6k|{
 1275|  77.6k|    const Scope* const s = el.Compound();
 1276|  77.6k|    if(!s) {
  ------------------
  |  Branch (1276:8): [True: 0, False: 77.6k]
  ------------------
 1277|      0|        ParseError("expected compound scope",&el);
 1278|      0|    }
 1279|       |
 1280|  77.6k|    return *s;
 1281|  77.6k|}
_ZN6Assimp3FBX16GetRequiredTokenERKNS0_7ElementEj:
 1287|   329k|{
 1288|   329k|    const TokenList& t = el.Tokens();
 1289|   329k|    if(index >= t.size()) {
  ------------------
  |  Branch (1289:8): [True: 0, False: 329k]
  ------------------
 1290|      0|        ParseError(Formatter::format( "missing token at index " ) << index,&el);
 1291|      0|    }
 1292|       |
 1293|   329k|    return *t[index];
 1294|   329k|}
_ZN6Assimp3FBX14ParseTokenAsIDERKNS0_5TokenE:
 1300|   173k|{
 1301|   173k|    const char* err;
 1302|   173k|    const uint64_t i = ParseTokenAsID(t,err);
 1303|   173k|    if(err) {
  ------------------
  |  Branch (1303:8): [True: 0, False: 173k]
  ------------------
 1304|      0|        ParseError(err,t);
 1305|      0|    }
 1306|   173k|    return i;
 1307|   173k|}
_ZN6Assimp3FBX15ParseTokenAsDimERKNS0_5TokenE:
 1313|     78|{
 1314|     78|    const char* err;
 1315|     78|    const size_t i = ParseTokenAsDim(t,err);
 1316|     78|    if(err) {
  ------------------
  |  Branch (1316:8): [True: 0, False: 78]
  ------------------
 1317|      0|        ParseError(err,t);
 1318|      0|    }
 1319|     78|    return i;
 1320|     78|}
_ZN6Assimp3FBX17ParseTokenAsFloatERKNS0_5TokenE:
 1326|  96.5k|{
 1327|  96.5k|    const char* err;
 1328|  96.5k|    const float i = ParseTokenAsFloat(t,err);
 1329|  96.5k|    if(err) {
  ------------------
  |  Branch (1329:8): [True: 29, False: 96.4k]
  ------------------
 1330|     29|        ParseError(err,t);
 1331|     29|    }
 1332|  96.4k|    return i;
 1333|  96.5k|}
_ZN6Assimp3FBX15ParseTokenAsIntERKNS0_5TokenE:
 1338|   580k|{
 1339|   580k|    const char* err;
 1340|   580k|    const int i = ParseTokenAsInt(t,err);
 1341|   580k|    if(err) {
  ------------------
  |  Branch (1341:8): [True: 2, False: 580k]
  ------------------
 1342|      2|        ParseError(err,t);
 1343|      2|    }
 1344|   580k|    return i;
 1345|   580k|}
_ZN6Assimp3FBX17ParseTokenAsInt64ERKNS0_5TokenE:
 1350|    893|{
 1351|    893|    const char* err;
 1352|    893|    const int64_t i = ParseTokenAsInt64(t, err);
 1353|    893|    if (err) {
  ------------------
  |  Branch (1353:9): [True: 0, False: 893]
  ------------------
 1354|      0|        ParseError(err, t);
 1355|      0|    }
 1356|    893|    return i;
 1357|    893|}
FBXParser.cpp:_ZN12_GLOBAL__N_110ParseErrorERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEPKN6Assimp3FBX5TokenE:
   88|      5|    {
   89|      5|        if(token) {
  ------------------
  |  Branch (89:12): [True: 5, False: 0]
  ------------------
   90|      5|            ParseError(message, *token);
   91|      5|        }
   92|      0|        ParseError(message);
   93|      5|    }
FBXParser.cpp:_ZN12_GLOBAL__N_110ParseErrorERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEPKN6Assimp3FBX7ElementE:
   77|    317|    {
   78|    317|        if(element) {
  ------------------
  |  Branch (78:12): [True: 69, False: 248]
  ------------------
   79|     69|            ParseError(message,element->KeyToken());
   80|     69|        }
   81|    248|        throw DeadlyImportError("FBX-Parser ", message);
   82|    317|    }
FBXParser.cpp:_ZN6Assimp3FBX12_GLOBAL__N_123ReadBinaryDataArrayHeadERPKcS3_RcRjRKNS0_7ElementE:
  517|   122k|{
  518|   122k|    if (static_cast<size_t>(end-data) < 5) {
  ------------------
  |  Branch (518:9): [True: 0, False: 122k]
  ------------------
  519|      0|        ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el);
  520|      0|    }
  521|       |
  522|       |    // data type
  523|   122k|    type = *data;
  524|       |
  525|       |    // read number of elements
  526|   122k|    BE_NCONST uint32_t len = SafeParse<uint32_t>(data+1, end);
  527|   122k|    AI_SWAP4(len);
  528|       |
  529|   122k|    count = len;
  530|   122k|    data += 5;
  531|   122k|}
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseIjEET_PKcS3_:
   99|   366k|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|   366k|        (void)(end);
  103|   366k|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|   366k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 366k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|   366k|        T result = static_cast<T>(0);
  105|   366k|        ::memcpy(&result, data, sizeof(T));
  106|   366k|        return result;
  107|   366k|    }
FBXParser.cpp:_ZN6Assimp3FBX12_GLOBAL__N_119ReadBinaryDataArrayEcjRPKcS3_RNSt3__16vectorIcNS5_9allocatorIcEEEERKNS0_7ElementE:
  537|   122k|        std::vector<char>& buff, const Element& /*el*/) {
  538|   122k|    BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
  539|   122k|    AI_SWAP4(encmode);
  540|   122k|    data += 4;
  541|       |
  542|       |    // next comes the compressed length
  543|   122k|    BE_NCONST uint32_t comp_len = SafeParse<uint32_t>(data, end);
  544|   122k|    AI_SWAP4(comp_len);
  545|   122k|    data += 4;
  546|       |
  547|   122k|    ai_assert(data + comp_len == end);
  ------------------
  |  |   67|   122k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 122k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  548|       |
  549|       |    // determine the length of the uncompressed data by looking at the type signature
  550|   122k|    uint32_t stride = 0;
  551|   122k|    switch(type)
  552|   122k|    {
  553|  55.4k|        case 'f':
  ------------------
  |  Branch (553:9): [True: 55.4k, False: 66.8k]
  ------------------
  554|  86.1k|        case 'i':
  ------------------
  |  Branch (554:9): [True: 30.7k, False: 91.4k]
  ------------------
  555|  86.1k|            stride = 4;
  556|  86.1k|            break;
  557|       |
  558|  8.26k|        case 'd':
  ------------------
  |  Branch (558:9): [True: 8.26k, False: 113k]
  ------------------
  559|  36.0k|        case 'l':
  ------------------
  |  Branch (559:9): [True: 27.8k, False: 94.4k]
  ------------------
  560|  36.0k|            stride = 8;
  561|  36.0k|            break;
  562|       |
  563|      0|        default:
  ------------------
  |  Branch (563:9): [True: 0, False: 122k]
  ------------------
  564|      0|            ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  565|   122k|    };
  566|       |
  567|   122k|    const uint32_t full_length = stride * count;
  568|   122k|    buff.resize(full_length);
  569|       |
  570|   122k|    if(encmode == 0) {
  ------------------
  |  Branch (570:8): [True: 116k, False: 5.55k]
  ------------------
  571|   116k|        ai_assert(full_length == comp_len);
  ------------------
  |  |   67|   116k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 116k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  572|       |
  573|       |        // plain data, no compression
  574|   116k|        std::copy(data, end, buff.begin());
  575|   116k|    }
  576|  5.55k|    else if(encmode == 1) {
  ------------------
  |  Branch (576:13): [True: 5.55k, False: 0]
  ------------------
  577|       |        // zlib/deflate, next comes ZIP head (0x78 0x01)
  578|       |        // see http://www.ietf.org/rfc/rfc1950.txt
  579|  5.55k|         Compression compress;
  580|  5.55k|        if (compress.open(Compression::Format::Binary, Compression::FlushMode::Finish, 0)) {
  ------------------
  |  Branch (580:13): [True: 5.55k, False: 0]
  ------------------
  581|  5.55k|            compress.decompress(data, comp_len, buff);
  582|  5.55k|            compress.close();
  583|  5.55k|        }
  584|  5.55k|    }
  585|      0|#ifdef ASSIMP_BUILD_DEBUG
  586|      0|    else {
  587|       |        // runtime check for this happens at tokenization stage
  588|      0|        ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  589|      0|    }
  590|   122k|#endif
  591|       |
  592|   122k|    data += comp_len;
  593|   122k|    ai_assert(data == end);
  ------------------
  |  |   67|   122k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 122k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  594|   122k|}
FBXParser.cpp:_ZN12_GLOBAL__N_110ParseErrorERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKN6Assimp3FBX5TokenE:
   70|    108|    {
   71|    108|        throw DeadlyImportError("FBX-Parser", Util::GetTokenText(&token), message);
   72|    108|    }
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseImEET_PKcS3_:
   99|   209k|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|   209k|        (void)(end);
  103|   209k|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|   209k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 209k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|   209k|        T result = static_cast<T>(0);
  105|   209k|        ::memcpy(&result, data, sizeof(T));
  106|   209k|        return result;
  107|   209k|    }
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseIdEET_PKcS3_:
   99|  48.4k|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|  48.4k|        (void)(end);
  103|  48.4k|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|  48.4k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 48.4k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|  48.4k|        T result = static_cast<T>(0);
  105|  48.4k|        ::memcpy(&result, data, sizeof(T));
  106|  48.4k|        return result;
  107|  48.4k|    }
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseIiEET_PKcS3_:
   99|   406k|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|   406k|        (void)(end);
  103|   406k|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|   406k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 406k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|   406k|        T result = static_cast<T>(0);
  105|   406k|        ::memcpy(&result, data, sizeof(T));
  106|   406k|        return result;
  107|   406k|    }
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseIlEET_PKcS3_:
   99|    874|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|    874|        (void)(end);
  103|    874|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|    874|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 874, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|    874|        T result = static_cast<T>(0);
  105|    874|        ::memcpy(&result, data, sizeof(T));
  106|    874|        return result;
  107|    874|    }

_ZNK6Assimp3FBX7Element8CompoundEv:
   92|   105k|    const Scope* Compound() const {
   93|   105k|        return compound;
   94|   105k|    }
_ZNK6Assimp3FBX7Element8KeyTokenEv:
   96|   398k|    const Token& KeyToken() const {
   97|   398k|        return key_token;
   98|   398k|    }
_ZNK6Assimp3FBX7Element6TokensEv:
  100|   721k|    const TokenList& Tokens() const {
  101|   721k|        return tokens;
  102|   721k|    }
_ZNK6Assimp3FBX5ScopeixERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  127|   165k|    const Element* operator[] (const std::string& index) const {
  128|   165k|        ElementMap::const_iterator it = elements.find(index);
  129|   165k|        return it == elements.end() ? nullptr : (*it).second;
  ------------------
  |  Branch (129:16): [True: 4.70k, False: 160k]
  ------------------
  130|   165k|    }
_ZNK6Assimp3FBX5Scope26FindElementCaseInsensitiveERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  132|     10|	const Element* FindElementCaseInsensitive(const std::string& elementName) const {
  133|     10|		const char* elementNameCStr = elementName.c_str();
  134|     14|		for (auto element = elements.begin(); element != elements.end(); ++element)
  ------------------
  |  Branch (134:41): [True: 14, False: 0]
  ------------------
  135|     14|		{
  136|     14|            if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, AI_MAXLEN)) {
  ------------------
  |  Branch (136:17): [True: 10, False: 4]
  ------------------
  137|     10|				return element->second;
  138|     10|			}
  139|     14|		}
  140|      0|        return nullptr;
  141|     10|	}
_ZNK6Assimp3FBX5Scope13GetCollectionERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  143|  4.17k|    ElementCollection GetCollection(const std::string& index) const {
  144|  4.17k|        return elements.equal_range(index);
  145|  4.17k|    }
_ZNK6Assimp3FBX5Scope8ElementsEv:
  147|  21.8k|    const ElementMap& Elements() const  {
  148|  21.8k|        return elements;
  149|  21.8k|    }
_ZNK6Assimp3FBX6Parser12GetRootScopeEv:
  165|  1.38k|    const Scope& GetRootScope() const {
  166|  1.38k|        return *root;
  167|  1.38k|    }
_ZN6Assimp3FBX6Parser12GetAllocatorEv:
  173|   744k|    StackAllocator &GetAllocator() {
  174|   744k|        return allocator;
  175|   744k|    }

_ZN6Assimp3FBX13PropertyTableC2ERKNS0_7ElementENSt3__110shared_ptrIKS1_EE:
  160|  21.4k|        templateProps(std::move(templateProps)), element(&element) {
  161|  21.4k|    const Scope& scope = GetRequiredScope(element);
  162|   121k|    for(const ElementMap::value_type& v : scope.Elements()) {
  ------------------
  |  Branch (162:41): [True: 121k, False: 21.4k]
  ------------------
  163|   121k|        if(v.first != "P") {
  ------------------
  |  Branch (163:12): [True: 99, False: 121k]
  ------------------
  164|     99|            DOMWarning("expected only P elements in property table",v.second);
  165|     99|            continue;
  166|     99|        }
  167|       |
  168|   121k|        const std::string& name = PeekPropertyName(*v.second);
  169|   121k|        if(!name.length()) {
  ------------------
  |  Branch (169:12): [True: 28, False: 121k]
  ------------------
  170|     28|            DOMWarning("could not read property name",v.second);
  171|     28|            continue;
  172|     28|        }
  173|       |
  174|   121k|        LazyPropertyMap::const_iterator it = lazyProps.find(name);
  175|   121k|        if (it != lazyProps.end()) {
  ------------------
  |  Branch (175:13): [True: 6, False: 121k]
  ------------------
  176|      6|            DOMWarning("duplicate property name, will hide previous value: " + name,v.second);
  177|      6|            continue;
  178|      6|        }
  179|       |
  180|   121k|        lazyProps[name] = v.second;
  181|   121k|    }
  182|  21.4k|}
_ZN6Assimp3FBX13PropertyTableD2Ev:
  186|  24.7k|{
  187|  24.7k|    for(PropertyMap::value_type& v : props) {
  ------------------
  |  Branch (187:36): [True: 21.0k, False: 24.7k]
  ------------------
  188|  21.0k|        delete v.second;
  189|  21.0k|    }
  190|  24.7k|}
_ZNK6Assimp3FBX13PropertyTable3GetERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  195|   207k|{
  196|   207k|    PropertyMap::const_iterator it = props.find(name);
  197|   207k|    if (it == props.end()) {
  ------------------
  |  Branch (197:9): [True: 133k, False: 74.0k]
  ------------------
  198|       |        // hasn't been parsed yet?
  199|   133k|        LazyPropertyMap::const_iterator lit = lazyProps.find(name);
  200|   133k|        if(lit != lazyProps.end()) {
  ------------------
  |  Branch (200:12): [True: 21.0k, False: 112k]
  ------------------
  201|  21.0k|            props[name] = ReadTypedProperty(*(*lit).second);
  202|  21.0k|            it = props.find(name);
  203|       |
  204|  21.0k|            ai_assert(it != props.end());
  ------------------
  |  |   67|  21.0k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 21.0k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  205|  21.0k|        }
  206|       |
  207|   133k|        if (it == props.end()) {
  ------------------
  |  Branch (207:13): [True: 112k, False: 21.0k]
  ------------------
  208|       |            // check property template
  209|   112k|            if(templateProps) {
  ------------------
  |  Branch (209:16): [True: 88.3k, False: 24.3k]
  ------------------
  210|  88.3k|                return templateProps->Get(name);
  211|  88.3k|            }
  212|       |
  213|  24.3k|            return nullptr;
  214|   112k|        }
  215|   133k|    }
  216|       |
  217|  95.0k|    return (*it).second;
  218|   207k|}
_ZNK6Assimp3FBX13PropertyTable21GetUnparsedPropertiesEv:
  221|  3.66k|{
  222|  3.66k|    DirectPropertyMap result;
  223|       |
  224|       |    // Loop through all the lazy properties (which is all the properties)
  225|  21.7k|    for(const LazyPropertyMap::value_type& currentElement : lazyProps) {
  ------------------
  |  Branch (225:59): [True: 21.7k, False: 3.66k]
  ------------------
  226|       |
  227|       |        // Skip parsed properties
  228|  21.7k|        if (props.end() != props.find(currentElement.first)) {
  ------------------
  |  Branch (228:13): [True: 11.1k, False: 10.6k]
  ------------------
  229|  11.1k|            continue;
  230|  11.1k|        }
  231|       |
  232|       |        // Read the element's value.
  233|       |        // Wrap the naked pointer (since the call site is required to acquire ownership)
  234|  10.6k|        std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*currentElement.second));
  235|       |
  236|       |        // Element could not be read. Skip it.
  237|  10.6k|        if (!prop) {
  ------------------
  |  Branch (237:13): [True: 175, False: 10.4k]
  ------------------
  238|    175|            continue;
  239|    175|        }
  240|       |
  241|       |        // Add to result
  242|  10.4k|        result[currentElement.first] = prop;
  243|  10.4k|    }
  244|       |
  245|  3.66k|    return result;
  246|  3.66k|}
FBXProperties.cpp:_ZN6Assimp3FBX12_GLOBAL__N_116PeekPropertyNameERKNS0_7ElementE:
  144|   121k|std::string PeekPropertyName(const Element& element) {
  145|   121k|    ai_assert(element.KeyToken().StringContents() == "P");
  ------------------
  |  |   67|   121k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 121k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  146|       |
  147|   121k|    const TokenList& tok = element.Tokens();
  148|   121k|    if(tok.size() < 4) {
  ------------------
  |  Branch (148:8): [True: 28, False: 121k]
  ------------------
  149|     28|        return std::string();
  150|     28|    }
  151|       |
  152|   121k|    return ParseTokenAsString(*tok[0]);
  153|   121k|}
FBXProperties.cpp:_ZN6Assimp3FBX12_GLOBAL__N_117ReadTypedPropertyERKNS0_7ElementE:
   80|  31.7k|{
   81|  31.7k|    ai_assert(element.KeyToken().StringContents() == "P");
  ------------------
  |  |   67|  31.7k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 31.7k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   82|       |
   83|  31.7k|    const TokenList& tok = element.Tokens();
   84|  31.7k|    if (tok.size() < 2) {
  ------------------
  |  Branch (84:9): [True: 0, False: 31.7k]
  ------------------
   85|      0|        return nullptr;
   86|      0|    }
   87|       |
   88|  31.7k|    const std::string& s = ParseTokenAsString(*tok[1]);
   89|  31.7k|    const char* const cs = s.c_str();
   90|  31.7k|    if (!strcmp(cs,"KString")) {
  ------------------
  |  Branch (90:9): [True: 21, False: 31.6k]
  ------------------
   91|     21|        checkTokenCount(tok, 5);
   92|     21|        return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
   93|     21|    }
   94|  31.6k|    else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
  ------------------
  |  Branch (94:14): [True: 1.40k, False: 30.2k]
  |  Branch (94:36): [True: 1, False: 30.2k]
  ------------------
   95|  1.40k|        checkTokenCount(tok, 5);
   96|  1.40k|        return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
   97|  1.40k|    }
   98|  30.2k|    else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum") || !strcmp(cs, "Integer")) {
  ------------------
  |  Branch (98:14): [True: 5.18k, False: 25.1k]
  |  Branch (98:36): [True: 0, False: 25.1k]
  |  Branch (98:58): [True: 4.92k, False: 20.1k]
  |  Branch (98:81): [True: 0, False: 20.1k]
  |  Branch (98:104): [True: 0, False: 20.1k]
  ------------------
   99|  10.1k|        checkTokenCount(tok, 5);
  100|  10.1k|        return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
  101|  10.1k|    }
  102|  20.1k|    else if (!strcmp(cs, "ULongLong")) {
  ------------------
  |  Branch (102:14): [True: 0, False: 20.1k]
  ------------------
  103|      0|        checkTokenCount(tok, 5);
  104|      0|        return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
  105|      0|    }
  106|  20.1k|    else if (!strcmp(cs, "KTime")) {
  ------------------
  |  Branch (106:14): [True: 893, False: 19.2k]
  ------------------
  107|    893|        checkTokenCount(tok, 5);
  108|    893|        return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
  109|    893|    }
  110|  19.2k|    else if (!strcmp(cs,"Vector3D") ||
  ------------------
  |  Branch (110:14): [True: 2.36k, False: 16.9k]
  ------------------
  111|  16.9k|        !strcmp(cs,"ColorRGB") ||
  ------------------
  |  Branch (111:9): [True: 215, False: 16.7k]
  ------------------
  112|  16.7k|        !strcmp(cs,"Vector") ||
  ------------------
  |  Branch (112:9): [True: 12, False: 16.6k]
  ------------------
  113|  16.6k|        !strcmp(cs,"Color") ||
  ------------------
  |  Branch (113:9): [True: 721, False: 15.9k]
  ------------------
  114|  15.9k|        !strcmp(cs,"Lcl Translation") ||
  ------------------
  |  Branch (114:9): [True: 3.98k, False: 11.9k]
  ------------------
  115|  11.9k|        !strcmp(cs,"Lcl Rotation") ||
  ------------------
  |  Branch (115:9): [True: 3.77k, False: 8.22k]
  ------------------
  116|  8.22k|        !strcmp(cs,"Lcl Scaling")
  ------------------
  |  Branch (116:9): [True: 3.77k, False: 4.44k]
  ------------------
  117|  19.2k|        ) {
  118|  14.8k|        checkTokenCount(tok, 7);
  119|  14.8k|        return new TypedProperty<aiVector3D>(aiVector3D(
  120|  14.8k|            ParseTokenAsFloat(*tok[4]),
  121|  14.8k|            ParseTokenAsFloat(*tok[5]),
  122|  14.8k|            ParseTokenAsFloat(*tok[6]))
  123|  14.8k|        );
  124|  14.8k|    }
  125|  4.44k|    else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"float") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) {
  ------------------
  |  Branch (125:14): [True: 3.04k, False: 1.40k]
  |  Branch (125:38): [True: 965, False: 436]
  |  Branch (125:62): [True: 0, False: 436]
  |  Branch (125:85): [True: 0, False: 436]
  |  Branch (125:108): [True: 218, False: 218]
  |  Branch (125:137): [True: 0, False: 218]
  ------------------
  126|  4.22k|        checkTokenCount(tok, 5);
  127|  4.22k|        return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
  128|  4.22k|    }
  129|    219|    else if (!strcmp(cs, "ColorAndAlpha")) {
  ------------------
  |  Branch (129:14): [True: 0, False: 219]
  ------------------
  130|      0|        checkTokenCount(tok, 8);
  131|      0|        return new TypedProperty<aiColor4D>(aiColor4D(
  132|      0|            ParseTokenAsFloat(*tok[4]),
  133|      0|            ParseTokenAsFloat(*tok[5]),
  134|      0|            ParseTokenAsFloat(*tok[6]),
  135|      0|            ParseTokenAsFloat(*tok[7]))
  136|      0|        );
  137|      0|    }
  138|    219|    return nullptr;
  139|  31.7k|}
FBXProperties.cpp:_ZN6Assimp3FBX12_GLOBAL__N_115checkTokenCountERKNSt3__16vectorIPKNS0_5TokenENS2_9allocatorIS6_EEEEj:
   65|  31.4k|    void checkTokenCount(const TokenList &tok, unsigned int expectedCount) {
   66|  31.4k|        ai_assert(expectedCount >= 2);
  ------------------
  |  |   67|  31.4k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 31.4k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   67|  31.4k|        if (tok.size() < expectedCount) {
  ------------------
  |  Branch (67:13): [True: 2, False: 31.4k]
  ------------------
   68|      2|            const std::string &s = ParseTokenAsString(*tok[1]);
   69|      2|            if (tok[1]->IsBinary()) {
  ------------------
  |  Branch (69:17): [True: 0, False: 2]
  ------------------
   70|      0|                throw DeadlyImportError("Not enough tokens for property of type ", s, " at offset ", tok[1]->Offset());
   71|      2|            } else {
   72|      2|                throw DeadlyImportError("Not enough tokens for property of type ", s, " at line ", tok[1]->Line());
   73|      2|            }
   74|      2|        }
   75|  31.4k|}

_ZN6Assimp3FBX13PropertyTableC2Ev:
  104|  3.27k|    PropertyTable() : element() {}
_ZNK6Assimp3FBX13PropertyTable13TemplatePropsEv:
  115|    107|    const PropertyTable* TemplateProps() const {
  116|    107|        return templateProps.get();
  117|    107|    }
_ZN6Assimp3FBX11PropertyGetI10aiVector3tIfEEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEERKS4_:
  130|  8.58k|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|  8.58k|    const Property* const prop = in.Get(name);
  132|  8.58k|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 67, False: 8.51k]
  ------------------
  133|     67|        return defaultValue;
  134|     67|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|  8.51k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|  8.51k|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 0, False: 8.51k]
  ------------------
  139|      0|        return defaultValue;
  140|      0|    }
  141|       |
  142|  8.51k|    return tprop->Value();
  143|  8.51k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyI10aiVector3tIfEEEEEPKT_v:
   73|  81.7k|    const T* As() const {
   74|  81.7k|        return dynamic_cast<const T*>(this);
   75|  81.7k|    }
_ZNK6Assimp3FBX13TypedPropertyI10aiVector3tIfEE5ValueEv:
   86|  81.6k|    const T& Value() const {
   87|  81.6k|        return value;
   88|  81.6k|    }
_ZN6Assimp3FBX11PropertyGetIfEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERKS2_:
  130|  2.72k|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|  2.72k|    const Property* const prop = in.Get(name);
  132|  2.72k|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 145, False: 2.57k]
  ------------------
  133|    145|        return defaultValue;
  134|    145|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|  2.57k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|  2.57k|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 0, False: 2.57k]
  ------------------
  139|      0|        return defaultValue;
  140|      0|    }
  141|       |
  142|  2.57k|    return tprop->Value();
  143|  2.57k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIfEEEEPKT_v:
   73|  4.96k|    const T* As() const {
   74|  4.96k|        return dynamic_cast<const T*>(this);
   75|  4.96k|    }
_ZNK6Assimp3FBX13TypedPropertyIfE5ValueEv:
   86|  4.70k|    const T& Value() const {
   87|  4.70k|        return value;
   88|  4.70k|    }
_ZN6Assimp3FBX11PropertyGetIiEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERKS2_:
  130|  9.54k|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|  9.54k|    const Property* const prop = in.Get(name);
  132|  9.54k|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 555, False: 8.99k]
  ------------------
  133|    555|        return defaultValue;
  134|    555|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|  8.99k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|  8.99k|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 54, False: 8.93k]
  ------------------
  139|     54|        return defaultValue;
  140|     54|    }
  141|       |
  142|  8.93k|    return tprop->Value();
  143|  8.99k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIiEEEEPKT_v:
   73|  17.9k|    const T* As() const {
   74|  17.9k|        return dynamic_cast<const T*>(this);
   75|  17.9k|    }
_ZNK6Assimp3FBX13TypedPropertyIiE5ValueEv:
   86|  16.4k|    const T& Value() const {
   87|  16.4k|        return value;
   88|  16.4k|    }
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIbEEEEPKT_v:
   73|  10.3k|    const T* As() const {
   74|  10.3k|        return dynamic_cast<const T*>(this);
   75|  10.3k|    }
_ZNK6Assimp3FBX13TypedPropertyIbE5ValueEv:
   86|  1.38k|    const T& Value() const {
   87|  1.38k|        return value;
   88|  1.38k|    }
_ZN6Assimp3FBX11PropertyGetINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEET_RKNS0_13PropertyTableERKS8_RKS9_:
  130|  3.56k|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|  3.56k|    const Property* const prop = in.Get(name);
  132|  3.56k|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 3.56k, False: 0]
  ------------------
  133|  3.56k|        return defaultValue;
  134|  3.56k|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|      0|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|      0|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 0, False: 0]
  ------------------
  139|      0|        return defaultValue;
  140|      0|    }
  141|       |
  142|      0|    return tprop->Value();
  143|      0|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyINSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEEEPKT_v:
   73|    264|    const T* As() const {
   74|    264|        return dynamic_cast<const T*>(this);
   75|    264|    }
_ZNK6Assimp3FBX13TypedPropertyINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEE5ValueEv:
   86|     24|    const T& Value() const {
   87|     24|        return value;
   88|     24|    }
_ZN6Assimp3FBX11PropertyGetIlEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERKS2_:
  130|    490|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|    490|    const Property* const prop = in.Get(name);
  132|    490|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 12, False: 478]
  ------------------
  133|     12|        return defaultValue;
  134|     12|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|    478|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|    478|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 0, False: 478]
  ------------------
  139|      0|        return defaultValue;
  140|      0|    }
  141|       |
  142|    478|    return tprop->Value();
  143|    478|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIlEEEEPKT_v:
   73|  1.84k|    const T* As() const {
   74|  1.84k|        return dynamic_cast<const T*>(this);
   75|  1.84k|    }
_ZNK6Assimp3FBX13TypedPropertyIlE5ValueEv:
   86|    478|    const T& Value() const {
   87|    478|        return value;
   88|    478|    }
_ZN6Assimp3FBX11PropertyGetImEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERKS2_:
  130|    454|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|    454|    const Property* const prop = in.Get(name);
  132|    454|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 42, False: 412]
  ------------------
  133|     42|        return defaultValue;
  134|     42|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|    412|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|    412|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 412, False: 0]
  ------------------
  139|    412|        return defaultValue;
  140|    412|    }
  141|       |
  142|      0|    return tprop->Value();
  143|    412|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyImEEEEPKT_v:
   73|  1.77k|    const T* As() const {
   74|  1.77k|        return dynamic_cast<const T*>(this);
   75|  1.77k|    }
_ZN6Assimp3FBX11PropertyGetI10aiVector3tIfEEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEERbb:
  147|  92.3k|inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
  148|  92.3k|    const Property* prop = in.Get(name);
  149|  92.3k|    if( nullptr == prop) {
  ------------------
  |  Branch (149:9): [True: 19.5k, False: 72.8k]
  ------------------
  150|  19.5k|        if ( ! useTemplate ) {
  ------------------
  |  Branch (150:14): [True: 19.4k, False: 100]
  ------------------
  151|  19.4k|            result = false;
  152|  19.4k|            return T();
  153|  19.4k|        }
  154|    100|        const PropertyTable* templ = in.TemplateProps();
  155|    100|        if ( nullptr == templ ) {
  ------------------
  |  Branch (155:14): [True: 23, False: 77]
  ------------------
  156|     23|            result = false;
  157|     23|            return T();
  158|     23|        }
  159|     77|        prop = templ->Get(name);
  160|     77|        if ( nullptr == prop ) {
  ------------------
  |  Branch (160:14): [True: 77, False: 0]
  ------------------
  161|     77|            result = false;
  162|     77|            return T();
  163|     77|        }
  164|     77|    }
  165|       |
  166|       |    // strong typing, no need to be lenient
  167|  72.8k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  168|  72.8k|    if( nullptr == tprop) {
  ------------------
  |  Branch (168:9): [True: 1, False: 72.8k]
  ------------------
  169|      1|        result = false;
  170|      1|        return T();
  171|      1|    }
  172|       |
  173|  72.8k|    result = true;
  174|  72.8k|    return tprop->Value();
  175|  72.8k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIjEEEEPKT_v:
   73|  1.36k|    const T* As() const {
   74|  1.36k|        return dynamic_cast<const T*>(this);
   75|  1.36k|    }
_ZN6Assimp3FBX11PropertyGetINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEET_RKNS0_13PropertyTableERKS8_Rbb:
  147|      6|inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
  148|      6|    const Property* prop = in.Get(name);
  149|      6|    if( nullptr == prop) {
  ------------------
  |  Branch (149:9): [True: 0, False: 6]
  ------------------
  150|      0|        if ( ! useTemplate ) {
  ------------------
  |  Branch (150:14): [True: 0, False: 0]
  ------------------
  151|      0|            result = false;
  152|      0|            return T();
  153|      0|        }
  154|      0|        const PropertyTable* templ = in.TemplateProps();
  155|      0|        if ( nullptr == templ ) {
  ------------------
  |  Branch (155:14): [True: 0, False: 0]
  ------------------
  156|      0|            result = false;
  157|      0|            return T();
  158|      0|        }
  159|      0|        prop = templ->Get(name);
  160|      0|        if ( nullptr == prop ) {
  ------------------
  |  Branch (160:14): [True: 0, False: 0]
  ------------------
  161|      0|            result = false;
  162|      0|            return T();
  163|      0|        }
  164|      0|    }
  165|       |
  166|       |    // strong typing, no need to be lenient
  167|      6|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  168|      6|    if( nullptr == tprop) {
  ------------------
  |  Branch (168:9): [True: 0, False: 6]
  ------------------
  169|      0|        result = false;
  170|      0|        return T();
  171|      0|    }
  172|       |
  173|      6|    result = true;
  174|      6|    return tprop->Value();
  175|      6|}
_ZN6Assimp3FBX11PropertyGetIfEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERbb:
  147|  1.62k|inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
  148|  1.62k|    const Property* prop = in.Get(name);
  149|  1.62k|    if( nullptr == prop) {
  ------------------
  |  Branch (149:9): [True: 707, False: 919]
  ------------------
  150|    707|        if ( ! useTemplate ) {
  ------------------
  |  Branch (150:14): [True: 700, False: 7]
  ------------------
  151|    700|            result = false;
  152|    700|            return T();
  153|    700|        }
  154|      7|        const PropertyTable* templ = in.TemplateProps();
  155|      7|        if ( nullptr == templ ) {
  ------------------
  |  Branch (155:14): [True: 6, False: 1]
  ------------------
  156|      6|            result = false;
  157|      6|            return T();
  158|      6|        }
  159|      1|        prop = templ->Get(name);
  160|      1|        if ( nullptr == prop ) {
  ------------------
  |  Branch (160:14): [True: 1, False: 0]
  ------------------
  161|      1|            result = false;
  162|      1|            return T();
  163|      1|        }
  164|      1|    }
  165|       |
  166|       |    // strong typing, no need to be lenient
  167|    919|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  168|    919|    if( nullptr == tprop) {
  ------------------
  |  Branch (168:9): [True: 0, False: 919]
  ------------------
  169|      0|        result = false;
  170|      0|        return T();
  171|      0|    }
  172|       |
  173|    919|    result = true;
  174|    919|    return tprop->Value();
  175|    919|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyI9aiColor3DEEEEPKT_v:
   73|    106|    const T* As() const {
   74|    106|        return dynamic_cast<const T*>(this);
   75|    106|    }
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyI9aiColor4tIfEEEEEPKT_v:
   73|    106|    const T* As() const {
   74|    106|        return dynamic_cast<const T*>(this);
   75|    106|    }
_ZN6Assimp3FBX13TypedPropertyINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEC2ERKS8_:
   84|     21|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX8PropertyC2Ev:
   78|  31.4k|    Property() = default;
_ZN6Assimp3FBX8PropertyD2Ev:
   70|  31.4k|    virtual ~Property() = default;
_ZN6Assimp3FBX13TypedPropertyIbEC2ERKb:
   84|  1.40k|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyIiEC2ERKi:
   84|  10.1k|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyIlEC2ERKl:
   84|    892|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyI10aiVector3tIfEEC2ERKS3_:
   84|  14.8k|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyIfEC2ERKf:
   84|  4.22k|    explicit TypedProperty(const T& value) : value(value) {}

_ZN6Assimp3FBX5TokenC2EPKcS3_NS0_9TokenTypeEjj:
   67|  2.90M|    sbegin(sbegin)
   68|  2.90M|    , send(send)
   69|  2.90M|    , type(type)
   70|  2.90M|    , line(line)
   71|  2.90M|    , column(column)
   72|  2.90M|{
   73|  2.90M|    ai_assert(sbegin);
   74|  2.90M|    ai_assert(send);
   75|       |
   76|       |    // tokens must be of non-zero length
   77|       |    ai_assert(static_cast<size_t>(send-sbegin) > 0);
   78|  2.90M|}
_ZN6Assimp3FBX8TokenizeERNSt3__16vectorIPKNS0_5TokenENS1_9allocatorIS5_EEEEPKcRNS_14StackAllocatorE:
  134|     39|void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &token_allocator) {
  135|     39|	ai_assert(input);
  136|     39|	ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file");
  137|       |
  138|       |    // line and column numbers numbers are one-based
  139|     39|    unsigned int line = 1;
  140|     39|    unsigned int column = 1;
  141|       |
  142|     39|    bool comment = false;
  143|     39|    bool in_double_quotes = false;
  144|     39|    bool pending_data_token = false;
  145|       |
  146|     39|    const char *token_begin = nullptr, *token_end = nullptr;
  147|  14.3M|    for (const char* cur = input;*cur;column += (*cur == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1), ++cur) {
  ------------------
  |  |   49|  57.5k|#define ASSIMP_FBX_TAB_WIDTH 4
  ------------------
  |  Branch (147:34): [True: 14.3M, False: 38]
  |  Branch (147:50): [True: 57.5k, False: 14.2M]
  ------------------
  148|  14.3M|        const char c = *cur;
  149|       |
  150|  14.3M|        if (IsLineEnd(c)) {
  ------------------
  |  Branch (150:13): [True: 58.3k, False: 14.2M]
  ------------------
  151|  58.3k|            comment = false;
  152|       |
  153|  58.3k|            column = 0;
  154|  58.3k|            ++line;
  155|  58.3k|        }
  156|       |
  157|  14.3M|        if(comment) {
  ------------------
  |  Branch (157:12): [True: 1.10M, False: 13.2M]
  ------------------
  158|  1.10M|            continue;
  159|  1.10M|        }
  160|       |
  161|  13.2M|        if(in_double_quotes) {
  ------------------
  |  Branch (161:12): [True: 3.94M, False: 9.26M]
  ------------------
  162|  3.94M|            if (c == '\"') {
  ------------------
  |  Branch (162:17): [True: 22.5k, False: 3.92M]
  ------------------
  163|  22.5k|                in_double_quotes = false;
  164|  22.5k|                token_end = cur;
  165|       |
  166|  22.5k|                ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
  167|  22.5k|                pending_data_token = false;
  168|  22.5k|            }
  169|  3.94M|            continue;
  170|  3.94M|        }
  171|       |
  172|  9.26M|        switch(c)
  ------------------
  |  Branch (172:16): [True: 2.10M, False: 7.15M]
  ------------------
  173|  9.26M|        {
  174|  22.5k|        case '\"':
  ------------------
  |  Branch (174:9): [True: 22.5k, False: 9.24M]
  ------------------
  175|  22.5k|            if (token_begin) {
  ------------------
  |  Branch (175:17): [True: 1, False: 22.5k]
  ------------------
  176|      1|                TokenizeError("unexpected double-quote", line, column);
  177|      1|            }
  178|  22.5k|            token_begin = cur;
  179|  22.5k|            in_double_quotes = true;
  180|  22.5k|            continue;
  181|       |
  182|  25.2k|        case ';':
  ------------------
  |  Branch (182:9): [True: 25.2k, False: 9.24M]
  ------------------
  183|  25.2k|            ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
  184|  25.2k|            comment = true;
  185|  25.2k|            continue;
  186|       |
  187|   961k|        case '{':
  ------------------
  |  Branch (187:9): [True: 961k, False: 8.30M]
  ------------------
  188|   961k|            ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
  189|   961k|            output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
  ------------------
  |  |  160|  1.92M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  190|   961k|            continue;
  191|       |
  192|  1.37k|        case '}':
  ------------------
  |  Branch (192:9): [True: 1.37k, False: 9.26M]
  ------------------
  193|  1.37k|            ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
  194|  1.37k|            output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
  ------------------
  |  |  160|  2.74k|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  195|  1.37k|            continue;
  196|       |
  197|  1.08M|        case ',':
  ------------------
  |  Branch (197:9): [True: 1.08M, False: 8.18M]
  ------------------
  198|  1.08M|            if (pending_data_token) {
  ------------------
  |  Branch (198:17): [True: 752k, False: 327k]
  ------------------
  199|   752k|                ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_DATA, true);
  200|   752k|            }
  201|  1.08M|            output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
  ------------------
  |  |  160|  2.16M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  202|  1.08M|            continue;
  203|       |
  204|  17.4k|        case ':':
  ------------------
  |  Branch (204:9): [True: 17.4k, False: 9.24M]
  ------------------
  205|  17.4k|            if (pending_data_token) {
  ------------------
  |  Branch (205:17): [True: 17.4k, False: 0]
  ------------------
  206|  17.4k|                ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_KEY, true);
  207|  17.4k|            }
  208|      0|            else {
  209|      0|                TokenizeError("unexpected colon", line, column);
  210|      0|            }
  211|  17.4k|            continue;
  212|  9.26M|        }
  213|       |
  214|  7.15M|        if (IsSpaceOrNewLine(c)) {
  ------------------
  |  Branch (214:13): [True: 141k, False: 7.01M]
  ------------------
  215|       |
  216|   141k|            if (token_begin) {
  ------------------
  |  Branch (216:17): [True: 13.1k, False: 127k]
  ------------------
  217|       |                // peek ahead and check if the next token is a colon in which
  218|       |                // case this counts as KEY token.
  219|  13.1k|                TokenType type = TokenType_DATA;
  220|  63.6k|                for (const char* peek = cur;  *peek && IsSpaceOrNewLine(*peek); ++peek) {
  ------------------
  |  Branch (220:47): [True: 63.6k, False: 2]
  |  Branch (220:56): [True: 50.4k, False: 13.1k]
  ------------------
  221|  50.4k|                    if (*peek == ':') {
  ------------------
  |  Branch (221:25): [True: 0, False: 50.4k]
  ------------------
  222|      0|                        type = TokenType_KEY;
  223|      0|                        cur = peek;
  224|      0|                        break;
  225|      0|                    }
  226|  50.4k|                }
  227|       |
  228|  13.1k|                ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, type);
  229|  13.1k|            }
  230|       |
  231|   141k|            pending_data_token = false;
  232|   141k|        }
  233|  7.01M|        else {
  234|  7.01M|            token_end = cur;
  235|  7.01M|            if (!token_begin) {
  ------------------
  |  Branch (235:17): [True: 835k, False: 6.18M]
  ------------------
  236|   835k|                token_begin = cur;
  237|   835k|            }
  238|       |
  239|  7.01M|            pending_data_token = true;
  240|  7.01M|        }
  241|  7.15M|    }
  242|     39|}
FBXTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_116ProcessDataTokenERNSt3__16vectorIPKNS0_5TokenENS2_9allocatorIS6_EEEERNS_14StackAllocatorERPKcSF_jjNS0_9TokenTypeEb:
  102|  1.79M|{
  103|  1.79M|    if (start && end) {
  ------------------
  |  Branch (103:9): [True: 858k, False: 935k]
  |  Branch (103:18): [True: 858k, False: 0]
  ------------------
  104|       |        // sanity check:
  105|       |        // tokens should have no whitespace outside quoted text and [start,end] should
  106|       |        // properly delimit the valid range.
  107|   858k|        bool in_double_quotes = false;
  108|  11.8M|        for (const char* c = start; c != end + 1; ++c) {
  ------------------
  |  Branch (108:37): [True: 10.9M, False: 858k]
  ------------------
  109|  10.9M|            if (*c == '\"') {
  ------------------
  |  Branch (109:17): [True: 45.1k, False: 10.9M]
  ------------------
  110|  45.1k|                in_double_quotes = !in_double_quotes;
  111|  45.1k|            }
  112|       |
  113|  10.9M|            if (!in_double_quotes && IsSpaceOrNewLine(*c)) {
  ------------------
  |  Branch (113:17): [True: 7.03M, False: 3.94M]
  |  Branch (113:38): [True: 0, False: 7.03M]
  ------------------
  114|      0|                TokenizeError("unexpected whitespace in token", line, column);
  115|      0|            }
  116|  10.9M|        }
  117|       |
  118|   858k|        if (in_double_quotes) {
  ------------------
  |  Branch (118:13): [True: 0, False: 858k]
  ------------------
  119|      0|            TokenizeError("non-terminated double quotes", line, column);
  120|      0|        }
  121|       |
  122|   858k|        output_tokens.push_back(new_Token(start,end + 1,type,line,column));
  ------------------
  |  |  160|  1.71M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  123|   858k|    }
  124|   935k|    else if (must_have_token) {
  ------------------
  |  Branch (124:14): [True: 0, False: 935k]
  ------------------
  125|      0|        TokenizeError("unexpected character, expected data token", line, column);
  126|      0|    }
  127|       |
  128|  1.79M|    start = end = nullptr;
  129|  1.79M|}
FBXTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_113TokenizeErrorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEjj:
   89|      1|{
   90|      1|    throw DeadlyImportError("FBX-Tokenize", Util::GetLineAndColumnText(line,column), message);
   91|      1|}

_ZNK6Assimp3FBX5Token14StringContentsEv:
  102|   802k|    std::string StringContents() const {
  103|   802k|        return std::string(begin(),end());
  104|   802k|    }
_ZNK6Assimp3FBX5Token8IsBinaryEv:
  106|  1.72M|    bool IsBinary() const {
  107|  1.72M|        return column == BINARY_MARKER;
  108|  1.72M|    }
_ZNK6Assimp3FBX5Token5beginEv:
  110|  3.29M|    const char* begin() const {
  111|  3.29M|        return sbegin;
  112|  3.29M|    }
_ZNK6Assimp3FBX5Token3endEv:
  114|  3.51M|    const char* end() const {
  115|  3.51M|        return send;
  116|  3.51M|    }
_ZNK6Assimp3FBX5Token4TypeEv:
  118|  13.9M|    TokenType Type() const {
  119|  13.9M|        return type;
  120|  13.9M|    }
_ZNK6Assimp3FBX5Token6OffsetEv:
  122|  6.01k|    size_t Offset() const {
  123|  6.01k|        ai_assert(IsBinary());
  ------------------
  |  |   67|  6.01k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 6.01k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  124|  6.01k|        return offset;
  125|  6.01k|    }
_ZNK6Assimp3FBX5Token4LineEv:
  127|  71.8k|    unsigned int Line() const {
  128|  71.8k|        ai_assert(!IsBinary());
  ------------------
  |  |   67|  71.8k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 71.8k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  129|  71.8k|        return static_cast<unsigned int>(line);
  130|  71.8k|    }
_ZNK6Assimp3FBX5Token6ColumnEv:
  132|  71.7k|    unsigned int Column() const {
  133|  71.7k|        ai_assert(!IsBinary());
  ------------------
  |  |   67|  71.7k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 71.7k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  134|  71.7k|        return column;
  135|  71.7k|    }

_ZN6Assimp3FBX4Util15TokenTypeStringENS0_9TokenTypeE:
   57|  77.8k|{
   58|  77.8k|    switch(t) {
  ------------------
  |  Branch (58:12): [True: 77.8k, False: 0]
  ------------------
   59|      1|        case TokenType_OPEN_BRACKET:
  ------------------
  |  Branch (59:9): [True: 1, False: 77.8k]
  ------------------
   60|      1|            return "TOK_OPEN_BRACKET";
   61|       |
   62|      0|        case TokenType_CLOSE_BRACKET:
  ------------------
  |  Branch (62:9): [True: 0, False: 77.8k]
  ------------------
   63|      0|            return "TOK_CLOSE_BRACKET";
   64|       |
   65|     36|        case TokenType_DATA:
  ------------------
  |  Branch (65:9): [True: 36, False: 77.7k]
  ------------------
   66|     36|            return "TOK_DATA";
   67|       |
   68|      1|        case TokenType_COMMA:
  ------------------
  |  Branch (68:9): [True: 1, False: 77.8k]
  ------------------
   69|      1|            return "TOK_COMMA";
   70|       |
   71|  77.7k|        case TokenType_KEY:
  ------------------
  |  Branch (71:9): [True: 77.7k, False: 38]
  ------------------
   72|  77.7k|            return "TOK_KEY";
   73|       |
   74|      0|        case TokenType_BINARY_DATA:
  ------------------
  |  Branch (74:9): [True: 0, False: 77.8k]
  ------------------
   75|      0|            return "TOK_BINARY_DATA";
   76|  77.8k|    }
   77|       |
   78|      0|    ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   79|      0|    return "";
   80|  77.8k|}
_ZN6Assimp3FBX4Util13GetOffsetTextEm:
   85|      8|{
   86|      8|    return static_cast<std::string>( Formatter::format() << " (offset 0x" << std::hex << offset << ") " );
   87|      8|}
_ZN6Assimp3FBX4Util20GetLineAndColumnTextEjj:
   91|      1|{
   92|      1|    return static_cast<std::string>( Formatter::format() << " (line " << line << " <<  col " << column << ") " );
   93|      1|}
_ZN6Assimp3FBX4Util12GetTokenTextEPKNS0_5TokenE:
   97|  77.8k|{
   98|  77.8k|    if(tok->IsBinary()) {
  ------------------
  |  Branch (98:8): [True: 6.01k, False: 71.7k]
  ------------------
   99|  6.01k|        return static_cast<std::string>( Formatter::format() <<
  100|  6.01k|            " (" << TokenTypeString(tok->Type()) <<
  101|  6.01k|            ", offset 0x" << std::hex << tok->Offset() << ") " );
  102|  6.01k|    }
  103|       |
  104|  71.7k|    return static_cast<std::string>( Formatter::format() <<
  105|  71.7k|        " (" << TokenTypeString(tok->Type()) <<
  106|  71.7k|        ", line " << tok->Line() <<
  107|  71.7k|        ", col " << tok->Column() << ") " );
  108|  77.8k|}
_ZN6Assimp3FBX4Util12DecodeBase64Ec:
  123|   695k|{
  124|   695k|    const auto idx = static_cast<uint8_t>(ch);
  125|   695k|    if (idx > 127)
  ------------------
  |  Branch (125:9): [True: 3, False: 695k]
  ------------------
  126|      3|        return 255;
  127|   695k|    return base64DecodeTable[idx];
  128|   695k|}
_ZN6Assimp3FBX4Util24ComputeDecodedSizeBase64EPKcm:
  131|      4|{
  132|      4|    if (inLength < 2)
  ------------------
  |  Branch (132:9): [True: 0, False: 4]
  ------------------
  133|      0|    {
  134|      0|        return 0;
  135|      0|    }
  136|      4|    const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
  137|      4|    const size_t full_length = (inLength * 3) >> 2; // div by 4
  138|      4|    if (full_length < equals)
  ------------------
  |  Branch (138:9): [True: 0, False: 4]
  ------------------
  139|      0|    {
  140|      0|        return 0;
  141|      0|    }
  142|      4|    return full_length - equals;
  143|      4|}
_ZN6Assimp3FBX4Util12DecodeBase64EPKcmPhm:
  146|      4|{
  147|      4|    if (maxOutLength == 0 || inLength < 2) {
  ------------------
  |  Branch (147:9): [True: 0, False: 4]
  |  Branch (147:30): [True: 0, False: 4]
  ------------------
  148|      0|        return 0;
  149|      0|    }
  150|      4|    const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
  151|      4|    size_t dst_offset = 0;
  152|      4|    int val = 0, valb = -8;
  153|   695k|    for (size_t src_offset = 0; src_offset < realLength && dst_offset < maxOutLength; ++src_offset)
  ------------------
  |  Branch (153:33): [True: 695k, False: 1]
  |  Branch (153:60): [True: 695k, False: 0]
  ------------------
  154|   695k|    {
  155|   695k|        const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
  156|   695k|        if (table_value == 255)
  ------------------
  |  Branch (156:13): [True: 3, False: 695k]
  ------------------
  157|      3|        {
  158|      3|            return 0;
  159|      3|        }
  160|   695k|        val = (val << 6) + table_value;
  161|   695k|        valb += 6;
  162|   695k|        if (valb >= 0)
  ------------------
  |  Branch (162:13): [True: 521k, False: 173k]
  ------------------
  163|   521k|        {
  164|   521k|            out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
  165|   521k|            valb -= 8;
  166|   521k|            val &= 0xFFF;
  167|   521k|        }
  168|   695k|    }
  169|      1|    return dst_offset;
  170|      4|}

_ZN6Assimp3FBX4Util14destructor_funINS0_5TokenEEclEPVKS3_:
   66|  6.14M|    void operator()(const volatile T* del) {
   67|  6.14M|        if (del) {
  ------------------
  |  Branch (67:13): [True: 6.14M, False: 0]
  ------------------
   68|  6.14M|            del->~T();
   69|  6.14M|        }
   70|  6.14M|    }
_ZN6Assimp3FBX4Util10delete_funI6aiMeshEclEPVKS3_:
   58|     95|    void operator()(const volatile T* del) {
   59|     95|        delete del;
   60|     95|    }
_ZN6Assimp3FBX4Util10delete_funI10aiMaterialEclEPVKS3_:
   58|     93|    void operator()(const volatile T* del) {
   59|     93|        delete del;
   60|     93|    }
_ZN6Assimp3FBX4Util10delete_funI11aiAnimationEclEPVKS3_:
   58|    208|    void operator()(const volatile T* del) {
   59|    208|        delete del;
   60|    208|    }
_ZN6Assimp3FBX4Util10delete_funI7aiLightEclEPVKS3_:
   58|    198|    void operator()(const volatile T* del) {
   59|    198|        delete del;
   60|    198|    }
_ZN6Assimp3FBX4Util10delete_funI8aiCameraEclEPVKS3_:
   58|    206|    void operator()(const volatile T* del) {
   59|    206|        delete del;
   60|    206|    }
_ZN6Assimp3FBX4Util10delete_funI9aiTextureEclEPVKS3_:
   58|      1|    void operator()(const volatile T* del) {
   59|      1|        delete del;
   60|      1|    }
_ZN6Assimp3FBX4Util10delete_funI10aiNodeAnimEclEPVKS3_:
   58|     60|    void operator()(const volatile T* del) {
   59|     60|        delete del;
   60|     60|    }

_ZN6Assimp11HMPImporterC2Ev:
   75|    297|HMPImporter::HMPImporter() = default;
_ZN6Assimp11HMPImporterD2Ev:
   79|    297|HMPImporter::~HMPImporter() = default;
_ZNK6Assimp11HMPImporter7GetInfoEv:
   94|    297|const aiImporterDesc *HMPImporter::GetInfo() const {
   95|    297|    return &desc;
   96|    297|}

_ZNK6Assimp11IFCImporter7GetInfoEv:
  131|    297|const aiImporterDesc *IFCImporter::GetInfo() const {
  132|    297|    return &desc;
  133|    297|}

_ZN6Assimp11IFCImporterC2Ev:
   89|    297|    IFCImporter() = default;
_ZN6Assimp11IFCImporter8SettingsC2Ev:
   80|    297|                skipSpaceRepresentations(), useCustomTriangulation(), skipAnnotations(), conicSamplingAngle(10.f), cylindricalTessellation(32) {}

_ZN6Assimp11IQMImporterC2Ev:
   87|    297|        mScene(nullptr) {
   88|       |    // empty
   89|    297|}
_ZNK6Assimp11IQMImporter7GetInfoEv:
  113|    297|const aiImporterDesc *IQMImporter::GetInfo() const {
  114|    297|    return &desc;
  115|    297|}

_ZN6Assimp11IRRImporterC2Ev:
   85|    297|        fps(), configSpeedFlag() {
   86|       |    // empty
   87|    297|}
_ZN6Assimp11IRRImporterD2Ev:
   91|    297|IRRImporter::~IRRImporter() = default;
_ZNK6Assimp11IRRImporter7GetInfoEv:
  101|    297|const aiImporterDesc *IRRImporter::GetInfo() const {
  102|    297|    return &desc;
  103|    297|}

_ZNK6Assimp15IRRMeshImporter7GetInfoEv:
   86|    297|const aiImporterDesc *IRRMeshImporter::GetInfo() const {
   87|    297|    return &desc;
   88|    297|}

_ZN6Assimp15IRRMeshImporterC2Ev:
   66|    297|    IRRMeshImporter() = default;
_ZN6Assimp15IRRMeshImporterD2Ev:
   69|    297|    ~IRRMeshImporter() override = default;

_ZN6Assimp12IrrlichtBaseC2Ev:
   61|    594|    IrrlichtBase() {
   62|       |        // empty
   63|    594|    }
_ZN6Assimp12IrrlichtBaseD2Ev:
   65|    594|    ~IrrlichtBase() = default;

_ZNK6Assimp11LWOImporter7GetInfoEv:
  101|    297|const aiImporterDesc *LWOImporter::GetInfo() const {
  102|    297|    return &desc;
  103|    297|}

_ZN6Assimp11LWOImporterC2Ev:
   77|    297|    LWOImporter() = default;
_ZN6Assimp11LWOImporterD2Ev:
   82|    297|    ~LWOImporter() override = default;

_ZN6Assimp11LWSImporterC2Ev:
  145|    297|        noSkeletonMesh() {
  146|       |    // nothing to do here
  147|    297|}
_ZNK6Assimp11LWSImporter7GetInfoEv:
  161|    297|const aiImporterDesc *LWSImporter::GetInfo() const {
  162|    297|    return &desc;
  163|    297|}

_ZN6Assimp11MD2ImporterC2Ev:
   98|    297|{}
_ZNK6Assimp11MD2Importer7GetInfoEv:
  111|    297|{
  112|    297|    return &desc;
  113|    297|}

_ZN6Assimp11MD3ImporterC2Ev:
  344|    297|        configFrameID(0), configHandleMP(true), configSpeedFlag(), pcHeader(), mBuffer(), fileSize(), mScene(), mIOHandler() {}
_ZN6Assimp11MD3ImporterD2Ev:
  348|    297|MD3Importer::~MD3Importer() = default;
_ZNK6Assimp11MD3Importer7GetInfoEv:
  431|    297|const aiImporterDesc *MD3Importer::GetInfo() const {
  432|    297|    return &desc;
  433|    297|}

_ZN6Assimp11MD5ImporterC2Ev:
   83|    297|        mIOHandler(nullptr),
   84|       |        mBuffer(),
   85|       |        mFileSize(),
   86|       |        mLineNumber(),
   87|       |        mScene(),
   88|       |        mHadMD5Mesh(),
   89|       |        mHadMD5Anim(),
   90|       |        mHadMD5Camera(),
   91|    297|        mCconfigNoAutoLoad(false) {
   92|       |    // empty
   93|    297|}
_ZNK6Assimp11MD5Importer7GetInfoEv:
  104|    297|const aiImporterDesc *MD5Importer::GetInfo() const {
  105|    297|    return &desc;
  106|    297|}

_ZN6Assimp11MD5ImporterD2Ev:
   68|    297|    ~MD5Importer() override = default;

_ZN6Assimp11MDCImporterC2Ev:
  102|    297|        fileSize() {
  103|       |    // empty
  104|    297|}
_ZNK6Assimp11MDCImporter7GetInfoEv:
  114|    297|const aiImporterDesc *MDCImporter::GetInfo() const {
  115|    297|    return &desc;
  116|    297|}

_ZN6Assimp3MDL8HalfLife17HL1ImportSettingsC2Ev:
   57|    594|        read_animations(false),
   58|    594|        read_animation_events(false),
   59|    594|        read_blend_controllers(false),
   60|    594|        read_sequence_groups_info(false),
   61|    594|        read_sequence_transitions(false),
   62|    594|        read_attachments(false),
   63|    594|        read_bone_controllers(false),
   64|    594|        read_hitboxes(false),
   65|    594|        read_textures(false),
   66|    594|        read_misc_global_info(false),
   67|    594|        transform_coord_system(true) {
   68|    594|    }

_ZN6Assimp11MDLImporterC2Ev:
   96|    594|        configFrameID(), mBuffer(), iGSFileVersion(), mIOHandler(nullptr), pScene(), iFileSize() {
   97|       |    // empty
   98|    594|}
_ZNK6Assimp11MDLImporter7GetInfoEv:
  147|    297|const aiImporterDesc *MDLImporter::GetInfo() const {
  148|    297|    return &desc;
  149|    297|}

_ZN6Assimp11MDLImporterD2Ev:
   87|    594|    ~MDLImporter() override = default;

_ZN6Assimp11MMDImporterC2Ev:
   78|    297|        m_Buffer(),
   79|    297|        m_strAbsPath() {
   80|    297|    DefaultIOSystem io;
   81|    297|    m_strAbsPath = io.getOsSeparator();
   82|    297|}
_ZNK6Assimp11MMDImporter7GetInfoEv:
   93|    297|const aiImporterDesc *MMDImporter::GetInfo() const {
   94|    297|    return &desc;
   95|    297|}

_ZN6Assimp11MMDImporterD2Ev:
   62|    297|    ~MMDImporter() override = default;

_ZN6Assimp12MS3DImporterC2Ev:
   81|    297|{}
_ZNK6Assimp12MS3DImporter7GetInfoEv:
   93|    297|{
   94|    297|    return &desc;
   95|    297|}

_ZNK6Assimp11NDOImporter7GetInfoEv:
   83|    297|{
   84|    297|    return &desc;
   85|    297|}

_ZN6Assimp11NDOImporterC2Ev:
   68|    297|    NDOImporter() = default;

_ZNK6Assimp11NFFImporter7GetInfoEv:
   82|    297|const aiImporterDesc *NFFImporter::GetInfo() const {
   83|    297|    return &desc;
   84|    297|}

_ZN6Assimp11NFFImporterC2Ev:
   65|    297|    NFFImporter() = default;

_ZNK6Assimp11OFFImporter7GetInfoEv:
   81|    297|const aiImporterDesc *OFFImporter::GetInfo() const {
   82|    297|    return &desc;
   83|    297|}

_ZN6Assimp11OFFImporterC2Ev:
   60|    297|    OFFImporter() = default;

_ZN6Assimp15ObjFileImporterC2Ev:
   79|    297|        m_Buffer(),
   80|    297|        m_pRootObject(nullptr),
   81|    297|        m_strAbsPath(std::string(1, DefaultIOSystem().getOsSeparator())) {
   82|       |    // empty
   83|    297|}
_ZN6Assimp15ObjFileImporterD2Ev:
   87|    297|ObjFileImporter::~ObjFileImporter() {
   88|    297|    delete m_pRootObject;
   89|    297|}
_ZNK6Assimp15ObjFileImporter7GetInfoEv:
   99|    297|const aiImporterDesc *ObjFileImporter::GetInfo() const {
  100|    297|    return &desc;
  101|    297|}

_ZNK6Assimp4Ogre12OgreImporter7GetInfoEv:
   67|    297|const aiImporterDesc *OgreImporter::GetInfo() const {
   68|    297|    return &desc;
   69|    297|}

_ZN6Assimp7OpenGEX15OpenGEXImporter15VertexContainerC2Ev:
  239|    297|        m_numColors(0), m_colors(nullptr), m_numUVComps(), m_textureCoords() {
  ------------------
  |  |   59|    297|#define nullptr nullptr
  ------------------
  240|       |    // empty
  241|    297|}
_ZN6Assimp7OpenGEX15OpenGEXImporter15VertexContainerD2Ev:
  244|    297|OpenGEXImporter::VertexContainer::~VertexContainer() {
  245|    297|    delete[] m_colors;
  246|       |
  247|  2.37k|    for (auto &texcoords : m_textureCoords) {
  ------------------
  |  Branch (247:26): [True: 2.37k, False: 297]
  ------------------
  248|  2.37k|        delete[] texcoords;
  249|  2.37k|    }
  250|    297|}
_ZN6Assimp7OpenGEX15OpenGEXImporterC2Ev:
  262|    297|        m_root(nullptr),
  ------------------
  |  |   59|    297|#define nullptr nullptr
  ------------------
  263|    297|        m_nodeChildMap(),
  264|    297|        m_mesh2refMap(),
  265|    297|        m_material2refMap(),
  266|    297|        m_ctx(nullptr),
  ------------------
  |  |   59|    297|#define nullptr nullptr
  ------------------
  267|    297|        m_metrics(),
  268|    297|        m_currentNode(nullptr),
  ------------------
  |  |   59|    297|#define nullptr nullptr
  ------------------
  269|    297|        m_currentVertices(),
  270|    297|        m_currentMesh(nullptr),
  ------------------
  |  |   59|    297|#define nullptr nullptr
  ------------------
  271|    297|        m_currentMaterial(nullptr),
  ------------------
  |  |   59|    297|#define nullptr nullptr
  ------------------
  272|    297|        m_currentLight(nullptr),
  ------------------
  |  |   59|    297|#define nullptr nullptr
  ------------------
  273|    297|        m_currentCamera(nullptr),
  ------------------
  |  |   59|    297|#define nullptr nullptr
  ------------------
  274|    297|        m_tokenType(Grammar::NoneType),
  275|    297|        m_materialCache(),
  276|    297|        m_cameraCache(),
  277|    297|        m_lightCache(),
  278|    297|        m_nodeStack(),
  279|    297|        m_unresolvedRefStack() {
  280|       |    // empty
  281|    297|}
_ZNK6Assimp7OpenGEX15OpenGEXImporter7GetInfoEv:
  321|    297|const aiImporterDesc *OpenGEXImporter::GetInfo() const {
  322|    297|    return &desc;
  323|    297|}

_ZN6Assimp7OpenGEX10MetricInfoC2Ev:
   81|  1.18k|    MetricInfo(): m_stringValue( ), m_floatValue( 0.0f ), m_intValue( -1 ) {}
_ZN6Assimp7OpenGEX15OpenGEXImporterD2Ev:
   94|    297|    ~OpenGEXImporter() override = default;

_ZN6Assimp11PLYImporterD2Ev:
  172|    297|    PLYImporter::~PLYImporter() {
  173|    297|        delete mGeneratedMesh;
  174|    297|    }
_ZNK6Assimp11PLYImporter7GetInfoEv:
  184|    297|    const aiImporterDesc *PLYImporter::GetInfo() const {
  185|    297|        return &desc;
  186|    297|    }

_ZN6Assimp11PLYImporterC2Ev:
   68|    297|    PLYImporter() = default;

_ZN6Assimp17Q3BSPFileImporterC2Ev:
  137|    297|        m_pCurrentMesh(nullptr), m_pCurrentFace(nullptr) {
  138|       |    // empty
  139|    297|}
_ZN6Assimp17Q3BSPFileImporterD2Ev:
  143|    297|Q3BSPFileImporter::~Q3BSPFileImporter() {
  144|    297|    clear();
  145|    297|}
_ZN6Assimp17Q3BSPFileImporter5clearEv:
  148|    297|void Q3BSPFileImporter::clear() {
  149|    297|    for (FaceMap::iterator it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it) {
  ------------------
  |  Branch (149:62): [True: 0, False: 297]
  ------------------
  150|      0|        const std::string &matName = it->first;
  151|      0|        if (!matName.empty()) {
  ------------------
  |  Branch (151:13): [True: 0, False: 0]
  ------------------
  152|      0|            delete it->second;
  153|      0|        }
  154|      0|    }
  155|    297|}
_ZNK6Assimp17Q3BSPFileImporter7GetInfoEv:
  168|    297|const aiImporterDesc *Q3BSPFileImporter::GetInfo() const {
  169|    297|    return &desc;
  170|    297|}

_ZN6Assimp11Q3DImporterC2Ev:
   77|    297|Q3DImporter::Q3DImporter() = default;
_ZN6Assimp11Q3DImporterD2Ev:
   81|    297|Q3DImporter::~Q3DImporter() = default;
_ZNK6Assimp11Q3DImporter7GetInfoEv:
   91|    297|const aiImporterDesc *Q3DImporter::GetInfo() const {
   92|    297|    return &desc;
   93|    297|}

_ZNK6Assimp11RAWImporter7GetInfoEv:
   80|    297|const aiImporterDesc *RAWImporter::GetInfo() const {
   81|    297|    return &desc;
   82|    297|}

_ZN6Assimp11RAWImporterC2Ev:
   60|    297|    RAWImporter() = default;

_ZNK6Assimp11SIBImporter7GetInfoEv:
  206|    297|const aiImporterDesc *SIBImporter::GetInfo() const {
  207|    297|    return &desc;
  208|    297|}

_ZN6Assimp11SIBImporterC2Ev:
   60|    297|    SIBImporter() = default;

_ZN6Assimp11SMDImporterC2Ev:
   86|    297|        mBuffer(),
   87|    297|        mEnd(nullptr),
   88|    297|        pScene(nullptr),
   89|    297|        iFileSize( 0 ),
   90|    297|        iSmallestFrame( INT_MAX ),
   91|    297|        dLengthOfAnim( 0.0 ),
   92|    297|        bHasUVs(false ),
   93|    297|        iLineNumber((unsigned int)-1)  {
   94|       |    // empty
   95|    297|}
_ZNK6Assimp11SMDImporter7GetInfoEv:
  106|    297|const aiImporterDesc* SMDImporter::GetInfo () const {
  107|    297|    return &desc;
  108|    297|}

_ZN6Assimp11SMDImporterD2Ev:
  165|    297|    ~SMDImporter() override = default;

_ZN6Assimp11STLImporterC2Ev:
  130|    297|        mFileSize(0),
  131|    297|        mScene() {
  132|       |    // empty
  133|    297|}
_ZN6Assimp11STLImporterD2Ev:
  137|    297|STLImporter::~STLImporter() = default;
_ZNK6Assimp11STLImporter7GetInfoEv:
  147|    297|const aiImporterDesc *STLImporter::GetInfo() const {
  148|    297|    return &desc;
  149|    297|}

_ZN6Assimp4STEP7EXPRESS16ConversionSchema11SchemaEntryC2EPKcPFPNS0_6ObjectERKNS0_2DBERKNS1_4LISTEE:
  321|  1.96k|        SchemaEntry(const char *name, ConvertObjectProc func) : mName(name), mFunc(func) {}

_ZN6Assimp16TerragenImporterC2Ev:
   72|    297|        configComputeUVs(false) {
   73|       |    // empty
   74|    297|}
_ZNK6Assimp16TerragenImporter7GetInfoEv:
   85|    297|const aiImporterDesc *TerragenImporter::GetInfo() const {
   86|    297|    return &desc;
   87|    297|}

_ZN6Assimp14UnrealImporterC2Ev:
  166|    297|        mConfigFrameID(0), mConfigHandleFlags(true) {
  167|       |    // empty
  168|    297|}
_ZNK6Assimp14UnrealImporter7GetInfoEv:
  178|    297|const aiImporterDesc *UnrealImporter::GetInfo() const {
  179|    297|    return &desc;
  180|    297|}

_ZNK6Assimp13XFileImporter7GetInfoEv:
   86|    297|const aiImporterDesc *XFileImporter::GetInfo() const {
   87|    297|    return &desc;
   88|    297|}

_ZN6Assimp13XFileImporterC2Ev:
   71|    297|    XFileImporter() = default;
_ZN6Assimp13XFileImporterD2Ev:
   72|    297|    ~XFileImporter() override = default;

_ZN6Assimp11X3DImporterC2Ev:
  192|    297|        mNodeElementCur(nullptr),
  193|    297|        mScene(nullptr),
  194|    297|        mpIOHandler(nullptr) {
  195|       |    // empty
  196|    297|}
_ZN6Assimp11X3DImporterD2Ev:
  198|    297|X3DImporter::~X3DImporter() {
  199|       |    // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
  200|    297|    Clear();
  201|    297|}
_ZN6Assimp11X3DImporter5ClearEv:
  203|    297|void X3DImporter::Clear() {
  204|    297|    mNodeElementCur = nullptr;
  205|       |    // Delete all elements
  206|    297|    if (!NodeElement_List.empty()) {
  ------------------
  |  Branch (206:9): [True: 0, False: 297]
  ------------------
  207|      0|        for (std::list<X3DNodeElementBase *>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) {
  ------------------
  |  Branch (207:87): [True: 0, False: 0]
  ------------------
  208|      0|            delete *it;
  209|      0|        }
  210|      0|        NodeElement_List.clear();
  211|      0|    }
  212|    297|}
_ZNK6Assimp11X3DImporter7GetInfoEv:
  340|    297|const aiImporterDesc *X3DImporter::GetInfo() const {
  341|    297|    return &Description;
  342|    297|}

_ZN6Assimp11XGLImporterC2Ev:
   75|    297|XGLImporter::XGLImporter() : mXmlParser(nullptr), m_scene(nullptr) {
   76|       |    // empty
   77|    297|}
_ZN6Assimp11XGLImporterD2Ev:
   80|    297|XGLImporter::~XGLImporter() {
   81|    297|    clear();
   82|    297|}
_ZNK6Assimp11XGLImporter7GetInfoEv:
   91|    297|const aiImporterDesc *XGLImporter::GetInfo() const {
   92|    297|	return &desc;
   93|    297|}
_ZN6Assimp11XGLImporter5clearEv:
  170|    297|void XGLImporter::clear() {
  171|    297|    delete mXmlParser;
  172|    297|    mXmlParser = nullptr;
  173|    297|}

_ZN6Assimp12glTFImporterC2Ev:
  148|    297|        mScene(nullptr) {
  149|       |    // empty
  150|    297|}
_ZNK6Assimp12glTFImporter7GetInfoEv:
  152|    297|const aiImporterDesc *glTFImporter::GetInfo() const {
  153|    297|    return &desc;
  154|    297|}

_ZN6Assimp12glTFImporterD2Ev:
   64|    297|    ~glTFImporter() override = default;

_ZN6Assimp13glTF2ImporterC2Ev:
  101|    297|        mScene(nullptr) {
  102|       |    // empty
  103|    297|}
_ZNK6Assimp13glTF2Importer7GetInfoEv:
  105|    297|const aiImporterDesc *glTF2Importer::GetInfo() const {
  106|    297|    return &desc;
  107|    297|}

_ZN6Assimp13glTF2ImporterD2Ev:
   62|    297|    ~glTF2Importer() override = default;

_ZN6Assimp12BaseImporterC2Ev:
   92|  14.2k|        : m_progress() {
   93|       |    // empty
   94|  14.2k|}
_ZN6Assimp12BaseImporter19UpdateImporterScaleEPNS_8ImporterE:
   96|    227|void BaseImporter::UpdateImporterScale(Importer *pImp) {
   97|    227|    ai_assert(pImp != nullptr);
   98|    227|    ai_assert(importerScale != 0.0);
   99|    227|    ai_assert(fileScale != 0.0);
  100|       |
  101|    227|    double activeScale = importerScale * fileScale;
  102|       |
  103|       |    // Set active scaling
  104|    227|    pImp->SetPropertyFloat(AI_CONFIG_APP_SCALE_KEY, static_cast<float>(activeScale));
  105|       |
  106|       |    ASSIMP_LOG_DEBUG("UpdateImporterScale scale set: ", activeScale);
  107|    227|}
_ZN6Assimp12BaseImporter8ReadFileEPNS_8ImporterERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS_8IOSystemE:
  111|    297|aiScene *BaseImporter::ReadFile(Importer *pImp, const std::string &pFile, IOSystem *pIOHandler) {
  112|       |
  113|    297|    m_progress = pImp->GetProgressHandler();
  114|    297|    if (nullptr == m_progress) {
  ------------------
  |  Branch (114:9): [True: 0, False: 297]
  ------------------
  115|      0|        return nullptr;
  116|      0|    }
  117|       |
  118|    297|    ai_assert(m_progress);
  119|       |
  120|       |    // Gather configuration properties for this run
  121|    297|    SetupProperties(pImp);
  122|       |
  123|       |    // Construct a file system filter to improve our success ratio at reading external files
  124|    297|    FileSystemFilter filter(pFile, pIOHandler);
  125|       |
  126|       |    // create a scene object to hold the data
  127|    297|    std::unique_ptr<aiScene> sc(new aiScene());
  128|       |
  129|       |    // dispatch importing
  130|    297|    try {
  131|    297|        InternReadFile(pFile, sc.get(), &filter);
  132|       |
  133|       |        // Calculate import scale hook - required because pImp not available anywhere else
  134|       |        // passes scale into ScaleProcess
  135|    297|        UpdateImporterScale(pImp);
  136|       |
  137|    297|    } catch( const std::exception &err ) {
  138|       |        // extract error description
  139|     70|        m_ErrorText = err.what();
  140|     70|        ASSIMP_LOG_ERROR(err.what());
  141|     70|        m_Exception = std::current_exception();
  142|     70|        return nullptr;
  143|     70|    }
  144|       |
  145|       |    // return what we gathered from the import.
  146|    227|    return sc.release();
  147|    297|}
_ZN6Assimp12BaseImporter16GetExtensionListERNSt3__13setINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_4lessIS8_EENS6_IS8_EEEE:
  155|    297|void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
  156|    297|    const aiImporterDesc *desc = GetInfo();
  157|    297|    ai_assert(desc != nullptr);
  158|       |
  159|    297|    const char *ext = desc->mFileExtensions;
  160|    297|    ai_assert(ext != nullptr);
  161|       |
  162|    297|    const char *last = ext;
  163|  1.18k|    do {
  164|  1.18k|        if (!*ext || *ext == ' ') {
  ------------------
  |  Branch (164:13): [True: 297, False: 891]
  |  Branch (164:22): [True: 0, False: 891]
  ------------------
  165|    297|            extensions.insert(std::string(last, ext - last));
  166|    297|            ai_assert(ext - last > 0);
  167|    297|            last = ext;
  168|    297|            while (*last == ' ') {
  ------------------
  |  Branch (168:20): [True: 0, False: 297]
  ------------------
  169|      0|                ++last;
  170|      0|            }
  171|    297|        }
  172|  1.18k|    } while (*ext++);
  ------------------
  |  Branch (172:14): [True: 891, False: 297]
  ------------------
  173|    297|}
_ZN6Assimp12BaseImporter12HasExtensionERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERKNS1_3setIS7_NS1_4lessIS7_EENS5_IS7_EEEE:
  265|    297|/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
  266|    297|    const std::string file = StripVersionHash(pFile);
  267|       |    // CAUTION: Do not just search for the extension!
  268|       |    // GetExtension() returns the part after the *last* dot, but some extensions
  269|       |    // have dots inside them, e.g. ogre.mesh.xml. Compare the entire end of the
  270|       |    // string.
  271|    297|    for (const std::string& ext : extensions) {
  ------------------
  |  Branch (271:33): [True: 297, False: 0]
  ------------------
  272|       |        // Yay for C++<20 not having std::string::ends_with()
  273|    297|        const std::string dotExt = "." + ext;
  274|    297|        if (dotExt.length() > file.length()) continue;
  ------------------
  |  Branch (274:13): [True: 0, False: 297]
  ------------------
  275|       |        // Possible optimization: Fetch the lowercase filename!
  276|    297|        if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) {
  ------------------
  |  Branch (276:13): [True: 297, False: 0]
  ------------------
  277|    297|            return true;
  278|    297|        }
  279|    297|    }
  280|      0|    return false;
  281|    297|}
_ZN6Assimp12BaseImporter12GetExtensionERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  285|      1|std::string BaseImporter::GetExtension(const std::string &pFile) {
  286|      1|    const std::string file = StripVersionHash(pFile);
  287|      1|    std::string::size_type pos = file.find_last_of('.');
  288|       |
  289|       |    // no file extension at all
  290|      1|    if (pos == std::string::npos) {
  ------------------
  |  Branch (290:9): [True: 0, False: 1]
  ------------------
  291|      0|        return std::string();
  292|      0|    }
  293|       |
  294|       |    // thanks to Andy Maloney for the hint
  295|      1|    std::string ret = file.substr(pos + 1);
  296|      1|    ret = ai_tolower(ret);
  297|       |
  298|      1|    return ret;
  299|      1|}
BaseImporter.cpp:_ZN12_GLOBAL__N_116StripVersionHashERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   75|    298|std::string StripVersionHash(const std::string &filename) {
   76|    298|    const std::string::size_type pos = filename.find_last_of('#');
   77|       |    // Only strip if the hash is behind a possible file extension and the part
   78|       |    // behind the hash is a version string.
   79|    298|    if (pos != std::string::npos && pos > filename.find_last_of('.') &&
  ------------------
  |  Branch (79:9): [True: 0, False: 298]
  |  Branch (79:9): [True: 0, False: 298]
  |  Branch (79:37): [True: 0, False: 0]
  ------------------
   80|      0|        IsGcsVersion(filename.substr(pos + 1))) {
  ------------------
  |  Branch (80:9): [True: 0, False: 0]
  ------------------
   81|      0|        return filename.substr(0, pos);
   82|      0|    }
   83|    298|    return filename;
   84|    298|}

_ZN6Assimp11BaseProcessC2Ev:
   56|  10.0k|          progress() {
   57|       |    // empty
   58|  10.0k|}
_ZN6Assimp11BaseProcess14ExecuteOnSceneEPNS_8ImporterE:
   61|  3.49k|void BaseProcess::ExecuteOnScene(Importer *pImp) {
   62|  3.49k|    ai_assert( nullptr != pImp );
   63|  3.49k|    if (pImp == nullptr) {
  ------------------
  |  Branch (63:9): [True: 0, False: 3.49k]
  ------------------
   64|      0|        return;
   65|      0|    }
   66|       |
   67|  3.49k|    ai_assert(nullptr != pImp->Pimpl()->mScene);
   68|  3.49k|    if (pImp->Pimpl()->mScene == nullptr) {
  ------------------
  |  Branch (68:9): [True: 0, False: 3.49k]
  ------------------
   69|      0|        return;
   70|      0|    }
   71|       |
   72|  3.49k|    progress = pImp->GetProgressHandler();
   73|  3.49k|    ai_assert(nullptr != progress);
   74|  3.49k|    if (progress == nullptr) {
  ------------------
  |  Branch (74:9): [True: 0, False: 3.49k]
  ------------------
   75|      0|        return;
   76|      0|    }
   77|       |
   78|  3.49k|    SetupProperties(pImp);
   79|       |
   80|       |    // catch exceptions thrown inside the PostProcess-Step
   81|  3.49k|    try {
   82|  3.49k|        Execute(pImp->Pimpl()->mScene);
   83|  3.49k|    } catch (const std::exception &err) {
   84|       |
   85|       |        // extract error description
   86|      9|        pImp->Pimpl()->mErrorString = err.what();
   87|      9|        ASSIMP_LOG_ERROR(pImp->Pimpl()->mErrorString);
   88|       |
   89|       |        // and kill the partially imported data
   90|      9|        delete pImp->Pimpl()->mScene;
   91|      9|        pImp->Pimpl()->mScene = nullptr;
   92|      9|    }
   93|  3.49k|}
_ZN6Assimp11BaseProcess15SetupPropertiesEPKNS_8ImporterE:
   96|  1.31k|void BaseProcess::SetupProperties(const Importer * /*pImp*/) {
   97|       |    // the default implementation does nothing
   98|  1.31k|}

_ZN6Assimp11BaseProcess13SetSharedDataEPNS_21SharedPostProcessInfoE:
  234|  9.80k|    inline void SetSharedData(SharedPostProcessInfo *sh) {
  235|  9.80k|        shared = sh;
  236|  9.80k|    }
_ZN6Assimp21SharedPostProcessInfoD2Ev:
   98|    297|    ~SharedPostProcessInfo() {
   99|    297|        Clean();
  100|    297|    }
_ZN6Assimp11BaseProcessD2Ev:
  186|  10.0k|    virtual ~BaseProcess() = default;
_ZN6Assimp21SharedPostProcessInfo5CleanEv:
  103|    803|    void Clean() {
  104|       |        // invoke the virtual destructor for all stored properties
  105|    803|        for (PropertyMap::iterator it = pmap.begin(), end = pmap.end();
  106|    803|                it != end; ++it) {
  ------------------
  |  Branch (106:17): [True: 0, False: 803]
  ------------------
  107|      0|            delete (*it).second;
  108|      0|        }
  109|    803|        pmap.clear();
  110|    803|    }
_ZN6Assimp21SharedPostProcessInfo14RemovePropertyEPKc:
  148|    218|    void RemoveProperty(const char *name) {
  149|    218|        SetGenericPropertyPtr<Base>(pmap, name, nullptr );
  150|    218|    }
_ZN6Assimp21SharedPostProcessInfo11AddPropertyEPKcPNS0_4BaseE:
  153|    218|    void AddProperty(const char *name, Base *data) {
  154|    218|        SetGenericPropertyPtr<Base>(pmap, name, data);
  155|    218|    }
_ZNK6Assimp21SharedPostProcessInfo19GetPropertyInternalEPKc:
  157|    142|    Base *GetPropertyInternal(const char *name) const {
  158|    142|        return GetGenericProperty<Base *>(pmap, name, nullptr );
  159|    142|    }
_ZN6Assimp21SharedPostProcessInfo11AddPropertyINSt3__16vectorINS2_4pairINS_11SpatialSortEfEENS2_9allocatorIS6_EEEEEEvPKcPT_:
  114|    218|    void AddProperty(const char *name, T *in) {
  115|    218|        AddProperty(name, (Base *)new THeapData<T>(in));
  116|    218|    }
_ZN6Assimp21SharedPostProcessInfo9THeapDataINSt3__16vectorINS2_4pairINS_11SpatialSortEfEENS2_9allocatorIS6_EEEEEC2EPS9_:
   73|    218|                data(in) {}
_ZN6Assimp21SharedPostProcessInfo4BaseD2Ev:
   66|    218|        virtual ~Base() = default;
_ZN6Assimp21SharedPostProcessInfo9THeapDataINSt3__16vectorINS2_4pairINS_11SpatialSortEfEENS2_9allocatorIS6_EEEEED2Ev:
   75|    218|        ~THeapData() override {
   76|    218|            delete data;
   77|    218|        }
_ZNK6Assimp21SharedPostProcessInfo11GetPropertyINSt3__16vectorINS2_4pairINS_11SpatialSortEfEENS2_9allocatorIS6_EEEEEEbPKcRPT_:
  126|    142|    bool GetProperty(const char *name, T *&out) const {
  127|    142|        THeapData<T> *t = (THeapData<T> *)GetPropertyInternal(name);
  128|    142|        if (!t) {
  ------------------
  |  Branch (128:13): [True: 0, False: 142]
  ------------------
  129|      0|            out = nullptr;
  130|      0|            return false;
  131|      0|        }
  132|    142|        out = t->data;
  133|    142|        return true;
  134|    142|    }

_ZN6Assimp11CompressionC2Ev:
   62|  5.55k|        mImpl(new impl) {
   63|       |    // empty
   64|  5.55k|}
_ZN6Assimp11CompressionD2Ev:
   66|  5.55k|Compression::~Compression() {
   67|  5.55k|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|  5.55k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 5.55k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   68|       |
   69|  5.55k|    if (mImpl->mOpen) {
  ------------------
  |  Branch (69:9): [True: 1.61k, False: 3.93k]
  ------------------
   70|  1.61k|        close();
   71|  1.61k|    }
   72|       |
   73|  5.55k|    delete mImpl;
   74|  5.55k|}
_ZN6Assimp11Compression4openENS0_6FormatENS0_9FlushModeEi:
   76|  5.55k|bool Compression::open(Format format, FlushMode flush, int windowBits) {
   77|  5.55k|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|  5.55k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 5.55k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   78|       |
   79|  5.55k|    if (mImpl->mOpen) {
  ------------------
  |  Branch (79:9): [True: 0, False: 5.55k]
  ------------------
   80|      0|        return false;
   81|      0|    }
   82|       |
   83|       |    // build a zlib stream
   84|  5.55k|    mImpl->mZSstream.opaque = Z_NULL;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   85|  5.55k|    mImpl->mZSstream.zalloc = Z_NULL;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   86|  5.55k|    mImpl->mZSstream.zfree = Z_NULL;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   87|  5.55k|    mImpl->mFlushMode = flush;
   88|  5.55k|    if (format == Format::Binary) {
  ------------------
  |  Branch (88:9): [True: 5.55k, False: 0]
  ------------------
   89|  5.55k|        mImpl->mZSstream.data_type = Z_BINARY;
  ------------------
  |  |  203|  5.55k|#define Z_BINARY   0
  ------------------
   90|  5.55k|    } else {
   91|      0|        mImpl->mZSstream.data_type = Z_ASCII;
  ------------------
  |  |  205|      0|#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
  |  |  ------------------
  |  |  |  |  204|      0|#define Z_TEXT     1
  |  |  ------------------
  ------------------
   92|      0|    }
   93|       |
   94|       |    // raw decompression without a zlib or gzip header
   95|  5.55k|    if (windowBits == 0) {
  ------------------
  |  Branch (95:9): [True: 5.55k, False: 0]
  ------------------
   96|  5.55k|        inflateInit(&mImpl->mZSstream);
  ------------------
  |  | 1813|  5.55k|          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
  |  |  ------------------
  |  |  |  |   40|  5.55k|#define ZLIB_VERSION "1.2.13"
  |  |  ------------------
  ------------------
   97|  5.55k|    } else {
   98|      0|        inflateInit2(&mImpl->mZSstream, windowBits);
  ------------------
  |  | 1818|      0|          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
  |  |  ------------------
  |  |  |  |   40|      0|#define ZLIB_VERSION "1.2.13"
  |  |  ------------------
  |  | 1819|      0|                        (int)sizeof(z_stream))
  ------------------
   99|      0|    }
  100|  5.55k|    mImpl->mOpen = true;
  101|       |
  102|  5.55k|    return mImpl->mOpen;
  103|  5.55k|}
_ZN6Assimp11Compression10decompressEPKvmRNSt3__16vectorIcNS3_9allocatorIcEEEE:
  133|  5.55k|size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
  134|  5.55k|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|  5.55k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 5.55k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  135|  5.55k|    if (data == nullptr || in == 0) {
  ------------------
  |  Branch (135:9): [True: 0, False: 5.55k]
  |  Branch (135:28): [True: 0, False: 5.55k]
  ------------------
  136|      0|        return 0l;
  137|      0|    }
  138|       |
  139|  5.55k|    mImpl->mZSstream.next_in = (Bytef*)(data);
  140|  5.55k|    mImpl->mZSstream.avail_in = (uInt)in;
  141|       |
  142|  5.55k|    int ret = 0;
  143|  5.55k|    size_t total = 0l;
  144|  5.55k|    const int flushMode = getFlushMode(mImpl->mFlushMode);
  145|  5.55k|    if (flushMode == Z_FINISH) {
  ------------------
  |  |  172|  5.55k|#define Z_FINISH        4
  ------------------
  |  Branch (145:9): [True: 5.55k, False: 0]
  ------------------
  146|  5.55k|        mImpl->mZSstream.avail_out = static_cast<uInt>(uncompressed.size());
  147|  5.55k|        mImpl->mZSstream.next_out = reinterpret_cast<Bytef *>(&*uncompressed.begin());
  148|  5.55k|        ret = inflate(&mImpl->mZSstream, Z_FINISH);
  ------------------
  |  |  172|  5.55k|#define Z_FINISH        4
  ------------------
  149|       |
  150|  5.55k|        if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  178|  11.1k|#define Z_STREAM_END    1
  ------------------
                      if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  177|  1.61k|#define Z_OK            0
  ------------------
  |  Branch (150:13): [True: 1.61k, False: 3.93k]
  |  Branch (150:36): [True: 1.61k, False: 0]
  ------------------
  151|  1.61k|            throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
  152|  1.61k|        }
  153|  3.93k|        total = mImpl->mZSstream.avail_out;
  154|  3.93k|    } else {
  155|      0|        do {
  156|      0|            Bytef block[MYBLOCK] = {};
  157|      0|            mImpl->mZSstream.avail_out = MYBLOCK;
  158|      0|            mImpl->mZSstream.next_out = block;
  159|       |
  160|      0|            ret = inflate(&mImpl->mZSstream, flushMode);
  161|       |
  162|      0|            if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  178|      0|#define Z_STREAM_END    1
  ------------------
                          if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  177|      0|#define Z_OK            0
  ------------------
  |  Branch (162:17): [True: 0, False: 0]
  |  Branch (162:40): [True: 0, False: 0]
  ------------------
  163|      0|                throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
  164|      0|            }
  165|      0|            const size_t have = MYBLOCK - mImpl->mZSstream.avail_out;
  166|      0|            total += have;
  167|      0|            uncompressed.resize(total);
  168|      0|            ::memcpy(uncompressed.data() + total - have, block, have);
  169|      0|        } while (ret != Z_STREAM_END);
  ------------------
  |  |  178|      0|#define Z_STREAM_END    1
  ------------------
  |  Branch (169:18): [True: 0, False: 0]
  ------------------
  170|      0|    }
  171|       |
  172|  3.93k|    return total;
  173|  5.55k|}
_ZN6Assimp11Compression5closeEv:
  205|  5.55k|bool Compression::close() {
  206|  5.55k|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|  5.55k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 5.55k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  207|       |
  208|  5.55k|    if (!mImpl->mOpen) {
  ------------------
  |  Branch (208:9): [True: 0, False: 5.55k]
  ------------------
  209|      0|        return false;
  210|      0|    }
  211|       |
  212|  5.55k|    inflateEnd(&mImpl->mZSstream);
  213|  5.55k|    mImpl->mOpen = false;
  214|       |
  215|  5.55k|    return true;
  216|  5.55k|}
_ZN6Assimp11Compression4implC2Ev:
   54|  5.55k|            mOpen(false),
   55|  5.55k|            mZSstream(),
   56|  5.55k|            mFlushMode(Compression::FlushMode::NoFlush) {
   57|       |        // empty
   58|  5.55k|    }
Compression.cpp:_ZN6AssimpL12getFlushModeENS_11Compression9FlushModeE:
  105|  5.55k|static int getFlushMode(Compression::FlushMode flush) {
  106|  5.55k|    int z_flush = 0;
  107|  5.55k|    switch (flush) {
  108|      0|        case Compression::FlushMode::NoFlush:
  ------------------
  |  Branch (108:9): [True: 0, False: 5.55k]
  ------------------
  109|      0|            z_flush = Z_NO_FLUSH;
  ------------------
  |  |  168|      0|#define Z_NO_FLUSH      0
  ------------------
  110|      0|            break;
  111|      0|        case Compression::FlushMode::Block:
  ------------------
  |  Branch (111:9): [True: 0, False: 5.55k]
  ------------------
  112|      0|            z_flush = Z_BLOCK;
  ------------------
  |  |  173|      0|#define Z_BLOCK         5
  ------------------
  113|      0|            break;
  114|      0|        case Compression::FlushMode::Tree:
  ------------------
  |  Branch (114:9): [True: 0, False: 5.55k]
  ------------------
  115|      0|            z_flush = Z_TREES;
  ------------------
  |  |  174|      0|#define Z_TREES         6
  ------------------
  116|      0|            break;
  117|      0|        case Compression::FlushMode::SyncFlush:
  ------------------
  |  Branch (117:9): [True: 0, False: 5.55k]
  ------------------
  118|      0|            z_flush = Z_SYNC_FLUSH;
  ------------------
  |  |  170|      0|#define Z_SYNC_FLUSH    2
  ------------------
  119|      0|            break;
  120|  5.55k|        case Compression::FlushMode::Finish:
  ------------------
  |  Branch (120:9): [True: 5.55k, False: 0]
  ------------------
  121|  5.55k|            z_flush = Z_FINISH;
  ------------------
  |  |  172|  5.55k|#define Z_FINISH        4
  ------------------
  122|  5.55k|            break;
  123|      0|        default:
  ------------------
  |  Branch (123:9): [True: 0, False: 5.55k]
  ------------------
  124|      0|            ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  125|      0|            break;
  126|  5.55k|    }
  127|       |
  128|  5.55k|    return z_flush;
  129|  5.55k|}

_ZNK6Assimp15DefaultIOSystem14getOsSeparatorEv:
  152|    891|char DefaultIOSystem::getOsSeparator() const {
  153|    891|#ifndef _WIN32
  154|    891|    return '/';
  155|       |#else
  156|       |    return '\\';
  157|       |#endif
  158|    891|}

_ZN6Assimp6Logger5debugEPKc:
  166|  8.15k|void Logger::debug(const char *message) {
  167|       |
  168|       |    // SECURITY FIX: otherwise it's easy to produce overruns since
  169|       |    // sometimes importers will include data from the input file
  170|       |    // (i.e. node names) in their messages.
  171|  8.15k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (171:9): [True: 0, False: 8.15k]
  ------------------
  172|      0|        return OnDebug("<fixme: long message discarded>");
  173|      0|    }
  174|  8.15k|    return OnDebug(message);
  175|  8.15k|}
_ZN6Assimp6Logger12verboseDebugEPKc:
  178|    792|void Logger::verboseDebug(const char *message) {
  179|       |
  180|       |    // SECURITY FIX: see above
  181|    792|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (181:9): [True: 0, False: 792]
  ------------------
  182|      0|        return OnVerboseDebug("<fixme: long message discarded>");
  183|      0|    }
  184|    792|    return OnVerboseDebug(message);
  185|    792|}
_ZN6Assimp6Logger4infoEPKc:
  188|  15.8k|void Logger::info(const char *message) {
  189|       |
  190|       |    // SECURITY FIX: see above
  191|  15.8k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (191:9): [True: 0, False: 15.8k]
  ------------------
  192|      0|        return OnInfo("<fixme: long message discarded>");
  193|      0|    }
  194|  15.8k|    return OnInfo(message);
  195|  15.8k|}
_ZN6Assimp6Logger4warnEPKc:
  198|   357k|void Logger::warn(const char *message) {
  199|       |
  200|       |    // SECURITY FIX: see above
  201|   357k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (201:9): [True: 343, False: 357k]
  ------------------
  202|    343|        return OnWarn("<fixme: long message discarded>");
  203|    343|    }
  204|   357k|    return OnWarn(message);
  205|   357k|}
_ZN6Assimp6Logger5errorEPKc:
  208|    105|void Logger::error(const char *message) {
  209|       |    // SECURITY FIX: see above
  210|    105|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (210:9): [True: 1, False: 104]
  ------------------
  211|      1|        return OnError("<fixme: long message discarded>");
  212|      1|    }
  213|    104|    return OnError(message);
  214|    105|}
_ZN6Assimp13DefaultLogger12isNullLoggerEv:
  232|  4.03k|bool DefaultLogger::isNullLogger() {
  233|  4.03k|    return m_pLogger == &s_pNullLogger;
  234|  4.03k|}
_ZN6Assimp13DefaultLogger3getEv:
  237|   460k|Logger *DefaultLogger::get() {
  238|   460k|    return m_pLogger;
  239|   460k|}

_ZN6Assimp22DefaultProgressHandler6UpdateEf:
   59|  8.00k|    bool Update(float) override {
   60|  8.00k|        return false;
   61|  8.00k|    }

_ZN15DeadlyErrorBaseC2EN6Assimp9Formatter15basic_formatterIcNSt3__111char_traitsIcEENS3_9allocatorIcEEEE:
   52|  2.19k|        runtime_error(std::string(f)){}

_ZN6Assimp16FileSystemFilterC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
   68|    297|    : mWrapped  (old)
   69|    297|    , mSrc_file(file)
   70|    297|    , mSep(mWrapped->getOsSeparator()) {
   71|    297|        ai_assert(nullptr != mWrapped);
   72|       |
   73|       |        // Determine base directory
   74|    297|        mBase = mSrc_file;
   75|    297|        std::string::size_type ss2;
   76|    297|        if (std::string::npos != (ss2 = mBase.find_last_of("\\/")))  {
  ------------------
  |  Branch (76:13): [True: 0, False: 297]
  ------------------
   77|      0|            mBase.erase(ss2,mBase.length()-ss2);
   78|    297|        } else {
   79|    297|            mBase = std::string();
   80|    297|        }
   81|       |
   82|       |        // make sure the directory is terminated properly
   83|    297|        char s;
   84|       |
   85|    297|        if ( mBase.empty() ) {
  ------------------
  |  Branch (85:14): [True: 297, False: 0]
  ------------------
   86|    297|            mBase = ".";
   87|    297|            mBase += getOsSeparator();
   88|    297|        } else if ((s = *(mBase.end()-1)) != '\\' && s != '/') {
  ------------------
  |  Branch (88:20): [True: 0, False: 0]
  |  Branch (88:20): [True: 0, False: 0]
  |  Branch (88:54): [True: 0, False: 0]
  ------------------
   89|      0|            mBase += getOsSeparator();
   90|      0|        }
   91|       |
   92|    297|        DefaultLogger::get()->info("Import root directory is \'", mBase, "\'");
   93|    297|    }
_ZNK6Assimp16FileSystemFilter14getOsSeparatorEv:
  116|    297|    char getOsSeparator() const {
  117|    297|        return mSep;
  118|    297|    }
_ZN6Assimp16FileSystemFilter4OpenEPKcS2_:
  122|    297|    IOStream* Open( const char* pFile, const char* pMode = "rb") {
  123|    297|        ai_assert( nullptr != mWrapped );
  124|    297|        if ( nullptr == pFile || nullptr == pMode ) {
  ------------------
  |  Branch (124:14): [True: 0, False: 297]
  |  Branch (124:34): [True: 0, False: 297]
  ------------------
  125|      0|            return nullptr;
  126|      0|        }
  127|       |
  128|    297|        ai_assert( nullptr != pFile );
  129|    297|        ai_assert( nullptr != pMode );
  130|       |
  131|       |        // First try the unchanged path
  132|    297|        IOStream* s = mWrapped->Open(pFile,pMode);
  133|       |
  134|    297|        if (nullptr == s) {
  ------------------
  |  Branch (134:13): [True: 0, False: 297]
  ------------------
  135|      0|            std::string tmp = pFile;
  136|       |
  137|       |            // Try to convert between absolute and relative paths
  138|      0|            BuildPath(tmp);
  139|      0|            s = mWrapped->Open(tmp,pMode);
  140|       |
  141|      0|            if (nullptr == s) {
  ------------------
  |  Branch (141:17): [True: 0, False: 0]
  ------------------
  142|       |                // Finally, look for typical issues with paths
  143|       |                // and try to correct them. This is our last
  144|       |                // resort.
  145|      0|                tmp = pFile;
  146|      0|                Cleanup(tmp);
  147|      0|                BuildPath(tmp);
  148|      0|                s = mWrapped->Open(tmp,pMode);
  149|      0|            }
  150|      0|        }
  151|       |
  152|    297|        return s;
  153|    297|    }
_ZN6Assimp16FileSystemFilter5CloseEPNS_8IOStreamE:
  157|    297|    void Close( IOStream* pFile) {
  158|       |        ai_assert( nullptr != mWrapped );
  159|    297|        return mWrapped->Close(pFile);
  160|    297|    }
_ZN6Assimp16FileSystemFilterD2Ev:
   96|    297|    ~FileSystemFilter() = default;

_ZN6Assimp6Intern22AllocateFromAssimpHeapnwEm:
  114|  1.48k|void* AllocateFromAssimpHeap::operator new ( size_t num_bytes)  {
  115|  1.48k|    return ::operator new(num_bytes);
  116|  1.48k|}
_ZN6Assimp6Intern22AllocateFromAssimpHeapdlEPv:
  127|  1.48k|void AllocateFromAssimpHeap::operator delete ( void* data)  {
  128|  1.48k|    return ::operator delete(data);
  129|  1.48k|}
_ZN6Assimp8ImporterC2Ev:
  150|    297| : pimpl( new ImporterPimpl ) {
  151|    297|    pimpl->mScene = nullptr;
  152|    297|    pimpl->mErrorString = std::string();
  153|       |
  154|       |    // Allocate a default IO handler
  155|    297|    pimpl->mIOHandler = new DefaultIOSystem;
  156|    297|    pimpl->mIsDefaultHandler = true;
  157|    297|    pimpl->bExtraVerbose     = false; // disable extra verbose mode by default
  158|       |
  159|    297|    pimpl->mProgressHandler = new DefaultProgressHandler();
  160|    297|    pimpl->mIsDefaultProgressHandler = true;
  161|       |
  162|    297|    GetImporterInstanceList(pimpl->mImporter);
  163|    297|    GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps);
  164|       |
  165|       |    // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list.
  166|    297|    pimpl->mPPShared = new SharedPostProcessInfo();
  167|    297|    for (std::vector<BaseProcess*>::iterator it =  pimpl->mPostProcessingSteps.begin();
  168|  10.0k|        it != pimpl->mPostProcessingSteps.end();
  ------------------
  |  Branch (168:9): [True: 9.80k, False: 297]
  ------------------
  169|  9.80k|        ++it)   {
  170|       |
  171|  9.80k|        (*it)->SetSharedData(pimpl->mPPShared);
  172|  9.80k|    }
  173|    297|}
_ZN6Assimp8ImporterD2Ev:
  177|    297|Importer::~Importer() {
  178|       |    // Delete all import plugins
  179|    297|	DeleteImporterInstanceList(pimpl->mImporter);
  180|       |
  181|       |    // Delete all post-processing plug-ins
  182|  10.0k|    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
  ------------------
  |  Branch (182:30): [True: 9.80k, False: 297]
  ------------------
  183|  9.80k|        delete pimpl->mPostProcessingSteps[a];
  184|  9.80k|    }
  185|       |
  186|       |    // Delete the assigned IO and progress handler
  187|    297|    delete pimpl->mIOHandler;
  188|    297|    delete pimpl->mProgressHandler;
  189|       |
  190|       |    // Kill imported scene. Destructor's should do that recursively
  191|    297|    delete pimpl->mScene;
  192|       |
  193|       |    // Delete shared post-processing data
  194|    297|    delete pimpl->mPPShared;
  195|       |
  196|       |    // and finally the pimpl itself
  197|    297|    delete pimpl;
  198|    297|}
_ZN6Assimp8Importer16UnregisterLoaderEPNS_12BaseImporterE:
  251|  13.9k|aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
  252|  13.9k|    if(!pImp) {
  ------------------
  |  Branch (252:8): [True: 0, False: 13.9k]
  ------------------
  253|       |        // unregistering a nullptr importer is no problem for us ... really!
  254|      0|        return AI_SUCCESS;
  255|      0|    }
  256|       |
  257|  13.9k|    ASSIMP_BEGIN_EXCEPTION_REGION();
  258|  13.9k|    std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),
  259|  13.9k|        pimpl->mImporter.end(),pImp);
  260|       |
  261|  13.9k|    if (it != pimpl->mImporter.end())   {
  ------------------
  |  Branch (261:9): [True: 13.9k, False: 0]
  ------------------
  262|  13.9k|        pimpl->mImporter.erase(it);
  263|  13.9k|        ASSIMP_LOG_INFO("Unregistering custom importer: ");
  264|  13.9k|        return AI_SUCCESS;
  265|  13.9k|    }
  266|  13.9k|    ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ...");
  267|      0|    ASSIMP_END_EXCEPTION_REGION(aiReturn);
  268|       |
  269|       |    return AI_FAILURE;
  270|  13.9k|}
_ZN6Assimp8Importer12SetIOHandlerEPNS_8IOSystemE:
  297|    594|void Importer::SetIOHandler( IOSystem* pIOHandler) {
  298|    594|    ai_assert(nullptr != pimpl);
  299|       |
  300|    594|    ASSIMP_BEGIN_EXCEPTION_REGION();
  301|       |    // If the new handler is zero, allocate a default IO implementation.
  302|    594|    if (!pIOHandler) {
  ------------------
  |  Branch (302:9): [True: 0, False: 594]
  ------------------
  303|       |        // Release pointer in the possession of the caller
  304|      0|        pimpl->mIOHandler = new DefaultIOSystem();
  305|      0|        pimpl->mIsDefaultHandler = true;
  306|    594|    } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
  ------------------
  |  Branch (306:16): [True: 594, False: 0]
  ------------------
  307|    594|        delete pimpl->mIOHandler;
  308|    594|        pimpl->mIOHandler = pIOHandler;
  309|    594|        pimpl->mIsDefaultHandler = false;
  310|    594|    }
  311|    594|    ASSIMP_END_EXCEPTION_REGION(void);
  312|    594|}
_ZNK6Assimp8Importer18GetProgressHandlerEv:
  352|  3.79k|ProgressHandler* Importer::GetProgressHandler() const {
  353|  3.79k|    ai_assert(nullptr != pimpl);
  354|       |
  355|  3.79k|    return pimpl->mProgressHandler;
  356|  3.79k|}
_Z14_ValidateFlagsj:
  368|    218|bool _ValidateFlags(unsigned int pFlags) {
  369|    218|    if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals)   {
  ------------------
  |  Branch (369:9): [True: 218, False: 0]
  |  Branch (369:48): [True: 0, False: 218]
  ------------------
  370|      0|        ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
  371|      0|        return false;
  372|      0|    }
  373|    218|    if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices)    {
  ------------------
  |  Branch (373:9): [True: 0, False: 218]
  |  Branch (373:45): [True: 0, False: 0]
  ------------------
  374|      0|        ASSIMP_LOG_ERROR("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible");
  375|      0|        return false;
  376|      0|    }
  377|    218|    return true;
  378|    218|}
_ZN6Assimp8Importer18ReadFileFromMemoryEPKvmjPKc:
  485|    297|const aiScene* Importer::ReadFileFromMemory(const void* pBuffer, size_t pLength, unsigned int pFlags, const char* pHint ) {
  486|    297|    ai_assert(nullptr != pimpl);
  487|       |
  488|    297|    IOSystem* io = pimpl->mIOHandler;
  489|    297|    try {
  490|    297|        if (pHint == nullptr) {
  ------------------
  |  Branch (490:13): [True: 0, False: 297]
  ------------------
  491|      0|            pHint = "";
  492|      0|        }
  493|    297|        if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
  ------------------
  |  Branch (493:13): [True: 0, False: 297]
  |  Branch (493:25): [True: 0, False: 297]
  |  Branch (493:37): [True: 0, False: 297]
  ------------------
  494|      0|            pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
  495|      0|            return nullptr;
  496|      0|        }
  497|       |        // prevent deletion of the previous IOHandler
  498|    297|        pimpl->mIOHandler = nullptr;
  499|       |
  500|    297|        SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
  501|       |
  502|       |        // read the file and recover the previous IOSystem
  503|    297|        static const size_t BufSize(Importer::MaxLenHint + 28);
  504|    297|        char fbuff[BufSize];
  505|    297|        ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
  506|       |
  507|    297|        ReadFile(fbuff,pFlags);
  508|    297|        SetIOHandler(io);
  509|    297|    } catch(const DeadlyImportError &e) {
  510|      0|        pimpl->mErrorString = e.what();
  511|      0|        pimpl->mException = std::current_exception();
  512|      0|        SetIOHandler(io);
  513|      0|        return ExceptionSwallower<const aiScene*>()();                                                                                                    \
  514|      0|    } catch(...) {
  515|      0|        pimpl->mErrorString = "Unknown exception";
  516|      0|        pimpl->mException = std::current_exception();
  517|      0|        SetIOHandler(io);
  518|      0|        return ExceptionSwallower<const aiScene*>()();                                                                                                    \
  519|      0|
  520|      0|    }
  521|       |
  522|    297|    return pimpl->mScene;
  523|    297|}
_Z15WriteLogOpeningRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
  526|    297|void WriteLogOpening(const std::string& file) {
  527|       |
  528|    297|    ASSIMP_LOG_INFO("Load ", file);
  529|       |
  530|       |    // print a full version dump. This is nice because we don't
  531|       |    // need to ask the authors of incoming bug reports for
  532|       |    // the library version they're using - a log dump is
  533|       |    // sufficient.
  534|    297|    const unsigned int flags = aiGetCompileFlags();
  535|    297|    std::stringstream stream;
  536|    297|    stream << "Assimp " << aiGetVersionMajor() << "." << aiGetVersionMinor() << "." << aiGetVersionRevision() << " "
  537|       |#if defined(ASSIMP_BUILD_ARCHITECTURE)
  538|       |           << ASSIMP_BUILD_ARCHITECTURE
  539|       |#elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__)
  540|       |           << "x86"
  541|       |#elif defined(_M_X64) || defined(__x86_64__)
  542|       |           << "amd64"
  543|       |#elif defined(_M_IA64) || defined(__ia64__)
  544|       |           << "itanium"
  545|       |#elif defined(__ppc__) || defined(__powerpc__)
  546|       |           << "ppc32"
  547|       |#elif defined(__powerpc64__)
  548|       |           << "ppc64"
  549|       |#elif defined(__arm__)
  550|       |           << "arm"
  551|       |#else
  552|       |           << "<unknown architecture>"
  553|       |#endif
  554|    297|           << " "
  555|       |#if defined(ASSIMP_BUILD_COMPILER)
  556|       |           << (ASSIMP_BUILD_COMPILER)
  557|       |#elif defined(_MSC_VER)
  558|       |           << "msvc"
  559|       |#elif defined(__GNUC__)
  560|       |           << "gcc"
  561|       |#elif defined(__clang__)
  562|       |           << "clang"
  563|       |#elif defined(__EMSCRIPTEN__)
  564|       |           << "emscripten"
  565|       |#elif defined(__MINGW32__)
  566|       |           << "MinGW-w64 32bit"
  567|       |#elif defined(__MINGW64__)
  568|       |           << "MinGW-w64 64bit"
  569|       |#else
  570|       |           << "<unknown compiler>"
  571|       |#endif
  572|       |
  573|    297|#ifdef ASSIMP_BUILD_DEBUG
  574|    297|           << " debug"
  575|    297|#endif
  576|       |
  577|    297|           << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
  ------------------
  |  |  105|    297|#define ASSIMP_CFLAGS_NOBOOST           0x8
  ------------------
  |  Branch (577:16): [True: 0, False: 297]
  ------------------
  578|    297|           << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "")
  ------------------
  |  |   98|    297|#define ASSIMP_CFLAGS_SHARED  0x1
  ------------------
  |  Branch (578:16): [True: 0, False: 297]
  ------------------
  579|    297|           << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "")
  ------------------
  |  |  107|    297|#define ASSIMP_CFLAGS_SINGLETHREADED    0x10
  ------------------
  |  Branch (579:16): [True: 297, False: 0]
  ------------------
  580|    297|           << (flags & ASSIMP_CFLAGS_DOUBLE_SUPPORT ? " double : " : "single : ");
  ------------------
  |  |  109|    297|#define ASSIMP_CFLAGS_DOUBLE_SUPPORT 0x20
  ------------------
  |  Branch (580:16): [True: 0, False: 297]
  ------------------
  581|       |
  582|       |    ASSIMP_LOG_DEBUG(stream.str());
  583|    297|}
_ZN6Assimp8Importer8ReadFileEPKcj:
  587|    297|const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
  588|    297|    ai_assert(nullptr != pimpl);
  589|       |
  590|    297|    ASSIMP_BEGIN_EXCEPTION_REGION();
  591|    297|    const std::string pFile(_pFile);
  592|       |
  593|       |    // ----------------------------------------------------------------------
  594|       |    // Put a large try block around everything to catch all std::exception's
  595|       |    // that might be thrown by STL containers or by new().
  596|       |    // ImportErrorException's are throw by ourselves and caught elsewhere.
  597|       |    //-----------------------------------------------------------------------
  598|       |
  599|    297|    WriteLogOpening(pFile);
  600|       |
  601|       |#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  602|       |    try
  603|       |#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  604|    297|    {
  605|       |        // Check whether this Importer instance has already loaded
  606|       |        // a scene. In this case we need to delete the old one
  607|    297|        if (pimpl->mScene)  {
  ------------------
  |  Branch (607:13): [True: 0, False: 297]
  ------------------
  608|       |
  609|      0|            ASSIMP_LOG_DEBUG("(Deleting previous scene)");
  610|      0|            FreeScene();
  611|      0|        }
  612|       |
  613|       |        // First check if the file is accessible at all
  614|    297|        if( !pimpl->mIOHandler->Exists( pFile)) {
  ------------------
  |  Branch (614:13): [True: 0, False: 297]
  ------------------
  615|       |
  616|      0|            pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
  617|      0|            ASSIMP_LOG_ERROR(pimpl->mErrorString);
  618|      0|            return nullptr;
  619|      0|        }
  620|       |
  621|    297|        std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
  ------------------
  |  Branch (621:44): [True: 0, False: 297]
  ------------------
  622|    297|        if (profiler) {
  ------------------
  |  Branch (622:13): [True: 0, False: 297]
  ------------------
  623|      0|            profiler->BeginRegion("total");
  624|      0|        }
  625|       |
  626|       |        // Find an worker class which can handle the file extension.
  627|       |        // Multiple importers may be able to handle the same extension (.xml!); gather them all.
  628|    297|        SetPropertyInteger("importerIndex", -1);
  629|    297|        struct ImporterAndIndex {
  630|    297|            BaseImporter * importer;
  631|    297|            unsigned int   index;
  632|    297|        };
  633|    297|        std::vector<ImporterAndIndex> possibleImporters;
  634|    594|        for (unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
  ------------------
  |  Branch (634:34): [True: 297, False: 297]
  ------------------
  635|       |
  636|       |            // Every importer has a list of supported extensions.
  637|    297|            std::set<std::string> extensions;
  638|    297|            pimpl->mImporter[a]->GetExtensionList(extensions);
  639|       |
  640|    297|            if (BaseImporter::HasExtension(pFile, extensions)) {
  ------------------
  |  Branch (640:17): [True: 297, False: 0]
  ------------------
  641|    297|                ImporterAndIndex candidate = { pimpl->mImporter[a], a };
  642|    297|                possibleImporters.push_back(candidate);
  643|    297|            }
  644|    297|        }
  645|       |
  646|       |        // If just one importer supports this extension, pick it and close the case.
  647|    297|        BaseImporter* imp = nullptr;
  648|    297|        if (1 == possibleImporters.size()) {
  ------------------
  |  Branch (648:13): [True: 297, False: 0]
  ------------------
  649|    297|            imp = possibleImporters[0].importer;
  650|    297|            SetPropertyInteger("importerIndex", possibleImporters[0].index);
  651|    297|        }
  652|       |        // If multiple importers claim this file extension, ask them to look at the actual file data to decide.
  653|       |        // This can happen e.g. with XML (COLLADA vs. Irrlicht).
  654|      0|        else {
  655|      0|            for (std::vector<ImporterAndIndex>::const_iterator it = possibleImporters.begin(); it < possibleImporters.end(); ++it) {
  ------------------
  |  Branch (655:96): [True: 0, False: 0]
  ------------------
  656|      0|                BaseImporter & importer = *it->importer;
  657|       |
  658|      0|                ASSIMP_LOG_INFO("Found a possible importer: " + std::string(importer.GetInfo()->mName) + "; trying signature-based detection");
  659|      0|                if (importer.CanRead( pFile, pimpl->mIOHandler, true)) {
  ------------------
  |  Branch (659:21): [True: 0, False: 0]
  ------------------
  660|      0|                    imp = &importer;
  661|      0|                    SetPropertyInteger("importerIndex", it->index);
  662|      0|                    break;
  663|      0|                }
  664|       |
  665|      0|            }
  666|       |
  667|      0|        }
  668|       |
  669|    297|        if (!imp)   {
  ------------------
  |  Branch (669:13): [True: 0, False: 297]
  ------------------
  670|       |            // not so bad yet ... try format auto detection.
  671|      0|            ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
  672|      0|            for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
  ------------------
  |  Branch (672:38): [True: 0, False: 0]
  ------------------
  673|      0|                if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
  ------------------
  |  Branch (673:21): [True: 0, False: 0]
  ------------------
  674|      0|                    imp = pimpl->mImporter[a];
  675|      0|                    SetPropertyInteger("importerIndex", a);
  676|      0|                    break;
  677|      0|                }
  678|      0|            }
  679|       |            // Put a proper error message if no suitable importer was found
  680|      0|            if( !imp)   {
  ------------------
  |  Branch (680:17): [True: 0, False: 0]
  ------------------
  681|      0|                pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
  682|      0|                ASSIMP_LOG_ERROR(pimpl->mErrorString);
  683|      0|                return nullptr;
  684|      0|            }
  685|      0|        }
  686|       |
  687|       |        // Get file size for progress handler
  688|    297|        IOStream * fileIO = pimpl->mIOHandler->Open( pFile );
  689|    297|        uint32_t fileSize = 0;
  690|    297|        if (fileIO)
  ------------------
  |  Branch (690:13): [True: 297, False: 0]
  ------------------
  691|    297|        {
  692|    297|            fileSize = static_cast<uint32_t>(fileIO->FileSize());
  693|    297|            pimpl->mIOHandler->Close( fileIO );
  694|    297|        }
  695|       |
  696|       |        // Dispatch the reading to the worker class for this format
  697|    297|        const aiImporterDesc *desc( imp->GetInfo() );
  698|    297|        std::string ext( "unknown" );
  699|    297|        if ( nullptr != desc ) {
  ------------------
  |  Branch (699:14): [True: 297, False: 0]
  ------------------
  700|    297|            ext = desc->mName;
  701|    297|        }
  702|    297|        ASSIMP_LOG_INFO("Found a matching importer for this file format: ", ext, "." );
  703|    297|        pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
  704|       |
  705|    297|        if (profiler) {
  ------------------
  |  Branch (705:13): [True: 0, False: 297]
  ------------------
  706|      0|            profiler->BeginRegion("import");
  707|      0|        }
  708|       |
  709|    297|        pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
  710|    297|        pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize );
  711|       |
  712|    297|        if (profiler) {
  ------------------
  |  Branch (712:13): [True: 0, False: 297]
  ------------------
  713|      0|            profiler->EndRegion("import");
  714|      0|        }
  715|       |
  716|    297|        SetPropertyString("sourceFilePath", pFile);
  717|       |
  718|       |        // If successful, apply all active post processing steps to the imported data
  719|    297|        if( pimpl->mScene)  {
  ------------------
  |  Branch (719:13): [True: 227, False: 70]
  ------------------
  720|    227|            if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
  ------------------
  |  Branch (720:17): [True: 0, False: 227]
  |  Branch (720:46): [True: 227, False: 0]
  ------------------
  721|    227|                if (!pimpl->mScene->mMetaData) {
  ------------------
  |  Branch (721:21): [True: 0, False: 227]
  ------------------
  722|      0|                    pimpl->mScene->mMetaData = new aiMetadata;
  723|      0|                }
  724|    227|                pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
  725|    227|            }
  726|       |
  727|    227|#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  728|       |            // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
  729|    227|            if (pFlags & aiProcess_ValidateDataStructure) {
  ------------------
  |  Branch (729:17): [True: 227, False: 0]
  ------------------
  730|    227|                ValidateDSProcess ds;
  731|    227|                ds.ExecuteOnScene (this);
  732|    227|                if (!pimpl->mScene) {
  ------------------
  |  Branch (732:21): [True: 9, False: 218]
  ------------------
  733|      9|                    return nullptr;
  734|      9|                }
  735|    227|            }
  736|    218|#endif // ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  737|       |
  738|       |            // Preprocess the scene and prepare it for post-processing
  739|    218|            if (profiler) {
  ------------------
  |  Branch (739:17): [True: 0, False: 218]
  ------------------
  740|      0|                profiler->BeginRegion("preprocess");
  741|      0|            }
  742|       |
  743|    218|            ScenePreprocessor pre(pimpl->mScene);
  744|    218|            pre.ProcessScene();
  745|       |
  746|    218|            if (profiler) {
  ------------------
  |  Branch (746:17): [True: 0, False: 218]
  ------------------
  747|      0|                profiler->EndRegion("preprocess");
  748|      0|            }
  749|       |
  750|       |            // Ensure that the validation process won't be called twice
  751|    218|            ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
  752|    218|        }
  753|       |        // if failed, extract the error string
  754|     70|        else if( !pimpl->mScene) {
  ------------------
  |  Branch (754:18): [True: 70, False: 0]
  ------------------
  755|     70|            pimpl->mErrorString = imp->GetErrorText();
  756|     70|            pimpl->mException = imp->GetException();
  757|     70|        }
  758|       |
  759|       |        // clear any data allocated by post-process steps
  760|    288|        pimpl->mPPShared->Clean();
  761|       |
  762|    288|        if (profiler) {
  ------------------
  |  Branch (762:13): [True: 0, False: 288]
  ------------------
  763|      0|            profiler->EndRegion("total");
  764|      0|        }
  765|    288|    }
  766|       |#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  767|       |    catch (std::exception &e) {
  768|       |#if (defined _MSC_VER) &&   (defined _CPPRTTI)
  769|       |        // if we have RTTI get the full name of the exception that occurred
  770|       |        pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
  771|       |#else
  772|       |        pimpl->mErrorString = std::string("std::exception: ") + e.what();
  773|       |#endif
  774|       |        pimpl->mException = std::current_exception();
  775|       |
  776|       |        ASSIMP_LOG_ERROR(pimpl->mErrorString);
  777|       |        delete pimpl->mScene; pimpl->mScene = nullptr;
  778|       |    }
  779|       |#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  780|       |
  781|       |    // either successful or failure - the pointer expresses it anyways
  782|    288|    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
  783|       |
  784|    288|    return pimpl->mScene;
  785|    297|}
_ZN6Assimp8Importer19ApplyPostProcessingEj:
  790|    218|const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
  791|    218|    ai_assert(nullptr != pimpl);
  792|       |
  793|    218|    ASSIMP_BEGIN_EXCEPTION_REGION();
  794|       |    // Return immediately if no scene is active
  795|    218|    if (!pimpl->mScene) {
  ------------------
  |  Branch (795:9): [True: 0, False: 218]
  ------------------
  796|      0|        return nullptr;
  797|      0|    }
  798|       |
  799|       |    // If no flags are given, return the current scene with no further action
  800|    218|    if (!pFlags) {
  ------------------
  |  Branch (800:9): [True: 0, False: 218]
  ------------------
  801|      0|        return pimpl->mScene;
  802|      0|    }
  803|       |
  804|       |    // In debug builds: run basic flag validation
  805|    218|    ai_assert(_ValidateFlags(pFlags));
  806|    218|    ASSIMP_LOG_INFO("Entering post processing pipeline");
  807|       |
  808|    218|#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  809|       |    // The ValidateDS process plays an exceptional role. It isn't contained in the global
  810|       |    // list of post-processing steps, so we need to call it manually.
  811|    218|    if (pFlags & aiProcess_ValidateDataStructure) {
  ------------------
  |  Branch (811:9): [True: 0, False: 218]
  ------------------
  812|      0|        ValidateDSProcess ds;
  813|      0|        ds.ExecuteOnScene (this);
  814|      0|        if (!pimpl->mScene) {
  ------------------
  |  Branch (814:13): [True: 0, False: 0]
  ------------------
  815|      0|            return nullptr;
  816|      0|        }
  817|      0|    }
  818|    218|#endif // no validation
  819|    218|#ifdef ASSIMP_BUILD_DEBUG
  820|    218|    if (pimpl->bExtraVerbose)
  ------------------
  |  Branch (820:9): [True: 0, False: 218]
  ------------------
  821|      0|    {
  822|       |#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  823|       |        ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
  824|       |#endif  // no validation
  825|      0|        pFlags |= aiProcess_ValidateDataStructure;
  826|      0|    }
  827|       |#else
  828|       |    if (pimpl->bExtraVerbose) {
  829|       |        ASSIMP_LOG_WARN("Not a debug build, ignoring extra verbose setting");
  830|       |    }
  831|       |#endif // ! DEBUG
  832|       |
  833|    218|    std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
  ------------------
  |  Branch (833:40): [True: 0, False: 218]
  ------------------
  834|  7.41k|    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)   {
  ------------------
  |  Branch (834:30): [True: 7.19k, False: 218]
  ------------------
  835|  7.19k|        BaseProcess* process = pimpl->mPostProcessingSteps[a];
  836|  7.19k|        pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
  837|  7.19k|        if( process->IsActive( pFlags)) {
  ------------------
  |  Branch (837:13): [True: 3.27k, False: 3.92k]
  ------------------
  838|  3.27k|            if (profiler) {
  ------------------
  |  Branch (838:17): [True: 0, False: 3.27k]
  ------------------
  839|      0|                profiler->BeginRegion("postprocess");
  840|      0|            }
  841|       |
  842|  3.27k|            process->ExecuteOnScene ( this );
  843|       |
  844|  3.27k|            if (profiler) {
  ------------------
  |  Branch (844:17): [True: 0, False: 3.27k]
  ------------------
  845|      0|                profiler->EndRegion("postprocess");
  846|      0|            }
  847|  3.27k|        }
  848|  7.19k|        if( !pimpl->mScene) {
  ------------------
  |  Branch (848:13): [True: 0, False: 7.19k]
  ------------------
  849|      0|            break;
  850|      0|        }
  851|  7.19k|#ifdef ASSIMP_BUILD_DEBUG
  852|  7.19k|#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  853|       |        // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
  854|  7.19k|        if (pimpl->bExtraVerbose)   {
  ------------------
  |  Branch (854:13): [True: 0, False: 7.19k]
  ------------------
  855|      0|            ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures");
  856|       |
  857|      0|            ValidateDSProcess ds;
  858|      0|            ds.ExecuteOnScene (this);
  859|      0|            if( !pimpl->mScene) {
  ------------------
  |  Branch (859:17): [True: 0, False: 0]
  ------------------
  860|      0|                ASSIMP_LOG_ERROR("Verbose Import: failed to re-validate data structures");
  861|      0|                break;
  862|      0|            }
  863|      0|        }
  864|  7.19k|#endif  // no validation
  865|  7.19k|#endif // ! DEBUG
  866|  7.19k|    }
  867|    218|    pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
  868|    218|        static_cast<int>(pimpl->mPostProcessingSteps.size()) );
  869|       |
  870|       |    // update private scene flags
  871|    218|    if( pimpl->mScene ) {
  ------------------
  |  Branch (871:9): [True: 218, False: 0]
  ------------------
  872|    218|      ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
  873|    218|    }
  874|       |
  875|       |    // clear any data allocated by post-process steps
  876|    218|    pimpl->mPPShared->Clean();
  877|    218|    ASSIMP_LOG_INFO("Leaving post processing pipeline");
  878|       |
  879|    218|    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
  880|       |
  881|    218|    return pimpl->mScene;
  882|    218|}
_ZNK6Assimp8Importer16GetImporterCountEv:
  969|    297|size_t Importer::GetImporterCount() const {
  970|    297|    ai_assert(nullptr != pimpl);
  971|       |
  972|    297|    return pimpl->mImporter.size();
  973|    297|}
_ZNK6Assimp8Importer15GetImporterInfoEm:
  976|  14.2k|const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
  977|  14.2k|    ai_assert(nullptr != pimpl);
  978|       |
  979|  14.2k|    if (index >= pimpl->mImporter.size()) {
  ------------------
  |  Branch (979:9): [True: 0, False: 14.2k]
  ------------------
  980|      0|        return nullptr;
  981|      0|    }
  982|  14.2k|    return pimpl->mImporter[index]->GetInfo();
  983|  14.2k|}
_ZNK6Assimp8Importer11GetImporterEm:
  987|  14.2k|BaseImporter* Importer::GetImporter (size_t index) const {
  988|  14.2k|    ai_assert(nullptr != pimpl);
  989|       |
  990|  14.2k|    if (index >= pimpl->mImporter.size()) {
  ------------------
  |  Branch (990:9): [True: 0, False: 14.2k]
  ------------------
  991|      0|        return nullptr;
  992|      0|    }
  993|  14.2k|    return pimpl->mImporter[index];
  994|  14.2k|}
_ZN6Assimp8Importer18SetPropertyIntegerEPKci:
 1063|    594|bool Importer::SetPropertyInteger(const char* szName, int iValue) {
 1064|    594|    ai_assert(nullptr != pimpl);
 1065|       |
 1066|    594|    bool existing;
 1067|    594|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1068|    594|        existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
 1069|    594|    ASSIMP_END_EXCEPTION_REGION(bool);
 1070|    594|    return existing;
 1071|    594|}
_ZN6Assimp8Importer16SetPropertyFloatEPKcf:
 1075|    227|bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
 1076|    227|    ai_assert(nullptr != pimpl);
 1077|       |
 1078|    227|    bool existing;
 1079|    227|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1080|    227|        existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
 1081|    227|    ASSIMP_END_EXCEPTION_REGION(bool);
 1082|    227|    return existing;
 1083|    227|}
_ZN6Assimp8Importer17SetPropertyStringEPKcRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
 1087|    297|bool Importer::SetPropertyString(const char* szName, const std::string& value) {
 1088|    297|    ai_assert(nullptr != pimpl);
 1089|       |
 1090|    297|    bool existing;
 1091|    297|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1092|    297|        existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
 1093|    297|    ASSIMP_END_EXCEPTION_REGION(bool);
 1094|    297|    return existing;
 1095|    297|}
_ZNK6Assimp8Importer18GetPropertyIntegerEPKci:
 1123|  7.44k|int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
 1124|  7.44k|    ai_assert(nullptr != pimpl);
 1125|       |
 1126|  7.44k|    return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
 1127|  7.44k|}
_ZNK6Assimp8Importer16GetPropertyFloatEPKcf:
 1131|    654|ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
 1132|    654|    ai_assert(nullptr != pimpl);
 1133|       |
 1134|    654|    return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
 1135|    654|}
_ZNK6Assimp8Importer17GetPropertyStringEPKcRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
 1139|    218|std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
 1140|    218|    ai_assert(nullptr != pimpl);
 1141|       |
 1142|    218|    return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 1143|    218|}

_ZN6Assimp13ImporterPimplC2Ev:
  137|    297|        mIOHandler( nullptr ),
  138|    297|        mIsDefaultHandler( false ),
  139|    297|        mProgressHandler( nullptr ),
  140|    297|        mIsDefaultProgressHandler( false ),
  141|    297|        mImporter(),
  142|    297|        mPostProcessingSteps(),
  143|    297|        mScene( nullptr ),
  144|    297|        mErrorString(),
  145|    297|        mException(),
  146|    297|        mIntProperties(),
  147|    297|        mFloatProperties(),
  148|    297|        mStringProperties(),
  149|    297|        mMatrixProperties(),
  150|    297|        mPointerProperties(),
  151|    297|        bExtraVerbose( false ),
  152|    297|        mPPShared( nullptr ) {
  153|       |    // empty
  154|    297|}
_ZN6Assimp13ImporterPimplD2Ev:
  133|    297|    ~ImporterPimpl() = default;

_ZN6Assimp23GetImporterInstanceListERNSt3__16vectorIPNS_12BaseImporterENS0_9allocatorIS3_EEEE:
  215|    297|void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
  216|       |
  217|       |    // Some importers may be unimplemented or otherwise unsuitable for general use
  218|       |    // in their current state. Devs can set ASSIMP_ENABLE_DEV_IMPORTERS in their
  219|       |    // local environment to enable them, otherwise they're left out of the registry.
  220|       |#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
  221|       |    // not supported under uwp
  222|       |    const char *envStr = std::getenv("ASSIMP_ENABLE_DEV_IMPORTERS");
  223|       |#else
  224|    297|    const char *envStr = { "0" };
  225|    297|#endif
  226|    297|    bool devImportersEnabled = envStr && strcmp(envStr, "0");
  ------------------
  |  Branch (226:32): [True: 297, False: 0]
  |  Branch (226:42): [True: 0, False: 297]
  ------------------
  227|       |
  228|       |    // Ensure no unused var warnings if all uses are #ifndef'd away below:
  229|    297|    (void)devImportersEnabled;
  230|       |
  231|       |    // ----------------------------------------------------------------------------
  232|       |    // Add an instance of each worker class here
  233|       |    // (register_new_importers_here)
  234|       |    // ----------------------------------------------------------------------------
  235|    297|    out.reserve(64);
  236|       |#if !defined(ASSIMP_BUILD_NO_USD_IMPORTER)
  237|       |    out.push_back(new USDImporter());
  238|       |#endif
  239|    297|#if (!defined ASSIMP_BUILD_NO_X_IMPORTER)
  240|    297|    out.push_back(new XFileImporter());
  241|    297|#endif
  242|    297|#if (!defined ASSIMP_BUILD_NO_OBJ_IMPORTER)
  243|    297|    out.push_back(new ObjFileImporter());
  244|    297|#endif
  245|    297|#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
  246|    297|    out.push_back(new AMFImporter());
  247|    297|#endif
  248|    297|#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
  249|    297|    out.push_back(new Discreet3DSImporter());
  250|    297|#endif
  251|       |#if (!defined ASSIMP_BUILD_NO_M3D_IMPORTER)
  252|       |    out.push_back(new M3DImporter());
  253|       |#endif
  254|    297|#if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER)
  255|    297|    out.push_back(new MD3Importer());
  256|    297|#endif
  257|    297|#if (!defined ASSIMP_BUILD_NO_MD2_IMPORTER)
  258|    297|    out.push_back(new MD2Importer());
  259|    297|#endif
  260|    297|#if (!defined ASSIMP_BUILD_NO_PLY_IMPORTER)
  261|    297|    out.push_back(new PLYImporter());
  262|    297|#endif
  263|    297|#if (!defined ASSIMP_BUILD_NO_MDL_IMPORTER)
  264|    297|    out.push_back(new MDLImporter());
  265|    297|#endif
  266|    297|#if (!defined ASSIMP_BUILD_NO_ASE_IMPORTER)
  267|    297|#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
  268|    297|    out.push_back(new ASEImporter());
  269|    297|#endif
  270|    297|#endif
  271|    297|#if (!defined ASSIMP_BUILD_NO_HMP_IMPORTER)
  272|    297|    out.push_back(new HMPImporter());
  273|    297|#endif
  274|    297|#if (!defined ASSIMP_BUILD_NO_SMD_IMPORTER)
  275|    297|    out.push_back(new SMDImporter());
  276|    297|#endif
  277|    297|#if (!defined ASSIMP_BUILD_NO_MDC_IMPORTER)
  278|    297|    out.push_back(new MDCImporter());
  279|    297|#endif
  280|    297|#if (!defined ASSIMP_BUILD_NO_MD5_IMPORTER)
  281|    297|    out.push_back(new MD5Importer());
  282|    297|#endif
  283|    297|#if (!defined ASSIMP_BUILD_NO_STL_IMPORTER)
  284|    297|    out.push_back(new STLImporter());
  285|    297|#endif
  286|    297|#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER)
  287|    297|    out.push_back(new LWOImporter());
  288|    297|#endif
  289|    297|#if (!defined ASSIMP_BUILD_NO_DXF_IMPORTER)
  290|    297|    out.push_back(new DXFImporter());
  291|    297|#endif
  292|    297|#if (!defined ASSIMP_BUILD_NO_NFF_IMPORTER)
  293|    297|    out.push_back(new NFFImporter());
  294|    297|#endif
  295|    297|#if (!defined ASSIMP_BUILD_NO_RAW_IMPORTER)
  296|    297|    out.push_back(new RAWImporter());
  297|    297|#endif
  298|    297|#if (!defined ASSIMP_BUILD_NO_SIB_IMPORTER)
  299|    297|    out.push_back(new SIBImporter());
  300|    297|#endif
  301|    297|#if (!defined ASSIMP_BUILD_NO_OFF_IMPORTER)
  302|    297|    out.push_back(new OFFImporter());
  303|    297|#endif
  304|    297|#if (!defined ASSIMP_BUILD_NO_AC_IMPORTER)
  305|    297|    out.push_back(new AC3DImporter());
  306|    297|#endif
  307|    297|#if (!defined ASSIMP_BUILD_NO_BVH_IMPORTER)
  308|    297|    out.push_back(new BVHLoader());
  309|    297|#endif
  310|    297|#if (!defined ASSIMP_BUILD_NO_IRRMESH_IMPORTER)
  311|    297|    out.push_back(new IRRMeshImporter());
  312|    297|#endif
  313|    297|#if (!defined ASSIMP_BUILD_NO_IRR_IMPORTER)
  314|    297|    out.push_back(new IRRImporter());
  315|    297|#endif
  316|    297|#if (!defined ASSIMP_BUILD_NO_Q3D_IMPORTER)
  317|    297|    out.push_back(new Q3DImporter());
  318|    297|#endif
  319|    297|#if (!defined ASSIMP_BUILD_NO_B3D_IMPORTER)
  320|    297|    out.push_back(new B3DImporter());
  321|    297|#endif
  322|    297|#if (!defined ASSIMP_BUILD_NO_COLLADA_IMPORTER)
  323|    297|    out.push_back(new ColladaLoader());
  324|    297|#endif
  325|    297|#if (!defined ASSIMP_BUILD_NO_TERRAGEN_IMPORTER)
  326|    297|    out.push_back(new TerragenImporter());
  327|    297|#endif
  328|    297|#if (!defined ASSIMP_BUILD_NO_CSM_IMPORTER)
  329|    297|    out.push_back(new CSMImporter());
  330|    297|#endif
  331|    297|#if (!defined ASSIMP_BUILD_NO_3D_IMPORTER)
  332|    297|    out.push_back(new UnrealImporter());
  333|    297|#endif
  334|    297|#if (!defined ASSIMP_BUILD_NO_LWS_IMPORTER)
  335|    297|    out.push_back(new LWSImporter());
  336|    297|#endif
  337|    297|#if (!defined ASSIMP_BUILD_NO_OGRE_IMPORTER)
  338|    297|    out.push_back(new Ogre::OgreImporter());
  339|    297|#endif
  340|    297|#if (!defined ASSIMP_BUILD_NO_OPENGEX_IMPORTER)
  341|    297|    out.push_back(new OpenGEX::OpenGEXImporter());
  342|    297|#endif
  343|    297|#if (!defined ASSIMP_BUILD_NO_MS3D_IMPORTER)
  344|    297|    out.push_back(new MS3DImporter());
  345|    297|#endif
  346|    297|#if (!defined ASSIMP_BUILD_NO_COB_IMPORTER)
  347|    297|    out.push_back(new COBImporter());
  348|    297|#endif
  349|    297|#if (!defined ASSIMP_BUILD_NO_BLEND_IMPORTER)
  350|    297|    out.push_back(new BlenderImporter());
  351|    297|#endif
  352|    297|#if (!defined ASSIMP_BUILD_NO_Q3BSP_IMPORTER)
  353|    297|    out.push_back(new Q3BSPFileImporter());
  354|    297|#endif
  355|    297|#if (!defined ASSIMP_BUILD_NO_NDO_IMPORTER)
  356|    297|    out.push_back(new NDOImporter());
  357|    297|#endif
  358|    297|#if (!defined ASSIMP_BUILD_NO_IFC_IMPORTER)
  359|    297|    out.push_back(new IFCImporter());
  360|    297|#endif
  361|    297|#if (!defined ASSIMP_BUILD_NO_XGL_IMPORTER)
  362|    297|    out.push_back(new XGLImporter());
  363|    297|#endif
  364|    297|#if (!defined ASSIMP_BUILD_NO_FBX_IMPORTER)
  365|    297|    out.push_back(new FBXImporter());
  366|    297|#endif
  367|    297|#if (!defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER)
  368|    297|    out.push_back(new AssbinImporter());
  369|    297|#endif
  370|    297|#if (!defined ASSIMP_BUILD_NO_GLTF_IMPORTER && !defined ASSIMP_BUILD_NO_GLTF1_IMPORTER)
  371|    297|    out.push_back(new glTFImporter());
  372|    297|#endif
  373|    297|#if (!defined ASSIMP_BUILD_NO_GLTF_IMPORTER && !defined ASSIMP_BUILD_NO_GLTF2_IMPORTER)
  374|    297|    out.push_back(new glTF2Importer());
  375|    297|#endif
  376|       |#if (!defined ASSIMP_BUILD_NO_C4D_IMPORTER)
  377|       |    out.push_back(new C4DImporter());
  378|       |#endif
  379|    297|#if (!defined ASSIMP_BUILD_NO_3MF_IMPORTER)
  380|    297|    out.push_back(new D3MFImporter());
  381|    297|#endif
  382|    297|#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
  383|    297|    out.push_back(new X3DImporter());
  384|    297|#endif
  385|    297|#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
  386|    297|    out.push_back(new MMDImporter());
  387|    297|#endif
  388|    297|#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
  389|    297|    out.push_back(new IQMImporter());
  390|    297|#endif
  391|    297|}
_ZN6Assimp26DeleteImporterInstanceListERNSt3__16vectorIPNS_12BaseImporterENS0_9allocatorIS3_EEEE:
  394|    297|void DeleteImporterInstanceList(std::vector<BaseImporter *> &deleteList) {
  395|    594|    for (size_t i = 0; i < deleteList.size(); ++i) {
  ------------------
  |  Branch (395:24): [True: 297, False: 297]
  ------------------
  396|    297|        delete deleteList[i];
  397|    297|        deleteList[i] = nullptr;
  398|    297|    } //for
  399|    297|}

_ZN6Assimp12NewellNormalILi3ELi3ELi3EfEEvR10aiVector3tIT2_EiPS2_S5_S5_:
  178|  1.88k|inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z) {
  179|       |    // Duplicate the first two vertices at the end
  180|  1.88k|    x[(num+0)*ofs_x] = x[0];
  181|  1.88k|    x[(num+1)*ofs_x] = x[ofs_x];
  182|       |
  183|  1.88k|    y[(num+0)*ofs_y] = y[0];
  184|  1.88k|    y[(num+1)*ofs_y] = y[ofs_y];
  185|       |
  186|  1.88k|    z[(num+0)*ofs_z] = z[0];
  187|  1.88k|    z[(num+1)*ofs_z] = z[ofs_z];
  188|       |
  189|  1.88k|    TReal sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0;
  190|       |
  191|  1.88k|    TReal *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2;
  192|  1.88k|    TReal *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2;
  193|  1.88k|    TReal *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2;
  194|       |
  195|   170k|    for (int tmp=0; tmp < num; tmp++) {
  ------------------
  |  Branch (195:21): [True: 168k, False: 1.88k]
  ------------------
  196|   168k|        sum_xy += (*xptr) * ( (*yhigh) - (*ylow) );
  197|   168k|        sum_yz += (*yptr) * ( (*zhigh) - (*zlow) );
  198|   168k|        sum_zx += (*zptr) * ( (*xhigh) - (*xlow) );
  199|       |
  200|   168k|        xptr  += ofs_x;
  201|   168k|        xlow  += ofs_x;
  202|   168k|        xhigh += ofs_x;
  203|       |
  204|   168k|        yptr  += ofs_y;
  205|   168k|        ylow  += ofs_y;
  206|   168k|        yhigh += ofs_y;
  207|       |
  208|   168k|        zptr  += ofs_z;
  209|   168k|        zlow  += ofs_z;
  210|   168k|        zhigh += ofs_z;
  211|   168k|    }
  212|  1.88k|    out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy);
  213|  1.88k|}

_ZN6Assimp33GetPostProcessingStepInstanceListERNSt3__16vectorIPNS_11BaseProcessENS0_9allocatorIS3_EEEE:
  147|    297|{
  148|       |    // ----------------------------------------------------------------------------
  149|       |    // Add an instance of each post processing step here in the order
  150|       |    // of sequence it is executed. Steps that are added here are not
  151|       |    // validated - as RegisterPPStep() does - all dependencies must be given.
  152|       |    // ----------------------------------------------------------------------------
  153|    297|    out.reserve(31);
  154|    297|#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
  155|    297|    out.push_back( new MakeLeftHandedProcess());
  156|    297|#endif
  157|    297|#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS)
  158|    297|    out.push_back( new FlipUVsProcess());
  159|    297|#endif
  160|    297|#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
  161|    297|    out.push_back( new FlipWindingOrderProcess());
  162|    297|#endif
  163|    297|#if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS)
  164|    297|    out.push_back( new RemoveVCProcess());
  165|    297|#endif
  166|    297|#if (!defined ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
  167|    297|    out.push_back( new RemoveRedundantMatsProcess());
  168|    297|#endif
  169|    297|#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS)
  170|    297|    out.push_back( new EmbedTexturesProcess());
  171|    297|#endif
  172|    297|#if (!defined ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS)
  173|    297|    out.push_back( new FindInstancesProcess());
  174|    297|#endif
  175|    297|#if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
  176|    297|    out.push_back( new OptimizeGraphProcess());
  177|    297|#endif
  178|    297|#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS
  179|    297|    out.push_back( new ComputeUVMappingProcess());
  180|    297|#endif
  181|    297|#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
  182|    297|    out.push_back( new TextureTransformStep());
  183|    297|#endif
  184|    297|#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
  185|    297|    out.push_back( new ScaleProcess());
  186|    297|#endif
  187|    297|#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
  188|    297|    out.push_back( new ArmaturePopulate());
  189|    297|#endif
  190|    297|#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
  191|    297|    out.push_back( new PretransformVertices());
  192|    297|#endif
  193|    297|#if (!defined ASSIMP_BUILD_NO_TRIANGULATE_PROCESS)
  194|    297|    out.push_back( new TriangulateProcess());
  195|    297|#endif
  196|    297|#if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS)
  197|       |    //find degenerates should run after triangulation (to sort out small
  198|       |    //generated triangles) but before sort by p types (in case there are lines
  199|       |    //and points generated and inserted into a mesh)
  200|    297|    out.push_back( new FindDegeneratesProcess());
  201|    297|#endif
  202|    297|#if (!defined ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS)
  203|    297|    out.push_back( new SortByPTypeProcess());
  204|    297|#endif
  205|    297|#if (!defined ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS)
  206|    297|    out.push_back( new FindInvalidDataProcess());
  207|    297|#endif
  208|    297|#if (!defined ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS)
  209|    297|    out.push_back( new OptimizeMeshesProcess());
  210|    297|#endif
  211|    297|#if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
  212|    297|    out.push_back( new FixInfacingNormalsProcess());
  213|    297|#endif
  214|    297|#if (!defined ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS)
  215|    297|    out.push_back( new SplitByBoneCountProcess());
  216|    297|#endif
  217|    297|#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
  218|    297|    out.push_back( new SplitLargeMeshesProcess_Triangle());
  219|    297|#endif
  220|    297|#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
  221|    297|    out.push_back( new DropFaceNormalsProcess());
  222|    297|#endif
  223|    297|#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
  224|    297|    out.push_back( new GenFaceNormalsProcess());
  225|    297|#endif
  226|       |    // .........................................................................
  227|       |    // DON'T change the order of these five ..
  228|       |    // XXX this is actually a design weakness that dates back to the time
  229|       |    // when Importer would maintain the postprocessing step list exclusively.
  230|       |    // Now that others access it too, we need a better solution.
  231|    297|    out.push_back( new ComputeSpatialSortProcess());
  232|       |    // .........................................................................
  233|       |
  234|    297|#if (!defined ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS)
  235|    297|    out.push_back( new GenVertexNormalsProcess());
  236|    297|#endif
  237|    297|#if (!defined ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS)
  238|    297|    out.push_back( new CalcTangentsProcess());
  239|    297|#endif
  240|    297|#if (!defined ASSIMP_BUILD_NO_JOINVERTICES_PROCESS)
  241|    297|    out.push_back( new JoinVerticesProcess());
  242|    297|#endif
  243|       |
  244|       |    // .........................................................................
  245|    297|    out.push_back( new DestroySpatialSortProcess());
  246|       |    // .........................................................................
  247|       |
  248|    297|#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
  249|    297|    out.push_back( new SplitLargeMeshesProcess_Vertex());
  250|    297|#endif
  251|    297|#if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS)
  252|    297|    out.push_back( new DeboneProcess());
  253|    297|#endif
  254|    297|#if (!defined ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
  255|    297|    out.push_back( new LimitBoneWeightsProcess());
  256|    297|#endif
  257|    297|#if (!defined ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
  258|    297|    out.push_back( new ImproveCacheLocalityProcess());
  259|    297|#endif
  260|    297|#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
  261|    297|    out.push_back(new GenBoundingBoxesProcess);
  262|    297|#endif
  263|    297|}

_ZN6Assimp17ScenePreprocessor12ProcessSceneEv:
   50|    218|void ScenePreprocessor::ProcessScene() {
   51|    218|    ai_assert(scene != nullptr);
  ------------------
  |  |   67|    218|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 218, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   52|       |
   53|       |    // Process all meshes
   54|    312|    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (54:30): [True: 94, False: 218]
  ------------------
   55|     94|        if (nullptr == scene->mMeshes[i]) {
  ------------------
  |  Branch (55:13): [True: 0, False: 94]
  ------------------
   56|      0|            continue;
   57|      0|        }
   58|     94|        ProcessMesh(scene->mMeshes[i]);
   59|     94|    }
   60|       |
   61|       |    // - nothing to do for nodes for the moment
   62|       |    // - nothing to do for textures for the moment
   63|       |    // - nothing to do for lights for the moment
   64|       |    // - nothing to do for cameras for the moment
   65|       |
   66|       |    // Process all animations
   67|    417|    for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
  ------------------
  |  Branch (67:30): [True: 199, False: 218]
  ------------------
   68|    199|        if (nullptr == scene->mAnimations[i]) {
  ------------------
  |  Branch (68:13): [True: 0, False: 199]
  ------------------
   69|      0|            continue;
   70|      0|        }
   71|    199|        ProcessAnimation(scene->mAnimations[i]);
   72|    199|    }
   73|       |
   74|       |    // Generate a default material if none was specified
   75|    218|    if (!scene->mNumMaterials && scene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 127, False: 91]
  |  Branch (75:34): [True: 0, False: 127]
  ------------------
   76|      0|        scene->mMaterials = new aiMaterial *[2];
   77|      0|        aiMaterial *helper;
   78|       |
   79|      0|        aiString name;
   80|       |
   81|      0|        scene->mMaterials[scene->mNumMaterials] = helper = new aiMaterial();
   82|      0|        aiColor3D clr(0.6f, 0.6f, 0.6f);
   83|      0|        helper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
   84|       |
   85|       |        // setup the default name to make this material identifiable
   86|      0|        name.Set(AI_DEFAULT_MATERIAL_NAME);
   87|      0|        helper->AddProperty(&name, AI_MATKEY_NAME);
   88|       |
   89|      0|        ASSIMP_LOG_DEBUG("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'");
   90|       |
   91|      0|        for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (91:34): [True: 0, False: 0]
  ------------------
   92|      0|            if (nullptr == scene->mMeshes[i]) {
  ------------------
  |  Branch (92:17): [True: 0, False: 0]
  ------------------
   93|      0|                continue;
   94|      0|            }
   95|      0|            scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials;
   96|      0|        }
   97|       |
   98|      0|        scene->mNumMaterials++;
   99|      0|    }
  100|    218|}
_ZN6Assimp17ScenePreprocessor11ProcessMeshEP6aiMesh:
  103|     94|void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
  104|       |    // If aiMesh::mNumUVComponents is *not* set assign the default value of 2
  105|    846|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (105:30): [True: 752, False: 94]
  ------------------
  106|    752|        if (!mesh->mTextureCoords[i]) {
  ------------------
  |  Branch (106:13): [True: 675, False: 77]
  ------------------
  107|    675|            mesh->mNumUVComponents[i] = 0;
  108|    675|            continue;
  109|    675|        }
  110|       |
  111|     77|        if (!mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (111:13): [True: 0, False: 77]
  ------------------
  112|      0|            mesh->mNumUVComponents[i] = 2;
  113|      0|        }
  114|       |
  115|     77|        aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices;
  116|       |
  117|       |        // Ensure unused components are zeroed. This will make 1D texture channels work
  118|       |        // as if they were 2D channels .. just in case an application doesn't handle
  119|       |        // this case
  120|     77|        if (2 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (120:13): [True: 77, False: 0]
  ------------------
  121|   300k|            for (; p != end; ++p) {
  ------------------
  |  Branch (121:20): [True: 300k, False: 77]
  ------------------
  122|   300k|                p->z = 0.f;
  123|   300k|            }
  124|     77|        } else if (1 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (124:20): [True: 0, False: 0]
  ------------------
  125|      0|            for (; p != end; ++p) {
  ------------------
  |  Branch (125:20): [True: 0, False: 0]
  ------------------
  126|      0|                p->z = p->y = 0.f;
  127|      0|            }
  128|      0|        } else if (3 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (128:20): [True: 0, False: 0]
  ------------------
  129|       |            // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
  130|      0|            for (; p != end; ++p) {
  ------------------
  |  Branch (130:20): [True: 0, False: 0]
  ------------------
  131|      0|                if (p->z != 0) {
  ------------------
  |  Branch (131:21): [True: 0, False: 0]
  ------------------
  132|      0|                    break;
  133|      0|                }
  134|      0|            }
  135|      0|            if (p == end) {
  ------------------
  |  Branch (135:17): [True: 0, False: 0]
  ------------------
  136|      0|                ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
  137|      0|                mesh->mNumUVComponents[i] = 2;
  138|      0|            }
  139|      0|        }
  140|     77|    }
  141|       |
  142|       |    // If the information which primitive types are there in the
  143|       |    // mesh is currently not available, compute it.
  144|     94|    if (!mesh->mPrimitiveTypes) {
  ------------------
  |  Branch (144:9): [True: 0, False: 94]
  ------------------
  145|      0|        ai_assert(mesh->mFaces != nullptr);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 0, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  146|      0|        for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (146:34): [True: 0, False: 0]
  ------------------
  147|      0|            aiFace &face = mesh->mFaces[a];
  148|      0|            switch (face.mNumIndices) {
  149|      0|            case 3u:
  ------------------
  |  Branch (149:13): [True: 0, False: 0]
  ------------------
  150|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  151|      0|                break;
  152|       |
  153|      0|            case 2u:
  ------------------
  |  Branch (153:13): [True: 0, False: 0]
  ------------------
  154|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  155|      0|                break;
  156|       |
  157|      0|            case 1u:
  ------------------
  |  Branch (157:13): [True: 0, False: 0]
  ------------------
  158|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  159|      0|                break;
  160|       |
  161|      0|            default:
  ------------------
  |  Branch (161:13): [True: 0, False: 0]
  ------------------
  162|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  163|      0|                break;
  164|      0|            }
  165|      0|        }
  166|      0|    }
  167|       |
  168|       |    // If tangents and normals are given but no bitangents compute them
  169|     94|    if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
  ------------------
  |  Branch (169:9): [True: 4, False: 90]
  |  Branch (169:28): [True: 4, False: 0]
  |  Branch (169:46): [True: 0, False: 4]
  ------------------
  170|      0|        mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
  171|      0|        for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
  ------------------
  |  Branch (171:34): [True: 0, False: 0]
  ------------------
  172|      0|            mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i];
  173|      0|        }
  174|      0|    }
  175|     94|}
_ZN6Assimp17ScenePreprocessor16ProcessAnimationEP11aiAnimation:
  178|    199|void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) {
  179|    199|    double first = 10e10, last = -10e10;
  180|  3.54k|    for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
  ------------------
  |  Branch (180:30): [True: 3.34k, False: 199]
  ------------------
  181|  3.34k|        aiNodeAnim *channel = anim->mChannels[i];
  182|       |
  183|       |        //  If the exact duration of the animation is not given
  184|       |        //  compute it now.
  185|  3.34k|        if (anim->mDuration == -1.) {
  ------------------
  |  Branch (185:13): [True: 0, False: 3.34k]
  ------------------
  186|       |            // Position keys
  187|      0|            for (unsigned int j = 0; j < channel->mNumPositionKeys; ++j) {
  ------------------
  |  Branch (187:38): [True: 0, False: 0]
  ------------------
  188|      0|                aiVectorKey &key = channel->mPositionKeys[j];
  189|      0|                first = std::min(first, key.mTime);
  190|      0|                last = std::max(last, key.mTime);
  191|      0|            }
  192|       |
  193|       |            // Scaling keys
  194|      0|            for (unsigned int j = 0; j < channel->mNumScalingKeys; ++j) {
  ------------------
  |  Branch (194:38): [True: 0, False: 0]
  ------------------
  195|      0|                aiVectorKey &key = channel->mScalingKeys[j];
  196|      0|                first = std::min(first, key.mTime);
  197|      0|                last = std::max(last, key.mTime);
  198|      0|            }
  199|       |
  200|       |            // Rotation keys
  201|      0|            for (unsigned int j = 0; j < channel->mNumRotationKeys; ++j) {
  ------------------
  |  Branch (201:38): [True: 0, False: 0]
  ------------------
  202|      0|                aiQuatKey &key = channel->mRotationKeys[j];
  203|      0|                first = std::min(first, key.mTime);
  204|      0|                last = std::max(last, key.mTime);
  205|      0|            }
  206|      0|        }
  207|       |
  208|       |        // Check whether the animation channel has no rotation
  209|       |        // or position tracks. In this case we generate a dummy
  210|       |        // track from the information we have in the transformation
  211|       |        // matrix of the corresponding node.
  212|  3.34k|        if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) {
  ------------------
  |  Branch (212:13): [True: 0, False: 3.34k]
  |  Branch (212:43): [True: 64, False: 3.28k]
  |  Branch (212:73): [True: 56, False: 3.22k]
  ------------------
  213|       |            // Find the node that belongs to this animation
  214|    120|            aiNode *node = scene->mRootNode->FindNode(channel->mNodeName);
  215|    120|            if (node) // ValidateDS will complain later if 'node' is nullptr
  ------------------
  |  Branch (215:17): [True: 86, False: 34]
  ------------------
  216|     86|            {
  217|       |                // Decompose the transformation matrix of the node
  218|     86|                aiVector3D scaling, position;
  219|     86|                aiQuaternion rotation;
  220|       |
  221|     86|                node->mTransformation.Decompose(scaling, rotation, position);
  222|       |
  223|       |                // No rotation keys? Generate a dummy track
  224|     86|                if (!channel->mNumRotationKeys) {
  ------------------
  |  Branch (224:21): [True: 0, False: 86]
  ------------------
  225|      0|                    if (channel->mRotationKeys) {
  ------------------
  |  Branch (225:25): [True: 0, False: 0]
  ------------------
  226|      0|                        delete[] channel->mRotationKeys;
  227|      0|                        channel->mRotationKeys = nullptr;
  228|      0|                    }
  229|      0|                    ai_assert(!channel->mRotationKeys);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 0, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  230|      0|                    channel->mNumRotationKeys = 1;
  231|      0|                    channel->mRotationKeys = new aiQuatKey[1];
  232|      0|                    aiQuatKey &q = channel->mRotationKeys[0];
  233|       |
  234|      0|                    q.mTime = 0.;
  235|      0|                    q.mValue = rotation;
  236|       |
  237|      0|                    ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy rotation track has been generated");
  238|     86|                } else {
  239|     86|                    ai_assert(channel->mRotationKeys);
  ------------------
  |  |   67|     86|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 86, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  240|     86|                }
  241|       |
  242|       |                // No scaling keys? Generate a dummy track
  243|     86|                if (!channel->mNumScalingKeys) {
  ------------------
  |  Branch (243:21): [True: 42, False: 44]
  ------------------
  244|     42|                    if (channel->mScalingKeys) {
  ------------------
  |  Branch (244:25): [True: 42, False: 0]
  ------------------
  245|     42|                        delete[] channel->mScalingKeys;
  246|     42|                        channel->mScalingKeys = nullptr;
  247|     42|                    }
  248|     42|                    ai_assert(!channel->mScalingKeys);
  ------------------
  |  |   67|     42|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 42, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  249|     42|                    channel->mNumScalingKeys = 1;
  250|     42|                    channel->mScalingKeys = new aiVectorKey[1];
  251|     42|                    aiVectorKey &q = channel->mScalingKeys[0];
  252|       |
  253|     42|                    q.mTime = 0.;
  254|     42|                    q.mValue = scaling;
  255|       |
  256|     42|                    ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy scaling track has been generated");
  257|     44|                } else {
  258|     44|                    ai_assert(channel->mScalingKeys);
  ------------------
  |  |   67|     44|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 44, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  259|     44|                }
  260|       |
  261|       |                // No position keys? Generate a dummy track
  262|     86|                if (!channel->mNumPositionKeys) {
  ------------------
  |  Branch (262:21): [True: 44, False: 42]
  ------------------
  263|     44|                    if (channel->mPositionKeys) {
  ------------------
  |  Branch (263:25): [True: 44, False: 0]
  ------------------
  264|     44|                        delete[] channel->mPositionKeys;
  265|     44|                        channel->mPositionKeys = nullptr;
  266|     44|                    }
  267|     44|                    ai_assert(!channel->mPositionKeys);
  ------------------
  |  |   67|     44|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 44, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  268|     44|                    channel->mNumPositionKeys = 1;
  269|     44|                    channel->mPositionKeys = new aiVectorKey[1];
  270|     44|                    aiVectorKey &q = channel->mPositionKeys[0];
  271|       |
  272|     44|                    q.mTime = 0.;
  273|     44|                    q.mValue = position;
  274|       |
  275|     44|                    ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy position track has been generated");
  276|     44|                } else {
  277|     42|                    ai_assert(channel->mPositionKeys);
  ------------------
  |  |   67|     42|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 42, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  278|     42|                }
  279|     86|            }
  280|    120|        }
  281|  3.34k|    }
  282|       |
  283|    199|    if (anim->mDuration == -1.) {
  ------------------
  |  Branch (283:9): [True: 0, False: 199]
  ------------------
  284|       |        ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Setting animation duration");
  285|      0|        anim->mDuration = last - std::min(first, 0.);
  286|      0|    }
  287|    199|}

_ZN6Assimp17ScenePreprocessorC2EP7aiScene:
   79|    218|            scene(_scene) {}

_ZN6Assimp9ScenePrivEP7aiScene:
   85|    218|ScenePrivateData* ScenePriv(aiScene* in) {
   86|    218|    ai_assert( nullptr != in );
   87|    218|    if ( nullptr == in ) {
  ------------------
  |  Branch (87:10): [True: 0, False: 218]
  ------------------
   88|      0|        return nullptr;
   89|      0|    }
   90|    218|    return static_cast<ScenePrivateData*>(in->mPrivate);
   91|    218|}
_ZN6Assimp16ScenePrivateDataC2Ev:
   77|    297|: mOrigImporter( nullptr )
   78|    297|, mPPStepsApplied( 0 )
   79|    297|, mIsCopy( false ) {
   80|       |    // empty
   81|    297|}

_ZN6Assimp11SpatialSortC2Ev:
   69|    239|        mPlaneNormal(PlaneInit),
   70|    239|        mFinalized(false) {
   71|    239|    mPlaneNormal.Normalize();
   72|    239|}
_ZN6Assimp11SpatialSort4FillEPK10aiVector3tIfEjjb:
   77|     97|        bool pFinalize /*= true */) {
   78|     97|    mPositions.clear();
   79|     97|    mFinalized = false;
   80|     97|    Append(pPositions, pNumPositions, pElementOffset, pFinalize);
   81|     97|    mFinalized = pFinalize;
   82|     97|}
_ZNK6Assimp11SpatialSort17CalculateDistanceERK10aiVector3tIfE:
   85|   552k|ai_real SpatialSort::CalculateDistance(const aiVector3D &pPosition) const {
   86|   552k|    return (pPosition - mCentroid) * mPlaneNormal;
   87|   552k|}
_ZN6Assimp11SpatialSort8FinalizeEv:
   90|     97|void SpatialSort::Finalize() {
   91|     97|    const ai_real scale = 1.0f / mPositions.size();
   92|   369k|    for (unsigned int i = 0; i < mPositions.size(); i++) {
  ------------------
  |  Branch (92:30): [True: 369k, False: 97]
  ------------------
   93|   369k|        mCentroid += scale * mPositions[i].mPosition;
   94|   369k|    }
   95|   369k|    for (unsigned int i = 0; i < mPositions.size(); i++) {
  ------------------
  |  Branch (95:30): [True: 369k, False: 97]
  ------------------
   96|   369k|        mPositions[i].mDistance = CalculateDistance(mPositions[i].mPosition);
   97|   369k|    }
   98|     97|    std::sort(mPositions.begin(), mPositions.end());
   99|     97|    mFinalized = true;
  100|     97|}
_ZN6Assimp11SpatialSort6AppendEPK10aiVector3tIfEjjb:
  105|     97|        bool pFinalize /*= true */) {
  106|     97|    ai_assert(!mFinalized && "You cannot add positions to the SpatialSort object after it has been finalized.");
  ------------------
  |  |   67|    194|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:45): [True: 97, False: 0]
  |  |  |  Branch (67:45): [True: 0, Folded]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  107|       |    // store references to all given positions along with their distance to the reference plane
  108|     97|    const size_t initial = mPositions.size();
  109|     97|    mPositions.reserve(initial + pNumPositions);
  110|   369k|    for (unsigned int a = 0; a < pNumPositions; a++) {
  ------------------
  |  Branch (110:30): [True: 369k, False: 97]
  ------------------
  111|   369k|        const char *tempPointer = reinterpret_cast<const char *>(pPositions);
  112|   369k|        const aiVector3D *vec = reinterpret_cast<const aiVector3D *>(tempPointer + a * pElementOffset);
  113|   369k|        mPositions.emplace_back(static_cast<unsigned int>(a + initial), *vec);
  114|   369k|    }
  115|       |
  116|     97|    if (pFinalize) {
  ------------------
  |  Branch (116:9): [True: 97, False: 0]
  ------------------
  117|       |        // now sort the array ascending by distance.
  118|     97|        Finalize();
  119|     97|    }
  120|     97|}
_ZNK6Assimp11SpatialSort13FindPositionsERK10aiVector3tIfEfRNSt3__16vectorIjNS5_9allocatorIjEEEE:
  125|   183k|        ai_real pRadius, std::vector<unsigned int> &poResults) const {
  126|   183k|    ai_assert(mFinalized && "The SpatialSort object must be finalized before FindPositions can be called.");
  ------------------
  |  |   67|   366k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:45): [True: 183k, False: 0]
  |  |  |  Branch (67:45): [True: 0, Folded]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  127|   183k|    const ai_real dist = CalculateDistance(pPosition);
  128|   183k|    const ai_real minDist = dist - pRadius, maxDist = dist + pRadius;
  129|       |
  130|       |    // clear the array
  131|   183k|    poResults.clear();
  132|       |
  133|       |    // quick check for positions outside the range
  134|   183k|    if (mPositions.size() == 0)
  ------------------
  |  Branch (134:9): [True: 0, False: 183k]
  ------------------
  135|      0|        return;
  136|   183k|    if (maxDist < mPositions.front().mDistance)
  ------------------
  |  Branch (136:9): [True: 0, False: 183k]
  ------------------
  137|      0|        return;
  138|   183k|    if (minDist > mPositions.back().mDistance)
  ------------------
  |  Branch (138:9): [True: 0, False: 183k]
  ------------------
  139|      0|        return;
  140|       |
  141|       |    // do a binary search for the minimal distance to start the iteration there
  142|   183k|    unsigned int index = (unsigned int)mPositions.size() / 2;
  143|   183k|    unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
  144|  2.01M|    while (binaryStepSize > 1) {
  ------------------
  |  Branch (144:12): [True: 1.83M, False: 183k]
  ------------------
  145|  1.83M|        if (mPositions[index].mDistance < minDist)
  ------------------
  |  Branch (145:13): [True: 925k, False: 907k]
  ------------------
  146|   925k|            index += binaryStepSize;
  147|   907k|        else
  148|   907k|            index -= binaryStepSize;
  149|       |
  150|  1.83M|        binaryStepSize /= 2;
  151|  1.83M|    }
  152|       |
  153|       |    // depending on the direction of the last step we need to single step a bit back or forth
  154|       |    // to find the actual beginning element of the range
  155|   360k|    while (index > 0 && mPositions[index].mDistance > minDist)
  ------------------
  |  Branch (155:12): [True: 360k, False: 203]
  |  Branch (155:25): [True: 177k, False: 183k]
  ------------------
  156|   177k|        index--;
  157|   378k|    while (index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist)
  ------------------
  |  Branch (157:12): [True: 378k, False: 0]
  |  Branch (157:47): [True: 195k, False: 183k]
  ------------------
  158|   195k|        index++;
  159|       |
  160|       |    // Mow start iterating from there until the first position lays outside of the distance range.
  161|       |    // Add all positions inside the distance range within the given radius to the result array
  162|   183k|    std::vector<Entry>::const_iterator it = mPositions.begin() + index;
  163|   183k|    const ai_real pSquared = pRadius * pRadius;
  164|  1.21M|    while (it->mDistance < maxDist) {
  ------------------
  |  Branch (164:12): [True: 1.02M, False: 183k]
  ------------------
  165|  1.02M|        if ((it->mPosition - pPosition).SquareLength() < pSquared)
  ------------------
  |  Branch (165:13): [True: 761k, False: 267k]
  ------------------
  166|   761k|            poResults.push_back(it->mIndex);
  167|  1.02M|        ++it;
  168|  1.02M|        if (it == mPositions.end())
  ------------------
  |  Branch (168:13): [True: 203, False: 1.02M]
  ------------------
  169|    203|            break;
  170|  1.02M|    }
  171|       |
  172|       |    // that's it
  173|   183k|}

_ZN6Assimp14StackAllocator8AllocateEm:
   54|  7.03M|inline void *StackAllocator::Allocate(size_t byteSize) {
   55|  7.03M|    if (m_subIndex + byteSize > m_blockAllocationSize) // start a new block
  ------------------
  |  Branch (55:9): [True: 1.40k, False: 7.03M]
  ------------------
   56|  1.40k|    {
   57|       |        // double block size every time, up to maximum of g_maxBytesPerBlock.
   58|       |        // Block size must be at least as large as byteSize, but we want to use this for small allocations anyway.
   59|  1.40k|        m_blockAllocationSize = std::max<std::size_t>(std::min<std::size_t>(m_blockAllocationSize * 2, g_maxBytesPerBlock), byteSize);
   60|  1.40k|        uint8_t *data = new uint8_t[m_blockAllocationSize];
   61|  1.40k|        m_storageBlocks.emplace_back(data);
   62|  1.40k|        m_subIndex = byteSize;
   63|  1.40k|        return data;
   64|  1.40k|    }
   65|       |
   66|  7.03M|    uint8_t *data = m_storageBlocks.back();
   67|  7.03M|    data += m_subIndex;
   68|  7.03M|    m_subIndex += byteSize;
   69|       |
   70|  7.03M|    return data;
   71|  7.03M|}
_ZN6Assimp14StackAllocator7FreeAllEv:
   73|    297|inline void StackAllocator::FreeAll() {
   74|  1.70k|    for (size_t i = 0; i < m_storageBlocks.size(); i++) {
  ------------------
  |  Branch (74:24): [True: 1.40k, False: 297]
  ------------------
   75|  1.40k|        delete [] m_storageBlocks[i];
   76|  1.40k|    }
   77|    297|    std::vector<uint8_t *> empty;
   78|    297|    m_storageBlocks.swap(empty);
   79|       |    // start over:
   80|    297|    m_blockAllocationSize = g_startBytesPerBlock;
   81|    297|    m_subIndex = g_maxBytesPerBlock;
   82|    297|}
_ZN6Assimp14StackAllocatorC2Ev:
   48|    297|inline StackAllocator::StackAllocator() : m_storageBlocks() {}
_ZN6Assimp14StackAllocatorD2Ev:
   50|    297|inline StackAllocator::~StackAllocator() {
   51|    297|    FreeAll();
   52|    297|}

aiGetVersionMinor:
   72|    297|ASSIMP_API unsigned int aiGetVersionMinor() {
   73|    297|    return VER_MINOR;
  ------------------
  |  |    8|    297|#define VER_MINOR 0
  ------------------
   74|    297|}
aiGetVersionMajor:
   78|    297|ASSIMP_API unsigned int aiGetVersionMajor() {
   79|    297|    return VER_MAJOR;
  ------------------
  |  |    7|    297|#define VER_MAJOR 6
  ------------------
   80|    297|}
aiGetCompileFlags:
   84|    297|ASSIMP_API unsigned int aiGetCompileFlags() {
   85|       |
   86|    297|    unsigned int flags = 0;
   87|       |
   88|       |#ifdef ASSIMP_BUILD_BOOST_WORKAROUND
   89|       |    flags |= ASSIMP_CFLAGS_NOBOOST;
   90|       |#endif
   91|    297|#ifdef ASSIMP_BUILD_SINGLETHREADED
   92|    297|    flags |= ASSIMP_CFLAGS_SINGLETHREADED;
  ------------------
  |  |  107|    297|#define ASSIMP_CFLAGS_SINGLETHREADED    0x10
  ------------------
   93|    297|#endif
   94|    297|#ifdef ASSIMP_BUILD_DEBUG
   95|    297|    flags |= ASSIMP_CFLAGS_DEBUG;
  ------------------
  |  |  102|    297|#define ASSIMP_CFLAGS_DEBUG   0x4
  ------------------
   96|    297|#endif
   97|       |#ifdef ASSIMP_BUILD_DLL_EXPORT
   98|       |    flags |= ASSIMP_CFLAGS_SHARED;
   99|       |#endif
  100|       |#ifdef _STLPORT_VERSION
  101|       |    flags |= ASSIMP_CFLAGS_STLPORT;
  102|       |#endif
  103|       |#ifdef ASSIMP_DOUBLE_PRECISION
  104|       |    flags |= ASSIMP_CFLAGS_DOUBLE_SUPPORT;
  105|       |#endif
  106|       |
  107|    297|    return flags;
  108|    297|}
aiGetVersionRevision:
  111|    297|ASSIMP_API unsigned int aiGetVersionRevision() {
  112|    297|    return GitVersion;
  ------------------
  |  |    4|    297|#define GitVersion 0x0404c875
  ------------------
  113|    297|}

_ZN6Assimp23VertexTriangleAdjacencyC2EP6aiFacejjb:
   55|     89|        bool bComputeNumTriangles /*= false*/) {
   56|       |    // compute the number of referenced vertices if it wasn't specified by the caller
   57|     89|    const aiFace *const pcFaceEnd = pcFaces + iNumFaces;
   58|     89|    if (0 == iNumVertices) {
  ------------------
  |  Branch (58:9): [True: 0, False: 89]
  ------------------
   59|      0|        for (aiFace *pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
  ------------------
  |  Branch (59:40): [True: 0, False: 0]
  ------------------
   60|      0|            ai_assert(nullptr != pcFace);
   61|      0|            ai_assert(3 == pcFace->mNumIndices);
   62|      0|            iNumVertices = std::max(iNumVertices, pcFace->mIndices[0]);
   63|      0|            iNumVertices = std::max(iNumVertices, pcFace->mIndices[1]);
   64|      0|            iNumVertices = std::max(iNumVertices, pcFace->mIndices[2]);
   65|      0|        }
   66|      0|    }
   67|       |
   68|     89|    mNumVertices = iNumVertices + 1;
   69|       |
   70|     89|    unsigned int *pi;
   71|       |
   72|       |    // allocate storage
   73|     89|    if (bComputeNumTriangles) {
  ------------------
  |  Branch (73:9): [True: 89, False: 0]
  ------------------
   74|     89|        pi = mLiveTriangles = new unsigned int[iNumVertices + 1];
   75|     89|        ::memset(mLiveTriangles, 0, sizeof(unsigned int) * (iNumVertices + 1));
   76|     89|        mOffsetTable = new unsigned int[iNumVertices + 2] + 1;
   77|     89|    } else {
   78|      0|        pi = mOffsetTable = new unsigned int[iNumVertices + 2] + 1;
   79|      0|        ::memset(mOffsetTable, 0, sizeof(unsigned int) * (iNumVertices + 1));
   80|      0|        mLiveTriangles = nullptr; // important, otherwise the d'tor would crash
   81|      0|    }
   82|       |
   83|       |    // get a pointer to the end of the buffer
   84|     89|    unsigned int *piEnd = pi + iNumVertices;
   85|     89|    *piEnd++ = 0u;
   86|       |
   87|       |    // first pass: compute the number of faces referencing each vertex
   88|   175k|    for (aiFace *pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
  ------------------
  |  Branch (88:36): [True: 175k, False: 89]
  ------------------
   89|   175k|        unsigned nind = pcFace->mNumIndices;
   90|   175k|        unsigned *ind = pcFace->mIndices;
   91|   175k|        if (nind > 0) pi[ind[0]]++;
  ------------------
  |  Branch (91:13): [True: 175k, False: 0]
  ------------------
   92|   175k|        if (nind > 1) pi[ind[1]]++;
  ------------------
  |  Branch (92:13): [True: 175k, False: 0]
  ------------------
   93|   175k|        if (nind > 2) pi[ind[2]]++;
  ------------------
  |  Branch (93:13): [True: 175k, False: 0]
  ------------------
   94|   175k|    }
   95|       |
   96|       |    // second pass: compute the final offset table
   97|     89|    unsigned int iSum = 0;
   98|     89|    unsigned int *piCurOut = this->mOffsetTable;
   99|   133k|    for (unsigned int *piCur = pi; piCur != piEnd; ++piCur, ++piCurOut) {
  ------------------
  |  Branch (99:36): [True: 132k, False: 89]
  ------------------
  100|       |
  101|   132k|        unsigned int iLastSum = iSum;
  102|   132k|        iSum += *piCur;
  103|   132k|        *piCurOut = iLastSum;
  104|   132k|    }
  105|     89|    pi = this->mOffsetTable;
  106|       |
  107|       |    // third pass: compute the final table
  108|     89|    this->mAdjacencyTable = new unsigned int[iSum];
  109|     89|    iSum = 0;
  110|   175k|    for (aiFace *pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace, ++iSum) {
  ------------------
  |  Branch (110:36): [True: 175k, False: 89]
  ------------------
  111|   175k|        unsigned nind = pcFace->mNumIndices;
  112|   175k|        unsigned *ind = pcFace->mIndices;
  113|       |
  114|   175k|        if (nind > 0) mAdjacencyTable[pi[ind[0]]++] = iSum;
  ------------------
  |  Branch (114:13): [True: 175k, False: 0]
  ------------------
  115|   175k|        if (nind > 1) mAdjacencyTable[pi[ind[1]]++] = iSum;
  ------------------
  |  Branch (115:13): [True: 175k, False: 0]
  ------------------
  116|   175k|        if (nind > 2) mAdjacencyTable[pi[ind[2]]++] = iSum;
  ------------------
  |  Branch (116:13): [True: 175k, False: 0]
  ------------------
  117|   175k|    }
  118|       |    // fourth pass: undo the offset computations made during the third pass
  119|       |    // We could do this in a separate buffer, but this would be TIMES slower.
  120|     89|    --mOffsetTable;
  121|     89|    *mOffsetTable = 0u;
  122|     89|}
_ZN6Assimp23VertexTriangleAdjacencyD2Ev:
  124|     89|VertexTriangleAdjacency::~VertexTriangleAdjacency() {
  125|       |    // delete allocated storage
  126|     89|    delete[] mOffsetTable;
  127|     89|    delete[] mAdjacencyTable;
  128|     89|    delete[] mLiveTriangles;
  129|     89|}

_ZNK6Assimp23VertexTriangleAdjacency20GetAdjacentTrianglesEj:
   85|  81.8k|    unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const {
   86|       |        ai_assert(iVertIndex < mNumVertices);
   87|  81.8k|        return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
   88|  81.8k|    }

aiTextureTypeToString:
   49|  1.56k|const char *aiTextureTypeToString(aiTextureType in) {
   50|  1.56k|    switch (in) {
   51|      0|    case aiTextureType_NONE:
  ------------------
  |  Branch (51:5): [True: 0, False: 1.56k]
  ------------------
   52|      0|        return "n/a";
   53|     92|    case aiTextureType_DIFFUSE:
  ------------------
  |  Branch (53:5): [True: 92, False: 1.47k]
  ------------------
   54|     92|        return "Diffuse";
   55|     92|    case aiTextureType_SPECULAR:
  ------------------
  |  Branch (55:5): [True: 92, False: 1.47k]
  ------------------
   56|     92|        return "Specular";
   57|     92|    case aiTextureType_AMBIENT:
  ------------------
  |  Branch (57:5): [True: 92, False: 1.47k]
  ------------------
   58|     92|        return "Ambient";
   59|     92|    case aiTextureType_EMISSIVE:
  ------------------
  |  Branch (59:5): [True: 92, False: 1.47k]
  ------------------
   60|     92|        return "Emissive";
   61|     92|    case aiTextureType_OPACITY:
  ------------------
  |  Branch (61:5): [True: 92, False: 1.47k]
  ------------------
   62|     92|        return "Opacity";
   63|     92|    case aiTextureType_NORMALS:
  ------------------
  |  Branch (63:5): [True: 92, False: 1.47k]
  ------------------
   64|     92|        return "Normals";
   65|     92|    case aiTextureType_HEIGHT:
  ------------------
  |  Branch (65:5): [True: 92, False: 1.47k]
  ------------------
   66|     92|        return "Height";
   67|     92|    case aiTextureType_SHININESS:
  ------------------
  |  Branch (67:5): [True: 92, False: 1.47k]
  ------------------
   68|     92|        return "Shininess";
   69|     92|    case aiTextureType_DISPLACEMENT:
  ------------------
  |  Branch (69:5): [True: 92, False: 1.47k]
  ------------------
   70|     92|        return "Displacement";
   71|     92|    case aiTextureType_LIGHTMAP:
  ------------------
  |  Branch (71:5): [True: 92, False: 1.47k]
  ------------------
   72|     92|        return "Lightmap";
   73|     92|    case aiTextureType_REFLECTION:
  ------------------
  |  Branch (73:5): [True: 92, False: 1.47k]
  ------------------
   74|     92|        return "Reflection";
   75|     92|    case aiTextureType_BASE_COLOR:
  ------------------
  |  Branch (75:5): [True: 92, False: 1.47k]
  ------------------
   76|     92|        return "BaseColor";
   77|     92|    case aiTextureType_NORMAL_CAMERA:
  ------------------
  |  Branch (77:5): [True: 92, False: 1.47k]
  ------------------
   78|     92|        return "NormalCamera";
   79|     92|    case aiTextureType_EMISSION_COLOR:
  ------------------
  |  Branch (79:5): [True: 92, False: 1.47k]
  ------------------
   80|     92|        return "EmissionColor";
   81|     92|    case aiTextureType_METALNESS:
  ------------------
  |  Branch (81:5): [True: 92, False: 1.47k]
  ------------------
   82|     92|        return "Metalness";
   83|     92|    case aiTextureType_DIFFUSE_ROUGHNESS:
  ------------------
  |  Branch (83:5): [True: 92, False: 1.47k]
  ------------------
   84|     92|        return "DiffuseRoughness";
   85|     92|    case aiTextureType_AMBIENT_OCCLUSION:
  ------------------
  |  Branch (85:5): [True: 92, False: 1.47k]
  ------------------
   86|     92|        return "AmbientOcclusion";
   87|      0|    case aiTextureType_SHEEN:
  ------------------
  |  Branch (87:5): [True: 0, False: 1.56k]
  ------------------
   88|      0|        return "Sheen";
   89|      0|    case aiTextureType_CLEARCOAT:
  ------------------
  |  Branch (89:5): [True: 0, False: 1.56k]
  ------------------
   90|      0|        return "Clearcoat";
   91|      0|    case aiTextureType_TRANSMISSION:
  ------------------
  |  Branch (91:5): [True: 0, False: 1.56k]
  ------------------
   92|      0|        return "Transmission";
   93|      0|    case aiTextureType_MAYA_BASE:
  ------------------
  |  Branch (93:5): [True: 0, False: 1.56k]
  ------------------
   94|      0|        return "MayaBase";
   95|      0|    case aiTextureType_MAYA_SPECULAR:
  ------------------
  |  Branch (95:5): [True: 0, False: 1.56k]
  ------------------
   96|      0|        return "MayaSpecular";
   97|      0|    case aiTextureType_MAYA_SPECULAR_COLOR:
  ------------------
  |  Branch (97:5): [True: 0, False: 1.56k]
  ------------------
   98|      0|        return "MayaSpecularColor";
   99|      0|    case aiTextureType_MAYA_SPECULAR_ROUGHNESS:
  ------------------
  |  Branch (99:5): [True: 0, False: 1.56k]
  ------------------
  100|      0|        return "MayaSpecularRoughness";
  101|      0|    case aiTextureType_ANISOTROPY:
  ------------------
  |  Branch (101:5): [True: 0, False: 1.56k]
  ------------------
  102|      0|        return "Anisotropy";
  103|      0|    case aiTextureType_GLTF_METALLIC_ROUGHNESS:
  ------------------
  |  Branch (103:5): [True: 0, False: 1.56k]
  ------------------
  104|      0|        return "glTFMetallicRoughness";
  105|      0|    case aiTextureType_UNKNOWN:
  ------------------
  |  Branch (105:5): [True: 0, False: 1.56k]
  ------------------
  106|      0|        return "Unknown";
  107|      0|    default:
  ------------------
  |  Branch (107:5): [True: 0, False: 1.56k]
  ------------------
  108|      0|        break;
  109|  1.56k|    }
  110|      0|    ai_assert(false);
  ------------------
  |  |   67|      0|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [Folded, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  111|      0|    return "BUG";
  112|  1.56k|}

_ZN7aiSceneC2Ev:
   46|    297|        mFlags(0),
   47|    297|        mRootNode(nullptr),
   48|    297|        mNumMeshes(0),
   49|    297|        mMeshes(nullptr),
   50|    297|        mNumMaterials(0),
   51|    297|        mMaterials(nullptr),
   52|    297|        mNumAnimations(0),
   53|    297|        mAnimations(nullptr),
   54|    297|        mNumTextures(0),
   55|    297|        mTextures(nullptr),
   56|    297|        mNumLights(0),
   57|    297|        mLights(nullptr),
   58|    297|        mNumCameras(0),
   59|    297|        mCameras(nullptr),
   60|    297|        mMetaData(nullptr),
   61|    297|        mName(),
   62|    297|        mNumSkeletons(0),
   63|    297|        mSkeletons(nullptr),
   64|    297|        mPrivate(new Assimp::ScenePrivateData()) {
   65|       |    // empty
   66|    297|}
_ZN7aiSceneD2Ev:
   68|    297|aiScene::~aiScene() {
   69|       |    // delete all sub-objects recursively
   70|    297|    delete mRootNode;
   71|       |
   72|       |    // To make sure we won't crash if the data is invalid it's
   73|       |    // much better to check whether both mNumXXX and mXXX are
   74|       |    // valid instead of relying on just one of them.
   75|    297|    if (mNumMeshes && mMeshes) {
  ------------------
  |  Branch (75:9): [True: 92, False: 205]
  |  Branch (75:23): [True: 92, False: 0]
  ------------------
   76|    190|        for (unsigned int a = 0; a < mNumMeshes; ++a) {
  ------------------
  |  Branch (76:34): [True: 98, False: 92]
  ------------------
   77|     98|            delete mMeshes[a];
   78|     98|        }
   79|     92|    }
   80|    297|    delete[] mMeshes;
   81|       |
   82|    297|    if (mNumMaterials && mMaterials) {
  ------------------
  |  Branch (82:9): [True: 92, False: 205]
  |  Branch (82:26): [True: 92, False: 0]
  ------------------
   83|    185|        for (unsigned int a = 0; a < mNumMaterials; ++a) {
  ------------------
  |  Branch (83:34): [True: 93, False: 92]
  ------------------
   84|     93|            delete mMaterials[a];
   85|     93|        }
   86|     92|    }
   87|    297|    delete[] mMaterials;
   88|       |
   89|    297|    if (mNumAnimations && mAnimations) {
  ------------------
  |  Branch (89:9): [True: 208, False: 89]
  |  Branch (89:27): [True: 208, False: 0]
  ------------------
   90|    416|        for (unsigned int a = 0; a < mNumAnimations; ++a) {
  ------------------
  |  Branch (90:34): [True: 208, False: 208]
  ------------------
   91|    208|            delete mAnimations[a];
   92|    208|        }
   93|    208|    }
   94|    297|    delete[] mAnimations;
   95|       |
   96|    297|    if (mNumTextures && mTextures) {
  ------------------
  |  Branch (96:9): [True: 1, False: 296]
  |  Branch (96:25): [True: 1, False: 0]
  ------------------
   97|      2|        for (unsigned int a = 0; a < mNumTextures; ++a) {
  ------------------
  |  Branch (97:34): [True: 1, False: 1]
  ------------------
   98|      1|            delete mTextures[a];
   99|      1|        }
  100|      1|    }
  101|    297|    delete[] mTextures;
  102|       |
  103|    297|    if (mNumLights && mLights) {
  ------------------
  |  Branch (103:9): [True: 198, False: 99]
  |  Branch (103:23): [True: 198, False: 0]
  ------------------
  104|    396|        for (unsigned int a = 0; a < mNumLights; ++a) {
  ------------------
  |  Branch (104:34): [True: 198, False: 198]
  ------------------
  105|    198|            delete mLights[a];
  106|    198|        }
  107|    198|    }
  108|    297|    delete[] mLights;
  109|       |
  110|    297|    if (mNumCameras && mCameras) {
  ------------------
  |  Branch (110:9): [True: 206, False: 91]
  |  Branch (110:24): [True: 206, False: 0]
  ------------------
  111|    412|        for (unsigned int a = 0; a < mNumCameras; ++a) {
  ------------------
  |  Branch (111:34): [True: 206, False: 206]
  ------------------
  112|    206|            delete mCameras[a];
  113|    206|        }
  114|    206|    }
  115|    297|    delete[] mCameras;
  116|       |
  117|    297|    aiMetadata::Dealloc(mMetaData);
  118|       |
  119|    297|    delete[] mSkeletons;
  120|       |
  121|    297|    delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
  122|    297|}
_ZN6aiNodeC2Ev:
  125|  5.02k|        mName(""),
  126|  5.02k|        mParent(nullptr),
  127|  5.02k|        mNumChildren(0),
  128|  5.02k|        mChildren(nullptr),
  129|  5.02k|        mNumMeshes(0),
  130|  5.02k|        mMeshes(nullptr),
  131|  5.02k|        mMetaData(nullptr) {
  132|       |    // empty
  133|  5.02k|}
_ZN6aiNodeC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  136|    356|        mName(name),
  137|    356|        mParent(nullptr),
  138|    356|        mNumChildren(0),
  139|    356|        mChildren(nullptr),
  140|    356|        mNumMeshes(0),
  141|    356|        mMeshes(nullptr),
  142|    356|        mMetaData(nullptr) {
  143|       |    // empty
  144|    356|}
_ZN6aiNodeD2Ev:
  147|  5.37k|aiNode::~aiNode() {
  148|       |    // delete all children recursively
  149|       |    // to make sure we won't crash if the data is invalid ...
  150|  5.37k|    if (mNumChildren && mChildren) {
  ------------------
  |  Branch (150:9): [True: 4.18k, False: 1.19k]
  |  Branch (150:25): [True: 4.18k, False: 0]
  ------------------
  151|  9.15k|        for (unsigned int a = 0; a < mNumChildren; a++)
  ------------------
  |  Branch (151:34): [True: 4.97k, False: 4.18k]
  ------------------
  152|  4.97k|            delete mChildren[a];
  153|  4.18k|    }
  154|  5.37k|    delete[] mChildren;
  155|  5.37k|    delete[] mMeshes;
  156|  5.37k|    delete mMetaData;
  157|  5.37k|}
_ZN6aiNode8FindNodeEPKc:
  176|  5.58k|aiNode *aiNode::FindNode(const char *name) {
  177|  5.58k|    if (!::strcmp(mName.data, name)) return this;
  ------------------
  |  Branch (177:9): [True: 86, False: 5.50k]
  ------------------
  178|  9.42k|    for (unsigned int i = 0; i < mNumChildren; ++i) {
  ------------------
  |  Branch (178:30): [True: 5.46k, False: 3.95k]
  ------------------
  179|  5.46k|        aiNode *const p = mChildren[i]->FindNode(name);
  180|  5.46k|        if (p) {
  ------------------
  |  Branch (180:13): [True: 1.54k, False: 3.92k]
  ------------------
  181|  1.54k|            return p;
  182|  1.54k|        }
  183|  5.46k|    }
  184|       |    // there is definitely no sub-node with this name
  185|  3.95k|    return nullptr;
  186|  5.50k|}

_ZN6Assimp13GeometryUtils5heronEfff:
   49|   544k|ai_real GeometryUtils::heron( ai_real a, ai_real b, ai_real c ) {
   50|   544k|    const ai_real s    = (a + b + c) * 0.5;
   51|   544k|    const ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), static_cast<ai_real>(0.5));
   52|   544k|    return area;
   53|   544k|}
_ZN6Assimp13GeometryUtils10distance3DERK10aiVector3tIfES4_:
   56|  1.63M|ai_real GeometryUtils::distance3D( const aiVector3D &vA, const aiVector3D &vB ) {
   57|  1.63M|    const ai_real lx = ( vB.x - vA.x );
   58|  1.63M|    const ai_real ly = ( vB.y - vA.y );
   59|  1.63M|    const ai_real lz = ( vB.z - vA.z );
   60|  1.63M|    const ai_real a  = lx*lx + ly*ly + lz*lz;
   61|  1.63M|    const ai_real d  = pow( a, static_cast<ai_real>(0.5));
   62|       |
   63|  1.63M|    return d;
   64|  1.63M|}
_ZN6Assimp13GeometryUtils23calculateAreaOfTriangleERK6aiFaceP6aiMesh:
   67|   544k|ai_real GeometryUtils::calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
   68|   544k|    ai_real area = 0;
   69|   544k|    if (mesh == nullptr) {
  ------------------
  |  Branch (69:9): [True: 0, False: 544k]
  ------------------
   70|      0|        return area;
   71|      0|    }
   72|       |
   73|   544k|    const aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
   74|   544k|    const aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
   75|   544k|    const aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
   76|       |
   77|   544k|    const ai_real a = distance3D( vA, vB );
   78|   544k|    const ai_real b = distance3D( vB, vC );
   79|   544k|    const ai_real c = distance3D( vC, vA );
   80|   544k|    area = heron( a, b, c );
   81|       |
   82|   544k|    return area;
   83|   544k|}

aiGetMaterialProperty:
   63|    438|        const aiMaterialProperty **pPropOut) {
   64|    438|    ai_assert(pMat != nullptr);
   65|    438|    ai_assert(pKey != nullptr);
   66|    438|    ai_assert(pPropOut != nullptr);
   67|       |
   68|       |    /*  Just search for a property with exactly this name ..
   69|       |     *  could be improved by hashing, but it's possibly
   70|       |     *  no worth the effort (we're bound to C structures,
   71|       |     *  thus std::map or derivates are not applicable. */
   72|  4.08k|    for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
  ------------------
  |  Branch (72:30): [True: 3.98k, False: 104]
  ------------------
   73|  3.98k|        aiMaterialProperty *prop = pMat->mProperties[i];
   74|       |
   75|  3.98k|        if (prop /* just for safety ... */
  ------------------
  |  Branch (75:13): [True: 3.98k, False: 0]
  ------------------
   76|  3.98k|                && 0 == strncmp(prop->mKey.data, pKey, strlen(pKey)) && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */
  ------------------
  |  Branch (76:20): [True: 334, False: 3.64k]
  |  Branch (76:74): [True: 0, False: 334]
  |  Branch (76:94): [True: 334, False: 0]
  ------------------
   77|    334|                && (UINT_MAX == index || prop->mIndex == index)) {
  ------------------
  |  Branch (77:21): [True: 0, False: 334]
  |  Branch (77:42): [True: 334, False: 0]
  ------------------
   78|    334|            *pPropOut = pMat->mProperties[i];
   79|    334|            return AI_SUCCESS;
   80|    334|        }
   81|  3.98k|    }
   82|    104|    *pPropOut = nullptr;
   83|       |
   84|       |    return AI_FAILURE;
   85|    438|}
aiGetMaterialFloatArray:
  194|    260|        unsigned int *pMax) {
  195|    260|    return GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
  196|    260|}
aiGetMaterialIntegerArray:
  205|    178|        unsigned int *pMax) {
  206|    178|    ai_assert(pOut != nullptr);
  207|    178|    ai_assert(pMat != nullptr);
  208|       |
  209|    178|    const aiMaterialProperty *prop;
  210|    178|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  211|    178|    if (!prop) {
  ------------------
  |  Branch (211:9): [True: 94, False: 84]
  ------------------
  212|     94|        return AI_FAILURE;
  213|     94|    }
  214|       |
  215|       |    // data is given in ints, simply copy it
  216|     84|    unsigned int iWrite = 0;
  217|     84|    if (aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) {
  ------------------
  |  Branch (217:9): [True: 0, False: 84]
  |  Branch (217:41): [True: 84, False: 0]
  ------------------
  218|     84|        iWrite = std::max(static_cast<unsigned int>(prop->mDataLength / sizeof(int32_t)), 1u);
  219|     84|        if (pMax) {
  ------------------
  |  Branch (219:13): [True: 0, False: 84]
  ------------------
  220|      0|            iWrite = std::min(*pMax, iWrite);
  221|      0|        }
  222|     84|        if (1 == prop->mDataLength) {
  ------------------
  |  Branch (222:13): [True: 0, False: 84]
  ------------------
  223|       |            // bool type, 1 byte
  224|      0|            *pOut = static_cast<int>(*prop->mData);
  225|     84|        } else {
  226|    168|            for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (226:38): [True: 84, False: 84]
  ------------------
  227|     84|                pOut[a] = static_cast<int>(reinterpret_cast<int32_t *>(prop->mData)[a]);
  228|     84|            }
  229|     84|        }
  230|     84|        if (pMax) {
  ------------------
  |  Branch (230:13): [True: 0, False: 84]
  ------------------
  231|      0|            *pMax = iWrite;
  232|      0|        }
  233|     84|    }
  234|       |    // data is given in floats convert to int
  235|      0|    else if (aiPTI_Float == prop->mType) {
  ------------------
  |  Branch (235:14): [True: 0, False: 0]
  ------------------
  236|      0|        iWrite = prop->mDataLength / sizeof(float);
  237|      0|        if (pMax) {
  ------------------
  |  Branch (237:13): [True: 0, False: 0]
  ------------------
  238|      0|            iWrite = std::min(*pMax, iWrite);
  239|      0|            ;
  240|      0|        }
  241|      0|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (241:34): [True: 0, False: 0]
  ------------------
  242|      0|            pOut[a] = static_cast<int>(reinterpret_cast<float *>(prop->mData)[a]);
  243|      0|        }
  244|      0|        if (pMax) {
  ------------------
  |  Branch (244:13): [True: 0, False: 0]
  ------------------
  245|      0|            *pMax = iWrite;
  246|      0|        }
  247|      0|    }
  248|       |    // it is a string ... no way to read something out of this
  249|      0|    else {
  250|      0|        if (pMax) {
  ------------------
  |  Branch (250:13): [True: 0, False: 0]
  ------------------
  251|      0|            iWrite = *pMax;
  252|      0|        }
  253|       |        // strings are zero-terminated with a 32 bit length prefix, so this is safe
  254|      0|        const char *cur = prop->mData + 4;
  255|      0|        ai_assert(prop->mDataLength >= 5);
  256|      0|        ai_assert(!prop->mData[prop->mDataLength - 1]);
  257|      0|        for (unsigned int a = 0;; ++a) {
  258|      0|            pOut[a] = strtol10(cur, &cur);
  259|      0|            if (a == iWrite - 1) {
  ------------------
  |  Branch (259:17): [True: 0, False: 0]
  ------------------
  260|      0|                break;
  261|      0|            }
  262|      0|            if (!IsSpace(*cur)) {
  ------------------
  |  Branch (262:17): [True: 0, False: 0]
  ------------------
  263|      0|                ASSIMP_LOG_ERROR("Material property", pKey,
  264|      0|                                 " is a string; failed to parse an integer array out of it.");
  265|      0|                return AI_FAILURE;
  266|      0|            }
  267|      0|        }
  268|       |
  269|      0|        if (pMax) {
  ------------------
  |  Branch (269:13): [True: 0, False: 0]
  ------------------
  270|      0|            *pMax = iWrite;
  271|      0|        }
  272|      0|    }
  273|     84|    return AI_SUCCESS;
  274|     84|}
_ZN10aiMaterialC2Ev:
  418|     93|aiMaterial::aiMaterial() : mProperties(nullptr), mNumProperties(0), mNumAllocated(DefaultNumAllocated) {
  419|       |    // Allocate 5 entries by default
  420|     93|    mProperties = new aiMaterialProperty *[DefaultNumAllocated];
  421|     93|}
_ZN10aiMaterialD2Ev:
  424|     93|aiMaterial::~aiMaterial() {
  425|     93|    Clear();
  426|       |
  427|     93|    delete[] mProperties;
  428|     93|}
_ZN10aiMaterial5ClearEv:
  439|     93|void aiMaterial::Clear() {
  440|  1.61k|    for (unsigned int i = 0; i < mNumProperties; ++i) {
  ------------------
  |  Branch (440:30): [True: 1.52k, False: 93]
  ------------------
  441|       |        // delete this entry
  442|  1.52k|        delete mProperties[i];
  443|  1.52k|        AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
  444|  1.52k|    }
  445|     93|    mNumProperties = 0;
  446|       |
  447|       |    // The array remains allocated, we just invalidated its contents
  448|     93|}
_ZN10aiMaterial17AddBinaryPropertyEPKvjPKcjj18aiPropertyTypeInfo:
  480|  1.52k|        aiPropertyTypeInfo pType) {
  481|  1.52k|    ai_assert(pInput != nullptr);
  482|  1.52k|    ai_assert(pKey != nullptr);
  483|  1.52k|    ai_assert(0 != pSizeInBytes);
  484|       |
  485|  1.52k|    if (0 == pSizeInBytes) {
  ------------------
  |  Branch (485:9): [True: 0, False: 1.52k]
  ------------------
  486|      0|        return AI_FAILURE;
  487|      0|    }
  488|       |
  489|       |    // first search the list whether there is already an entry with this key
  490|  1.52k|    unsigned int iOutIndex(UINT_MAX);
  491|  14.4k|    for (unsigned int i = 0; i < mNumProperties; ++i) {
  ------------------
  |  Branch (491:30): [True: 12.9k, False: 1.52k]
  ------------------
  492|  12.9k|        aiMaterialProperty *prop(mProperties[i]);
  493|       |
  494|  12.9k|        if (prop /* just for safety */ && !strcmp(prop->mKey.data, pKey) &&
  ------------------
  |  Branch (494:13): [True: 12.9k, False: 0]
  |  Branch (494:43): [True: 0, False: 12.9k]
  ------------------
  495|      0|                prop->mSemantic == type && prop->mIndex == index) {
  ------------------
  |  Branch (495:17): [True: 0, False: 0]
  |  Branch (495:44): [True: 0, False: 0]
  ------------------
  496|       |
  497|      0|            delete mProperties[i];
  498|      0|            iOutIndex = i;
  499|      0|        }
  500|  12.9k|    }
  501|       |
  502|       |    // Allocate a new material property
  503|  1.52k|    auto pcNew = std::make_unique<aiMaterialProperty>();
  504|       |
  505|       |    // .. and fill it
  506|  1.52k|    pcNew->mType = pType;
  507|  1.52k|    pcNew->mSemantic = type;
  508|  1.52k|    pcNew->mIndex = index;
  509|       |
  510|  1.52k|    pcNew->mDataLength = pSizeInBytes;
  511|  1.52k|    pcNew->mData = new char[pSizeInBytes];
  512|  1.52k|    memcpy(pcNew->mData, pInput, pSizeInBytes);
  513|       |
  514|  1.52k|    const size_t keyLen = ::strlen(pKey);
  515|  1.52k|    pcNew->mKey.length = static_cast<ai_uint32>(std::min<size_t>(keyLen, AI_MAXLEN - 1));
  516|  1.52k|    if (keyLen >= AI_MAXLEN) {
  ------------------
  |  Branch (516:9): [True: 0, False: 1.52k]
  ------------------
  517|      0|        ASSIMP_LOG_WARN("aiMaterial: property key '", pKey, "' exceeds AI_MAXLEN and will be truncated.");
  518|      0|    }
  519|  1.52k|	memcpy(pcNew->mKey.data, pKey, pcNew->mKey.length);
  520|  1.52k|    pcNew->mKey.data[pcNew->mKey.length] = '\0';
  521|       |
  522|  1.52k|    if (UINT_MAX != iOutIndex) {
  ------------------
  |  Branch (522:9): [True: 0, False: 1.52k]
  ------------------
  523|      0|        mProperties[iOutIndex] = pcNew.release();
  524|      0|        return AI_SUCCESS;
  525|      0|    }
  526|       |
  527|       |    // resize the array ... double the storage allocated
  528|  1.52k|    if (mNumProperties == mNumAllocated) {
  ------------------
  |  Branch (528:9): [True: 179, False: 1.34k]
  ------------------
  529|    179|        const unsigned int iOld = mNumAllocated;
  530|    179|        mNumAllocated *= 2;
  531|       |
  532|    179|        aiMaterialProperty **ppTemp;
  533|    179|        try {
  534|    179|            ppTemp = new aiMaterialProperty *[mNumAllocated];
  535|    179|        } catch (std::bad_alloc &) {
  536|      0|            return AI_OUTOFMEMORY;
  537|      0|        }
  538|       |
  539|       |        // just copy all items over; then replace the old array
  540|    179|        memcpy(ppTemp, mProperties, iOld * sizeof(void *));
  541|       |
  542|    179|        delete[] mProperties;
  543|    179|        mProperties = ppTemp;
  544|    179|    }
  545|       |    // push back ...
  546|  1.52k|    mProperties[mNumProperties++] = pcNew.release();
  547|       |
  548|       |    return AI_SUCCESS;
  549|  1.52k|}
_ZN10aiMaterial11AddPropertyEPK8aiStringPKcjj:
  555|    107|        unsigned int index) {
  556|       |    ai_assert(sizeof(ai_uint32) == 4);
  557|    107|    return AddBinaryProperty(pInput,
  558|    107|            static_cast<unsigned int>(pInput->length + 1 + 4),
  559|    107|            pKey,
  560|    107|            type,
  561|    107|            index,
  562|    107|            aiPTI_String);
  563|    107|}
_ZN6Assimp19ComputeMaterialHashEPK10aiMaterialb:
  566|     92|uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName /*= false*/) {
  567|     92|    uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
  568|  1.59k|    for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
  ------------------
  |  Branch (568:30): [True: 1.50k, False: 92]
  ------------------
  569|       |        // Exclude all properties whose first character is '?' from the hash
  570|       |        // See doc for aiMaterialProperty.
  571|  1.50k|        const aiMaterialProperty *prop = mat->mProperties[i];
  572|  1.50k|        if (nullptr != prop && (includeMatName || prop->mKey.data[0] != '?')) {
  ------------------
  |  Branch (572:13): [True: 1.50k, False: 0]
  |  Branch (572:33): [True: 0, False: 1.50k]
  |  Branch (572:51): [True: 1.41k, False: 92]
  ------------------
  573|       |
  574|  1.41k|            hash = SuperFastHash(prop->mKey.data, (unsigned int)prop->mKey.length, hash);
  575|  1.41k|            hash = SuperFastHash(prop->mData, prop->mDataLength, hash);
  576|       |
  577|       |            // Combine the semantic and the index with the hash
  578|  1.41k|            hash = SuperFastHash((const char *)&prop->mSemantic, sizeof(unsigned int), hash);
  579|  1.41k|            hash = SuperFastHash((const char *)&prop->mIndex, sizeof(unsigned int), hash);
  580|  1.41k|        }
  581|  1.50k|    }
  582|     92|    return hash;
  583|     92|}
MaterialSystem.cpp:_ZN12_GLOBAL__N_121GetMaterialFloatArrayIfEE8aiReturnPK10aiMaterialPKcjjPT_Pj:
   97|    260|        unsigned int *pMax) {
   98|    260|    ai_assert(pOut != nullptr);
   99|    260|    ai_assert(pMat != nullptr);
  100|       |
  101|    260|    const aiMaterialProperty *prop{nullptr};
  102|    260|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  103|    260|    if (nullptr == prop) {
  ------------------
  |  Branch (103:9): [True: 10, False: 250]
  ------------------
  104|     10|        return AI_FAILURE;
  105|     10|    }
  106|       |
  107|       |    // data is given in floats, convert to TReal
  108|    250|    unsigned int iWrite = 0;
  109|    250|    if (aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) {
  ------------------
  |  Branch (109:9): [True: 250, False: 0]
  |  Branch (109:39): [True: 0, False: 0]
  ------------------
  110|    250|        iWrite = prop->mDataLength / sizeof(float);
  111|    250|        if (pMax) {
  ------------------
  |  Branch (111:13): [True: 0, False: 250]
  ------------------
  112|      0|            iWrite = std::min(*pMax, iWrite);
  113|      0|        }
  114|       |
  115|    500|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (115:34): [True: 250, False: 250]
  ------------------
  116|    250|            pOut[a] = static_cast<TReal>(reinterpret_cast<float *>(prop->mData)[a]);
  117|    250|        }
  118|       |
  119|    250|        if (pMax) {
  ------------------
  |  Branch (119:13): [True: 0, False: 250]
  ------------------
  120|      0|            *pMax = iWrite;
  121|      0|        }
  122|    250|    } else if (aiPTI_Double == prop->mType) { // data is given in doubles, convert to TReal
  ------------------
  |  Branch (122:16): [True: 0, False: 0]
  ------------------
  123|      0|        iWrite = prop->mDataLength / sizeof(double);
  124|      0|        if (pMax) {
  ------------------
  |  Branch (124:13): [True: 0, False: 0]
  ------------------
  125|      0|            iWrite = std::min(*pMax, iWrite);
  126|      0|            ;
  127|      0|        }
  128|      0|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (128:34): [True: 0, False: 0]
  ------------------
  129|      0|            pOut[a] = static_cast<TReal>(reinterpret_cast<double *>(prop->mData)[a]);
  130|      0|        }
  131|      0|        if (pMax) {
  ------------------
  |  Branch (131:13): [True: 0, False: 0]
  ------------------
  132|      0|            *pMax = iWrite;
  133|      0|        }
  134|      0|    } else if (aiPTI_Integer == prop->mType) { // data is given in ints, convert to TReal
  ------------------
  |  Branch (134:16): [True: 0, False: 0]
  ------------------
  135|      0|        iWrite = prop->mDataLength / sizeof(int32_t);
  136|      0|        if (pMax) {
  ------------------
  |  Branch (136:13): [True: 0, False: 0]
  ------------------
  137|      0|            iWrite = std::min(*pMax, iWrite);
  138|      0|            ;
  139|      0|        }
  140|      0|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (140:34): [True: 0, False: 0]
  ------------------
  141|      0|            pOut[a] = static_cast<TReal>(reinterpret_cast<int32_t *>(prop->mData)[a]);
  142|      0|        }
  143|      0|        if (pMax) {
  ------------------
  |  Branch (143:13): [True: 0, False: 0]
  ------------------
  144|      0|            *pMax = iWrite;
  145|      0|        }
  146|      0|    } else { // a string ... read floats separated by spaces
  147|      0|        if (pMax) {
  ------------------
  |  Branch (147:13): [True: 0, False: 0]
  ------------------
  148|      0|            iWrite = *pMax;
  149|      0|        }
  150|       |        // strings are zero-terminated with a 32 bit length prefix, so this is safe
  151|      0|        const char *cur = prop->mData + 4;
  152|      0|        ai_assert(prop->mDataLength >= 5);
  153|      0|        ai_assert(!prop->mData[prop->mDataLength - 1]);
  154|      0|        for (unsigned int a = 0;; ++a) {
  155|      0|            cur = fast_atoreal_move(cur, pOut[a]);
  156|      0|            if (a == iWrite - 1) {
  ------------------
  |  Branch (156:17): [True: 0, False: 0]
  ------------------
  157|      0|                break;
  158|      0|            }
  159|      0|            if (!IsSpace(*cur)) {
  ------------------
  |  Branch (159:17): [True: 0, False: 0]
  ------------------
  160|      0|                ASSIMP_LOG_ERROR("Material property", pKey,
  161|      0|                                 " is a string; failed to parse a float array out of it.");
  162|      0|                return AI_FAILURE;
  163|      0|            }
  164|      0|        }
  165|       |
  166|      0|        if (pMax) {
  ------------------
  |  Branch (166:13): [True: 0, False: 0]
  ------------------
  167|      0|            *pMax = iWrite;
  168|      0|        }
  169|      0|    }
  170|       |
  171|    250|    return AI_SUCCESS;
  172|    250|}

_ZNK6Assimp16ArmaturePopulate8IsActiveEj:
   59|    218|bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
   60|    218|    return (pFlags & aiProcess_PopulateArmatureData) != 0;
   61|    218|}

_ZN6Assimp16ArmaturePopulateC2Ev:
   71|    297|    ArmaturePopulate() = default;

_ZN6Assimp19CalcTangentsProcessC2Ev:
   59|    297|        configMaxAngle(float(AI_DEG_TO_RAD(45.f))), configSourceUV(0) {
   60|       |    // nothing to do here
   61|    297|}
_ZNK6Assimp19CalcTangentsProcess8IsActiveEj:
   65|    218|bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
   66|    218|    return (pFlags & aiProcess_CalcTangentSpace) != 0;
   67|    218|}
_ZN6Assimp19CalcTangentsProcess15SetupPropertiesEPKNS_8ImporterE:
   71|    218|void CalcTangentsProcess::SetupProperties(const Importer *pImp) {
   72|    218|    ai_assert(nullptr != pImp);
   73|       |
   74|       |    // get the current value of the property
   75|    218|    configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 45.f);
   76|    218|    configMaxAngle = std::max(std::min(configMaxAngle, 45.0f), 0.0f);
   77|    218|    configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
   78|       |
   79|       |    configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX, 0);
   80|    218|}
_ZN6Assimp19CalcTangentsProcess7ExecuteEP7aiScene:
   84|    218|void CalcTangentsProcess::Execute(aiScene *pScene) {
   85|    218|    ai_assert(nullptr != pScene);
   86|       |
   87|    218|    ASSIMP_LOG_DEBUG("CalcTangentsProcess begin");
   88|       |
   89|    218|    bool bHas = false;
   90|    315|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (90:30): [True: 97, False: 218]
  ------------------
   91|     97|        if (ProcessMesh(pScene->mMeshes[a], a)) bHas = true;
  ------------------
  |  Branch (91:13): [True: 73, False: 24]
  ------------------
   92|     97|    }
   93|       |
   94|    218|    if (bHas) {
  ------------------
  |  Branch (94:9): [True: 72, False: 146]
  ------------------
   95|     72|        ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated");
   96|    146|    } else {
   97|       |        ASSIMP_LOG_DEBUG("CalcTangentsProcess finished");
   98|    146|    }
   99|    218|}
_ZN6Assimp19CalcTangentsProcess11ProcessMeshEP6aiMeshj:
  103|     97|bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
  104|       |    // we assume that the mesh is still in the verbose vertex format where each face has its own set
  105|       |    // of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
  106|       |    // assert() it here.
  107|       |    // assert( must be verbose, dammit);
  108|       |
  109|     97|    if (pMesh->mTangents) // this implies that mBitangents is also there
  ------------------
  |  Branch (109:9): [True: 4, False: 93]
  ------------------
  110|      4|        return false;
  111|       |
  112|       |    // If the mesh consists of lines and/or points but not of
  113|       |    // triangles or higher-order polygons the normal vectors
  114|       |    // are undefined.
  115|     93|    if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
  ------------------
  |  Branch (115:9): [True: 4, False: 89]
  ------------------
  116|      4|        ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes");
  117|      4|        return false;
  118|      4|    }
  119|       |
  120|       |    // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
  121|     89|    if (pMesh->mNormals == nullptr) {
  ------------------
  |  Branch (121:9): [True: 0, False: 89]
  ------------------
  122|      0|        ASSIMP_LOG_ERROR("Failed to compute tangents; need normals");
  123|      0|        return false;
  124|      0|    }
  125|     89|    if (configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV]) {
  ------------------
  |  Branch (125:9): [True: 0, False: 89]
  |  Branch (125:61): [True: 16, False: 73]
  ------------------
  126|     16|        ASSIMP_LOG_ERROR("Failed to compute tangents; need UV data in channel", configSourceUV);
  127|     16|        return false;
  128|     16|    }
  129|       |
  130|     73|    const float angleEpsilon = 0.9999f;
  131|       |
  132|     73|    std::vector<bool> vertexDone(pMesh->mNumVertices, false);
  133|     73|    const float qnan = get_qnan();
  134|       |
  135|       |    // create space for the tangents and bitangents
  136|     73|    pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  137|     73|    pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  138|       |
  139|     73|    const aiVector3D *meshPos = pMesh->mVertices;
  140|     73|    const aiVector3D *meshNorm = pMesh->mNormals;
  141|     73|    const aiVector3D *meshTex = pMesh->mTextureCoords[configSourceUV];
  142|     73|    aiVector3D *meshTang = pMesh->mTangents;
  143|     73|    aiVector3D *meshBitang = pMesh->mBitangents;
  144|       |
  145|       |    // calculate the tangent and bitangent for every face
  146|   150k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (146:30): [True: 150k, False: 73]
  ------------------
  147|   150k|        const aiFace &face = pMesh->mFaces[a];
  148|   150k|        if (face.mNumIndices < 3) {
  ------------------
  |  Branch (148:13): [True: 0, False: 150k]
  ------------------
  149|       |            // There are less than three indices, thus the tangent vector
  150|       |            // is not defined. We are finished with these vertices now,
  151|       |            // their tangent vectors are set to qnan.
  152|      0|            for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (152:38): [True: 0, False: 0]
  ------------------
  153|      0|                unsigned int idx = face.mIndices[i];
  154|      0|                vertexDone[idx] = true;
  155|      0|                meshTang[idx] = aiVector3D(qnan);
  156|      0|                meshBitang[idx] = aiVector3D(qnan);
  157|      0|            }
  158|       |
  159|      0|            continue;
  160|      0|        }
  161|       |
  162|       |        // triangle or polygon... we always use only the first three indices. A polygon
  163|       |        // is supposed to be planar anyways....
  164|       |        // FIXME: (thom) create correct calculation for multi-vertex polygons maybe?
  165|   150k|        const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2];
  166|       |
  167|       |        // position differences p1->p2 and p1->p3
  168|   150k|        aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
  169|       |
  170|       |        // texture offset p1->p2 and p1->p3
  171|   150k|        float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
  172|   150k|        float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
  173|   150k|        float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
  ------------------
  |  Branch (173:31): [True: 150k, False: 255]
  ------------------
  174|       |        // when t1, t2, t3 in same position in UV space, just use default UV direction.
  175|   150k|        if (sx * ty == sy * tx) {
  ------------------
  |  Branch (175:13): [True: 175, False: 150k]
  ------------------
  176|    175|            sx = 0.0;
  177|    175|            sy = 1.0;
  178|    175|            tx = 1.0;
  179|    175|            ty = 0.0;
  180|    175|        }
  181|       |
  182|       |        // tangent points in the direction where to positive X axis of the texture coord's would point in model space
  183|       |        // bitangent's points along the positive Y axis of the texture coord's, respectively
  184|   150k|        aiVector3D tangent, bitangent;
  185|   150k|        tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
  186|   150k|        tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
  187|   150k|        tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
  188|   150k|        bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
  189|   150k|        bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
  190|   150k|        bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
  191|       |
  192|       |        // store for every vertex of that face
  193|   601k|        for (unsigned int b = 0; b < face.mNumIndices; ++b) {
  ------------------
  |  Branch (193:34): [True: 450k, False: 150k]
  ------------------
  194|   450k|            unsigned int p = face.mIndices[b];
  195|       |
  196|       |            // project tangent and bitangent into the plane formed by the vertex' normal
  197|   450k|            aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
  198|   450k|            aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
  199|   450k|            localTangent.NormalizeSafe();
  200|   450k|            localBitangent.NormalizeSafe();
  201|       |
  202|       |            // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
  203|   450k|            bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z)
  ------------------
  |  Branch (203:36): [True: 0, False: 450k]
  |  Branch (203:72): [True: 0, False: 450k]
  |  Branch (203:108): [True: 0, False: 450k]
  ------------------
  204|   450k|                || (-0.5f < localTangent.x && localTangent.x < 0.5f && -0.5f < localTangent.y && localTangent.y < 0.5f && -0.5f < localTangent.z && localTangent.z < 0.5f);
  ------------------
  |  Branch (204:21): [True: 336k, False: 114k]
  |  Branch (204:47): [True: 221k, False: 114k]
  |  Branch (204:72): [True: 188k, False: 33.3k]
  |  Branch (204:98): [True: 154k, False: 33.9k]
  |  Branch (204:123): [True: 154k, False: 59]
  |  Branch (204:149): [True: 0, False: 154k]
  ------------------
  205|   450k|            bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z)
  ------------------
  |  Branch (205:38): [True: 0, False: 450k]
  |  Branch (205:76): [True: 0, False: 450k]
  |  Branch (205:114): [True: 0, False: 450k]
  ------------------
  206|   450k|                || (-0.5f < localBitangent.x && localBitangent.x < 0.5f && -0.5f < localBitangent.y && localBitangent.y < 0.5f && -0.5f < localBitangent.z && localBitangent.z < 0.5f);
  ------------------
  |  Branch (206:21): [True: 336k, False: 114k]
  |  Branch (206:49): [True: 221k, False: 114k]
  |  Branch (206:76): [True: 217k, False: 3.55k]
  |  Branch (206:104): [True: 139, False: 217k]
  |  Branch (206:131): [True: 76, False: 63]
  |  Branch (206:159): [True: 0, False: 76]
  ------------------
  207|   450k|            if (invalid_tangent != invalid_bitangent) {
  ------------------
  |  Branch (207:17): [True: 0, False: 450k]
  ------------------
  208|      0|                if (invalid_tangent) {
  ------------------
  |  Branch (208:21): [True: 0, False: 0]
  ------------------
  209|      0|                    localTangent = meshNorm[p] ^ localBitangent;
  210|      0|                    localTangent.NormalizeSafe();
  211|      0|                } else {
  212|      0|                    localBitangent = localTangent ^ meshNorm[p];
  213|      0|                    localBitangent.NormalizeSafe();
  214|      0|                }
  215|      0|            }
  216|       |
  217|       |            // and write it into the mesh.
  218|   450k|            meshTang[p] = localTangent;
  219|   450k|            meshBitang[p] = localBitangent;
  220|   450k|        }
  221|   150k|    }
  222|       |
  223|       |    // create a helper to quickly find locally close vertices among the vertex array
  224|       |    // FIX: check whether we can reuse the SpatialSort of a previous step
  225|     73|    SpatialSort *vertexFinder = nullptr;
  226|     73|    SpatialSort _vertexFinder;
  227|     73|    float posEpsilon = 10e-6f;
  228|     73|    if (shared) {
  ------------------
  |  Branch (228:9): [True: 73, False: 0]
  ------------------
  229|     73|        std::vector<std::pair<SpatialSort, float>> *avf;
  230|     73|        shared->GetProperty(AI_SPP_SPATIAL_SORT, avf);
  ------------------
  |  |  166|     73|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  231|     73|        if (avf) {
  ------------------
  |  Branch (231:13): [True: 73, False: 0]
  ------------------
  232|     73|            std::pair<SpatialSort, float> &blubb = avf->operator[](meshIndex);
  233|     73|            vertexFinder = &blubb.first;
  234|     73|            posEpsilon = blubb.second;
  235|     73|            ;
  236|     73|        }
  237|     73|    }
  238|     73|    if (!vertexFinder) {
  ------------------
  |  Branch (238:9): [True: 0, False: 73]
  ------------------
  239|      0|        _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof(aiVector3D));
  240|      0|        vertexFinder = &_vertexFinder;
  241|      0|        posEpsilon = ComputePositionEpsilon(pMesh);
  242|      0|    }
  243|     73|    std::vector<unsigned int> verticesFound;
  244|       |
  245|     73|    const float fLimit = std::cos(configMaxAngle);
  246|     73|    std::vector<unsigned int> closeVertices;
  247|       |
  248|       |    // in the second pass we now smooth out all tangents and bitangents at the same local position
  249|       |    // if they are not too far off.
  250|   301k|    for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
  ------------------
  |  Branch (250:30): [True: 301k, False: 73]
  ------------------
  251|   301k|        if (vertexDone[a])
  ------------------
  |  Branch (251:13): [True: 184k, False: 116k]
  ------------------
  252|   184k|            continue;
  253|       |
  254|   116k|        const aiVector3D &origPos = pMesh->mVertices[a];
  255|   116k|        const aiVector3D &origNorm = pMesh->mNormals[a];
  256|   116k|        const aiVector3D &origTang = pMesh->mTangents[a];
  257|   116k|        const aiVector3D &origBitang = pMesh->mBitangents[a];
  258|   116k|        closeVertices.resize(0);
  259|       |
  260|       |        // find all vertices close to that position
  261|   116k|        vertexFinder->FindPositions(origPos, posEpsilon, verticesFound);
  262|       |
  263|   116k|        closeVertices.reserve(verticesFound.size() + 5);
  264|   116k|        closeVertices.push_back(a);
  265|       |
  266|       |        // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
  267|   594k|        for (unsigned int b = 0; b < verticesFound.size(); b++) {
  ------------------
  |  Branch (267:34): [True: 477k, False: 116k]
  ------------------
  268|   477k|            unsigned int idx = verticesFound[b];
  269|   477k|            if (vertexDone[idx])
  ------------------
  |  Branch (269:17): [True: 90.5k, False: 387k]
  ------------------
  270|  90.5k|                continue;
  271|   387k|            if (meshNorm[idx] * origNorm < angleEpsilon)
  ------------------
  |  Branch (271:17): [True: 50.8k, False: 336k]
  ------------------
  272|  50.8k|                continue;
  273|   336k|            if (meshTang[idx] * origTang < fLimit)
  ------------------
  |  Branch (273:17): [True: 33.2k, False: 303k]
  ------------------
  274|  33.2k|                continue;
  275|   303k|            if (meshBitang[idx] * origBitang < fLimit)
  ------------------
  |  Branch (275:17): [True: 2.07k, False: 301k]
  ------------------
  276|  2.07k|                continue;
  277|       |
  278|       |            // it's similar enough -> add it to the smoothing group
  279|   301k|            closeVertices.push_back(idx);
  280|   301k|            vertexDone[idx] = true;
  281|   301k|        }
  282|       |
  283|       |        // smooth the tangents and bitangents of all vertices that were found to be close enough
  284|   116k|        aiVector3D smoothTangent(0, 0, 0), smoothBitangent(0, 0, 0);
  285|   534k|        for (unsigned int b = 0; b < closeVertices.size(); ++b) {
  ------------------
  |  Branch (285:34): [True: 417k, False: 116k]
  ------------------
  286|   417k|            smoothTangent += meshTang[closeVertices[b]];
  287|   417k|            smoothBitangent += meshBitang[closeVertices[b]];
  288|   417k|        }
  289|   116k|        smoothTangent.Normalize();
  290|   116k|        smoothBitangent.Normalize();
  291|       |
  292|       |        // and write it back into all affected tangents
  293|   534k|        for (unsigned int b = 0; b < closeVertices.size(); ++b) {
  ------------------
  |  Branch (293:34): [True: 417k, False: 116k]
  ------------------
  294|   417k|            meshTang[closeVertices[b]] = smoothTangent;
  295|   417k|            meshBitang[closeVertices[b]] = smoothBitangent;
  296|   417k|        }
  297|   116k|    }
  298|     73|    return true;
  299|     89|}

_ZNK6Assimp23ComputeUVMappingProcess8IsActiveEj:
   61|    218|bool ComputeUVMappingProcess::IsActive(unsigned int pFlags) const {
   62|    218|    return (pFlags & aiProcess_GenUVCoords) != 0;
   63|    218|}
_ZN6Assimp23ComputeUVMappingProcess7ExecuteEP7aiScene:
  345|    218|void ComputeUVMappingProcess::Execute(aiScene *pScene) {
  346|    218|    ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
  347|    218|    char buffer[1024];
  348|       |
  349|    218|    if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
  ------------------
  |  Branch (349:9): [True: 0, False: 218]
  ------------------
  350|      0|        throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
  351|      0|    }
  352|       |
  353|    218|    std::list<MappingInfo> mappingStack;
  354|       |
  355|       |    // Iterate through all materials and search for non-UV mapped textures
  356|    310|    for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (356:30): [True: 92, False: 218]
  ------------------
  357|     92|        mappingStack.clear();
  358|     92|        aiMaterial *mat = pScene->mMaterials[i];
  359|     92|        if (mat == nullptr) {
  ------------------
  |  Branch (359:13): [True: 0, False: 92]
  ------------------
  360|      0|            ASSIMP_LOG_INFO("Material pointer in nullptr, skipping.");
  361|      0|            continue;
  362|      0|        }
  363|  1.59k|        for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
  ------------------
  |  Branch (363:34): [True: 1.50k, False: 92]
  ------------------
  364|  1.50k|            aiMaterialProperty *prop = mat->mProperties[a];
  365|  1.50k|            if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
  ------------------
  |  Branch (365:17): [True: 0, False: 1.50k]
  ------------------
  366|      0|                aiTextureMapping &mapping = *((aiTextureMapping *)prop->mData);
  367|      0|                if (aiTextureMapping_UV != mapping) {
  ------------------
  |  Branch (367:21): [True: 0, False: 0]
  ------------------
  368|      0|                    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (368:25): [True: 0, False: 0]
  ------------------
  369|      0|                        ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
  370|      0|                                aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex,
  371|      0|                                MappingTypeToString(mapping));
  372|       |
  373|      0|                        ASSIMP_LOG_INFO(buffer);
  374|      0|                    }
  375|       |
  376|      0|                    if (aiTextureMapping_OTHER == mapping)
  ------------------
  |  Branch (376:25): [True: 0, False: 0]
  ------------------
  377|      0|                        continue;
  378|       |
  379|      0|                    MappingInfo info(mapping);
  380|       |
  381|       |                    // Get further properties - currently only the major axis
  382|      0|                    for (unsigned int a2 = 0; a2 < mat->mNumProperties; ++a2) {
  ------------------
  |  Branch (382:47): [True: 0, False: 0]
  ------------------
  383|      0|                        aiMaterialProperty *prop2 = mat->mProperties[a2];
  384|      0|                        if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
  ------------------
  |  Branch (384:29): [True: 0, False: 0]
  |  Branch (384:68): [True: 0, False: 0]
  ------------------
  385|      0|                            continue;
  386|       |
  387|      0|                        if (!::strcmp(prop2->mKey.data, "$tex.mapaxis")) {
  ------------------
  |  Branch (387:29): [True: 0, False: 0]
  ------------------
  388|      0|                            info.axis = *((aiVector3D *)prop2->mData);
  389|      0|                            break;
  390|      0|                        }
  391|      0|                    }
  392|       |
  393|      0|                    unsigned int idx(99999999);
  394|       |
  395|       |                    // Check whether we have this mapping mode already
  396|      0|                    std::list<MappingInfo>::iterator it = std::find(mappingStack.begin(), mappingStack.end(), info);
  397|      0|                    if (mappingStack.end() != it) {
  ------------------
  |  Branch (397:25): [True: 0, False: 0]
  ------------------
  398|      0|                        idx = (*it).uv;
  399|      0|                    } else {
  400|       |                        /*  We have found a non-UV mapped texture. Now
  401|       |                         *   we need to find all meshes using this material
  402|       |                         *   that we can compute UV channels for them.
  403|       |                         */
  404|      0|                        for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
  ------------------
  |  Branch (404:50): [True: 0, False: 0]
  ------------------
  405|      0|                            aiMesh *mesh = pScene->mMeshes[m];
  406|      0|                            unsigned int outIdx = 0;
  407|      0|                            if (mesh->mMaterialIndex != i || (outIdx = FindEmptyUVChannel(mesh)) == UINT_MAX ||
  ------------------
  |  Branch (407:33): [True: 0, False: 0]
  |  Branch (407:62): [True: 0, False: 0]
  ------------------
  408|      0|                                    !mesh->mNumVertices) {
  ------------------
  |  Branch (408:37): [True: 0, False: 0]
  ------------------
  409|      0|                                continue;
  410|      0|                            }
  411|       |
  412|       |                            // Allocate output storage
  413|      0|                            aiVector3D *p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
  414|       |
  415|      0|                            switch (mapping) {
  416|      0|                            case aiTextureMapping_SPHERE:
  ------------------
  |  Branch (416:29): [True: 0, False: 0]
  ------------------
  417|      0|                                ComputeSphereMapping(mesh, info.axis, p);
  418|      0|                                break;
  419|      0|                            case aiTextureMapping_CYLINDER:
  ------------------
  |  Branch (419:29): [True: 0, False: 0]
  ------------------
  420|      0|                                ComputeCylinderMapping(mesh, info.axis, p);
  421|      0|                                break;
  422|      0|                            case aiTextureMapping_PLANE:
  ------------------
  |  Branch (422:29): [True: 0, False: 0]
  ------------------
  423|      0|                                ComputePlaneMapping(mesh, info.axis, p);
  424|      0|                                break;
  425|      0|                            case aiTextureMapping_BOX:
  ------------------
  |  Branch (425:29): [True: 0, False: 0]
  ------------------
  426|      0|                                ComputeBoxMapping(mesh, p);
  427|      0|                                break;
  428|      0|                            default:
  ------------------
  |  Branch (428:29): [True: 0, False: 0]
  ------------------
  429|      0|                                ai_assert(false);
  430|      0|                            }
  431|      0|                            if (m && idx != outIdx) {
  ------------------
  |  Branch (431:33): [True: 0, False: 0]
  |  Branch (431:38): [True: 0, False: 0]
  ------------------
  432|      0|                                ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
  433|      0|                                                "this material have equal numbers of UV channels. The UV index stored in  "
  434|      0|                                                "the material structure does therefore not apply for all meshes. ");
  435|      0|                            }
  436|      0|                            idx = outIdx;
  437|      0|                        }
  438|      0|                        info.uv = idx;
  439|      0|                        mappingStack.push_back(info);
  440|      0|                    }
  441|       |
  442|       |                    // Update the material property list
  443|      0|                    mapping = aiTextureMapping_UV;
  444|      0|                    ((aiMaterial *)mat)->AddProperty(&idx, 1, AI_MATKEY_UVWSRC(prop->mSemantic, prop->mIndex));
  445|      0|                }
  446|      0|            }
  447|  1.50k|        }
  448|     92|    }
  449|    218|    ASSIMP_LOG_DEBUG("GenUVCoordsProcess finished");
  450|    218|}

_ZN6Assimp23ComputeUVMappingProcessC2Ev:
   63|    297|    ComputeUVMappingProcess() = default;

_ZNK6Assimp21MakeLeftHandedProcess8IsActiveEj:
   82|    218|bool MakeLeftHandedProcess::IsActive(unsigned int pFlags) const {
   83|    218|    return 0 != (pFlags & aiProcess_MakeLeftHanded);
   84|    218|}
_ZN6Assimp14FlipUVsProcessC2Ev:
  244|    297|FlipUVsProcess::FlipUVsProcess() = default;
_ZN6Assimp14FlipUVsProcessD2Ev:
  248|    297|FlipUVsProcess::~FlipUVsProcess() = default;
_ZNK6Assimp14FlipUVsProcess8IsActiveEj:
  252|    218|bool FlipUVsProcess::IsActive(unsigned int pFlags) const {
  253|    218|    return 0 != (pFlags & aiProcess_FlipUVs);
  254|    218|}
_ZNK6Assimp23FlipWindingOrderProcess8IsActiveEj:
  306|    218|bool FlipWindingOrderProcess::IsActive(unsigned int pFlags) const {
  307|    218|    return 0 != (pFlags & aiProcess_FlipWindingOrder);
  308|    218|}

_ZN6Assimp21MakeLeftHandedProcessC2Ev:
   77|    297|    MakeLeftHandedProcess() = default;
_ZN6Assimp23FlipWindingOrderProcessC2Ev:
  132|    297|    FlipWindingOrderProcess() = default;

_ZN6Assimp13DeboneProcessC2Ev:
   54|    297|DeboneProcess::DeboneProcess() : mNumBones(0), mNumBonesCanDoWithout(0), mThreshold(AI_DEBONE_THRESHOLD), mAllOrNone(false) {}
_ZNK6Assimp13DeboneProcess8IsActiveEj:
   58|    218|bool DeboneProcess::IsActive( unsigned int pFlags) const {
   59|    218|    return (pFlags & aiProcess_Debone) != 0;
   60|    218|}

_ZN6Assimp13DeboneProcessD2Ev:
   72|    297|    ~DeboneProcess() override = default;

_ZNK6Assimp22DropFaceNormalsProcess8IsActiveEj:
   58|    218|bool DropFaceNormalsProcess::IsActive(unsigned int pFlags) const {
   59|    218|    return (pFlags & aiProcess_DropNormals) != 0;
   60|    218|}

_ZN6Assimp22DropFaceNormalsProcessC2Ev:
   57|    297|    DropFaceNormalsProcess() = default;

_ZNK6Assimp20EmbedTexturesProcess8IsActiveEj:
   53|    218|bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
   54|    218|    return (pFlags & aiProcess_EmbedTextures) != 0;
   55|    218|}

_ZN6Assimp20EmbedTexturesProcessC2Ev:
   64|    297|    EmbedTexturesProcess() = default;
_ZN6Assimp20EmbedTexturesProcessD2Ev:
   67|    297|    ~EmbedTexturesProcess() override = default;

_ZN6Assimp22FindDegeneratesProcessC2Ev:
   62|    297|        mConfigRemoveDegenerates(false),
   63|    297|        mConfigCheckAreaOfTriangle(false) {
   64|       |    // empty
   65|    297|}
_ZNK6Assimp22FindDegeneratesProcess8IsActiveEj:
   69|    218|bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const {
   70|    218|    return 0 != (pFlags & aiProcess_FindDegenerates);
   71|    218|}
_ZN6Assimp22FindDegeneratesProcess15SetupPropertiesEPKNS_8ImporterE:
   75|    218|void FindDegeneratesProcess::SetupProperties(const Importer *pImp) {
   76|       |    // Get the current value of AI_CONFIG_PP_FD_REMOVE
   77|    218|    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0));
   78|       |    mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA));
   79|    218|}
_ZN6Assimp22FindDegeneratesProcess7ExecuteEP7aiScene:
   83|    218|void FindDegeneratesProcess::Execute(aiScene *pScene) {
   84|    218|    ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
   85|    218|    if (nullptr == pScene) {
  ------------------
  |  Branch (85:9): [True: 0, False: 218]
  ------------------
   86|      0|        return;
   87|      0|    }
   88|       |
   89|    218|    std::unordered_map<unsigned int, unsigned int> meshMap;
   90|    218|    meshMap.reserve(pScene->mNumMeshes);
   91|       |
   92|    218|    const unsigned int originalNumMeshes = pScene->mNumMeshes;
   93|    218|    unsigned int targetIndex = 0;
   94|    312|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (94:30): [True: 94, False: 218]
  ------------------
   95|       |        // Do not process point cloud, ExecuteOnMesh works only with faces data
   96|     94|        if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
  ------------------
  |  Branch (96:13): [True: 94, False: 0]
  |  Branch (96:96): [True: 0, False: 94]
  ------------------
   97|      0|            delete pScene->mMeshes[i];
   98|       |            // Not strictly required, but clean:
   99|      0|            pScene->mMeshes[i] = nullptr;
  100|     94|        } else {
  101|     94|            meshMap[i] = targetIndex;
  102|     94|            pScene->mMeshes[targetIndex] = pScene->mMeshes[i];
  103|     94|            ++targetIndex;
  104|     94|        }
  105|     94|    }
  106|    218|    pScene->mNumMeshes = targetIndex;
  107|       |
  108|    218|    if (meshMap.size() < originalNumMeshes) {
  ------------------
  |  Branch (108:9): [True: 0, False: 218]
  ------------------
  109|      0|        updateSceneGraph(pScene->mRootNode, meshMap);
  110|      0|    }
  111|       |
  112|       |    ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
  113|    218|}
_ZN6Assimp22FindDegeneratesProcess13ExecuteOnMeshEP6aiMesh:
  134|     94|bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
  135|     94|    mesh->mPrimitiveTypes = 0;
  136|       |
  137|     94|    std::vector<bool> remove_me;
  138|     94|    if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (138:9): [True: 0, False: 94]
  ------------------
  139|      0|        remove_me.resize(mesh->mNumFaces, false);
  140|      0|    }
  141|       |
  142|     94|    unsigned int deg = 0, limit;
  143|   181k|    for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (143:30): [True: 181k, False: 94]
  ------------------
  144|   181k|        aiFace &face = mesh->mFaces[a];
  145|   181k|        bool first = true;
  146|   181k|        auto vertex_in_range = [numVertices = mesh->mNumVertices](unsigned int vertex_idx) { return vertex_idx < numVertices; };
  147|       |
  148|       |        // check whether the face contains degenerated entries
  149|   726k|        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (149:34): [True: 544k, False: 181k]
  ------------------
  150|   544k|            if (!std::all_of(face.mIndices, face.mIndices + face.mNumIndices, vertex_in_range))
  ------------------
  |  Branch (150:17): [True: 0, False: 544k]
  ------------------
  151|      0|                continue;
  152|       |
  153|       |            // Polygons with more than 4 points are allowed to have double points, that is
  154|       |            // simulating polygons with holes just with concave polygons. However,
  155|       |            // double points may not come directly after another.
  156|   544k|            limit = face.mNumIndices;
  157|   544k|            if (face.mNumIndices > 4) {
  ------------------
  |  Branch (157:17): [True: 0, False: 544k]
  ------------------
  158|      0|                limit = std::min(limit, i + 2);
  159|      0|            }
  160|       |
  161|  1.08M|            for (unsigned int t = i + 1; t < limit; ++t) {
  ------------------
  |  Branch (161:42): [True: 544k, False: 544k]
  ------------------
  162|   544k|                if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) {
  ------------------
  |  Branch (162:21): [True: 247, False: 544k]
  ------------------
  163|       |                    // we have found a matching vertex position
  164|       |                    // remove the corresponding index from the array
  165|    247|                    --face.mNumIndices;
  166|    247|                    --limit;
  167|    268|                    for (unsigned int m = t; m < face.mNumIndices; ++m) {
  ------------------
  |  Branch (167:46): [True: 21, False: 247]
  ------------------
  168|     21|                        face.mIndices[m] = face.mIndices[m + 1];
  169|     21|                    }
  170|    247|                    --t;
  171|       |
  172|       |                    // NOTE: we set the removed vertex index to an unique value
  173|       |                    // to make sure the developer gets notified when his
  174|       |                    // application attempts to access this data.
  175|    247|                    face.mIndices[face.mNumIndices] = 0xdeadbeef;
  176|       |
  177|    247|                    if (first) {
  ------------------
  |  Branch (177:25): [True: 236, False: 11]
  ------------------
  178|    236|                        ++deg;
  179|    236|                        first = false;
  180|    236|                    }
  181|       |
  182|    247|                    if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (182:25): [True: 0, False: 247]
  ------------------
  183|      0|                        remove_me[a] = true;
  184|      0|                        goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
  185|      0|                    }
  186|    247|                }
  187|   544k|            }
  188|       |
  189|   544k|            if (mConfigCheckAreaOfTriangle) {
  ------------------
  |  Branch (189:17): [True: 544k, False: 0]
  ------------------
  190|   544k|                if (face.mNumIndices == 3) {
  ------------------
  |  Branch (190:21): [True: 544k, False: 254]
  ------------------
  191|   544k|                    ai_real area = GeometryUtils::calculateAreaOfTriangle(face, mesh);
  192|   544k|                    if (area < ai_epsilon) {
  ------------------
  |  Branch (192:25): [True: 1.86k, False: 542k]
  ------------------
  193|  1.86k|                        if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (193:29): [True: 0, False: 1.86k]
  ------------------
  194|      0|                            remove_me[a] = true;
  195|      0|                            ++deg;
  196|      0|                            goto evil_jump_outside;
  197|      0|                        }
  198|       |
  199|       |                        // todo: check for index which is corrupt.
  200|  1.86k|                    }
  201|   544k|                }
  202|   544k|            }
  203|   544k|        }
  204|       |
  205|       |        // We need to update the primitive flags array of the mesh.
  206|   181k|        switch (face.mNumIndices) {
  207|     31|        case 1u:
  ------------------
  |  Branch (207:9): [True: 31, False: 181k]
  ------------------
  208|     31|            mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  209|     31|            break;
  210|    206|        case 2u:
  ------------------
  |  Branch (210:9): [True: 206, False: 181k]
  ------------------
  211|    206|            mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  212|    206|            break;
  213|   181k|        case 3u:
  ------------------
  |  Branch (213:9): [True: 181k, False: 237]
  ------------------
  214|   181k|            mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  215|   181k|            break;
  216|      0|        default:
  ------------------
  |  Branch (216:9): [True: 0, False: 181k]
  ------------------
  217|      0|            mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  218|      0|            break;
  219|   181k|        };
  220|   181k|    evil_jump_outside:
  221|   181k|        continue;
  222|   181k|    }
  223|       |
  224|       |    // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
  225|     94|    if (mConfigRemoveDegenerates && deg) {
  ------------------
  |  Branch (225:9): [True: 0, False: 94]
  |  Branch (225:37): [True: 0, False: 0]
  ------------------
  226|      0|        unsigned int n = 0;
  227|      0|        for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (227:34): [True: 0, False: 0]
  ------------------
  228|      0|            aiFace &face_src = mesh->mFaces[a];
  229|      0|            if (!remove_me[a]) {
  ------------------
  |  Branch (229:17): [True: 0, False: 0]
  ------------------
  230|      0|                aiFace &face_dest = mesh->mFaces[n++];
  231|       |
  232|       |                // Do a manual copy, keep the index array
  233|      0|                face_dest.mNumIndices = face_src.mNumIndices;
  234|      0|                face_dest.mIndices = face_src.mIndices;
  235|       |
  236|      0|                if (&face_src != &face_dest) {
  ------------------
  |  Branch (236:21): [True: 0, False: 0]
  ------------------
  237|       |                    // clear source
  238|      0|                    face_src.mNumIndices = 0;
  239|      0|                    face_src.mIndices = nullptr;
  240|      0|                }
  241|      0|            } else {
  242|       |                // Otherwise delete it if we don't need this face
  243|      0|                delete[] face_src.mIndices;
  244|      0|                face_src.mIndices = nullptr;
  245|      0|                face_src.mNumIndices = 0;
  246|      0|            }
  247|      0|        }
  248|       |        // Just leave the rest of the array unreferenced, we don't care for now
  249|      0|        mesh->mNumFaces = n;
  250|      0|        if (!mesh->mNumFaces) {
  ------------------
  |  Branch (250:13): [True: 0, False: 0]
  ------------------
  251|       |            // The whole mesh consists of degenerated faces
  252|       |            // signal upward, that this mesh should be deleted.
  253|      0|            ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
  254|      0|            return true;
  255|      0|        }
  256|      0|    }
  257|       |
  258|     94|    if (deg && !DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (258:9): [True: 4, False: 90]
  |  Branch (258:16): [True: 0, False: 4]
  ------------------
  259|       |        ASSIMP_LOG_WARN("Found ", deg, " degenerated primitives");
  260|      0|    }
  261|     94|    return false;
  262|     94|}
FindDegenerates.cpp:_ZZN6Assimp22FindDegeneratesProcess13ExecuteOnMeshEP6aiMeshENK3$_0clEj:
  146|  1.63M|        auto vertex_in_range = [numVertices = mesh->mNumVertices](unsigned int vertex_idx) { return vertex_idx < numVertices; };

_ZN6Assimp20FindInstancesProcessC2Ev:
   58|    297|:   configSpeedFlag (false)
   59|    297|{}
_ZNK6Assimp20FindInstancesProcess8IsActiveEj:
   64|    218|{
   65|       |    // FindInstances makes absolutely no sense together with PreTransformVertices
   66|       |    // fixme: spawn error message somewhere else?
   67|    218|    return 0 != (pFlags & aiProcess_FindInstances) && 0 == (pFlags & aiProcess_PreTransformVertices);
  ------------------
  |  Branch (67:12): [True: 0, False: 218]
  |  Branch (67:55): [True: 0, False: 0]
  ------------------
   68|    218|}

_ZN6Assimp22FindInvalidDataProcessC2Ev:
   59|    297|        configEpsilon(0.0), mIgnoreTexCoods(false) {
   60|       |    // nothing to do here
   61|    297|}
_ZNK6Assimp22FindInvalidDataProcess8IsActiveEj:
   65|    218|bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {
   66|    218|    return 0 != (pFlags & aiProcess_FindInvalidData);
   67|    218|}
_ZN6Assimp22FindInvalidDataProcess15SetupPropertiesEPKNS_8ImporterE:
   71|    218|void FindInvalidDataProcess::SetupProperties(const Importer *pImp) {
   72|       |    // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
   73|    218|    configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY, 0.f));
   74|       |    mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false);
   75|    218|}
_Z20UpdateMeshReferencesP6aiNodeRKNSt3__16vectorIjNS1_9allocatorIjEEEE:
   79|     13|void UpdateMeshReferences(aiNode *node, const std::vector<unsigned int> &meshMapping) {
   80|     13|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 8, False: 5]
  ------------------
   81|      8|        unsigned int out = 0;
   82|     24|        for (unsigned int a = 0; a < node->mNumMeshes; ++a) {
  ------------------
  |  Branch (82:34): [True: 16, False: 8]
  ------------------
   83|       |
   84|     16|            unsigned int ref = node->mMeshes[a];
   85|     16|            if (ref >= meshMapping.size())
  ------------------
  |  Branch (85:17): [True: 0, False: 16]
  ------------------
   86|      0|                throw DeadlyImportError("Invalid mesh ref");
   87|       |
   88|     16|            if (UINT_MAX != (ref = meshMapping[ref])) {
  ------------------
  |  Branch (88:17): [True: 3, False: 13]
  ------------------
   89|      3|                node->mMeshes[out++] = ref;
   90|      3|            }
   91|     16|        }
   92|       |        // just let the members that are unused, that's much cheaper
   93|       |        // than a full array realloc'n'copy party ...
   94|      8|        node->mNumMeshes = out;
   95|      8|        if (0 == out) {
  ------------------
  |  Branch (95:13): [True: 6, False: 2]
  ------------------
   96|      6|            delete[] node->mMeshes;
   97|      6|            node->mMeshes = nullptr;
   98|      6|        }
   99|      8|    }
  100|       |    // recursively update all children
  101|     24|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 11, False: 13]
  ------------------
  102|     11|        UpdateMeshReferences(node->mChildren[i], meshMapping);
  103|     11|    }
  104|     13|}
_ZN6Assimp22FindInvalidDataProcess7ExecuteEP7aiScene:
  108|    218|void FindInvalidDataProcess::Execute(aiScene *pScene) {
  109|    218|    ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin");
  110|       |
  111|    218|    bool out = false;
  112|    218|    std::vector<unsigned int> meshMapping(pScene->mNumMeshes);
  113|    218|    unsigned int real = 0;
  114|       |
  115|       |    // Process meshes
  116|    318|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (116:30): [True: 100, False: 218]
  ------------------
  117|    100|        int result = ProcessMesh(pScene->mMeshes[a]);
  118|    100|        if (0 == result) {
  ------------------
  |  Branch (118:13): [True: 97, False: 3]
  ------------------
  119|     97|            out = true;
  120|     97|        }
  121|    100|        if (2 == result) {
  ------------------
  |  Branch (121:13): [True: 3, False: 97]
  ------------------
  122|       |            // remove this mesh
  123|      3|            delete pScene->mMeshes[a];
  124|      3|            pScene->mMeshes[a] = nullptr;
  125|       |
  126|      3|            meshMapping[a] = UINT_MAX;
  127|      3|            out = true;
  128|      3|            continue;
  129|      3|        }
  130|       |
  131|     97|        pScene->mMeshes[real] = pScene->mMeshes[a];
  132|     97|        meshMapping[a] = real++;
  133|     97|    }
  134|       |
  135|       |    // Process animations
  136|    417|    for (unsigned int animIdx = 0; animIdx < pScene->mNumAnimations; ++animIdx) {
  ------------------
  |  Branch (136:36): [True: 199, False: 218]
  ------------------
  137|    199|        ProcessAnimation(pScene->mAnimations[animIdx]);
  138|    199|    }
  139|       |
  140|    218|    if (out) {
  ------------------
  |  Branch (140:9): [True: 91, False: 127]
  ------------------
  141|     91|        if (real != pScene->mNumMeshes) {
  ------------------
  |  Branch (141:13): [True: 2, False: 89]
  ------------------
  142|      2|            if (!real) {
  ------------------
  |  Branch (142:17): [True: 0, False: 2]
  ------------------
  143|      0|                throw DeadlyImportError("No meshes remaining");
  144|      0|            }
  145|       |
  146|       |            // we need to remove some meshes.
  147|       |            // therefore we'll also need to remove all references
  148|       |            // to them from the scenegraph
  149|      2|            try {
  150|      2|                UpdateMeshReferences(pScene->mRootNode, meshMapping);
  151|      2|            } catch (const std::exception&) {
  152|       |                // fix the real number of meshes otherwise we'll get double free in the scene destructor
  153|      0|                pScene->mNumMeshes = real;
  154|      0|                throw;
  155|      0|            }
  156|      2|            pScene->mNumMeshes = real;
  157|      2|        }
  158|       |
  159|     91|        ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ...");
  160|    127|    } else {
  161|       |        ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK.");
  162|    127|    }
  163|    218|}
_ZN6Assimp22FindInvalidDataProcess16ProcessAnimationEP11aiAnimation:
  265|    199|void FindInvalidDataProcess::ProcessAnimation(aiAnimation *anim) {
  266|       |    // Process all animation channels
  267|  3.54k|    for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
  ------------------
  |  Branch (267:30): [True: 3.34k, False: 199]
  ------------------
  268|  3.34k|        ProcessAnimationChannel(anim->mChannels[a]);
  269|  3.34k|    }
  270|    199|}
_ZN6Assimp22FindInvalidDataProcess23ProcessAnimationChannelEP10aiNodeAnim:
  273|  3.34k|void FindInvalidDataProcess::ProcessAnimationChannel(aiNodeAnim *anim) {
  274|  3.34k|    ai_assert(nullptr != anim);
  275|  3.34k|    if (anim->mNumPositionKeys == 0 && anim->mNumRotationKeys == 0 && anim->mNumScalingKeys == 0) {
  ------------------
  |  Branch (275:9): [True: 20, False: 3.32k]
  |  Branch (275:40): [True: 0, False: 20]
  |  Branch (275:71): [True: 0, False: 0]
  ------------------
  276|      0|        ASSIMP_LOG_ERROR("Invalid node anuimation instance detected.");
  277|       |
  278|      0|        return;
  279|      0|    }
  280|       |
  281|       |    // Check whether all values in a tracks are identical - in this case
  282|       |    // we can remove al keys except one.
  283|       |    // POSITIONS
  284|  3.34k|    int i = 0;
  285|  3.34k|    if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys, anim->mNumPositionKeys, configEpsilon)) {
  ------------------
  |  Branch (285:9): [True: 2.70k, False: 640]
  |  Branch (285:39): [True: 2.50k, False: 205]
  ------------------
  286|  2.50k|        aiVectorKey v = anim->mPositionKeys[0];
  287|       |
  288|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  289|  2.50k|        delete[] anim->mPositionKeys;
  290|  2.50k|        anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = 1];
  291|  2.50k|        anim->mPositionKeys[0] = v;
  292|  2.50k|        i = 1;
  293|  2.50k|    }
  294|       |
  295|       |    // ROTATIONS
  296|  3.34k|    if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys, anim->mNumRotationKeys, configEpsilon)) {
  ------------------
  |  Branch (296:9): [True: 2.73k, False: 610]
  |  Branch (296:39): [True: 2.25k, False: 481]
  ------------------
  297|  2.25k|        aiQuatKey v = anim->mRotationKeys[0];
  298|       |
  299|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  300|  2.25k|        delete[] anim->mRotationKeys;
  301|  2.25k|        anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = 1];
  302|  2.25k|        anim->mRotationKeys[0] = v;
  303|  2.25k|        i = 1;
  304|  2.25k|    }
  305|       |
  306|       |    // SCALINGS
  307|  3.34k|    if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys, anim->mNumScalingKeys, configEpsilon)) {
  ------------------
  |  Branch (307:9): [True: 2.71k, False: 629]
  |  Branch (307:38): [True: 2.37k, False: 339]
  ------------------
  308|  2.37k|        aiVectorKey v = anim->mScalingKeys[0];
  309|       |
  310|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  311|  2.37k|        delete[] anim->mScalingKeys;
  312|  2.37k|        anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = 1];
  313|  2.37k|        anim->mScalingKeys[0] = v;
  314|  2.37k|        i = 1;
  315|  2.37k|    }
  316|  3.34k|    if (1 == i) {
  ------------------
  |  Branch (316:9): [True: 2.89k, False: 455]
  ------------------
  317|       |        ASSIMP_LOG_WARN("Simplified dummy tracks with just one key");
  318|  2.89k|    }
  319|  3.34k|}
_ZN6Assimp22FindInvalidDataProcess11ProcessMeshEP6aiMesh:
  323|    100|int FindInvalidDataProcess::ProcessMesh(aiMesh *pMesh) {
  324|    100|    bool ret = false;
  325|    100|    std::vector<bool> dirtyMask(pMesh->mNumVertices, pMesh->mNumFaces != 0);
  326|       |
  327|       |    // Ignore elements that are not referenced by vertices.
  328|       |    // (they are, for example, caused by the FindDegenerates step)
  329|   181k|    for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
  ------------------
  |  Branch (329:30): [True: 181k, False: 100]
  ------------------
  330|   181k|        const aiFace &f = pMesh->mFaces[m];
  331|       |
  332|   726k|        for (unsigned int i = 0; i < f.mNumIndices; ++i) {
  ------------------
  |  Branch (332:34): [True: 544k, False: 181k]
  ------------------
  333|   544k|            dirtyMask[f.mIndices[i]] = false;
  334|   544k|        }
  335|   181k|    }
  336|       |
  337|       |    // Process vertex positions
  338|    100|    if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) {
  ------------------
  |  Branch (338:9): [True: 100, False: 0]
  |  Branch (338:29): [True: 3, False: 97]
  ------------------
  339|      3|        ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions");
  340|       |
  341|      3|        return 2;
  342|      3|    }
  343|       |
  344|       |    // process texture coordinates
  345|     97|    if (!mIgnoreTexCoods) {
  ------------------
  |  Branch (345:9): [True: 97, False: 0]
  ------------------
  346|    175|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) {
  ------------------
  |  Branch (346:34): [True: 175, False: 0]
  |  Branch (346:72): [True: 78, False: 97]
  ------------------
  347|     78|            if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) {
  ------------------
  |  Branch (347:17): [True: 0, False: 78]
  ------------------
  348|      0|                pMesh->mNumUVComponents[i] = 0;
  349|       |
  350|       |                // delete all subsequent texture coordinate sets.
  351|      0|                for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
  ------------------
  |  Branch (351:46): [True: 0, False: 0]
  ------------------
  352|      0|                    delete[] pMesh->mTextureCoords[a];
  353|      0|                    pMesh->mTextureCoords[a] = nullptr;
  354|      0|                    pMesh->mNumUVComponents[a] = 0;
  355|      0|                }
  356|       |
  357|      0|                ret = true;
  358|      0|            }
  359|     78|        }
  360|     97|    }
  361|       |
  362|       |    // -- we don't validate vertex colors, it's difficult to say whether
  363|       |    // they are invalid or not.
  364|       |
  365|       |    // Normals and tangents are undefined for point and line faces.
  366|     97|    if (pMesh->mNormals || pMesh->mTangents) {
  ------------------
  |  Branch (366:9): [True: 24, False: 73]
  |  Branch (366:28): [True: 0, False: 73]
  ------------------
  367|       |
  368|     24|        if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (368:13): [True: 0, False: 24]
  ------------------
  369|     24|                aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (369:17): [True: 0, False: 24]
  ------------------
  370|      0|            if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (370:17): [True: 0, False: 0]
  ------------------
  371|      0|                    aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (371:21): [True: 0, False: 0]
  ------------------
  372|       |                // We need to update the lookup-table
  373|      0|                for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
  ------------------
  |  Branch (373:42): [True: 0, False: 0]
  ------------------
  374|      0|                    const aiFace &f = pMesh->mFaces[m];
  375|       |
  376|      0|                    if (f.mNumIndices < 3) {
  ------------------
  |  Branch (376:25): [True: 0, False: 0]
  ------------------
  377|      0|                        dirtyMask[f.mIndices[0]] = true;
  378|      0|                        if (f.mNumIndices == 2) {
  ------------------
  |  Branch (378:29): [True: 0, False: 0]
  ------------------
  379|      0|                            dirtyMask[f.mIndices[1]] = true;
  380|      0|                        }
  381|      0|                    }
  382|      0|                }
  383|      0|            }
  384|       |            // Normals, tangents and bitangents are undefined for
  385|       |            // the whole mesh (and should not even be there)
  386|      0|            else {
  387|      0|                return ret;
  388|      0|            }
  389|      0|        }
  390|       |
  391|       |        // Process mesh normals
  392|     24|        if (pMesh->mNormals && ProcessArray(pMesh->mNormals, pMesh->mNumVertices,
  ------------------
  |  Branch (392:13): [True: 24, False: 0]
  |  Branch (392:32): [True: 0, False: 24]
  ------------------
  393|     24|                                       "normals", dirtyMask, true, false))
  394|      0|            ret = true;
  395|       |
  396|       |        // Process mesh tangents
  397|     24|        if (pMesh->mTangents && ProcessArray(pMesh->mTangents, pMesh->mNumVertices, "tangents", dirtyMask)) {
  ------------------
  |  Branch (397:13): [True: 4, False: 20]
  |  Branch (397:33): [True: 0, False: 4]
  ------------------
  398|      0|            delete[] pMesh->mBitangents;
  399|      0|            pMesh->mBitangents = nullptr;
  400|      0|            ret = true;
  401|      0|        }
  402|       |
  403|       |        // Process mesh bitangents
  404|     24|        if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents, pMesh->mNumVertices, "bitangents", dirtyMask)) {
  ------------------
  |  Branch (404:13): [True: 4, False: 20]
  |  Branch (404:35): [True: 0, False: 4]
  ------------------
  405|      0|            delete[] pMesh->mTangents;
  406|      0|            pMesh->mTangents = nullptr;
  407|      0|            ret = true;
  408|      0|        }
  409|     24|    }
  410|     97|    return ret ? 1 : 0;
  ------------------
  |  Branch (410:12): [True: 0, False: 97]
  ------------------
  411|     97|}
_Z12AllIdenticalI11aiVectorKeyEbPT_jf:
  242|  5.42k|inline bool AllIdentical(T *in, unsigned int num, ai_real epsilon) {
  243|  5.42k|    if (num <= 1) {
  ------------------
  |  Branch (243:9): [True: 0, False: 5.42k]
  ------------------
  244|      0|        return true;
  245|      0|    }
  246|       |
  247|  5.42k|    if (fabs(epsilon) > 0.f) {
  ------------------
  |  Branch (247:9): [True: 0, False: 5.42k]
  ------------------
  248|      0|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (248:34): [True: 0, False: 0]
  ------------------
  249|      0|            if (!EpsilonCompare(in[i], in[i + 1], epsilon)) {
  ------------------
  |  Branch (249:17): [True: 0, False: 0]
  ------------------
  250|      0|                return false;
  251|      0|            }
  252|      0|        }
  253|  5.42k|    } else {
  254|  4.15M|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (254:34): [True: 4.14M, False: 4.88k]
  ------------------
  255|  4.14M|            if (in[i] != in[i + 1]) {
  ------------------
  |  Branch (255:17): [True: 544, False: 4.14M]
  ------------------
  256|    544|                return false;
  257|    544|            }
  258|  4.14M|        }
  259|  5.42k|    }
  260|  4.88k|    return true;
  261|  5.42k|}
_Z12AllIdenticalI9aiQuatKeyEbPT_jf:
  242|  2.73k|inline bool AllIdentical(T *in, unsigned int num, ai_real epsilon) {
  243|  2.73k|    if (num <= 1) {
  ------------------
  |  Branch (243:9): [True: 0, False: 2.73k]
  ------------------
  244|      0|        return true;
  245|      0|    }
  246|       |
  247|  2.73k|    if (fabs(epsilon) > 0.f) {
  ------------------
  |  Branch (247:9): [True: 0, False: 2.73k]
  ------------------
  248|      0|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (248:34): [True: 0, False: 0]
  ------------------
  249|      0|            if (!EpsilonCompare(in[i], in[i + 1], epsilon)) {
  ------------------
  |  Branch (249:17): [True: 0, False: 0]
  ------------------
  250|      0|                return false;
  251|      0|            }
  252|      0|        }
  253|  2.73k|    } else {
  254|  5.44k|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (254:34): [True: 3.19k, False: 2.25k]
  ------------------
  255|  3.19k|            if (in[i] != in[i + 1]) {
  ------------------
  |  Branch (255:17): [True: 481, False: 2.71k]
  ------------------
  256|    481|                return false;
  257|    481|            }
  258|  3.19k|        }
  259|  2.73k|    }
  260|  2.25k|    return true;
  261|  2.73k|}
_Z12ProcessArrayI10aiVector3tIfEEbRPT_jPKcRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  203|    210|        const std::vector<bool> &dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) {
  204|    210|    const char *err = ValidateArrayContents(in, num, dirtyMask, mayBeIdentical, mayBeZero);
  205|    210|    if (err) {
  ------------------
  |  Branch (205:9): [True: 3, False: 207]
  ------------------
  206|      3|        ASSIMP_LOG_ERROR("FindInvalidDataProcess fails on mesh ", name, ": ", err);
  207|      3|        delete[] in;
  208|      3|        in = nullptr;
  209|      3|        return true;
  210|      3|    }
  211|    207|    return false;
  212|    210|}
_Z21ValidateArrayContentsI10aiVector3tIfEEPKcPKT_jRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  175|    210|        const std::vector<bool> &dirtyMask, bool mayBeIdentical, bool mayBeZero) {
  176|    210|    bool b = false;
  177|    210|    unsigned int cnt = 0;
  178|   755k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (178:30): [True: 754k, False: 209]
  ------------------
  179|       |
  180|   754k|        if (dirtyMask.size() && dirtyMask[i]) {
  ------------------
  |  Branch (180:13): [True: 754k, False: 0]
  |  Branch (180:13): [True: 4, False: 754k]
  |  Branch (180:33): [True: 4, False: 754k]
  ------------------
  181|      4|            continue;
  182|      4|        }
  183|   754k|        ++cnt;
  184|       |
  185|   754k|        const aiVector3D &v = arr[i];
  186|   754k|        if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
  ------------------
  |  Branch (186:13): [True: 0, False: 754k]
  |  Branch (186:38): [True: 0, False: 754k]
  |  Branch (186:63): [True: 1, False: 754k]
  ------------------
  187|      1|            return "INF/NAN was found in a vector component";
  188|      1|        }
  189|   754k|        if (!mayBeZero && !v.x && !v.y && !v.z) {
  ------------------
  |  Branch (189:13): [True: 84.5k, False: 670k]
  |  Branch (189:27): [True: 10.6k, False: 73.9k]
  |  Branch (189:35): [True: 32, False: 10.5k]
  |  Branch (189:43): [True: 0, False: 32]
  ------------------
  190|      0|            return "Found zero-length vector";
  191|      0|        }
  192|   754k|        if (i && v != arr[i - 1]) b = true;
  ------------------
  |  Branch (192:13): [True: 754k, False: 210]
  |  Branch (192:18): [True: 658k, False: 96.0k]
  ------------------
  193|   754k|    }
  194|    209|    if (cnt > 1 && !b && !mayBeIdentical) {
  ------------------
  |  Branch (194:9): [True: 208, False: 1]
  |  Branch (194:20): [True: 2, False: 206]
  |  Branch (194:26): [True: 2, False: 0]
  ------------------
  195|      2|        return "All vectors are identical";
  196|      2|    }
  197|    207|    return nullptr;
  198|    209|}

_ZNK6Assimp25FixInfacingNormalsProcess8IsActiveEj:
   61|    218|bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const {
   62|    218|    return (pFlags & aiProcess_FixInfacingNormals) != 0;
   63|    218|}

_ZN6Assimp25FixInfacingNormalsProcessC2Ev:
   62|    297|    FixInfacingNormalsProcess() = default;

_ZNK6Assimp23GenBoundingBoxesProcess8IsActiveEj:
   51|    218|bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const {
   52|    218|    return 0 != ( pFlags & aiProcess_GenBoundingBoxes );
   53|    218|}

_ZN6Assimp23GenBoundingBoxesProcessC2Ev:
   65|    297|    GenBoundingBoxesProcess() = default;

_ZNK6Assimp21GenFaceNormalsProcess8IsActiveEj:
   61|    218|bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const {
   62|    218|    force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
   63|    218|    flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
   64|    218|    leftHanded_ = (pFlags & aiProcess_MakeLeftHanded) != 0;
   65|    218|    return (pFlags & aiProcess_GenNormals) != 0;
   66|    218|}

_ZN6Assimp21GenFaceNormalsProcessC2Ev:
   59|    297|    GenFaceNormalsProcess() = default;

_ZN6Assimp23GenVertexNormalsProcessC2Ev:
   57|    297|        configMaxAngle(AI_DEG_TO_RAD(175.f)) {
   58|       |    // empty
   59|    297|}
_ZNK6Assimp23GenVertexNormalsProcess8IsActiveEj:
   63|    218|bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const {
   64|    218|    force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
   65|    218|    flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
   66|    218|    leftHanded_ = (pFlags & aiProcess_MakeLeftHanded) != 0;
   67|    218|    return (pFlags & aiProcess_GenSmoothNormals) != 0;
   68|    218|}
_ZN6Assimp23GenVertexNormalsProcess15SetupPropertiesEPKNS_8ImporterE:
   72|    218|void GenVertexNormalsProcess::SetupProperties(const Importer *pImp) {
   73|       |    // Get the current value of the AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE property
   74|    218|    configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, (ai_real)175.0);
   75|       |    configMaxAngle = AI_DEG_TO_RAD(std::max(std::min(configMaxAngle, (ai_real)175.0), (ai_real)0.0));
   76|    218|}
_ZN6Assimp23GenVertexNormalsProcess7ExecuteEP7aiScene:
   80|    218|void GenVertexNormalsProcess::Execute(aiScene *pScene) {
   81|    218|    ASSIMP_LOG_DEBUG("GenVertexNormalsProcess begin");
   82|       |
   83|    218|    if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
  ------------------
  |  Branch (83:9): [True: 0, False: 218]
  ------------------
   84|      0|        throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
   85|      0|    }
   86|       |
   87|    218|    bool bHas = false;
   88|    315|    for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (88:30): [True: 97, False: 218]
  ------------------
   89|     97|        if (GenMeshVertexNormals(pScene->mMeshes[a], a))
  ------------------
  |  Branch (89:13): [True: 69, False: 28]
  ------------------
   90|     69|            bHas = true;
   91|     97|    }
   92|       |
   93|    218|    if (bHas) {
  ------------------
  |  Branch (93:9): [True: 67, False: 151]
  ------------------
   94|     67|        ASSIMP_LOG_INFO("GenVertexNormalsProcess finished. "
   95|     67|                        "Vertex normals have been calculated");
   96|    151|    } else {
   97|       |        ASSIMP_LOG_DEBUG("GenVertexNormalsProcess finished. "
   98|    151|                         "Normals are already there");
   99|    151|    }
  100|    218|}
_ZN6Assimp23GenVertexNormalsProcess20GenMeshVertexNormalsEP6aiMeshj:
  104|     97|bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int meshIndex) {
  105|     97|    if (nullptr != pMesh->mNormals) {
  ------------------
  |  Branch (105:9): [True: 24, False: 73]
  ------------------
  106|     24|        if (!force_) {
  ------------------
  |  Branch (106:13): [True: 24, False: 0]
  ------------------
  107|     24|            return false;
  108|     24|        }
  109|      0|        delete[] pMesh->mNormals;
  110|      0|        pMesh->mNormals = nullptr;
  111|      0|    }
  112|       |
  113|       |    // If the mesh consists of lines and/or points but not of
  114|       |    // triangles or higher-order polygons the normal vectors
  115|       |    // are undefined.
  116|     73|    if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
  ------------------
  |  Branch (116:9): [True: 4, False: 69]
  ------------------
  117|      4|        ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes");
  118|      4|        return false;
  119|      4|    }
  120|       |
  121|       |    // Allocate the array to hold the output normals
  122|     69|    const float qnan = std::numeric_limits<ai_real>::quiet_NaN();
  123|     69|    pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  124|       |
  125|       |    // Compute per-face normals but store them per-vertex
  126|   139k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (126:30): [True: 139k, False: 69]
  ------------------
  127|   139k|        const aiFace &face = pMesh->mFaces[a];
  128|   139k|        if (face.mNumIndices < 3) {
  ------------------
  |  Branch (128:13): [True: 0, False: 139k]
  ------------------
  129|       |            // either a point or a line -> no normal vector
  130|      0|            for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (130:38): [True: 0, False: 0]
  ------------------
  131|      0|                pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan);
  132|      0|            }
  133|       |
  134|      0|            continue;
  135|      0|        }
  136|       |
  137|   139k|        const aiVector3D *pV1 = &pMesh->mVertices[face.mIndices[0]];
  138|   139k|        const aiVector3D *pV2 = &pMesh->mVertices[face.mIndices[1]];
  139|   139k|        const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]];
  140|       |        // Boolean XOR - if either but not both of these flags is set, then the winding order has
  141|       |        // changed and the cross product to calculate the normal needs to be reversed
  142|   139k|        if (flippedWindingOrder_ != leftHanded_) {
  ------------------
  |  Branch (142:13): [True: 0, False: 139k]
  ------------------
  143|      0|            std::swap(pV2, pV3);
  144|      0|        }
  145|   139k|        const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
  146|       |
  147|   556k|        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (147:34): [True: 417k, False: 139k]
  ------------------
  148|   417k|            pMesh->mNormals[face.mIndices[i]] = vNor;
  149|   417k|        }
  150|   139k|    }
  151|       |
  152|       |    // Set up a SpatialSort to quickly find all vertices close to a given position
  153|       |    // check whether we can reuse the SpatialSort of a previous step.
  154|     69|    SpatialSort *vertexFinder = nullptr;
  155|     69|    SpatialSort _vertexFinder;
  156|     69|    ai_real posEpsilon = ai_real(1e-5);
  157|     69|    if (shared) {
  ------------------
  |  Branch (157:9): [True: 69, False: 0]
  ------------------
  158|     69|        std::vector<std::pair<SpatialSort, ai_real>> *avf;
  159|     69|        shared->GetProperty(AI_SPP_SPATIAL_SORT, avf);
  ------------------
  |  |  166|     69|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  160|     69|        if (avf) {
  ------------------
  |  Branch (160:13): [True: 69, False: 0]
  ------------------
  161|     69|            std::pair<SpatialSort, ai_real> &blubb = avf->operator[](meshIndex);
  162|     69|            vertexFinder = &blubb.first;
  163|     69|            posEpsilon = blubb.second;
  164|     69|        }
  165|     69|    }
  166|     69|    if (!vertexFinder) {
  ------------------
  |  Branch (166:9): [True: 0, False: 69]
  ------------------
  167|      0|        _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof(aiVector3D));
  168|      0|        vertexFinder = &_vertexFinder;
  169|      0|        posEpsilon = ComputePositionEpsilon(pMesh);
  170|      0|    }
  171|     69|    std::vector<unsigned int> verticesFound;
  172|     69|    aiVector3D *pcNew = new aiVector3D[pMesh->mNumVertices];
  173|       |
  174|     69|    if (configMaxAngle >= AI_DEG_TO_RAD(175.f)) {
  ------------------
  |  Branch (174:9): [True: 69, False: 0]
  ------------------
  175|       |        // There is no angle limit. Thus all vertices with positions close
  176|       |        // to each other will receive the same vertex normal. This allows us
  177|       |        // to optimize the whole algorithm a little bit ...
  178|     69|        std::vector<bool> abHad(pMesh->mNumVertices, false);
  179|   284k|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (179:34): [True: 284k, False: 69]
  ------------------
  180|   284k|            if (abHad[i]) {
  ------------------
  |  Branch (180:17): [True: 217k, False: 66.7k]
  ------------------
  181|   217k|                continue;
  182|   217k|            }
  183|       |
  184|       |            // Get all vertices that share this one ...
  185|  66.7k|            vertexFinder->FindPositions(pMesh->mVertices[i], posEpsilon, verticesFound);
  186|       |
  187|  66.7k|            aiVector3D pcNor;
  188|   350k|            for (unsigned int a = 0; a < verticesFound.size(); ++a) {
  ------------------
  |  Branch (188:38): [True: 284k, False: 66.7k]
  ------------------
  189|   284k|                const aiVector3D &v = pMesh->mNormals[verticesFound[a]];
  190|   284k|                if (is_not_qnan(v.x)) pcNor += v;
  ------------------
  |  Branch (190:21): [True: 284k, False: 0]
  ------------------
  191|   284k|            }
  192|  66.7k|            pcNor.NormalizeSafe();
  193|       |
  194|       |            // Write the smoothed normal back to all affected normals
  195|   350k|            for (unsigned int a = 0; a < verticesFound.size(); ++a) {
  ------------------
  |  Branch (195:38): [True: 284k, False: 66.7k]
  ------------------
  196|   284k|                unsigned int vidx = verticesFound[a];
  197|   284k|                pcNew[vidx] = pcNor;
  198|   284k|                abHad[vidx] = true;
  199|   284k|            }
  200|  66.7k|        }
  201|     69|    }
  202|       |    // Slower code path if a smooth angle is set. There are many ways to achieve
  203|       |    // the effect, this one is the most straightforward one.
  204|      0|    else {
  205|      0|        const ai_real fLimit = std::cos(configMaxAngle);
  206|      0|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (206:34): [True: 0, False: 0]
  ------------------
  207|       |            // Get all vertices that share this one ...
  208|      0|            vertexFinder->FindPositions(pMesh->mVertices[i], posEpsilon, verticesFound);
  209|       |
  210|      0|            aiVector3D vr = pMesh->mNormals[i];
  211|       |
  212|      0|            aiVector3D pcNor;
  213|      0|            for (unsigned int a = 0; a < verticesFound.size(); ++a) {
  ------------------
  |  Branch (213:38): [True: 0, False: 0]
  ------------------
  214|      0|                aiVector3D v = pMesh->mNormals[verticesFound[a]];
  215|       |
  216|       |                // Check whether the angle between the two normals is not too large.
  217|       |                // Skip the angle check on our own normal to avoid false negatives
  218|       |                // (v*v is not guaranteed to be 1.0 for all unit vectors v)
  219|      0|                if (is_not_qnan(v.x) && (verticesFound[a] == i || (v * vr >= fLimit)))
  ------------------
  |  Branch (219:21): [True: 0, False: 0]
  |  Branch (219:42): [True: 0, False: 0]
  |  Branch (219:67): [True: 0, False: 0]
  ------------------
  220|      0|                    pcNor += v;
  221|      0|            }
  222|      0|            pcNew[i] = pcNor.NormalizeSafe();
  223|      0|        }
  224|      0|    }
  225|       |
  226|     69|    delete[] pMesh->mNormals;
  227|     69|    pMesh->mNormals = pcNew;
  228|       |
  229|     69|    return true;
  230|     73|}

_ZN6Assimp27ImproveCacheLocalityProcessC2Ev:
  109|    297|ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() : mConfigCacheDepth(PP_ICL_PTCACHE_SIZE) {
  110|       |    // empty
  111|    297|}
_ZNK6Assimp27ImproveCacheLocalityProcess8IsActiveEj:
  115|    218|bool ImproveCacheLocalityProcess::IsActive(unsigned int pFlags) const {
  116|    218|    return (pFlags & aiProcess_ImproveCacheLocality) != 0;
  117|    218|}
_ZN6Assimp27ImproveCacheLocalityProcess15SetupPropertiesEPKNS_8ImporterE:
  121|    218|void ImproveCacheLocalityProcess::SetupProperties(const Importer *pImp) {
  122|       |    // AI_CONFIG_PP_ICL_PTCACHE_SIZE controls the target cache size for the optimizer
  123|    218|    mConfigCacheDepth = pImp->GetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE, PP_ICL_PTCACHE_SIZE);
  124|    218|}
_ZN6Assimp27ImproveCacheLocalityProcess7ExecuteEP7aiScene:
  128|    218|void ImproveCacheLocalityProcess::Execute(aiScene *pScene) {
  129|    218|    if (!pScene->mNumMeshes) {
  ------------------
  |  Branch (129:9): [True: 127, False: 91]
  ------------------
  130|    127|        ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess skipped; there are no meshes");
  131|    127|        return;
  132|    127|    }
  133|       |
  134|    218|    ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess begin");
  135|       |
  136|     91|    float out = 0.f;
  137|     91|    unsigned int numf = 0, numm = 0;
  138|    188|    for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (138:30): [True: 97, False: 91]
  ------------------
  139|     97|        const float res = ProcessMesh(pScene->mMeshes[a], a);
  140|     97|        if (res) {
  ------------------
  |  Branch (140:13): [True: 0, False: 97]
  ------------------
  141|      0|            numf += pScene->mMeshes[a]->mNumFaces;
  142|      0|            out += res;
  143|      0|            ++numm;
  144|      0|        }
  145|     97|    }
  146|     91|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (146:9): [True: 0, False: 91]
  ------------------
  147|      0|        if (numf > 0) {
  ------------------
  |  Branch (147:13): [True: 0, False: 0]
  ------------------
  148|      0|            ASSIMP_LOG_INFO("Cache relevant are ", numm, " meshes (", numf, " faces). Average output ACMR is ", out / numf);
  149|      0|        }
  150|       |        ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess finished. ");
  151|      0|    }
  152|     91|}
_ZN6Assimp27ImproveCacheLocalityProcess11ProcessMeshEP6aiMeshj:
  156|     97|ai_real ImproveCacheLocalityProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshNum) {
  157|       |    // TODO: rewrite this to use std::vector or boost::shared_array
  158|     97|    ai_assert(nullptr != pMesh);
  159|       |
  160|       |    // Check whether the input data is valid
  161|       |    // - there must be vertices and faces
  162|       |    // - all faces must be triangulated or we can't operate on them
  163|     97|    if (!pMesh->HasFaces() || !pMesh->HasPositions())
  ------------------
  |  Branch (163:9): [True: 0, False: 97]
  |  Branch (163:31): [True: 0, False: 97]
  ------------------
  164|      0|        return static_cast<ai_real>(0.f);
  165|       |
  166|     97|    if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) {
  ------------------
  |  Branch (166:9): [True: 4, False: 93]
  ------------------
  167|      4|        ASSIMP_LOG_ERROR("This algorithm works on triangle meshes only");
  168|      4|        return static_cast<ai_real>(0.f);
  169|      4|    }
  170|       |
  171|     93|    if (pMesh->mNumVertices <= mConfigCacheDepth) {
  ------------------
  |  Branch (171:9): [True: 4, False: 89]
  ------------------
  172|      4|        return static_cast<ai_real>(0.f);
  173|      4|    }
  174|       |
  175|     89|    ai_real fACMR = 3.f;
  176|     89|    const aiFace *const pcEnd = pMesh->mFaces + pMesh->mNumFaces;
  177|       |
  178|       |    // Input ACMR is for logging purposes only
  179|     89|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (179:9): [True: 0, False: 89]
  ------------------
  180|      0|        fACMR = calculateInputACMR(pMesh, pcEnd, mConfigCacheDepth, meshNum);
  181|      0|    }
  182|       |
  183|       |    // first we need to build a vertex-triangle adjacency list
  184|     89|    VertexTriangleAdjacency adj(pMesh->mFaces, pMesh->mNumFaces, pMesh->mNumVertices, true);
  185|       |
  186|       |    // build a list to store per-vertex caching time stamps
  187|     89|    std::vector<unsigned int> piCachingStamps;
  188|     89|    piCachingStamps.resize(pMesh->mNumVertices);
  189|     89|    memset(&piCachingStamps[0], 0x0, pMesh->mNumVertices * sizeof(unsigned int));
  190|       |
  191|       |    // allocate an empty output index buffer. We store the output indices in one large array.
  192|       |    // Since the number of triangles won't change the input faces can be reused. This is how
  193|       |    // we save thousands of redundant mini allocations for aiFace::mIndices
  194|     89|    const unsigned int iIdxCnt = pMesh->mNumFaces * 3;
  195|     89|    std::vector<unsigned int> piIBOutput;
  196|     89|    piIBOutput.resize(iIdxCnt);
  197|     89|    std::vector<unsigned int>::iterator piCSIter = piIBOutput.begin();
  198|       |
  199|       |    // allocate the flag array to hold the information
  200|       |    // whether a face has already been emitted or not
  201|     89|    std::vector<bool> abEmitted(pMesh->mNumFaces, false);
  202|       |
  203|       |    // dead-end vertex index stack
  204|     89|    std::stack<unsigned int, std::vector<unsigned int>> sDeadEndVStack;
  205|       |
  206|       |    // create a copy of the piNumTriPtr buffer
  207|     89|    unsigned int *const piNumTriPtr = adj.mLiveTriangles;
  208|     89|    const std::vector<unsigned int> piNumTriPtrNoModify(piNumTriPtr, piNumTriPtr + pMesh->mNumVertices);
  209|       |
  210|       |    // get the largest number of referenced triangles and allocate the "candidate buffer"
  211|     89|    unsigned int iMaxRefTris = 0;
  212|     89|    {
  213|     89|        const unsigned int *piCur = adj.mLiveTriangles;
  214|     89|        const unsigned int *const piCurEnd = adj.mLiveTriangles + pMesh->mNumVertices;
  215|   132k|        for (; piCur != piCurEnd; ++piCur) {
  ------------------
  |  Branch (215:16): [True: 132k, False: 89]
  ------------------
  216|   132k|            iMaxRefTris = std::max(iMaxRefTris, *piCur);
  217|   132k|        }
  218|     89|    }
  219|     89|    ai_assert(iMaxRefTris > 0);
  220|     89|    std::vector<unsigned int> piCandidates;
  221|     89|    piCandidates.resize(iMaxRefTris * 3);
  222|     89|    unsigned int iCacheMisses = 0;
  223|       |
  224|       |    // ...................................................................................
  225|       |    /** PSEUDOCODE for the algorithm
  226|       |
  227|       |        A = Build-Adjacency(I) Vertex-triangle adjacency
  228|       |        L = Get-Triangle-Counts(A) Per-vertex live triangle counts
  229|       |        C = Zero(Vertex-Count(I)) Per-vertex caching time stamps
  230|       |        D = Empty-Stack() Dead-end vertex stack
  231|       |        E = False(Triangle-Count(I)) Per triangle emitted flag
  232|       |        O = Empty-Index-Buffer() Empty output buffer
  233|       |        f = 0 Arbitrary starting vertex
  234|       |        s = k+1, i = 1 Time stamp and cursor
  235|       |        while f >= 0 For all valid fanning vertices
  236|       |            N = Empty-Set() 1-ring of next candidates
  237|       |            for each Triangle t in Neighbors(A, f)
  238|       |                if !Emitted(E,t)
  239|       |                    for each Vertex v in t
  240|       |                        Append(O,v) Output vertex
  241|       |                        Push(D,v) Add to dead-end stack
  242|       |                        Insert(N,v) Register as candidate
  243|       |                        L[v] = L[v]-1 Decrease live triangle count
  244|       |                        if s-C[v] > k If not in cache
  245|       |                            C[v] = s Set time stamp
  246|       |                            s = s+1 Increment time stamp
  247|       |                    E[t] = true Flag triangle as emitted
  248|       |            Select next fanning vertex
  249|       |            f = Get-Next-Vertex(I,i,k,N,C,s,L,D)
  250|       |        return O
  251|       |        */
  252|       |    // ...................................................................................
  253|       |
  254|     89|    int ivdx = 0;
  255|     89|    int ics = 1;
  256|     89|    int iStampCnt = mConfigCacheDepth + 1;
  257|  81.9k|    while (ivdx >= 0) {
  ------------------
  |  Branch (257:12): [True: 81.8k, False: 89]
  ------------------
  258|       |
  259|  81.8k|        unsigned int icnt = piNumTriPtrNoModify[ivdx];
  260|  81.8k|        unsigned int *piList = adj.GetAdjacentTriangles(ivdx);
  261|  81.8k|        std::vector<unsigned int>::iterator piCurCandidate = piCandidates.begin();
  262|       |
  263|       |        // get all triangles in the neighborhood
  264|   451k|        for (unsigned int tri = 0; tri < icnt; ++tri) {
  ------------------
  |  Branch (264:36): [True: 369k, False: 81.8k]
  ------------------
  265|       |
  266|       |            // if they have not yet been emitted, add them to the output IB
  267|   369k|            const unsigned int fidx = *piList++;
  268|   369k|            if (!abEmitted[fidx]) {
  ------------------
  |  Branch (268:17): [True: 175k, False: 193k]
  ------------------
  269|       |
  270|       |                // so iterate through all vertices of the current triangle
  271|   175k|                const aiFace *pcFace = &pMesh->mFaces[fidx];
  272|   175k|                const unsigned nind = pcFace->mNumIndices;
  273|   702k|                for (unsigned ind = 0; ind < nind; ind++) {
  ------------------
  |  Branch (273:40): [True: 527k, False: 175k]
  ------------------
  274|   527k|                    unsigned dp = pcFace->mIndices[ind];
  275|       |
  276|       |                    // the current vertex won't have any free triangles after this step
  277|   527k|                    if (ivdx != (int)dp) {
  ------------------
  |  Branch (277:25): [True: 351k, False: 175k]
  ------------------
  278|       |                        // append the vertex to the dead-end stack
  279|   351k|                        sDeadEndVStack.push(dp);
  280|       |
  281|       |                        // register as candidate for the next step
  282|   351k|                        *piCurCandidate++ = dp;
  283|       |
  284|       |                        // decrease the per-vertex triangle counts
  285|   351k|                        piNumTriPtr[dp]--;
  286|   351k|                    }
  287|       |
  288|       |                    // append the vertex to the output index buffer
  289|   527k|                    *piCSIter++ = dp;
  290|       |
  291|       |                    // if the vertex is not yet in cache, set its cache count
  292|   527k|                    if (iStampCnt - piCachingStamps[dp] > mConfigCacheDepth) {
  ------------------
  |  Branch (292:25): [True: 163k, False: 363k]
  ------------------
  293|   163k|                        piCachingStamps[dp] = iStampCnt++;
  294|   163k|                        ++iCacheMisses;
  295|   163k|                    }
  296|   527k|                }
  297|       |                // flag triangle as emitted
  298|   175k|                abEmitted[fidx] = true;
  299|   175k|            }
  300|   369k|        }
  301|       |
  302|       |        // the vertex has now no living adjacent triangles anymore
  303|  81.8k|        piNumTriPtr[ivdx] = 0;
  304|       |
  305|       |        // get next fanning vertex
  306|  81.8k|        ivdx = -1;
  307|  81.8k|        int max_priority = -1;
  308|   433k|        for (std::vector<unsigned int>::iterator piCur = piCandidates.begin(); piCur != piCurCandidate; ++piCur) {
  ------------------
  |  Branch (308:80): [True: 351k, False: 81.8k]
  ------------------
  309|   351k|            const unsigned int dp = *piCur;
  310|       |
  311|       |            // must have live triangles
  312|   351k|            if (piNumTriPtr[dp] > 0) {
  ------------------
  |  Branch (312:17): [True: 295k, False: 55.5k]
  ------------------
  313|   295k|                int priority = 0;
  314|       |
  315|       |                // will the vertex be in cache, even after fanning occurs?
  316|   295k|                unsigned int tmp;
  317|   295k|                if ((tmp = iStampCnt - piCachingStamps[dp]) + 2 * piNumTriPtr[dp] <= mConfigCacheDepth) {
  ------------------
  |  Branch (317:21): [True: 283k, False: 12.5k]
  ------------------
  318|   283k|                    priority = tmp;
  319|   283k|                }
  320|       |
  321|       |                // keep best candidate
  322|   295k|                if (priority > max_priority) {
  ------------------
  |  Branch (322:21): [True: 105k, False: 190k]
  ------------------
  323|   105k|                    max_priority = priority;
  324|   105k|                    ivdx = dp;
  325|   105k|                }
  326|   295k|            }
  327|   351k|        }
  328|       |        // did we reach a dead end?
  329|  81.8k|        if (-1 == ivdx) {
  ------------------
  |  Branch (329:13): [True: 9.13k, False: 72.7k]
  ------------------
  330|       |            // need to get a non-local vertex for which we have a good chance that it is still
  331|       |            // in the cache ...
  332|   355k|            while (!sDeadEndVStack.empty()) {
  ------------------
  |  Branch (332:20): [True: 351k, False: 4.02k]
  ------------------
  333|   351k|                unsigned int iCachedIdx = sDeadEndVStack.top();
  334|   351k|                sDeadEndVStack.pop();
  335|   351k|                if (piNumTriPtr[iCachedIdx] > 0) {
  ------------------
  |  Branch (335:21): [True: 5.10k, False: 346k]
  ------------------
  336|  5.10k|                    ivdx = iCachedIdx;
  337|  5.10k|                    break;
  338|  5.10k|                }
  339|   351k|            }
  340|       |
  341|  9.13k|            if (-1 == ivdx) {
  ------------------
  |  Branch (341:17): [True: 4.02k, False: 5.10k]
  ------------------
  342|       |                // well, there isn't such a vertex. Simply get the next vertex in input order and
  343|       |                // hope it is not too bad ...
  344|   132k|                while (ics < (int)pMesh->mNumVertices) {
  ------------------
  |  Branch (344:24): [True: 132k, False: 89]
  ------------------
  345|   132k|                    ++ics;
  346|   132k|                    if (piNumTriPtr[ics] > 0) {
  ------------------
  |  Branch (346:25): [True: 3.93k, False: 128k]
  ------------------
  347|  3.93k|                        ivdx = ics;
  348|  3.93k|                        break;
  349|  3.93k|                    }
  350|   132k|                }
  351|  4.02k|            }
  352|  9.13k|        }
  353|  81.8k|    }
  354|     89|    ai_real fACMR2 = 0.0f;
  355|     89|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (355:9): [True: 0, False: 89]
  ------------------
  356|      0|        fACMR2 = static_cast<ai_real>(iCacheMisses / pMesh->mNumFaces);
  357|      0|        const ai_real averageACMR = ((fACMR - fACMR2) / fACMR) * 100.f;
  358|       |        // very intense verbose logging ... prepare for much text if there are many meshes
  359|      0|        if (DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) {
  ------------------
  |  Branch (359:13): [True: 0, False: 0]
  ------------------
  360|      0|            ASSIMP_LOG_VERBOSE_DEBUG("Mesh ", meshNum, "| ACMR in: ", fACMR, " out: ", fACMR2, " | average ACMR ", averageACMR);
  361|      0|        }
  362|      0|        fACMR2 *= pMesh->mNumFaces;
  363|      0|    }
  364|       |
  365|       |    // sort the output index buffer back to the input array
  366|     89|    piCSIter = piIBOutput.begin();
  367|   175k|    for (aiFace *pcFace = pMesh->mFaces; pcFace != pcEnd; ++pcFace) {
  ------------------
  |  Branch (367:42): [True: 175k, False: 89]
  ------------------
  368|   175k|        unsigned nind = pcFace->mNumIndices;
  369|   175k|        unsigned *ind = pcFace->mIndices;
  370|   175k|        if (nind > 0)
  ------------------
  |  Branch (370:13): [True: 175k, False: 0]
  ------------------
  371|   175k|            ind[0] = *piCSIter++;
  372|   175k|        if (nind > 1)
  ------------------
  |  Branch (372:13): [True: 175k, False: 0]
  ------------------
  373|   175k|            ind[1] = *piCSIter++;
  374|   175k|        if (nind > 2)
  ------------------
  |  Branch (374:13): [True: 175k, False: 0]
  ------------------
  375|   175k|            ind[2] = *piCSIter++;
  376|   175k|    }
  377|       |
  378|     89|    return fACMR2;
  379|     93|}

_ZNK6Assimp19JoinVerticesProcess8IsActiveEj:
   63|    218|bool JoinVerticesProcess::IsActive( unsigned int pFlags) const {
   64|    218|    return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
   65|    218|}
_ZN6Assimp19JoinVerticesProcess7ExecuteEP7aiScene:
   68|    218|void JoinVerticesProcess::Execute( aiScene* pScene) {
   69|    218|    ASSIMP_LOG_DEBUG("JoinVerticesProcess begin");
   70|       |
   71|       |    // get the total number of vertices BEFORE the step is executed
   72|    218|    int iNumOldVertices = 0;
   73|    218|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (73:9): [True: 0, False: 218]
  ------------------
   74|      0|        for( unsigned int a = 0; a < pScene->mNumMeshes; a++)   {
  ------------------
  |  Branch (74:34): [True: 0, False: 0]
  ------------------
   75|      0|            iNumOldVertices +=  pScene->mMeshes[a]->mNumVertices;
   76|      0|        }
   77|      0|    }
   78|       |
   79|       |    // execute the step
   80|    218|    int iNumVertices = 0;
   81|    315|    for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (81:30): [True: 97, False: 218]
  ------------------
   82|     97|        iNumVertices += ProcessMesh( pScene->mMeshes[a],a);
   83|     97|    }
   84|       |
   85|    218|    pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
   86|       |
   87|       |    // if logging is active, print detailed statistics
   88|    218|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (88:9): [True: 0, False: 218]
  ------------------
   89|      0|        if (iNumOldVertices == iNumVertices) {
  ------------------
  |  Branch (89:13): [True: 0, False: 0]
  ------------------
   90|      0|            ASSIMP_LOG_DEBUG("JoinVerticesProcess finished ");
   91|      0|            return;
   92|      0|        }
   93|       |
   94|       |        // Show statistics
   95|      0|        ASSIMP_LOG_INFO("JoinVerticesProcess finished | Verts in: ", iNumOldVertices,
   96|      0|            " out: ", iNumVertices, " | ~",
   97|      0|            ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f );
   98|      0|    }
   99|    218|}
_ZN6Assimp19JoinVerticesProcess11ProcessMeshEP6aiMeshj:
  225|     97|int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
  226|     97|    static_assert( AI_MAX_NUMBER_OF_COLOR_SETS    == 8, "AI_MAX_NUMBER_OF_COLOR_SETS    == 8");
  227|     97|	static_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 8, "AI_MAX_NUMBER_OF_TEXTURECOORDS == 8");
  228|       |
  229|       |    // Return early if we don't have any positions
  230|     97|    if (!pMesh->HasPositions() || !pMesh->HasFaces()) {
  ------------------
  |  Branch (230:9): [True: 0, False: 97]
  |  Branch (230:35): [True: 0, False: 97]
  ------------------
  231|      0|        return 0;
  232|      0|    }
  233|       |
  234|       |    // We should care only about used vertices, not all of them
  235|       |    // (this can happen due to original file vertices buffer being used by
  236|       |    // multiple meshes)
  237|     97|    std::vector<bool> usedVertexIndicesMask;
  238|     97|    usedVertexIndicesMask.resize(pMesh->mNumVertices, false);
  239|   181k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (239:30): [True: 181k, False: 97]
  ------------------
  240|   181k|        aiFace& face = pMesh->mFaces[a];
  241|   725k|        for (unsigned int b = 0; b < face.mNumIndices; b++) {
  ------------------
  |  Branch (241:34): [True: 544k, False: 181k]
  ------------------
  242|   544k|            usedVertexIndicesMask[face.mIndices[b]] = true;
  243|   544k|        }
  244|   181k|    }
  245|       |
  246|       |    // We'll never have more vertices afterwards.
  247|     97|    std::vector<int> uniqueVertices;
  248|       |
  249|       |    // For each vertex the index of the vertex it was replaced by.
  250|       |    // Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark
  251|       |    //  whether a new vertex was created for the index (true) or if it was replaced by an existing
  252|       |    //  unique vertex (false). This saves an additional std::vector<bool> and greatly enhances
  253|       |    //  branching performance.
  254|     97|    static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
  255|     97|    std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
  256|       |
  257|       |    // Run an optimized code path if we don't have multiple UVs or vertex colors.
  258|       |    // This should yield false in more than 99% of all imports ...
  259|     97|    const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
  260|       |
  261|       |    // We'll never have more vertices afterwards.
  262|     97|    std::vector<std::vector<int>> uniqueAnimatedVertices;
  263|     97|    if (hasAnimMeshes) {
  ------------------
  |  Branch (263:9): [True: 0, False: 97]
  ------------------
  264|      0|        uniqueAnimatedVertices.resize(pMesh->mNumAnimMeshes);
  265|      0|        for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
  ------------------
  |  Branch (265:46): [True: 0, False: 0]
  ------------------
  266|      0|            uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices);
  267|      0|        }
  268|      0|    }
  269|       |    // a map that maps a vertex to its new index
  270|     97|    std::unordered_map<Vertex, int, HashVertex, CompareVerticesAlmostEqual> vertex2Index = {};
  271|       |    // we can not end up with more vertices than we started with
  272|       |    // Now check each vertex if it brings something new to the table
  273|     97|    int newIndex = 0;
  274|   369k|    for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
  ------------------
  |  Branch (274:30): [True: 369k, False: 97]
  ------------------
  275|       |        // if the vertex is unused Do nothing
  276|   369k|        if (!usedVertexIndicesMask[a]) {
  ------------------
  |  Branch (276:13): [True: 4, False: 369k]
  ------------------
  277|      4|            continue;
  278|      4|        }
  279|       |        // collect the vertex data
  280|   369k|        Vertex v(pMesh,a);
  281|       |        // is the vertex already in the map?
  282|   369k|        auto it = vertex2Index.find(v);
  283|       |        // if the vertex is not in the map then it is a new vertex add it.
  284|   369k|        if (it == vertex2Index.end()) {
  ------------------
  |  Branch (284:13): [True: 132k, False: 236k]
  ------------------
  285|       |            // this is a new vertex give it a new index
  286|   132k|            vertex2Index.emplace(v, newIndex);
  287|       |            // keep track of its index and increment 1
  288|   132k|            replaceIndex[a] = newIndex++;
  289|       |            // add the vertex to the unique vertices
  290|   132k|            uniqueVertices.push_back(a);
  291|   132k|            if (hasAnimMeshes) {
  ------------------
  |  Branch (291:17): [True: 0, False: 132k]
  ------------------
  292|      0|                for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
  ------------------
  |  Branch (292:54): [True: 0, False: 0]
  ------------------
  293|      0|                    uniqueAnimatedVertices[animMeshIndex].emplace_back(a);
  294|      0|                }
  295|      0|            }
  296|   236k|        } else{
  297|       |            // if the vertex is already there just find the replace index that is appropriate to it
  298|       |			// mark it with JOINED_VERTICES_MARK
  299|   236k|            replaceIndex[a] = it->second | JOINED_VERTICES_MARK;
  300|   236k|        }
  301|   369k|    }
  302|       |
  303|     97|    if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE)    {
  ------------------
  |  Branch (303:9): [True: 0, False: 97]
  |  Branch (303:43): [True: 0, False: 0]
  ------------------
  304|      0|        ASSIMP_LOG_VERBOSE_DEBUG(
  ------------------
  |  Branch (304:9): [True: 0, False: 0]
  ------------------
  305|      0|            "Mesh ",meshIndex,
  306|      0|            " (",
  307|      0|            (pMesh->mName.length ? pMesh->mName.data : "unnamed"),
  308|      0|            ") | Verts in: ",pMesh->mNumVertices,
  309|      0|            " out: ",
  310|      0|            uniqueVertices.size(),
  311|      0|            " | ~",
  312|      0|            ((pMesh->mNumVertices - uniqueVertices.size()) / (float)pMesh->mNumVertices) * 100.f,
  313|      0|            "%"
  314|      0|        );
  315|      0|    }
  316|       |
  317|     97|    updateXMeshVertices(pMesh, uniqueVertices);
  318|     97|    if (hasAnimMeshes) {
  ------------------
  |  Branch (318:9): [True: 0, False: 97]
  ------------------
  319|      0|        for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
  ------------------
  |  Branch (319:46): [True: 0, False: 0]
  ------------------
  320|      0|            updateXMeshVertices(pMesh->mAnimMeshes[animMeshIndex], uniqueAnimatedVertices[animMeshIndex]);
  321|      0|        }
  322|      0|    }
  323|       |
  324|       |    // adjust the indices in all faces
  325|   181k|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (325:30): [True: 181k, False: 97]
  ------------------
  326|   181k|        aiFace& face = pMesh->mFaces[a];
  327|   725k|        for( unsigned int b = 0; b < face.mNumIndices; b++) {
  ------------------
  |  Branch (327:34): [True: 544k, False: 181k]
  ------------------
  328|   544k|            face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~JOINED_VERTICES_MARK;
  329|   544k|        }
  330|   181k|    }
  331|       |
  332|       |    // adjust bone vertex weights.
  333|    790|    for( int a = 0; a < (int)pMesh->mNumBones; a++) {
  ------------------
  |  Branch (333:21): [True: 693, False: 97]
  ------------------
  334|    693|        aiBone* bone = pMesh->mBones[a];
  335|    693|        std::vector<aiVertexWeight> newWeights;
  336|    693|        newWeights.reserve( bone->mNumWeights);
  337|       |
  338|    693|        if (nullptr != bone->mWeights) {
  ------------------
  |  Branch (338:13): [True: 693, False: 0]
  ------------------
  339|   965k|            for ( unsigned int b = 0; b < bone->mNumWeights; b++ ) {
  ------------------
  |  Branch (339:39): [True: 964k, False: 693]
  ------------------
  340|   964k|                const aiVertexWeight& ow = bone->mWeights[ b ];
  341|       |                // if the vertex is a unique one, translate it
  342|       |				// filter out joined vertices by JOINED_VERTICES_MARK.
  343|   964k|                if ( !( replaceIndex[ ow.mVertexId ] & JOINED_VERTICES_MARK ) ) {
  ------------------
  |  Branch (343:22): [True: 366k, False: 598k]
  ------------------
  344|   366k|                    aiVertexWeight nw;
  345|   366k|                    nw.mVertexId = replaceIndex[ ow.mVertexId ];
  346|   366k|                    nw.mWeight = ow.mWeight;
  347|   366k|                    newWeights.push_back( nw );
  348|   366k|                }
  349|   964k|            }
  350|    693|        } else {
  351|      0|            ASSIMP_LOG_ERROR( "X-Export: aiBone shall contain weights, but pointer to them is nullptr." );
  352|      0|        }
  353|       |
  354|    693|        if (newWeights.size() > 0) {
  ------------------
  |  Branch (354:13): [True: 693, False: 0]
  ------------------
  355|       |            // kill the old and replace them with the translated weights
  356|    693|            delete [] bone->mWeights;
  357|    693|            bone->mNumWeights = (unsigned int)newWeights.size();
  358|       |
  359|    693|            bone->mWeights = new aiVertexWeight[bone->mNumWeights];
  360|    693|            memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
  361|    693|        }
  362|    693|    }
  363|     97|    return pMesh->mNumVertices;
  364|     97|}
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_110HashVertexclERKN6Assimp6VertexE:
  151|   501k|    size_t operator () (const Vertex & v) const {
  152|   501k|        size_t hash = 0;
  153|       |
  154|   501k|        hash_combine(hash, v.position.x);
  155|   501k|        hash_combine(hash, v.position.y);
  156|   501k|        hash_combine(hash, v.position.z);
  157|       |
  158|   501k|        return hash;
  159|   501k|    }
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_110HashVertex12hash_combineERmRKf:
  146|  1.50M|    inline void hash_combine(std::size_t& seed, const ai_real& v) const {
  147|  1.50M|        std::hash<ai_real> hasher;
  148|  1.50M|        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  149|  1.50M|    }
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_126CompareVerticesAlmostEqualclERKN6Assimp6VertexES4_:
  104|   373k|    bool operator () (const Vertex & a, const Vertex & b) const {
  105|   373k|        static const float epsilon = 1e-5f;
  106|   373k|        static const float squareEpsilon = epsilon * epsilon;
  107|       |
  108|   373k|        if ((a.position - b.position).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (108:13): [True: 0, False: 373k]
  ------------------
  109|      0|            return false;
  110|      0|        }
  111|       |
  112|       |        // We just test the other attributes even if they're not present in the mesh.
  113|       |        // In this case they're initialized to 0 so the comparison succeeds.
  114|       |        // By this method the non-present attributes are effectively ignored in the comparison.
  115|       |
  116|   373k|        if ((a.normal - b.normal).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (116:13): [True: 85.8k, False: 287k]
  ------------------
  117|  85.8k|            return false;
  118|  85.8k|        }
  119|       |
  120|   287k|        if ((a.tangent - b.tangent).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (120:13): [True: 49.7k, False: 237k]
  ------------------
  121|  49.7k|            return false;
  122|  49.7k|        }
  123|       |
  124|   237k|        if ((a.bitangent - b.bitangent).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (124:13): [True: 34, False: 237k]
  ------------------
  125|     34|            return false;
  126|     34|        }
  127|       |
  128|  2.12M|        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i ++) {
  ------------------
  |  Branch (128:30): [True: 1.89M, False: 236k]
  ------------------
  129|  1.89M|            if ((a.texcoords[i] - b.texcoords[i]).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (129:17): [True: 1.55k, False: 1.88M]
  ------------------
  130|  1.55k|                return false;
  131|  1.55k|            }
  132|  1.89M|        }
  133|       |
  134|  2.12M|        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; i ++) {
  ------------------
  |  Branch (134:30): [True: 1.88M, False: 236k]
  ------------------
  135|  1.88M|            if (GetColorDifference(a.colors[i], b.colors[i]) > squareEpsilon) {
  ------------------
  |  Branch (135:17): [True: 0, False: 1.88M]
  ------------------
  136|      0|                return false;
  137|      0|            }
  138|  1.88M|        }
  139|       |
  140|       |        // If reached this point, they are ~equal
  141|   236k|        return true;
  142|   236k|    }
JoinVerticesProcess.cpp:_ZN12_GLOBAL__N_119updateXMeshVerticesI6aiMeshEEvPT_RNSt3__16vectorIiNS4_9allocatorIiEEEE:
  163|     97|void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
  164|       |    // replace vertex data with the unique data sets
  165|     97|    pMesh->mNumVertices = (unsigned int)uniqueVertices.size();
  166|       |
  167|       |    // ----------------------------------------------------------------------------
  168|       |    // NOTE - we're *not* calling Vertex::SortBack() because it would check for
  169|       |    // presence of every single vertex component once PER VERTEX. And our CPU
  170|       |    // dislikes branches, even if they're easily predictable.
  171|       |    // ----------------------------------------------------------------------------
  172|       |
  173|       |    // Position, if present (check made for aiAnimMesh)
  174|     97|    if (pMesh->mVertices) {
  ------------------
  |  Branch (174:9): [True: 97, False: 0]
  ------------------
  175|     97|        std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
  176|     97|        pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  177|   132k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (177:34): [True: 132k, False: 97]
  ------------------
  178|   132k|            pMesh->mVertices[a] = oldVertices[uniqueVertices[a]];
  179|     97|    }
  180|       |
  181|       |    // Normals, if present
  182|     97|    if (pMesh->mNormals) {
  ------------------
  |  Branch (182:9): [True: 93, False: 4]
  ------------------
  183|     93|        std::unique_ptr<aiVector3D[]> oldNormals(pMesh->mNormals);
  184|     93|        pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  185|   132k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (185:34): [True: 132k, False: 93]
  ------------------
  186|   132k|            pMesh->mNormals[a] = oldNormals[uniqueVertices[a]];
  187|     93|    }
  188|       |    // Tangents, if present
  189|     97|    if (pMesh->mTangents) {
  ------------------
  |  Branch (189:9): [True: 77, False: 20]
  ------------------
  190|     77|        std::unique_ptr<aiVector3D[]> oldTangents(pMesh->mTangents);
  191|     77|        pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  192|   118k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (192:34): [True: 118k, False: 77]
  ------------------
  193|   118k|            pMesh->mTangents[a] = oldTangents[uniqueVertices[a]];
  194|     77|    }
  195|       |    // Bitangents as well
  196|     97|    if (pMesh->mBitangents) {
  ------------------
  |  Branch (196:9): [True: 77, False: 20]
  ------------------
  197|     77|        std::unique_ptr<aiVector3D[]> oldBitangents(pMesh->mBitangents);
  198|     77|        pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  199|   118k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (199:34): [True: 118k, False: 77]
  ------------------
  200|   118k|            pMesh->mBitangents[a] = oldBitangents[uniqueVertices[a]];
  201|     77|    }
  202|       |    // Vertex colors
  203|     97|    for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) {
  ------------------
  |  Branch (203:30): [True: 0, False: 97]
  ------------------
  204|      0|        std::unique_ptr<aiColor4D[]> oldColors(pMesh->mColors[a]);
  205|      0|        pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
  206|      0|        for (unsigned int b = 0; b < pMesh->mNumVertices; b++)
  ------------------
  |  Branch (206:34): [True: 0, False: 0]
  ------------------
  207|      0|            pMesh->mColors[a][b] = oldColors[uniqueVertices[b]];
  208|      0|    }
  209|       |    // Texture coords
  210|    175|    for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) {
  ------------------
  |  Branch (210:30): [True: 78, False: 97]
  ------------------
  211|     78|        std::unique_ptr<aiVector3D[]> oldTextureCoords(pMesh->mTextureCoords[a]);
  212|     78|        pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
  213|   118k|        for (unsigned int b = 0; b < pMesh->mNumVertices; b++)
  ------------------
  |  Branch (213:34): [True: 118k, False: 78]
  ------------------
  214|   118k|            pMesh->mTextureCoords[a][b] = oldTextureCoords[uniqueVertices[b]];
  215|     78|    }
  216|     97|}

_ZN6Assimp19JoinVerticesProcessC2Ev:
   67|    297|    JoinVerticesProcess() = default;

_ZN6Assimp23LimitBoneWeightsProcessC2Ev:
   57|    297|        mMaxWeights(AI_LMW_MAX_WEIGHTS), mRemoveEmptyBones(true) {
   58|       |    // empty
   59|    297|}
_ZNK6Assimp23LimitBoneWeightsProcess8IsActiveEj:
   63|    218|bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const {
   64|    218|    return (pFlags & aiProcess_LimitBoneWeights) != 0;
   65|    218|}
_ZN6Assimp23LimitBoneWeightsProcess7ExecuteEP7aiScene:
   69|    218|void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
   70|    218|    ai_assert(pScene != nullptr);
   71|       |
   72|    218|    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin");
   73|       |
   74|    315|    for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
  ------------------
  |  Branch (74:30): [True: 97, False: 218]
  ------------------
   75|     97|        ProcessMesh(pScene->mMeshes[m]);
   76|     97|    }
   77|       |
   78|       |    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end");
   79|    218|}
_ZN6Assimp23LimitBoneWeightsProcess15SetupPropertiesEPKNS_8ImporterE:
   83|    218|void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) {
   84|    218|    this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
   85|       |    this->mRemoveEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, 1) != 0;
   86|    218|}
_ZN6Assimp23LimitBoneWeightsProcess11ProcessMeshEP6aiMesh:
  107|     97|void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) {
  108|     97|    if (!pMesh->HasBones())
  ------------------
  |  Branch (108:9): [True: 15, False: 82]
  ------------------
  109|     15|        return;
  110|       |
  111|       |    // collect all bone weights per vertex
  112|     82|    typedef SmallVector<Weight,8> VertexWeightArray;
  113|     82|    typedef std::vector<VertexWeightArray> WeightsPerVertex;
  114|     82|    WeightsPerVertex vertexWeights(pMesh->mNumVertices);
  115|     82|    size_t maxVertexWeights = 0;
  116|       |
  117|    775|    for (unsigned int b = 0; b < pMesh->mNumBones; ++b) {
  ------------------
  |  Branch (117:30): [True: 693, False: 82]
  ------------------
  118|    693|        const aiBone* bone = pMesh->mBones[b];
  119|   367k|        for (unsigned int w = 0; w < bone->mNumWeights; ++w) {
  ------------------
  |  Branch (119:34): [True: 366k, False: 693]
  ------------------
  120|   366k|            const aiVertexWeight& vw = bone->mWeights[w];
  121|       |
  122|   366k|            if (vertexWeights.size() <= vw.mVertexId)
  ------------------
  |  Branch (122:17): [True: 0, False: 366k]
  ------------------
  123|      0|                continue;
  124|       |
  125|   366k|            vertexWeights[vw.mVertexId].push_back(Weight(b, vw.mWeight));
  126|   366k|            maxVertexWeights = std::max(maxVertexWeights, vertexWeights[vw.mVertexId].size());
  127|   366k|        }
  128|    693|    }
  129|       |
  130|     82|    if (maxVertexWeights <= mMaxWeights)
  ------------------
  |  Branch (130:9): [True: 30, False: 52]
  ------------------
  131|     30|        return;
  132|       |
  133|     52|    unsigned int removed = 0, old_bones = pMesh->mNumBones;
  134|       |
  135|       |    // now cut the weight count if it exceeds the maximum
  136|  85.8k|    for (WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) {
  ------------------
  |  Branch (136:66): [True: 85.8k, False: 52]
  ------------------
  137|  85.8k|        if (vit->size() <= mMaxWeights)
  ------------------
  |  Branch (137:13): [True: 67.5k, False: 18.3k]
  ------------------
  138|  67.5k|            continue;
  139|       |
  140|       |        // more than the defined maximum -> first sort by weight in descending order. That's
  141|       |        // why we defined the < operator in such a weird way.
  142|  18.3k|        std::sort(vit->begin(), vit->end());
  143|       |
  144|       |        // now kill everything beyond the maximum count
  145|  18.3k|        unsigned int m = static_cast<unsigned int>(vit->size());
  146|  18.3k|        vit->resize(mMaxWeights);
  147|  18.3k|        removed += static_cast<unsigned int>(m - vit->size());
  148|       |
  149|       |        // and renormalize the weights
  150|  18.3k|        float sum = 0.0f;
  151|  91.5k|        for(const Weight* it = vit->begin(); it != vit->end(); ++it) {
  ------------------
  |  Branch (151:46): [True: 73.2k, False: 18.3k]
  ------------------
  152|  73.2k|            sum += it->mWeight;
  153|  73.2k|        }
  154|  18.3k|        if (0.0f != sum) {
  ------------------
  |  Branch (154:13): [True: 18.3k, False: 0]
  ------------------
  155|  18.3k|            const float invSum = 1.0f / sum;
  156|  91.5k|            for(Weight* it = vit->begin(); it != vit->end(); ++it) {
  ------------------
  |  Branch (156:44): [True: 73.2k, False: 18.3k]
  ------------------
  157|  73.2k|                it->mWeight *= invSum;
  158|  73.2k|            }
  159|  18.3k|        }
  160|  18.3k|    }
  161|       |
  162|       |    // clear weight count for all bone
  163|    568|    for (unsigned int a = 0; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (163:30): [True: 516, False: 52]
  ------------------
  164|    516|        pMesh->mBones[a]->mNumWeights = 0;
  165|    516|    }
  166|       |
  167|       |    // rebuild the vertex weight array for all bones
  168|  85.8k|    for (unsigned int a = 0; a < vertexWeights.size(); ++a) {
  ------------------
  |  Branch (168:30): [True: 85.8k, False: 52]
  ------------------
  169|  85.8k|        const VertexWeightArray& vw = vertexWeights[a];
  170|   352k|        for (const Weight* it = vw.begin(); it != vw.end(); ++it) {
  ------------------
  |  Branch (170:45): [True: 266k, False: 85.8k]
  ------------------
  171|   266k|            aiBone* bone = pMesh->mBones[it->mBone];
  172|   266k|            bone->mWeights[bone->mNumWeights++] = aiVertexWeight(a, it->mWeight);
  173|   266k|        }
  174|  85.8k|    }
  175|       |
  176|       |    // remove empty bones
  177|     52|    if (mRemoveEmptyBones) {
  ------------------
  |  Branch (177:9): [True: 52, False: 0]
  ------------------
  178|     52|        pMesh->mNumBones = removeEmptyBones(pMesh);
  179|     52|    }
  180|       |
  181|     52|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (181:9): [True: 0, False: 52]
  ------------------
  182|       |        ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones);
  183|      0|    }
  184|     52|}
LimitBoneWeightsProcess.cpp:_ZN6AssimpL16removeEmptyBonesEP6aiMesh:
   89|     52|static unsigned int removeEmptyBones(aiMesh *pMesh) {
   90|     52|    ai_assert(pMesh != nullptr);
   91|       |
   92|     52|    unsigned int writeBone = 0;
   93|    568|    for (unsigned int readBone = 0; readBone< pMesh->mNumBones; ++readBone) {
  ------------------
  |  Branch (93:37): [True: 516, False: 52]
  ------------------
   94|    516|        aiBone* bone = pMesh->mBones[readBone];
   95|    516|        if (bone->mNumWeights > 0) {
  ------------------
  |  Branch (95:13): [True: 499, False: 17]
  ------------------
   96|    499|            pMesh->mBones[writeBone++] = bone;
   97|    499|        } else {
   98|     17|            delete bone;
   99|     17|        }
  100|    516|    }
  101|       |
  102|     52|    return writeBone;
  103|     52|}

_ZN6Assimp23LimitBoneWeightsProcess6WeightC2Ev:
  116|  1.03M|        : mBone(0)
  117|  1.03M|        , mWeight(0.0f) {
  118|       |            // empty
  119|  1.03M|        }
_ZN6Assimp23LimitBoneWeightsProcess6WeightC2Ejf:
  122|   366k|        : mBone(pBone)
  123|   366k|        , mWeight(pWeight) {
  124|       |            // empty
  125|   366k|        }
_ZNK6Assimp23LimitBoneWeightsProcess6WeightltERKS1_:
  128|   126k|        bool operator < (const Weight& pWeight) const {
  129|   126k|            return mWeight > pWeight.mWeight;
  130|   126k|        }

_ZN6Assimp20OptimizeGraphProcessC2Ev:
   77|    297|		count_merged() {
   78|       |	// empty
   79|    297|}
_ZNK6Assimp20OptimizeGraphProcess8IsActiveEj:
   83|    218|bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const {
   84|    218|	return (0 != (pFlags & aiProcess_OptimizeGraph));
   85|    218|}

_ZN6Assimp20OptimizeGraphProcessD2Ev:
   76|    297|    ~OptimizeGraphProcess() override = default;

_ZN6Assimp21OptimizeMeshesProcessC2Ev:
   66|    297|    , pts(false)
   67|    297|    , max_verts( NotSet )
   68|    297|    , max_faces( NotSet ) {
   69|       |    // empty
   70|    297|}
_ZNK6Assimp21OptimizeMeshesProcess8IsActiveEj:
   75|    218|{
   76|       |    // Our behaviour needs to be different if the SortByPType or SplitLargeMeshes
   77|       |    // steps are active. Thus we need to query their flags here and store the
   78|       |    // information, although we're breaking const-correctness.
   79|       |    // That's a serious design flaw, consider redesign.
   80|    218|    if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
  ------------------
  |  Branch (80:9): [True: 0, False: 218]
  ------------------
   81|      0|        pts = (0 != (pFlags & aiProcess_SortByPType));
   82|      0|        max_verts = ( 0 != ( pFlags & aiProcess_SplitLargeMeshes ) ) ? DeadBeef : max_verts;
  ------------------
  |  Branch (82:21): [True: 0, False: 0]
  ------------------
   83|      0|        return true;
   84|      0|    }
   85|    218|    return false;
   86|    218|}

_ZN6Assimp21OptimizeMeshesProcessD2Ev:
   73|    297|    ~OptimizeMeshesProcess() override = default;

_ZN6Assimp20PretransformVerticesC2Ev:
   90|    297|		mConfigKeepHierarchy(false),
   91|    297|		mConfigNormalize(false),
   92|    297|		mConfigTransform(false),
   93|    297|		mConfigTransformation(),
   94|    297|		mConfigPointCloud(false) {}
_ZNK6Assimp20PretransformVertices8IsActiveEj:
   98|    218|bool PretransformVertices::IsActive(unsigned int pFlags) const {
   99|    218|	return (pFlags & aiProcess_PreTransformVertices) != 0;
  100|    218|}

_ZN6Assimp22ComputePositionEpsilonEPK6aiMesh:
  136|     97|ai_real ComputePositionEpsilon(const aiMesh *pMesh) {
  137|     97|    const ai_real epsilon = ai_real(1e-4);
  138|       |
  139|       |    // calculate the position bounds so we have a reliable epsilon to check position differences against
  140|     97|    aiVector3D minVec, maxVec;
  141|     97|    ArrayBounds(pMesh->mVertices, pMesh->mNumVertices, minVec, maxVec);
  142|     97|    return (maxVec - minVec).Length() * epsilon;
  143|     97|}
_ZN6Assimp28ComputeVertexBoneWeightTableEPK6aiMesh:
  199|      4|VertexWeightTable *ComputeVertexBoneWeightTable(const aiMesh *pMesh) {
  200|      4|    if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
  ------------------
  |  Branch (200:9): [True: 0, False: 4]
  |  Branch (200:19): [True: 0, False: 4]
  |  Branch (200:43): [True: 4, False: 0]
  ------------------
  201|      4|        return nullptr;
  202|      4|    }
  203|       |
  204|      0|    VertexWeightTable *avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
  205|      0|    for (unsigned int i = 0; i < pMesh->mNumBones; ++i) {
  ------------------
  |  Branch (205:30): [True: 0, False: 0]
  ------------------
  206|       |
  207|      0|        aiBone *bone = pMesh->mBones[i];
  208|      0|        for (unsigned int a = 0; a < bone->mNumWeights; ++a) {
  ------------------
  |  Branch (208:34): [True: 0, False: 0]
  ------------------
  209|      0|            const aiVertexWeight &weight = bone->mWeights[a];
  210|      0|            avPerVertexWeights[weight.mVertexId].emplace_back(i, weight.mWeight);
  211|      0|        }
  212|      0|    }
  213|      0|    return avPerVertexWeights;
  214|      4|}

_ZNK6Assimp25ComputeSpatialSortProcess8IsActiveEj:
  337|    218|    bool IsActive(unsigned int pFlags) const {
  338|    218|        return nullptr != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace |
  ------------------
  |  Branch (338:16): [True: 218, False: 0]
  |  Branch (338:37): [True: 218, False: 0]
  ------------------
  339|    218|                                                           aiProcess_GenNormals | aiProcess_JoinIdenticalVertices));
  340|    218|    }
_ZN6Assimp25ComputeSpatialSortProcess7ExecuteEP7aiScene:
  342|    218|    void Execute(aiScene *pScene) {
  343|    218|        typedef std::pair<SpatialSort, ai_real> _Type;
  344|    218|        ASSIMP_LOG_DEBUG("Generate spatially-sorted vertex cache");
  345|       |
  346|    218|        std::vector<_Type> *p = new std::vector<_Type>(pScene->mNumMeshes);
  347|    218|        std::vector<_Type>::iterator it = p->begin();
  348|       |
  349|    315|        for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++it) {
  ------------------
  |  Branch (349:34): [True: 97, False: 218]
  ------------------
  350|     97|            aiMesh *mesh = pScene->mMeshes[i];
  351|     97|            _Type &blubb = *it;
  352|     97|            blubb.first.Fill(mesh->mVertices, mesh->mNumVertices, sizeof(aiVector3D));
  353|     97|            blubb.second = ComputePositionEpsilon(mesh);
  354|     97|        }
  355|       |
  356|    218|        shared->AddProperty(AI_SPP_SPATIAL_SORT, p);
  ------------------
  |  |  166|    218|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  357|    218|    }
_ZNK6Assimp25DestroySpatialSortProcess8IsActiveEj:
  363|    218|    bool IsActive(unsigned int pFlags) const {
  364|    218|        return nullptr != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace |
  ------------------
  |  Branch (364:16): [True: 218, False: 0]
  |  Branch (364:37): [True: 218, False: 0]
  ------------------
  365|    218|                                                        aiProcess_GenNormals | aiProcess_JoinIdenticalVertices));
  366|    218|    }
_ZN6Assimp25DestroySpatialSortProcess7ExecuteEP7aiScene:
  368|    218|    void Execute(aiScene * /*pScene*/) {
  369|    218|        shared->RemoveProperty(AI_SPP_SPATIAL_SORT);
  ------------------
  |  |  166|    218|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  370|    218|    }
_ZN6Assimp18GetColorDifferenceERK9aiColor4tIfES3_:
  250|  1.88M|inline ai_real GetColorDifference(const aiColor4D &pColor1, const aiColor4D &pColor2) {
  251|  1.88M|    const aiColor4D c(pColor1.r - pColor2.r, pColor1.g - pColor2.g, pColor1.b - pColor2.b, pColor1.a - pColor2.a);
  252|  1.88M|    return c.r * c.r + c.g * c.g + c.b * c.b + c.a * c.a;
  253|  1.88M|}
_ZSt3minIfE10aiVector3tIT_ERKS2_S4_:
   67|   369k|inline ::aiVector3t<TReal> min(const ::aiVector3t<TReal> &a, const ::aiVector3t<TReal> &b) {
   68|   369k|    return ::aiVector3t<TReal>(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
   69|   369k|}
_ZSt3maxIfE10aiVector3tIT_ERKS2_S4_:
   73|   369k|inline ::aiVector3t<TReal> max(const ::aiVector3t<TReal> &a, const ::aiVector3t<TReal> &b) {
   74|   369k|    return ::aiVector3t<TReal>(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
   75|   369k|}
_ZN6Assimp13MinMaxChooserI10aiVector3tIfEEclERS2_S4_:
  177|     97|    void operator()(aiVector3t<T> &min, aiVector3t<T> &max) {
  178|     97|        max = aiVector3t<T>(-1e10f, -1e10f, -1e10f);
  179|     97|        min = aiVector3t<T>(1e10f, 1e10f, 1e10f);
  180|     97|    }
_ZN6Assimp11ArrayBoundsI10aiVector3tIfEEEvPKT_jRS3_S6_:
  236|     97|inline void ArrayBounds(const T *in, unsigned int size, T &min, T &max) {
  237|     97|    MinMaxChooser<T>()(min, max);
  238|   369k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (238:30): [True: 369k, False: 97]
  ------------------
  239|   369k|        min = std::min(in[i], min);
  240|   369k|        max = std::max(in[i], max);
  241|   369k|    }
  242|     97|}

_ZN6Assimp26RemoveRedundantMatsProcessC2Ev:
   57|    297|RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() : mConfigFixedMaterials() {}
_ZNK6Assimp26RemoveRedundantMatsProcess8IsActiveEj:
   61|    218|bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const {
   62|    218|    return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
   63|    218|}
_ZN6Assimp26RemoveRedundantMatsProcess15SetupPropertiesEPKNS_8ImporterE:
   67|    218|void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) {
   68|       |    // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST
   69|       |    mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,"");
   70|    218|}
_ZN6Assimp26RemoveRedundantMatsProcess7ExecuteEP7aiScene:
   74|    218|void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
   75|    218|    ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
   76|       |
   77|    218|    unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
   78|    218|    if (pScene->mNumMaterials == 0) {
  ------------------
  |  Branch (78:9): [True: 127, False: 91]
  ------------------
   79|    127|        return;
   80|    127|    }
   81|       |
   82|       |    // Find out which materials are referenced by meshes
   83|     91|    std::vector<bool> abReferenced(pScene->mNumMaterials,false);
   84|    185|    for (unsigned int i = 0;i < pScene->mNumMeshes;++i) {
  ------------------
  |  Branch (84:29): [True: 94, False: 91]
  ------------------
   85|     94|        abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
   86|     94|    }
   87|       |
   88|       |    // If a list of materials to be excluded was given, match the list with
   89|       |    // our imported materials and 'salt' all positive matches to ensure that
   90|       |    // we get unique hashes later.
   91|     91|    if (mConfigFixedMaterials.length()) {
  ------------------
  |  Branch (91:9): [True: 0, False: 91]
  ------------------
   92|      0|        std::list<std::string> strings;
   93|      0|        ConvertListToStrings(mConfigFixedMaterials,strings);
   94|       |
   95|      0|        for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
  ------------------
  |  Branch (95:34): [True: 0, False: 0]
  ------------------
   96|      0|            aiMaterial* mat = pScene->mMaterials[i];
   97|      0|            ai_assert(mat != nullptr);
   98|      0|            aiString name;
   99|      0|            mat->Get(AI_MATKEY_NAME,name);
  100|       |
  101|      0|            if (name.length != 0) {
  ------------------
  |  Branch (101:17): [True: 0, False: 0]
  ------------------
  102|      0|                std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data);
  103|      0|                if (it != strings.end()) {
  ------------------
  |  Branch (103:21): [True: 0, False: 0]
  ------------------
  104|       |                    // Our brilliant 'salt': A single material property with ~ as first
  105|       |                    // character to mark it as internal and temporary.
  106|      0|                    const int dummy = 1;
  107|      0|                    ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0);
  108|       |
  109|       |                    // Keep this material even if no mesh references it
  110|      0|                    abReferenced[i] = true;
  111|      0|                    ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'");
  112|      0|                }
  113|      0|            }
  114|      0|        }
  115|      0|    }
  116|       |
  117|       |    // TODO: re-implement this algorithm to work in-place
  118|     91|    unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials];
  119|    183|    for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) {
  ------------------
  |  Branch (119:29): [True: 92, False: 91]
  ------------------
  120|     92|        aiMappingTable[ i ] = 0;
  121|     92|    }
  122|     91|    unsigned int iNewNum = 0;
  123|       |
  124|       |    // Iterate through all materials and calculate a hash for them
  125|       |    // store all hashes in a list and so a quick search whether
  126|       |    // we do already have a specific hash. This allows us to
  127|       |    // determine which materials are identical.
  128|     91|    uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];
  129|    183|    for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
  ------------------
  |  Branch (129:30): [True: 92, False: 91]
  ------------------
  130|       |        // No mesh is referencing this material, remove it.
  131|     92|        if (!abReferenced[i]) {
  ------------------
  |  Branch (131:13): [True: 0, False: 92]
  ------------------
  132|      0|            ++unreferencedRemoved;
  133|      0|            delete pScene->mMaterials[i];
  134|      0|            pScene->mMaterials[i] = nullptr;
  135|      0|            continue;
  136|      0|        }
  137|       |
  138|       |        // Check all previously mapped materials for a matching hash.
  139|       |        // On a match we can delete this material and just make it ref to the same index.
  140|     92|        uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
  141|     93|        for (unsigned int a = 0; a < i;++a) {
  ------------------
  |  Branch (141:34): [True: 1, False: 92]
  ------------------
  142|      1|            if (abReferenced[a] && me == aiHashes[a]) {
  ------------------
  |  Branch (142:17): [True: 1, False: 0]
  |  Branch (142:17): [True: 0, False: 1]
  |  Branch (142:36): [True: 0, False: 1]
  ------------------
  143|      0|                ++redundantRemoved;
  144|      0|                me = 0;
  145|      0|                aiMappingTable[i] = aiMappingTable[a];
  146|      0|                delete pScene->mMaterials[i];
  147|      0|                pScene->mMaterials[i] = nullptr;
  148|      0|                break;
  149|      0|            }
  150|      1|        }
  151|       |        // This is a new material that is referenced, add to the map.
  152|     92|        if (me) {
  ------------------
  |  Branch (152:13): [True: 92, False: 0]
  ------------------
  153|     92|            aiMappingTable[i] = iNewNum++;
  154|     92|        }
  155|     92|    }
  156|       |    // If the new material count differs from the original,
  157|       |    // we need to rebuild the material list and remap mesh material indexes.
  158|     91|    if (iNewNum < 1) {
  ------------------
  |  Branch (158:9): [True: 0, False: 91]
  ------------------
  159|      0|        delete [] aiMappingTable;
  160|      0|        delete [] aiHashes;
  161|      0|        pScene->mNumMaterials = 0;
  162|      0|        return;
  163|      0|    }
  164|     91|    if (iNewNum != pScene->mNumMaterials) {
  ------------------
  |  Branch (164:9): [True: 0, False: 91]
  ------------------
  165|      0|        ai_assert(iNewNum > 0);
  166|      0|        aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
  167|      0|        ::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
  168|      0|        for (unsigned int p = 0; p < pScene->mNumMaterials;++p) {
  ------------------
  |  Branch (168:34): [True: 0, False: 0]
  ------------------
  169|       |            // if the material is not referenced ... remove it
  170|      0|            if (!abReferenced[p]) {
  ------------------
  |  Branch (170:17): [True: 0, False: 0]
  ------------------
  171|      0|                continue;
  172|      0|            }
  173|       |
  174|       |            // generate new names for modified materials that had no names
  175|      0|            const unsigned int idx = aiMappingTable[p];
  176|      0|            if (ppcMaterials[idx]) {
  ------------------
  |  Branch (176:17): [True: 0, False: 0]
  ------------------
  177|      0|                aiString sz;
  178|      0|                if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
  ------------------
  |  Branch (178:21): [True: 0, False: 0]
  ------------------
  179|      0|                    sz.length = ::ai_snprintf(sz.data, AI_MAXLEN,"JoinedMaterial_#%u",p);
  180|      0|                    ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
  181|      0|                }
  182|      0|            } else {
  183|      0|                ppcMaterials[idx] = pScene->mMaterials[p];
  184|      0|            }
  185|      0|        }
  186|       |        // update all material indices
  187|      0|        for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
  ------------------
  |  Branch (187:34): [True: 0, False: 0]
  ------------------
  188|      0|            aiMesh* mesh = pScene->mMeshes[p];
  189|      0|            ai_assert(nullptr != mesh);
  190|      0|            mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
  191|      0|        }
  192|       |        // delete the old material list
  193|      0|        delete[] pScene->mMaterials;
  194|      0|        pScene->mMaterials = ppcMaterials;
  195|      0|        pScene->mNumMaterials = iNewNum;
  196|      0|    }
  197|       |    // delete temporary storage
  198|     91|    delete[] aiHashes;
  199|     91|    delete[] aiMappingTable;
  200|       |
  201|     91|    if (redundantRemoved == 0 && unreferencedRemoved == 0) {
  ------------------
  |  Branch (201:9): [True: 91, False: 0]
  |  Branch (201:34): [True: 91, False: 0]
  ------------------
  202|     91|        ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
  203|     91|    } else {
  204|       |        ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
  205|      0|            unreferencedRemoved, " unused materials.");
  206|      0|    }
  207|     91|}

_ZN6Assimp26RemoveRedundantMatsProcessD2Ev:
   64|    297|    ~RemoveRedundantMatsProcess() override = default;

_ZN6Assimp15RemoveVCProcessC2Ev:
   55|    297|        configDeleteFlags(), mScene() {}
_ZNK6Assimp15RemoveVCProcess8IsActiveEj:
   59|    218|bool RemoveVCProcess::IsActive(unsigned int pFlags) const {
   60|    218|    return (pFlags & aiProcess_RemoveComponent) != 0;
   61|    218|}

_ZN6Assimp12ScaleProcessC2Ev:
   50|    297|ScaleProcess::ScaleProcess() : BaseProcess(), mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) {
   51|       |    // empty
   52|    297|}
_ZNK6Assimp12ScaleProcess8IsActiveEj:
   65|    218|bool ScaleProcess::IsActive( unsigned int pFlags ) const {
   66|    218|    return ( pFlags & aiProcess_GlobalScale ) != 0;
   67|    218|}

_ZN6Assimp18SortByPTypeProcessC2Ev:
   55|    297|SortByPTypeProcess::SortByPTypeProcess() : mConfigRemoveMeshes(0) {}
_ZNK6Assimp18SortByPTypeProcess8IsActiveEj:
   59|    218|bool SortByPTypeProcess::IsActive(unsigned int pFlags) const {
   60|    218|    return (pFlags & aiProcess_SortByPType) != 0;
   61|    218|}
_ZN6Assimp18SortByPTypeProcess15SetupPropertiesEPKNS_8ImporterE:
   64|    218|void SortByPTypeProcess::SetupProperties(const Importer *pImp) {
   65|       |    mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, 0);
   66|    218|}
_Z11UpdateNodesRKNSt3__16vectorIjNS_9allocatorIjEEEEP6aiNode:
   77|     20|void UpdateNodes(const std::vector<unsigned int> &replaceMeshIndex, aiNode *node) {
   78|     20|    ai_assert(node != nullptr);
   79|       |
   80|     20|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 12, False: 8]
  ------------------
   81|     12|        unsigned int newSize = 0;
   82|     24|        for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
  ------------------
  |  Branch (82:34): [True: 12, False: 12]
  ------------------
   83|     12|            unsigned int add = node->mMeshes[m] << 2;
   84|     60|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (84:38): [True: 48, False: 12]
  ------------------
   85|     48|                if (UINT_MAX != replaceMeshIndex[add + i]) {
  ------------------
  |  Branch (85:21): [True: 23, False: 25]
  ------------------
   86|     23|                    ++newSize;
   87|     23|                }
   88|     48|            }
   89|     12|        }
   90|     12|        if (newSize == 0) {
  ------------------
  |  Branch (90:13): [True: 0, False: 12]
  ------------------
   91|      0|            clearMeshesInNode(node);
   92|      0|            return;
   93|      0|        }
   94|       |
   95|       |        // Try to reuse the old array if possible
   96|     12|        unsigned int *newMeshes = (newSize > node->mNumMeshes ? new unsigned int[newSize] : node->mMeshes);
  ------------------
  |  Branch (96:36): [True: 9, False: 3]
  ------------------
   97|     24|        for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
  ------------------
  |  Branch (97:34): [True: 12, False: 12]
  ------------------
   98|     12|            unsigned int add = node->mMeshes[m] << 2;
   99|     60|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (99:38): [True: 48, False: 12]
  ------------------
  100|     48|                if (UINT_MAX != replaceMeshIndex[add + i]) {
  ------------------
  |  Branch (100:21): [True: 23, False: 25]
  ------------------
  101|     23|                    *newMeshes++ = replaceMeshIndex[add + i];
  102|     23|                }
  103|     48|            }
  104|     12|        }
  105|     12|        if (newSize > node->mNumMeshes) {
  ------------------
  |  Branch (105:13): [True: 9, False: 3]
  ------------------
  106|      9|            clearMeshesInNode(node);
  107|      9|        }
  108|     12|        node->mMeshes = newMeshes - (node->mNumMeshes = newSize);
  109|     12|    }
  110|       |
  111|       |    // call all subnodes recursively
  112|     36|    for (unsigned int m = 0; m < node->mNumChildren; ++m) {
  ------------------
  |  Branch (112:30): [True: 16, False: 20]
  ------------------
  113|     16|        UpdateNodes(replaceMeshIndex, node->mChildren[m]);
  114|     16|    }
  115|     20|}
_ZN6Assimp18SortByPTypeProcess7ExecuteEP7aiScene:
  119|    218|void SortByPTypeProcess::Execute(aiScene *pScene) {
  120|    218|    if (0 == pScene->mNumMeshes) {
  ------------------
  |  Branch (120:9): [True: 127, False: 91]
  ------------------
  121|    127|        ASSIMP_LOG_DEBUG("SortByPTypeProcess skipped, there are no meshes");
  122|    127|        return;
  123|    127|    }
  124|       |
  125|    218|    ASSIMP_LOG_DEBUG("SortByPTypeProcess begin");
  126|       |
  127|     91|    unsigned int aiNumMeshesPerPType[4] = { 0, 0, 0, 0 };
  128|       |
  129|     91|    std::vector<aiMesh *> outMeshes;
  130|     91|    outMeshes.reserve(static_cast<size_t>(pScene->mNumMeshes) << 1u);
  131|       |
  132|     91|    bool bAnyChanges = false;
  133|       |
  134|     91|    std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes * 4, UINT_MAX);
  135|     91|    std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin();
  136|    185|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (136:30): [True: 94, False: 91]
  ------------------
  137|     94|        aiMesh *const mesh = pScene->mMeshes[i];
  138|     94|        if (mesh->mPrimitiveTypes == 0) {
  ------------------
  |  Branch (138:13): [True: 0, False: 94]
  ------------------
  139|      0|            for (size_t idx = 0; idx < outMeshes.size(); ++idx) {
  ------------------
  |  Branch (139:34): [True: 0, False: 0]
  ------------------
  140|      0|                delete outMeshes[idx];
  141|      0|            }
  142|      0|            throw DeadlyImportError("Mesh with invalid primitive type: ", mesh->mName.C_Str());
  143|      0|        }
  144|       |
  145|       |        // if there's just one primitive type in the mesh there's nothing to do for us
  146|     94|        unsigned int num = 0;
  147|     94|        if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) {
  ------------------
  |  Branch (147:13): [True: 3, False: 91]
  ------------------
  148|      3|            ++aiNumMeshesPerPType[0];
  149|      3|            ++num;
  150|      3|        }
  151|     94|        if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) {
  ------------------
  |  Branch (151:13): [True: 3, False: 91]
  ------------------
  152|      3|            ++aiNumMeshesPerPType[1];
  153|      3|            ++num;
  154|      3|        }
  155|     94|        if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) {
  ------------------
  |  Branch (155:13): [True: 94, False: 0]
  ------------------
  156|     94|            ++aiNumMeshesPerPType[2];
  157|     94|            ++num;
  158|     94|        }
  159|     94|        if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) {
  ------------------
  |  Branch (159:13): [True: 0, False: 94]
  ------------------
  160|      0|            ++aiNumMeshesPerPType[3];
  161|      0|            ++num;
  162|      0|        }
  163|       |
  164|     94|        if (1 == num) {
  ------------------
  |  Branch (164:13): [True: 90, False: 4]
  ------------------
  165|     90|            if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) {
  ------------------
  |  Branch (165:17): [True: 90, False: 0]
  ------------------
  166|     90|                *meshIdx = static_cast<unsigned int>(outMeshes.size());
  167|     90|                outMeshes.emplace_back(mesh);
  168|     90|                pScene->mMeshes[i] = nullptr; // Indicate ownership transfer
  169|     90|            } else {
  170|      0|                delete mesh;
  171|      0|                pScene->mMeshes[i] = nullptr;
  172|      0|                bAnyChanges = true;
  173|      0|            }
  174|       |
  175|     90|            meshIdx += 4;
  176|     90|            continue;
  177|     90|        }
  178|      4|        bAnyChanges = true;
  179|       |
  180|       |        // reuse our current mesh arrays for the submesh
  181|       |        // with the largest number of primitives
  182|      4|        unsigned int aiNumPerPType[4] = { 0, 0, 0, 0 };
  183|      4|        aiFace *pFirstFace = mesh->mFaces;
  184|      4|        if (pFirstFace == nullptr) {
  ------------------
  |  Branch (184:13): [True: 0, False: 4]
  ------------------
  185|      0|            continue;
  186|      0|        }
  187|       |
  188|      4|        aiFace *const pLastFace = pFirstFace + mesh->mNumFaces;
  189|       |
  190|      4|        unsigned int numPolyVerts = 0;
  191|  6.22k|        for (; pFirstFace != pLastFace; ++pFirstFace) {
  ------------------
  |  Branch (191:16): [True: 6.22k, False: 4]
  ------------------
  192|  6.22k|            if (pFirstFace->mNumIndices >= 1 && pFirstFace->mNumIndices <= 3)
  ------------------
  |  Branch (192:17): [True: 6.22k, False: 0]
  |  Branch (192:49): [True: 6.22k, False: 0]
  ------------------
  193|  6.22k|                ++aiNumPerPType[pFirstFace->mNumIndices - 1];
  194|      0|            else {
  195|      0|                ++aiNumPerPType[3];
  196|      0|                numPolyVerts += pFirstFace->mNumIndices;
  197|      0|            }
  198|  6.22k|            if (pFirstFace->mNumIndices == 0) {
  ------------------
  |  Branch (198:17): [True: 0, False: 6.22k]
  ------------------
  199|      0|                ASSIMP_LOG_WARN("Face with 0 indices treated as polygon");
  200|      0|            }
  201|  6.22k|        }
  202|       |
  203|      4|        VertexWeightTable *avw = ComputeVertexBoneWeightTable(mesh);
  204|     20|        for (unsigned int real = 0; real < 4; ++real, ++meshIdx) {
  ------------------
  |  Branch (204:37): [True: 16, False: 4]
  ------------------
  205|     16|            if (!aiNumPerPType[real] || mConfigRemoveMeshes & (1u << real)) {
  ------------------
  |  Branch (205:17): [True: 6, False: 10]
  |  Branch (205:41): [True: 0, False: 10]
  ------------------
  206|      6|                continue;
  207|      6|            }
  208|       |
  209|     10|            *meshIdx = (unsigned int)outMeshes.size();
  210|     10|            outMeshes.push_back(new aiMesh());
  211|     10|            aiMesh *out = outMeshes.back();
  212|       |
  213|       |            // the name carries the adjacency information between the meshes
  214|     10|            out->mName = mesh->mName;
  215|       |
  216|       |            // copy data members
  217|     10|            out->mPrimitiveTypes = 1u << real;
  218|     10|            out->mMaterialIndex = mesh->mMaterialIndex;
  219|       |
  220|       |            // allocate output storage
  221|     10|            out->mNumFaces = aiNumPerPType[real];
  222|     10|            aiFace *outFaces = out->mFaces = new aiFace[out->mNumFaces];
  223|       |
  224|     10|            out->mNumVertices = (3 == real ? numPolyVerts : out->mNumFaces * (real + 1));
  ------------------
  |  Branch (224:34): [True: 0, False: 10]
  ------------------
  225|       |
  226|     10|            aiVector3D *vert(nullptr), *nor(nullptr), *tan(nullptr), *bit(nullptr);
  227|     10|            aiVector3D *uv[AI_MAX_NUMBER_OF_TEXTURECOORDS];
  228|     10|            aiColor4D *cols[AI_MAX_NUMBER_OF_COLOR_SETS];
  229|       |
  230|     10|            if (mesh->mVertices) {
  ------------------
  |  Branch (230:17): [True: 10, False: 0]
  ------------------
  231|     10|                vert = out->mVertices = new aiVector3D[out->mNumVertices];
  232|     10|            }
  233|       |
  234|     10|            if (mesh->mNormals) {
  ------------------
  |  Branch (234:17): [True: 0, False: 10]
  ------------------
  235|      0|                nor = out->mNormals = new aiVector3D[out->mNumVertices];
  236|      0|            }
  237|       |
  238|     10|            if (mesh->mTangents) {
  ------------------
  |  Branch (238:17): [True: 0, False: 10]
  ------------------
  239|      0|                tan = out->mTangents = new aiVector3D[out->mNumVertices];
  240|      0|                bit = out->mBitangents = new aiVector3D[out->mNumVertices];
  241|      0|            }
  242|       |
  243|     90|            for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++j) {
  ------------------
  |  Branch (243:38): [True: 80, False: 10]
  ------------------
  244|     80|                uv[j] = nullptr;
  245|     80|                if (mesh->mTextureCoords[j]) {
  ------------------
  |  Branch (245:21): [True: 2, False: 78]
  ------------------
  246|      2|                    uv[j] = out->mTextureCoords[j] = new aiVector3D[out->mNumVertices];
  247|      2|                }
  248|       |
  249|     80|                out->mNumUVComponents[j] = mesh->mNumUVComponents[j];
  250|     80|            }
  251|       |
  252|     90|            for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_COLOR_SETS; ++j) {
  ------------------
  |  Branch (252:38): [True: 80, False: 10]
  ------------------
  253|     80|                cols[j] = nullptr;
  254|     80|                if (mesh->mColors[j]) {
  ------------------
  |  Branch (254:21): [True: 0, False: 80]
  ------------------
  255|      0|                    cols[j] = out->mColors[j] = new aiColor4D[out->mNumVertices];
  256|      0|                }
  257|     80|            }
  258|       |
  259|     10|            if (mesh->mNumAnimMeshes > 0 && mesh->mAnimMeshes) {
  ------------------
  |  Branch (259:17): [True: 0, False: 10]
  |  Branch (259:45): [True: 0, False: 0]
  ------------------
  260|      0|                out->mNumAnimMeshes = mesh->mNumAnimMeshes;
  261|      0|                out->mAnimMeshes = new aiAnimMesh *[out->mNumAnimMeshes];
  262|      0|            }
  263|       |
  264|     10|            for (unsigned int j = 0; j < mesh->mNumAnimMeshes; ++j) {
  ------------------
  |  Branch (264:38): [True: 0, False: 10]
  ------------------
  265|      0|                aiAnimMesh *animMesh = mesh->mAnimMeshes[j];
  266|      0|                aiAnimMesh *outAnimMesh = out->mAnimMeshes[j] = new aiAnimMesh;
  267|      0|                outAnimMesh->mNumVertices = out->mNumVertices;
  268|      0|                if (animMesh->mVertices)
  ------------------
  |  Branch (268:21): [True: 0, False: 0]
  ------------------
  269|      0|                    outAnimMesh->mVertices = new aiVector3D[out->mNumVertices];
  270|      0|                else
  271|      0|                    outAnimMesh->mVertices = nullptr;
  272|      0|                if (animMesh->mNormals)
  ------------------
  |  Branch (272:21): [True: 0, False: 0]
  ------------------
  273|      0|                    outAnimMesh->mNormals = new aiVector3D[out->mNumVertices];
  274|      0|                else
  275|      0|                    outAnimMesh->mNormals = nullptr;
  276|      0|                if (animMesh->mTangents)
  ------------------
  |  Branch (276:21): [True: 0, False: 0]
  ------------------
  277|      0|                    outAnimMesh->mTangents = new aiVector3D[out->mNumVertices];
  278|      0|                else
  279|      0|                    outAnimMesh->mTangents = nullptr;
  280|      0|                if (animMesh->mBitangents)
  ------------------
  |  Branch (280:21): [True: 0, False: 0]
  ------------------
  281|      0|                    outAnimMesh->mBitangents = new aiVector3D[out->mNumVertices];
  282|      0|                else
  283|      0|                    outAnimMesh->mBitangents = nullptr;
  284|      0|                for (int jj = 0; jj < AI_MAX_NUMBER_OF_COLOR_SETS; ++jj) {
  ------------------
  |  Branch (284:34): [True: 0, False: 0]
  ------------------
  285|      0|                    if (animMesh->mColors[jj])
  ------------------
  |  Branch (285:25): [True: 0, False: 0]
  ------------------
  286|      0|                        outAnimMesh->mColors[jj] = new aiColor4D[out->mNumVertices];
  287|      0|                    else
  288|      0|                        outAnimMesh->mColors[jj] = nullptr;
  289|      0|                }
  290|      0|                for (int jj = 0; jj < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++jj) {
  ------------------
  |  Branch (290:34): [True: 0, False: 0]
  ------------------
  291|      0|                    if (animMesh->mTextureCoords[jj])
  ------------------
  |  Branch (291:25): [True: 0, False: 0]
  ------------------
  292|      0|                        outAnimMesh->mTextureCoords[jj] = new aiVector3D[out->mNumVertices];
  293|      0|                    else
  294|      0|                        outAnimMesh->mTextureCoords[jj] = nullptr;
  295|      0|                }
  296|      0|            }
  297|       |
  298|     10|            typedef std::vector<aiVertexWeight> TempBoneInfo;
  299|     10|            std::vector<TempBoneInfo> tempBones(mesh->mNumBones);
  300|       |
  301|       |            // try to guess how much storage we'll need
  302|     10|            for (unsigned int q = 0; q < mesh->mNumBones; ++q) {
  ------------------
  |  Branch (302:38): [True: 0, False: 10]
  ------------------
  303|      0|                tempBones[q].reserve(mesh->mBones[q]->mNumWeights / (num - 1));
  304|      0|            }
  305|       |
  306|     10|            unsigned int outIdx = 0;
  307|     10|            unsigned int amIdx = 0; // AnimMesh index
  308|  18.2k|            for (unsigned int m = 0; m < mesh->mNumFaces; ++m) {
  ------------------
  |  Branch (308:38): [True: 18.2k, False: 10]
  ------------------
  309|  18.2k|                aiFace &in = mesh->mFaces[m];
  310|  18.2k|                if ((real == 3 && in.mNumIndices <= 3) || (real != 3 && in.mNumIndices != real + 1)) {
  ------------------
  |  Branch (310:22): [True: 0, False: 18.2k]
  |  Branch (310:35): [True: 0, False: 0]
  |  Branch (310:60): [True: 18.2k, False: 0]
  |  Branch (310:73): [True: 12.0k, False: 6.22k]
  ------------------
  311|  12.0k|                    continue;
  312|  12.0k|                }
  313|       |
  314|  6.22k|                outFaces->mNumIndices = in.mNumIndices;
  315|  6.22k|                outFaces->mIndices = in.mIndices;
  316|       |
  317|  24.6k|                for (unsigned int q = 0; q < in.mNumIndices; ++q) {
  ------------------
  |  Branch (317:42): [True: 18.4k, False: 6.22k]
  ------------------
  318|  18.4k|                    unsigned int idx = in.mIndices[q];
  319|       |
  320|       |                    // process all bones of this index
  321|  18.4k|                    if (avw) {
  ------------------
  |  Branch (321:25): [True: 0, False: 18.4k]
  ------------------
  322|      0|                        VertexWeightTable &tbl = avw[idx];
  323|      0|                        for (VertexWeightTable::const_iterator it = tbl.begin(), end = tbl.end();
  324|      0|                                it != end; ++it) {
  ------------------
  |  Branch (324:33): [True: 0, False: 0]
  ------------------
  325|      0|                            tempBones[(*it).first].emplace_back(outIdx, (*it).second);
  326|      0|                        }
  327|      0|                    }
  328|       |
  329|  18.4k|                    if (vert) {
  ------------------
  |  Branch (329:25): [True: 18.4k, False: 0]
  ------------------
  330|  18.4k|                        *vert++ = mesh->mVertices[idx];
  331|  18.4k|                    }
  332|  18.4k|                    if (nor)
  ------------------
  |  Branch (332:25): [True: 0, False: 18.4k]
  ------------------
  333|      0|                        *nor++ = mesh->mNormals[idx];
  334|  18.4k|                    if (tan) {
  ------------------
  |  Branch (334:25): [True: 0, False: 18.4k]
  ------------------
  335|      0|                        *tan++ = mesh->mTangents[idx];
  336|      0|                        *bit++ = mesh->mBitangents[idx];
  337|      0|                    }
  338|       |
  339|  19.5k|                    for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) {
  ------------------
  |  Branch (339:47): [True: 19.5k, False: 0]
  ------------------
  340|  19.5k|                        if (!uv[pp])
  ------------------
  |  Branch (340:29): [True: 18.4k, False: 1.12k]
  ------------------
  341|  18.4k|                            break;
  342|  1.12k|                        *uv[pp]++ = mesh->mTextureCoords[pp][idx];
  343|  1.12k|                    }
  344|       |
  345|  18.4k|                    for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) {
  ------------------
  |  Branch (345:47): [True: 18.4k, False: 0]
  ------------------
  346|  18.4k|                        if (!cols[pp])
  ------------------
  |  Branch (346:29): [True: 18.4k, False: 0]
  ------------------
  347|  18.4k|                            break;
  348|      0|                        *cols[pp]++ = mesh->mColors[pp][idx];
  349|      0|                    }
  350|       |
  351|  18.4k|                    unsigned int pp = 0;
  352|  18.4k|                    for (; pp < mesh->mNumAnimMeshes; ++pp) {
  ------------------
  |  Branch (352:28): [True: 0, False: 18.4k]
  ------------------
  353|      0|                        aiAnimMesh *animMesh = mesh->mAnimMeshes[pp];
  354|      0|                        aiAnimMesh *outAnimMesh = out->mAnimMeshes[pp];
  355|      0|                        if (animMesh->mVertices)
  ------------------
  |  Branch (355:29): [True: 0, False: 0]
  ------------------
  356|      0|                            outAnimMesh->mVertices[amIdx] = animMesh->mVertices[idx];
  357|      0|                        if (animMesh->mNormals)
  ------------------
  |  Branch (357:29): [True: 0, False: 0]
  ------------------
  358|      0|                            outAnimMesh->mNormals[amIdx] = animMesh->mNormals[idx];
  359|      0|                        if (animMesh->mTangents)
  ------------------
  |  Branch (359:29): [True: 0, False: 0]
  ------------------
  360|      0|                            outAnimMesh->mTangents[amIdx] = animMesh->mTangents[idx];
  361|      0|                        if (animMesh->mBitangents)
  ------------------
  |  Branch (361:29): [True: 0, False: 0]
  ------------------
  362|      0|                            outAnimMesh->mBitangents[amIdx] = animMesh->mBitangents[idx];
  363|      0|                        for (int jj = 0; jj < AI_MAX_NUMBER_OF_COLOR_SETS; ++jj) {
  ------------------
  |  Branch (363:42): [True: 0, False: 0]
  ------------------
  364|      0|                            if (animMesh->mColors[jj])
  ------------------
  |  Branch (364:33): [True: 0, False: 0]
  ------------------
  365|      0|                                outAnimMesh->mColors[jj][amIdx] = animMesh->mColors[jj][idx];
  366|      0|                        }
  367|      0|                        for (int jj = 0; jj < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++jj) {
  ------------------
  |  Branch (367:42): [True: 0, False: 0]
  ------------------
  368|      0|                            if (animMesh->mTextureCoords[jj])
  ------------------
  |  Branch (368:33): [True: 0, False: 0]
  ------------------
  369|      0|                                outAnimMesh->mTextureCoords[jj][amIdx] = animMesh->mTextureCoords[jj][idx];
  370|      0|                        }
  371|      0|                    }
  372|  18.4k|                    if (pp == mesh->mNumAnimMeshes)
  ------------------
  |  Branch (372:25): [True: 18.4k, False: 0]
  ------------------
  373|  18.4k|                        ++amIdx;
  374|       |
  375|  18.4k|                    in.mIndices[q] = outIdx++;
  376|  18.4k|                }
  377|       |
  378|  6.22k|                in.mIndices = nullptr;
  379|  6.22k|                ++outFaces;
  380|  6.22k|            }
  381|     10|            ai_assert(outFaces == out->mFaces + out->mNumFaces);
  382|       |
  383|       |            // now generate output bones
  384|     10|            for (unsigned int q = 0; q < mesh->mNumBones; ++q) {
  ------------------
  |  Branch (384:38): [True: 0, False: 10]
  ------------------
  385|      0|                if (!tempBones[q].empty()) {
  ------------------
  |  Branch (385:21): [True: 0, False: 0]
  ------------------
  386|      0|                    ++out->mNumBones;
  387|      0|                }
  388|      0|            }
  389|       |
  390|     10|            if (out->mNumBones) {
  ------------------
  |  Branch (390:17): [True: 0, False: 10]
  ------------------
  391|      0|                out->mBones = new aiBone *[out->mNumBones];
  392|      0|                for (unsigned int q = 0, boneIdx = 0; q < mesh->mNumBones; ++q) {
  ------------------
  |  Branch (392:55): [True: 0, False: 0]
  ------------------
  393|      0|                    TempBoneInfo &in = tempBones[q];
  394|      0|                    if (in.empty()) {
  ------------------
  |  Branch (394:25): [True: 0, False: 0]
  ------------------
  395|      0|                        continue;
  396|      0|                    }
  397|       |
  398|      0|                    aiBone *srcBone = mesh->mBones[q];
  399|      0|                    aiBone *bone = out->mBones[boneIdx] = new aiBone();
  400|       |
  401|      0|                    bone->mName = srcBone->mName;
  402|      0|                    bone->mOffsetMatrix = srcBone->mOffsetMatrix;
  403|       |
  404|      0|                    bone->mNumWeights = (unsigned int)in.size();
  405|      0|                    bone->mWeights = new aiVertexWeight[bone->mNumWeights];
  406|       |
  407|      0|                    ::memcpy(bone->mWeights, &in[0], bone->mNumWeights * sizeof(aiVertexWeight));
  408|       |
  409|      0|                    ++boneIdx;
  410|      0|                }
  411|      0|            }
  412|     10|        }
  413|       |
  414|       |        // delete the per-vertex bone weights table
  415|      4|        delete[] avw;
  416|       |
  417|       |        // delete the input mesh
  418|      4|        delete mesh;
  419|       |
  420|       |        // avoid invalid pointer
  421|      4|        pScene->mMeshes[i] = nullptr;
  422|      4|    }
  423|       |
  424|     91|    if (outMeshes.empty()) {
  ------------------
  |  Branch (424:9): [True: 0, False: 91]
  ------------------
  425|       |        // This should not occur
  426|      0|        throw DeadlyImportError("No meshes remaining");
  427|      0|    }
  428|       |
  429|       |    // If we added at least one mesh process all nodes in the node
  430|       |    // graph and update their respective mesh indices.
  431|     91|    if (bAnyChanges) {
  ------------------
  |  Branch (431:9): [True: 4, False: 87]
  ------------------
  432|      4|        UpdateNodes(replaceMeshIndex, pScene->mRootNode);
  433|      4|    }
  434|       |
  435|     91|    if (outMeshes.size() != pScene->mNumMeshes) {
  ------------------
  |  Branch (435:9): [True: 4, False: 87]
  ------------------
  436|      4|        delete[] pScene->mMeshes;
  437|      4|        pScene->mNumMeshes = (unsigned int)outMeshes.size();
  438|      4|        pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  439|      4|    }
  440|     91|    ::memcpy(pScene->mMeshes, &outMeshes[0], pScene->mNumMeshes * sizeof(void *));
  441|       |
  442|     91|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (442:9): [True: 0, False: 91]
  ------------------
  443|      0|        char buffer[1024];
  444|      0|        ::ai_snprintf(buffer, 1024, "Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)",
  445|      0|                aiNumMeshesPerPType[0], ((mConfigRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""),
  ------------------
  |  Branch (445:42): [True: 0, False: 0]
  ------------------
  446|      0|                aiNumMeshesPerPType[1], ((mConfigRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""),
  ------------------
  |  Branch (446:42): [True: 0, False: 0]
  ------------------
  447|      0|                aiNumMeshesPerPType[2], ((mConfigRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""),
  ------------------
  |  Branch (447:42): [True: 0, False: 0]
  ------------------
  448|      0|                aiNumMeshesPerPType[3], ((mConfigRemoveMeshes & aiPrimitiveType_POLYGON) ? "X" : ""));
  ------------------
  |  Branch (448:42): [True: 0, False: 0]
  ------------------
  449|      0|        ASSIMP_LOG_INFO(buffer);
  450|       |        ASSIMP_LOG_DEBUG("SortByPTypeProcess finished");
  451|      0|    }
  452|     91|}
SortByPTypeProcess.cpp:_ZL17clearMeshesInNodeP6aiNode:
   69|      9|static void clearMeshesInNode(aiNode *node) {
   70|      9|    delete[] node->mMeshes;
   71|      9|    node->mNumMeshes = 0;
   72|      9|    node->mMeshes = nullptr;
   73|      9|}

_ZN6Assimp23SplitByBoneCountProcessC2Ev:
   60|    297|SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {}
_ZNK6Assimp23SplitByBoneCountProcess8IsActiveEj:
   64|    218|bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const {
   65|    218|    return !!(pFlags & aiProcess_SplitByBoneCount);
   66|    218|}

_ZN6Assimp23SplitByBoneCountProcessD2Ev:
   66|    297|    ~SplitByBoneCountProcess() override = default;

_ZN6Assimp32SplitLargeMeshesProcess_TriangleC2Ev:
   51|    297|SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() {
   52|       |    LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
   53|    297|}
_ZNK6Assimp32SplitLargeMeshesProcess_Triangle8IsActiveEj:
   57|    218|bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const {
   58|    218|    return (pFlags & aiProcess_SplitLargeMeshes) != 0;
   59|    218|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle7ExecuteEP7aiScene:
   63|    218|void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) {
   64|    218|    if (0xffffffff == this->LIMIT || nullptr == pScene ) {
  ------------------
  |  Branch (64:9): [True: 0, False: 218]
  |  Branch (64:38): [True: 0, False: 218]
  ------------------
   65|      0|        return;
   66|      0|    }
   67|       |
   68|    218|    ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle begin");
   69|    218|    std::vector<std::pair<aiMesh*, unsigned int> > avList;
   70|       |
   71|    315|    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (71:30): [True: 97, False: 218]
  ------------------
   72|     97|        this->SplitMesh(a, pScene->mMeshes[a],avList);
   73|     97|    }
   74|       |
   75|    218|    if (avList.size() == pScene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 218, False: 0]
  ------------------
   76|    218|        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
   77|    218|    }
   78|       |
   79|       |    // it seems something has been split. rebuild the mesh list
   80|    218|    delete[] pScene->mMeshes;
   81|    218|    pScene->mNumMeshes = (unsigned int)avList.size();
   82|    218|    pScene->mMeshes = new aiMesh*[avList.size()];
   83|       |
   84|    315|    for (unsigned int i = 0; i < avList.size();++i) {
  ------------------
  |  Branch (84:30): [True: 97, False: 218]
  ------------------
   85|     97|        pScene->mMeshes[i] = avList[i].first;
   86|     97|    }
   87|       |
   88|       |    // now we need to update all nodes
   89|    218|    this->UpdateNode(pScene->mRootNode,avList);
   90|       |    ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
   91|    218|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle15SetupPropertiesEPKNS_8ImporterE:
   95|    218|void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) {
   96|       |    // get the current value of the split property
   97|    218|    this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
   98|    218|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle10UpdateNodeEP6aiNodeRKNSt3__16vectorINS3_4pairIP6aiMeshjEENS3_9allocatorIS8_EEEE:
  102|  4.81k|void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  103|  4.81k|    if (pcNode == nullptr) {
  ------------------
  |  Branch (103:9): [True: 0, False: 4.81k]
  ------------------
  104|      0|        ASSIMP_LOG_WARN("UpdateNode skipped, nullptr detected.");
  105|      0|        return;
  106|      0|    }
  107|       |
  108|       |    // for every index in out list build a new entry
  109|  4.81k|    std::vector<unsigned int> aiEntries;
  110|  4.81k|    aiEntries.reserve(pcNode->mNumMeshes + 1);
  111|  4.90k|    for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) {
  ------------------
  |  Branch (111:30): [True: 97, False: 4.81k]
  ------------------
  112|    214|        for (unsigned int a = 0; a < avList.size();++a) {
  ------------------
  |  Branch (112:34): [True: 117, False: 97]
  ------------------
  113|    117|            if (avList[a].second == pcNode->mMeshes[i]) {
  ------------------
  |  Branch (113:17): [True: 97, False: 20]
  ------------------
  114|     97|                aiEntries.push_back(a);
  115|     97|            }
  116|    117|        }
  117|     97|    }
  118|       |
  119|       |    // now build the new list
  120|  4.81k|    delete[] pcNode->mMeshes;
  121|  4.81k|    pcNode->mNumMeshes = (unsigned int)aiEntries.size();
  122|  4.81k|    pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
  123|       |
  124|  4.90k|    for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) {
  ------------------
  |  Branch (124:30): [True: 97, False: 4.81k]
  ------------------
  125|     97|        pcNode->mMeshes[b] = aiEntries[b];
  126|     97|    }
  127|       |
  128|       |    // recursively update all other nodes
  129|  9.40k|    for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
  ------------------
  |  Branch (129:30): [True: 4.59k, False: 4.81k]
  ------------------
  130|  4.59k|        UpdateNode ( pcNode->mChildren[i], avList );
  131|  4.59k|    }
  132|  4.81k|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle9SplitMeshEjP6aiMeshRNSt3__16vectorINS3_4pairIS2_jEENS3_9allocatorIS6_EEEE:
  139|     97|        std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  140|     97|    if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT) {
  ------------------
  |  Branch (140:9): [True: 0, False: 97]
  ------------------
  141|      0|        ASSIMP_LOG_INFO("Mesh exceeds the triangle limit. It will be split ...");
  142|       |
  143|       |        // we need to split this mesh into sub meshes
  144|       |        // determine the size of a submesh
  145|      0|        const unsigned int iSubMeshes = (pMesh->mNumFaces / LIMIT) + 1;
  146|       |
  147|      0|        const unsigned int iOutFaceNum = pMesh->mNumFaces / iSubMeshes;
  148|      0|        const unsigned int iOutVertexNum = iOutFaceNum * 3;
  149|       |
  150|       |        // now generate all submeshes
  151|      0|        for (unsigned int i = 0; i < iSubMeshes;++i) {
  ------------------
  |  Branch (151:34): [True: 0, False: 0]
  ------------------
  152|      0|            aiMesh* pcMesh          = new aiMesh;
  153|      0|            pcMesh->mNumFaces       = iOutFaceNum;
  154|      0|            pcMesh->mMaterialIndex  = pMesh->mMaterialIndex;
  155|       |
  156|       |            // the name carries the adjacency information between the meshes
  157|      0|            pcMesh->mName = pMesh->mName;
  158|       |
  159|      0|            if (i == iSubMeshes-1) {
  ------------------
  |  Branch (159:17): [True: 0, False: 0]
  ------------------
  160|      0|                pcMesh->mNumFaces = iOutFaceNum + (
  161|      0|                    pMesh->mNumFaces - iOutFaceNum * iSubMeshes);
  162|      0|            }
  163|       |            // copy the list of faces
  164|      0|            pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
  165|       |
  166|      0|            const unsigned int iBase = iOutFaceNum * i;
  167|       |
  168|       |            // get the total number of indices
  169|      0|            unsigned int iCnt = 0;
  170|      0|            for (unsigned int p = iBase; p < pcMesh->mNumFaces + iBase;++p) {
  ------------------
  |  Branch (170:42): [True: 0, False: 0]
  ------------------
  171|      0|                iCnt += pMesh->mFaces[p].mNumIndices;
  172|      0|            }
  173|      0|            pcMesh->mNumVertices = iCnt;
  174|       |
  175|       |            // allocate storage
  176|      0|            if (pMesh->mVertices != nullptr) {
  ------------------
  |  Branch (176:17): [True: 0, False: 0]
  ------------------
  177|      0|                pcMesh->mVertices = new aiVector3D[iCnt];
  178|      0|            }
  179|       |
  180|      0|            if (pMesh->HasNormals()) {
  ------------------
  |  Branch (180:17): [True: 0, False: 0]
  ------------------
  181|      0|                pcMesh->mNormals = new aiVector3D[iCnt];
  182|      0|            }
  183|       |
  184|      0|            if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (184:17): [True: 0, False: 0]
  ------------------
  185|      0|                pcMesh->mTangents = new aiVector3D[iCnt];
  186|      0|                pcMesh->mBitangents = new aiVector3D[iCnt];
  187|      0|            }
  188|       |
  189|       |            // texture coordinates
  190|      0|            for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
  ------------------
  |  Branch (190:39): [True: 0, False: 0]
  ------------------
  191|      0|                pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
  192|      0|                if (pMesh->HasTextureCoords( c)) {
  ------------------
  |  Branch (192:21): [True: 0, False: 0]
  ------------------
  193|      0|                    pcMesh->mTextureCoords[c] = new aiVector3D[iCnt];
  194|      0|                }
  195|      0|            }
  196|       |
  197|       |            // vertex colors
  198|      0|            for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
  ------------------
  |  Branch (198:39): [True: 0, False: 0]
  ------------------
  199|      0|                if (pMesh->HasVertexColors( c)) {
  ------------------
  |  Branch (199:21): [True: 0, False: 0]
  ------------------
  200|      0|                    pcMesh->mColors[c] = new aiColor4D[iCnt];
  201|      0|                }
  202|      0|            }
  203|       |
  204|      0|            if (pMesh->HasBones()) {
  ------------------
  |  Branch (204:17): [True: 0, False: 0]
  ------------------
  205|       |                // assume the number of bones won't change in most cases
  206|      0|                pcMesh->mBones = new aiBone*[pMesh->mNumBones];
  207|       |
  208|       |                // iterate through all bones of the mesh and find those which
  209|       |                // need to be copied to the split mesh
  210|      0|                std::vector<aiVertexWeight> avTempWeights;
  211|      0|                for (unsigned int p = 0; p < pcMesh->mNumBones;++p) {
  ------------------
  |  Branch (211:42): [True: 0, False: 0]
  ------------------
  212|      0|                    aiBone* const bone = pcMesh->mBones[p];
  213|      0|                    avTempWeights.clear();
  214|      0|                    avTempWeights.reserve(bone->mNumWeights / iSubMeshes);
  215|       |
  216|      0|                    for (unsigned int q = 0; q < bone->mNumWeights;++q) {
  ------------------
  |  Branch (216:46): [True: 0, False: 0]
  ------------------
  217|      0|                        aiVertexWeight& weight = bone->mWeights[q];
  218|      0|                        if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum) {
  ------------------
  |  Branch (218:28): [True: 0, False: 0]
  |  Branch (218:57): [True: 0, False: 0]
  ------------------
  219|      0|                            avTempWeights.push_back(weight);
  220|      0|                            weight = avTempWeights.back();
  221|      0|                            weight.mVertexId -= iBase;
  222|      0|                        }
  223|      0|                    }
  224|       |
  225|      0|                    if (!avTempWeights.empty()) {
  ------------------
  |  Branch (225:25): [True: 0, False: 0]
  ------------------
  226|       |                        // we'll need this bone. Copy it ...
  227|      0|                        aiBone* pc = new aiBone();
  228|      0|                        pcMesh->mBones[pcMesh->mNumBones++] = pc;
  229|      0|                        pc->mName = aiString(bone->mName);
  230|      0|                        pc->mNumWeights = (unsigned int)avTempWeights.size();
  231|      0|                        pc->mOffsetMatrix = bone->mOffsetMatrix;
  232|       |
  233|       |                        // no need to reallocate the array for the last submesh.
  234|       |                        // Here we can reuse the (large) source array, although
  235|       |                        // we'll waste some memory
  236|      0|                        if (iSubMeshes-1 == i) {
  ------------------
  |  Branch (236:29): [True: 0, False: 0]
  ------------------
  237|      0|                            pc->mWeights = bone->mWeights;
  238|      0|                            bone->mWeights = nullptr;
  239|      0|                        } else {
  240|      0|                            pc->mWeights = new aiVertexWeight[pc->mNumWeights];
  241|      0|                        }
  242|       |
  243|       |                        // copy the weights
  244|      0|                        ::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights);
  245|      0|                    }
  246|      0|                }
  247|      0|            }
  248|       |
  249|       |            // (we will also need to copy the array of indices)
  250|      0|            unsigned int iCurrent = 0;
  251|      0|            for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) {
  ------------------
  |  Branch (251:38): [True: 0, False: 0]
  ------------------
  252|      0|                pcMesh->mFaces[p].mNumIndices = 3;
  253|       |                // allocate a new array
  254|      0|                const unsigned int iTemp = p + iBase;
  255|      0|                const unsigned int iNumIndices = pMesh->mFaces[iTemp].mNumIndices;
  256|       |
  257|       |                // setup face type and number of indices
  258|      0|                pcMesh->mFaces[p].mNumIndices = iNumIndices;
  259|      0|                unsigned int* pi = pMesh->mFaces[iTemp].mIndices;
  260|      0|                unsigned int* piOut = pcMesh->mFaces[p].mIndices = new unsigned int[iNumIndices];
  261|       |
  262|       |                // need to update the output primitive types
  263|      0|                switch (iNumIndices) {
  264|      0|                case 1:
  ------------------
  |  Branch (264:17): [True: 0, False: 0]
  ------------------
  265|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  266|      0|                    break;
  267|      0|                case 2:
  ------------------
  |  Branch (267:17): [True: 0, False: 0]
  ------------------
  268|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  269|      0|                    break;
  270|      0|                case 3:
  ------------------
  |  Branch (270:17): [True: 0, False: 0]
  ------------------
  271|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  272|      0|                    break;
  273|      0|                default:
  ------------------
  |  Branch (273:17): [True: 0, False: 0]
  ------------------
  274|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  275|      0|                }
  276|       |
  277|       |                // and copy the contents of the old array, offset by current base
  278|      0|                for (unsigned int v = 0; v < iNumIndices;++v) {
  ------------------
  |  Branch (278:42): [True: 0, False: 0]
  ------------------
  279|      0|                    unsigned int iIndex = pi[v];
  280|      0|                    unsigned int iIndexOut = iCurrent++;
  281|      0|                    piOut[v] = iIndexOut;
  282|       |
  283|       |                    // copy positions
  284|      0|                    if (pMesh->mVertices != nullptr) {
  ------------------
  |  Branch (284:25): [True: 0, False: 0]
  ------------------
  285|      0|                        pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex];
  286|      0|                    }
  287|       |
  288|       |                    // copy normals
  289|      0|                    if (pMesh->HasNormals()) {
  ------------------
  |  Branch (289:25): [True: 0, False: 0]
  ------------------
  290|      0|                        pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex];
  291|      0|                    }
  292|       |
  293|       |                    // copy tangents/bitangents
  294|      0|                    if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (294:25): [True: 0, False: 0]
  ------------------
  295|      0|                        pcMesh->mTangents[iIndexOut] = pMesh->mTangents[iIndex];
  296|      0|                        pcMesh->mBitangents[iIndexOut] = pMesh->mBitangents[iIndex];
  297|      0|                    }
  298|       |
  299|       |                    // texture coordinates
  300|      0|                    for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
  ------------------
  |  Branch (300:47): [True: 0, False: 0]
  ------------------
  301|      0|                        if (pMesh->HasTextureCoords( c ) ) {
  ------------------
  |  Branch (301:29): [True: 0, False: 0]
  ------------------
  302|      0|                            pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex];
  303|      0|                        }
  304|      0|                    }
  305|       |                    // vertex colors
  306|      0|                    for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
  ------------------
  |  Branch (306:47): [True: 0, False: 0]
  ------------------
  307|      0|                        if (pMesh->HasVertexColors( c)) {
  ------------------
  |  Branch (307:29): [True: 0, False: 0]
  ------------------
  308|      0|                            pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex];
  309|      0|                        }
  310|      0|                    }
  311|      0|                }
  312|      0|            }
  313|       |
  314|       |            // add the newly created mesh to the list
  315|      0|            avList.emplace_back(pcMesh,a);
  316|      0|        }
  317|       |
  318|       |        // now delete the old mesh data
  319|      0|        delete pMesh;
  320|     97|    } else {
  321|     97|        avList.emplace_back(pMesh,a);
  322|     97|    }
  323|     97|}
_ZN6Assimp30SplitLargeMeshesProcess_VertexC2Ev:
  326|    297|SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() {
  327|       |    LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
  328|    297|}
_ZNK6Assimp30SplitLargeMeshesProcess_Vertex8IsActiveEj:
  332|    218|bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const {
  333|    218|    return (pFlags & aiProcess_SplitLargeMeshes) != 0;
  334|    218|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex7ExecuteEP7aiScene:
  338|    218|void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) {
  339|    218|    if (0xffffffff == this->LIMIT || nullptr == pScene ) {
  ------------------
  |  Branch (339:9): [True: 0, False: 218]
  |  Branch (339:38): [True: 0, False: 218]
  ------------------
  340|      0|        return;
  341|      0|    }
  342|       |
  343|    218|    ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex begin");
  344|       |
  345|    218|    std::vector<std::pair<aiMesh*, unsigned int> > avList;
  346|       |
  347|       |    //Check for point cloud first,
  348|       |    //Do not process point cloud, splitMesh works only with faces data
  349|    312|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (349:30): [True: 95, False: 217]
  ------------------
  350|     95|        if ( pScene->mMeshes[a]->mPrimitiveTypes == aiPrimitiveType_POINT ) {
  ------------------
  |  Branch (350:14): [True: 1, False: 94]
  ------------------
  351|      1|            return;
  352|      1|        }
  353|     95|    }
  354|       |
  355|    311|    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
  ------------------
  |  Branch (355:30): [True: 94, False: 217]
  ------------------
  356|     94|        this->SplitMesh(a, pScene->mMeshes[a], avList);
  357|     94|    }
  358|       |
  359|    217|    if (avList.size() != pScene->mNumMeshes) {
  ------------------
  |  Branch (359:9): [True: 0, False: 217]
  ------------------
  360|       |        // it seems something has been split. rebuild the mesh list
  361|      0|        delete[] pScene->mMeshes;
  362|      0|        pScene->mNumMeshes = (unsigned int)avList.size();
  363|      0|        pScene->mMeshes = new aiMesh*[avList.size()];
  364|       |
  365|      0|        for (unsigned int i = 0; i < avList.size();++i) {
  ------------------
  |  Branch (365:34): [True: 0, False: 0]
  ------------------
  366|      0|            pScene->mMeshes[i] = avList[i].first;
  367|      0|        }
  368|       |
  369|       |        // now we need to update all nodes
  370|      0|        SplitLargeMeshesProcess_Triangle::UpdateNode(pScene->mRootNode,avList);
  371|      0|        ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Vertex finished. Meshes have been split");
  372|    217|    } else {
  373|       |        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex finished. There was nothing to do");
  374|    217|    }
  375|    217|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex15SetupPropertiesEPKNS_8ImporterE:
  379|    218|void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) {
  380|    218|    this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
  381|    218|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex9SplitMeshEjP6aiMeshRNSt3__16vectorINS3_4pairIS2_jEENS3_9allocatorIS6_EEEE:
  388|     94|        std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  389|     94|    if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT) {
  ------------------
  |  Branch (389:9): [True: 0, False: 94]
  ------------------
  390|      0|        typedef std::vector< std::pair<unsigned int,float> > VertexWeightTable;
  391|       |
  392|       |        // build a per-vertex weight list if necessary
  393|      0|        VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(pMesh);
  394|       |
  395|       |        // we need to split this mesh into sub meshes
  396|       |        // determine the estimated size of a submesh
  397|       |        // (this could be too large. Max waste is a single digit percentage)
  398|      0|        const unsigned int iSubMeshes = (pMesh->mNumVertices / SplitLargeMeshesProcess_Vertex::LIMIT) + 1;
  399|       |
  400|       |        // create a std::vector<unsigned int> to indicate which vertices
  401|       |        // have already been copied
  402|      0|        std::vector<unsigned int> avWasCopied;
  403|      0|        avWasCopied.resize(pMesh->mNumVertices,0xFFFFFFFF);
  404|       |
  405|       |        // try to find a good estimate for the number of output faces
  406|       |        // per mesh. Add 12.5% as buffer
  407|      0|        unsigned int iEstimatedSize = pMesh->mNumFaces / iSubMeshes;
  408|      0|        iEstimatedSize += iEstimatedSize >> 3;
  409|       |
  410|       |        // now generate all submeshes
  411|      0|        unsigned int iBase( 0 );
  412|      0|        while (true) {
  ------------------
  |  Branch (412:16): [True: 0, Folded]
  ------------------
  413|      0|            const unsigned int iOutVertexNum = SplitLargeMeshesProcess_Vertex::LIMIT;
  414|      0|            aiMesh* pcMesh          = new aiMesh;
  415|      0|            pcMesh->mNumVertices    = 0;
  416|      0|            pcMesh->mMaterialIndex  = pMesh->mMaterialIndex;
  417|       |
  418|       |            // the name carries the adjacency information between the meshes
  419|      0|            pcMesh->mName = pMesh->mName;
  420|       |
  421|      0|            typedef std::vector<aiVertexWeight> BoneWeightList;
  422|      0|            if (pMesh->HasBones()) {
  ------------------
  |  Branch (422:17): [True: 0, False: 0]
  ------------------
  423|      0|                pcMesh->mBones = new aiBone*[pMesh->mNumBones];
  424|      0|                ::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones);
  425|      0|            }
  426|       |
  427|       |            // clear the temporary helper array
  428|      0|            if (iBase) {
  ------------------
  |  Branch (428:17): [True: 0, False: 0]
  ------------------
  429|       |                // we can't use memset here we unsigned int needn' be 32 bits
  430|      0|                for (auto &elem : avWasCopied) {
  ------------------
  |  Branch (430:33): [True: 0, False: 0]
  ------------------
  431|      0|                    elem = 0xffffffff;
  432|      0|                }
  433|      0|            }
  434|       |
  435|       |            // output vectors
  436|      0|            std::vector<aiFace> vFaces;
  437|       |
  438|       |            // reserve enough storage for most cases
  439|      0|            if (pMesh->HasPositions()) {
  ------------------
  |  Branch (439:17): [True: 0, False: 0]
  ------------------
  440|      0|                pcMesh->mVertices = new aiVector3D[iOutVertexNum];
  441|      0|            }
  442|      0|            if (pMesh->HasNormals()) {
  ------------------
  |  Branch (442:17): [True: 0, False: 0]
  ------------------
  443|      0|                pcMesh->mNormals = new aiVector3D[iOutVertexNum];
  444|      0|            }
  445|      0|            if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (445:17): [True: 0, False: 0]
  ------------------
  446|      0|                pcMesh->mTangents = new aiVector3D[iOutVertexNum];
  447|      0|                pcMesh->mBitangents = new aiVector3D[iOutVertexNum];
  448|      0|            }
  449|      0|            for (unsigned int c = 0; pMesh->HasVertexColors(c);++c) {
  ------------------
  |  Branch (449:38): [True: 0, False: 0]
  ------------------
  450|      0|                pcMesh->mColors[c] = new aiColor4D[iOutVertexNum];
  451|      0|            }
  452|      0|            for (unsigned int c = 0; pMesh->HasTextureCoords(c);++c) {
  ------------------
  |  Branch (452:38): [True: 0, False: 0]
  ------------------
  453|      0|                pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
  454|      0|                pcMesh->mTextureCoords[c] = new aiVector3D[iOutVertexNum];
  455|      0|            }
  456|      0|            vFaces.reserve(iEstimatedSize);
  457|       |
  458|       |            // (we will also need to copy the array of indices)
  459|      0|            while (iBase < pMesh->mNumFaces) {
  ------------------
  |  Branch (459:20): [True: 0, False: 0]
  ------------------
  460|       |                // allocate a new array
  461|      0|                const unsigned int iNumIndices = pMesh->mFaces[iBase].mNumIndices;
  462|       |
  463|       |                // doesn't catch degenerates but is quite fast
  464|      0|                unsigned int iNeed = 0;
  465|      0|                for (unsigned int v = 0; v < iNumIndices;++v) {
  ------------------
  |  Branch (465:42): [True: 0, False: 0]
  ------------------
  466|      0|                    unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
  467|       |
  468|       |                    // check whether we do already have this vertex
  469|      0|                    if (0xFFFFFFFF == avWasCopied[iIndex]) {
  ------------------
  |  Branch (469:25): [True: 0, False: 0]
  ------------------
  470|      0|                        iNeed++;
  471|      0|                    }
  472|      0|                }
  473|      0|                if (pcMesh->mNumVertices + iNeed > iOutVertexNum) {
  ------------------
  |  Branch (473:21): [True: 0, False: 0]
  ------------------
  474|       |                    // don't use this face
  475|      0|                    break;
  476|      0|                }
  477|       |
  478|      0|                vFaces.emplace_back();
  479|      0|                aiFace& rFace = vFaces.back();
  480|       |
  481|       |                // setup face type and number of indices
  482|      0|                rFace.mNumIndices = iNumIndices;
  483|      0|                rFace.mIndices = new unsigned int[iNumIndices];
  484|       |
  485|       |                // need to update the output primitive types
  486|      0|                switch (rFace.mNumIndices) {
  487|      0|                case 1:
  ------------------
  |  Branch (487:17): [True: 0, False: 0]
  ------------------
  488|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  489|      0|                    break;
  490|      0|                case 2:
  ------------------
  |  Branch (490:17): [True: 0, False: 0]
  ------------------
  491|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  492|      0|                    break;
  493|      0|                case 3:
  ------------------
  |  Branch (493:17): [True: 0, False: 0]
  ------------------
  494|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  495|      0|                    break;
  496|      0|                default:
  ------------------
  |  Branch (496:17): [True: 0, False: 0]
  ------------------
  497|      0|                    pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  498|      0|                }
  499|       |
  500|       |                // and copy the contents of the old array, offset by current base
  501|      0|                for (unsigned int v = 0; v < iNumIndices;++v) {
  ------------------
  |  Branch (501:42): [True: 0, False: 0]
  ------------------
  502|      0|                    unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
  503|       |
  504|       |                    // check whether we do already have this vertex
  505|      0|                    if (0xFFFFFFFF != avWasCopied[iIndex]) {
  ------------------
  |  Branch (505:25): [True: 0, False: 0]
  ------------------
  506|      0|                        rFace.mIndices[v] = avWasCopied[iIndex];
  507|      0|                        continue;
  508|      0|                    }
  509|       |
  510|       |                    // copy positions
  511|      0|                    pcMesh->mVertices[pcMesh->mNumVertices] = (pMesh->mVertices[iIndex]);
  512|       |
  513|       |                    // copy normals
  514|      0|                    if (pMesh->HasNormals()) {
  ------------------
  |  Branch (514:25): [True: 0, False: 0]
  ------------------
  515|      0|                        pcMesh->mNormals[pcMesh->mNumVertices] = (pMesh->mNormals[iIndex]);
  516|      0|                    }
  517|       |
  518|       |                    // copy tangents/bitangents
  519|      0|                    if (pMesh->HasTangentsAndBitangents()) {
  ------------------
  |  Branch (519:25): [True: 0, False: 0]
  ------------------
  520|      0|                        pcMesh->mTangents[pcMesh->mNumVertices] = (pMesh->mTangents[iIndex]);
  521|      0|                        pcMesh->mBitangents[pcMesh->mNumVertices] = (pMesh->mBitangents[iIndex]);
  522|      0|                    }
  523|       |
  524|       |                    // texture coordinates
  525|      0|                    for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
  ------------------
  |  Branch (525:47): [True: 0, False: 0]
  ------------------
  526|      0|                        if (pMesh->HasTextureCoords( c)) {
  ------------------
  |  Branch (526:29): [True: 0, False: 0]
  ------------------
  527|      0|                            pcMesh->mTextureCoords[c][pcMesh->mNumVertices] = pMesh->mTextureCoords[c][iIndex];
  528|      0|                        }
  529|      0|                    }
  530|       |                    // vertex colors
  531|      0|                    for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) {
  ------------------
  |  Branch (531:47): [True: 0, False: 0]
  ------------------
  532|      0|                        if (pMesh->HasVertexColors( c)) {
  ------------------
  |  Branch (532:29): [True: 0, False: 0]
  ------------------
  533|      0|                            pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex];
  534|      0|                        }
  535|      0|                    }
  536|       |                    // check whether we have bone weights assigned to this vertex
  537|      0|                    rFace.mIndices[v] = pcMesh->mNumVertices;
  538|      0|                    if (avPerVertexWeights) {
  ------------------
  |  Branch (538:25): [True: 0, False: 0]
  ------------------
  539|      0|                        VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ];
  540|      0|                        if( !table.empty() ) {
  ------------------
  |  Branch (540:29): [True: 0, False: 0]
  ------------------
  541|      0|                            for (VertexWeightTable::const_iterator iter =  table.begin();
  542|      0|                                    iter != table.end();++iter) {
  ------------------
  |  Branch (542:37): [True: 0, False: 0]
  ------------------
  543|       |                                // allocate the bone weight array if necessary
  544|      0|                                BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first];
  545|      0|                                if (nullptr == pcWeightList) {
  ------------------
  |  Branch (545:37): [True: 0, False: 0]
  ------------------
  546|      0|                                    pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList());
  547|      0|                                }
  548|      0|                                pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second));
  549|      0|                            }
  550|      0|                        }
  551|      0|                    }
  552|       |
  553|      0|                    avWasCopied[iIndex] = pcMesh->mNumVertices;
  554|      0|                    pcMesh->mNumVertices++;
  555|      0|                }
  556|      0|                ++iBase;
  557|      0|                if(pcMesh->mNumVertices == iOutVertexNum) {
  ------------------
  |  Branch (557:20): [True: 0, False: 0]
  ------------------
  558|       |                    // break here. The face is only added if it was complete
  559|      0|                    break;
  560|      0|                }
  561|      0|            }
  562|       |
  563|       |            // check which bones we'll need to create for this submesh
  564|      0|            if (pMesh->HasBones()) {
  ------------------
  |  Branch (564:17): [True: 0, False: 0]
  ------------------
  565|      0|                aiBone** ppCurrent = pcMesh->mBones;
  566|      0|                for (unsigned int k = 0; k < pMesh->mNumBones;++k) {
  ------------------
  |  Branch (566:42): [True: 0, False: 0]
  ------------------
  567|       |                    // check whether the bone is existing
  568|      0|                    BoneWeightList* pcWeightList;
  569|      0|                    pcWeightList = (BoneWeightList *)pcMesh->mBones[k];
  570|      0|                    if (nullptr != pcWeightList) {
  ------------------
  |  Branch (570:25): [True: 0, False: 0]
  ------------------
  571|      0|                        aiBone *pcOldBone = pMesh->mBones[k];
  572|      0|                        aiBone* pcOut( nullptr );
  573|      0|                        *ppCurrent++ = pcOut = new aiBone();
  574|      0|                        pcOut->mName = aiString(pcOldBone->mName);
  575|      0|                        pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix;
  576|      0|                        pcOut->mNumWeights = (unsigned int)pcWeightList->size();
  577|      0|                        pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights];
  578|       |
  579|       |                        // copy the vertex weights
  580|      0|                        ::memcpy(pcOut->mWeights,&pcWeightList->operator[](0),
  581|      0|                            pcOut->mNumWeights * sizeof(aiVertexWeight));
  582|       |
  583|       |                        // delete the temporary bone weight list
  584|      0|                        delete pcWeightList;
  585|      0|                        pcMesh->mNumBones++;
  586|      0|                    }
  587|      0|                }
  588|      0|            }
  589|       |
  590|       |            // copy the face list to the mesh
  591|      0|            pcMesh->mFaces = new aiFace[vFaces.size()];
  592|      0|            pcMesh->mNumFaces = (unsigned int)vFaces.size();
  593|       |
  594|      0|            for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) {
  ------------------
  |  Branch (594:38): [True: 0, False: 0]
  ------------------
  595|      0|                pcMesh->mFaces[p] = vFaces[p];
  596|      0|            }
  597|       |
  598|       |            // add the newly created mesh to the list
  599|      0|            avList.emplace_back(pcMesh,a);
  600|       |
  601|      0|            if (iBase == pMesh->mNumFaces) {
  ------------------
  |  Branch (601:17): [True: 0, False: 0]
  ------------------
  602|       |                // have all faces ... finish the outer loop, too
  603|      0|                break;
  604|      0|            }
  605|      0|        }
  606|       |
  607|       |        // delete the per-vertex weight list again
  608|      0|        delete[] avPerVertexWeights;
  609|       |
  610|       |        // now delete the old mesh data
  611|      0|        delete pMesh;
  612|      0|        return;
  613|      0|    }
  614|     94|    avList.emplace_back(pMesh,a);
  615|     94|}

_ZNK6Assimp20TextureTransformStep8IsActiveEj:
   54|    218|bool TextureTransformStep::IsActive( unsigned int pFlags) const {
   55|    218|    return  (pFlags & aiProcess_TransformUVCoords) != 0;
   56|    218|}

_ZN6Assimp20TextureTransformStepC2Ev:
  172|    297|    TextureTransformStep() = default;

_ZNK6Assimp18TriangulateProcess8IsActiveEj:
  179|    218|bool TriangulateProcess::IsActive( unsigned int pFlags) const {
  180|    218|    return (pFlags & aiProcess_Triangulate) != 0;
  181|    218|}
_ZN6Assimp18TriangulateProcess7ExecuteEP7aiScene:
  185|    218|void TriangulateProcess::Execute( aiScene* pScene) {
  186|    218|    ASSIMP_LOG_DEBUG("TriangulateProcess begin");
  187|       |
  188|    218|    bool bHas = false;
  189|    312|    for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
  ------------------
  |  Branch (189:30): [True: 94, False: 218]
  ------------------
  190|     94|    {
  191|     94|        if (pScene->mMeshes[ a ]) {
  ------------------
  |  Branch (191:13): [True: 94, False: 0]
  ------------------
  192|     94|            if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
  ------------------
  |  Branch (192:18): [True: 94, False: 0]
  ------------------
  193|     94|                bHas = true;
  194|     94|            }
  195|     94|        }
  196|     94|    }
  197|    218|    if ( bHas ) {
  ------------------
  |  Branch (197:10): [True: 91, False: 127]
  ------------------
  198|     91|        ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." );
  199|    127|    } else {
  200|       |        ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." );
  201|    127|    }
  202|    218|}
_ZN6Assimp18TriangulateProcess15TriangulateMeshEP6aiMesh:
  206|     94|bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) {
  207|       |    // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
  208|     94|    if (!pMesh->mPrimitiveTypes)    {
  ------------------
  |  Branch (208:9): [True: 0, False: 94]
  ------------------
  209|      0|        bool bNeed = false;
  210|       |
  211|      0|        for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (211:34): [True: 0, False: 0]
  ------------------
  212|      0|            const aiFace& face = pMesh->mFaces[a];
  213|      0|            if( face.mNumIndices != 3)  {
  ------------------
  |  Branch (213:17): [True: 0, False: 0]
  ------------------
  214|      0|                bNeed = true;
  215|      0|            }
  216|      0|        }
  217|      0|        if (!bNeed) {
  ------------------
  |  Branch (217:13): [True: 0, False: 0]
  ------------------
  218|      0|            return false;
  219|      0|        }
  220|      0|    }
  221|     94|    else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (221:14): [True: 0, False: 94]
  ------------------
  222|      0|        return false;
  223|      0|    }
  224|       |
  225|       |    // Find out how many output faces we'll get
  226|     94|    uint32_t numOut = 0, max_out = 0;
  227|     94|    bool get_normals = true;
  228|  89.9k|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (228:30): [True: 89.8k, False: 94]
  ------------------
  229|  89.8k|        aiFace& face = pMesh->mFaces[a];
  230|  89.8k|        if (face.mNumIndices <= 4) {
  ------------------
  |  Branch (230:13): [True: 87.9k, False: 1.88k]
  ------------------
  231|  87.9k|            get_normals = false;
  232|  87.9k|        }
  233|  89.8k|        if( face.mNumIndices <= 3) {
  ------------------
  |  Branch (233:13): [True: 32, False: 89.7k]
  ------------------
  234|     32|            ++numOut;
  235|  89.7k|        } else {
  236|  89.7k|            numOut += face.mNumIndices-2;
  237|  89.7k|            max_out = std::max<uint32_t>(max_out,face.mNumIndices);
  238|  89.7k|        }
  239|  89.8k|    }
  240|       |
  241|       |    // Just another check whether aiMesh::mPrimitiveTypes is correct
  242|     94|    if (numOut == pMesh->mNumFaces) {
  ------------------
  |  Branch (242:9): [True: 0, False: 94]
  ------------------
  243|      0|        ASSIMP_LOG_ERROR( "Invalidation detected in the number of indices: does not fit to the primitive type." );
  244|      0|        return false;
  245|      0|    }
  246|       |
  247|     94|    aiVector3D *nor_out = nullptr;
  248|       |
  249|       |    // if we don't have normals yet, but expect them to be a cheap side
  250|       |    // product of triangulation anyway, allocate storage for them.
  251|     94|    if (!pMesh->mNormals && get_normals) {
  ------------------
  |  Branch (251:9): [True: 70, False: 24]
  |  Branch (251:29): [True: 0, False: 70]
  ------------------
  252|       |        // XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals
  253|       |    //  nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  254|      0|    }
  255|       |
  256|       |    // the output mesh will contain triangles, but no polys anymore
  257|     94|    pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  258|     94|    pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
  259|       |
  260|       |    // The mesh becomes NGON encoded now, during the triangulation process.
  261|     94|    pMesh->mPrimitiveTypes |= aiPrimitiveType_NGONEncodingFlag;
  262|       |
  263|     94|    aiFace* out = new aiFace[numOut](), *curOut = out;
  264|     94|    std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */
  265|     94|    std::vector<std::vector<aiVector2D>> temp_poly(1); /* temporary storage for earcut.hpp */
  266|     94|    std::vector<aiVector2D>& temp_verts = temp_poly[0];
  267|     94|    temp_verts.reserve(max_out + 2);
  268|       |
  269|     94|    NGONEncoder ngonEncoder;
  270|       |
  271|       |    // Apply vertex colors to represent the face winding?
  272|       |#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
  273|       |    if (!pMesh->mColors[0])
  274|       |        pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
  275|       |    else
  276|       |        new(pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices];
  277|       |
  278|       |    aiColor4D* clr = pMesh->mColors[0];
  279|       |#endif
  280|       |
  281|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  282|       |    FILE* fout = fopen(POLY_OUTPUT_FILE,"a");
  283|       |#endif
  284|       |
  285|     94|    const aiVector3D* verts = pMesh->mVertices;
  286|       |
  287|  89.9k|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (287:30): [True: 89.8k, False: 94]
  ------------------
  288|  89.8k|        aiFace& face = pMesh->mFaces[a];
  289|       |
  290|  89.8k|        unsigned int* idx = face.mIndices;
  291|  89.8k|        unsigned int num = face.mNumIndices;
  292|       |
  293|       |        // Apply vertex colors to represent the face winding?
  294|       |#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
  295|       |        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  296|       |            aiColor4D& c = clr[idx[i]];
  297|       |            c.r = (i+1) / (float)max;
  298|       |            c.b = 1.f - c.r;
  299|       |        }
  300|       |#endif
  301|       |
  302|  89.8k|        aiFace* const last_face = curOut;
  303|       |
  304|       |        // if it's a simple point,line or triangle: just copy it
  305|  89.8k|        if( face.mNumIndices <= 3)
  ------------------
  |  Branch (305:13): [True: 32, False: 89.7k]
  ------------------
  306|     32|        {
  307|     32|            aiFace& nface = *curOut++;
  308|     32|            nface.mNumIndices = face.mNumIndices;
  309|     32|            nface.mIndices    = face.mIndices;
  310|     32|            face.mIndices = nullptr;
  311|       |
  312|       |            // points and lines don't require ngon encoding (and are not supported either!)
  313|     32|            if (nface.mNumIndices == 3) ngonEncoder.ngonEncodeTriangle(&nface);
  ------------------
  |  Branch (313:17): [True: 11, False: 21]
  ------------------
  314|       |
  315|     32|            continue;
  316|     32|        }
  317|       |        // optimized code for quadrilaterals
  318|  89.7k|        else if ( face.mNumIndices == 4) {
  ------------------
  |  Branch (318:19): [True: 87.8k, False: 1.88k]
  ------------------
  319|       |
  320|       |            // quads can have at maximum one concave vertex. Determine
  321|       |            // this vertex (if it exists) and start tri-fanning from
  322|       |            // it.
  323|  87.8k|            unsigned int start_vertex = 0;
  324|   439k|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (324:38): [True: 351k, False: 87.8k]
  ------------------
  325|   351k|                const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]];
  326|   351k|                const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]];
  327|   351k|                const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]];
  328|       |
  329|   351k|                const aiVector3D& v = verts[face.mIndices[i]];
  330|       |
  331|   351k|                aiVector3D left = (v0-v);
  332|   351k|                aiVector3D diag = (v1-v);
  333|   351k|                aiVector3D right = (v2-v);
  334|       |
  335|   351k|                left.Normalize();
  336|   351k|                diag.Normalize();
  337|   351k|                right.Normalize();
  338|       |
  339|   351k|                const float angle = std::acos(left*diag) + std::acos(right*diag);
  340|   351k|                if (angle > AI_MATH_PI_F) {
  ------------------
  |  Branch (340:21): [True: 76, False: 351k]
  ------------------
  341|       |                    // this is the concave point
  342|     76|                    start_vertex = i;
  343|     76|                    break;
  344|     76|                }
  345|   351k|            }
  346|       |
  347|  87.8k|            const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]};
  348|       |
  349|  87.8k|            aiFace& nface = *curOut++;
  350|  87.8k|            nface.mNumIndices = 3;
  351|  87.8k|            nface.mIndices = face.mIndices;
  352|       |
  353|  87.8k|            nface.mIndices[0] = temp[start_vertex];
  354|  87.8k|            nface.mIndices[1] = temp[(start_vertex + 1) % 4];
  355|  87.8k|            nface.mIndices[2] = temp[(start_vertex + 2) % 4];
  356|       |
  357|  87.8k|            aiFace& sface = *curOut++;
  358|  87.8k|            sface.mNumIndices = 3;
  359|  87.8k|            sface.mIndices = new unsigned int[3];
  360|       |
  361|  87.8k|            sface.mIndices[0] = temp[start_vertex];
  362|  87.8k|            sface.mIndices[1] = temp[(start_vertex + 2) % 4];
  363|  87.8k|            sface.mIndices[2] = temp[(start_vertex + 3) % 4];
  364|       |
  365|       |            // prevent double deletion of the indices field
  366|  87.8k|            face.mIndices = nullptr;
  367|       |
  368|  87.8k|            ngonEncoder.ngonEncodeQuad(&nface, &sface);
  369|       |
  370|  87.8k|            continue;
  371|  87.8k|        }
  372|  1.88k|        else
  373|  1.88k|        {
  374|       |            // A polygon with more than 3 vertices can be either concave or convex.
  375|       |            // Usually everything we're getting is convex and we could easily
  376|       |            // triangulate by tri-fanning. However, LightWave is probably the only
  377|       |            // modeling suite to make extensive use of highly concave, monster polygons ...
  378|       |            // so we need to apply the full 'ear cutting' algorithm to get it right.
  379|       |
  380|       |            // REQUIREMENT: polygon is expected to be simple and *nearly* planar.
  381|       |            // We project it onto a plane to get a 2d triangle.
  382|       |
  383|       |            // Collect all vertices of of the polygon.
  384|   170k|            for (unsigned int tmp = 0; tmp < num; ++tmp) {
  ------------------
  |  Branch (384:40): [True: 168k, False: 1.88k]
  ------------------
  385|   168k|                temp_verts3d[tmp] = verts[idx[tmp]];
  386|   168k|            }
  387|       |
  388|       |            // Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh
  389|  1.88k|            aiVector3D n;
  390|  1.88k|            NewellNormal<3, 3, 3>(n, num, &temp_verts3d.front().x, &temp_verts3d.front().y, &temp_verts3d.front().z);
  391|  1.88k|            if (nor_out) {
  ------------------
  |  Branch (391:17): [True: 0, False: 1.88k]
  ------------------
  392|      0|                for (unsigned int tmp = 0; tmp < num; ++tmp)
  ------------------
  |  Branch (392:44): [True: 0, False: 0]
  ------------------
  393|      0|                    nor_out[idx[tmp]] = n;
  394|      0|            }
  395|       |
  396|       |            // Select largest normal coordinate to ignore for projection
  397|  1.88k|            const float ax = (n.x>0 ? n.x : -n.x);
  ------------------
  |  Branch (397:31): [True: 1.22k, False: 664]
  ------------------
  398|  1.88k|            const float ay = (n.y>0 ? n.y : -n.y);
  ------------------
  |  Branch (398:31): [True: 1.18k, False: 699]
  ------------------
  399|  1.88k|            const float az = (n.z>0 ? n.z : -n.z);
  ------------------
  |  Branch (399:31): [True: 527, False: 1.35k]
  ------------------
  400|       |
  401|  1.88k|            unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */
  402|  1.88k|            float inv = n.z;
  403|  1.88k|            if (ax > ay) {
  ------------------
  |  Branch (403:17): [True: 1.16k, False: 717]
  ------------------
  404|  1.16k|                if (ax > az) { /* no x coord. projection to yz */
  ------------------
  |  Branch (404:21): [True: 663, False: 504]
  ------------------
  405|    663|                    ac = 1; bc = 2;
  406|    663|                    inv = n.x;
  407|    663|                }
  408|  1.16k|            }
  409|    717|            else if (ay > az) { /* no y coord. projection to zy */
  ------------------
  |  Branch (409:22): [True: 20, False: 697]
  ------------------
  410|     20|                ac = 2; bc = 0;
  411|     20|                inv = n.y;
  412|     20|            }
  413|       |
  414|       |            // Swap projection axes to take the negated projection vector into account
  415|  1.88k|            if (inv < 0.f) {
  ------------------
  |  Branch (415:17): [True: 1.37k, False: 509]
  ------------------
  416|  1.37k|                std::swap(ac,bc);
  417|  1.37k|            }
  418|       |
  419|  1.88k|            temp_verts.resize(num);
  420|   170k|            for (unsigned int tmp = 0; tmp < num; ++tmp) {
  ------------------
  |  Branch (420:40): [True: 168k, False: 1.88k]
  ------------------
  421|   168k|                temp_verts[tmp].x = verts[idx[tmp]][ac];
  422|   168k|                temp_verts[tmp].y = verts[idx[tmp]][bc];
  423|   168k|            }
  424|       |
  425|  1.88k|            auto indices = mapbox::earcut(temp_poly);
  426|  7.66k|            for (size_t i = 0; i < indices.size(); i += 3) {
  ------------------
  |  Branch (426:32): [True: 5.77k, False: 1.88k]
  ------------------
  427|  5.77k|                aiFace& nface = *curOut++;
  428|  5.77k|                nface.mIndices = new unsigned int[3];
  429|  5.77k|                nface.mNumIndices = 3;
  430|  5.77k|                nface.mIndices[0] = indices[i];
  431|  5.77k|                nface.mIndices[1] = indices[i + 1];
  432|  5.77k|                nface.mIndices[2] = indices[i + 2];
  433|  5.77k|            }
  434|       |
  435|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  436|       |            // plot the plane onto which we mapped the polygon to a 2D ASCII pic
  437|       |            aiVector2D bmin,bmax;
  438|       |            ArrayBounds(&temp_verts[0],max,bmin,bmax);
  439|       |
  440|       |            char grid[POLY_GRID_Y][POLY_GRID_X+POLY_GRID_XPAD];
  441|       |            std::fill_n((char*)grid,POLY_GRID_Y*(POLY_GRID_X+POLY_GRID_XPAD),' ');
  442|       |
  443|       |            for (int i =0; i < max; ++i) {
  444|       |                const aiVector2D& v = (temp_verts[i] - bmin) / (bmax-bmin);
  445|       |                const size_t x = static_cast<size_t>(v.x*(POLY_GRID_X-1)), y = static_cast<size_t>(v.y*(POLY_GRID_Y-1));
  446|       |                char* loc = grid[y]+x;
  447|       |                if (grid[y][x] != ' ') {
  448|       |                    for(;*loc != ' '; ++loc);
  449|       |                    *loc++ = '_';
  450|       |                }
  451|       |                *(loc+::ai_snprintf(loc, POLY_GRID_XPAD,"%i",i)) = ' ';
  452|       |            }
  453|       |
  454|       |
  455|       |            for(size_t y = 0; y < POLY_GRID_Y; ++y) {
  456|       |                grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0';
  457|       |                fprintf(fout,"%s\n",grid[y]);
  458|       |            }
  459|       |
  460|       |            fprintf(fout,"\ntriangulation sequence: ");
  461|       |#endif
  462|  1.88k|        }
  463|       |
  464|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  465|       |
  466|       |        for(aiFace* f = last_face; f != curOut; ++f) {
  467|       |            unsigned int* i = f->mIndices;
  468|       |            fprintf(fout," (%i %i %i)",i[0],i[1],i[2]);
  469|       |        }
  470|       |
  471|       |        fprintf(fout,"\n*********************************************************************\n");
  472|       |        fflush(fout);
  473|       |
  474|       |#endif
  475|       |
  476|  7.66k|        for(aiFace* f = last_face; f != curOut; ) {
  ------------------
  |  Branch (476:36): [True: 5.77k, False: 1.88k]
  ------------------
  477|  5.77k|            unsigned int* i = f->mIndices;
  478|       |
  479|  5.77k|            i[0] = idx[i[0]];
  480|  5.77k|            i[1] = idx[i[1]];
  481|  5.77k|            i[2] = idx[i[2]];
  482|       |
  483|       |            // IMPROVEMENT: Polygons are not supported yet by this ngon encoding + triangulation step.
  484|       |            //              So we encode polygons as regular triangles. No way to reconstruct the original
  485|       |            //              polygon in this case.
  486|  5.77k|            ngonEncoder.ngonEncodeTriangle(f);
  487|  5.77k|            ++f;
  488|  5.77k|        }
  489|       |
  490|  1.88k|        delete[] face.mIndices;
  491|  1.88k|        face.mIndices = nullptr;
  492|  1.88k|    }
  493|       |
  494|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  495|       |    fclose(fout);
  496|       |#endif
  497|       |
  498|       |    // kill the old faces
  499|     94|    delete [] pMesh->mFaces;
  500|       |
  501|       |    // ... and store the new ones
  502|     94|    pMesh->mFaces    = out;
  503|     94|    pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */
  504|     94|    return true;
  505|     94|}
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoderC2Ev:
  103|     94|        NGONEncoder() : mLastNGONFirstIndex((unsigned int)-1) {}
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoder18ngonEncodeTriangleEP6aiFace:
  114|  5.78k|        void ngonEncodeTriangle(aiFace * tri) {
  115|  5.78k|            ai_assert(tri->mNumIndices == 3);
  116|       |
  117|       |            // Rotate indices in new triangle to avoid ngon encoding false ngons
  118|       |            // Otherwise, the new triangle would be considered part of the previous NGON.
  119|  5.78k|            if (isConsideredSameAsLastNgon(tri)) {
  ------------------
  |  Branch (119:17): [True: 189, False: 5.59k]
  ------------------
  120|    189|                std::swap(tri->mIndices[0], tri->mIndices[2]);
  121|    189|                std::swap(tri->mIndices[1], tri->mIndices[2]);
  122|    189|            }
  123|       |
  124|  5.78k|            mLastNGONFirstIndex = tri->mIndices[0];
  125|  5.78k|        }
TriangulateProcess.cpp:_ZNK12_GLOBAL__N_111NGONEncoder26isConsideredSameAsLastNgonEPK6aiFace:
  166|  93.6k|        bool isConsideredSameAsLastNgon(const aiFace * tri) const {
  167|       |            ai_assert(tri->mNumIndices == 3);
  168|  93.6k|            return tri->mIndices[0] == mLastNGONFirstIndex;
  169|  93.6k|        }
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoder14ngonEncodeQuadEP6aiFaceS2_:
  135|  87.8k|        void ngonEncodeQuad(aiFace *tri1, aiFace *tri2) {
  136|  87.8k|            ai_assert(tri1->mNumIndices == 3);
  137|  87.8k|            ai_assert(tri2->mNumIndices == 3);
  138|  87.8k|            ai_assert(tri1->mIndices[0] == tri2->mIndices[0]);
  139|       |
  140|       |            // If the selected fanning vertex is the same as the previously
  141|       |            // emitted ngon, we use the opposite vertex which also happens to work
  142|       |            // for tri-fanning a concave quad.
  143|       |            // ref: https://github.com/assimp/assimp/pull/3695#issuecomment-805999760
  144|  87.8k|            if (isConsideredSameAsLastNgon(tri1)) {
  ------------------
  |  Branch (144:17): [True: 0, False: 87.8k]
  ------------------
  145|       |                // Right-rotate indices for tri1 (index 2 becomes the new fanning vertex)
  146|      0|                std::swap(tri1->mIndices[0], tri1->mIndices[2]);
  147|      0|                std::swap(tri1->mIndices[1], tri1->mIndices[2]);
  148|       |
  149|       |                // Left-rotate indices for tri2 (index 2 becomes the new fanning vertex)
  150|      0|                std::swap(tri2->mIndices[1], tri2->mIndices[2]);
  151|      0|                std::swap(tri2->mIndices[0], tri2->mIndices[2]);
  152|       |
  153|      0|                ai_assert(tri1->mIndices[0] == tri2->mIndices[0]);
  154|      0|            }
  155|       |
  156|  87.8k|            mLastNGONFirstIndex = tri1->mIndices[0];
  157|  87.8k|        }
_ZN6mapbox4util3nthILm0E10aiVector2tIfEE3getERKS3_:
   82|   505k|    inline static auto get(const aiVector2D& t) {
   83|   505k|        return t.x;
   84|   505k|    }
_ZN6mapbox4util3nthILm1E10aiVector2tIfEE3getERKS3_:
   88|   505k|    inline static auto get(const aiVector2D& t) {
   89|   505k|        return t.y;
   90|   505k|    }

_ZN6Assimp18TriangulateProcessC2Ev:
   65|    297|    TriangulateProcess() = default;

_ZN6Assimp17ValidateDSProcessC2Ev:
   61|    227|ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {}
_ZN6Assimp17ValidateDSProcess11ReportErrorEPKcz:
   69|      9|AI_WONT_RETURN void ValidateDSProcess::ReportError(const char *msg, ...) {
   70|      9|    ai_assert(nullptr != msg);
   71|       |
   72|      9|    va_list args;
   73|      9|    va_start(args, msg);
   74|       |
   75|      9|    char szBuffer[3000];
   76|      9|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   77|      9|    ai_assert(iLen > 0);
   78|       |
   79|      9|    va_end(args);
   80|       |
   81|      9|    throw DeadlyImportError("Validation failed: ", std::string(szBuffer, iLen));
   82|      9|}
_ZN6Assimp17ValidateDSProcess13ReportWarningEPKcz:
   84|   276k|void ValidateDSProcess::ReportWarning(const char *msg, ...) {
   85|   276k|    ai_assert(nullptr != msg);
   86|       |
   87|   276k|    va_list args;
   88|   276k|    va_start(args, msg);
   89|       |
   90|   276k|    char szBuffer[3000];
   91|   276k|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   92|   276k|    ai_assert(iLen > 0);
   93|       |
   94|   276k|    va_end(args);
   95|       |    ASSIMP_LOG_WARN("Validation warning: ", std::string(szBuffer, iLen));
   96|   276k|}
_ZN6Assimp17ValidateDSProcess7ExecuteEP7aiScene:
  183|    227|void ValidateDSProcess::Execute(aiScene *pScene) {
  184|    227|    mScene = pScene;
  185|    227|    ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin");
  186|       |
  187|       |    // validate the node graph of the scene
  188|    227|    Validate(pScene->mRootNode);
  189|       |
  190|       |    // validate all meshes
  191|    227|    if (pScene->mNumMeshes) {
  ------------------
  |  Branch (191:9): [True: 92, False: 135]
  ------------------
  192|     92|        DoValidation(pScene->mMeshes, pScene->mNumMeshes, "mMeshes", "mNumMeshes");
  193|    135|    } else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
  ------------------
  |  Branch (193:16): [True: 0, False: 135]
  ------------------
  194|      0|        ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
  195|    135|    } else if (pScene->mMeshes) {
  ------------------
  |  Branch (195:16): [True: 0, False: 135]
  ------------------
  196|      0|        ReportError("aiScene::mMeshes is non-null although there are no meshes");
  197|      0|    }
  198|       |
  199|       |    // validate all animations
  200|    227|    if (pScene->mNumAnimations) {
  ------------------
  |  Branch (200:9): [True: 203, False: 24]
  ------------------
  201|    203|        DoValidation(pScene->mAnimations, pScene->mNumAnimations,
  202|    203|                "mAnimations", "mNumAnimations");
  203|    203|    } else if (pScene->mAnimations) {
  ------------------
  |  Branch (203:16): [True: 0, False: 24]
  ------------------
  204|      0|        ReportError("aiScene::mAnimations is non-null although there are no animations");
  205|      0|    }
  206|       |
  207|       |    // validate all cameras
  208|    227|    if (pScene->mNumCameras) {
  ------------------
  |  Branch (208:9): [True: 197, False: 30]
  ------------------
  209|    197|        DoValidationWithNameCheck(pScene->mCameras, pScene->mNumCameras,
  210|    197|                "mCameras", "mNumCameras");
  211|    197|    } else if (pScene->mCameras) {
  ------------------
  |  Branch (211:16): [True: 0, False: 30]
  ------------------
  212|      0|        ReportError("aiScene::mCameras is non-null although there are no cameras");
  213|      0|    }
  214|       |
  215|       |    // validate all lights
  216|    227|    if (pScene->mNumLights) {
  ------------------
  |  Branch (216:9): [True: 190, False: 37]
  ------------------
  217|    190|        DoValidationWithNameCheck(pScene->mLights, pScene->mNumLights,
  218|    190|                "mLights", "mNumLights");
  219|    190|    } else if (pScene->mLights) {
  ------------------
  |  Branch (219:16): [True: 0, False: 37]
  ------------------
  220|      0|        ReportError("aiScene::mLights is non-null although there are no lights");
  221|      0|    }
  222|       |
  223|       |    // validate all textures
  224|    227|    if (pScene->mNumTextures) {
  ------------------
  |  Branch (224:9): [True: 1, False: 226]
  ------------------
  225|      1|        DoValidation(pScene->mTextures, pScene->mNumTextures,
  226|      1|                "mTextures", "mNumTextures");
  227|    226|    } else if (pScene->mTextures) {
  ------------------
  |  Branch (227:16): [True: 0, False: 226]
  ------------------
  228|      0|        ReportError("aiScene::mTextures is non-null although there are no textures");
  229|      0|    }
  230|       |
  231|       |    // validate all materials
  232|    227|    if (pScene->mNumMaterials) {
  ------------------
  |  Branch (232:9): [True: 91, False: 136]
  ------------------
  233|     91|        DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials");
  234|     91|    }
  235|    136|    else if (pScene->mMaterials) {
  ------------------
  |  Branch (235:14): [True: 0, False: 136]
  ------------------
  236|      0|        ReportError("aiScene::mMaterials is non-null although there are no materials");
  237|      0|    }
  238|       |
  239|       |    //  if (!has)ReportError("The aiScene data structure is empty");
  240|       |    ASSIMP_LOG_DEBUG("ValidateDataStructureProcess end");
  241|    227|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK7aiLight:
  244|    190|void ValidateDSProcess::Validate(const aiLight *pLight) {
  245|    190|    if (pLight->mType == aiLightSource_UNDEFINED)
  ------------------
  |  Branch (245:9): [True: 0, False: 190]
  ------------------
  246|      0|        ReportWarning("aiLight::mType is aiLightSource_UNDEFINED");
  247|       |
  248|    190|    if (!pLight->mAttenuationConstant &&
  ------------------
  |  Branch (248:9): [True: 190, False: 0]
  ------------------
  249|    190|            !pLight->mAttenuationLinear &&
  ------------------
  |  Branch (249:13): [True: 190, False: 0]
  ------------------
  250|    190|            !pLight->mAttenuationQuadratic) {
  ------------------
  |  Branch (250:13): [True: 1, False: 189]
  ------------------
  251|      1|        ReportWarning("aiLight::mAttenuationXXX - all are zero");
  252|      1|    }
  253|       |
  254|    190|    if (pLight->mAngleInnerCone > pLight->mAngleOuterCone)
  ------------------
  |  Branch (254:9): [True: 0, False: 190]
  ------------------
  255|      0|        ReportError("aiLight::mAngleInnerCone is larger than aiLight::mAngleOuterCone");
  256|       |
  257|    190|    if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack() && pLight->mColorSpecular.IsBlack()) {
  ------------------
  |  Branch (257:9): [True: 0, False: 190]
  |  Branch (257:44): [True: 0, False: 0]
  |  Branch (257:79): [True: 0, False: 0]
  ------------------
  258|      0|        ReportWarning("aiLight::mColorXXX - all are black and won't have any influence");
  259|      0|    }
  260|    190|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiCamera:
  263|    197|void ValidateDSProcess::Validate(const aiCamera *pCamera) {
  264|    197|    if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear)
  ------------------
  |  Branch (264:9): [True: 0, False: 197]
  ------------------
  265|      0|        ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear");
  266|       |
  267|       |    // There are many 3ds files with invalid FOVs. No reason to reject them at all ... a warning is appropriate.
  268|    197|    if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI)
  ------------------
  |  Branch (268:9): [True: 0, False: 197]
  |  Branch (268:37): [True: 0, False: 197]
  ------------------
  269|      0|        ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV);
  270|    197|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMesh:
  273|     95|void ValidateDSProcess::Validate(const aiMesh *pMesh) {
  274|       |    // validate the material index of the mesh
  275|     95|    if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) {
  ------------------
  |  Branch (275:9): [True: 95, False: 0]
  |  Branch (275:34): [True: 0, False: 95]
  ------------------
  276|      0|        ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)",
  277|      0|                pMesh->mMaterialIndex, mScene->mNumMaterials - 1);
  278|      0|    }
  279|       |
  280|     95|    Validate(&pMesh->mName);
  281|       |
  282|  90.9k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (282:30): [True: 90.8k, False: 95]
  ------------------
  283|  90.8k|        aiFace &face = pMesh->mFaces[i];
  284|       |
  285|  90.8k|        if (pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (285:13): [True: 90.8k, False: 0]
  ------------------
  286|  90.8k|            switch (face.mNumIndices) {
  287|      0|            case 0:
  ------------------
  |  Branch (287:13): [True: 0, False: 90.8k]
  ------------------
  288|      0|                ReportError("aiMesh::mFaces[%i].mNumIndices is 0", i);
  289|      0|            case 1:
  ------------------
  |  Branch (289:13): [True: 0, False: 90.8k]
  ------------------
  290|      0|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT)) {
  ------------------
  |  Branch (290:21): [True: 0, False: 0]
  ------------------
  291|      0|                    ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimitiveTypes "
  292|      0|                                "does not report the POINT flag",
  293|      0|                            i);
  294|      0|                }
  295|      0|                break;
  296|     21|            case 2:
  ------------------
  |  Branch (296:13): [True: 21, False: 90.8k]
  ------------------
  297|     21|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE)) {
  ------------------
  |  Branch (297:21): [True: 0, False: 21]
  ------------------
  298|      0|                    ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimitiveTypes "
  299|      0|                                "does not report the LINE flag",
  300|      0|                            i);
  301|      0|                }
  302|     21|                break;
  303|     11|            case 3:
  ------------------
  |  Branch (303:13): [True: 11, False: 90.8k]
  ------------------
  304|     11|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) {
  ------------------
  |  Branch (304:21): [True: 0, False: 11]
  ------------------
  305|      0|                    ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimitiveTypes "
  306|      0|                                "does not report the TRIANGLE flag",
  307|      0|                            i);
  308|      0|                }
  309|     11|                break;
  310|  90.8k|            default:
  ------------------
  |  Branch (310:13): [True: 90.8k, False: 32]
  ------------------
  311|  90.8k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (311:21): [True: 0, False: 90.8k]
  ------------------
  312|      0|                    this->ReportError("aiMesh::mFaces[%i] is a POLYGON but aiMesh::mPrimitiveTypes "
  313|      0|                                      "does not report the POLYGON flag",
  314|      0|                            i);
  315|      0|                }
  316|  90.8k|                break;
  317|  90.8k|            };
  318|  90.8k|        }
  319|       |
  320|  90.8k|        if (!face.mIndices)
  ------------------
  |  Branch (320:13): [True: 0, False: 90.8k]
  ------------------
  321|      0|            ReportError("aiMesh::mFaces[%i].mIndices is nullptr", i);
  322|  90.8k|    }
  323|       |
  324|       |    // positions must always be there ...
  325|     95|    if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) {
  ------------------
  |  Branch (325:9): [True: 0, False: 95]
  |  Branch (325:34): [True: 0, False: 95]
  |  Branch (325:55): [True: 0, False: 0]
  ------------------
  326|      0|        ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str());
  327|      0|    }
  328|       |
  329|     95|    if (pMesh->mNumVertices > AI_MAX_VERTICES) {
  ------------------
  |  Branch (329:9): [True: 0, False: 95]
  ------------------
  330|      0|        ReportError("Mesh has too many vertices: %u, but the limit is %u", pMesh->mNumVertices, AI_MAX_VERTICES);
  331|      0|    }
  332|     95|    if (pMesh->mNumFaces > AI_MAX_FACES) {
  ------------------
  |  Branch (332:9): [True: 0, False: 95]
  ------------------
  333|      0|        ReportError("Mesh has too many faces: %u, but the limit is %u", pMesh->mNumFaces, AI_MAX_FACES);
  334|      0|    }
  335|       |
  336|       |    // if tangents are there there must also be bitangent vectors ...
  337|     95|    if ((pMesh->mTangents != nullptr) != (pMesh->mBitangents != nullptr)) {
  ------------------
  |  Branch (337:9): [True: 0, False: 95]
  ------------------
  338|      0|        ReportError("If there are tangents, bitangent vectors must be present as well");
  339|      0|    }
  340|       |
  341|       |    // faces, too
  342|     95|    if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) {
  ------------------
  |  Branch (342:9): [True: 0, False: 95]
  |  Branch (342:31): [True: 0, False: 95]
  |  Branch (342:49): [True: 0, False: 0]
  ------------------
  343|      0|        ReportError("Mesh %s contains no faces", pMesh->mName.C_Str());
  344|      0|    }
  345|       |
  346|       |    // now check whether the face indexing layout is correct:
  347|       |    // unique vertices, pseudo-indexed.
  348|     95|    std::vector<bool> abRefList;
  349|     95|    abRefList.resize(pMesh->mNumVertices, false);
  350|  90.9k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (350:30): [True: 90.8k, False: 95]
  ------------------
  351|  90.8k|        aiFace &face = pMesh->mFaces[i];
  352|  90.8k|        if (face.mNumIndices > AI_MAX_FACE_INDICES) {
  ------------------
  |  Branch (352:13): [True: 0, False: 90.8k]
  ------------------
  353|      0|            ReportError("Face %u has too many faces: %u, but the limit is %u", i, face.mNumIndices, AI_MAX_FACE_INDICES);
  354|      0|        }
  355|       |
  356|   615k|        for (unsigned int a = 0; a < face.mNumIndices; ++a) {
  ------------------
  |  Branch (356:34): [True: 524k, False: 90.8k]
  ------------------
  357|   524k|            if (face.mIndices[a] >= pMesh->mNumVertices) {
  ------------------
  |  Branch (357:17): [True: 0, False: 524k]
  ------------------
  358|      0|                ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a);
  359|      0|            }
  360|   524k|            abRefList[face.mIndices[a]] = true;
  361|   524k|        }
  362|  90.8k|    }
  363|       |
  364|       |    // check whether there are vertices that aren't referenced by a face
  365|     95|    bool b = false;
  366|   524k|    for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (366:30): [True: 524k, False: 95]
  ------------------
  367|   524k|        if (!abRefList[i]) b = true;
  ------------------
  |  Branch (367:13): [True: 57, False: 524k]
  ------------------
  368|   524k|    }
  369|     95|    abRefList.clear();
  370|     95|    if (b) {
  ------------------
  |  Branch (370:9): [True: 5, False: 90]
  ------------------
  371|      5|        ReportWarning("There are unreferenced vertices");
  372|      5|    }
  373|       |
  374|       |    // vertex color channel 2 may not be set if channel 1 is zero ...
  375|     95|    {
  376|     95|        unsigned int i = 0;
  377|     95|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
  ------------------
  |  Branch (377:16): [True: 95, False: 0]
  ------------------
  378|     95|            if (!pMesh->HasVertexColors(i)) break;
  ------------------
  |  Branch (378:17): [True: 95, False: 0]
  ------------------
  379|     95|        }
  380|    855|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i)
  ------------------
  |  Branch (380:16): [True: 760, False: 95]
  ------------------
  381|    760|            if (pMesh->HasVertexColors(i)) {
  ------------------
  |  Branch (381:17): [True: 0, False: 760]
  ------------------
  382|      0|                ReportError("Vertex color channel %i is exists "
  383|      0|                            "although the previous channel was nullptr.",
  384|      0|                        i);
  385|      0|            }
  386|     95|    }
  387|       |
  388|       |    // now validate all bones
  389|     95|    if (pMesh->mNumBones) {
  ------------------
  |  Branch (389:9): [True: 83, False: 12]
  ------------------
  390|     83|        if (!pMesh->mBones) {
  ------------------
  |  Branch (390:13): [True: 0, False: 83]
  ------------------
  391|      0|            ReportError("aiMesh::mBones is nullptr (aiMesh::mNumBones is %i)",
  392|      0|                    pMesh->mNumBones);
  393|      0|        }
  394|     83|        std::unique_ptr<float[]> afSum(nullptr);
  395|     83|        if (pMesh->mNumVertices) {
  ------------------
  |  Branch (395:13): [True: 83, False: 0]
  ------------------
  396|     83|            afSum.reset(new float[pMesh->mNumVertices]);
  397|   350k|            for (unsigned int i = 0; i < pMesh->mNumVertices; ++i)
  ------------------
  |  Branch (397:38): [True: 350k, False: 83]
  ------------------
  398|   350k|                afSum[i] = 0.0f;
  399|     83|        }
  400|       |
  401|       |        // check whether there are duplicate bone names
  402|    782|        for (unsigned int i = 0; i < pMesh->mNumBones; ++i) {
  ------------------
  |  Branch (402:34): [True: 699, False: 83]
  ------------------
  403|    699|            const aiBone *bone = pMesh->mBones[i];
  404|    699|            if (bone->mNumWeights > AI_MAX_BONE_WEIGHTS) {
  ------------------
  |  Branch (404:17): [True: 0, False: 699]
  ------------------
  405|      0|                ReportError("Bone %u has too many weights: %u, but the limit is %u", i, bone->mNumWeights, AI_MAX_BONE_WEIGHTS);
  406|      0|            }
  407|       |
  408|    699|            if (!pMesh->mBones[i]) {
  ------------------
  |  Branch (408:17): [True: 0, False: 699]
  ------------------
  409|      0|                ReportError("aiMesh::mBones[%i] is nullptr (aiMesh::mNumBones is %i)",
  410|      0|                        i, pMesh->mNumBones);
  411|      0|            }
  412|    699|            Validate(pMesh, pMesh->mBones[i], afSum.get());
  413|       |
  414|  3.59k|            for (unsigned int a = i + 1; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (414:42): [True: 2.89k, False: 699]
  ------------------
  415|  2.89k|                if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName) {
  ------------------
  |  Branch (415:21): [True: 0, False: 2.89k]
  ------------------
  416|      0|                    const char *name = "unknown";
  417|      0|                    if (nullptr != pMesh->mBones[i]->mName.C_Str()) {
  ------------------
  |  Branch (417:25): [True: 0, False: 0]
  ------------------
  418|      0|                        name = pMesh->mBones[i]->mName.C_Str();
  419|      0|                    }
  420|      0|                    ReportError("aiMesh::mBones[%i], name = \"%s\" has the same name as "
  421|      0|                                "aiMesh::mBones[%i]",
  422|      0|                            i, name, a);
  423|      0|                }
  424|  2.89k|            }
  425|    699|        }
  426|       |        // check whether all bone weights for a vertex sum to 1.0 ...
  427|   350k|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (427:34): [True: 350k, False: 83]
  ------------------
  428|   350k|            if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) {
  ------------------
  |  Branch (428:17): [True: 330k, False: 19.8k]
  |  Branch (428:30): [True: 272k, False: 58.4k]
  |  Branch (428:50): [True: 4.61k, False: 53.8k]
  ------------------
  429|   276k|                ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)", i, afSum[i]);
  430|   276k|            }
  431|   350k|        }
  432|     83|    } else if (pMesh->mBones) {
  ------------------
  |  Branch (432:16): [True: 0, False: 12]
  ------------------
  433|      0|        ReportError("aiMesh::mBones is non-null although there are no bones");
  434|      0|    }
  435|     95|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMeshPK6aiBonePf:
  438|    699|void ValidateDSProcess::Validate(const aiMesh *pMesh, const aiBone *pBone, float *afSum) {
  439|    699|    this->Validate(&pBone->mName);
  440|       |
  441|    699|    if (!pBone->mNumWeights) {
  ------------------
  |  Branch (441:9): [True: 0, False: 699]
  ------------------
  442|      0|        ReportWarning("aiBone::mNumWeights is zero");
  443|      0|    }
  444|       |
  445|       |    // check whether all vertices affected by this bone are valid
  446|   974k|    for (unsigned int i = 0; i < pBone->mNumWeights; ++i) {
  ------------------
  |  Branch (446:30): [True: 974k, False: 699]
  ------------------
  447|   974k|        if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) {
  ------------------
  |  Branch (447:13): [True: 0, False: 974k]
  ------------------
  448|      0|            ReportError("aiBone::mWeights[%i].mVertexId is out of range", i);
  449|   974k|        } else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) {
  ------------------
  |  Branch (449:20): [True: 0, False: 974k]
  |  Branch (449:51): [True: 0, False: 974k]
  ------------------
  450|      0|                ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value %i. Value must be greater than zero and less than 1.", i, pBone->mWeights[i].mWeight);
  451|      0|        }
  452|   974k|        afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight;
  453|   974k|    }
  454|    699|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK11aiAnimation:
  457|    203|void ValidateDSProcess::Validate(const aiAnimation *pAnimation) {
  458|    203|    Validate(&pAnimation->mName);
  459|       |
  460|       |    // validate all animations
  461|    203|    if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels) {
  ------------------
  |  Branch (461:9): [True: 203, False: 0]
  |  Branch (461:37): [True: 0, False: 0]
  ------------------
  462|    201|        if (!pAnimation->mChannels && pAnimation->mNumChannels) {
  ------------------
  |  Branch (462:13): [True: 0, False: 201]
  |  Branch (462:39): [True: 0, False: 0]
  ------------------
  463|      0|            ReportError("aiAnimation::mChannels is nullptr (aiAnimation::mNumChannels is %i)",
  464|      0|                    pAnimation->mNumChannels);
  465|      0|        }
  466|    201|        if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) {
  ------------------
  |  Branch (466:13): [True: 201, False: 0]
  |  Branch (466:48): [True: 0, False: 201]
  ------------------
  467|      0|            ReportError("aiAnimation::mMorphMeshChannels is nullptr (aiAnimation::mNumMorphMeshChannels is %i)",
  468|      0|                    pAnimation->mNumMorphMeshChannels);
  469|      0|        }
  470|  3.55k|        for (unsigned int i = 0; i < pAnimation->mNumChannels; ++i) {
  ------------------
  |  Branch (470:34): [True: 3.35k, False: 201]
  ------------------
  471|  3.35k|            if (!pAnimation->mChannels[i]) {
  ------------------
  |  Branch (471:17): [True: 0, False: 3.35k]
  ------------------
  472|      0|                ReportError("aiAnimation::mChannels[%i] is nullptr (aiAnimation::mNumChannels is %i)",
  473|      0|                        i, pAnimation->mNumChannels);
  474|      0|            }
  475|  3.35k|            Validate(pAnimation, pAnimation->mChannels[i]);
  476|  3.35k|        }
  477|    201|        for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels; ++i) {
  ------------------
  |  Branch (477:34): [True: 0, False: 201]
  ------------------
  478|      0|            if (!pAnimation->mMorphMeshChannels[i]) {
  ------------------
  |  Branch (478:17): [True: 0, False: 0]
  ------------------
  479|      0|                ReportError("aiAnimation::mMorphMeshChannels[%i] is nullptr (aiAnimation::mNumMorphMeshChannels is %i)",
  480|      0|                        i, pAnimation->mNumMorphMeshChannels);
  481|      0|            }
  482|      0|            Validate(pAnimation, pAnimation->mMorphMeshChannels[i]);
  483|      0|        }
  484|    201|    } else {
  485|      2|        ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there.");
  486|      2|    }
  487|    203|}
_ZN6Assimp17ValidateDSProcess24SearchForInvalidTexturesEPK10aiMaterial13aiTextureType:
  491|  1.56k|        aiTextureType type) {
  492|  1.56k|    const char *szType = aiTextureTypeToString(type);
  493|       |
  494|       |    // ****************************************************************************
  495|       |    // Search all keys of the material ...
  496|       |    // textures must be specified with ascending indices
  497|       |    // (e.g. diffuse #2 may not be specified if diffuse #1 is not there ...)
  498|       |    // ****************************************************************************
  499|       |
  500|  1.56k|    int iNumIndices = 0;
  501|  1.56k|    int iIndex = -1;
  502|  27.1k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (502:30): [True: 25.6k, False: 1.56k]
  ------------------
  503|  25.6k|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  504|  25.6k|        ai_assert(nullptr != prop);
  505|  25.6k|        if (!::strcmp(prop->mKey.data, "$tex.file") && prop->mSemantic == static_cast<unsigned int>(type)) {
  ------------------
  |  Branch (505:13): [True: 51, False: 25.5k]
  |  Branch (505:56): [True: 3, False: 48]
  ------------------
  506|      3|            iIndex = std::max(iIndex, (int)prop->mIndex);
  507|      3|            ++iNumIndices;
  508|       |
  509|      3|            if (aiPTI_String != prop->mType) {
  ------------------
  |  Branch (509:17): [True: 0, False: 3]
  ------------------
  510|      0|                ReportError("Material property %s is expected to be a string", prop->mKey.data);
  511|      0|            }
  512|      3|        }
  513|  25.6k|    }
  514|  1.56k|    if (iIndex + 1 != iNumIndices) {
  ------------------
  |  Branch (514:9): [True: 0, False: 1.56k]
  ------------------
  515|      0|        ReportError("%s #%i is set, but there are only %i %s textures",
  516|      0|                szType, iIndex, iNumIndices, szType);
  517|      0|    }
  518|  1.56k|    if (!iNumIndices) {
  ------------------
  |  Branch (518:9): [True: 1.56k, False: 3]
  ------------------
  519|  1.56k|        return;
  520|  1.56k|    }
  521|      3|    std::vector<aiTextureMapping> mappings(iNumIndices);
  522|       |
  523|       |    // Now check whether all UV indices are valid ...
  524|      3|    bool bNoSpecified = true;
  525|     90|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (525:30): [True: 87, False: 3]
  ------------------
  526|     87|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  527|     87|        if (static_cast<aiTextureType>(prop->mSemantic) != type) {
  ------------------
  |  Branch (527:13): [True: 78, False: 9]
  ------------------
  528|     78|            continue;
  529|     78|        }
  530|       |
  531|      9|        if ((int)prop->mIndex >= iNumIndices) {
  ------------------
  |  Branch (531:13): [True: 0, False: 9]
  ------------------
  532|      0|            ReportError("Found texture property with index %i, although there "
  533|      0|                        "are only %i textures of type %s",
  534|      0|                    prop->mIndex, iNumIndices, szType);
  535|      0|        }
  536|       |
  537|      9|        if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
  ------------------
  |  Branch (537:13): [True: 0, False: 9]
  ------------------
  538|      0|            if (aiPTI_Integer != prop->mType || prop->mDataLength < sizeof(aiTextureMapping)) {
  ------------------
  |  Branch (538:17): [True: 0, False: 0]
  |  Branch (538:49): [True: 0, False: 0]
  ------------------
  539|      0|                ReportError("Material property %s%i is expected to be an integer (size is %i)",
  540|      0|                        prop->mKey.data, prop->mIndex, prop->mDataLength);
  541|      0|            }
  542|      0|            mappings[prop->mIndex] = *((aiTextureMapping *)prop->mData);
  543|      9|        } else if (!::strcmp(prop->mKey.data, "$tex.uvtrafo")) {
  ------------------
  |  Branch (543:20): [True: 3, False: 6]
  ------------------
  544|      3|            if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform)) {
  ------------------
  |  Branch (544:17): [True: 0, False: 3]
  |  Branch (544:47): [True: 0, False: 3]
  ------------------
  545|      0|                ReportError("Material property %s%i is expected to be 5 floats large (size is %i)",
  546|      0|                        prop->mKey.data, prop->mIndex, prop->mDataLength);
  547|      0|            }
  548|       |            //mappings[prop->mIndex] = ((aiUVTransform*)prop->mData);
  549|      6|        } else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
  ------------------
  |  Branch (549:20): [True: 3, False: 3]
  ------------------
  550|      3|            if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) {
  ------------------
  |  Branch (550:17): [True: 0, False: 3]
  |  Branch (550:49): [True: 0, False: 3]
  ------------------
  551|      0|                ReportError("Material property %s%i is expected to be an integer (size is %i)",
  552|      0|                        prop->mKey.data, prop->mIndex, prop->mDataLength);
  553|      0|            }
  554|      3|            bNoSpecified = false;
  555|       |
  556|       |            // Ignore UV indices for texture channels that are not there ...
  557|       |
  558|       |            // Get the value
  559|      3|            iIndex = *((unsigned int *)prop->mData);
  560|       |
  561|       |            // Check whether there is a mesh using this material
  562|       |            // which has not enough UV channels ...
  563|      6|            for (unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (563:38): [True: 3, False: 3]
  ------------------
  564|      3|                aiMesh *mesh = this->mScene->mMeshes[a];
  565|      3|                if (mesh->mMaterialIndex == (unsigned int)i) {
  ------------------
  |  Branch (565:21): [True: 0, False: 3]
  ------------------
  566|      0|                    int iChannels = 0;
  567|      0|                    while (mesh->HasTextureCoords(iChannels))
  ------------------
  |  Branch (567:28): [True: 0, False: 0]
  ------------------
  568|      0|                        ++iChannels;
  569|      0|                    if (iIndex >= iChannels) {
  ------------------
  |  Branch (569:25): [True: 0, False: 0]
  ------------------
  570|      0|                        ReportWarning("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
  571|      0|                                iIndex, prop->mKey.data, a, iChannels);
  572|      0|                    }
  573|      0|                }
  574|      3|            }
  575|      3|        }
  576|      9|    }
  577|      3|    if (bNoSpecified) {
  ------------------
  |  Branch (577:9): [True: 0, False: 3]
  ------------------
  578|       |        // Assume that all textures are using the first UV channel
  579|      0|        for (unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (579:34): [True: 0, False: 0]
  ------------------
  580|      0|            aiMesh *mesh = mScene->mMeshes[a];
  581|      0|            if (mesh->mMaterialIndex == (unsigned int)iIndex && mappings[0] == aiTextureMapping_UV) {
  ------------------
  |  Branch (581:17): [True: 0, False: 0]
  |  Branch (581:65): [True: 0, False: 0]
  ------------------
  582|      0|                if (!mesh->mTextureCoords[0]) {
  ------------------
  |  Branch (582:21): [True: 0, False: 0]
  ------------------
  583|       |                    // This is a special case ... it could be that the
  584|       |                    // original mesh format intended the use of a special
  585|       |                    // mapping here.
  586|      0|                    ReportWarning("UV-mapped texture, but there are no UV coords");
  587|      0|                }
  588|      0|            }
  589|      0|        }
  590|      0|    }
  591|      3|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK10aiMaterial:
  593|     92|void ValidateDSProcess::Validate(const aiMaterial *pMaterial) {
  594|       |    // check whether there are material keys that are obviously not legal
  595|  1.59k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (595:30): [True: 1.50k, False: 92]
  ------------------
  596|  1.50k|        const aiMaterialProperty *prop = pMaterial->mProperties[i];
  597|  1.50k|        if (!prop) {
  ------------------
  |  Branch (597:13): [True: 0, False: 1.50k]
  ------------------
  598|      0|            ReportError("aiMaterial::mProperties[%i] is nullptr (aiMaterial::mNumProperties is %i)",
  599|      0|                    i, pMaterial->mNumProperties);
  600|      0|        }
  601|  1.50k|        if (!prop->mDataLength || !prop->mData) {
  ------------------
  |  Branch (601:13): [True: 0, False: 1.50k]
  |  Branch (601:35): [True: 0, False: 1.50k]
  ------------------
  602|      0|            ReportError("aiMaterial::mProperties[%i].mDataLength or "
  603|      0|                        "aiMaterial::mProperties[%i].mData is 0",
  604|      0|                    i, i);
  605|      0|        }
  606|       |        // check all predefined types
  607|  1.50k|        if (aiPTI_String == prop->mType) {
  ------------------
  |  Branch (607:13): [True: 106, False: 1.40k]
  ------------------
  608|       |            // FIX: strings are now stored in a less expensive way, but we can't use the
  609|       |            // validation routine for 'normal' aiStrings
  610|    106|            if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast<uint32_t *>(prop->mData)) + 1) {
  ------------------
  |  Branch (610:17): [True: 0, False: 106]
  |  Branch (610:42): [True: 0, False: 106]
  ------------------
  611|      0|                ReportError("aiMaterial::mProperties[%i].mDataLength is "
  612|      0|                            "too small to contain a string (%i, needed: %i)",
  613|      0|                        i, prop->mDataLength, static_cast<int>(sizeof(aiString)));
  614|      0|            }
  615|    106|            if (prop->mData[prop->mDataLength - 1]) {
  ------------------
  |  Branch (615:17): [True: 0, False: 106]
  ------------------
  616|      0|                ReportError("Missing null-terminator in string material property");
  617|      0|            }
  618|       |            //  Validate((const aiString*)prop->mData);
  619|  1.40k|        } else if (aiPTI_Float == prop->mType) {
  ------------------
  |  Branch (619:20): [True: 1.30k, False: 95]
  ------------------
  620|  1.30k|            if (prop->mDataLength < sizeof(float)) {
  ------------------
  |  Branch (620:17): [True: 0, False: 1.30k]
  ------------------
  621|      0|                ReportError("aiMaterial::mProperties[%i].mDataLength is "
  622|      0|                            "too small to contain a float (%i, needed: %i)",
  623|      0|                        i, prop->mDataLength, static_cast<int>(sizeof(float)));
  624|      0|            }
  625|  1.30k|        } else if (aiPTI_Integer == prop->mType) {
  ------------------
  |  Branch (625:20): [True: 11, False: 84]
  ------------------
  626|     11|            if (prop->mDataLength < sizeof(int)) {
  ------------------
  |  Branch (626:17): [True: 0, False: 11]
  ------------------
  627|      0|                ReportError("aiMaterial::mProperties[%i].mDataLength is "
  628|      0|                            "too small to contain an integer (%i, needed: %i)",
  629|      0|                        i, prop->mDataLength, static_cast<int>(sizeof(int)));
  630|      0|            }
  631|     11|        }
  632|       |        // TODO: check whether there is a key with an unknown name ...
  633|  1.50k|    }
  634|       |
  635|       |    // make some more specific tests
  636|     92|    ai_real fTemp;
  637|     92|    int iShading;
  638|     92|    if (AI_SUCCESS == aiGetMaterialInteger(pMaterial, AI_MATKEY_SHADING_MODEL, &iShading)) {
  ------------------
  |  Branch (638:9): [True: 84, False: 8]
  ------------------
  639|     84|        switch ((aiShadingMode)iShading) {
  640|      0|        case aiShadingMode_Blinn:
  ------------------
  |  Branch (640:9): [True: 0, False: 84]
  ------------------
  641|      0|        case aiShadingMode_CookTorrance:
  ------------------
  |  Branch (641:9): [True: 0, False: 84]
  ------------------
  642|     84|        case aiShadingMode_Phong:
  ------------------
  |  Branch (642:9): [True: 84, False: 0]
  ------------------
  643|       |
  644|     84|            if (AI_SUCCESS != aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS, &fTemp)) {
  ------------------
  |  Branch (644:17): [True: 0, False: 84]
  ------------------
  645|      0|                ReportWarning("A specular shading model is specified but there is no "
  646|      0|                              "AI_MATKEY_SHININESS key");
  647|      0|            }
  648|     84|            if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS_STRENGTH, &fTemp) && !fTemp) {
  ------------------
  |  Branch (648:17): [True: 84, False: 0]
  |  Branch (648:102): [True: 3, False: 81]
  ------------------
  649|      3|                ReportWarning("A specular shading model is specified but the value of the "
  650|      3|                              "AI_MATKEY_SHININESS_STRENGTH key is 0.0");
  651|      3|            }
  652|     84|            break;
  653|      0|        default:
  ------------------
  |  Branch (653:9): [True: 0, False: 84]
  ------------------
  654|      0|            break;
  655|     84|        }
  656|     84|    }
  657|       |
  658|     92|    if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_OPACITY, &fTemp) && (!fTemp || fTemp > 1.01)) {
  ------------------
  |  Branch (658:9): [True: 82, False: 10]
  |  Branch (658:84): [True: 0, False: 82]
  |  Branch (658:94): [True: 0, False: 82]
  ------------------
  659|      0|        ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)");
  660|      0|    }
  661|       |
  662|       |    // Check whether there are invalid texture keys
  663|       |    // TODO: that's a relict of the past, where texture type and index were baked
  664|       |    // into the material string ... we could do that in one single pass.
  665|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE);
  666|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_SPECULAR);
  667|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT);
  668|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSIVE);
  669|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_OPACITY);
  670|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_SHININESS);
  671|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_HEIGHT);
  672|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMALS);
  673|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_DISPLACEMENT);
  674|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_LIGHTMAP);
  675|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_REFLECTION);
  676|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_BASE_COLOR);
  677|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMAL_CAMERA);
  678|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSION_COLOR);
  679|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_METALNESS);
  680|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE_ROUGHNESS);
  681|     92|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT_OCCLUSION);
  682|     92|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK9aiTexture:
  685|      1|void ValidateDSProcess::Validate(const aiTexture *pTexture) {
  686|       |    // the data section may NEVER be nullptr
  687|      1|    if (nullptr == pTexture->pcData) {
  ------------------
  |  Branch (687:9): [True: 0, False: 1]
  ------------------
  688|      0|        ReportError("aiTexture::pcData is nullptr");
  689|      0|    }
  690|      1|    if (pTexture->mHeight) {
  ------------------
  |  Branch (690:9): [True: 0, False: 1]
  ------------------
  691|      0|        if (!pTexture->mWidth) {
  ------------------
  |  Branch (691:13): [True: 0, False: 0]
  ------------------
  692|      0|            ReportError("aiTexture::mWidth is zero (aiTexture::mHeight is %i, uncompressed texture)",
  693|      0|                    pTexture->mHeight);
  694|      0|        }
  695|      1|    } else {
  696|      1|        if (!pTexture->mWidth) {
  ------------------
  |  Branch (696:13): [True: 0, False: 1]
  ------------------
  697|      0|            ReportError("aiTexture::mWidth is zero (compressed texture)");
  698|      0|        }
  699|      1|        if ('\0' != pTexture->achFormatHint[HINTMAXTEXTURELEN - 1]) {
  ------------------
  |  Branch (699:13): [True: 0, False: 1]
  ------------------
  700|      0|            ReportWarning("aiTexture::achFormatHint must be zero-terminated");
  701|      1|        } else if ('.' == pTexture->achFormatHint[0]) {
  ------------------
  |  Branch (701:20): [True: 0, False: 1]
  ------------------
  702|      0|            ReportWarning("aiTexture::achFormatHint should contain a file extension "
  703|      0|                          "without a leading dot (format hint: %s).",
  704|      0|                    pTexture->achFormatHint);
  705|      0|        }
  706|      1|    }
  707|       |
  708|      1|    const char *sz = pTexture->achFormatHint;
  709|      1|    if ((sz[0] >= 'A' && sz[0] <= 'Z') ||
  ------------------
  |  Branch (709:10): [True: 1, False: 0]
  |  Branch (709:26): [True: 0, False: 1]
  ------------------
  710|      1|            (sz[1] >= 'A' && sz[1] <= 'Z') ||
  ------------------
  |  Branch (710:14): [True: 1, False: 0]
  |  Branch (710:30): [True: 0, False: 1]
  ------------------
  711|      1|            (sz[2] >= 'A' && sz[2] <= 'Z') ||
  ------------------
  |  Branch (711:14): [True: 1, False: 0]
  |  Branch (711:30): [True: 0, False: 1]
  ------------------
  712|      1|            (sz[3] >= 'A' && sz[3] <= 'Z')) {
  ------------------
  |  Branch (712:14): [True: 0, False: 1]
  |  Branch (712:30): [True: 0, False: 0]
  ------------------
  713|      0|        ReportError("aiTexture::achFormatHint contains non-lowercase letters");
  714|      0|    }
  715|      1|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK11aiAnimationPK10aiNodeAnim:
  719|  3.35k|        const aiNodeAnim *pNodeAnim) {
  720|  3.35k|    Validate(&pNodeAnim->mNodeName);
  721|       |
  722|  3.35k|    if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys) {
  ------------------
  |  Branch (722:9): [True: 64, False: 3.28k]
  |  Branch (722:41): [True: 0, False: 64]
  |  Branch (722:69): [True: 0, False: 0]
  ------------------
  723|      0|        ReportError("Empty node animation channel");
  724|      0|    }
  725|       |    // otherwise check whether one of the keys exceeds the total duration of the animation
  726|  3.35k|    if (pNodeAnim->mNumPositionKeys) {
  ------------------
  |  Branch (726:9): [True: 3.28k, False: 65]
  ------------------
  727|  3.28k|        if (!pNodeAnim->mPositionKeys) {
  ------------------
  |  Branch (727:13): [True: 0, False: 3.28k]
  ------------------
  728|      0|            ReportError("aiNodeAnim::mPositionKeys is nullptr (aiNodeAnim::mNumPositionKeys is %i)",
  729|      0|                    pNodeAnim->mNumPositionKeys);
  730|      0|        }
  731|  3.28k|        double dLast = -10e10;
  732|  4.15M|        for (unsigned int i = 0; i < pNodeAnim->mNumPositionKeys; ++i) {
  ------------------
  |  Branch (732:34): [True: 4.14M, False: 3.28k]
  ------------------
  733|       |            // ScenePreprocessor will compute the duration if still the default value
  734|       |            // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration,
  735|       |            //  seems to be due the compilers register usage/width.
  736|  4.14M|            if (pAnimation->mDuration > 0. && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (736:17): [True: 4.14M, False: 143]
  |  Branch (736:47): [True: 1, False: 4.14M]
  ------------------
  737|      1|                ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger "
  738|      1|                            "than aiAnimation::mDuration (which is %.5f)",
  739|      1|                        i,
  740|      1|                        (float)pNodeAnim->mPositionKeys[i].mTime,
  741|      1|                        (float)pAnimation->mDuration);
  742|      1|            }
  743|  4.14M|            if (i && pNodeAnim->mPositionKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (743:17): [True: 4.14M, False: 3.28k]
  |  Branch (743:22): [True: 2, False: 4.14M]
  ------------------
  744|      2|                ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller "
  745|      2|                              "than aiAnimation::mPositionKeys[%i] (which is %.5f)",
  746|      2|                        i,
  747|      2|                        (float)pNodeAnim->mPositionKeys[i].mTime,
  748|      2|                        i - 1, (float)dLast);
  749|      2|            }
  750|  4.14M|            dLast = pNodeAnim->mPositionKeys[i].mTime;
  751|  4.14M|        }
  752|  3.28k|    }
  753|       |    // rotation keys
  754|  3.35k|    if (pNodeAnim->mNumRotationKeys) {
  ------------------
  |  Branch (754:9): [True: 3.35k, False: 2]
  ------------------
  755|  3.35k|        if (!pNodeAnim->mRotationKeys) {
  ------------------
  |  Branch (755:13): [True: 0, False: 3.35k]
  ------------------
  756|      0|            ReportError("aiNodeAnim::mRotationKeys is nullptr (aiNodeAnim::mNumRotationKeys is %i)",
  757|      0|                    pNodeAnim->mNumRotationKeys);
  758|      0|        }
  759|  3.35k|        double dLast = -10e10;
  760|  4.88M|        for (unsigned int i = 0; i < pNodeAnim->mNumRotationKeys; ++i) {
  ------------------
  |  Branch (760:34): [True: 4.88M, False: 3.35k]
  ------------------
  761|  4.88M|            if (pAnimation->mDuration > 0. && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (761:17): [True: 4.88M, False: 215]
  |  Branch (761:47): [True: 0, False: 4.88M]
  ------------------
  762|      0|                ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger "
  763|      0|                            "than aiAnimation::mDuration (which is %.5f)",
  764|      0|                        i,
  765|      0|                        (float)pNodeAnim->mRotationKeys[i].mTime,
  766|      0|                        (float)pAnimation->mDuration);
  767|      0|            }
  768|  4.88M|            if (i && pNodeAnim->mRotationKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (768:17): [True: 4.87M, False: 3.35k]
  |  Branch (768:22): [True: 2, False: 4.87M]
  ------------------
  769|      2|                ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller "
  770|      2|                              "than aiAnimation::mRotationKeys[%i] (which is %.5f)",
  771|      2|                        i,
  772|      2|                        (float)pNodeAnim->mRotationKeys[i].mTime,
  773|      2|                        i - 1, (float)dLast);
  774|      2|            }
  775|  4.88M|            dLast = pNodeAnim->mRotationKeys[i].mTime;
  776|  4.88M|        }
  777|  3.35k|    }
  778|       |    // scaling keys
  779|  3.35k|    if (pNodeAnim->mNumScalingKeys) {
  ------------------
  |  Branch (779:9): [True: 3.29k, False: 58]
  ------------------
  780|  3.29k|        if (!pNodeAnim->mScalingKeys) {
  ------------------
  |  Branch (780:13): [True: 0, False: 3.29k]
  ------------------
  781|      0|            ReportError("aiNodeAnim::mScalingKeys is nullptr (aiNodeAnim::mNumScalingKeys is %i)",
  782|      0|                    pNodeAnim->mNumScalingKeys);
  783|      0|        }
  784|  3.29k|        double dLast = -10e10;
  785|  4.15M|        for (unsigned int i = 0; i < pNodeAnim->mNumScalingKeys; ++i) {
  ------------------
  |  Branch (785:34): [True: 4.14M, False: 3.29k]
  ------------------
  786|  4.14M|            if (pAnimation->mDuration > 0. && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (786:17): [True: 4.14M, False: 151]
  |  Branch (786:47): [True: 0, False: 4.14M]
  ------------------
  787|      0|                ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger "
  788|      0|                            "than aiAnimation::mDuration (which is %.5f)",
  789|      0|                        i,
  790|      0|                        (float)pNodeAnim->mScalingKeys[i].mTime,
  791|      0|                        (float)pAnimation->mDuration);
  792|      0|            }
  793|  4.14M|            if (i && pNodeAnim->mScalingKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (793:17): [True: 4.14M, False: 3.29k]
  |  Branch (793:22): [True: 2, False: 4.14M]
  ------------------
  794|      2|                ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller "
  795|      2|                              "than aiAnimation::mScalingKeys[%i] (which is %.5f)",
  796|      2|                        i,
  797|      2|                        (float)pNodeAnim->mScalingKeys[i].mTime,
  798|      2|                        i - 1, (float)dLast);
  799|      2|            }
  800|  4.14M|            dLast = pNodeAnim->mScalingKeys[i].mTime;
  801|  4.14M|        }
  802|  3.29k|    }
  803|       |
  804|  3.35k|    if (!pNodeAnim->mNumScalingKeys && !pNodeAnim->mNumRotationKeys &&
  ------------------
  |  Branch (804:9): [True: 56, False: 3.29k]
  |  Branch (804:40): [True: 0, False: 56]
  ------------------
  805|      0|            !pNodeAnim->mNumPositionKeys) {
  ------------------
  |  Branch (805:13): [True: 0, False: 0]
  ------------------
  806|      0|        ReportError("A node animation channel must have at least one subtrack");
  807|      0|    }
  808|  3.35k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiNode:
  850|  5.02k|void ValidateDSProcess::Validate(const aiNode *pNode) {
  851|  5.02k|    if (!pNode) {
  ------------------
  |  Branch (851:9): [True: 0, False: 5.02k]
  ------------------
  852|      0|        ReportError("A node of the scene-graph is nullptr");
  853|      0|    }
  854|       |    // Validate node name string first so that it's safe to use in below expressions
  855|  5.02k|    this->Validate(&pNode->mName);
  856|  5.02k|    const char *nodeName = (&pNode->mName)->C_Str();
  857|  5.02k|    if (pNode != mScene->mRootNode && !pNode->mParent) {
  ------------------
  |  Branch (857:9): [True: 4.79k, False: 232]
  |  Branch (857:39): [True: 0, False: 4.79k]
  ------------------
  858|      0|        ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is nullptr) ", nodeName);
  859|      0|    }
  860|       |
  861|       |    // validate all meshes
  862|  5.02k|    if (pNode->mNumMeshes) {
  ------------------
  |  Branch (862:9): [True: 100, False: 4.92k]
  ------------------
  863|    100|        if (!pNode->mMeshes) {
  ------------------
  |  Branch (863:13): [True: 0, False: 100]
  ------------------
  864|      0|            ReportError("aiNode::mMeshes is nullptr for node %s (aiNode::mNumMeshes is %i)",
  865|      0|                    nodeName, pNode->mNumMeshes);
  866|      0|        }
  867|    100|        std::vector<bool> abHadMesh;
  868|    100|        abHadMesh.resize(mScene->mNumMeshes, false);
  869|    200|        for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) {
  ------------------
  |  Branch (869:34): [True: 100, False: 100]
  ------------------
  870|    100|            if (pNode->mMeshes[i] >= mScene->mNumMeshes) {
  ------------------
  |  Branch (870:17): [True: 0, False: 100]
  ------------------
  871|      0|                ReportError("aiNode::mMeshes[%i] is out of range for node %s (maximum is %i)",
  872|      0|                        pNode->mMeshes[i], nodeName, mScene->mNumMeshes - 1);
  873|      0|            }
  874|    100|            if (abHadMesh[pNode->mMeshes[i]]) {
  ------------------
  |  Branch (874:17): [True: 0, False: 100]
  ------------------
  875|      0|                ReportError("aiNode::mMeshes[%i] is already referenced by this node %s (value: %i)",
  876|      0|                        i, nodeName, pNode->mMeshes[i]);
  877|      0|            }
  878|    100|            abHadMesh[pNode->mMeshes[i]] = true;
  879|    100|        }
  880|    100|    }
  881|  5.02k|    if (pNode->mNumChildren) {
  ------------------
  |  Branch (881:9): [True: 4.00k, False: 1.01k]
  ------------------
  882|  4.00k|        if (!pNode->mChildren) {
  ------------------
  |  Branch (882:13): [True: 0, False: 4.00k]
  ------------------
  883|      0|            ReportError("aiNode::mChildren is nullptr for node %s (aiNode::mNumChildren is %i)",
  884|      0|                    nodeName, pNode->mNumChildren);
  885|      0|        }
  886|  8.80k|        for (unsigned int i = 0; i < pNode->mNumChildren; ++i) {
  ------------------
  |  Branch (886:34): [True: 4.79k, False: 4.00k]
  ------------------
  887|  4.79k|            const aiNode *pChild = pNode->mChildren[i];
  888|  4.79k|            Validate(pChild);
  889|  4.79k|            if (pChild->mParent != pNode) {
  ------------------
  |  Branch (889:17): [True: 0, False: 4.79k]
  ------------------
  890|      0|                const char *parentName = (pChild->mParent != nullptr) ? pChild->mParent->mName.C_Str() : "null";
  ------------------
  |  Branch (890:42): [True: 0, False: 0]
  ------------------
  891|      0|                ReportError("aiNode \"%s\" child %i \"%s\" parent is someone else: \"%s\"", pNode->mName.C_Str(), i, pChild->mName.C_Str(), parentName);
  892|      0|            }
  893|  4.79k|        }
  894|  4.00k|    } else if (pNode->mChildren) {
  ------------------
  |  Branch (894:16): [True: 0, False: 1.01k]
  ------------------
  895|      0|        ReportError("aiNode::mChildren is not nullptr for empty node %s (aiNode::mNumChildren is %i)",
  896|      0|                nodeName, pNode->mNumChildren);
  897|      0|    }
  898|  5.02k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiString:
  901|  9.37k|void ValidateDSProcess::Validate(const aiString *pString) {
  902|  9.37k|    if (pString->length > AI_MAXLEN) {
  ------------------
  |  Branch (902:9): [True: 0, False: 9.37k]
  ------------------
  903|      0|        ReportError("aiString::length is too large (%u, maximum is %lu)",
  904|      0|                pString->length, AI_MAXLEN);
  905|      0|    }
  906|  9.37k|    const char *sz = pString->data;
  907|   133k|    while (true) {
  ------------------
  |  Branch (907:12): [True: 133k, Folded]
  ------------------
  908|   133k|        if ('\0' == *sz) {
  ------------------
  |  Branch (908:13): [True: 9.37k, False: 124k]
  ------------------
  909|  9.37k|            if (pString->length != (unsigned int)(sz - pString->data)) {
  ------------------
  |  Branch (909:17): [True: 8, False: 9.36k]
  ------------------
  910|      8|                ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
  911|      8|            }
  912|  9.37k|            break;
  913|   124k|        } else if (sz >= &pString->data[AI_MAXLEN]) {
  ------------------
  |  Branch (913:20): [True: 0, False: 124k]
  ------------------
  914|      0|            ReportError("aiString::data is invalid. There is no terminal character");
  915|      0|        }
  916|   124k|        ++sz;
  917|   124k|    }
  918|  9.37k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI6aiMeshEEvPPT_jPKcS7_:
  109|     92|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|     92|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 92]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|     92|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 92]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|    187|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 95, False: 92]
  ------------------
  121|     95|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 95]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|     95|        Validate(parray[i]);
  126|     95|    }
  127|     92|}
_ZN6Assimp17ValidateDSProcess12DoValidationI11aiAnimationEEvPPT_jPKcS7_:
  109|    203|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|    203|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 203]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|    203|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 203]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|    406|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 203, False: 203]
  ------------------
  121|    203|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 203]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|    203|        Validate(parray[i]);
  126|    203|    }
  127|    203|}
_ZN6Assimp17ValidateDSProcess25DoValidationWithNameCheckI8aiCameraEEvPPT_jPKcS7_:
  163|    197|        const char *secondName) {
  164|       |    // validate all entries
  165|    197|    DoValidationEx(array, size, firstName, secondName);
  166|       |
  167|    394|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (167:30): [True: 197, False: 197]
  ------------------
  168|    197|        int res = HasNameMatch(array[i]->mName, mScene->mRootNode);
  169|    197|        if (0 == res) {
  ------------------
  |  Branch (169:13): [True: 0, False: 197]
  ------------------
  170|      0|            const std::string name = static_cast<char *>(array[i]->mName.data);
  171|      0|            ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)",
  172|      0|                    firstName, i, name.c_str());
  173|    197|        } else if (1 != res) {
  ------------------
  |  Branch (173:20): [True: 0, False: 197]
  ------------------
  174|      0|            const std::string name = static_cast<char *>(array[i]->mName.data);
  175|      0|            ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name",
  176|      0|                    firstName, i, name.c_str());
  177|      0|        }
  178|    197|    }
  179|    197|}
_ZN6Assimp17ValidateDSProcess14DoValidationExI8aiCameraEEvPPT_jPKcS7_:
  132|    197|        const char *firstName, const char *secondName) {
  133|       |    // validate all entries
  134|    197|    if (size == 0) {
  ------------------
  |  Branch (134:9): [True: 0, False: 197]
  ------------------
  135|      0|        return;
  136|      0|    }
  137|       |
  138|    197|    if (!parray) {
  ------------------
  |  Branch (138:9): [True: 0, False: 197]
  ------------------
  139|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  140|      0|                firstName, secondName, size);
  141|      0|    }
  142|    394|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (142:30): [True: 197, False: 197]
  ------------------
  143|    197|        if (!parray[i]) {
  ------------------
  |  Branch (143:13): [True: 0, False: 197]
  ------------------
  144|      0|            ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
  145|      0|                    firstName, i, secondName, size);
  146|      0|        }
  147|    197|        Validate(parray[i]);
  148|       |
  149|       |        // check whether there are duplicate names
  150|    197|        for (unsigned int a = i + 1; a < size; ++a) {
  ------------------
  |  Branch (150:38): [True: 0, False: 197]
  ------------------
  151|      0|            if (parray[i]->mName == parray[a]->mName) {
  ------------------
  |  Branch (151:17): [True: 0, False: 0]
  ------------------
  152|      0|                ReportError("aiScene::%s[%u] has the same name as "
  153|      0|                            "aiScene::%s[%u]",
  154|      0|                        firstName, i, secondName, a);
  155|      0|            }
  156|      0|        }
  157|    197|    }
  158|    197|}
_Z12HasNameMatchRK8aiStringP6aiNode:
   99|  9.33k|inline int HasNameMatch(const aiString &in, aiNode *node) {
  100|  9.33k|    int result = (node->mName == in ? 1 : 0);
  ------------------
  |  Branch (100:19): [True: 387, False: 8.95k]
  ------------------
  101|  18.2k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 8.95k, False: 9.33k]
  ------------------
  102|  8.95k|        result += HasNameMatch(in, node->mChildren[i]);
  103|  8.95k|    }
  104|  9.33k|    return result;
  105|  9.33k|}
_ZN6Assimp17ValidateDSProcess25DoValidationWithNameCheckI7aiLightEEvPPT_jPKcS7_:
  163|    190|        const char *secondName) {
  164|       |    // validate all entries
  165|    190|    DoValidationEx(array, size, firstName, secondName);
  166|       |
  167|    380|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (167:30): [True: 190, False: 190]
  ------------------
  168|    190|        int res = HasNameMatch(array[i]->mName, mScene->mRootNode);
  169|    190|        if (0 == res) {
  ------------------
  |  Branch (169:13): [True: 0, False: 190]
  ------------------
  170|      0|            const std::string name = static_cast<char *>(array[i]->mName.data);
  171|      0|            ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)",
  172|      0|                    firstName, i, name.c_str());
  173|    190|        } else if (1 != res) {
  ------------------
  |  Branch (173:20): [True: 0, False: 190]
  ------------------
  174|      0|            const std::string name = static_cast<char *>(array[i]->mName.data);
  175|      0|            ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name",
  176|      0|                    firstName, i, name.c_str());
  177|      0|        }
  178|    190|    }
  179|    190|}
_ZN6Assimp17ValidateDSProcess14DoValidationExI7aiLightEEvPPT_jPKcS7_:
  132|    190|        const char *firstName, const char *secondName) {
  133|       |    // validate all entries
  134|    190|    if (size == 0) {
  ------------------
  |  Branch (134:9): [True: 0, False: 190]
  ------------------
  135|      0|        return;
  136|      0|    }
  137|       |
  138|    190|    if (!parray) {
  ------------------
  |  Branch (138:9): [True: 0, False: 190]
  ------------------
  139|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  140|      0|                firstName, secondName, size);
  141|      0|    }
  142|    380|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (142:30): [True: 190, False: 190]
  ------------------
  143|    190|        if (!parray[i]) {
  ------------------
  |  Branch (143:13): [True: 0, False: 190]
  ------------------
  144|      0|            ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
  145|      0|                    firstName, i, secondName, size);
  146|      0|        }
  147|    190|        Validate(parray[i]);
  148|       |
  149|       |        // check whether there are duplicate names
  150|    190|        for (unsigned int a = i + 1; a < size; ++a) {
  ------------------
  |  Branch (150:38): [True: 0, False: 190]
  ------------------
  151|      0|            if (parray[i]->mName == parray[a]->mName) {
  ------------------
  |  Branch (151:17): [True: 0, False: 0]
  ------------------
  152|      0|                ReportError("aiScene::%s[%u] has the same name as "
  153|      0|                            "aiScene::%s[%u]",
  154|      0|                        firstName, i, secondName, a);
  155|      0|            }
  156|      0|        }
  157|    190|    }
  158|    190|}
_ZN6Assimp17ValidateDSProcess12DoValidationI9aiTextureEEvPPT_jPKcS7_:
  109|      1|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|      1|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 1]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|      1|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 1]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|      2|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 1, False: 1]
  ------------------
  121|      1|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 1]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|      1|        Validate(parray[i]);
  126|      1|    }
  127|      1|}
_ZN6Assimp17ValidateDSProcess12DoValidationI10aiMaterialEEvPPT_jPKcS7_:
  109|     91|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|     91|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 91]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|     91|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 91]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|    183|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 92, False: 91]
  ------------------
  121|     92|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 92]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|     92|        Validate(parray[i]);
  126|     92|    }
  127|     91|}

_ZN6mapbox6earcutIjNSt3__16vectorINS2_I10aiVector2tIfENS1_9allocatorIS4_EEEENS5_IS7_EEEEEENS2_IT_NS5_ISA_EEEERKT0_:
  809|  1.88k|std::vector<N> earcut(const Polygon& poly) {
  810|  1.88k|    mapbox::detail::Earcut<N> earcut;
  811|  1.88k|    earcut(poly);
  812|  1.88k|    return std::move(earcut.indices);
  813|  1.88k|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEEC2Ev:
   99|  1.88k|        ObjectPool() { }
_ZN6mapbox6detail6EarcutIjEclINSt3__16vectorINS5_I10aiVector2tIfENS4_9allocatorIS7_EEEENS8_ISA_EEEEEEvRKT_:
  139|  1.88k|void Earcut<N>::operator()(const Polygon& points) {
  140|       |    // reset
  141|  1.88k|    indices.clear();
  142|  1.88k|    vertices = 0;
  143|       |
  144|  1.88k|    if (points.empty()) return;
  ------------------
  |  Branch (144:9): [True: 0, False: 1.88k]
  ------------------
  145|       |
  146|  1.88k|    double x;
  147|  1.88k|    double y;
  148|  1.88k|    int threshold = 80;
  149|  1.88k|    std::size_t len = 0;
  150|       |
  151|  3.76k|    for (size_t i = 0; threshold >= 0 && i < points.size(); i++) {
  ------------------
  |  Branch (151:24): [True: 2.88k, False: 879]
  |  Branch (151:42): [True: 1.88k, False: 1.00k]
  ------------------
  152|  1.88k|        threshold -= static_cast<int>(points[i].size());
  153|  1.88k|        len += points[i].size();
  154|  1.88k|    }
  155|       |
  156|       |    //estimate size of nodes and indices
  157|  1.88k|    nodes.reset(len * 3 / 2);
  158|  1.88k|    indices.reserve(len + points[0].size());
  159|       |
  160|  1.88k|    Node* outerNode = linkedList(points[0], true);
  161|  1.88k|    if (!outerNode || outerNode->prev == outerNode->next) return;
  ------------------
  |  Branch (161:9): [True: 0, False: 1.88k]
  |  Branch (161:23): [True: 0, False: 1.88k]
  ------------------
  162|       |
  163|  1.88k|    if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
  ------------------
  |  Branch (163:9): [True: 0, False: 1.88k]
  ------------------
  164|       |
  165|       |    // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
  166|  1.88k|    hashing = threshold < 0;
  167|  1.88k|    if (hashing) {
  ------------------
  |  Branch (167:9): [True: 879, False: 1.00k]
  ------------------
  168|    879|        Node* p = outerNode->next;
  169|    879|        minX = maxX = outerNode->x;
  170|    879|        minY = maxY = outerNode->y;
  171|   101k|        do {
  172|   101k|            x = p->x;
  173|   101k|            y = p->y;
  174|   101k|            minX = std::min<double>(minX, x);
  175|   101k|            minY = std::min<double>(minY, y);
  176|   101k|            maxX = std::max<double>(maxX, x);
  177|   101k|            maxY = std::max<double>(maxY, y);
  178|   101k|            p = p->next;
  179|   101k|        } while (p != outerNode);
  ------------------
  |  Branch (179:18): [True: 100k, False: 879]
  ------------------
  180|       |
  181|       |        // minX, minY and inv_size are later used to transform coords into integers for z-order calculation
  182|    879|        inv_size = std::max<double>(maxX - minX, maxY - minY);
  183|    879|        inv_size = inv_size != .0 ? (32767. / inv_size) : .0;
  ------------------
  |  Branch (183:20): [True: 879, False: 0]
  ------------------
  184|    879|    }
  185|       |
  186|  1.88k|    earcutLinked(outerNode);
  187|       |
  188|  1.88k|    nodes.clear();
  189|  1.88k|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE5resetEm:
  117|  5.65k|        void reset(std::size_t newBlockSize) {
  118|  5.65k|            for (auto allocation : allocations) {
  ------------------
  |  Branch (118:34): [True: 1.88k, False: 5.65k]
  ------------------
  119|  1.88k|                alloc_traits::deallocate(alloc, allocation, blockSize);
  120|  1.88k|            }
  121|  5.65k|            allocations.clear();
  122|  5.65k|            blockSize = std::max<std::size_t>(1, newBlockSize);
  123|  5.65k|            currentBlock = nullptr;
  124|  5.65k|            currentIndex = blockSize;
  125|  5.65k|        }
_ZN6mapbox6detail6EarcutIjE10linkedListINSt3__16vectorI10aiVector2tIfENS4_9allocatorIS7_EEEEEEPNS2_4NodeERKT_b:
  194|  1.88k|Earcut<N>::linkedList(const Ring& points, const bool clockwise) {
  195|  1.88k|    using Point = typename Ring::value_type;
  196|  1.88k|    double sum = 0;
  197|  1.88k|    const std::size_t len = points.size();
  198|  1.88k|    std::size_t i, j;
  199|  1.88k|    Node* last = nullptr;
  200|       |
  201|       |    // calculate original winding order of a polygon ring
  202|   170k|    for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) {
  ------------------
  |  Branch (202:21): [True: 1.88k, False: 0]
  |  Branch (202:44): [True: 168k, False: 1.88k]
  ------------------
  203|   168k|        const auto& p1 = points[i];
  204|   168k|        const auto& p2 = points[j];
  205|   168k|        const double p20 = util::nth<0, Point>::get(p2);
  206|   168k|        const double p10 = util::nth<0, Point>::get(p1);
  207|   168k|        const double p11 = util::nth<1, Point>::get(p1);
  208|   168k|        const double p21 = util::nth<1, Point>::get(p2);
  209|   168k|        sum += (p20 - p10) * (p11 + p21);
  210|   168k|    }
  211|       |
  212|       |    // link points into circular doubly-linked list in the specified winding order
  213|  1.88k|    if (clockwise == (sum > 0)) {
  ------------------
  |  Branch (213:9): [True: 1.87k, False: 6]
  ------------------
  214|   169k|        for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
  ------------------
  |  Branch (214:21): [True: 167k, False: 1.87k]
  ------------------
  215|  1.87k|    } else {
  216|    401|        for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
  ------------------
  |  Branch (216:23): [True: 395, False: 6]
  ------------------
  217|      6|    }
  218|       |
  219|  1.88k|    if (last && equals(last, last->next)) {
  ------------------
  |  Branch (219:9): [True: 1.88k, False: 0]
  |  Branch (219:17): [True: 3, False: 1.88k]
  ------------------
  220|      3|        removeNode(last);
  221|      3|        last = last->next;
  222|      3|    }
  223|       |
  224|  1.88k|    vertices += len;
  225|       |
  226|  1.88k|    return last;
  227|  1.88k|}
_ZN6mapbox6detail6EarcutIjE10insertNodeI10aiVector2tIfEEEPNS2_4NodeEmRKT_S7_:
  781|   168k|Earcut<N>::insertNode(std::size_t i, const Point& pt, Node* last) {
  782|   168k|    Node* p = nodes.construct(static_cast<N>(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt));
  783|       |
  784|   168k|    if (!last) {
  ------------------
  |  Branch (784:9): [True: 1.88k, False: 166k]
  ------------------
  785|  1.88k|        p->prev = p;
  786|  1.88k|        p->next = p;
  787|       |
  788|   166k|    } else {
  789|   166k|        assert(last);
  ------------------
  |  Branch (789:9): [True: 166k, False: 0]
  ------------------
  790|   166k|        p->next = last->next;
  791|   166k|        p->prev = last;
  792|   166k|        last->next->prev = p;
  793|   166k|        last->next = p;
  794|   166k|    }
  795|   168k|    return p;
  796|   168k|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE9constructIJjffEEEPS4_DpOT_:
  107|   168k|        T* construct(Args&&... args) {
  108|   168k|            if (currentIndex >= blockSize) {
  ------------------
  |  Branch (108:17): [True: 1.88k, False: 166k]
  ------------------
  109|  1.88k|                currentBlock = alloc_traits::allocate(alloc, blockSize);
  110|  1.88k|                allocations.emplace_back(currentBlock);
  111|  1.88k|                currentIndex = 0;
  112|  1.88k|            }
  113|   168k|            T* object = &currentBlock[currentIndex++];
  114|   168k|            alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
  115|   168k|            return object;
  116|   168k|        }
_ZN6mapbox6detail6EarcutIjE4NodeC2Ejdd:
   37|   170k|        Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {}
_ZN6mapbox6detail6EarcutIjE6equalsEPKNS2_4NodeES5_:
  678|   547k|bool Earcut<N>::equals(const Node* p1, const Node* p2) {
  679|   547k|    return p1->x == p2->x && p1->y == p2->y;
  ------------------
  |  Branch (679:12): [True: 143k, False: 404k]
  |  Branch (679:30): [True: 128k, False: 14.5k]
  ------------------
  680|   547k|}
_ZN6mapbox6detail6EarcutIjE10removeNodeEPNS2_4NodeE:
  799|   142k|void Earcut<N>::removeNode(Node* p) {
  800|   142k|    p->next->prev = p->prev;
  801|   142k|    p->prev->next = p->next;
  802|       |
  803|   142k|    if (p->prevZ) p->prevZ->nextZ = p->nextZ;
  ------------------
  |  Branch (803:9): [True: 83.3k, False: 58.7k]
  ------------------
  804|   142k|    if (p->nextZ) p->nextZ->prevZ = p->prevZ;
  ------------------
  |  Branch (804:9): [True: 85.4k, False: 56.5k]
  ------------------
  805|   142k|}
_ZNK6mapbox6detail6EarcutIjE15pointInTriangleEdddddddd:
  655|   322k|bool Earcut<N>::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const {
  656|   322k|    return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
  ------------------
  |  Branch (656:12): [True: 281k, False: 41.7k]
  ------------------
  657|   281k|           (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
  ------------------
  |  Branch (657:12): [True: 261k, False: 19.8k]
  ------------------
  658|   261k|           (bx - px) * (cy - py) >= (cx - px) * (by - py);
  ------------------
  |  Branch (658:12): [True: 250k, False: 11.2k]
  ------------------
  659|   322k|}
_ZN6mapbox6detail6EarcutIjE13locallyInsideEPKNS2_4NodeES5_:
  729|  18.1k|bool Earcut<N>::locallyInside(const Node* a, const Node* b) {
  730|  18.1k|    return area(a->prev, a, a->next) < 0 ?
  ------------------
  |  Branch (730:12): [True: 7.93k, False: 10.2k]
  ------------------
  731|  7.93k|        area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 :
  ------------------
  |  Branch (731:9): [True: 5.52k, False: 2.40k]
  |  Branch (731:37): [True: 3.10k, False: 2.42k]
  ------------------
  732|  18.1k|        area(a, b, a->prev) < 0 || area(a, a->next, b) < 0;
  ------------------
  |  Branch (732:9): [True: 2.34k, False: 7.85k]
  |  Branch (732:36): [True: 700, False: 7.15k]
  ------------------
  733|  18.1k|}
_ZNK6mapbox6detail6EarcutIjE4areaEPKNS2_4NodeES5_S5_:
  672|  4.10M|double Earcut<N>::area(const Node* p, const Node* q, const Node* r) const {
  673|  4.10M|    return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y);
  674|  4.10M|}
_ZN6mapbox6detail6EarcutIjE12splitPolygonEPNS2_4NodeES4_:
  757|    929|Earcut<N>::splitPolygon(Node* a, Node* b) {
  758|    929|    Node* a2 = nodes.construct(a->i, a->x, a->y);
  759|    929|    Node* b2 = nodes.construct(b->i, b->x, b->y);
  760|    929|    Node* an = a->next;
  761|    929|    Node* bp = b->prev;
  762|       |
  763|    929|    a->next = b;
  764|    929|    b->prev = a;
  765|       |
  766|    929|    a2->next = an;
  767|    929|    an->prev = a2;
  768|       |
  769|    929|    b2->next = a2;
  770|    929|    a2->prev = b2;
  771|       |
  772|    929|    bp->next = b2;
  773|    929|    b2->prev = bp;
  774|       |
  775|    929|    return b2;
  776|    929|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE9constructIJRKjRKdSD_EEEPS4_DpOT_:
  107|  1.85k|        T* construct(Args&&... args) {
  108|  1.85k|            if (currentIndex >= blockSize) {
  ------------------
  |  Branch (108:17): [True: 0, False: 1.85k]
  ------------------
  109|      0|                currentBlock = alloc_traits::allocate(alloc, blockSize);
  110|      0|                allocations.emplace_back(currentBlock);
  111|      0|                currentIndex = 0;
  112|      0|            }
  113|  1.85k|            T* object = &currentBlock[currentIndex++];
  114|  1.85k|            alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
  115|  1.85k|            return object;
  116|  1.85k|        }
_ZN6mapbox6detail6EarcutIjE12filterPointsEPNS2_4NodeES4_:
  232|  13.0k|Earcut<N>::filterPoints(Node* start, Node* end) {
  233|  13.0k|    if (!end) end = start;
  ------------------
  |  Branch (233:9): [True: 11.1k, False: 1.85k]
  ------------------
  234|       |
  235|  13.0k|    Node* p = start;
  236|  13.0k|    bool again;
  237|   470k|    do {
  238|   470k|        again = false;
  239|       |
  240|   470k|        if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
  ------------------
  |  Branch (240:13): [True: 470k, False: 0]
  |  Branch (240:29): [True: 92.2k, False: 378k]
  |  Branch (240:51): [True: 42.2k, False: 336k]
  ------------------
  241|   134k|            removeNode(p);
  242|   134k|            p = end = p->prev;
  243|       |
  244|   134k|            if (p == p->next) break;
  ------------------
  |  Branch (244:17): [True: 3, False: 134k]
  ------------------
  245|   134k|            again = true;
  246|       |
  247|   336k|        } else {
  248|   336k|            p = p->next;
  249|   336k|        }
  250|   470k|    } while (again || p != end);
  ------------------
  |  Branch (250:14): [True: 134k, False: 336k]
  |  Branch (250:23): [True: 323k, False: 13.0k]
  ------------------
  251|       |
  252|  13.0k|    return end;
  253|  13.0k|}
_ZN6mapbox6detail6EarcutIjE12earcutLinkedEPNS2_4NodeEi:
  257|  11.1k|void Earcut<N>::earcutLinked(Node* ear, int pass) {
  258|  11.1k|    if (!ear) return;
  ------------------
  |  Branch (258:9): [True: 0, False: 11.1k]
  ------------------
  259|       |
  260|       |    // interlink polygon nodes in z-order
  261|  11.1k|    if (!pass && hashing) indexCurve(ear);
  ------------------
  |  Branch (261:9): [True: 3.74k, False: 7.44k]
  |  Branch (261:18): [True: 1.76k, False: 1.97k]
  ------------------
  262|       |
  263|  11.1k|    Node* stop = ear;
  264|  11.1k|    Node* prev;
  265|  11.1k|    Node* next;
  266|       |
  267|       |    // iterate through ears, slicing them one by one
  268|   284k|    while (ear->prev != ear->next) {
  ------------------
  |  Branch (268:12): [True: 284k, False: 41]
  ------------------
  269|   284k|        prev = ear->prev;
  270|   284k|        next = ear->next;
  271|       |
  272|   284k|        if (hashing ? isEarHashed(ear) : isEar(ear)) {
  ------------------
  |  Branch (272:13): [True: 166k, False: 118k]
  |  Branch (272:13): [True: 4.07k, False: 280k]
  ------------------
  273|       |            // cut off the triangle
  274|  4.07k|            indices.emplace_back(prev->i);
  275|  4.07k|            indices.emplace_back(ear->i);
  276|  4.07k|            indices.emplace_back(next->i);
  277|       |
  278|  4.07k|            removeNode(ear);
  279|       |
  280|       |            // skipping the next vertice leads to less sliver triangles
  281|  4.07k|            ear = next->next;
  282|  4.07k|            stop = next->next;
  283|       |
  284|  4.07k|            continue;
  285|  4.07k|        }
  286|       |
  287|   280k|        ear = next;
  288|       |
  289|       |        // if we looped through the whole remaining polygon and can't find any more ears
  290|   280k|        if (ear == stop) {
  ------------------
  |  Branch (290:13): [True: 11.1k, False: 269k]
  ------------------
  291|       |            // try filtering points and slicing again
  292|  11.1k|            if (!pass) earcutLinked(filterPoints(ear), 1);
  ------------------
  |  Branch (292:17): [True: 3.72k, False: 7.42k]
  ------------------
  293|       |
  294|       |            // if this didn't work, try curing all small self-intersections locally
  295|  7.42k|            else if (pass == 1) {
  ------------------
  |  Branch (295:22): [True: 3.72k, False: 3.70k]
  ------------------
  296|  3.72k|                ear = cureLocalIntersections(filterPoints(ear));
  297|  3.72k|                earcutLinked(ear, 2);
  298|       |
  299|       |            // as a last resort, try splitting the remaining polygon into two
  300|  3.72k|            } else if (pass == 2) splitEarcut(ear);
  ------------------
  |  Branch (300:24): [True: 3.70k, False: 0]
  ------------------
  301|       |
  302|  11.1k|            break;
  303|  11.1k|        }
  304|   280k|    }
  305|  11.1k|}
_ZN6mapbox6detail6EarcutIjE10indexCurveEPNS2_4NodeE:
  532|  1.76k|void Earcut<N>::indexCurve(Node* start) {
  533|  1.76k|    assert(start);
  ------------------
  |  Branch (533:5): [True: 1.76k, False: 0]
  ------------------
  534|  1.76k|    Node* p = start;
  535|       |
  536|   109k|    do {
  537|   109k|        p->z = p->z ? p->z : zOrder(p->x, p->y);
  ------------------
  |  Branch (537:16): [True: 1.46k, False: 107k]
  ------------------
  538|   109k|        p->prevZ = p->prev;
  539|   109k|        p->nextZ = p->next;
  540|   109k|        p = p->next;
  541|   109k|    } while (p != start);
  ------------------
  |  Branch (541:14): [True: 107k, False: 1.76k]
  ------------------
  542|       |
  543|  1.76k|    p->prevZ->nextZ = nullptr;
  544|  1.76k|    p->prevZ = nullptr;
  545|       |
  546|  1.76k|    sortLinked(p);
  547|  1.76k|}
_ZN6mapbox6detail6EarcutIjE6zOrderEdd:
  620|   159k|int32_t Earcut<N>::zOrder(const double x_, const double y_) {
  621|       |    // coords are transformed into non-negative 15-bit integer range
  622|   159k|    int32_t x = static_cast<int32_t>((x_ - minX) * inv_size);
  623|   159k|    int32_t y = static_cast<int32_t>((y_ - minY) * inv_size);
  624|       |
  625|   159k|    x = (x | (x << 8)) & 0x00FF00FF;
  626|   159k|    x = (x | (x << 4)) & 0x0F0F0F0F;
  627|   159k|    x = (x | (x << 2)) & 0x33333333;
  628|   159k|    x = (x | (x << 1)) & 0x55555555;
  629|       |
  630|   159k|    y = (y | (y << 8)) & 0x00FF00FF;
  631|   159k|    y = (y | (y << 4)) & 0x0F0F0F0F;
  632|   159k|    y = (y | (y << 2)) & 0x33333333;
  633|   159k|    y = (y | (y << 1)) & 0x55555555;
  634|       |
  635|   159k|    return x | (y << 1);
  636|   159k|}
_ZN6mapbox6detail6EarcutIjE10sortLinkedEPNS2_4NodeE:
  553|  1.76k|Earcut<N>::sortLinked(Node* list) {
  554|  1.76k|    assert(list);
  ------------------
  |  Branch (554:5): [True: 1.76k, False: 0]
  ------------------
  555|  1.76k|    Node* p;
  556|  1.76k|    Node* q;
  557|  1.76k|    Node* e;
  558|  1.76k|    Node* tail;
  559|  1.76k|    int i, numMerges, pSize, qSize;
  560|  1.76k|    int inSize = 1;
  561|       |
  562|  9.48k|    for (;;) {
  563|  9.48k|        p = list;
  564|  9.48k|        list = nullptr;
  565|  9.48k|        tail = nullptr;
  566|  9.48k|        numMerges = 0;
  567|       |
  568|   122k|        while (p) {
  ------------------
  |  Branch (568:16): [True: 112k, False: 9.48k]
  ------------------
  569|   112k|            numMerges++;
  570|   112k|            q = p;
  571|   112k|            pSize = 0;
  572|   558k|            for (i = 0; i < inSize; i++) {
  ------------------
  |  Branch (572:25): [True: 450k, False: 107k]
  ------------------
  573|   450k|                pSize++;
  574|   450k|                q = q->nextZ;
  575|   450k|                if (!q) break;
  ------------------
  |  Branch (575:21): [True: 5.35k, False: 445k]
  ------------------
  576|   450k|            }
  577|       |
  578|   112k|            qSize = inSize;
  579|       |
  580|   914k|            while (pSize > 0 || (qSize > 0 && q)) {
  ------------------
  |  Branch (580:20): [True: 584k, False: 329k]
  |  Branch (580:34): [True: 225k, False: 104k]
  |  Branch (580:47): [True: 217k, False: 8.07k]
  ------------------
  581|       |
  582|   801k|                if (pSize == 0) {
  ------------------
  |  Branch (582:21): [True: 217k, False: 584k]
  ------------------
  583|   217k|                    e = q;
  584|   217k|                    q = q->nextZ;
  585|   217k|                    qSize--;
  586|   584k|                } else if (qSize == 0 || !q) {
  ------------------
  |  Branch (586:28): [True: 15.5k, False: 568k]
  |  Branch (586:42): [True: 16.5k, False: 552k]
  ------------------
  587|  32.0k|                    e = p;
  588|  32.0k|                    p = p->nextZ;
  589|  32.0k|                    pSize--;
  590|   552k|                } else if (p->z <= q->z) {
  ------------------
  |  Branch (590:28): [True: 418k, False: 133k]
  ------------------
  591|   418k|                    e = p;
  592|   418k|                    p = p->nextZ;
  593|   418k|                    pSize--;
  594|   418k|                } else {
  595|   133k|                    e = q;
  596|   133k|                    q = q->nextZ;
  597|   133k|                    qSize--;
  598|   133k|                }
  599|       |
  600|   801k|                if (tail) tail->nextZ = e;
  ------------------
  |  Branch (600:21): [True: 791k, False: 9.48k]
  ------------------
  601|  9.48k|                else list = e;
  602|       |
  603|   801k|                e->prevZ = tail;
  604|   801k|                tail = e;
  605|   801k|            }
  606|       |
  607|   112k|            p = q;
  608|   112k|        }
  609|       |
  610|  9.48k|        tail->nextZ = nullptr;
  611|       |
  612|  9.48k|        if (numMerges <= 1) return list;
  ------------------
  |  Branch (612:13): [True: 1.76k, False: 7.71k]
  ------------------
  613|       |
  614|  7.71k|        inSize *= 2;
  615|  7.71k|    }
  616|  1.76k|}
_ZN6mapbox6detail6EarcutIjE11isEarHashedEPNS2_4NodeE:
  329|   166k|bool Earcut<N>::isEarHashed(Node* ear) {
  330|   166k|    const Node* a = ear->prev;
  331|   166k|    const Node* b = ear;
  332|   166k|    const Node* c = ear->next;
  333|       |
  334|   166k|    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  ------------------
  |  Branch (334:9): [True: 140k, False: 25.8k]
  ------------------
  335|       |
  336|       |    // triangle bbox; min & max are calculated like this for speed
  337|  25.8k|    const double minTX = std::min<double>(a->x, std::min<double>(b->x, c->x));
  338|  25.8k|    const double minTY = std::min<double>(a->y, std::min<double>(b->y, c->y));
  339|  25.8k|    const double maxTX = std::max<double>(a->x, std::max<double>(b->x, c->x));
  340|  25.8k|    const double maxTY = std::max<double>(a->y, std::max<double>(b->y, c->y));
  341|       |
  342|       |    // z-order range for the current triangle bbox;
  343|  25.8k|    const int32_t minZ = zOrder(minTX, minTY);
  344|  25.8k|    const int32_t maxZ = zOrder(maxTX, maxTY);
  345|       |
  346|       |    // first look for points inside the triangle in increasing z-order
  347|  25.8k|    Node* p = ear->nextZ;
  348|       |
  349|  57.3k|    while (p && p->z <= maxZ) {
  ------------------
  |  Branch (349:12): [True: 51.7k, False: 5.65k]
  |  Branch (349:17): [True: 51.6k, False: 65]
  ------------------
  350|  51.6k|        if (p != ear->prev && p != ear->next &&
  ------------------
  |  Branch (350:13): [True: 50.6k, False: 1.01k]
  |  Branch (350:31): [True: 42.8k, False: 7.79k]
  ------------------
  351|  42.8k|            pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (351:13): [True: 28.6k, False: 14.2k]
  ------------------
  352|  28.6k|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (352:13): [True: 20.1k, False: 8.47k]
  ------------------
  353|  31.5k|        p = p->nextZ;
  354|  31.5k|    }
  355|       |
  356|       |    // then look for points in decreasing z-order
  357|  5.72k|    p = ear->prevZ;
  358|       |
  359|  13.4k|    while (p && p->z >= minZ) {
  ------------------
  |  Branch (359:12): [True: 12.8k, False: 599]
  |  Branch (359:17): [True: 12.8k, False: 20]
  ------------------
  360|  12.8k|        if (p != ear->prev && p != ear->next &&
  ------------------
  |  Branch (360:13): [True: 9.45k, False: 3.35k]
  |  Branch (360:31): [True: 8.72k, False: 731]
  ------------------
  361|  8.72k|            pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (361:13): [True: 5.89k, False: 2.82k]
  ------------------
  362|  5.89k|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (362:13): [True: 5.10k, False: 786]
  ------------------
  363|  7.69k|        p = p->prevZ;
  364|  7.69k|    }
  365|       |
  366|    619|    return true;
  367|  5.72k|}
_ZN6mapbox6detail6EarcutIjE5isEarEPNS2_4NodeE:
  309|   118k|bool Earcut<N>::isEar(Node* ear) {
  310|   118k|    const Node* a = ear->prev;
  311|   118k|    const Node* b = ear;
  312|   118k|    const Node* c = ear->next;
  313|       |
  314|   118k|    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  ------------------
  |  Branch (314:9): [True: 75.1k, False: 43.1k]
  ------------------
  315|       |
  316|       |    // now make sure we don't have other points inside the potential ear
  317|  43.1k|    Node* p = ear->next->next;
  318|       |
  319|   274k|    while (p != ear->prev) {
  ------------------
  |  Branch (319:12): [True: 271k, False: 3.45k]
  ------------------
  320|   271k|        if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (320:13): [True: 215k, False: 55.7k]
  ------------------
  321|   215k|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (321:13): [True: 39.7k, False: 175k]
  ------------------
  322|   231k|        p = p->next;
  323|   231k|    }
  324|       |
  325|  3.45k|    return true;
  326|  43.1k|}
_ZN6mapbox6detail6EarcutIjE22cureLocalIntersectionsEPNS2_4NodeE:
  372|  3.72k|Earcut<N>::cureLocalIntersections(Node* start) {
  373|  3.72k|    Node* p = start;
  374|  67.7k|    do {
  375|  67.7k|        Node* a = p->prev;
  376|  67.7k|        Node* b = p->next->next;
  377|       |
  378|       |        // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2])
  379|  67.7k|        if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) {
  ------------------
  |  Branch (379:13): [True: 33.1k, False: 34.6k]
  |  Branch (379:30): [True: 6.50k, False: 26.6k]
  |  Branch (379:62): [True: 2.65k, False: 3.84k]
  |  Branch (379:85): [True: 1.70k, False: 955]
  ------------------
  380|  1.70k|            indices.emplace_back(a->i);
  381|  1.70k|            indices.emplace_back(p->i);
  382|  1.70k|            indices.emplace_back(b->i);
  383|       |
  384|       |            // remove two nodes involved
  385|  1.70k|            removeNode(p);
  386|  1.70k|            removeNode(p->next);
  387|       |
  388|  1.70k|            p = start = b;
  389|  1.70k|        }
  390|  67.7k|        p = p->next;
  391|  67.7k|    } while (p != start);
  ------------------
  |  Branch (391:14): [True: 64.0k, False: 3.72k]
  ------------------
  392|       |
  393|  3.72k|    return filterPoints(p);
  394|  3.72k|}
_ZN6mapbox6detail6EarcutIjE10intersectsEPKNS2_4NodeES5_S5_S5_:
  684|   784k|bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) {
  685|   784k|    int o1 = sign(area(p1, q1, p2));
  686|   784k|    int o2 = sign(area(p1, q1, q2));
  687|   784k|    int o3 = sign(area(p2, q2, p1));
  688|   784k|    int o4 = sign(area(p2, q2, q1));
  689|       |
  690|   784k|    if (o1 != o2 && o3 != o4) return true; // general case
  ------------------
  |  Branch (690:9): [True: 349k, False: 435k]
  |  Branch (690:21): [True: 304k, False: 44.9k]
  ------------------
  691|       |
  692|   480k|    if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
  ------------------
  |  Branch (692:9): [True: 103k, False: 376k]
  |  Branch (692:20): [True: 102k, False: 178]
  ------------------
  693|   377k|    if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
  ------------------
  |  Branch (693:9): [True: 542, False: 376k]
  |  Branch (693:20): [True: 0, False: 542]
  ------------------
  694|   377k|    if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
  ------------------
  |  Branch (694:9): [True: 199k, False: 177k]
  |  Branch (694:20): [True: 0, False: 199k]
  ------------------
  695|   377k|    if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
  ------------------
  |  Branch (695:9): [True: 198k, False: 178k]
  |  Branch (695:20): [True: 0, False: 198k]
  ------------------
  696|       |
  697|   377k|    return false;
  698|   377k|}
_ZN6mapbox6detail6EarcutIjE4signEd:
  710|  3.13M|int Earcut<N>::sign(double val) {
  711|  3.13M|    return (0.0 < val) - (val < 0.0);
  712|  3.13M|}
_ZN6mapbox6detail6EarcutIjE9onSegmentEPKNS2_4NodeES5_S5_:
  702|   501k|bool Earcut<N>::onSegment(const Node* p, const Node* q, const Node* r) {
  703|   501k|    return q->x <= std::max<double>(p->x, r->x) &&
  ------------------
  |  Branch (703:12): [True: 314k, False: 187k]
  ------------------
  704|   314k|        q->x >= std::min<double>(p->x, r->x) &&
  ------------------
  |  Branch (704:9): [True: 137k, False: 176k]
  ------------------
  705|   137k|        q->y <= std::max<double>(p->y, r->y) &&
  ------------------
  |  Branch (705:9): [True: 120k, False: 17.0k]
  ------------------
  706|   120k|        q->y >= std::min<double>(p->y, r->y);
  ------------------
  |  Branch (706:9): [True: 102k, False: 17.5k]
  ------------------
  707|   501k|}
_ZN6mapbox6detail6EarcutIjE11splitEarcutEPNS2_4NodeE:
  398|  3.70k|void Earcut<N>::splitEarcut(Node* start) {
  399|       |    // look for a valid diagonal that divides the polygon into two
  400|  3.70k|    Node* a = start;
  401|  31.3k|    do {
  402|  31.3k|        Node* b = a->next->next;
  403|   438k|        while (b != a->prev) {
  ------------------
  |  Branch (403:16): [True: 407k, False: 30.3k]
  ------------------
  404|   407k|            if (a->i != b->i && isValidDiagonal(a, b)) {
  ------------------
  |  Branch (404:17): [True: 407k, False: 0]
  |  Branch (404:33): [True: 929, False: 406k]
  ------------------
  405|       |                // split the polygon in two by the diagonal
  406|    929|                Node* c = splitPolygon(a, b);
  407|       |
  408|       |                // filter colinear points around the cuts
  409|    929|                a = filterPoints(a, a->next);
  410|    929|                c = filterPoints(c, c->next);
  411|       |
  412|       |                // run earcut on each half
  413|    929|                earcutLinked(a);
  414|    929|                earcutLinked(c);
  415|    929|                return;
  416|    929|            }
  417|   406k|            b = b->next;
  418|   406k|        }
  419|  30.3k|        a = a->next;
  420|  30.3k|    } while (a != start);
  ------------------
  |  Branch (420:14): [True: 27.6k, False: 2.77k]
  ------------------
  421|  3.70k|}
_ZN6mapbox6detail6EarcutIjE15isValidDiagonalEPNS2_4NodeES4_:
  663|   407k|bool Earcut<N>::isValidDiagonal(Node* a, Node* b) {
  664|   407k|    return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges
  ------------------
  |  Branch (664:12): [True: 407k, False: 0]
  |  Branch (664:34): [True: 407k, False: 0]
  |  Branch (664:56): [True: 7.23k, False: 400k]
  ------------------
  665|  7.23k|           ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
  ------------------
  |  Branch (665:14): [True: 1.72k, False: 5.50k]
  |  Branch (665:37): [True: 57, False: 1.67k]
  |  Branch (665:60): [True: 21, False: 36]
  ------------------
  666|     21|            (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors
  ------------------
  |  Branch (666:14): [True: 19, False: 2]
  |  Branch (666:50): [True: 0, False: 2]
  ------------------
  667|  7.21k|            (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case
  ------------------
  |  Branch (667:14): [True: 2.00k, False: 5.20k]
  |  Branch (667:30): [True: 973, False: 1.03k]
  |  Branch (667:63): [True: 910, False: 63]
  ------------------
  668|   407k|}
_ZN6mapbox6detail6EarcutIjE17intersectsPolygonEPKNS2_4NodeES5_:
  716|   407k|bool Earcut<N>::intersectsPolygon(const Node* a, const Node* b) {
  717|   407k|    const Node* p = a;
  718|  1.29M|    do {
  719|  1.29M|        if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i &&
  ------------------
  |  Branch (719:13): [True: 888k, False: 407k]
  |  Branch (719:29): [True: 881k, False: 7.23k]
  |  Branch (719:51): [True: 816k, False: 65.3k]
  |  Branch (719:67): [True: 750k, False: 65.3k]
  ------------------
  720|   750k|                intersects(p, p->next, a, b)) return true;
  ------------------
  |  Branch (720:17): [True: 400k, False: 350k]
  ------------------
  721|   896k|        p = p->next;
  722|   896k|    } while (p != a);
  ------------------
  |  Branch (722:14): [True: 888k, False: 7.23k]
  ------------------
  723|       |
  724|  7.23k|    return false;
  725|   407k|}
_ZN6mapbox6detail6EarcutIjE12middleInsideEPKNS2_4NodeES5_:
  737|     57|bool Earcut<N>::middleInside(const Node* a, const Node* b) {
  738|     57|    const Node* p = a;
  739|     57|    bool inside = false;
  740|     57|    double px = (a->x + b->x) / 2;
  741|     57|    double py = (a->y + b->y) / 2;
  742|  1.29k|    do {
  743|  1.29k|        if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y &&
  ------------------
  |  Branch (743:13): [True: 884, False: 407]
  |  Branch (743:51): [True: 884, False: 0]
  ------------------
  744|    884|                (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x))
  ------------------
  |  Branch (744:17): [True: 617, False: 267]
  ------------------
  745|    617|            inside = !inside;
  746|  1.29k|        p = p->next;
  747|  1.29k|    } while (p != a);
  ------------------
  |  Branch (747:14): [True: 1.23k, False: 57]
  ------------------
  748|       |
  749|     57|    return inside;
  750|     57|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE5clearEv:
  126|  3.76k|        void clear() { reset(blockSize); }
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEED2Ev:
  103|  1.88k|        ~ObjectPool() {
  104|  1.88k|            clear();
  105|  1.88k|        }

_ZN10ODDLParser5Value8IteratorC2EPS0_:
   39|      2|        m_start(start),
   40|      2|        m_current(start) {
   41|       |    // empty
   42|      2|}

_ZN4pugi13xml_attributeC2Ev:
 5234|      2|	PUGI_IMPL_FN xml_attribute::xml_attribute(): _attr(nullptr)
 5235|      2|	{
 5236|      2|	}
_ZN4pugi8xml_nodeC2Ev:
 5593|    596|	PUGI_IMPL_FN xml_node::xml_node(): _root(nullptr)
 5594|    596|	{
 5595|    596|	}
_ZN4pugi10xpath_nodeC2Ev:
12714|      2|	{
12715|      2|	}
_ZN4pugi14xpath_node_setC2Ev:
12821|      2|	PUGI_IMPL_FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage)
12822|      2|	{
12823|      2|	}

adler32_z:
   67|  10.9k|{
   68|  10.9k|    unsigned long sum2;
   69|  10.9k|    unsigned n;
   70|       |
   71|       |    /* split Adler-32 into component sums */
   72|  10.9k|    sum2 = (adler >> 16) & 0xffff;
   73|  10.9k|    adler &= 0xffff;
   74|       |
   75|       |    /* in case user likes doing a byte at a time, keep it fast */
   76|  10.9k|    if (len == 1) {
  ------------------
  |  Branch (76:9): [True: 2, False: 10.9k]
  ------------------
   77|      2|        adler += buf[0];
   78|      2|        if (adler >= BASE)
  ------------------
  |  |   12|      2|#define BASE 65521U     /* largest prime smaller than 65536 */
  ------------------
  |  Branch (78:13): [True: 0, False: 2]
  ------------------
   79|      0|            adler -= BASE;
  ------------------
  |  |   12|      0|#define BASE 65521U     /* largest prime smaller than 65536 */
  ------------------
   80|      2|        sum2 += adler;
   81|      2|        if (sum2 >= BASE)
  ------------------
  |  |   12|      2|#define BASE 65521U     /* largest prime smaller than 65536 */
  ------------------
  |  Branch (81:13): [True: 0, False: 2]
  ------------------
   82|      0|            sum2 -= BASE;
  ------------------
  |  |   12|      0|#define BASE 65521U     /* largest prime smaller than 65536 */
  ------------------
   83|      2|        return adler | (sum2 << 16);
   84|      2|    }
   85|       |
   86|       |    /* initial Adler-32 value (deferred check for len == 1 speed) */
   87|  10.9k|    if (buf == Z_NULL)
  ------------------
  |  |  212|  10.9k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (87:9): [True: 5.54k, False: 5.35k]
  ------------------
   88|  5.54k|        return 1L;
   89|       |
   90|       |    /* in case short lengths are provided, keep it somewhat fast */
   91|  5.35k|    if (len < 16) {
  ------------------
  |  Branch (91:9): [True: 10, False: 5.34k]
  ------------------
   92|    151|        while (len--) {
  ------------------
  |  Branch (92:16): [True: 141, False: 10]
  ------------------
   93|    141|            adler += *buf++;
   94|    141|            sum2 += adler;
   95|    141|        }
   96|     10|        if (adler >= BASE)
  ------------------
  |  |   12|     10|#define BASE 65521U     /* largest prime smaller than 65536 */
  ------------------
  |  Branch (96:13): [True: 0, False: 10]
  ------------------
   97|      0|            adler -= BASE;
  ------------------
  |  |   12|      0|#define BASE 65521U     /* largest prime smaller than 65536 */
  ------------------
   98|     10|        MOD28(sum2);            /* only added so many BASE's */
  ------------------
  |  |   58|     10|#  define MOD28(a) a %= BASE
  |  |  ------------------
  |  |  |  |   12|     10|#define BASE 65521U     /* largest prime smaller than 65536 */
  |  |  ------------------
  ------------------
   99|     10|        return adler | (sum2 << 16);
  100|     10|    }
  101|       |
  102|       |    /* do length NMAX blocks -- requires just one modulo operation */
  103|  7.26k|    while (len >= NMAX) {
  ------------------
  |  |   13|  7.26k|#define NMAX 5552
  ------------------
  |  Branch (103:12): [True: 1.91k, False: 5.34k]
  ------------------
  104|  1.91k|        len -= NMAX;
  ------------------
  |  |   13|  1.91k|#define NMAX 5552
  ------------------
  105|  1.91k|        n = NMAX / 16;          /* NMAX is divisible by 16 */
  ------------------
  |  |   13|  1.91k|#define NMAX 5552
  ------------------
  106|   665k|        do {
  107|   665k|            DO16(buf);          /* 16 sums unrolled */
  ------------------
  |  |   20|   665k|#define DO16(buf)   DO8(buf,0); DO8(buf,8);
  |  |  ------------------
  |  |  |  |   19|   665k|#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
  |  |  |  |  ------------------
  |  |  |  |  |  |   18|   665k|#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   665k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |               #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   665k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |               #define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
  |  |  |  |  ------------------
  |  |  |  |  |  |   18|   665k|#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   665k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |               #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   665k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               #define DO16(buf)   DO8(buf,0); DO8(buf,8);
  |  |  ------------------
  |  |  |  |   19|   665k|#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
  |  |  |  |  ------------------
  |  |  |  |  |  |   18|   665k|#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   665k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |               #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   665k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |               #define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
  |  |  |  |  ------------------
  |  |  |  |  |  |   18|   665k|#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   665k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |               #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   665k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   665k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  108|   665k|            buf += 16;
  109|   665k|        } while (--n);
  ------------------
  |  Branch (109:18): [True: 663k, False: 1.91k]
  ------------------
  110|  1.91k|        MOD(adler);
  ------------------
  |  |   57|  1.91k|#  define MOD(a) a %= BASE
  |  |  ------------------
  |  |  |  |   12|  1.91k|#define BASE 65521U     /* largest prime smaller than 65536 */
  |  |  ------------------
  ------------------
  111|  1.91k|        MOD(sum2);
  ------------------
  |  |   57|  1.91k|#  define MOD(a) a %= BASE
  |  |  ------------------
  |  |  |  |   12|  1.91k|#define BASE 65521U     /* largest prime smaller than 65536 */
  |  |  ------------------
  ------------------
  112|  1.91k|    }
  113|       |
  114|       |    /* do remaining bytes (less than NMAX, still just one modulo) */
  115|  5.34k|    if (len) {                  /* avoid modulos if none remaining */
  ------------------
  |  Branch (115:9): [True: 5.34k, False: 0]
  ------------------
  116|   646k|        while (len >= 16) {
  ------------------
  |  Branch (116:16): [True: 640k, False: 5.34k]
  ------------------
  117|   640k|            len -= 16;
  118|   640k|            DO16(buf);
  ------------------
  |  |   20|   640k|#define DO16(buf)   DO8(buf,0); DO8(buf,8);
  |  |  ------------------
  |  |  |  |   19|   640k|#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
  |  |  |  |  ------------------
  |  |  |  |  |  |   18|   640k|#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   640k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |               #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   640k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |               #define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
  |  |  |  |  ------------------
  |  |  |  |  |  |   18|   640k|#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   640k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |               #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   640k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  |  |               #define DO16(buf)   DO8(buf,0); DO8(buf,8);
  |  |  ------------------
  |  |  |  |   19|   640k|#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
  |  |  |  |  ------------------
  |  |  |  |  |  |   18|   640k|#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   640k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |               #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   640k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  |  |               #define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
  |  |  |  |  ------------------
  |  |  |  |  |  |   18|   640k|#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   640k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |               #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |   17|   640k|#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |               #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  |  |  |  |   16|   640k|#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
  |  |  |  |  |  |  |  |  ------------------
  |  |  |  |  |  |  ------------------
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  119|   640k|            buf += 16;
  120|   640k|        }
  121|  26.1k|        while (len--) {
  ------------------
  |  Branch (121:16): [True: 20.7k, False: 5.34k]
  ------------------
  122|  20.7k|            adler += *buf++;
  123|  20.7k|            sum2 += adler;
  124|  20.7k|        }
  125|  5.34k|        MOD(adler);
  ------------------
  |  |   57|  5.34k|#  define MOD(a) a %= BASE
  |  |  ------------------
  |  |  |  |   12|  5.34k|#define BASE 65521U     /* largest prime smaller than 65536 */
  |  |  ------------------
  ------------------
  126|  5.34k|        MOD(sum2);
  ------------------
  |  |   57|  5.34k|#  define MOD(a) a %= BASE
  |  |  ------------------
  |  |  |  |   12|  5.34k|#define BASE 65521U     /* largest prime smaller than 65536 */
  |  |  ------------------
  ------------------
  127|  5.34k|    }
  128|       |
  129|       |    /* return recombined sums */
  130|  5.34k|    return adler | (sum2 << 16);
  131|  5.35k|}
adler32:
  138|  10.9k|{
  139|  10.9k|    return adler32_z(adler, buf, len);
  140|  10.9k|}

inflate_fast:
   53|  5.16k|{
   54|  5.16k|    struct inflate_state FAR *state;
   55|  5.16k|    z_const unsigned char FAR *in;      /* local strm->next_in */
   56|  5.16k|    z_const unsigned char FAR *last;    /* have enough input while in < last */
   57|  5.16k|    unsigned char FAR *out;     /* local strm->next_out */
   58|  5.16k|    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
   59|  5.16k|    unsigned char FAR *end;     /* while out < end, enough space available */
   60|       |#ifdef INFLATE_STRICT
   61|       |    unsigned dmax;              /* maximum distance from zlib header */
   62|       |#endif
   63|  5.16k|    unsigned wsize;             /* window size or zero if not using window */
   64|  5.16k|    unsigned whave;             /* valid bytes in the window */
   65|  5.16k|    unsigned wnext;             /* window write index */
   66|  5.16k|    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
   67|  5.16k|    unsigned long hold;         /* local strm->hold */
   68|  5.16k|    unsigned bits;              /* local strm->bits */
   69|  5.16k|    code const FAR *lcode;      /* local strm->lencode */
   70|  5.16k|    code const FAR *dcode;      /* local strm->distcode */
   71|  5.16k|    unsigned lmask;             /* mask for first level of length codes */
   72|  5.16k|    unsigned dmask;             /* mask for first level of distance codes */
   73|  5.16k|    code const *here;           /* retrieved table entry */
   74|  5.16k|    unsigned op;                /* code bits, operation, extra bits, or */
   75|       |                                /*  window position, window bytes to copy */
   76|  5.16k|    unsigned len;               /* match length, unused bytes */
   77|  5.16k|    unsigned dist;              /* match distance */
   78|  5.16k|    unsigned char FAR *from;    /* where to copy match from */
   79|       |
   80|       |    /* copy state to local variables */
   81|  5.16k|    state = (struct inflate_state FAR *)strm->state;
   82|  5.16k|    in = strm->next_in;
   83|  5.16k|    last = in + (strm->avail_in - 5);
   84|  5.16k|    out = strm->next_out;
   85|  5.16k|    beg = out - (start - strm->avail_out);
   86|  5.16k|    end = out + (strm->avail_out - 257);
   87|       |#ifdef INFLATE_STRICT
   88|       |    dmax = state->dmax;
   89|       |#endif
   90|  5.16k|    wsize = state->wsize;
   91|  5.16k|    whave = state->whave;
   92|  5.16k|    wnext = state->wnext;
   93|  5.16k|    window = state->window;
   94|  5.16k|    hold = state->hold;
   95|  5.16k|    bits = state->bits;
   96|  5.16k|    lcode = state->lencode;
   97|  5.16k|    dcode = state->distcode;
   98|  5.16k|    lmask = (1U << state->lenbits) - 1;
   99|  5.16k|    dmask = (1U << state->distbits) - 1;
  100|       |
  101|       |    /* decode literals and length/distances until end-of-block or not enough
  102|       |       input data or output space */
  103|  5.64M|    do {
  104|  5.64M|        if (bits < 15) {
  ------------------
  |  Branch (104:13): [True: 2.59M, False: 3.05M]
  ------------------
  105|  2.59M|            hold += (unsigned long)(*in++) << bits;
  106|  2.59M|            bits += 8;
  107|  2.59M|            hold += (unsigned long)(*in++) << bits;
  108|  2.59M|            bits += 8;
  109|  2.59M|        }
  110|  5.64M|        here = lcode + (hold & lmask);
  111|  6.04M|      dolen:
  112|  6.04M|        op = (unsigned)(here->bits);
  113|  6.04M|        hold >>= op;
  114|  6.04M|        bits -= op;
  115|  6.04M|        op = (unsigned)(here->op);
  116|  6.04M|        if (op == 0) {                          /* literal */
  ------------------
  |  Branch (116:13): [True: 2.64M, False: 3.40M]
  ------------------
  117|  2.64M|            Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
  118|  2.64M|                    "inflate:         literal '%c'\n" :
  119|  2.64M|                    "inflate:         literal 0x%02x\n", here->val));
  120|  2.64M|            *out++ = (unsigned char)(here->val);
  121|  2.64M|        }
  122|  3.40M|        else if (op & 16) {                     /* length base */
  ------------------
  |  Branch (122:18): [True: 3.00M, False: 403k]
  ------------------
  123|  3.00M|            len = (unsigned)(here->val);
  124|  3.00M|            op &= 15;                           /* number of extra bits */
  125|  3.00M|            if (op) {
  ------------------
  |  Branch (125:17): [True: 194k, False: 2.80M]
  ------------------
  126|   194k|                if (bits < op) {
  ------------------
  |  Branch (126:21): [True: 5, False: 194k]
  ------------------
  127|      5|                    hold += (unsigned long)(*in++) << bits;
  128|      5|                    bits += 8;
  129|      5|                }
  130|   194k|                len += (unsigned)hold & ((1U << op) - 1);
  131|   194k|                hold >>= op;
  132|   194k|                bits -= op;
  133|   194k|            }
  134|  3.00M|            Tracevv((stderr, "inflate:         length %u\n", len));
  135|  3.00M|            if (bits < 15) {
  ------------------
  |  Branch (135:17): [True: 501k, False: 2.49M]
  ------------------
  136|   501k|                hold += (unsigned long)(*in++) << bits;
  137|   501k|                bits += 8;
  138|   501k|                hold += (unsigned long)(*in++) << bits;
  139|   501k|                bits += 8;
  140|   501k|            }
  141|  3.00M|            here = dcode + (hold & dmask);
  142|  3.04M|          dodist:
  143|  3.04M|            op = (unsigned)(here->bits);
  144|  3.04M|            hold >>= op;
  145|  3.04M|            bits -= op;
  146|  3.04M|            op = (unsigned)(here->op);
  147|  3.04M|            if (op & 16) {                      /* distance base */
  ------------------
  |  Branch (147:17): [True: 3.00M, False: 41.9k]
  ------------------
  148|  3.00M|                dist = (unsigned)(here->val);
  149|  3.00M|                op &= 15;                       /* number of extra bits */
  150|  3.00M|                if (bits < op) {
  ------------------
  |  Branch (150:21): [True: 11.6k, False: 2.98M]
  ------------------
  151|  11.6k|                    hold += (unsigned long)(*in++) << bits;
  152|  11.6k|                    bits += 8;
  153|  11.6k|                    if (bits < op) {
  ------------------
  |  Branch (153:25): [True: 0, False: 11.6k]
  ------------------
  154|      0|                        hold += (unsigned long)(*in++) << bits;
  155|      0|                        bits += 8;
  156|      0|                    }
  157|  11.6k|                }
  158|  3.00M|                dist += (unsigned)hold & ((1U << op) - 1);
  159|       |#ifdef INFLATE_STRICT
  160|       |                if (dist > dmax) {
  161|       |                    strm->msg = (char *)"invalid distance too far back";
  162|       |                    state->mode = BAD;
  163|       |                    break;
  164|       |                }
  165|       |#endif
  166|  3.00M|                hold >>= op;
  167|  3.00M|                bits -= op;
  168|  3.00M|                Tracevv((stderr, "inflate:         distance %u\n", dist));
  169|  3.00M|                op = (unsigned)(out - beg);     /* max distance in output */
  170|  3.00M|                if (dist > op) {                /* see if copy from window */
  ------------------
  |  Branch (170:21): [True: 396, False: 3.00M]
  ------------------
  171|    396|                    op = dist - op;             /* distance back in window */
  172|    396|                    if (op > whave) {
  ------------------
  |  Branch (172:25): [True: 396, False: 0]
  ------------------
  173|    396|                        if (state->sane) {
  ------------------
  |  Branch (173:29): [True: 396, False: 0]
  ------------------
  174|    396|                            strm->msg =
  175|    396|                                (char *)"invalid distance too far back";
  176|    396|                            state->mode = BAD;
  177|    396|                            break;
  178|    396|                        }
  179|       |#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
  180|       |                        if (len <= op - whave) {
  181|       |                            do {
  182|       |                                *out++ = 0;
  183|       |                            } while (--len);
  184|       |                            continue;
  185|       |                        }
  186|       |                        len -= op - whave;
  187|       |                        do {
  188|       |                            *out++ = 0;
  189|       |                        } while (--op > whave);
  190|       |                        if (op == 0) {
  191|       |                            from = out - dist;
  192|       |                            do {
  193|       |                                *out++ = *from++;
  194|       |                            } while (--len);
  195|       |                            continue;
  196|       |                        }
  197|       |#endif
  198|    396|                    }
  199|      0|                    from = window;
  200|      0|                    if (wnext == 0) {           /* very common case */
  ------------------
  |  Branch (200:25): [True: 0, False: 0]
  ------------------
  201|      0|                        from += wsize - op;
  202|      0|                        if (op < len) {         /* some from window */
  ------------------
  |  Branch (202:29): [True: 0, False: 0]
  ------------------
  203|      0|                            len -= op;
  204|      0|                            do {
  205|      0|                                *out++ = *from++;
  206|      0|                            } while (--op);
  ------------------
  |  Branch (206:38): [True: 0, False: 0]
  ------------------
  207|      0|                            from = out - dist;  /* rest from output */
  208|      0|                        }
  209|      0|                    }
  210|      0|                    else if (wnext < op) {      /* wrap around window */
  ------------------
  |  Branch (210:30): [True: 0, False: 0]
  ------------------
  211|      0|                        from += wsize + wnext - op;
  212|      0|                        op -= wnext;
  213|      0|                        if (op < len) {         /* some from end of window */
  ------------------
  |  Branch (213:29): [True: 0, False: 0]
  ------------------
  214|      0|                            len -= op;
  215|      0|                            do {
  216|      0|                                *out++ = *from++;
  217|      0|                            } while (--op);
  ------------------
  |  Branch (217:38): [True: 0, False: 0]
  ------------------
  218|      0|                            from = window;
  219|      0|                            if (wnext < len) {  /* some from start of window */
  ------------------
  |  Branch (219:33): [True: 0, False: 0]
  ------------------
  220|      0|                                op = wnext;
  221|      0|                                len -= op;
  222|      0|                                do {
  223|      0|                                    *out++ = *from++;
  224|      0|                                } while (--op);
  ------------------
  |  Branch (224:42): [True: 0, False: 0]
  ------------------
  225|      0|                                from = out - dist;      /* rest from output */
  226|      0|                            }
  227|      0|                        }
  228|      0|                    }
  229|      0|                    else {                      /* contiguous in window */
  230|      0|                        from += wnext - op;
  231|      0|                        if (op < len) {         /* some from window */
  ------------------
  |  Branch (231:29): [True: 0, False: 0]
  ------------------
  232|      0|                            len -= op;
  233|      0|                            do {
  234|      0|                                *out++ = *from++;
  235|      0|                            } while (--op);
  ------------------
  |  Branch (235:38): [True: 0, False: 0]
  ------------------
  236|      0|                            from = out - dist;  /* rest from output */
  237|      0|                        }
  238|      0|                    }
  239|      0|                    while (len > 2) {
  ------------------
  |  Branch (239:28): [True: 0, False: 0]
  ------------------
  240|      0|                        *out++ = *from++;
  241|      0|                        *out++ = *from++;
  242|      0|                        *out++ = *from++;
  243|      0|                        len -= 3;
  244|      0|                    }
  245|      0|                    if (len) {
  ------------------
  |  Branch (245:25): [True: 0, False: 0]
  ------------------
  246|      0|                        *out++ = *from++;
  247|      0|                        if (len > 1)
  ------------------
  |  Branch (247:29): [True: 0, False: 0]
  ------------------
  248|      0|                            *out++ = *from++;
  249|      0|                    }
  250|      0|                }
  251|  3.00M|                else {
  252|  3.00M|                    from = out - dist;          /* copy direct from output */
  253|  5.02M|                    do {                        /* minimum length is three */
  254|  5.02M|                        *out++ = *from++;
  255|  5.02M|                        *out++ = *from++;
  256|  5.02M|                        *out++ = *from++;
  257|  5.02M|                        len -= 3;
  258|  5.02M|                    } while (len > 2);
  ------------------
  |  Branch (258:30): [True: 2.02M, False: 3.00M]
  ------------------
  259|  3.00M|                    if (len) {
  ------------------
  |  Branch (259:25): [True: 1.40M, False: 1.59M]
  ------------------
  260|  1.40M|                        *out++ = *from++;
  261|  1.40M|                        if (len > 1)
  ------------------
  |  Branch (261:29): [True: 581k, False: 827k]
  ------------------
  262|   581k|                            *out++ = *from++;
  263|  1.40M|                    }
  264|  3.00M|                }
  265|  3.00M|            }
  266|  41.9k|            else if ((op & 64) == 0) {          /* 2nd level distance code */
  ------------------
  |  Branch (266:22): [True: 41.9k, False: 1]
  ------------------
  267|  41.9k|                here = dcode + here->val + (hold & ((1U << op) - 1));
  268|  41.9k|                goto dodist;
  269|  41.9k|            }
  270|      1|            else {
  271|      1|                strm->msg = (char *)"invalid distance code";
  272|      1|                state->mode = BAD;
  273|      1|                break;
  274|      1|            }
  275|  3.04M|        }
  276|   403k|        else if ((op & 64) == 0) {              /* 2nd level length code */
  ------------------
  |  Branch (276:18): [True: 403k, False: 23]
  ------------------
  277|   403k|            here = lcode + here->val + (hold & ((1U << op) - 1));
  278|   403k|            goto dolen;
  279|   403k|        }
  280|     23|        else if (op & 32) {                     /* end-of-block */
  ------------------
  |  Branch (280:18): [True: 23, False: 0]
  ------------------
  281|     23|            Tracevv((stderr, "inflate:         end of block\n"));
  282|     23|            state->mode = TYPE;
  283|     23|            break;
  284|     23|        }
  285|      0|        else {
  286|      0|            strm->msg = (char *)"invalid literal/length code";
  287|      0|            state->mode = BAD;
  288|      0|            break;
  289|      0|        }
  290|  6.04M|    } while (in < last && out < end);
  ------------------
  |  Branch (290:14): [True: 5.64M, False: 17]
  |  Branch (290:27): [True: 5.63M, False: 4.73k]
  ------------------
  291|       |
  292|       |    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
  293|  5.16k|    len = bits >> 3;
  294|  5.16k|    in -= len;
  295|  5.16k|    bits -= len << 3;
  296|  5.16k|    hold &= (1U << bits) - 1;
  297|       |
  298|       |    /* update state and return */
  299|  5.16k|    strm->next_in = in;
  300|  5.16k|    strm->next_out = out;
  301|  5.16k|    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
  ------------------
  |  Branch (301:33): [True: 5.16k, False: 7]
  ------------------
  302|  5.16k|    strm->avail_out = (unsigned)(out < end ?
  ------------------
  |  Branch (302:34): [True: 436, False: 4.73k]
  ------------------
  303|  4.73k|                                 257 + (end - out) : 257 - (out - end));
  304|  5.16k|    state->hold = hold;
  305|  5.16k|    state->bits = bits;
  306|  5.16k|    return;
  307|  5.16k|}

inflateResetKeep:
  121|  5.55k|{
  122|  5.55k|    struct inflate_state FAR *state;
  123|       |
  124|  5.55k|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (124:9): [True: 0, False: 5.55k]
  ------------------
  125|  5.55k|    state = (struct inflate_state FAR *)strm->state;
  126|  5.55k|    strm->total_in = strm->total_out = state->total = 0;
  127|  5.55k|    strm->msg = Z_NULL;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  128|  5.55k|    if (state->wrap)        /* to support ill-conceived Java test suite */
  ------------------
  |  Branch (128:9): [True: 5.55k, False: 0]
  ------------------
  129|  5.55k|        strm->adler = state->wrap & 1;
  130|  5.55k|    state->mode = HEAD;
  131|  5.55k|    state->last = 0;
  132|  5.55k|    state->havedict = 0;
  133|  5.55k|    state->flags = -1;
  134|  5.55k|    state->dmax = 32768U;
  135|  5.55k|    state->head = Z_NULL;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  136|  5.55k|    state->hold = 0;
  137|  5.55k|    state->bits = 0;
  138|  5.55k|    state->lencode = state->distcode = state->next = state->codes;
  139|  5.55k|    state->sane = 1;
  140|  5.55k|    state->back = -1;
  141|  5.55k|    Tracev((stderr, "inflate: reset\n"));
  142|  5.55k|    return Z_OK;
  ------------------
  |  |  177|  5.55k|#define Z_OK            0
  ------------------
  143|  5.55k|}
inflateReset:
  147|  5.55k|{
  148|  5.55k|    struct inflate_state FAR *state;
  149|       |
  150|  5.55k|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (150:9): [True: 0, False: 5.55k]
  ------------------
  151|  5.55k|    state = (struct inflate_state FAR *)strm->state;
  152|  5.55k|    state->wsize = 0;
  153|  5.55k|    state->whave = 0;
  154|  5.55k|    state->wnext = 0;
  155|  5.55k|    return inflateResetKeep(strm);
  156|  5.55k|}
inflateReset2:
  161|  5.55k|{
  162|  5.55k|    int wrap;
  163|  5.55k|    struct inflate_state FAR *state;
  164|       |
  165|       |    /* get the state */
  166|  5.55k|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (166:9): [True: 0, False: 5.55k]
  ------------------
  167|  5.55k|    state = (struct inflate_state FAR *)strm->state;
  168|       |
  169|       |    /* extract wrap request from windowBits parameter */
  170|  5.55k|    if (windowBits < 0) {
  ------------------
  |  Branch (170:9): [True: 0, False: 5.55k]
  ------------------
  171|      0|        if (windowBits < -15)
  ------------------
  |  Branch (171:13): [True: 0, False: 0]
  ------------------
  172|      0|            return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  173|      0|        wrap = 0;
  174|      0|        windowBits = -windowBits;
  175|      0|    }
  176|  5.55k|    else {
  177|  5.55k|        wrap = (windowBits >> 4) + 5;
  178|  5.55k|#ifdef GUNZIP
  179|  5.55k|        if (windowBits < 48)
  ------------------
  |  Branch (179:13): [True: 5.55k, False: 0]
  ------------------
  180|  5.55k|            windowBits &= 15;
  181|  5.55k|#endif
  182|  5.55k|    }
  183|       |
  184|       |    /* set number of window bits, free window if different */
  185|  5.55k|    if (windowBits && (windowBits < 8 || windowBits > 15))
  ------------------
  |  Branch (185:9): [True: 5.55k, False: 0]
  |  Branch (185:24): [True: 0, False: 5.55k]
  |  Branch (185:42): [True: 0, False: 5.55k]
  ------------------
  186|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  187|  5.55k|    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
  ------------------
  |  |  212|  11.1k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (187:9): [True: 0, False: 5.55k]
  |  Branch (187:36): [True: 0, False: 0]
  ------------------
  188|      0|        ZFREE(strm, state->window);
  ------------------
  |  |  268|      0|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
  189|      0|        state->window = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  190|      0|    }
  191|       |
  192|       |    /* update state and reset the rest of it */
  193|  5.55k|    state->wrap = wrap;
  194|  5.55k|    state->wbits = (unsigned)windowBits;
  195|  5.55k|    return inflateReset(strm);
  196|  5.55k|}
inflateInit2_:
  203|  5.55k|{
  204|  5.55k|    int ret;
  205|  5.55k|    struct inflate_state FAR *state;
  206|       |
  207|  5.55k|    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
  ------------------
  |  |  212|  11.1k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
  ------------------
  |  |   40|  5.55k|#define ZLIB_VERSION "1.2.13"
  ------------------
  |  Branch (207:9): [True: 0, False: 5.55k]
  |  Branch (207:30): [True: 0, False: 5.55k]
  ------------------
  208|  5.55k|        stream_size != (int)(sizeof(z_stream)))
  ------------------
  |  Branch (208:9): [True: 0, False: 5.55k]
  ------------------
  209|      0|        return Z_VERSION_ERROR;
  ------------------
  |  |  185|      0|#define Z_VERSION_ERROR (-6)
  ------------------
  210|  5.55k|    if (strm == Z_NULL) return Z_STREAM_ERROR;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (strm == Z_NULL) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (210:9): [True: 0, False: 5.55k]
  ------------------
  211|  5.55k|    strm->msg = Z_NULL;                 /* in case we return an error */
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  212|  5.55k|    if (strm->zalloc == (alloc_func)0) {
  ------------------
  |  Branch (212:9): [True: 5.55k, False: 0]
  ------------------
  213|       |#ifdef Z_SOLO
  214|       |        return Z_STREAM_ERROR;
  215|       |#else
  216|  5.55k|        strm->zalloc = zcalloc;
  217|  5.55k|        strm->opaque = (voidpf)0;
  218|  5.55k|#endif
  219|  5.55k|    }
  220|  5.55k|    if (strm->zfree == (free_func)0)
  ------------------
  |  Branch (220:9): [True: 5.55k, False: 0]
  ------------------
  221|       |#ifdef Z_SOLO
  222|       |        return Z_STREAM_ERROR;
  223|       |#else
  224|  5.55k|        strm->zfree = zcfree;
  225|  5.55k|#endif
  226|  5.55k|    state = (struct inflate_state FAR *)
  227|  5.55k|            ZALLOC(strm, 1, sizeof(struct inflate_state));
  ------------------
  |  |  267|  5.55k|           (*((strm)->zalloc))((strm)->opaque, (items), (size))
  ------------------
  228|  5.55k|    if (state == Z_NULL) return Z_MEM_ERROR;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (state == Z_NULL) return Z_MEM_ERROR;
  ------------------
  |  |  183|      0|#define Z_MEM_ERROR    (-4)
  ------------------
  |  Branch (228:9): [True: 0, False: 5.55k]
  ------------------
  229|  5.55k|    Tracev((stderr, "inflate: allocated\n"));
  230|  5.55k|    strm->state = (struct internal_state FAR *)state;
  231|  5.55k|    state->strm = strm;
  232|  5.55k|    state->window = Z_NULL;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  233|  5.55k|    state->mode = HEAD;     /* to pass state test in inflateReset2() */
  234|  5.55k|    ret = inflateReset2(strm, windowBits);
  235|  5.55k|    if (ret != Z_OK) {
  ------------------
  |  |  177|  5.55k|#define Z_OK            0
  ------------------
  |  Branch (235:9): [True: 0, False: 5.55k]
  ------------------
  236|      0|        ZFREE(strm, state);
  ------------------
  |  |  268|      0|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
  237|      0|        strm->state = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  238|      0|    }
  239|  5.55k|    return ret;
  240|  5.55k|}
inflateInit_:
  246|  5.55k|{
  247|  5.55k|    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
  ------------------
  |  |   68|  5.55k|#  define DEF_WBITS MAX_WBITS
  |  |  ------------------
  |  |  |  |  275|  5.55k|#  define MAX_WBITS   15 /* 32K LZ77 window */
  |  |  ------------------
  ------------------
  248|  5.55k|}
inflate:
  628|  5.55k|{
  629|  5.55k|    struct inflate_state FAR *state;
  630|  5.55k|    z_const unsigned char FAR *next;    /* next input */
  631|  5.55k|    unsigned char FAR *put;     /* next output */
  632|  5.55k|    unsigned have, left;        /* available input and output */
  633|  5.55k|    unsigned long hold;         /* bit buffer */
  634|  5.55k|    unsigned bits;              /* bits in bit buffer */
  635|  5.55k|    unsigned in, out;           /* save starting available input and output */
  636|  5.55k|    unsigned copy;              /* number of stored or match bytes to copy */
  637|  5.55k|    unsigned char FAR *from;    /* where to copy match bytes from */
  638|  5.55k|    code here;                  /* current decoding table entry */
  639|  5.55k|    code last;                  /* parent table entry */
  640|  5.55k|    unsigned len;               /* length to copy for repeats, bits to drop */
  641|  5.55k|    int ret;                    /* return code */
  642|  5.55k|#ifdef GUNZIP
  643|  5.55k|    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
  644|  5.55k|#endif
  645|  5.55k|    static const unsigned short order[19] = /* permutation of code lengths */
  646|  5.55k|        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
  647|       |
  648|  5.55k|    if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||
  ------------------
  |  |  212|  11.1k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (648:9): [True: 0, False: 5.55k]
  |  Branch (648:36): [True: 0, False: 5.55k]
  ------------------
  649|  5.55k|        (strm->next_in == Z_NULL && strm->avail_in != 0))
  ------------------
  |  |  212|  11.1k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (649:10): [True: 0, False: 5.55k]
  |  Branch (649:37): [True: 0, False: 0]
  ------------------
  650|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  651|       |
  652|  5.55k|    state = (struct inflate_state FAR *)strm->state;
  653|  5.55k|    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
  ------------------
  |  Branch (653:9): [True: 0, False: 5.55k]
  ------------------
  654|  5.55k|    LOAD();
  ------------------
  |  |  480|  5.55k|    do { \
  |  |  481|  5.55k|        put = strm->next_out; \
  |  |  482|  5.55k|        left = strm->avail_out; \
  |  |  483|  5.55k|        next = strm->next_in; \
  |  |  484|  5.55k|        have = strm->avail_in; \
  |  |  485|  5.55k|        hold = state->hold; \
  |  |  486|  5.55k|        bits = state->bits; \
  |  |  487|  5.55k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (487:14): [Folded, False: 5.55k]
  |  |  ------------------
  ------------------
  655|  5.55k|    in = have;
  656|  5.55k|    out = left;
  657|  5.55k|    ret = Z_OK;
  ------------------
  |  |  177|  5.55k|#define Z_OK            0
  ------------------
  658|  5.55k|    for (;;)
  659|   711k|        switch (state->mode) {
  660|  5.55k|        case HEAD:
  ------------------
  |  Branch (660:9): [True: 5.55k, False: 705k]
  ------------------
  661|  5.55k|            if (state->wrap == 0) {
  ------------------
  |  Branch (661:17): [True: 0, False: 5.55k]
  ------------------
  662|      0|                state->mode = TYPEDO;
  663|      0|                break;
  664|      0|            }
  665|  5.55k|            NEEDBITS(16);
  ------------------
  |  |  520|  5.55k|    do { \
  |  |  521|  16.6k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 11.1k, False: 5.55k]
  |  |  ------------------
  |  |  522|  11.1k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  11.1k|    do { \
  |  |  |  |  511|  11.1k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 11.1k]
  |  |  |  |  ------------------
  |  |  |  |  512|  11.1k|        have--; \
  |  |  |  |  513|  11.1k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  11.1k|        bits += 8; \
  |  |  |  |  515|  11.1k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 11.1k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  5.55k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 5.55k]
  |  |  ------------------
  ------------------
  666|  5.55k|#ifdef GUNZIP
  667|  5.55k|            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
  ------------------
  |  Branch (667:17): [True: 0, False: 5.55k]
  |  Branch (667:38): [True: 0, False: 0]
  ------------------
  668|      0|                if (state->wbits == 0)
  ------------------
  |  Branch (668:21): [True: 0, False: 0]
  ------------------
  669|      0|                    state->wbits = 15;
  670|      0|                state->check = crc32(0L, Z_NULL, 0);
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  671|      0|                CRC2(state->check, hold);
  ------------------
  |  |  462|      0|    do { \
  |  |  463|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  464|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  465|      0|        check = crc32(check, hbuf, 2); \
  |  |  466|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (466:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  672|      0|                INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  673|      0|                state->mode = FLAGS;
  674|      0|                break;
  675|      0|            }
  676|  5.55k|            if (state->head != Z_NULL)
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (676:17): [True: 0, False: 5.55k]
  ------------------
  677|      0|                state->head->done = -1;
  678|  5.55k|            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
  ------------------
  |  Branch (678:17): [True: 0, False: 5.55k]
  ------------------
  679|       |#else
  680|       |            if (
  681|       |#endif
  682|  5.55k|                ((BITS(8) << 8) + (hold >> 8)) % 31) {
  ------------------
  |  |  527|  5.55k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  |  Branch (682:17): [True: 9, False: 5.54k]
  ------------------
  683|      9|                strm->msg = (char *)"incorrect header check";
  684|      9|                state->mode = BAD;
  685|      9|                break;
  686|      9|            }
  687|  5.54k|            if (BITS(4) != Z_DEFLATED) {
  ------------------
  |  |  527|  5.54k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
                          if (BITS(4) != Z_DEFLATED) {
  ------------------
  |  |  209|  5.54k|#define Z_DEFLATED   8
  ------------------
  |  Branch (687:17): [True: 0, False: 5.54k]
  ------------------
  688|      0|                strm->msg = (char *)"unknown compression method";
  689|      0|                state->mode = BAD;
  690|      0|                break;
  691|      0|            }
  692|  5.54k|            DROPBITS(4);
  ------------------
  |  |  531|  5.54k|    do { \
  |  |  532|  5.54k|        hold >>= (n); \
  |  |  533|  5.54k|        bits -= (unsigned)(n); \
  |  |  534|  5.54k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 5.54k]
  |  |  ------------------
  ------------------
  693|  5.54k|            len = BITS(4) + 8;
  ------------------
  |  |  527|  5.54k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  694|  5.54k|            if (state->wbits == 0)
  ------------------
  |  Branch (694:17): [True: 0, False: 5.54k]
  ------------------
  695|      0|                state->wbits = len;
  696|  5.54k|            if (len > 15 || len > state->wbits) {
  ------------------
  |  Branch (696:17): [True: 0, False: 5.54k]
  |  Branch (696:29): [True: 0, False: 5.54k]
  ------------------
  697|      0|                strm->msg = (char *)"invalid window size";
  698|      0|                state->mode = BAD;
  699|      0|                break;
  700|      0|            }
  701|  5.54k|            state->dmax = 1U << len;
  702|  5.54k|            state->flags = 0;               /* indicate zlib header */
  703|  5.54k|            Tracev((stderr, "inflate:   zlib header ok\n"));
  704|  5.54k|            strm->adler = state->check = adler32(0L, Z_NULL, 0);
  ------------------
  |  |  212|  5.54k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  705|  5.54k|            state->mode = hold & 0x200 ? DICTID : TYPE;
  ------------------
  |  Branch (705:27): [True: 0, False: 5.54k]
  ------------------
  706|  5.54k|            INITBITS();
  ------------------
  |  |  502|  5.54k|    do { \
  |  |  503|  5.54k|        hold = 0; \
  |  |  504|  5.54k|        bits = 0; \
  |  |  505|  5.54k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 5.54k]
  |  |  ------------------
  ------------------
  707|  5.54k|            break;
  708|      0|#ifdef GUNZIP
  709|      0|        case FLAGS:
  ------------------
  |  Branch (709:9): [True: 0, False: 711k]
  ------------------
  710|      0|            NEEDBITS(16);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  711|      0|            state->flags = (int)(hold);
  712|      0|            if ((state->flags & 0xff) != Z_DEFLATED) {
  ------------------
  |  |  209|      0|#define Z_DEFLATED   8
  ------------------
  |  Branch (712:17): [True: 0, False: 0]
  ------------------
  713|      0|                strm->msg = (char *)"unknown compression method";
  714|      0|                state->mode = BAD;
  715|      0|                break;
  716|      0|            }
  717|      0|            if (state->flags & 0xe000) {
  ------------------
  |  Branch (717:17): [True: 0, False: 0]
  ------------------
  718|      0|                strm->msg = (char *)"unknown header flags set";
  719|      0|                state->mode = BAD;
  720|      0|                break;
  721|      0|            }
  722|      0|            if (state->head != Z_NULL)
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (722:17): [True: 0, False: 0]
  ------------------
  723|      0|                state->head->text = (int)((hold >> 8) & 1);
  724|      0|            if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (724:17): [True: 0, False: 0]
  |  Branch (724:44): [True: 0, False: 0]
  ------------------
  725|      0|                CRC2(state->check, hold);
  ------------------
  |  |  462|      0|    do { \
  |  |  463|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  464|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  465|      0|        check = crc32(check, hbuf, 2); \
  |  |  466|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (466:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  726|      0|            INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  727|      0|            state->mode = TIME;
  728|       |                /* fallthrough */
  729|      0|        case TIME:
  ------------------
  |  Branch (729:9): [True: 0, False: 711k]
  ------------------
  730|      0|            NEEDBITS(32);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  731|      0|            if (state->head != Z_NULL)
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (731:17): [True: 0, False: 0]
  ------------------
  732|      0|                state->head->time = hold;
  733|      0|            if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (733:17): [True: 0, False: 0]
  |  Branch (733:44): [True: 0, False: 0]
  ------------------
  734|      0|                CRC4(state->check, hold);
  ------------------
  |  |  469|      0|    do { \
  |  |  470|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  471|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  472|      0|        hbuf[2] = (unsigned char)((word) >> 16); \
  |  |  473|      0|        hbuf[3] = (unsigned char)((word) >> 24); \
  |  |  474|      0|        check = crc32(check, hbuf, 4); \
  |  |  475|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (475:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  735|      0|            INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  736|      0|            state->mode = OS;
  737|       |                /* fallthrough */
  738|      0|        case OS:
  ------------------
  |  Branch (738:9): [True: 0, False: 711k]
  ------------------
  739|      0|            NEEDBITS(16);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  740|      0|            if (state->head != Z_NULL) {
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (740:17): [True: 0, False: 0]
  ------------------
  741|      0|                state->head->xflags = (int)(hold & 0xff);
  742|      0|                state->head->os = (int)(hold >> 8);
  743|      0|            }
  744|      0|            if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (744:17): [True: 0, False: 0]
  |  Branch (744:44): [True: 0, False: 0]
  ------------------
  745|      0|                CRC2(state->check, hold);
  ------------------
  |  |  462|      0|    do { \
  |  |  463|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  464|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  465|      0|        check = crc32(check, hbuf, 2); \
  |  |  466|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (466:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  746|      0|            INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  747|      0|            state->mode = EXLEN;
  748|       |                /* fallthrough */
  749|      0|        case EXLEN:
  ------------------
  |  Branch (749:9): [True: 0, False: 711k]
  ------------------
  750|      0|            if (state->flags & 0x0400) {
  ------------------
  |  Branch (750:17): [True: 0, False: 0]
  ------------------
  751|      0|                NEEDBITS(16);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  752|      0|                state->length = (unsigned)(hold);
  753|      0|                if (state->head != Z_NULL)
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (753:21): [True: 0, False: 0]
  ------------------
  754|      0|                    state->head->extra_len = (unsigned)hold;
  755|      0|                if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (755:21): [True: 0, False: 0]
  |  Branch (755:48): [True: 0, False: 0]
  ------------------
  756|      0|                    CRC2(state->check, hold);
  ------------------
  |  |  462|      0|    do { \
  |  |  463|      0|        hbuf[0] = (unsigned char)(word); \
  |  |  464|      0|        hbuf[1] = (unsigned char)((word) >> 8); \
  |  |  465|      0|        check = crc32(check, hbuf, 2); \
  |  |  466|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (466:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  757|      0|                INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  758|      0|            }
  759|      0|            else if (state->head != Z_NULL)
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (759:22): [True: 0, False: 0]
  ------------------
  760|      0|                state->head->extra = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  761|      0|            state->mode = EXTRA;
  762|       |                /* fallthrough */
  763|      0|        case EXTRA:
  ------------------
  |  Branch (763:9): [True: 0, False: 711k]
  ------------------
  764|      0|            if (state->flags & 0x0400) {
  ------------------
  |  Branch (764:17): [True: 0, False: 0]
  ------------------
  765|      0|                copy = state->length;
  766|      0|                if (copy > have) copy = have;
  ------------------
  |  Branch (766:21): [True: 0, False: 0]
  ------------------
  767|      0|                if (copy) {
  ------------------
  |  Branch (767:21): [True: 0, False: 0]
  ------------------
  768|      0|                    if (state->head != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (768:25): [True: 0, False: 0]
  ------------------
  769|      0|                        state->head->extra != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (769:25): [True: 0, False: 0]
  ------------------
  770|      0|                        (len = state->head->extra_len - state->length) <
  ------------------
  |  Branch (770:25): [True: 0, False: 0]
  ------------------
  771|      0|                            state->head->extra_max) {
  772|      0|                        zmemcpy(state->head->extra + len, next,
  ------------------
  |  |  230|      0|#    define zmemcpy memcpy
  ------------------
  773|      0|                                len + copy > state->head->extra_max ?
  ------------------
  |  Branch (773:33): [True: 0, False: 0]
  ------------------
  774|      0|                                state->head->extra_max - len : copy);
  775|      0|                    }
  776|      0|                    if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (776:25): [True: 0, False: 0]
  |  Branch (776:52): [True: 0, False: 0]
  ------------------
  777|      0|                        state->check = crc32(state->check, next, copy);
  778|      0|                    have -= copy;
  779|      0|                    next += copy;
  780|      0|                    state->length -= copy;
  781|      0|                }
  782|      0|                if (state->length) goto inf_leave;
  ------------------
  |  Branch (782:21): [True: 0, False: 0]
  ------------------
  783|      0|            }
  784|      0|            state->length = 0;
  785|      0|            state->mode = NAME;
  786|       |                /* fallthrough */
  787|      0|        case NAME:
  ------------------
  |  Branch (787:9): [True: 0, False: 711k]
  ------------------
  788|      0|            if (state->flags & 0x0800) {
  ------------------
  |  Branch (788:17): [True: 0, False: 0]
  ------------------
  789|      0|                if (have == 0) goto inf_leave;
  ------------------
  |  Branch (789:21): [True: 0, False: 0]
  ------------------
  790|      0|                copy = 0;
  791|      0|                do {
  792|      0|                    len = (unsigned)(next[copy++]);
  793|      0|                    if (state->head != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (793:25): [True: 0, False: 0]
  ------------------
  794|      0|                            state->head->name != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (794:29): [True: 0, False: 0]
  ------------------
  795|      0|                            state->length < state->head->name_max)
  ------------------
  |  Branch (795:29): [True: 0, False: 0]
  ------------------
  796|      0|                        state->head->name[state->length++] = (Bytef)len;
  797|      0|                } while (len && copy < have);
  ------------------
  |  Branch (797:26): [True: 0, False: 0]
  |  Branch (797:33): [True: 0, False: 0]
  ------------------
  798|      0|                if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (798:21): [True: 0, False: 0]
  |  Branch (798:48): [True: 0, False: 0]
  ------------------
  799|      0|                    state->check = crc32(state->check, next, copy);
  800|      0|                have -= copy;
  801|      0|                next += copy;
  802|      0|                if (len) goto inf_leave;
  ------------------
  |  Branch (802:21): [True: 0, False: 0]
  ------------------
  803|      0|            }
  804|      0|            else if (state->head != Z_NULL)
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (804:22): [True: 0, False: 0]
  ------------------
  805|      0|                state->head->name = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  806|      0|            state->length = 0;
  807|      0|            state->mode = COMMENT;
  808|       |                /* fallthrough */
  809|      0|        case COMMENT:
  ------------------
  |  Branch (809:9): [True: 0, False: 711k]
  ------------------
  810|      0|            if (state->flags & 0x1000) {
  ------------------
  |  Branch (810:17): [True: 0, False: 0]
  ------------------
  811|      0|                if (have == 0) goto inf_leave;
  ------------------
  |  Branch (811:21): [True: 0, False: 0]
  ------------------
  812|      0|                copy = 0;
  813|      0|                do {
  814|      0|                    len = (unsigned)(next[copy++]);
  815|      0|                    if (state->head != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (815:25): [True: 0, False: 0]
  ------------------
  816|      0|                            state->head->comment != Z_NULL &&
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (816:29): [True: 0, False: 0]
  ------------------
  817|      0|                            state->length < state->head->comm_max)
  ------------------
  |  Branch (817:29): [True: 0, False: 0]
  ------------------
  818|      0|                        state->head->comment[state->length++] = (Bytef)len;
  819|      0|                } while (len && copy < have);
  ------------------
  |  Branch (819:26): [True: 0, False: 0]
  |  Branch (819:33): [True: 0, False: 0]
  ------------------
  820|      0|                if ((state->flags & 0x0200) && (state->wrap & 4))
  ------------------
  |  Branch (820:21): [True: 0, False: 0]
  |  Branch (820:48): [True: 0, False: 0]
  ------------------
  821|      0|                    state->check = crc32(state->check, next, copy);
  822|      0|                have -= copy;
  823|      0|                next += copy;
  824|      0|                if (len) goto inf_leave;
  ------------------
  |  Branch (824:21): [True: 0, False: 0]
  ------------------
  825|      0|            }
  826|      0|            else if (state->head != Z_NULL)
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (826:22): [True: 0, False: 0]
  ------------------
  827|      0|                state->head->comment = Z_NULL;
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  828|      0|            state->mode = HCRC;
  829|       |                /* fallthrough */
  830|      0|        case HCRC:
  ------------------
  |  Branch (830:9): [True: 0, False: 711k]
  ------------------
  831|      0|            if (state->flags & 0x0200) {
  ------------------
  |  Branch (831:17): [True: 0, False: 0]
  ------------------
  832|      0|                NEEDBITS(16);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  833|      0|                if ((state->wrap & 4) && hold != (state->check & 0xffff)) {
  ------------------
  |  Branch (833:21): [True: 0, False: 0]
  |  Branch (833:42): [True: 0, False: 0]
  ------------------
  834|      0|                    strm->msg = (char *)"header crc mismatch";
  835|      0|                    state->mode = BAD;
  836|      0|                    break;
  837|      0|                }
  838|      0|                INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  839|      0|            }
  840|      0|            if (state->head != Z_NULL) {
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (840:17): [True: 0, False: 0]
  ------------------
  841|      0|                state->head->hcrc = (int)((state->flags >> 9) & 1);
  842|      0|                state->head->done = 1;
  843|      0|            }
  844|      0|            strm->adler = state->check = crc32(0L, Z_NULL, 0);
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  845|      0|            state->mode = TYPE;
  846|      0|            break;
  847|      0|#endif
  848|      0|        case DICTID:
  ------------------
  |  Branch (848:9): [True: 0, False: 711k]
  ------------------
  849|      0|            NEEDBITS(32);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  850|      0|            strm->adler = state->check = ZSWAP32(hold);
  ------------------
  |  |  272|      0|#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
  |  |  273|      0|                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
  ------------------
  851|      0|            INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  852|      0|            state->mode = DICT;
  853|       |                /* fallthrough */
  854|      0|        case DICT:
  ------------------
  |  Branch (854:9): [True: 0, False: 711k]
  ------------------
  855|      0|            if (state->havedict == 0) {
  ------------------
  |  Branch (855:17): [True: 0, False: 0]
  ------------------
  856|      0|                RESTORE();
  ------------------
  |  |  491|      0|    do { \
  |  |  492|      0|        strm->next_out = put; \
  |  |  493|      0|        strm->avail_out = left; \
  |  |  494|      0|        strm->next_in = next; \
  |  |  495|      0|        strm->avail_in = have; \
  |  |  496|      0|        state->hold = hold; \
  |  |  497|      0|        state->bits = bits; \
  |  |  498|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  857|      0|                return Z_NEED_DICT;
  ------------------
  |  |  179|      0|#define Z_NEED_DICT     2
  ------------------
  858|      0|            }
  859|      0|            strm->adler = state->check = adler32(0L, Z_NULL, 0);
  ------------------
  |  |  212|      0|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  860|      0|            state->mode = TYPE;
  861|       |                /* fallthrough */
  862|  10.1k|        case TYPE:
  ------------------
  |  Branch (862:9): [True: 10.1k, False: 701k]
  ------------------
  863|  10.1k|            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  173|  20.3k|#define Z_BLOCK         5
  ------------------
                          if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  174|  10.1k|#define Z_TREES         6
  ------------------
  |  Branch (863:17): [True: 0, False: 10.1k]
  |  Branch (863:37): [True: 0, False: 10.1k]
  ------------------
  864|       |                /* fallthrough */
  865|  10.1k|        case TYPEDO:
  ------------------
  |  Branch (865:9): [True: 0, False: 711k]
  ------------------
  866|  10.1k|            if (state->last) {
  ------------------
  |  Branch (866:17): [True: 4.61k, False: 5.54k]
  ------------------
  867|  4.61k|                BYTEBITS();
  ------------------
  |  |  538|  4.61k|    do { \
  |  |  539|  4.61k|        hold >>= bits & 7; \
  |  |  540|  4.61k|        bits -= bits & 7; \
  |  |  541|  4.61k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (541:14): [Folded, False: 4.61k]
  |  |  ------------------
  ------------------
  868|  4.61k|                state->mode = CHECK;
  869|  4.61k|                break;
  870|  4.61k|            }
  871|  5.54k|            NEEDBITS(3);
  ------------------
  |  |  520|  5.54k|    do { \
  |  |  521|  11.0k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 5.54k, False: 5.54k]
  |  |  ------------------
  |  |  522|  5.54k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  5.54k|    do { \
  |  |  |  |  511|  5.54k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 5.54k]
  |  |  |  |  ------------------
  |  |  |  |  512|  5.54k|        have--; \
  |  |  |  |  513|  5.54k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  5.54k|        bits += 8; \
  |  |  |  |  515|  5.54k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 5.54k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  5.54k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 5.54k]
  |  |  ------------------
  ------------------
  872|  5.54k|            state->last = BITS(1);
  ------------------
  |  |  527|  5.54k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  873|  5.54k|            DROPBITS(1);
  ------------------
  |  |  531|  5.54k|    do { \
  |  |  532|  5.54k|        hold >>= (n); \
  |  |  533|  5.54k|        bits -= (unsigned)(n); \
  |  |  534|  5.54k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 5.54k]
  |  |  ------------------
  ------------------
  874|  5.54k|            switch (BITS(2)) {
  ------------------
  |  |  527|  5.54k|    ((unsigned)hold & ((1U << (n)) - 1))
  |  |  ------------------
  |  |  |  Branch (527:5): [True: 5.54k, False: 0]
  |  |  ------------------
  ------------------
  875|      2|            case 0:                             /* stored block */
  ------------------
  |  Branch (875:13): [True: 2, False: 5.54k]
  ------------------
  876|      2|                Tracev((stderr, "inflate:     stored block%s\n",
  877|      2|                        state->last ? " (last)" : ""));
  878|      2|                state->mode = STORED;
  879|      2|                break;
  880|    205|            case 1:                             /* fixed block */
  ------------------
  |  Branch (880:13): [True: 205, False: 5.34k]
  ------------------
  881|    205|                fixedtables(state);
  882|    205|                Tracev((stderr, "inflate:     fixed codes block%s\n",
  883|    205|                        state->last ? " (last)" : ""));
  884|    205|                state->mode = LEN_;             /* decode codes */
  885|    205|                if (flush == Z_TREES) {
  ------------------
  |  |  174|    205|#define Z_TREES         6
  ------------------
  |  Branch (885:21): [True: 0, False: 205]
  ------------------
  886|      0|                    DROPBITS(2);
  ------------------
  |  |  531|      0|    do { \
  |  |  532|      0|        hold >>= (n); \
  |  |  533|      0|        bits -= (unsigned)(n); \
  |  |  534|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  887|      0|                    goto inf_leave;
  888|      0|                }
  889|    205|                break;
  890|  5.33k|            case 2:                             /* dynamic block */
  ------------------
  |  Branch (890:13): [True: 5.33k, False: 207]
  ------------------
  891|  5.33k|                Tracev((stderr, "inflate:     dynamic codes block%s\n",
  892|  5.33k|                        state->last ? " (last)" : ""));
  893|  5.33k|                state->mode = TABLE;
  894|  5.33k|                break;
  895|      0|            case 3:
  ------------------
  |  Branch (895:13): [True: 0, False: 5.54k]
  ------------------
  896|      0|                strm->msg = (char *)"invalid block type";
  897|      0|                state->mode = BAD;
  898|  5.54k|            }
  899|  5.54k|            DROPBITS(2);
  ------------------
  |  |  531|  5.54k|    do { \
  |  |  532|  5.54k|        hold >>= (n); \
  |  |  533|  5.54k|        bits -= (unsigned)(n); \
  |  |  534|  5.54k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 5.54k]
  |  |  ------------------
  ------------------
  900|  5.54k|            break;
  901|      2|        case STORED:
  ------------------
  |  Branch (901:9): [True: 2, False: 711k]
  ------------------
  902|      2|            BYTEBITS();                         /* go to byte boundary */
  ------------------
  |  |  538|      2|    do { \
  |  |  539|      2|        hold >>= bits & 7; \
  |  |  540|      2|        bits -= bits & 7; \
  |  |  541|      2|    } while (0)
  |  |  ------------------
  |  |  |  Branch (541:14): [Folded, False: 2]
  |  |  ------------------
  ------------------
  903|      2|            NEEDBITS(32);
  ------------------
  |  |  520|      2|    do { \
  |  |  521|     10|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 8, False: 2]
  |  |  ------------------
  |  |  522|      8|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      8|    do { \
  |  |  |  |  511|      8|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 8]
  |  |  |  |  ------------------
  |  |  |  |  512|      8|        have--; \
  |  |  |  |  513|      8|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      8|        bits += 8; \
  |  |  |  |  515|      8|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 8]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      2|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 2]
  |  |  ------------------
  ------------------
  904|      2|            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
  ------------------
  |  Branch (904:17): [True: 2, False: 0]
  ------------------
  905|      2|                strm->msg = (char *)"invalid stored block lengths";
  906|      2|                state->mode = BAD;
  907|      2|                break;
  908|      2|            }
  909|      0|            state->length = (unsigned)hold & 0xffff;
  910|      0|            Tracev((stderr, "inflate:       stored length %u\n",
  911|      0|                    state->length));
  912|      0|            INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
  913|      0|            state->mode = COPY_;
  914|      0|            if (flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  174|      0|#define Z_TREES         6
  ------------------
  |  Branch (914:17): [True: 0, False: 0]
  ------------------
  915|       |                /* fallthrough */
  916|      0|        case COPY_:
  ------------------
  |  Branch (916:9): [True: 0, False: 711k]
  ------------------
  917|      0|            state->mode = COPY;
  918|       |                /* fallthrough */
  919|      0|        case COPY:
  ------------------
  |  Branch (919:9): [True: 0, False: 711k]
  ------------------
  920|      0|            copy = state->length;
  921|      0|            if (copy) {
  ------------------
  |  Branch (921:17): [True: 0, False: 0]
  ------------------
  922|      0|                if (copy > have) copy = have;
  ------------------
  |  Branch (922:21): [True: 0, False: 0]
  ------------------
  923|      0|                if (copy > left) copy = left;
  ------------------
  |  Branch (923:21): [True: 0, False: 0]
  ------------------
  924|      0|                if (copy == 0) goto inf_leave;
  ------------------
  |  Branch (924:21): [True: 0, False: 0]
  ------------------
  925|      0|                zmemcpy(put, next, copy);
  ------------------
  |  |  230|      0|#    define zmemcpy memcpy
  ------------------
  926|      0|                have -= copy;
  927|      0|                next += copy;
  928|      0|                left -= copy;
  929|      0|                put += copy;
  930|      0|                state->length -= copy;
  931|      0|                break;
  932|      0|            }
  933|      0|            Tracev((stderr, "inflate:       stored end\n"));
  934|      0|            state->mode = TYPE;
  935|      0|            break;
  936|  5.33k|        case TABLE:
  ------------------
  |  Branch (936:9): [True: 5.33k, False: 705k]
  ------------------
  937|  5.33k|            NEEDBITS(14);
  ------------------
  |  |  520|  5.33k|    do { \
  |  |  521|  16.0k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 10.6k, False: 5.33k]
  |  |  ------------------
  |  |  522|  10.6k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  10.6k|    do { \
  |  |  |  |  511|  10.6k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 10.6k]
  |  |  |  |  ------------------
  |  |  |  |  512|  10.6k|        have--; \
  |  |  |  |  513|  10.6k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  10.6k|        bits += 8; \
  |  |  |  |  515|  10.6k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 10.6k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  5.33k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 5.33k]
  |  |  ------------------
  ------------------
  938|  5.33k|            state->nlen = BITS(5) + 257;
  ------------------
  |  |  527|  5.33k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  939|  5.33k|            DROPBITS(5);
  ------------------
  |  |  531|  5.33k|    do { \
  |  |  532|  5.33k|        hold >>= (n); \
  |  |  533|  5.33k|        bits -= (unsigned)(n); \
  |  |  534|  5.33k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 5.33k]
  |  |  ------------------
  ------------------
  940|  5.33k|            state->ndist = BITS(5) + 1;
  ------------------
  |  |  527|  5.33k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  941|  5.33k|            DROPBITS(5);
  ------------------
  |  |  531|  5.33k|    do { \
  |  |  532|  5.33k|        hold >>= (n); \
  |  |  533|  5.33k|        bits -= (unsigned)(n); \
  |  |  534|  5.33k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 5.33k]
  |  |  ------------------
  ------------------
  942|  5.33k|            state->ncode = BITS(4) + 4;
  ------------------
  |  |  527|  5.33k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  943|  5.33k|            DROPBITS(4);
  ------------------
  |  |  531|  5.33k|    do { \
  |  |  532|  5.33k|        hold >>= (n); \
  |  |  533|  5.33k|        bits -= (unsigned)(n); \
  |  |  534|  5.33k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 5.33k]
  |  |  ------------------
  ------------------
  944|  5.33k|#ifndef PKZIP_BUG_WORKAROUND
  945|  5.33k|            if (state->nlen > 286 || state->ndist > 30) {
  ------------------
  |  Branch (945:17): [True: 0, False: 5.33k]
  |  Branch (945:38): [True: 0, False: 5.33k]
  ------------------
  946|      0|                strm->msg = (char *)"too many length or distance symbols";
  947|      0|                state->mode = BAD;
  948|      0|                break;
  949|      0|            }
  950|  5.33k|#endif
  951|  5.33k|            Tracev((stderr, "inflate:       table sizes ok\n"));
  952|  5.33k|            state->have = 0;
  953|  5.33k|            state->mode = LENLENS;
  954|       |                /* fallthrough */
  955|  5.33k|        case LENLENS:
  ------------------
  |  Branch (955:9): [True: 0, False: 711k]
  ------------------
  956|  95.9k|            while (state->have < state->ncode) {
  ------------------
  |  Branch (956:20): [True: 90.5k, False: 5.33k]
  ------------------
  957|  90.5k|                NEEDBITS(3);
  ------------------
  |  |  520|  90.5k|    do { \
  |  |  521|   122k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 31.6k, False: 90.5k]
  |  |  ------------------
  |  |  522|  90.5k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  31.6k|    do { \
  |  |  |  |  511|  31.6k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 31.6k]
  |  |  |  |  ------------------
  |  |  |  |  512|  31.6k|        have--; \
  |  |  |  |  513|  31.6k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  31.6k|        bits += 8; \
  |  |  |  |  515|  31.6k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 31.6k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  90.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 90.5k]
  |  |  ------------------
  ------------------
  958|  90.5k|                state->lens[order[state->have++]] = (unsigned short)BITS(3);
  ------------------
  |  |  527|  90.5k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  959|  90.5k|                DROPBITS(3);
  ------------------
  |  |  531|  90.5k|    do { \
  |  |  532|  90.5k|        hold >>= (n); \
  |  |  533|  90.5k|        bits -= (unsigned)(n); \
  |  |  534|  90.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 90.5k]
  |  |  ------------------
  ------------------
  960|  90.5k|            }
  961|  16.1k|            while (state->have < 19)
  ------------------
  |  Branch (961:20): [True: 10.8k, False: 5.33k]
  ------------------
  962|  10.8k|                state->lens[order[state->have++]] = 0;
  963|  5.33k|            state->next = state->codes;
  964|  5.33k|            state->lencode = (const code FAR *)(state->next);
  965|  5.33k|            state->lenbits = 7;
  966|  5.33k|            ret = inflate_table(CODES, state->lens, 19, &(state->next),
  967|  5.33k|                                &(state->lenbits), state->work);
  968|  5.33k|            if (ret) {
  ------------------
  |  Branch (968:17): [True: 11, False: 5.32k]
  ------------------
  969|     11|                strm->msg = (char *)"invalid code lengths set";
  970|     11|                state->mode = BAD;
  971|     11|                break;
  972|     11|            }
  973|  5.32k|            Tracev((stderr, "inflate:       code lengths ok\n"));
  974|  5.32k|            state->have = 0;
  975|  5.32k|            state->mode = CODELENS;
  976|       |                /* fallthrough */
  977|  5.32k|        case CODELENS:
  ------------------
  |  Branch (977:9): [True: 0, False: 711k]
  ------------------
  978|   934k|            while (state->have < state->nlen + state->ndist) {
  ------------------
  |  Branch (978:20): [True: 929k, False: 5.31k]
  ------------------
  979|  1.23M|                for (;;) {
  980|  1.23M|                    here = state->lencode[BITS(state->lenbits)];
  ------------------
  |  |  527|  1.23M|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  981|  1.23M|                    if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (981:25): [True: 929k, False: 302k]
  ------------------
  982|   302k|                    PULLBYTE();
  ------------------
  |  |  510|   302k|    do { \
  |  |  511|   302k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 302k]
  |  |  ------------------
  |  |  512|   302k|        have--; \
  |  |  513|   302k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|   302k|        bits += 8; \
  |  |  515|   302k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 302k]
  |  |  ------------------
  ------------------
  983|   302k|                }
  984|   929k|                if (here.val < 16) {
  ------------------
  |  Branch (984:21): [True: 801k, False: 127k]
  ------------------
  985|   801k|                    DROPBITS(here.bits);
  ------------------
  |  |  531|   801k|    do { \
  |  |  532|   801k|        hold >>= (n); \
  |  |  533|   801k|        bits -= (unsigned)(n); \
  |  |  534|   801k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 801k]
  |  |  ------------------
  ------------------
  986|   801k|                    state->lens[state->have++] = here.val;
  987|   801k|                }
  988|   127k|                else {
  989|   127k|                    if (here.val == 16) {
  ------------------
  |  Branch (989:25): [True: 100k, False: 26.9k]
  ------------------
  990|   100k|                        NEEDBITS(here.bits + 2);
  ------------------
  |  |  520|   100k|    do { \
  |  |  521|   126k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 25.4k, False: 100k]
  |  |  ------------------
  |  |  522|   100k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  25.4k|    do { \
  |  |  |  |  511|  25.4k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 25.4k]
  |  |  |  |  ------------------
  |  |  |  |  512|  25.4k|        have--; \
  |  |  |  |  513|  25.4k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  25.4k|        bits += 8; \
  |  |  |  |  515|  25.4k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 25.4k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|   100k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 100k]
  |  |  ------------------
  ------------------
  991|   100k|                        DROPBITS(here.bits);
  ------------------
  |  |  531|   100k|    do { \
  |  |  532|   100k|        hold >>= (n); \
  |  |  533|   100k|        bits -= (unsigned)(n); \
  |  |  534|   100k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 100k]
  |  |  ------------------
  ------------------
  992|   100k|                        if (state->have == 0) {
  ------------------
  |  Branch (992:29): [True: 2, False: 100k]
  ------------------
  993|      2|                            strm->msg = (char *)"invalid bit length repeat";
  994|      2|                            state->mode = BAD;
  995|      2|                            break;
  996|      2|                        }
  997|   100k|                        len = state->lens[state->have - 1];
  998|   100k|                        copy = 3 + BITS(2);
  ------------------
  |  |  527|   100k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  999|   100k|                        DROPBITS(2);
  ------------------
  |  |  531|   100k|    do { \
  |  |  532|   100k|        hold >>= (n); \
  |  |  533|   100k|        bits -= (unsigned)(n); \
  |  |  534|   100k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 100k]
  |  |  ------------------
  ------------------
 1000|   100k|                    }
 1001|  26.9k|                    else if (here.val == 17) {
  ------------------
  |  Branch (1001:30): [True: 20.9k, False: 5.92k]
  ------------------
 1002|  20.9k|                        NEEDBITS(here.bits + 3);
  ------------------
  |  |  520|  20.9k|    do { \
  |  |  521|  27.4k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 6.44k, False: 20.9k]
  |  |  ------------------
  |  |  522|  20.9k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  6.44k|    do { \
  |  |  |  |  511|  6.44k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 6.44k]
  |  |  |  |  ------------------
  |  |  |  |  512|  6.44k|        have--; \
  |  |  |  |  513|  6.44k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  6.44k|        bits += 8; \
  |  |  |  |  515|  6.44k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 6.44k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  20.9k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 20.9k]
  |  |  ------------------
  ------------------
 1003|  20.9k|                        DROPBITS(here.bits);
  ------------------
  |  |  531|  20.9k|    do { \
  |  |  532|  20.9k|        hold >>= (n); \
  |  |  533|  20.9k|        bits -= (unsigned)(n); \
  |  |  534|  20.9k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 20.9k]
  |  |  ------------------
  ------------------
 1004|  20.9k|                        len = 0;
 1005|  20.9k|                        copy = 3 + BITS(3);
  ------------------
  |  |  527|  20.9k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1006|  20.9k|                        DROPBITS(3);
  ------------------
  |  |  531|  20.9k|    do { \
  |  |  532|  20.9k|        hold >>= (n); \
  |  |  533|  20.9k|        bits -= (unsigned)(n); \
  |  |  534|  20.9k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 20.9k]
  |  |  ------------------
  ------------------
 1007|  20.9k|                    }
 1008|  5.92k|                    else {
 1009|  5.92k|                        NEEDBITS(here.bits + 7);
  ------------------
  |  |  520|  5.92k|    do { \
  |  |  521|  11.0k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 5.15k, False: 5.92k]
  |  |  ------------------
  |  |  522|  5.92k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  5.15k|    do { \
  |  |  |  |  511|  5.15k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 5.15k]
  |  |  |  |  ------------------
  |  |  |  |  512|  5.15k|        have--; \
  |  |  |  |  513|  5.15k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  5.15k|        bits += 8; \
  |  |  |  |  515|  5.15k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 5.15k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  5.92k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 5.92k]
  |  |  ------------------
  ------------------
 1010|  5.92k|                        DROPBITS(here.bits);
  ------------------
  |  |  531|  5.92k|    do { \
  |  |  532|  5.92k|        hold >>= (n); \
  |  |  533|  5.92k|        bits -= (unsigned)(n); \
  |  |  534|  5.92k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 5.92k]
  |  |  ------------------
  ------------------
 1011|  5.92k|                        len = 0;
 1012|  5.92k|                        copy = 11 + BITS(7);
  ------------------
  |  |  527|  5.92k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1013|  5.92k|                        DROPBITS(7);
  ------------------
  |  |  531|  5.92k|    do { \
  |  |  532|  5.92k|        hold >>= (n); \
  |  |  533|  5.92k|        bits -= (unsigned)(n); \
  |  |  534|  5.92k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 5.92k]
  |  |  ------------------
  ------------------
 1014|  5.92k|                    }
 1015|   127k|                    if (state->have + copy > state->nlen + state->ndist) {
  ------------------
  |  Branch (1015:25): [True: 13, False: 127k]
  ------------------
 1016|     13|                        strm->msg = (char *)"invalid bit length repeat";
 1017|     13|                        state->mode = BAD;
 1018|     13|                        break;
 1019|     13|                    }
 1020|   843k|                    while (copy--)
  ------------------
  |  Branch (1020:28): [True: 715k, False: 127k]
  ------------------
 1021|   715k|                        state->lens[state->have++] = (unsigned short)len;
 1022|   127k|                }
 1023|   929k|            }
 1024|       |
 1025|       |            /* handle error breaks in while */
 1026|  5.32k|            if (state->mode == BAD) break;
  ------------------
  |  Branch (1026:17): [True: 15, False: 5.31k]
  ------------------
 1027|       |
 1028|       |            /* check for end-of-block code (better have one) */
 1029|  5.31k|            if (state->lens[256] == 0) {
  ------------------
  |  Branch (1029:17): [True: 16, False: 5.29k]
  ------------------
 1030|     16|                strm->msg = (char *)"invalid code -- missing end-of-block";
 1031|     16|                state->mode = BAD;
 1032|     16|                break;
 1033|     16|            }
 1034|       |
 1035|       |            /* build code tables -- note: do not change the lenbits or distbits
 1036|       |               values here (9 and 6) without reading the comments in inftrees.h
 1037|       |               concerning the ENOUGH constants, which depend on those values */
 1038|  5.29k|            state->next = state->codes;
 1039|  5.29k|            state->lencode = (const code FAR *)(state->next);
 1040|  5.29k|            state->lenbits = 9;
 1041|  5.29k|            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
 1042|  5.29k|                                &(state->lenbits), state->work);
 1043|  5.29k|            if (ret) {
  ------------------
  |  Branch (1043:17): [True: 125, False: 5.17k]
  ------------------
 1044|    125|                strm->msg = (char *)"invalid literal/lengths set";
 1045|    125|                state->mode = BAD;
 1046|    125|                break;
 1047|    125|            }
 1048|  5.17k|            state->distcode = (const code FAR *)(state->next);
 1049|  5.17k|            state->distbits = 6;
 1050|  5.17k|            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
 1051|  5.17k|                            &(state->next), &(state->distbits), state->work);
 1052|  5.17k|            if (ret) {
  ------------------
  |  Branch (1052:17): [True: 15, False: 5.15k]
  ------------------
 1053|     15|                strm->msg = (char *)"invalid distances set";
 1054|     15|                state->mode = BAD;
 1055|     15|                break;
 1056|     15|            }
 1057|  5.15k|            Tracev((stderr, "inflate:       codes ok\n"));
 1058|  5.15k|            state->mode = LEN_;
 1059|  5.15k|            if (flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  174|  5.15k|#define Z_TREES         6
  ------------------
  |  Branch (1059:17): [True: 0, False: 5.15k]
  ------------------
 1060|       |                /* fallthrough */
 1061|  5.36k|        case LEN_:
  ------------------
  |  Branch (1061:9): [True: 205, False: 711k]
  ------------------
 1062|  5.36k|            state->mode = LEN;
 1063|       |                /* fallthrough */
 1064|   464k|        case LEN:
  ------------------
  |  Branch (1064:9): [True: 459k, False: 252k]
  ------------------
 1065|   464k|            if (have >= 6 && left >= 258) {
  ------------------
  |  Branch (1065:17): [True: 458k, False: 5.62k]
  |  Branch (1065:30): [True: 5.16k, False: 453k]
  ------------------
 1066|  5.16k|                RESTORE();
  ------------------
  |  |  491|  5.16k|    do { \
  |  |  492|  5.16k|        strm->next_out = put; \
  |  |  493|  5.16k|        strm->avail_out = left; \
  |  |  494|  5.16k|        strm->next_in = next; \
  |  |  495|  5.16k|        strm->avail_in = have; \
  |  |  496|  5.16k|        state->hold = hold; \
  |  |  497|  5.16k|        state->bits = bits; \
  |  |  498|  5.16k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 5.16k]
  |  |  ------------------
  ------------------
 1067|  5.16k|                inflate_fast(strm, out);
 1068|  5.16k|                LOAD();
  ------------------
  |  |  480|  5.16k|    do { \
  |  |  481|  5.16k|        put = strm->next_out; \
  |  |  482|  5.16k|        left = strm->avail_out; \
  |  |  483|  5.16k|        next = strm->next_in; \
  |  |  484|  5.16k|        have = strm->avail_in; \
  |  |  485|  5.16k|        hold = state->hold; \
  |  |  486|  5.16k|        bits = state->bits; \
  |  |  487|  5.16k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (487:14): [Folded, False: 5.16k]
  |  |  ------------------
  ------------------
 1069|  5.16k|                if (state->mode == TYPE)
  ------------------
  |  Branch (1069:21): [True: 23, False: 5.14k]
  ------------------
 1070|     23|                    state->back = -1;
 1071|  5.16k|                break;
 1072|  5.16k|            }
 1073|   459k|            state->back = 0;
 1074|   751k|            for (;;) {
 1075|   751k|                here = state->lencode[BITS(state->lenbits)];
  ------------------
  |  |  527|   751k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1076|   751k|                if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (1076:21): [True: 459k, False: 292k]
  ------------------
 1077|   292k|                PULLBYTE();
  ------------------
  |  |  510|   292k|    do { \
  |  |  511|   292k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 5, False: 292k]
  |  |  ------------------
  |  |  512|   292k|        have--; \
  |  |  513|   292k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|   292k|        bits += 8; \
  |  |  515|   292k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 292k]
  |  |  ------------------
  ------------------
 1078|   292k|            }
 1079|   459k|            if (here.op && (here.op & 0xf0) == 0) {
  ------------------
  |  Branch (1079:17): [True: 257k, False: 201k]
  |  Branch (1079:28): [True: 25.6k, False: 231k]
  ------------------
 1080|  25.6k|                last = here;
 1081|  28.3k|                for (;;) {
 1082|  28.3k|                    here = state->lencode[last.val +
 1083|  28.3k|                            (BITS(last.bits + last.op) >> last.bits)];
  ------------------
  |  |  527|  28.3k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1084|  28.3k|                    if ((unsigned)(last.bits + here.bits) <= bits) break;
  ------------------
  |  Branch (1084:25): [True: 25.6k, False: 2.73k]
  ------------------
 1085|  2.73k|                    PULLBYTE();
  ------------------
  |  |  510|  2.73k|    do { \
  |  |  511|  2.73k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 2.73k]
  |  |  ------------------
  |  |  512|  2.73k|        have--; \
  |  |  513|  2.73k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|  2.73k|        bits += 8; \
  |  |  515|  2.73k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 2.73k]
  |  |  ------------------
  ------------------
 1086|  2.73k|                }
 1087|  25.6k|                DROPBITS(last.bits);
  ------------------
  |  |  531|  25.6k|    do { \
  |  |  532|  25.6k|        hold >>= (n); \
  |  |  533|  25.6k|        bits -= (unsigned)(n); \
  |  |  534|  25.6k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 25.6k]
  |  |  ------------------
  ------------------
 1088|  25.6k|                state->back += last.bits;
 1089|  25.6k|            }
 1090|   459k|            DROPBITS(here.bits);
  ------------------
  |  |  531|   459k|    do { \
  |  |  532|   459k|        hold >>= (n); \
  |  |  533|   459k|        bits -= (unsigned)(n); \
  |  |  534|   459k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 459k]
  |  |  ------------------
  ------------------
 1091|   459k|            state->back += here.bits;
 1092|   459k|            state->length = (unsigned)here.val;
 1093|   459k|            if ((int)(here.op) == 0) {
  ------------------
  |  Branch (1093:17): [True: 224k, False: 234k]
  ------------------
 1094|   224k|                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
 1095|   224k|                        "inflate:         literal '%c'\n" :
 1096|   224k|                        "inflate:         literal 0x%02x\n", here.val));
 1097|   224k|                state->mode = LIT;
 1098|   224k|                break;
 1099|   224k|            }
 1100|   234k|            if (here.op & 32) {
  ------------------
  |  Branch (1100:17): [True: 4.59k, False: 229k]
  ------------------
 1101|  4.59k|                Tracevv((stderr, "inflate:         end of block\n"));
 1102|  4.59k|                state->back = -1;
 1103|  4.59k|                state->mode = TYPE;
 1104|  4.59k|                break;
 1105|  4.59k|            }
 1106|   229k|            if (here.op & 64) {
  ------------------
  |  Branch (1106:17): [True: 0, False: 229k]
  ------------------
 1107|      0|                strm->msg = (char *)"invalid literal/length code";
 1108|      0|                state->mode = BAD;
 1109|      0|                break;
 1110|      0|            }
 1111|   229k|            state->extra = (unsigned)(here.op) & 15;
 1112|   229k|            state->mode = LENEXT;
 1113|       |                /* fallthrough */
 1114|   229k|        case LENEXT:
  ------------------
  |  Branch (1114:9): [True: 0, False: 711k]
  ------------------
 1115|   229k|            if (state->extra) {
  ------------------
  |  Branch (1115:17): [True: 7.94k, False: 221k]
  ------------------
 1116|  7.94k|                NEEDBITS(state->extra);
  ------------------
  |  |  520|  7.94k|    do { \
  |  |  521|  9.18k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 1.24k, False: 7.94k]
  |  |  ------------------
  |  |  522|  7.94k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  1.24k|    do { \
  |  |  |  |  511|  1.24k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 1.24k]
  |  |  |  |  ------------------
  |  |  |  |  512|  1.24k|        have--; \
  |  |  |  |  513|  1.24k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  1.24k|        bits += 8; \
  |  |  |  |  515|  1.24k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 1.24k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  7.94k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 7.94k]
  |  |  ------------------
  ------------------
 1117|  7.94k|                state->length += BITS(state->extra);
  ------------------
  |  |  527|  7.94k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1118|  7.94k|                DROPBITS(state->extra);
  ------------------
  |  |  531|  7.94k|    do { \
  |  |  532|  7.94k|        hold >>= (n); \
  |  |  533|  7.94k|        bits -= (unsigned)(n); \
  |  |  534|  7.94k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 7.94k]
  |  |  ------------------
  ------------------
 1119|  7.94k|                state->back += state->extra;
 1120|  7.94k|            }
 1121|   229k|            Tracevv((stderr, "inflate:         length %u\n", state->length));
 1122|   229k|            state->was = state->length;
 1123|   229k|            state->mode = DIST;
 1124|       |                /* fallthrough */
 1125|   229k|        case DIST:
  ------------------
  |  Branch (1125:9): [True: 0, False: 711k]
  ------------------
 1126|   282k|            for (;;) {
 1127|   282k|                here = state->distcode[BITS(state->distbits)];
  ------------------
  |  |  527|   282k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1128|   282k|                if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (1128:21): [True: 229k, False: 52.5k]
  ------------------
 1129|  52.5k|                PULLBYTE();
  ------------------
  |  |  510|  52.5k|    do { \
  |  |  511|  52.5k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 1, False: 52.5k]
  |  |  ------------------
  |  |  512|  52.5k|        have--; \
  |  |  513|  52.5k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|  52.5k|        bits += 8; \
  |  |  515|  52.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 52.5k]
  |  |  ------------------
  ------------------
 1130|  52.5k|            }
 1131|   229k|            if ((here.op & 0xf0) == 0) {
  ------------------
  |  Branch (1131:17): [True: 589, False: 229k]
  ------------------
 1132|    589|                last = here;
 1133|    662|                for (;;) {
 1134|    662|                    here = state->distcode[last.val +
 1135|    662|                            (BITS(last.bits + last.op) >> last.bits)];
  ------------------
  |  |  527|    662|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1136|    662|                    if ((unsigned)(last.bits + here.bits) <= bits) break;
  ------------------
  |  Branch (1136:25): [True: 589, False: 73]
  ------------------
 1137|     73|                    PULLBYTE();
  ------------------
  |  |  510|     73|    do { \
  |  |  511|     73|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 73]
  |  |  ------------------
  |  |  512|     73|        have--; \
  |  |  513|     73|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|     73|        bits += 8; \
  |  |  515|     73|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 73]
  |  |  ------------------
  ------------------
 1138|     73|                }
 1139|    589|                DROPBITS(last.bits);
  ------------------
  |  |  531|    589|    do { \
  |  |  532|    589|        hold >>= (n); \
  |  |  533|    589|        bits -= (unsigned)(n); \
  |  |  534|    589|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 589]
  |  |  ------------------
  ------------------
 1140|    589|                state->back += last.bits;
 1141|    589|            }
 1142|   229k|            DROPBITS(here.bits);
  ------------------
  |  |  531|   229k|    do { \
  |  |  532|   229k|        hold >>= (n); \
  |  |  533|   229k|        bits -= (unsigned)(n); \
  |  |  534|   229k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 229k]
  |  |  ------------------
  ------------------
 1143|   229k|            state->back += here.bits;
 1144|   229k|            if (here.op & 64) {
  ------------------
  |  Branch (1144:17): [True: 0, False: 229k]
  ------------------
 1145|      0|                strm->msg = (char *)"invalid distance code";
 1146|      0|                state->mode = BAD;
 1147|      0|                break;
 1148|      0|            }
 1149|   229k|            state->offset = (unsigned)here.val;
 1150|   229k|            state->extra = (unsigned)(here.op) & 15;
 1151|   229k|            state->mode = DISTEXT;
 1152|       |                /* fallthrough */
 1153|   229k|        case DISTEXT:
  ------------------
  |  Branch (1153:9): [True: 0, False: 711k]
  ------------------
 1154|   229k|            if (state->extra) {
  ------------------
  |  Branch (1154:17): [True: 67.7k, False: 162k]
  ------------------
 1155|  67.7k|                NEEDBITS(state->extra);
  ------------------
  |  |  520|  67.7k|    do { \
  |  |  521|   118k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 50.6k, False: 67.7k]
  |  |  ------------------
  |  |  522|  67.7k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  50.6k|    do { \
  |  |  |  |  511|  50.6k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 3, False: 50.6k]
  |  |  |  |  ------------------
  |  |  |  |  512|  50.6k|        have--; \
  |  |  |  |  513|  50.6k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  50.6k|        bits += 8; \
  |  |  |  |  515|  50.6k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 50.6k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  67.7k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 67.7k]
  |  |  ------------------
  ------------------
 1156|  67.7k|                state->offset += BITS(state->extra);
  ------------------
  |  |  527|  67.7k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1157|  67.7k|                DROPBITS(state->extra);
  ------------------
  |  |  531|  67.7k|    do { \
  |  |  532|  67.7k|        hold >>= (n); \
  |  |  533|  67.7k|        bits -= (unsigned)(n); \
  |  |  534|  67.7k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 67.7k]
  |  |  ------------------
  ------------------
 1158|  67.7k|                state->back += state->extra;
 1159|  67.7k|            }
 1160|       |#ifdef INFLATE_STRICT
 1161|       |            if (state->offset > state->dmax) {
 1162|       |                strm->msg = (char *)"invalid distance too far back";
 1163|       |                state->mode = BAD;
 1164|       |                break;
 1165|       |            }
 1166|       |#endif
 1167|   229k|            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
 1168|   229k|            state->mode = MATCH;
 1169|       |                /* fallthrough */
 1170|   230k|        case MATCH:
  ------------------
  |  Branch (1170:9): [True: 168, False: 711k]
  ------------------
 1171|   230k|            if (left == 0) goto inf_leave;
  ------------------
  |  Branch (1171:17): [True: 208, False: 229k]
  ------------------
 1172|   229k|            copy = out - left;
 1173|   229k|            if (state->offset > copy) {         /* copy from window */
  ------------------
  |  Branch (1173:17): [True: 24, False: 229k]
  ------------------
 1174|     24|                copy = state->offset - copy;
 1175|     24|                if (copy > state->whave) {
  ------------------
  |  Branch (1175:21): [True: 24, False: 0]
  ------------------
 1176|     24|                    if (state->sane) {
  ------------------
  |  Branch (1176:25): [True: 24, False: 0]
  ------------------
 1177|     24|                        strm->msg = (char *)"invalid distance too far back";
 1178|     24|                        state->mode = BAD;
 1179|     24|                        break;
 1180|     24|                    }
 1181|       |#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
 1182|       |                    Trace((stderr, "inflate.c too far\n"));
 1183|       |                    copy -= state->whave;
 1184|       |                    if (copy > state->length) copy = state->length;
 1185|       |                    if (copy > left) copy = left;
 1186|       |                    left -= copy;
 1187|       |                    state->length -= copy;
 1188|       |                    do {
 1189|       |                        *put++ = 0;
 1190|       |                    } while (--copy);
 1191|       |                    if (state->length == 0) state->mode = LEN;
 1192|       |                    break;
 1193|       |#endif
 1194|     24|                }
 1195|      0|                if (copy > state->wnext) {
  ------------------
  |  Branch (1195:21): [True: 0, False: 0]
  ------------------
 1196|      0|                    copy -= state->wnext;
 1197|      0|                    from = state->window + (state->wsize - copy);
 1198|      0|                }
 1199|      0|                else
 1200|      0|                    from = state->window + (state->wnext - copy);
 1201|      0|                if (copy > state->length) copy = state->length;
  ------------------
  |  Branch (1201:21): [True: 0, False: 0]
  ------------------
 1202|      0|            }
 1203|   229k|            else {                              /* copy from output */
 1204|   229k|                from = put - state->offset;
 1205|   229k|                copy = state->length;
 1206|   229k|            }
 1207|   229k|            if (copy > left) copy = left;
  ------------------
  |  Branch (1207:17): [True: 168, False: 229k]
  ------------------
 1208|   229k|            left -= copy;
 1209|   229k|            state->length -= copy;
 1210|   994k|            do {
 1211|   994k|                *put++ = *from++;
 1212|   994k|            } while (--copy);
  ------------------
  |  Branch (1212:22): [True: 764k, False: 229k]
  ------------------
 1213|   229k|            if (state->length == 0) state->mode = LEN;
  ------------------
  |  Branch (1213:17): [True: 229k, False: 168]
  ------------------
 1214|   229k|            break;
 1215|   224k|        case LIT:
  ------------------
  |  Branch (1215:9): [True: 224k, False: 486k]
  ------------------
 1216|   224k|            if (left == 0) goto inf_leave;
  ------------------
  |  Branch (1216:17): [True: 106, False: 224k]
  ------------------
 1217|   224k|            *put++ = (unsigned char)(state->length);
 1218|   224k|            left--;
 1219|   224k|            state->mode = LEN;
 1220|   224k|            break;
 1221|  4.61k|        case CHECK:
  ------------------
  |  Branch (1221:9): [True: 4.61k, False: 706k]
  ------------------
 1222|  4.61k|            if (state->wrap) {
  ------------------
  |  Branch (1222:17): [True: 4.61k, False: 0]
  ------------------
 1223|  4.61k|                NEEDBITS(32);
  ------------------
  |  |  520|  4.61k|    do { \
  |  |  521|  23.0k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 18.4k, False: 4.61k]
  |  |  ------------------
  |  |  522|  18.4k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  18.4k|    do { \
  |  |  |  |  511|  18.4k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 18.4k]
  |  |  |  |  ------------------
  |  |  |  |  512|  18.4k|        have--; \
  |  |  |  |  513|  18.4k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  18.4k|        bits += 8; \
  |  |  |  |  515|  18.4k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 18.4k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  4.61k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 4.61k]
  |  |  ------------------
  ------------------
 1224|  4.61k|                out -= left;
 1225|  4.61k|                strm->total_out += out;
 1226|  4.61k|                state->total += out;
 1227|  4.61k|                if ((state->wrap & 4) && out)
  ------------------
  |  Branch (1227:21): [True: 4.61k, False: 0]
  |  Branch (1227:42): [True: 4.61k, False: 0]
  ------------------
 1228|  4.61k|                    strm->adler = state->check =
 1229|  4.61k|                        UPDATE_CHECK(state->check, put - out, out);
  ------------------
  |  |  454|  4.61k|    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
  |  |  ------------------
  |  |  |  Branch (454:6): [True: 0, False: 4.61k]
  |  |  ------------------
  ------------------
 1230|  4.61k|                out = left;
 1231|  4.61k|                if ((state->wrap & 4) && (
  ------------------
  |  Branch (1231:21): [True: 4.61k, False: 0]
  |  Branch (1231:42): [True: 682, False: 3.93k]
  ------------------
 1232|  4.61k|#ifdef GUNZIP
 1233|  4.61k|                     state->flags ? hold :
  ------------------
  |  Branch (1233:22): [True: 0, False: 4.61k]
  ------------------
 1234|  4.61k|#endif
 1235|  4.61k|                     ZSWAP32(hold)) != state->check) {
  ------------------
  |  |  272|  4.61k|#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
  |  |  273|  4.61k|                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
  ------------------
 1236|    682|                    strm->msg = (char *)"incorrect data check";
 1237|    682|                    state->mode = BAD;
 1238|    682|                    break;
 1239|    682|                }
 1240|  3.93k|                INITBITS();
  ------------------
  |  |  502|  3.93k|    do { \
  |  |  503|  3.93k|        hold = 0; \
  |  |  504|  3.93k|        bits = 0; \
  |  |  505|  3.93k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 3.93k]
  |  |  ------------------
  ------------------
 1241|  3.93k|                Tracev((stderr, "inflate:   check matches trailer\n"));
 1242|  3.93k|            }
 1243|  3.93k|#ifdef GUNZIP
 1244|  3.93k|            state->mode = LENGTH;
 1245|       |                /* fallthrough */
 1246|  3.93k|        case LENGTH:
  ------------------
  |  Branch (1246:9): [True: 0, False: 711k]
  ------------------
 1247|  3.93k|            if (state->wrap && state->flags) {
  ------------------
  |  Branch (1247:17): [True: 3.93k, False: 0]
  |  Branch (1247:32): [True: 0, False: 3.93k]
  ------------------
 1248|      0|                NEEDBITS(32);
  ------------------
  |  |  520|      0|    do { \
  |  |  521|      0|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 0, False: 0]
  |  |  ------------------
  |  |  522|      0|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      0|    do { \
  |  |  |  |  511|      0|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 0]
  |  |  |  |  ------------------
  |  |  |  |  512|      0|        have--; \
  |  |  |  |  513|      0|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      0|        bits += 8; \
  |  |  |  |  515|      0|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 0]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
 1249|      0|                if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
  ------------------
  |  Branch (1249:21): [True: 0, False: 0]
  |  Branch (1249:42): [True: 0, False: 0]
  ------------------
 1250|      0|                    strm->msg = (char *)"incorrect length check";
 1251|      0|                    state->mode = BAD;
 1252|      0|                    break;
 1253|      0|                }
 1254|      0|                INITBITS();
  ------------------
  |  |  502|      0|    do { \
  |  |  503|      0|        hold = 0; \
  |  |  504|      0|        bits = 0; \
  |  |  505|      0|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 0]
  |  |  ------------------
  ------------------
 1255|      0|                Tracev((stderr, "inflate:   length matches trailer\n"));
 1256|      0|            }
 1257|  3.93k|#endif
 1258|  3.93k|            state->mode = DONE;
 1259|       |                /* fallthrough */
 1260|  3.93k|        case DONE:
  ------------------
  |  Branch (1260:9): [True: 0, False: 711k]
  ------------------
 1261|  3.93k|            ret = Z_STREAM_END;
  ------------------
  |  |  178|  3.93k|#define Z_STREAM_END    1
  ------------------
 1262|  3.93k|            goto inf_leave;
 1263|  1.29k|        case BAD:
  ------------------
  |  Branch (1263:9): [True: 1.29k, False: 710k]
  ------------------
 1264|  1.29k|            ret = Z_DATA_ERROR;
  ------------------
  |  |  182|  1.29k|#define Z_DATA_ERROR   (-3)
  ------------------
 1265|  1.29k|            goto inf_leave;
 1266|      0|        case MEM:
  ------------------
  |  Branch (1266:9): [True: 0, False: 711k]
  ------------------
 1267|      0|            return Z_MEM_ERROR;
  ------------------
  |  |  183|      0|#define Z_MEM_ERROR    (-4)
  ------------------
 1268|      0|        case SYNC:
  ------------------
  |  Branch (1268:9): [True: 0, False: 711k]
  ------------------
 1269|       |                /* fallthrough */
 1270|      0|        default:
  ------------------
  |  Branch (1270:9): [True: 0, False: 711k]
  ------------------
 1271|      0|            return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
 1272|   711k|        }
 1273|       |
 1274|       |    /*
 1275|       |       Return from inflate(), updating the total counts and the check value.
 1276|       |       If there was no progress during the inflate() call, return a buffer
 1277|       |       error.  Call updatewindow() to create and/or update the window state.
 1278|       |       Note: a memory error from inflate() is non-recoverable.
 1279|       |     */
 1280|  5.55k|  inf_leave:
 1281|  5.55k|    RESTORE();
  ------------------
  |  |  491|  5.55k|    do { \
  |  |  492|  5.55k|        strm->next_out = put; \
  |  |  493|  5.55k|        strm->avail_out = left; \
  |  |  494|  5.55k|        strm->next_in = next; \
  |  |  495|  5.55k|        strm->avail_in = have; \
  |  |  496|  5.55k|        state->hold = hold; \
  |  |  497|  5.55k|        state->bits = bits; \
  |  |  498|  5.55k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 5.55k]
  |  |  ------------------
  ------------------
 1282|  5.55k|    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
  ------------------
  |  Branch (1282:9): [True: 0, False: 5.55k]
  |  Branch (1282:26): [True: 745, False: 4.80k]
  |  Branch (1282:52): [True: 323, False: 422]
  ------------------
 1283|    323|            (state->mode < CHECK || flush != Z_FINISH)))
  ------------------
  |  |  172|      0|#define Z_FINISH        4
  ------------------
  |  Branch (1283:14): [True: 323, False: 0]
  |  Branch (1283:37): [True: 0, False: 0]
  ------------------
 1284|    323|        if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
  ------------------
  |  Branch (1284:13): [True: 0, False: 323]
  ------------------
 1285|      0|            state->mode = MEM;
 1286|      0|            return Z_MEM_ERROR;
  ------------------
  |  |  183|      0|#define Z_MEM_ERROR    (-4)
  ------------------
 1287|      0|        }
 1288|  5.55k|    in -= strm->avail_in;
 1289|  5.55k|    out -= strm->avail_out;
 1290|  5.55k|    strm->total_in += in;
 1291|  5.55k|    strm->total_out += out;
 1292|  5.55k|    state->total += out;
 1293|  5.55k|    if ((state->wrap & 4) && out)
  ------------------
  |  Branch (1293:9): [True: 5.55k, False: 0]
  |  Branch (1293:30): [True: 745, False: 4.80k]
  ------------------
 1294|    745|        strm->adler = state->check =
 1295|    745|            UPDATE_CHECK(state->check, strm->next_out - out, out);
  ------------------
  |  |  454|    745|    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
  |  |  ------------------
  |  |  |  Branch (454:6): [True: 0, False: 745]
  |  |  ------------------
  ------------------
 1296|  5.55k|    strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
  ------------------
  |  Branch (1296:43): [True: 5.54k, False: 11]
  ------------------
 1297|  5.55k|                      (state->mode == TYPE ? 128 : 0) +
  ------------------
  |  Branch (1297:24): [True: 0, False: 5.55k]
  ------------------
 1298|  5.55k|                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
  ------------------
  |  Branch (1298:24): [True: 0, False: 5.55k]
  |  Branch (1298:47): [True: 0, False: 5.55k]
  ------------------
 1299|  5.55k|    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
  ------------------
  |  |  172|  5.55k|#define Z_FINISH        4
  ------------------
                  if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
  ------------------
  |  |  177|  5.55k|#define Z_OK            0
  ------------------
  |  Branch (1299:11): [True: 0, False: 5.55k]
  |  Branch (1299:22): [True: 0, False: 0]
  |  Branch (1299:35): [True: 5.55k, False: 0]
  |  Branch (1299:57): [True: 323, False: 5.23k]
  ------------------
 1300|    323|        ret = Z_BUF_ERROR;
  ------------------
  |  |  184|    323|#define Z_BUF_ERROR    (-5)
  ------------------
 1301|  5.55k|    return ret;
 1302|  5.55k|}
inflateEnd:
 1306|  5.55k|{
 1307|  5.55k|    struct inflate_state FAR *state;
 1308|  5.55k|    if (inflateStateCheck(strm))
  ------------------
  |  Branch (1308:9): [True: 0, False: 5.55k]
  ------------------
 1309|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
 1310|  5.55k|    state = (struct inflate_state FAR *)strm->state;
 1311|  5.55k|    if (state->window != Z_NULL) ZFREE(strm, state->window);
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (state->window != Z_NULL) ZFREE(strm, state->window);
  ------------------
  |  |  268|    323|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
  |  Branch (1311:9): [True: 323, False: 5.23k]
  ------------------
 1312|  5.55k|    ZFREE(strm, strm->state);
  ------------------
  |  |  268|  5.55k|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
 1313|  5.55k|    strm->state = Z_NULL;
  ------------------
  |  |  212|  5.55k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
 1314|  5.55k|    Tracev((stderr, "inflate: end\n"));
 1315|  5.55k|    return Z_OK;
  ------------------
  |  |  177|  5.55k|#define Z_OK            0
  ------------------
 1316|  5.55k|}
inflate.c:inflateStateCheck:
  107|  27.7k|{
  108|  27.7k|    struct inflate_state FAR *state;
  109|  27.7k|    if (strm == Z_NULL ||
  ------------------
  |  |  212|  55.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (109:9): [True: 0, False: 27.7k]
  ------------------
  110|  27.7k|        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
  ------------------
  |  Branch (110:9): [True: 0, False: 27.7k]
  |  Branch (110:42): [True: 0, False: 27.7k]
  ------------------
  111|      0|        return 1;
  112|  27.7k|    state = (struct inflate_state FAR *)strm->state;
  113|  27.7k|    if (state == Z_NULL || state->strm != strm ||
  ------------------
  |  |  212|  55.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (113:9): [True: 0, False: 27.7k]
  |  Branch (113:28): [True: 0, False: 27.7k]
  ------------------
  114|  27.7k|        state->mode < HEAD || state->mode > SYNC)
  ------------------
  |  Branch (114:9): [True: 0, False: 27.7k]
  |  Branch (114:31): [True: 0, False: 27.7k]
  ------------------
  115|      0|        return 1;
  116|  27.7k|    return 0;
  117|  27.7k|}
inflate.c:fixedtables:
  283|    205|{
  284|       |#ifdef BUILDFIXED
  285|       |    static int virgin = 1;
  286|       |    static code *lenfix, *distfix;
  287|       |    static code fixed[544];
  288|       |
  289|       |    /* build fixed huffman tables if first call (may not be thread safe) */
  290|       |    if (virgin) {
  291|       |        unsigned sym, bits;
  292|       |        static code *next;
  293|       |
  294|       |        /* literal/length table */
  295|       |        sym = 0;
  296|       |        while (sym < 144) state->lens[sym++] = 8;
  297|       |        while (sym < 256) state->lens[sym++] = 9;
  298|       |        while (sym < 280) state->lens[sym++] = 7;
  299|       |        while (sym < 288) state->lens[sym++] = 8;
  300|       |        next = fixed;
  301|       |        lenfix = next;
  302|       |        bits = 9;
  303|       |        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
  304|       |
  305|       |        /* distance table */
  306|       |        sym = 0;
  307|       |        while (sym < 32) state->lens[sym++] = 5;
  308|       |        distfix = next;
  309|       |        bits = 5;
  310|       |        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
  311|       |
  312|       |        /* do this just once */
  313|       |        virgin = 0;
  314|       |    }
  315|       |#else /* !BUILDFIXED */
  316|    205|#   include "inffixed.h"
  ------------------
  |  |    1|       |    /* inffixed.h -- table for decoding fixed codes
  |  |    2|       |     * Generated automatically by makefixed().
  |  |    3|       |     */
  |  |    4|       |
  |  |    5|       |    /* WARNING: this file should *not* be used by applications.
  |  |    6|       |       It is part of the implementation of this library and is
  |  |    7|       |       subject to change. Applications should only use zlib.h.
  |  |    8|       |     */
  |  |    9|       |
  |  |   10|    205|    static const code lenfix[512] = {
  |  |   11|    205|        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
  |  |   12|    205|        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
  |  |   13|    205|        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
  |  |   14|    205|        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
  |  |   15|    205|        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
  |  |   16|    205|        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
  |  |   17|    205|        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
  |  |   18|    205|        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
  |  |   19|    205|        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
  |  |   20|    205|        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
  |  |   21|    205|        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
  |  |   22|    205|        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
  |  |   23|    205|        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
  |  |   24|    205|        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
  |  |   25|    205|        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
  |  |   26|    205|        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
  |  |   27|    205|        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
  |  |   28|    205|        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
  |  |   29|    205|        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
  |  |   30|    205|        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
  |  |   31|    205|        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
  |  |   32|    205|        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
  |  |   33|    205|        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
  |  |   34|    205|        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
  |  |   35|    205|        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
  |  |   36|    205|        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
  |  |   37|    205|        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
  |  |   38|    205|        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
  |  |   39|    205|        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
  |  |   40|    205|        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
  |  |   41|    205|        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
  |  |   42|    205|        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
  |  |   43|    205|        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
  |  |   44|    205|        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
  |  |   45|    205|        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
  |  |   46|    205|        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
  |  |   47|    205|        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
  |  |   48|    205|        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
  |  |   49|    205|        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
  |  |   50|    205|        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
  |  |   51|    205|        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
  |  |   52|    205|        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
  |  |   53|    205|        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
  |  |   54|    205|        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
  |  |   55|    205|        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
  |  |   56|    205|        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
  |  |   57|    205|        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
  |  |   58|    205|        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
  |  |   59|    205|        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
  |  |   60|    205|        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
  |  |   61|    205|        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
  |  |   62|    205|        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
  |  |   63|    205|        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
  |  |   64|    205|        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
  |  |   65|    205|        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
  |  |   66|    205|        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
  |  |   67|    205|        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
  |  |   68|    205|        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
  |  |   69|    205|        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
  |  |   70|    205|        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
  |  |   71|    205|        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
  |  |   72|    205|        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
  |  |   73|    205|        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
  |  |   74|    205|        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
  |  |   75|    205|        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
  |  |   76|    205|        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
  |  |   77|    205|        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
  |  |   78|    205|        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
  |  |   79|    205|        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
  |  |   80|    205|        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
  |  |   81|    205|        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
  |  |   82|    205|        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
  |  |   83|    205|        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
  |  |   84|    205|        {0,9,255}
  |  |   85|    205|    };
  |  |   86|       |
  |  |   87|    205|    static const code distfix[32] = {
  |  |   88|    205|        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
  |  |   89|    205|        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
  |  |   90|    205|        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
  |  |   91|    205|        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
  |  |   92|    205|        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
  |  |   93|    205|        {22,5,193},{64,5,0}
  |  |   94|    205|    };
  ------------------
  317|    205|#endif /* BUILDFIXED */
  318|    205|    state->lencode = lenfix;
  319|    205|    state->lenbits = 9;
  320|    205|    state->distcode = distfix;
  321|    205|    state->distbits = 5;
  322|    205|}
inflate.c:updatewindow:
  403|    323|{
  404|    323|    struct inflate_state FAR *state;
  405|    323|    unsigned dist;
  406|       |
  407|    323|    state = (struct inflate_state FAR *)strm->state;
  408|       |
  409|       |    /* if it hasn't been done already, allocate space for the window */
  410|    323|    if (state->window == Z_NULL) {
  ------------------
  |  |  212|    323|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (410:9): [True: 323, False: 0]
  ------------------
  411|    323|        state->window = (unsigned char FAR *)
  412|    323|                        ZALLOC(strm, 1U << state->wbits,
  ------------------
  |  |  267|    323|           (*((strm)->zalloc))((strm)->opaque, (items), (size))
  ------------------
  413|    323|                               sizeof(unsigned char));
  414|    323|        if (state->window == Z_NULL) return 1;
  ------------------
  |  |  212|    323|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (414:13): [True: 0, False: 323]
  ------------------
  415|    323|    }
  416|       |
  417|       |    /* if window not in use yet, initialize */
  418|    323|    if (state->wsize == 0) {
  ------------------
  |  Branch (418:9): [True: 323, False: 0]
  ------------------
  419|    323|        state->wsize = 1U << state->wbits;
  420|    323|        state->wnext = 0;
  421|    323|        state->whave = 0;
  422|    323|    }
  423|       |
  424|       |    /* copy state->wsize or less output bytes into the circular window */
  425|    323|    if (copy >= state->wsize) {
  ------------------
  |  Branch (425:9): [True: 3, False: 320]
  ------------------
  426|      3|        zmemcpy(state->window, end - state->wsize, state->wsize);
  ------------------
  |  |  230|      3|#    define zmemcpy memcpy
  ------------------
  427|      3|        state->wnext = 0;
  428|      3|        state->whave = state->wsize;
  429|      3|    }
  430|    320|    else {
  431|    320|        dist = state->wsize - state->wnext;
  432|    320|        if (dist > copy) dist = copy;
  ------------------
  |  Branch (432:13): [True: 320, False: 0]
  ------------------
  433|    320|        zmemcpy(state->window + state->wnext, end - copy, dist);
  ------------------
  |  |  230|    320|#    define zmemcpy memcpy
  ------------------
  434|    320|        copy -= dist;
  435|    320|        if (copy) {
  ------------------
  |  Branch (435:13): [True: 0, False: 320]
  ------------------
  436|      0|            zmemcpy(state->window, end - copy, copy);
  ------------------
  |  |  230|      0|#    define zmemcpy memcpy
  ------------------
  437|      0|            state->wnext = copy;
  438|      0|            state->whave = state->wsize;
  439|      0|        }
  440|    320|        else {
  441|    320|            state->wnext += dist;
  442|    320|            if (state->wnext == state->wsize) state->wnext = 0;
  ------------------
  |  Branch (442:17): [True: 0, False: 320]
  ------------------
  443|    320|            if (state->whave < state->wsize) state->whave += dist;
  ------------------
  |  Branch (443:17): [True: 320, False: 0]
  ------------------
  444|    320|        }
  445|    320|    }
  446|    323|    return 0;
  447|    323|}

inflate_table:
   39|  15.8k|{
   40|  15.8k|    unsigned len;               /* a code's length in bits */
   41|  15.8k|    unsigned sym;               /* index of code symbols */
   42|  15.8k|    unsigned min, max;          /* minimum and maximum code lengths */
   43|  15.8k|    unsigned root;              /* number of index bits for root table */
   44|  15.8k|    unsigned curr;              /* number of index bits for current table */
   45|  15.8k|    unsigned drop;              /* code bits to drop for sub-table */
   46|  15.8k|    int left;                   /* number of prefix codes available */
   47|  15.8k|    unsigned used;              /* code entries in table used */
   48|  15.8k|    unsigned huff;              /* Huffman code */
   49|  15.8k|    unsigned incr;              /* for incrementing code, index */
   50|  15.8k|    unsigned fill;              /* index for replicating entries */
   51|  15.8k|    unsigned low;               /* low bits for current root entry */
   52|  15.8k|    unsigned mask;              /* mask for low root bits */
   53|  15.8k|    code here;                  /* table entry for duplication */
   54|  15.8k|    code FAR *next;             /* next available space in table */
   55|  15.8k|    const unsigned short FAR *base;     /* base value table to use */
   56|  15.8k|    const unsigned short FAR *extra;    /* extra bits table to use */
   57|  15.8k|    unsigned match;             /* use base and extra for symbol >= match */
   58|  15.8k|    unsigned short count[MAXBITS+1];    /* number of codes of each length */
   59|  15.8k|    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
   60|  15.8k|    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
   61|  15.8k|        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
   62|  15.8k|        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
   63|  15.8k|    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
   64|  15.8k|        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
   65|  15.8k|        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65};
   66|  15.8k|    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
   67|  15.8k|        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
   68|  15.8k|        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
   69|  15.8k|        8193, 12289, 16385, 24577, 0, 0};
   70|  15.8k|    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
   71|  15.8k|        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
   72|  15.8k|        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
   73|  15.8k|        28, 28, 29, 29, 64, 64};
   74|       |
   75|       |    /*
   76|       |       Process a set of code lengths to create a canonical Huffman code.  The
   77|       |       code lengths are lens[0..codes-1].  Each length corresponds to the
   78|       |       symbols 0..codes-1.  The Huffman code is generated by first sorting the
   79|       |       symbols by length from short to long, and retaining the symbol order
   80|       |       for codes with equal lengths.  Then the code starts with all zero bits
   81|       |       for the first code of the shortest length, and the codes are integer
   82|       |       increments for the same length, and zeros are appended as the length
   83|       |       increases.  For the deflate format, these bits are stored backwards
   84|       |       from their more natural integer increment ordering, and so when the
   85|       |       decoding tables are built in the large loop below, the integer codes
   86|       |       are incremented backwards.
   87|       |
   88|       |       This routine assumes, but does not check, that all of the entries in
   89|       |       lens[] are in the range 0..MAXBITS.  The caller must assure this.
   90|       |       1..MAXBITS is interpreted as that code length.  zero means that that
   91|       |       symbol does not occur in this code.
   92|       |
   93|       |       The codes are sorted by computing a count of codes for each length,
   94|       |       creating from that a table of starting indices for each length in the
   95|       |       sorted table, and then entering the symbols in order in the sorted
   96|       |       table.  The sorted table is work[], with that space being provided by
   97|       |       the caller.
   98|       |
   99|       |       The length counts are used for other purposes as well, i.e. finding
  100|       |       the minimum and maximum length codes, determining if there are any
  101|       |       codes at all, checking for a valid set of lengths, and looking ahead
  102|       |       at length counts to determine sub-table sizes when building the
  103|       |       decoding tables.
  104|       |     */
  105|       |
  106|       |    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
  107|   268k|    for (len = 0; len <= MAXBITS; len++)
  ------------------
  |  |    9|   268k|#define MAXBITS 15
  ------------------
  |  Branch (107:19): [True: 252k, False: 15.8k]
  ------------------
  108|   252k|        count[len] = 0;
  109|  1.62M|    for (sym = 0; sym < codes; sym++)
  ------------------
  |  Branch (109:19): [True: 1.60M, False: 15.8k]
  ------------------
  110|  1.60M|        count[lens[sym]]++;
  111|       |
  112|       |    /* bound code lengths, force root to be within code lengths */
  113|  15.8k|    root = *bits;
  114|   143k|    for (max = MAXBITS; max >= 1; max--)
  ------------------
  |  |    9|  15.8k|#define MAXBITS 15
  ------------------
  |  Branch (114:25): [True: 143k, False: 0]
  ------------------
  115|   143k|        if (count[max] != 0) break;
  ------------------
  |  Branch (115:13): [True: 15.8k, False: 127k]
  ------------------
  116|  15.8k|    if (root > max) root = max;
  ------------------
  |  Branch (116:9): [True: 5.69k, False: 10.1k]
  ------------------
  117|  15.8k|    if (max == 0) {                     /* no symbols to code at all */
  ------------------
  |  Branch (117:9): [True: 0, False: 15.8k]
  ------------------
  118|      0|        here.op = (unsigned char)64;    /* invalid code marker */
  119|      0|        here.bits = (unsigned char)1;
  120|      0|        here.val = (unsigned short)0;
  121|      0|        *(*table)++ = here;             /* make a table to force an error */
  122|      0|        *(*table)++ = here;
  123|      0|        *bits = 1;
  124|      0|        return 0;     /* no symbols, but wait for decoding to report error */
  125|      0|    }
  126|  26.9k|    for (min = 1; min < max; min++)
  ------------------
  |  Branch (126:19): [True: 26.3k, False: 603]
  ------------------
  127|  26.3k|        if (count[min] != 0) break;
  ------------------
  |  Branch (127:13): [True: 15.2k, False: 11.1k]
  ------------------
  128|  15.8k|    if (root < min) root = min;
  ------------------
  |  Branch (128:9): [True: 0, False: 15.8k]
  ------------------
  129|       |
  130|       |    /* check for an over-subscribed or incomplete set of lengths */
  131|  15.8k|    left = 1;
  132|   251k|    for (len = 1; len <= MAXBITS; len++) {
  ------------------
  |  |    9|   251k|#define MAXBITS 15
  ------------------
  |  Branch (132:19): [True: 236k, False: 15.6k]
  ------------------
  133|   236k|        left <<= 1;
  134|   236k|        left -= count[len];
  135|   236k|        if (left < 0) return -1;        /* over-subscribed */
  ------------------
  |  Branch (135:13): [True: 108, False: 236k]
  ------------------
  136|   236k|    }
  137|  15.6k|    if (left > 0 && (type == CODES || max != 1))
  ------------------
  |  Branch (137:9): [True: 44, False: 15.6k]
  |  Branch (137:22): [True: 5, False: 39]
  |  Branch (137:39): [True: 38, False: 1]
  ------------------
  138|     43|        return -1;                      /* incomplete set */
  139|       |
  140|       |    /* generate offsets into symbol table for each length for sorting */
  141|  15.6k|    offs[1] = 0;
  142|   234k|    for (len = 1; len < MAXBITS; len++)
  ------------------
  |  |    9|   234k|#define MAXBITS 15
  ------------------
  |  Branch (142:19): [True: 219k, False: 15.6k]
  ------------------
  143|   219k|        offs[len + 1] = offs[len] + count[len];
  144|       |
  145|       |    /* sort symbols by length, by symbol order within each length */
  146|  1.58M|    for (sym = 0; sym < codes; sym++)
  ------------------
  |  Branch (146:19): [True: 1.57M, False: 15.6k]
  ------------------
  147|  1.57M|        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
  ------------------
  |  Branch (147:13): [True: 1.22M, False: 353k]
  ------------------
  148|       |
  149|       |    /*
  150|       |       Create and fill in decoding tables.  In this loop, the table being
  151|       |       filled is at next and has curr index bits.  The code being used is huff
  152|       |       with length len.  That code is converted to an index by dropping drop
  153|       |       bits off of the bottom.  For codes where len is less than drop + curr,
  154|       |       those top drop + curr - len bits are incremented through all values to
  155|       |       fill the table with replicated entries.
  156|       |
  157|       |       root is the number of index bits for the root table.  When len exceeds
  158|       |       root, sub-tables are created pointed to by the root entry with an index
  159|       |       of the low root bits of huff.  This is saved in low to check for when a
  160|       |       new sub-table should be started.  drop is zero when the root table is
  161|       |       being filled, and drop is root when sub-tables are being filled.
  162|       |
  163|       |       When a new sub-table is needed, it is necessary to look ahead in the
  164|       |       code lengths to determine what size sub-table is needed.  The length
  165|       |       counts are used for this, and so count[] is decremented as codes are
  166|       |       entered in the tables.
  167|       |
  168|       |       used keeps track of how many table entries have been allocated from the
  169|       |       provided *table space.  It is checked for LENS and DIST tables against
  170|       |       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
  171|       |       the initial root table size constants.  See the comments in inftrees.h
  172|       |       for more information.
  173|       |
  174|       |       sym increments through all symbols, and the loop terminates when
  175|       |       all codes of length max, i.e. all codes, have been processed.  This
  176|       |       routine permits incomplete codes, so another loop after this one fills
  177|       |       in the rest of the decoding tables with invalid code markers.
  178|       |     */
  179|       |
  180|       |    /* set up for code type */
  181|  15.6k|    switch (type) {
  182|  5.32k|    case CODES:
  ------------------
  |  Branch (182:5): [True: 5.32k, False: 10.3k]
  ------------------
  183|  5.32k|        base = extra = work;    /* dummy value--not used */
  184|  5.32k|        match = 20;
  185|  5.32k|        break;
  186|  5.17k|    case LENS:
  ------------------
  |  Branch (186:5): [True: 5.17k, False: 10.4k]
  ------------------
  187|  5.17k|        base = lbase;
  188|  5.17k|        extra = lext;
  189|  5.17k|        match = 257;
  190|  5.17k|        break;
  191|  5.15k|    default:    /* DISTS */
  ------------------
  |  Branch (191:5): [True: 5.15k, False: 10.4k]
  ------------------
  192|  5.15k|        base = dbase;
  193|  5.15k|        extra = dext;
  194|  5.15k|        match = 0;
  195|  15.6k|    }
  196|       |
  197|       |    /* initialize state for loop */
  198|  15.6k|    huff = 0;                   /* starting code */
  199|  15.6k|    sym = 0;                    /* starting code symbol */
  200|  15.6k|    len = min;                  /* starting code length */
  201|  15.6k|    next = *table;              /* current table to fill in */
  202|  15.6k|    curr = root;                /* current table index bits */
  203|  15.6k|    drop = 0;                   /* current bits to drop from code for index */
  204|  15.6k|    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
  205|  15.6k|    used = 1U << root;          /* use root table entries */
  206|  15.6k|    mask = used - 1;            /* mask for comparing low */
  207|       |
  208|       |    /* check available table space */
  209|  15.6k|    if ((type == LENS && used > ENOUGH_LENS) ||
  ------------------
  |  |   49|  5.17k|#define ENOUGH_LENS 852
  ------------------
  |  Branch (209:10): [True: 5.17k, False: 10.4k]
  |  Branch (209:26): [True: 0, False: 5.17k]
  ------------------
  210|  15.6k|        (type == DISTS && used > ENOUGH_DISTS))
  ------------------
  |  |   50|  5.15k|#define ENOUGH_DISTS 592
  ------------------
  |  Branch (210:10): [True: 5.15k, False: 10.4k]
  |  Branch (210:27): [True: 0, False: 5.15k]
  ------------------
  211|      0|        return 1;
  212|       |
  213|       |    /* process all codes and make table entries */
  214|  1.22M|    for (;;) {
  215|       |        /* create table entry */
  216|  1.22M|        here.bits = (unsigned char)(len - drop);
  217|  1.22M|        if (work[sym] + 1U < match) {
  ------------------
  |  Branch (217:13): [True: 1.13M, False: 87.8k]
  ------------------
  218|  1.13M|            here.op = (unsigned char)0;
  219|  1.13M|            here.val = work[sym];
  220|  1.13M|        }
  221|  87.8k|        else if (work[sym] >= match) {
  ------------------
  |  Branch (221:18): [True: 82.6k, False: 5.17k]
  ------------------
  222|  82.6k|            here.op = (unsigned char)(extra[work[sym] - match]);
  223|  82.6k|            here.val = base[work[sym] - match];
  224|  82.6k|        }
  225|  5.17k|        else {
  226|  5.17k|            here.op = (unsigned char)(32 + 64);         /* end of block */
  227|  5.17k|            here.val = 0;
  228|  5.17k|        }
  229|       |
  230|       |        /* replicate for those indices with low len bits equal to huff */
  231|  1.22M|        incr = 1U << (len - drop);
  232|  1.22M|        fill = 1U << curr;
  233|  1.22M|        min = fill;                 /* save offset to next table */
  234|  3.37M|        do {
  235|  3.37M|            fill -= incr;
  236|  3.37M|            next[(huff >> drop) + fill] = here;
  237|  3.37M|        } while (fill != 0);
  ------------------
  |  Branch (237:18): [True: 2.15M, False: 1.22M]
  ------------------
  238|       |
  239|       |        /* backwards increment the len-bit code huff */
  240|  1.22M|        incr = 1U << (len - 1);
  241|  2.42M|        while (huff & incr)
  ------------------
  |  Branch (241:16): [True: 1.20M, False: 1.22M]
  ------------------
  242|  1.20M|            incr >>= 1;
  243|  1.22M|        if (incr != 0) {
  ------------------
  |  Branch (243:13): [True: 1.20M, False: 15.6k]
  ------------------
  244|  1.20M|            huff &= incr - 1;
  245|  1.20M|            huff += incr;
  246|  1.20M|        }
  247|  15.6k|        else
  248|  15.6k|            huff = 0;
  249|       |
  250|       |        /* go to next symbol, update count, len */
  251|  1.22M|        sym++;
  252|  1.22M|        if (--(count[len]) == 0) {
  ------------------
  |  Branch (252:13): [True: 76.4k, False: 1.14M]
  ------------------
  253|  76.4k|            if (len == max) break;
  ------------------
  |  Branch (253:17): [True: 15.6k, False: 60.8k]
  ------------------
  254|  60.8k|            len = lens[work[sym]];
  255|  60.8k|        }
  256|       |
  257|       |        /* create new sub-table if needed */
  258|  1.20M|        if (len > root && (huff & mask) != low) {
  ------------------
  |  Branch (258:13): [True: 282k, False: 921k]
  |  Branch (258:27): [True: 130k, False: 152k]
  ------------------
  259|       |            /* if first time, transition to sub-tables */
  260|   130k|            if (drop == 0)
  ------------------
  |  Branch (260:17): [True: 5.55k, False: 124k]
  ------------------
  261|  5.55k|                drop = root;
  262|       |
  263|       |            /* increment past last table */
  264|   130k|            next += min;            /* here min is 1 << curr */
  265|       |
  266|       |            /* determine length of next table */
  267|   130k|            curr = len - drop;
  268|   130k|            left = (int)(1 << curr);
  269|   131k|            while (curr + drop < max) {
  ------------------
  |  Branch (269:20): [True: 27.3k, False: 104k]
  ------------------
  270|  27.3k|                left -= count[curr + drop];
  271|  27.3k|                if (left <= 0) break;
  ------------------
  |  Branch (271:21): [True: 25.5k, False: 1.77k]
  ------------------
  272|  1.77k|                curr++;
  273|  1.77k|                left <<= 1;
  274|  1.77k|            }
  275|       |
  276|       |            /* check for enough space */
  277|   130k|            used += 1U << curr;
  278|   130k|            if ((type == LENS && used > ENOUGH_LENS) ||
  ------------------
  |  |   49|   127k|#define ENOUGH_LENS 852
  ------------------
  |  Branch (278:18): [True: 127k, False: 2.23k]
  |  Branch (278:34): [True: 0, False: 127k]
  ------------------
  279|   130k|                (type == DISTS && used > ENOUGH_DISTS))
  ------------------
  |  |   50|  2.23k|#define ENOUGH_DISTS 592
  ------------------
  |  Branch (279:18): [True: 2.23k, False: 127k]
  |  Branch (279:35): [True: 0, False: 2.23k]
  ------------------
  280|      0|                return 1;
  281|       |
  282|       |            /* point entry in root table to sub-table */
  283|   130k|            low = huff & mask;
  284|   130k|            (*table)[low].op = (unsigned char)curr;
  285|   130k|            (*table)[low].bits = (unsigned char)root;
  286|   130k|            (*table)[low].val = (unsigned short)(next - *table);
  287|   130k|        }
  288|  1.20M|    }
  289|       |
  290|       |    /* fill in remaining table entry if code is incomplete (guaranteed to have
  291|       |       at most one remaining entry, since if the code is incomplete, the
  292|       |       maximum code length that was allowed to get this far is one bit) */
  293|  15.6k|    if (huff != 0) {
  ------------------
  |  Branch (293:9): [True: 1, False: 15.6k]
  ------------------
  294|      1|        here.op = (unsigned char)64;            /* invalid code marker */
  295|      1|        here.bits = (unsigned char)(len - drop);
  296|      1|        here.val = (unsigned short)0;
  297|      1|        next[huff] = here;
  298|      1|    }
  299|       |
  300|       |    /* set return parameters */
  301|  15.6k|    *table += used;
  302|  15.6k|    *bits = root;
  303|  15.6k|    return 0;
  304|  15.6k|}

zcalloc:
  310|  5.87k|{
  311|  5.87k|    (void)opaque;
  312|  5.87k|    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
  ------------------
  |  Branch (312:12): [True: 5.87k, Folded]
  ------------------
  313|  5.87k|                              (voidpf)calloc(items, size);
  314|  5.87k|}
zcfree:
  319|  5.87k|{
  320|  5.87k|    (void)opaque;
  321|  5.87k|    free(ptr);
  322|  5.87k|}

LLVMFuzzerTestOneInput:
   48|    297|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize) {
   49|    297|    if (dataSize > 1024 * 1024) {
  ------------------
  |  Branch (49:9): [True: 0, False: 297]
  ------------------
   50|      0|        return 0;
   51|      0|    }
   52|       |
   53|    297|    Importer importer;
   54|       |    // Force FBX format
   55|    297|    if (!AssimpFuzz::ForceFormat(importer, "fbx")) {
  ------------------
  |  Branch (55:9): [True: 0, False: 297]
  ------------------
   56|      0|        return 0;
   57|      0|    }
   58|       |
   59|    297|    unsigned int flags = aiProcessPreset_TargetRealtime_Quality | aiProcess_ValidateDataStructure;
   60|    297|    const aiScene *sc = importer.ReadFileFromMemory(data, dataSize, flags, "fbx");
   61|       |
   62|    297|    return 0;
   63|    297|}

_ZN10AssimpFuzz11ForceFormatERN6Assimp8ImporterEPKc:
   53|    297|inline bool ForceFormat(Assimp::Importer& importer, const char* targetExtension) {
   54|    297|    size_t count = importer.GetImporterCount();
   55|    297|    std::vector<Assimp::BaseImporter*> toRemove;
   56|    297|    bool found = false;
   57|       |
   58|  14.5k|    for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (58:24): [True: 14.2k, False: 297]
  ------------------
   59|  14.2k|        const aiImporterDesc* desc = importer.GetImporterInfo(i);
   60|  14.2k|        Assimp::BaseImporter* imp = importer.GetImporter(i);
   61|       |        
   62|  14.2k|        if (!desc || !imp) continue;
  ------------------
  |  Branch (62:13): [True: 0, False: 14.2k]
  |  Branch (62:22): [True: 0, False: 14.2k]
  ------------------
   63|       |
   64|       |        // Check if the importer supports the target extension
   65|       |        // mFileExtensions is a space-separated list (e.g., "obj mod")
   66|       |        // We wrap target in spaces or check bounds to be precise, 
   67|       |        // but for fuzzing, a simple strstr is usually sufficient 
   68|       |        // if the target string is unique enough (e.g. "gltf", "obj").
   69|       |        // A more robust check:
   70|       |        
   71|  14.2k|        bool isTarget = false;
   72|  14.2k|        const char* extList = desc->mFileExtensions;
   73|  14.2k|        if (!extList) {
  ------------------
  |  Branch (73:13): [True: 0, False: 14.2k]
  ------------------
   74|      0|            toRemove.push_back(imp);
   75|      0|            continue;
   76|      0|        }
   77|  14.2k|        const size_t targetLen = strlen(targetExtension);
   78|       |
   79|  14.2k|        const char* p = extList;
   80|  14.2k|        while ((p = strstr(p, targetExtension)) != nullptr) {
  ------------------
  |  Branch (80:16): [True: 297, False: 13.9k]
  ------------------
   81|       |            // Check boundaries
   82|    297|            const char prev = (p == extList) ? ' ' : *(p - 1);
  ------------------
  |  Branch (82:31): [True: 297, False: 0]
  ------------------
   83|    297|            const char next = *(p + targetLen);
   84|       |            
   85|    297|            if (prev == ' ' && (next == ' ' || next == '\0')) {
  ------------------
  |  Branch (85:17): [True: 297, False: 0]
  |  Branch (85:33): [True: 0, False: 297]
  |  Branch (85:48): [True: 297, False: 0]
  ------------------
   86|    297|                isTarget = true;
   87|    297|                break;
   88|    297|            }
   89|      0|            p++;
   90|      0|        }
   91|       |
   92|  14.2k|        if (isTarget) {
  ------------------
  |  Branch (92:13): [True: 297, False: 13.9k]
  ------------------
   93|    297|            found = true;
   94|  13.9k|        } else {
   95|  13.9k|            toRemove.push_back(imp);
   96|  13.9k|        }
   97|  14.2k|    }
   98|       |
   99|  13.9k|    for (auto* imp : toRemove) {
  ------------------
  |  Branch (99:20): [True: 13.9k, False: 297]
  ------------------
  100|  13.9k|        importer.UnregisterLoader(imp);
  101|  13.9k|        delete imp;  // Free the unregistered importer to prevent memory leaks
  102|  13.9k|    }
  103|       |
  104|    297|    return found;
  105|    297|}

_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEEC2Ev:
  256|    594|        mDoc(nullptr),
  257|    594|        mData() {
  258|       |    // empty
  259|    594|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEE5clearEv:
  267|    594|inline void TXmlParser<TNodeType>::clear() {
  268|    594|    if (mData.empty()) {
  ------------------
  |  Branch (268:9): [True: 594, False: 0]
  ------------------
  269|    594|        if (mDoc) {
  ------------------
  |  Branch (269:13): [True: 0, False: 594]
  ------------------
  270|      0|            delete mDoc;
  271|      0|        }
  272|    594|        mDoc = nullptr;
  273|    594|        return;
  274|    594|    }
  275|       |
  276|      0|    mData.clear();
  277|      0|    delete mDoc;
  278|      0|    mDoc = nullptr;
  279|      0|}
_ZN6Assimp10TXmlParserIN4pugi8xml_nodeEED2Ev:
  262|    594|inline TXmlParser<TNodeType>::~TXmlParser() {
  263|    594|    clear();
  264|    594|}

