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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp3FBX14AnimationCurveC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentE:
   61|  26.6k|        Object(id, element, name) {
   62|  26.6k|    const Scope &sc = GetRequiredScope(element);
   63|  26.6k|    const Element &KeyTime = GetRequiredElement(sc, "KeyTime");
   64|  26.6k|    const Element &KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat");
   65|       |
   66|  26.6k|    ParseVectorDataArray(keys, KeyTime);
   67|  26.6k|    ParseVectorDataArray(values, KeyValueFloat);
   68|       |
   69|  26.6k|    if (keys.size() != values.size()) {
  ------------------
  |  Branch (69:9): [True: 0, False: 26.6k]
  ------------------
   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|  26.6k|    if (!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
  ------------------
  |  Branch (74:9): [True: 172, False: 26.4k]
  ------------------
   75|    172|        DOMError("the keyframes are not in ascending order", &KeyTime);
   76|    172|    }
   77|       |
   78|  26.4k|    const Element *KeyAttrDataFloat = sc["KeyAttrDataFloat"];
   79|  26.4k|    if (KeyAttrDataFloat) {
  ------------------
  |  Branch (79:9): [True: 26.2k, False: 237]
  ------------------
   80|  26.2k|        ParseVectorDataArray(attributes, *KeyAttrDataFloat);
   81|  26.2k|    }
   82|       |
   83|  26.4k|    const Element *KeyAttrFlags = sc["KeyAttrFlags"];
   84|  26.4k|    if (KeyAttrFlags) {
  ------------------
  |  Branch (84:9): [True: 26.2k, False: 247]
  ------------------
   85|  26.2k|        ParseVectorDataArray(flags, *KeyAttrFlags);
   86|  26.2k|    }
   87|  26.4k|}
_ZN6Assimp3FBX18AnimationCurveNodeC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentEPKPKcm:
   93|  10.0k|        Object(id, element, name), target(), doc(doc) {
   94|  10.0k|    const Scope &sc = GetRequiredScope(element);
   95|       |
   96|       |    // find target node
   97|  10.0k|    const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
   98|  10.0k|    const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
   99|       |
  100|  10.0k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (100:32): [True: 9.49k, False: 548]
  ------------------
  101|       |
  102|       |        // link should go for a property
  103|  9.49k|        if (!con->PropertyName().length()) {
  ------------------
  |  Branch (103:13): [True: 12, False: 9.47k]
  ------------------
  104|     12|            continue;
  105|     12|        }
  106|       |
  107|  9.47k|        if (target_prop_whitelist) {
  ------------------
  |  Branch (107:13): [True: 0, False: 9.47k]
  ------------------
  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|  9.47k|        const Object *const ob = con->DestinationObject();
  123|  9.47k|        if (!ob) {
  ------------------
  |  Branch (123:13): [True: 15, False: 9.46k]
  ------------------
  124|     15|            DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", &element);
  125|     15|            continue;
  126|     15|        }
  127|       |
  128|  9.46k|        target = ob;
  129|  9.46k|        if (!target) {
  ------------------
  |  Branch (129:13): [True: 0, False: 9.46k]
  ------------------
  130|      0|            continue;
  131|      0|        }
  132|       |
  133|  9.46k|        prop = con->PropertyName();
  134|  9.46k|        break;
  135|  9.46k|    }
  136|       |
  137|  10.0k|    if (!target) {
  ------------------
  |  Branch (137:9): [True: 548, False: 9.46k]
  ------------------
  138|    548|        DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode", &element);
  139|    548|    }
  140|       |
  141|  10.0k|    props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
  142|  10.0k|}
_ZNK6Assimp3FBX18AnimationCurveNode6CurvesEv:
  145|  26.7k|const AnimationCurveMap &AnimationCurveNode::Curves() const {
  146|  26.7k|    if (!curves.empty()) {
  ------------------
  |  Branch (146:9): [True: 17.6k, False: 9.03k]
  ------------------
  147|  17.6k|        return curves;
  148|  17.6k|    }
  149|       |
  150|       |    // resolve attached animation curves
  151|  9.03k|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
  152|       |
  153|  26.6k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (153:32): [True: 26.6k, False: 9.03k]
  ------------------
  154|       |
  155|       |        // link should go for a property
  156|  26.6k|        if (!con->PropertyName().length()) {
  ------------------
  |  Branch (156:13): [True: 6, False: 26.6k]
  ------------------
  157|      6|            continue;
  158|      6|        }
  159|       |
  160|  26.6k|        const Object *const ob = con->SourceObject();
  161|  26.6k|        if (nullptr == ob) {
  ------------------
  |  Branch (161:13): [True: 358, False: 26.2k]
  ------------------
  162|    358|            DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring", &element);
  163|    358|            continue;
  164|    358|        }
  165|       |
  166|  26.2k|        const AnimationCurve *const anim = dynamic_cast<const AnimationCurve *>(ob);
  167|  26.2k|        if (nullptr == anim) {
  ------------------
  |  Branch (167:13): [True: 0, False: 26.2k]
  ------------------
  168|      0|            DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element);
  169|      0|            continue;
  170|      0|        }
  171|       |
  172|  26.2k|        curves[con->PropertyName()] = anim;
  173|  26.2k|    }
  174|       |
  175|  9.03k|    return curves;
  176|  26.7k|}
_ZN6Assimp3FBX14AnimationLayerC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentE:
  180|    231|        Object(id, element, name), doc(doc) {
  181|    231|    const Scope &sc = GetRequiredScope(element);
  182|       |
  183|       |    // note: the props table here bears little importance and is usually absent
  184|    231|    props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
  185|    231|}
_ZNK6Assimp3FBX14AnimationLayer5NodesEPKPKcm:
  189|    231|        size_t whitelist_size /*= 0*/) const {
  190|    231|    AnimationCurveNodeList nodes;
  191|       |
  192|       |    // resolve attached animation nodes
  193|    231|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode");
  194|    231|    nodes.reserve(conns.size());
  195|       |
  196|  10.0k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (196:32): [True: 10.0k, False: 231]
  ------------------
  197|       |
  198|       |        // link should not go to a property
  199|  10.0k|        if (con->PropertyName().length()) {
  ------------------
  |  Branch (199:13): [True: 0, False: 10.0k]
  ------------------
  200|      0|            continue;
  201|      0|        }
  202|       |
  203|  10.0k|        const Object *const ob = con->SourceObject();
  204|  10.0k|        if (!ob) {
  ------------------
  |  Branch (204:13): [True: 0, False: 10.0k]
  ------------------
  205|      0|            DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", &element);
  206|      0|            continue;
  207|      0|        }
  208|       |
  209|  10.0k|        const AnimationCurveNode *const anim = dynamic_cast<const AnimationCurveNode *>(ob);
  210|  10.0k|        if (!anim) {
  ------------------
  |  Branch (210:13): [True: 0, False: 10.0k]
  ------------------
  211|      0|            DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", &element);
  212|      0|            continue;
  213|      0|        }
  214|       |
  215|  10.0k|        if (target_prop_whitelist) {
  ------------------
  |  Branch (215:13): [True: 10.0k, False: 4]
  ------------------
  216|  10.0k|            const char *s = anim->TargetProperty().c_str();
  217|  10.0k|            bool ok = false;
  218|  22.3k|            for (size_t i = 0; i < whitelist_size; ++i) {
  ------------------
  |  Branch (218:32): [True: 21.5k, False: 805]
  ------------------
  219|  21.5k|                if (!strcmp(s, target_prop_whitelist[i])) {
  ------------------
  |  Branch (219:21): [True: 9.20k, False: 12.3k]
  ------------------
  220|  9.20k|                    ok = true;
  221|  9.20k|                    break;
  222|  9.20k|                }
  223|  21.5k|            }
  224|  10.0k|            if (!ok) {
  ------------------
  |  Branch (224:17): [True: 805, False: 9.20k]
  ------------------
  225|    805|                continue;
  226|    805|            }
  227|  10.0k|        }
  228|  9.21k|        nodes.push_back(anim);
  229|  9.21k|    }
  230|       |
  231|    231|    return nodes; // pray for NRVO
  232|    231|}
_ZN6Assimp3FBX14AnimationStackC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERKNS0_8DocumentE:
  236|    247|        Object(id, element, name) {
  237|    247|    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|    247|    props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
  241|       |
  242|       |    // resolve attached animation layers
  243|    247|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
  244|    247|    layers.reserve(conns.size());
  245|       |
  246|    247|    for (const Connection *con : conns) {
  ------------------
  |  Branch (246:32): [True: 231, False: 247]
  ------------------
  247|       |
  248|       |        // link should not go to a property
  249|    231|        if (con->PropertyName().length()) {
  ------------------
  |  Branch (249:13): [True: 0, False: 231]
  ------------------
  250|      0|            continue;
  251|      0|        }
  252|       |
  253|    231|        const Object *const ob = con->SourceObject();
  254|    231|        if (!ob) {
  ------------------
  |  Branch (254:13): [True: 0, False: 231]
  ------------------
  255|      0|            DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", &element);
  256|      0|            continue;
  257|      0|        }
  258|       |
  259|    231|        const AnimationLayer *const anim = dynamic_cast<const AnimationLayer *>(ob);
  260|    231|        if (!anim) {
  ------------------
  |  Branch (260:13): [True: 0, False: 231]
  ------------------
  261|      0|            DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", &element);
  262|      0|            continue;
  263|      0|        }
  264|    231|        layers.push_back(anim);
  265|    231|    }
  266|    247|}

_ZN6Assimp3FBX5TokenC2EPKcS3_NS0_9TokenTypeEm:
   67|  3.67M|        sbegin(sbegin),
   68|  3.67M|        send(send),
   69|  3.67M|        type(type),
   70|  3.67M|        line(offset),
   71|  3.67M|        column(BINARY_MARKER) {
   72|  3.67M|    ai_assert(sbegin);
  ------------------
  |  |   67|  3.67M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 3.67M, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   73|  3.67M|    ai_assert(send);
  ------------------
  |  |   67|  3.67M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 3.67M, 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.67M|    ai_assert(send >= sbegin);
  ------------------
  |  |   67|  3.67M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 3.67M, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   78|  3.67M|}
_ZN6Assimp3FBX14TokenizeBinaryERNSt3__16vectorIPKNS0_5TokenENS1_9allocatorIS5_EEEEPKcmRNS_14StackAllocatorE:
  394|    325|void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, StackAllocator &token_allocator) {
  395|    325|	ai_assert(input);
  ------------------
  |  |   67|    325|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 325, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  396|    325|	ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
  397|       |
  398|    325|    if(length < 0x1b) {
  ------------------
  |  Branch (398:8): [True: 0, False: 325]
  ------------------
  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|    325|    if (strncmp(input,"Kaydara FBX Binary",18)) {
  ------------------
  |  Branch (410:9): [True: 0, False: 325]
  ------------------
  411|      0|        TokenizeError("magic bytes not found",0);
  412|      0|    }
  413|       |
  414|    325|    const char* cursor = input + 18;
  415|    325|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  416|    325|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  417|    325|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  418|    325|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  419|    325|	/*Result ignored*/ ReadByte(input, cursor, input + length);
  420|    325|	const uint32_t version = ReadWord(input, cursor, input + length);
  421|    325|	ASSIMP_LOG_DEBUG("FBX version: ", version);
  422|    325|	const bool is64bits = version >= 7500;
  423|    325|    const char *end = input + length;
  424|    325|    try
  425|    325|    {
  426|  3.83k|        while (cursor < end ) {
  ------------------
  |  Branch (426:16): [True: 3.81k, False: 16]
  ------------------
  427|  3.81k|            if (!ReadScope(output_tokens, token_allocator, input, cursor, input + length, is64bits)) {
  ------------------
  |  Branch (427:17): [True: 309, False: 3.50k]
  ------------------
  428|    309|                break;
  429|    309|            }
  430|  3.81k|        }
  431|    325|    }
  432|    325|    catch (const DeadlyImportError& e)
  433|    325|    {
  434|     16|        if (!is64bits && (length > std::numeric_limits<uint32_t>::max())) {
  ------------------
  |  Branch (434:13): [True: 15, False: 1]
  |  Branch (434:26): [True: 0, False: 15]
  ------------------
  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|     16|        throw;
  438|     16|    }
  439|    325|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_113TokenizeErrorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEm:
   87|     16|{
   88|     16|    throw DeadlyImportError("FBX-Tokenize", Util::GetOffsetText(offset), message);
   89|     16|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_18ReadByteEPKcRS3_S3_:
  140|   711k|uint8_t ReadByte(const char* input, const char*& cursor, const char* end) {
  141|   711k|    if(Offset(cursor, end) < sizeof( uint8_t ) ) {
  ------------------
  |  Branch (141:8): [True: 0, False: 711k]
  ------------------
  142|      0|        TokenizeError("cannot ReadByte, out of bounds",input, cursor);
  143|      0|    }
  144|       |
  145|   711k|    uint8_t word;/* = *reinterpret_cast< const uint8_t* >( cursor )*/
  146|   711k|    ::memcpy( &word, cursor, sizeof( uint8_t ) );
  147|   711k|    ++cursor;
  148|       |
  149|   711k|    return word;
  150|   711k|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_16OffsetEPKcS3_:
   93|  17.5M|size_t Offset(const char* begin, const char* cursor) {
   94|  17.5M|    if (begin > cursor) {
  ------------------
  |  Branch (94:9): [True: 0, False: 17.5M]
  ------------------
   95|      0|		return 0;
   96|      0|	}
   97|       |
   98|  17.5M|    return cursor - begin;
   99|  17.5M|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_113TokenizeErrorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKcSC_:
  103|     16|void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
  104|     16|    TokenizeError(message, Offset(begin, cursor));
  105|     16|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_18ReadWordEPKcRS3_S3_:
  108|  3.65M|uint32_t ReadWord(const char* input, const char*& cursor, const char* end) {
  109|  3.65M|    const size_t k_to_read = sizeof( uint32_t );
  110|  3.65M|    if(Offset(cursor, end) < k_to_read ) {
  ------------------
  |  Branch (110:8): [True: 0, False: 3.65M]
  ------------------
  111|      0|        TokenizeError("cannot ReadWord, out of bounds",input, cursor);
  112|      0|    }
  113|       |
  114|  3.65M|    uint32_t word;
  115|  3.65M|    ::memcpy(&word, cursor, 4);
  116|  3.65M|    AI_SWAP4(word);
  117|       |
  118|  3.65M|    cursor += k_to_read;
  119|       |
  120|  3.65M|    return word;
  121|  3.65M|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_19ReadScopeERNSt3__16vectorIPKNS0_5TokenENS2_9allocatorIS6_EEEERNS_14StackAllocatorEPKcRSE_SE_b:
  305|   710k|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|   710k|	const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
  ------------------
  |  Branch (307:30): [True: 1, False: 710k]
  ------------------
  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|   710k|    if(!end_offset) {
  ------------------
  |  Branch (313:8): [True: 309, False: 709k]
  ------------------
  314|    309|        return false;
  315|    309|    }
  316|       |
  317|   709k|    if(end_offset > Offset(input, end)) {
  ------------------
  |  Branch (317:8): [True: 4, False: 709k]
  ------------------
  318|      4|        TokenizeError("block offset is out of range",input, cursor);
  319|      4|    }
  320|   709k|    else if(end_offset < Offset(input, cursor)) {
  ------------------
  |  Branch (320:13): [True: 0, False: 709k]
  ------------------
  321|      0|        TokenizeError("block offset is negative out of range",input, cursor);
  322|      0|    }
  323|       |
  324|       |    // the second data word contains the number of properties in the scope
  325|   709k|	const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
  ------------------
  |  Branch (325:30): [True: 0, False: 709k]
  ------------------
  326|       |
  327|       |    // the third data word contains the length of the property list
  328|   709k|	const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
  ------------------
  |  Branch (328:31): [True: 0, False: 709k]
  ------------------
  329|       |
  330|       |    // now comes the name of the scope/key
  331|   709k|    const char* sbeg, *send;
  332|   709k|    ReadString(sbeg, send, input, cursor, end);
  333|       |
  334|   709k|    output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) ));
  ------------------
  |  |  160|  1.41M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  335|       |
  336|       |    // now come the individual properties
  337|   709k|    const char* begin_cursor = cursor;
  338|       |
  339|   709k|    if ((begin_cursor + prop_length) > end) {
  ------------------
  |  Branch (339:9): [True: 0, False: 709k]
  ------------------
  340|      0|        TokenizeError("property length out of bounds reading length ", input, cursor);
  341|      0|    }
  342|       |
  343|  2.41M|    for (unsigned int i = 0; i < prop_count; ++i) {
  ------------------
  |  Branch (343:30): [True: 1.70M, False: 709k]
  ------------------
  344|  1.70M|        ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
  345|       |
  346|  1.70M|        output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) ));
  ------------------
  |  |  160|  3.41M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  347|       |
  348|  1.70M|        if(i != prop_count-1) {
  ------------------
  |  Branch (348:12): [True: 1.03M, False: 669k]
  ------------------
  349|  1.03M|            output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) ));
  ------------------
  |  |  160|  2.07M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  350|  1.03M|        }
  351|  1.70M|    }
  352|       |
  353|   709k|    if (Offset(begin_cursor, cursor) != prop_length) {
  ------------------
  |  Branch (353:9): [True: 1, False: 709k]
  ------------------
  354|      1|        TokenizeError("property length not reached, something is wrong",input, cursor);
  355|      1|    }
  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|   709k|	const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1);
  ------------------
  |  Branch (360:39): [True: 0, False: 709k]
  ------------------
  361|       |
  362|   709k|    if (Offset(input, cursor) < end_offset) {
  ------------------
  |  Branch (362:9): [True: 113k, False: 596k]
  ------------------
  363|   113k|        if (end_offset - Offset(input, cursor) < sentinel_block_length) {
  ------------------
  |  Branch (363:13): [True: 0, False: 113k]
  ------------------
  364|      0|            TokenizeError("insufficient padding bytes at block end",input, cursor);
  365|      0|        }
  366|       |
  367|   113k|        output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) ));
  ------------------
  |  |  160|   227k|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  368|       |
  369|       |        // XXX this is vulnerable to stack overflowing ..
  370|   819k|        while(Offset(input, cursor) < end_offset - sentinel_block_length) {
  ------------------
  |  Branch (370:15): [True: 706k, False: 113k]
  ------------------
  371|   706k|            ReadScope(output_tokens, token_allocator, input, cursor, input + end_offset - sentinel_block_length, is64bits);
  372|   706k|        }
  373|   113k|        output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) ));
  ------------------
  |  |  160|   227k|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  374|       |
  375|  1.59M|        for (unsigned int i = 0; i < sentinel_block_length; ++i) {
  ------------------
  |  Branch (375:34): [True: 1.47M, False: 113k]
  ------------------
  376|  1.47M|            if(cursor[i] != '\0') {
  ------------------
  |  Branch (376:16): [True: 2, False: 1.47M]
  ------------------
  377|      2|                TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor);
  378|      2|            }
  379|  1.47M|        }
  380|   113k|        cursor += sentinel_block_length;
  381|   113k|    }
  382|       |
  383|   709k|    if (Offset(input, cursor) != end_offset) {
  ------------------
  |  Branch (383:9): [True: 0, False: 709k]
  ------------------
  384|      0|        TokenizeError("scope length not reached, something is wrong",input, cursor);
  385|      0|    }
  386|       |
  387|   709k|    return true;
  388|   709k|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_114ReadDoubleWordEPKcRS3_S3_:
  124|      1|uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) {
  125|      1|    const size_t k_to_read = sizeof(uint64_t);
  126|      1|    if(Offset(cursor, end) < k_to_read) {
  ------------------
  |  Branch (126:8): [True: 0, False: 1]
  ------------------
  127|      0|        TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor);
  128|      0|    }
  129|       |
  130|      1|    uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
  131|      1|    ::memcpy( &dword, cursor, sizeof( uint64_t ) );
  132|      1|    AI_SWAP8(dword);
  133|       |
  134|      1|    cursor += k_to_read;
  135|       |
  136|      1|    return dword;
  137|      1|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_110ReadStringERPKcS4_S3_S4_S3_bb:
  154|  1.65M|        const char*& cursor, const char* end, bool long_length = false, bool allow_null = false) {
  155|  1.65M|    const uint32_t len_len = long_length ? 4 : 1;
  ------------------
  |  Branch (155:30): [True: 945k, False: 709k]
  ------------------
  156|  1.65M|    if(Offset(cursor, end) < len_len) {
  ------------------
  |  Branch (156:8): [True: 0, False: 1.65M]
  ------------------
  157|      0|        TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
  158|      0|    }
  159|       |
  160|  1.65M|    const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end);
  ------------------
  |  Branch (160:29): [True: 945k, False: 709k]
  ------------------
  161|       |
  162|  1.65M|    if (Offset(cursor, end) < length) {
  ------------------
  |  Branch (162:9): [True: 1, False: 1.65M]
  ------------------
  163|      1|        TokenizeError("cannot ReadString, length is out of bounds",input, cursor);
  164|      1|    }
  165|       |
  166|  1.65M|    sbegin_out = cursor;
  167|  1.65M|    cursor += length;
  168|       |
  169|  1.65M|    send_out = cursor;
  170|       |
  171|  1.65M|    if(!allow_null) {
  ------------------
  |  Branch (171:8): [True: 709k, False: 945k]
  ------------------
  172|  6.04M|        for (unsigned int i = 0; i < length; ++i) {
  ------------------
  |  Branch (172:34): [True: 5.33M, False: 709k]
  ------------------
  173|  5.33M|            if(sbegin_out[i] == '\0') {
  ------------------
  |  Branch (173:16): [True: 3, False: 5.33M]
  ------------------
  174|      3|                TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor);
  175|      3|            }
  176|  5.33M|        }
  177|   709k|    }
  178|       |
  179|  1.65M|    return length;
  180|  1.65M|}
FBXBinaryTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_18ReadDataERPKcS4_S3_S4_S3_:
  183|  1.70M|void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) {
  184|  1.70M|    if(Offset(cursor, end) < 1) {
  ------------------
  |  Branch (184:8): [True: 1, False: 1.70M]
  ------------------
  185|      1|        TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
  186|      1|    }
  187|       |
  188|  1.70M|    const char type = *cursor;
  189|  1.70M|    sbegin_out = cursor++;
  190|       |
  191|  1.70M|    switch(type)
  192|  1.70M|    {
  193|       |        // 16 bit int
  194|      0|    case 'Y':
  ------------------
  |  Branch (194:5): [True: 0, False: 1.70M]
  ------------------
  195|      0|        cursor += 2;
  196|      0|        break;
  197|       |
  198|       |        // 1 bit bool flag (yes/no)
  199|  6.37k|    case 'C':
  ------------------
  |  Branch (199:5): [True: 6.37k, False: 1.69M]
  ------------------
  200|  6.37k|        cursor += 1;
  201|  6.37k|        break;
  202|       |
  203|       |        // 32 bit int
  204|   136k|    case 'I':
  ------------------
  |  Branch (204:5): [True: 136k, False: 1.56M]
  ------------------
  205|       |        // <- fall through
  206|       |
  207|       |        // float
  208|   136k|    case 'F':
  ------------------
  |  Branch (208:5): [True: 0, False: 1.70M]
  ------------------
  209|   136k|        cursor += 4;
  210|   136k|        break;
  211|       |
  212|       |        // double
  213|   206k|    case 'D':
  ------------------
  |  Branch (213:5): [True: 206k, False: 1.49M]
  ------------------
  214|   206k|        cursor += 8;
  215|   206k|        break;
  216|       |
  217|       |        // 64 bit int
  218|   218k|    case 'L':
  ------------------
  |  Branch (218:5): [True: 218k, False: 1.48M]
  ------------------
  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|    333|    case 'R':
  ------------------
  |  Branch (225:5): [True: 333, False: 1.70M]
  ------------------
  226|    333|    {
  227|    333|        const uint32_t length = ReadWord(input, cursor, end);
  228|    333|        cursor += length;
  229|    333|        break;
  230|   136k|    }
  231|       |
  232|     18|    case 'b':
  ------------------
  |  Branch (232:5): [True: 18, False: 1.70M]
  ------------------
  233|       |        // TODO: what is the 'b' type code? Right now we just skip over it /
  234|       |        // take the full range we could get
  235|     18|        cursor = end;
  236|     18|        break;
  237|       |
  238|       |        // array of *
  239|  63.6k|    case 'f':
  ------------------
  |  Branch (239:5): [True: 63.6k, False: 1.64M]
  ------------------
  240|  85.8k|    case 'd':
  ------------------
  |  Branch (240:5): [True: 22.1k, False: 1.68M]
  ------------------
  241|   117k|    case 'l':
  ------------------
  |  Branch (241:5): [True: 31.8k, False: 1.67M]
  ------------------
  242|   191k|    case 'i':
  ------------------
  |  Branch (242:5): [True: 73.9k, False: 1.63M]
  ------------------
  243|   191k|    case 'c':   {
  ------------------
  |  Branch (243:5): [True: 1, False: 1.70M]
  ------------------
  244|   191k|        const uint32_t length = ReadWord(input, cursor, end);
  245|   191k|        const uint32_t encoding = ReadWord(input, cursor, end);
  246|       |
  247|   191k|        const uint32_t comp_len = ReadWord(input, cursor, end);
  248|       |
  249|       |        // compute length based on type and check against the stored value
  250|   191k|        if(encoding == 0) {
  ------------------
  |  Branch (250:12): [True: 174k, False: 16.9k]
  ------------------
  251|   174k|            uint32_t stride = 0;
  252|   174k|            switch(type)
  253|   174k|            {
  254|  63.6k|            case 'f':
  ------------------
  |  Branch (254:13): [True: 63.6k, False: 110k]
  ------------------
  255|   129k|            case 'i':
  ------------------
  |  Branch (255:13): [True: 65.4k, False: 109k]
  ------------------
  256|   129k|                stride = 4;
  257|   129k|                break;
  258|       |
  259|  13.6k|            case 'd':
  ------------------
  |  Branch (259:13): [True: 13.6k, False: 160k]
  ------------------
  260|  45.5k|            case 'l':
  ------------------
  |  Branch (260:13): [True: 31.8k, False: 142k]
  ------------------
  261|  45.5k|                stride = 8;
  262|  45.5k|                break;
  263|       |
  264|      0|            case 'c':
  ------------------
  |  Branch (264:13): [True: 0, False: 174k]
  ------------------
  265|      0|                stride = 1;
  266|      0|                break;
  267|       |
  268|      0|            default:
  ------------------
  |  Branch (268:13): [True: 0, False: 174k]
  ------------------
  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|   174k|            };
  271|   174k|            ai_assert(stride > 0);
  ------------------
  |  |   67|   174k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 174k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  272|   174k|            if(length * stride != comp_len) {
  ------------------
  |  Branch (272:16): [True: 0, False: 174k]
  ------------------
  273|      0|                TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor);
  274|      0|            }
  275|   174k|        }
  276|       |        // zip/deflate algorithm (encoding==1)? take given length. anything else? die
  277|  16.9k|        else if (encoding != 1) {
  ------------------
  |  Branch (277:18): [True: 0, False: 16.9k]
  ------------------
  278|      0|            TokenizeError("cannot ReadData, unknown encoding",input, cursor);
  279|      0|        }
  280|   191k|        cursor += comp_len;
  281|   191k|        break;
  282|   191k|    }
  283|       |
  284|       |        // string
  285|   945k|    case 'S': {
  ------------------
  |  Branch (285:5): [True: 945k, False: 759k]
  ------------------
  286|   945k|        const char* sb, *se;
  287|       |        // 0 characters can legally happen in such strings
  288|   945k|        ReadString(sb, se, input, cursor, end, true, true);
  289|   945k|        break;
  290|   191k|    }
  291|      4|    default:
  ------------------
  |  Branch (291:5): [True: 4, False: 1.70M]
  ------------------
  292|      4|        TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor);
  293|  1.70M|    }
  294|       |
  295|  1.70M|    if(cursor > end) {
  ------------------
  |  Branch (295:8): [True: 0, False: 1.70M]
  ------------------
  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.70M|    send_out = cursor;
  301|  1.70M|}

_ZN6Assimp3FBX12FBXConverterC2EP7aiSceneRKNS0_8DocumentEb:
  128|    355|        mMeshes(),
  129|    355|        lights(),
  130|    355|        cameras(),
  131|    355|        textures(),
  132|    355|        materials_converted(),
  133|    355|        textures_converted(),
  134|    355|        meshes_converted(),
  135|    355|        node_anim_chain_bits(),
  136|    355|        mNodeNames(),
  137|       |        anim_fps(),
  138|    355|        mSceneOut(out),
  139|    355|        doc(doc),
  140|    355|        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|    355|    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|    355|    if (doc.Settings().readTextures) {
  ------------------
  |  Branch (151:9): [True: 344, False: 11]
  ------------------
  152|    344|        ConvertOrphanedEmbeddedTextures();
  153|    344|    }
  154|    355|    ConvertRootNode();
  155|       |
  156|    355|    if (doc.Settings().readAllMaterials) {
  ------------------
  |  Branch (156:9): [True: 0, False: 355]
  ------------------
  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|    355|    ConvertGlobalSettings();
  176|    355|    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|    355|    if (out->mNumMeshes == 0) {
  ------------------
  |  Branch (181:9): [True: 178, False: 177]
  ------------------
  182|    178|        out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
  183|    178|    } else {
  184|       |        // Apply the FBX axis metadata unless requested not to
  185|    177|        if (!doc.Settings().ignoreUpDirection)
  ------------------
  |  Branch (185:13): [True: 159, False: 18]
  ------------------
  186|    159|            correctRootTransform(mSceneOut);
  187|    177|    }
  188|    355|}
_ZN6Assimp3FBX12FBXConverterD2Ev:
  190|    337|FBXConverter::~FBXConverter() {
  191|    337|    std::for_each(mMeshes.begin(), mMeshes.end(), Util::delete_fun<aiMesh>());
  192|    337|    std::for_each(materials.begin(), materials.end(), Util::delete_fun<aiMaterial>());
  193|    337|    std::for_each(animations.begin(), animations.end(), Util::delete_fun<aiAnimation>());
  194|    337|    std::for_each(lights.begin(), lights.end(), Util::delete_fun<aiLight>());
  195|    337|    std::for_each(cameras.begin(), cameras.end(), Util::delete_fun<aiCamera>());
  196|    337|    std::for_each(textures.begin(), textures.end(), Util::delete_fun<aiTexture>());
  197|    337|}
_ZN6Assimp3FBX12FBXConverter15ConvertRootNodeEv:
  199|    344|void FBXConverter::ConvertRootNode() {
  200|    344|    mSceneOut->mRootNode = new aiNode();
  201|    344|    std::string unique_name;
  202|    344|    GetUniqueName("RootNode", unique_name);
  203|    344|    mSceneOut->mRootNode->mName.Set(unique_name);
  204|       |
  205|       |    // root has ID 0
  206|    344|    ConvertNodes(0L, mSceneOut->mRootNode, mSceneOut->mRootNode);
  207|    344|}
_ZN6Assimp3FBX12FBXConverter12ConvertNodesEmP6aiNodeS3_RK12aiMatrix4x4tIfE:
  250|  5.25k|void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node, const aiMatrix4x4& parent_transform) {
  251|  5.25k|    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
  252|       |
  253|  5.25k|    std::vector<PotentialNode> nodes;
  254|  5.25k|    nodes.reserve(conns.size());
  255|       |
  256|  5.25k|    std::vector<PotentialNode> nodes_chain;
  257|  5.25k|    std::vector<PotentialNode> post_nodes_chain;
  258|       |
  259|  5.25k|    for (const Connection *con : conns) {
  ------------------
  |  Branch (259:32): [True: 4.92k, False: 5.25k]
  ------------------
  260|       |        // ignore object-property links
  261|  4.92k|        if (con->PropertyName().length()) {
  ------------------
  |  Branch (261:13): [True: 0, False: 4.92k]
  ------------------
  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|  4.92k|        const Object *const object = con->SourceObject();
  269|  4.92k|        if (nullptr == object) {
  ------------------
  |  Branch (269:13): [True: 9, False: 4.91k]
  ------------------
  270|      9|            FBXImporter::LogError("failed to convert source object for Model link");
  271|      9|            continue;
  272|      9|        }
  273|       |
  274|       |        // FBX Model::Cube, Model::Bone001, etc elements
  275|       |        // This detects if we can cast the object into this model structure.
  276|  4.91k|        const Model *const model = dynamic_cast<const Model *>(object);
  277|       |
  278|  4.91k|        if (nullptr != model) {
  ------------------
  |  Branch (278:13): [True: 4.91k, False: 0]
  ------------------
  279|  4.91k|            nodes_chain.clear();
  280|  4.91k|            post_nodes_chain.clear();
  281|  4.91k|            aiMatrix4x4 new_abs_transform = parent_transform;
  282|  4.91k|            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|  4.91k|            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|  4.91k|            ai_assert(nodes_chain.size());
  294|       |
  295|  4.91k|            if (need_additional_node) {
  ------------------
  |  Branch (295:17): [True: 416, False: 4.49k]
  ------------------
  296|    416|                nodes_chain.emplace_back(node_name);
  297|    416|            }
  298|       |
  299|       |            //setup metadata on newest node
  300|  4.91k|            SetupNodeMetadata(*model, *nodes_chain.back().mNode);
  301|       |
  302|       |            // link all nodes in a row
  303|  4.91k|            aiNode *last_parent = parent;
  304|  6.51k|            for (PotentialNode& child : nodes_chain) {
  ------------------
  |  Branch (304:39): [True: 6.51k, False: 4.91k]
  ------------------
  305|  6.51k|                ai_assert(child.mNode);
  306|       |
  307|  6.51k|                if (last_parent != parent) {
  ------------------
  |  Branch (307:21): [True: 1.60k, False: 4.90k]
  ------------------
  308|  1.60k|                    last_parent->mNumChildren = 1;
  309|  1.60k|                    last_parent->mChildren = new aiNode *[1];
  310|  1.60k|                    last_parent->mChildren[0] = child.mOwnership.release();
  311|  1.60k|                }
  312|       |
  313|  6.51k|                child->mParent = last_parent;
  314|  6.51k|                last_parent = child.mNode;
  315|       |
  316|  6.51k|                new_abs_transform *= child->mTransformation;
  317|  6.51k|            }
  318|       |
  319|       |            // attach geometry
  320|  4.91k|            ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);
  321|       |
  322|       |            // check if there will be any child nodes
  323|  4.91k|            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|  4.91k|            if (child_conns.size()) {
  ------------------
  |  Branch (327:17): [True: 2.23k, False: 2.68k]
  ------------------
  328|  2.23k|                for (PotentialNode& postnode : post_nodes_chain) {
  ------------------
  |  Branch (328:46): [True: 184, False: 2.23k]
  ------------------
  329|    184|                    ai_assert(postnode.mNode);
  330|       |
  331|    184|                    if (last_parent != parent) {
  ------------------
  |  Branch (331:25): [True: 184, False: 0]
  ------------------
  332|    184|                        last_parent->mNumChildren = 1;
  333|    184|                        last_parent->mChildren = new aiNode *[1];
  334|    184|                        last_parent->mChildren[0] = postnode.mOwnership.release();
  335|    184|                    }
  336|       |
  337|    184|                    postnode->mParent = last_parent;
  338|    184|                    last_parent = postnode.mNode;
  339|       |
  340|    184|                    new_abs_transform *= postnode->mTransformation;
  341|    184|                }
  342|  2.68k|            } else {
  343|       |                // free the nodes we allocated as we don't need them
  344|  2.68k|                post_nodes_chain.clear();
  345|  2.68k|            }
  346|       |
  347|       |            // recursion call - child nodes
  348|  4.91k|            ConvertNodes(model->ID(), last_parent, root_node, new_abs_transform);
  349|       |
  350|  4.91k|            if (doc.Settings().readLights) {
  ------------------
  |  Branch (350:17): [True: 4.89k, False: 21]
  ------------------
  351|  4.89k|                ConvertLights(*model, node_name);
  352|  4.89k|            }
  353|       |
  354|  4.91k|            if (doc.Settings().readCameras) {
  ------------------
  |  Branch (354:17): [True: 4.89k, False: 22]
  ------------------
  355|  4.89k|                ConvertCameras(*model, node_name);
  356|  4.89k|            }
  357|       |
  358|  4.91k|            nodes.push_back(std::move(nodes_chain.front()));
  359|  4.91k|            nodes_chain.clear();
  360|  4.91k|        }
  361|  4.91k|    }
  362|       |
  363|  5.25k|    if (nodes.empty()) {
  ------------------
  |  Branch (363:9): [True: 2.68k, False: 2.57k]
  ------------------
  364|  2.68k|        parent->mNumChildren = 0;
  365|  2.68k|        parent->mChildren = nullptr;
  366|  2.68k|    } else {
  367|  2.57k|        parent->mChildren = new aiNode *[nodes.size()]();
  368|  2.57k|        parent->mNumChildren = static_cast<unsigned int>(nodes.size());
  369|  7.41k|        for (unsigned int i = 0; i < nodes.size(); ++i) {
  ------------------
  |  Branch (369:34): [True: 4.84k, False: 2.57k]
  ------------------
  370|  4.84k|            parent->mChildren[i] = nodes[i].mOwnership.release();
  371|  4.84k|        }
  372|  2.57k|    }
  373|  5.25k|}
_ZN6Assimp3FBX12FBXConverter13ConvertLightsERKNS0_5ModelERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  375|  4.89k|void FBXConverter::ConvertLights(const Model &model, const std::string &orig_name) {
  376|  4.89k|    const std::vector<const NodeAttribute *> &node_attrs = model.GetAttributes();
  377|  4.89k|    for (const NodeAttribute *attr : node_attrs) {
  ------------------
  |  Branch (377:36): [True: 3.05k, False: 4.89k]
  ------------------
  378|  3.05k|        const Light *const light = dynamic_cast<const Light *>(attr);
  379|  3.05k|        if (light) {
  ------------------
  |  Branch (379:13): [True: 277, False: 2.77k]
  ------------------
  380|    277|            ConvertLight(*light, orig_name);
  381|    277|        }
  382|  3.05k|    }
  383|  4.89k|}
_ZN6Assimp3FBX12FBXConverter14ConvertCamerasERKNS0_5ModelERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  385|  4.89k|void FBXConverter::ConvertCameras(const Model &model, const std::string &orig_name) {
  386|  4.89k|    const std::vector<const NodeAttribute *> &node_attrs = model.GetAttributes();
  387|  4.89k|    for (const NodeAttribute *attr : node_attrs) {
  ------------------
  |  Branch (387:36): [True: 3.05k, False: 4.89k]
  ------------------
  388|  3.05k|        const Camera *const cam = dynamic_cast<const Camera *>(attr);
  389|  3.05k|        if (cam) {
  ------------------
  |  Branch (389:13): [True: 290, False: 2.76k]
  ------------------
  390|    290|            ConvertCamera(*cam, orig_name);
  391|    290|        }
  392|  3.05k|    }
  393|  4.89k|}
_ZN6Assimp3FBX12FBXConverter12ConvertLightERKNS0_5LightERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  395|    277|void FBXConverter::ConvertLight(const Light &light, const std::string &orig_name) {
  396|    277|    lights.push_back(new aiLight());
  397|    277|    aiLight *const out_light = lights.back();
  398|       |
  399|    277|    out_light->mName.Set(orig_name);
  400|       |
  401|    277|    const float intensity = light.Intensity() / 100.0f;
  402|    277|    const aiVector3D &col = light.Color();
  403|       |
  404|    277|    out_light->mColorDiffuse = aiColor3D(col.x, col.y, col.z);
  405|    277|    out_light->mColorDiffuse.r *= intensity;
  406|    277|    out_light->mColorDiffuse.g *= intensity;
  407|    277|    out_light->mColorDiffuse.b *= intensity;
  408|       |
  409|    277|    out_light->mColorSpecular = out_light->mColorDiffuse;
  410|       |
  411|       |    //lights are defined along negative y direction
  412|    277|    out_light->mPosition = aiVector3D(0.0f);
  413|    277|    out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f);
  414|    277|    out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f);
  415|       |
  416|    277|    switch (light.LightType()) {
  417|    276|        case Light::Type_Point:
  ------------------
  |  Branch (417:9): [True: 276, False: 1]
  ------------------
  418|    276|            out_light->mType = aiLightSource_POINT;
  419|    276|            break;
  420|       |
  421|      0|        case Light::Type_Directional:
  ------------------
  |  Branch (421:9): [True: 0, False: 277]
  ------------------
  422|      0|            out_light->mType = aiLightSource_DIRECTIONAL;
  423|      0|            break;
  424|       |
  425|      0|        case Light::Type_Spot:
  ------------------
  |  Branch (425:9): [True: 0, False: 277]
  ------------------
  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: 277]
  ------------------
  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: 277]
  ------------------
  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: 277]
  ------------------
  441|      0|            FBXImporter::LogError("Not handled light type: ", light.LightType());
  442|      0|            break;
  443|    277|    }
  444|       |
  445|    276|    float decay = light.DecayStart();
  446|    276|    switch (light.DecayType()) {
  447|      0|        case Light::Decay_None:
  ------------------
  |  Branch (447:9): [True: 0, False: 276]
  ------------------
  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: 276]
  ------------------
  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|    276|        case Light::Decay_Quadratic:
  ------------------
  |  Branch (457:9): [True: 276, False: 0]
  ------------------
  458|    276|            out_light->mAttenuationConstant = 0.0f;
  459|    276|            out_light->mAttenuationLinear = 0.0f;
  460|    276|            out_light->mAttenuationQuadratic = 2.0f / (decay * decay);
  461|    276|            break;
  462|      0|        case Light::Decay_Cubic:
  ------------------
  |  Branch (462:9): [True: 0, False: 276]
  ------------------
  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: 276]
  ------------------
  467|      0|            FBXImporter::LogError("Not handled light decay type: ", light.DecayType());
  468|      0|            break;
  469|    276|    }
  470|    276|}
_ZN6Assimp3FBX12FBXConverter13ConvertCameraERKNS0_6CameraERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  472|    290|void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name) {
  473|    290|    cameras.push_back(new aiCamera());
  474|    290|    aiCamera *const out_camera = cameras.back();
  475|       |
  476|    290|    out_camera->mName.Set(orig_name);
  477|       |
  478|    290|    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|    290|    out_camera->mPosition = aiVector3D(0.0f);
  483|    290|    out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
  484|    290|    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|    290|    float fov_deg = cam.FieldOfView();
  494|       |    // If FOV not specified in file, compute using FilmWidth and FocalLength.
  495|    290|    if (fov_deg == kFovUnknown) {
  ------------------
  |  Branch (495:9): [True: 0, False: 290]
  ------------------
  496|      0|        float film_width_inches = cam.FilmWidth();
  497|      0|        float focal_length_mm = cam.FocalLength();
  498|      0|        ASSIMP_LOG_VERBOSE_DEBUG("FBX FOV unspecified. Computing from FilmWidth (", film_width_inches, "inches) and FocalLength (", focal_length_mm, "mm).");
  499|      0|        double half_fov_rad = std::atan2(film_width_inches * 25.4 * 0.5, focal_length_mm);
  500|      0|        out_camera->mHorizontalFOV = static_cast<float>(half_fov_rad);
  501|    290|    } else {
  502|       |        // FBX fov is full-view degrees. We want half-view radians.
  503|    290|        out_camera->mHorizontalFOV = AI_DEG_TO_RAD(fov_deg) * 0.5f;
  504|    290|    }
  505|       |
  506|    290|    out_camera->mClipPlaneNear = cam.NearPlane();
  507|    290|    out_camera->mClipPlaneFar = cam.FarPlane();
  508|    290|}
_ZN6Assimp3FBX12FBXConverter13GetUniqueNameERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERS8_:
  510|    344|void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName) {
  511|    344|    uniqueName = name;
  512|    344|    auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
  513|    344|    unsigned int &i = it_pair.first->second;
  514|    344|    while (!it_pair.second) {
  ------------------
  |  Branch (514:12): [True: 0, False: 344]
  ------------------
  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|    344|}
_ZN6Assimp3FBX12FBXConverter22NameTransformationCompENS1_18TransformationCompE:
  523|  3.08k|const char *FBXConverter::NameTransformationComp(TransformationComp comp) {
  524|  3.08k|    switch (comp) {
  525|    801|        case TransformationComp_Translation:
  ------------------
  |  Branch (525:9): [True: 801, False: 2.28k]
  ------------------
  526|    801|            return "Translation";
  527|     58|        case TransformationComp_RotationOffset:
  ------------------
  |  Branch (527:9): [True: 58, False: 3.03k]
  ------------------
  528|     58|            return "RotationOffset";
  529|     50|        case TransformationComp_RotationPivot:
  ------------------
  |  Branch (529:9): [True: 50, False: 3.03k]
  ------------------
  530|     50|            return "RotationPivot";
  531|      5|        case TransformationComp_PreRotation:
  ------------------
  |  Branch (531:9): [True: 5, False: 3.08k]
  ------------------
  532|      5|            return "PreRotation";
  533|    768|        case TransformationComp_Rotation:
  ------------------
  |  Branch (533:9): [True: 768, False: 2.32k]
  ------------------
  534|    768|            return "Rotation";
  535|     42|        case TransformationComp_PostRotation:
  ------------------
  |  Branch (535:9): [True: 42, False: 3.04k]
  ------------------
  536|     42|            return "PostRotation";
  537|     50|        case TransformationComp_RotationPivotInverse:
  ------------------
  |  Branch (537:9): [True: 50, False: 3.03k]
  ------------------
  538|     50|            return "RotationPivotInverse";
  539|      0|        case TransformationComp_ScalingOffset:
  ------------------
  |  Branch (539:9): [True: 0, False: 3.08k]
  ------------------
  540|      0|            return "ScalingOffset";
  541|      0|        case TransformationComp_ScalingPivot:
  ------------------
  |  Branch (541:9): [True: 0, False: 3.08k]
  ------------------
  542|      0|            return "ScalingPivot";
  543|    739|        case TransformationComp_Scaling:
  ------------------
  |  Branch (543:9): [True: 739, False: 2.35k]
  ------------------
  544|    739|            return "Scaling";
  545|      0|        case TransformationComp_ScalingPivotInverse:
  ------------------
  |  Branch (545:9): [True: 0, False: 3.08k]
  ------------------
  546|      0|            return "ScalingPivotInverse";
  547|    278|        case TransformationComp_GeometricScaling:
  ------------------
  |  Branch (547:9): [True: 278, False: 2.81k]
  ------------------
  548|    278|            return "GeometricScaling";
  549|     20|        case TransformationComp_GeometricRotation:
  ------------------
  |  Branch (549:9): [True: 20, False: 3.06k]
  ------------------
  550|     20|            return "GeometricRotation";
  551|      0|        case TransformationComp_GeometricTranslation:
  ------------------
  |  Branch (551:9): [True: 0, False: 3.08k]
  ------------------
  552|      0|            return "GeometricTranslation";
  553|    258|        case TransformationComp_GeometricScalingInverse:
  ------------------
  |  Branch (553:9): [True: 258, False: 2.83k]
  ------------------
  554|    258|            return "GeometricScalingInverse";
  555|     20|        case TransformationComp_GeometricRotationInverse:
  ------------------
  |  Branch (555:9): [True: 20, False: 3.06k]
  ------------------
  556|     20|            return "GeometricRotationInverse";
  557|      0|        case TransformationComp_GeometricTranslationInverse:
  ------------------
  |  Branch (557:9): [True: 0, False: 3.08k]
  ------------------
  558|      0|            return "GeometricTranslationInverse";
  559|      0|        case TransformationComp_MAXIMUM: // this is to silence compiler warnings
  ------------------
  |  Branch (559:9): [True: 0, False: 3.08k]
  ------------------
  560|      0|        default:
  ------------------
  |  Branch (560:9): [True: 0, False: 3.08k]
  ------------------
  561|      0|            break;
  562|  3.08k|    }
  563|       |
  564|  3.08k|    ai_assert(false);
  565|       |
  566|      0|    return nullptr;
  567|  3.08k|}
_ZN6Assimp3FBX12FBXConverter30NameTransformationCompPropertyENS1_18TransformationCompE:
  569|  87.5k|const char *FBXConverter::NameTransformationCompProperty(TransformationComp comp) {
  570|  87.5k|    switch (comp) {
  ------------------
  |  Branch (570:13): [True: 87.5k, False: 0]
  ------------------
  571|  3.07k|        case TransformationComp_Translation:
  ------------------
  |  Branch (571:9): [True: 3.07k, False: 84.4k]
  ------------------
  572|  3.07k|            return "Lcl Translation";
  573|  6.15k|        case TransformationComp_RotationOffset:
  ------------------
  |  Branch (573:9): [True: 6.15k, False: 81.3k]
  ------------------
  574|  6.15k|            return "RotationOffset";
  575|  6.07k|        case TransformationComp_RotationPivot:
  ------------------
  |  Branch (575:9): [True: 6.07k, False: 81.4k]
  ------------------
  576|  6.07k|            return "RotationPivot";
  577|  5.99k|        case TransformationComp_PreRotation:
  ------------------
  |  Branch (577:9): [True: 5.99k, False: 81.5k]
  ------------------
  578|  5.99k|            return "PreRotation";
  579|  3.07k|        case TransformationComp_Rotation:
  ------------------
  |  Branch (579:9): [True: 3.07k, False: 84.4k]
  ------------------
  580|  3.07k|            return "Lcl Rotation";
  581|  5.99k|        case TransformationComp_PostRotation:
  ------------------
  |  Branch (581:9): [True: 5.99k, False: 81.5k]
  ------------------
  582|  5.99k|            return "PostRotation";
  583|  2.88k|        case TransformationComp_RotationPivotInverse:
  ------------------
  |  Branch (583:9): [True: 2.88k, False: 84.6k]
  ------------------
  584|  2.88k|            return "RotationPivotInverse";
  585|  5.96k|        case TransformationComp_ScalingOffset:
  ------------------
  |  Branch (585:9): [True: 5.96k, False: 81.5k]
  ------------------
  586|  5.96k|            return "ScalingOffset";
  587|  5.96k|        case TransformationComp_ScalingPivot:
  ------------------
  |  Branch (587:9): [True: 5.96k, False: 81.5k]
  ------------------
  588|  5.96k|            return "ScalingPivot";
  589|  3.07k|        case TransformationComp_Scaling:
  ------------------
  |  Branch (589:9): [True: 3.07k, False: 84.4k]
  ------------------
  590|  3.07k|            return "Lcl Scaling";
  591|  2.88k|        case TransformationComp_ScalingPivotInverse:
  ------------------
  |  Branch (591:9): [True: 2.88k, False: 84.6k]
  ------------------
  592|  2.88k|            return "ScalingPivotInverse";
  593|  5.94k|        case TransformationComp_GeometricScaling:
  ------------------
  |  Branch (593:9): [True: 5.94k, False: 81.5k]
  ------------------
  594|  5.94k|            return "GeometricScaling";
  595|  5.96k|        case TransformationComp_GeometricRotation:
  ------------------
  |  Branch (595:9): [True: 5.96k, False: 81.5k]
  ------------------
  596|  5.96k|            return "GeometricRotation";
  597|  5.96k|        case TransformationComp_GeometricTranslation:
  ------------------
  |  Branch (597:9): [True: 5.96k, False: 81.5k]
  ------------------
  598|  5.96k|            return "GeometricTranslation";
  599|  6.15k|        case TransformationComp_GeometricScalingInverse:
  ------------------
  |  Branch (599:9): [True: 6.15k, False: 81.3k]
  ------------------
  600|  6.15k|            return "GeometricScalingInverse";
  601|  6.15k|        case TransformationComp_GeometricRotationInverse:
  ------------------
  |  Branch (601:9): [True: 6.15k, False: 81.3k]
  ------------------
  602|  6.15k|            return "GeometricRotationInverse";
  603|  6.15k|        case TransformationComp_GeometricTranslationInverse:
  ------------------
  |  Branch (603:9): [True: 6.15k, False: 81.3k]
  ------------------
  604|  6.15k|            return "GeometricTranslationInverse";
  605|      0|        case TransformationComp_MAXIMUM:
  ------------------
  |  Branch (605:9): [True: 0, False: 87.5k]
  ------------------
  606|      0|            break;
  607|  87.5k|    }
  608|       |
  609|  87.5k|    ai_assert(false);
  610|       |
  611|      0|    return nullptr;
  612|  87.5k|}
_ZN6Assimp3FBX12FBXConverter17GetRotationMatrixENS0_5Model8RotOrderERK10aiVector3tIfER12aiMatrix4x4tIfE:
  620|  4.38M|void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rotation, aiMatrix4x4 &out) {
  621|  4.38M|    if (mode == Model::RotOrder_SphericXYZ) {
  ------------------
  |  Branch (621:9): [True: 0, False: 4.38M]
  ------------------
  622|      0|        FBXImporter::LogError("Unsupported RotationMode: SphericXYZ");
  623|      0|        out = aiMatrix4x4();
  624|      0|        return;
  625|      0|    }
  626|       |
  627|  4.38M|    const float angle_epsilon = Math::getEpsilon<float>();
  628|       |
  629|  4.38M|    out = aiMatrix4x4();
  630|       |
  631|  4.38M|    bool is_id[3] = { true, true, true };
  632|       |
  633|  4.38M|    aiMatrix4x4 temp[3];
  634|  4.38M|    const auto rot = AI_DEG_TO_RAD(rotation);
  635|  4.38M|    if (std::fabs(rot.z) > angle_epsilon) {
  ------------------
  |  Branch (635:9): [True: 782k, False: 3.59M]
  ------------------
  636|   782k|        aiMatrix4x4::RotationZ(rot.z, temp[2]);
  637|   782k|        is_id[2] = false;
  638|   782k|    }
  639|  4.38M|    if (std::fabs(rot.y) > angle_epsilon) {
  ------------------
  |  Branch (639:9): [True: 782k, False: 3.59M]
  ------------------
  640|   782k|        aiMatrix4x4::RotationY(rot.y, temp[1]);
  641|   782k|        is_id[1] = false;
  642|   782k|    }
  643|  4.38M|    if (std::fabs(rot.x) > angle_epsilon) {
  ------------------
  |  Branch (643:9): [True: 4.21M, False: 164k]
  ------------------
  644|  4.21M|        aiMatrix4x4::RotationX(rot.x, temp[0]);
  645|  4.21M|        is_id[0] = false;
  646|  4.21M|    }
  647|       |
  648|  4.38M|    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.38M|    switch (mode) {
  652|  4.38M|        case Model::RotOrder_EulerXYZ:
  ------------------
  |  Branch (652:9): [True: 4.38M, False: 0]
  ------------------
  653|  4.38M|            order[0] = 2;
  654|  4.38M|            order[1] = 1;
  655|  4.38M|            order[2] = 0;
  656|  4.38M|            break;
  657|       |
  658|      0|        case Model::RotOrder_EulerXZY:
  ------------------
  |  Branch (658:9): [True: 0, False: 4.38M]
  ------------------
  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.38M]
  ------------------
  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.38M]
  ------------------
  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.38M]
  ------------------
  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.38M]
  ------------------
  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.38M]
  ------------------
  689|      0|            ai_assert(false);
  690|      0|            break;
  691|  4.38M|    }
  692|       |
  693|  4.38M|    ai_assert(order[0] >= 0);
  694|  4.38M|    ai_assert(order[0] <= 2);
  695|  4.38M|    ai_assert(order[1] >= 0);
  696|  4.38M|    ai_assert(order[1] <= 2);
  697|  4.38M|    ai_assert(order[2] >= 0);
  698|  4.38M|    ai_assert(order[2] <= 2);
  699|       |
  700|  4.38M|    if (!is_id[order[0]]) {
  ------------------
  |  Branch (700:9): [True: 782k, False: 3.59M]
  ------------------
  701|   782k|        out = temp[order[0]];
  702|   782k|    }
  703|       |
  704|  4.38M|    if (!is_id[order[1]]) {
  ------------------
  |  Branch (704:9): [True: 782k, False: 3.59M]
  ------------------
  705|   782k|        out = out * temp[order[1]];
  706|   782k|    }
  707|       |
  708|  4.38M|    if (!is_id[order[2]]) {
  ------------------
  |  Branch (708:9): [True: 4.21M, False: 164k]
  ------------------
  709|  4.21M|        out = out * temp[order[2]];
  710|  4.21M|    }
  711|  4.38M|}
_ZN6Assimp3FBX12FBXConverter31NeedsComplexTransformationChainERKNS0_5ModelE:
  713|  3.07k|bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
  714|  3.07k|    const PropertyTable &props = model.Props();
  715|       |
  716|  3.07k|    const auto zero_epsilon = Math::getEpsilon<ai_real>();
  717|  3.07k|    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
  718|  52.8k|    for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
  ------------------
  |  Branch (718:24): [True: 50.1k, False: 2.63k]
  ------------------
  719|  50.1k|        const TransformationComp comp = static_cast<TransformationComp>(i);
  720|       |
  721|  50.1k|        if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) {
  ------------------
  |  Branch (721:13): [True: 2.91k, False: 47.2k]
  |  Branch (721:52): [True: 2.88k, False: 44.3k]
  |  Branch (721:90): [True: 3.07k, False: 41.3k]
  ------------------
  722|  8.87k|            continue;
  723|  8.87k|        }
  724|       |
  725|  41.3k|        bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
  ------------------
  |  Branch (725:31): [True: 2.87k, False: 38.4k]
  |  Branch (725:78): [True: 0, False: 38.4k]
  ------------------
  726|       |
  727|  41.3k|        bool ok = true;
  728|  41.3k|        const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
  729|  41.3k|        if (ok && scale_compare) {
  ------------------
  |  Branch (729:13): [True: 24.7k, False: 16.5k]
  |  Branch (729:19): [True: 2.71k, False: 22.0k]
  ------------------
  730|  2.71k|            if ((v - all_ones).SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (730:17): [True: 234, False: 2.47k]
  ------------------
  731|    234|                return true;
  732|    234|            }
  733|  38.6k|        } else if (ok) {
  ------------------
  |  Branch (733:20): [True: 22.0k, False: 16.5k]
  ------------------
  734|  22.0k|            if (v.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (734:17): [True: 209, False: 21.8k]
  ------------------
  735|    209|                return true;
  736|    209|            }
  737|  22.0k|        }
  738|  41.3k|    }
  739|       |
  740|  2.63k|    return false;
  741|  3.07k|}
_ZN6Assimp3FBX12FBXConverter27NameTransformationChainNodeERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS1_18TransformationCompE:
  743|  3.08k|std::string FBXConverter::NameTransformationChainNode(const std::string &name, TransformationComp comp) {
  744|  3.08k|    return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
  ------------------
  |  |   75|  3.08k|#define MAGIC_NODE_TAG "_$AssimpFbx$"
  ------------------
  745|  3.08k|}
_ZN6Assimp3FBX12FBXConverter31GenerateTransformationNodeChainERKNS0_5ModelERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERNS5_6vectorINS1_13PotentialNodeENS9_ISF_EEEESI_:
  748|  4.91k|        std::vector<PotentialNode> &post_output_nodes) {
  749|  4.91k|    const PropertyTable &props = model.Props();
  750|  4.91k|    const Model::RotOrder rot = model.RotationOrder();
  751|       |
  752|  4.91k|    bool ok;
  753|       |
  754|  4.91k|    aiMatrix4x4 chain[TransformationComp_MAXIMUM];
  755|       |
  756|  4.91k|    ai_assert(TransformationComp_MAXIMUM < 32);
  757|  4.91k|    std::uint32_t chainBits = 0;
  758|       |    // A node won't need a node chain if it only has these.
  759|  4.91k|    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|  4.91k|    const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple;
  762|       |
  763|  4.91k|    std::fill_n(chain, static_cast<unsigned int>(TransformationComp_MAXIMUM), aiMatrix4x4());
  764|       |
  765|       |    // generate transformation matrices for all the different transformation components
  766|  4.91k|    const float zero_epsilon = Math::getEpsilon<float>();
  767|  4.91k|    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
  768|       |
  769|  4.91k|    const aiVector3D &PreRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
  770|  4.91k|    if (ok && PreRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (770:9): [True: 4.70k, False: 210]
  |  Branch (770:15): [True: 5, False: 4.69k]
  ------------------
  771|      5|        chainBits = chainBits | (1 << TransformationComp_PreRotation);
  772|       |
  773|      5|        GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]);
  774|      5|    }
  775|       |
  776|  4.91k|    const aiVector3D &PostRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok);
  777|  4.91k|    if (ok && PostRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (777:9): [True: 4.69k, False: 217]
  |  Branch (777:15): [True: 42, False: 4.65k]
  ------------------
  778|     42|        chainBits = chainBits | (1 << TransformationComp_PostRotation);
  779|       |
  780|     42|        GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]);
  781|     42|    }
  782|       |
  783|  4.91k|    const aiVector3D &RotationPivot = PropertyGet<aiVector3D>(props, "RotationPivot", ok);
  784|  4.91k|    if (ok && RotationPivot.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (784:9): [True: 4.70k, False: 208]
  |  Branch (784:15): [True: 50, False: 4.65k]
  ------------------
  785|     50|        chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse);
  786|       |
  787|     50|        aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]);
  788|     50|        aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]);
  789|     50|    }
  790|       |
  791|  4.91k|    const aiVector3D &RotationOffset = PropertyGet<aiVector3D>(props, "RotationOffset", ok);
  792|  4.91k|    if (ok && RotationOffset.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (792:9): [True: 4.70k, False: 210]
  |  Branch (792:15): [True: 59, False: 4.64k]
  ------------------
  793|     59|        chainBits = chainBits | (1 << TransformationComp_RotationOffset);
  794|       |
  795|     59|        aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]);
  796|     59|    }
  797|       |
  798|  4.91k|    const aiVector3D &ScalingOffset = PropertyGet<aiVector3D>(props, "ScalingOffset", ok);
  799|  4.91k|    if (ok && ScalingOffset.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (799:9): [True: 4.60k, False: 310]
  |  Branch (799:15): [True: 0, False: 4.60k]
  ------------------
  800|      0|        chainBits = chainBits | (1 << TransformationComp_ScalingOffset);
  801|       |
  802|      0|        aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]);
  803|      0|    }
  804|       |
  805|  4.91k|    const aiVector3D &ScalingPivot = PropertyGet<aiVector3D>(props, "ScalingPivot", ok);
  806|  4.91k|    if (ok && ScalingPivot.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (806:9): [True: 4.63k, False: 277]
  |  Branch (806:15): [True: 0, False: 4.63k]
  ------------------
  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|  4.91k|    const aiVector3D &Translation = PropertyGet<aiVector3D>(props, "Lcl Translation", ok);
  814|  4.91k|    if (ok && Translation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (814:9): [True: 4.85k, False: 61]
  |  Branch (814:15): [True: 3.33k, False: 1.52k]
  ------------------
  815|  3.33k|        chainBits = chainBits | (1 << TransformationComp_Translation);
  816|       |
  817|  3.33k|        aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]);
  818|  3.33k|    }
  819|       |
  820|  4.91k|    const aiVector3D &Scaling = PropertyGet<aiVector3D>(props, "Lcl Scaling", ok);
  821|  4.91k|    if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (821:9): [True: 4.85k, False: 55]
  |  Branch (821:9): [True: 2.45k, False: 2.46k]
  |  Branch (821:15): [True: 2.45k, False: 2.40k]
  ------------------
  822|  2.45k|        chainBits = chainBits | (1 << TransformationComp_Scaling);
  823|       |
  824|  2.45k|        aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]);
  825|  2.45k|    }
  826|       |
  827|  4.91k|    const aiVector3D &Rotation = PropertyGet<aiVector3D>(props, "Lcl Rotation", ok);
  828|  4.91k|    if (ok && Rotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (828:9): [True: 4.83k, False: 76]
  |  Branch (828:15): [True: 2.75k, False: 2.08k]
  ------------------
  829|  2.75k|        chainBits = chainBits | (1 << TransformationComp_Rotation);
  830|       |
  831|  2.75k|        GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]);
  832|  2.75k|    }
  833|       |
  834|  4.91k|    const aiVector3D &GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok);
  835|  4.91k|    if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (835:9): [True: 4.69k, False: 216]
  |  Branch (835:9): [True: 278, False: 4.63k]
  |  Branch (835:15): [True: 278, False: 4.42k]
  ------------------
  836|    278|        chainBits = chainBits | (1 << TransformationComp_GeometricScaling);
  837|    278|        aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]);
  838|    278|        aiVector3D GeometricScalingInverse = GeometricScaling;
  839|    278|        bool canscale = true;
  840|  1.07k|        for (unsigned int i = 0; i < 3; ++i) {
  ------------------
  |  Branch (840:34): [True: 814, False: 258]
  ------------------
  841|    814|            if (std::fabs(GeometricScalingInverse[i]) > zero_epsilon) {
  ------------------
  |  Branch (841:17): [True: 794, False: 20]
  ------------------
  842|    794|                GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
  843|    794|            } else {
  844|     20|                FBXImporter::LogError("cannot invert geometric scaling matrix with a 0.0 scale component");
  845|     20|                canscale = false;
  846|     20|                break;
  847|     20|            }
  848|    814|        }
  849|    278|        if (canscale) {
  ------------------
  |  Branch (849:13): [True: 258, False: 20]
  ------------------
  850|    258|            chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse);
  851|    258|            aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]);
  852|    258|        }
  853|    278|    }
  854|       |
  855|  4.91k|    const aiVector3D &GeometricRotation = PropertyGet<aiVector3D>(props, "GeometricRotation", ok);
  856|  4.91k|    if (ok && GeometricRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (856:9): [True: 4.69k, False: 222]
  |  Branch (856:15): [True: 20, False: 4.67k]
  ------------------
  857|     20|        chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse);
  858|     20|        GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]);
  859|     20|        GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]);
  860|     20|        chain[TransformationComp_GeometricRotationInverse].Inverse();
  861|     20|    }
  862|       |
  863|  4.91k|    const aiVector3D &GeometricTranslation = PropertyGet<aiVector3D>(props, "GeometricTranslation", ok);
  864|  4.91k|    if (ok && GeometricTranslation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (864:9): [True: 4.64k, False: 271]
  |  Branch (864:15): [True: 0, False: 4.64k]
  ------------------
  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|  4.91k|    if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) {
  ------------------
  |  Branch (873:9): [True: 416, False: 4.49k]
  |  Branch (873:43): [True: 416, False: 0]
  ------------------
  874|    416|        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|    416|        NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find(name);
  880|    416|        const unsigned int anim_chain_bitmask = (it == node_anim_chain_bits.end() ? 0 : (*it).second);
  ------------------
  |  Branch (880:50): [True: 140, False: 276]
  ------------------
  881|       |
  882|    416|        unsigned int bit = 0x1;
  883|  7.48k|        for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) {
  ------------------
  |  Branch (883:28): [True: 7.07k, False: 416]
  ------------------
  884|  7.07k|            const TransformationComp comp = static_cast<TransformationComp>(i);
  885|       |
  886|  7.07k|            if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) {
  ------------------
  |  Branch (886:17): [True: 5.46k, False: 1.61k]
  |  Branch (886:43): [True: 5.18k, False: 274]
  ------------------
  887|  5.18k|                continue;
  888|  5.18k|            }
  889|       |
  890|  1.88k|            if (comp == TransformationComp_PostRotation) {
  ------------------
  |  Branch (890:17): [True: 42, False: 1.84k]
  ------------------
  891|     42|                chain[i] = chain[i].Inverse();
  892|     42|            }
  893|       |
  894|  1.88k|            PotentialNode nd;
  895|  1.88k|            nd->mName.Set(NameTransformationChainNode(name, comp));
  896|  1.88k|            nd->mTransformation = chain[i];
  897|       |
  898|       |            // geometric inverses go in a post-node chain
  899|  1.88k|            if (comp == TransformationComp_GeometricScalingInverse ||
  ------------------
  |  Branch (899:17): [True: 258, False: 1.62k]
  ------------------
  900|  1.62k|                    comp == TransformationComp_GeometricRotationInverse ||
  ------------------
  |  Branch (900:21): [True: 20, False: 1.60k]
  ------------------
  901|  1.60k|                    comp == TransformationComp_GeometricTranslationInverse) {
  ------------------
  |  Branch (901:21): [True: 0, False: 1.60k]
  ------------------
  902|    278|                post_output_nodes.emplace_back(std::move(nd));
  903|  1.60k|            } else {
  904|  1.60k|                output_nodes.emplace_back(std::move(nd));
  905|  1.60k|            }
  906|  1.88k|        }
  907|       |
  908|    416|        ai_assert(output_nodes.size());
  909|    416|        return true;
  910|    416|    }
  911|       |
  912|       |    // else, we can just multiply the matrices together
  913|  4.49k|    PotentialNode nd;
  914|       |
  915|       |    // name passed to the method is already unique
  916|  4.49k|    nd->mName.Set(name);
  917|       |    // for (const auto &transform : chain) {
  918|       |    // skip inverse chain for no preservePivots
  919|  67.4k|    for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
  ------------------
  |  Branch (919:59): [True: 62.9k, False: 4.49k]
  ------------------
  920|  62.9k|      nd->mTransformation = nd->mTransformation * chain[i];
  921|  62.9k|    }
  922|  4.49k|    output_nodes.push_back(std::move(nd));
  923|  4.49k|    return false;
  924|  4.91k|}
_ZN6Assimp3FBX12FBXConverter17SetupNodeMetadataERKNS0_5ModelER6aiNode:
  926|  4.91k|void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
  927|  4.91k|    const PropertyTable &props = model.Props();
  928|  4.91k|    DirectPropertyMap unparsedProperties = props.GetUnparsedProperties();
  929|       |
  930|       |    // create metadata on node
  931|  4.91k|    const std::size_t numStaticMetaData = 2;
  932|  4.91k|    aiMetadata *data = aiMetadata::Alloc(static_cast<unsigned int>(unparsedProperties.size() + numStaticMetaData));
  933|  4.91k|    nd.mMetaData = data;
  934|  4.91k|    int index = 0;
  935|       |
  936|       |    // find user defined properties (3ds Max)
  937|  4.91k|    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|  4.91k|    data->Set(index++, "IsNull", model.IsNull() ? true : false);
  ------------------
  |  Branch (939:34): [True: 178, False: 4.73k]
  ------------------
  940|       |
  941|       |    // add unparsed properties to the node's metadata
  942|  14.8k|    for (const DirectPropertyMap::value_type &prop : unparsedProperties) {
  ------------------
  |  Branch (942:52): [True: 14.8k, False: 4.91k]
  ------------------
  943|       |        // Interpret the property as a concrete type
  944|  14.8k|        if (const TypedProperty<bool> *interpretedBool = prop.second->As<TypedProperty<bool>>()) {
  ------------------
  |  Branch (944:40): [True: 2.24k, False: 12.6k]
  ------------------
  945|  2.24k|            data->Set(index++, prop.first, interpretedBool->Value());
  946|  12.6k|        } else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
  ------------------
  |  Branch (946:46): [True: 10.4k, False: 2.21k]
  ------------------
  947|  10.4k|            data->Set(index++, prop.first, interpretedInt->Value());
  948|  10.4k|        } else if (const TypedProperty<uint32_t> *interpretedUInt = prop.second->As<TypedProperty<uint32_t>>()) {
  ------------------
  |  Branch (948:51): [True: 0, False: 2.21k]
  ------------------
  949|      0|            data->Set(index++, prop.first, interpretedUInt->Value());
  950|  2.21k|        } else if (const TypedProperty<uint64_t> *interpretedUint64 = prop.second->As<TypedProperty<uint64_t>>()) {
  ------------------
  |  Branch (950:51): [True: 9, False: 2.20k]
  ------------------
  951|      9|            data->Set(index++, prop.first, interpretedUint64->Value());
  952|  2.20k|        } else if (const TypedProperty<int64_t> *interpretedint64 = prop.second->As<TypedProperty<int64_t>>()) {
  ------------------
  |  Branch (952:50): [True: 0, False: 2.20k]
  ------------------
  953|      0|            data->Set(index++, prop.first, interpretedint64->Value());
  954|  2.20k|        } else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
  ------------------
  |  Branch (954:48): [True: 1.75k, False: 446]
  ------------------
  955|  1.75k|            data->Set(index++, prop.first, interpretedFloat->Value());
  956|  1.75k|        } else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
  ------------------
  |  Branch (956:54): [True: 25, False: 421]
  ------------------
  957|     25|            data->Set(index++, prop.first, aiString(interpretedString->Value()));
  958|    421|        } else if (const TypedProperty<aiVector3D> *interpretedVec3 = prop.second->As<TypedProperty<aiVector3D>>()) {
  ------------------
  |  Branch (958:53): [True: 421, False: 0]
  ------------------
  959|    421|            data->Set(index++, prop.first, interpretedVec3->Value());
  960|    421|        } else {
  961|       |            ai_assert(false);
  962|      0|        }
  963|  14.8k|    }
  964|  4.91k|}
_ZN6Assimp3FBX12FBXConverter12ConvertModelERKNS0_5ModelEP6aiNodeS6_RK12aiMatrix4x4tIfE:
  966|  4.90k|void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
  967|  4.90k|    const std::vector<const Geometry *> &geos = model.GetGeometry();
  968|       |
  969|  4.90k|    std::vector<unsigned int> meshes;
  970|  4.90k|    meshes.reserve(geos.size());
  971|       |
  972|  4.90k|    for (const Geometry *geo : geos) {
  ------------------
  |  Branch (972:30): [True: 788, False: 4.90k]
  ------------------
  973|    788|        const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
  974|    788|        const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
  975|    788|        if (mesh) {
  ------------------
  |  Branch (975:13): [True: 788, False: 0]
  ------------------
  976|    788|            const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node, absolute_transform);
  977|    788|            std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
  978|    788|        } 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|    788|    }
  987|       |
  988|  4.90k|    if (meshes.size()) {
  ------------------
  |  Branch (988:9): [True: 788, False: 4.12k]
  ------------------
  989|    788|        parent->mMeshes = new unsigned int[meshes.size()]();
  990|    788|        parent->mNumMeshes = static_cast<unsigned int>(meshes.size());
  991|       |
  992|    788|        std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes);
  993|    788|    }
  994|  4.90k|}
_ZN6Assimp3FBX12FBXConverter11ConvertMeshERKNS0_12MeshGeometryERKNS0_5ModelEP6aiNodeS9_RK12aiMatrix4x4tIfE:
  997|    788|FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
  998|    788|    std::vector<unsigned int> temp;
  999|       |
 1000|    788|    MeshMap::const_iterator it = meshes_converted.find(&mesh);
 1001|    788|    if (it != meshes_converted.end()) {
  ------------------
  |  Branch (1001:9): [True: 2, False: 786]
  ------------------
 1002|      2|        std::copy((*it).second.begin(), (*it).second.end(), std::back_inserter(temp));
 1003|      2|        return temp;
 1004|      2|    }
 1005|       |
 1006|    786|    const std::vector<aiVector3D> &vertices = mesh.GetVertices();
 1007|    786|    const std::vector<unsigned int> &faces = mesh.GetFaceIndexCounts();
 1008|    786|    if (vertices.empty() || faces.empty()) {
  ------------------
  |  Branch (1008:9): [True: 0, False: 786]
  |  Branch (1008:29): [True: 0, False: 786]
  ------------------
 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|    786|    const MatIndexArray &mindices = mesh.GetMaterialIndices();
 1016|    786|    if (doc.Settings().readMaterials && !mindices.empty()) {
  ------------------
  |  Branch (1016:9): [True: 786, False: 0]
  |  Branch (1016:41): [True: 761, False: 25]
  ------------------
 1017|    761|        const MatIndexArray::value_type base = mindices[0];
 1018|  24.4M|        for (MatIndexArray::value_type index : mindices) {
  ------------------
  |  Branch (1018:46): [True: 24.4M, False: 761]
  ------------------
 1019|  24.4M|            if (index != base) {
  ------------------
  |  Branch (1019:17): [True: 0, False: 24.4M]
  ------------------
 1020|      0|                return ConvertMeshMultiMaterial(mesh, model, absolute_transform, parent, root_node);
 1021|      0|            }
 1022|  24.4M|        }
 1023|    761|    }
 1024|       |
 1025|       |    // faster code-path, just copy the data
 1026|    786|    temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
 1027|    786|    return temp;
 1028|    786|}
_ZN6Assimp3FBX12FBXConverter14SetupEmptyMeshERKNS0_8GeometryEP6aiNode:
 1074|    786|aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) {
 1075|    786|    aiMesh *const out_mesh = new aiMesh();
 1076|    786|    mMeshes.push_back(out_mesh);
 1077|    786|    meshes_converted[&mesh].push_back(static_cast<unsigned int>(mMeshes.size() - 1));
 1078|       |
 1079|       |    // set name
 1080|    786|    std::string name = mesh.Name();
 1081|    786|    if (name.substr(0, 10) == "Geometry::") {
  ------------------
  |  Branch (1081:9): [True: 785, False: 1]
  ------------------
 1082|    785|        name = name.substr(10);
 1083|    785|    }
 1084|       |
 1085|    786|    if (name.length()) {
  ------------------
  |  Branch (1085:9): [True: 764, False: 22]
  ------------------
 1086|    764|        out_mesh->mName.Set(name);
 1087|    764|    } else {
 1088|     22|        out_mesh->mName = parent->mName;
 1089|     22|    }
 1090|       |
 1091|    786|    return out_mesh;
 1092|    786|}
_ZN6Assimp3FBX12FBXConverter25ConvertMeshSingleMaterialERKNS0_12MeshGeometryERKNS0_5ModelERK12aiMatrix4x4tIfEP6aiNodeSD_:
 1123|    786|        aiNode *parent, aiNode *) {
 1124|    786|    const MatIndexArray &mindices = mesh.GetMaterialIndices();
 1125|    786|    aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
 1126|       |
 1127|    786|    const std::vector<aiVector3D> &vertices = mesh.GetVertices();
 1128|    786|    const std::vector<unsigned int> &faces = mesh.GetFaceIndexCounts();
 1129|       |
 1130|       |    // copy vertices
 1131|    786|    out_mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
 1132|    786|    out_mesh->mVertices = new aiVector3D[vertices.size()];
 1133|       |
 1134|    786|    std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices);
 1135|       |
 1136|       |    // generate dummy faces
 1137|    786|    out_mesh->mNumFaces = static_cast<unsigned int>(faces.size());
 1138|    786|    aiFace *fac = out_mesh->mFaces = new aiFace[faces.size()]();
 1139|       |
 1140|    786|    unsigned int cursor = 0;
 1141|   119k|    for (unsigned int pcount : faces) {
  ------------------
  |  Branch (1141:30): [True: 119k, False: 786]
  ------------------
 1142|   119k|        aiFace &f = *fac++;
 1143|   119k|        f.mNumIndices = pcount;
 1144|   119k|        f.mIndices = new unsigned int[pcount];
 1145|   119k|        switch (pcount) {
 1146|      0|            case 1:
  ------------------
  |  Branch (1146:13): [True: 0, False: 119k]
  ------------------
 1147|      0|                out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
 1148|      0|                break;
 1149|      0|            case 2:
  ------------------
  |  Branch (1149:13): [True: 0, False: 119k]
  ------------------
 1150|      0|                out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
 1151|      0|                break;
 1152|  47.7k|            case 3:
  ------------------
  |  Branch (1152:13): [True: 47.7k, False: 72.0k]
  ------------------
 1153|  47.7k|                out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
 1154|  47.7k|                break;
 1155|  72.0k|            default:
  ------------------
  |  Branch (1155:13): [True: 72.0k, False: 47.7k]
  ------------------
 1156|  72.0k|                out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
 1157|  72.0k|                break;
 1158|   119k|        }
 1159|   551k|        for (unsigned int i = 0; i < pcount; ++i) {
  ------------------
  |  Branch (1159:34): [True: 431k, False: 119k]
  ------------------
 1160|   431k|            f.mIndices[i] = cursor++;
 1161|   431k|        }
 1162|   119k|    }
 1163|       |
 1164|       |    // copy normals
 1165|    786|    const std::vector<aiVector3D> &normals = mesh.GetNormals();
 1166|    786|    if (normals.size()) {
  ------------------
  |  Branch (1166:9): [True: 710, False: 76]
  ------------------
 1167|    710|        ai_assert(normals.size() == vertices.size());
 1168|       |
 1169|    710|        out_mesh->mNormals = new aiVector3D[vertices.size()];
 1170|    710|        std::copy(normals.begin(), normals.end(), out_mesh->mNormals);
 1171|    710|    }
 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|    786|    const std::vector<aiVector3D> &tangents = mesh.GetTangents();
 1177|    786|    const std::vector<aiVector3D> *binormals = &mesh.GetBinormals();
 1178|       |
 1179|    786|    if (tangents.size()) {
  ------------------
  |  Branch (1179:9): [True: 13, False: 773]
  ------------------
 1180|     13|        std::vector<aiVector3D> tempBinormals;
 1181|     13|        if (!binormals->size()) {
  ------------------
  |  Branch (1181:13): [True: 1, False: 12]
  ------------------
 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|     13|        if (binormals) {
  ------------------
  |  Branch (1194:13): [True: 12, False: 1]
  ------------------
 1195|     12|            ai_assert(tangents.size() == vertices.size());
 1196|     12|            ai_assert(binormals->size() == vertices.size());
 1197|       |
 1198|     12|            out_mesh->mTangents = new aiVector3D[vertices.size()];
 1199|     12|            std::copy(tangents.begin(), tangents.end(), out_mesh->mTangents);
 1200|       |
 1201|     12|            out_mesh->mBitangents = new aiVector3D[vertices.size()];
 1202|     12|            std::copy(binormals->begin(), binormals->end(), out_mesh->mBitangents);
 1203|     12|        }
 1204|     13|    }
 1205|       |
 1206|       |    // copy texture coords
 1207|  1.53k|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (1207:30): [True: 1.53k, False: 0]
  ------------------
 1208|  1.53k|        const std::vector<aiVector2D> &uvs = mesh.GetTextureCoords(i);
 1209|  1.53k|        if (uvs.empty()) {
  ------------------
  |  Branch (1209:13): [True: 786, False: 746]
  ------------------
 1210|    786|            break;
 1211|    786|        }
 1212|       |
 1213|    746|        aiVector3D *out_uv = out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()];
 1214|   387k|        for (const aiVector2D &v : uvs) {
  ------------------
  |  Branch (1214:34): [True: 387k, False: 746]
  ------------------
 1215|   387k|            *out_uv++ = aiVector3D(v.x, v.y, 0.0f);
 1216|   387k|        }
 1217|       |
 1218|    746|        out_mesh->SetTextureCoordsName(i, aiString(mesh.GetTextureCoordChannelName(i)));
 1219|       |
 1220|    746|        out_mesh->mNumUVComponents[i] = 2;
 1221|    746|    }
 1222|       |
 1223|       |    // copy vertex colors
 1224|    786|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
  ------------------
  |  Branch (1224:30): [True: 786, False: 0]
  ------------------
 1225|    786|        const std::vector<aiColor4D> &colors = mesh.GetVertexColors(i);
 1226|    786|        if (colors.empty()) {
  ------------------
  |  Branch (1226:13): [True: 786, False: 0]
  ------------------
 1227|    786|            break;
 1228|    786|        }
 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|    786|    if (!doc.Settings().readMaterials || mindices.empty()) {
  ------------------
  |  Branch (1234:9): [True: 0, False: 786]
  |  Branch (1234:42): [True: 25, False: 761]
  ------------------
 1235|     25|        FBXImporter::LogError("no material assigned to mesh, setting default material");
 1236|     25|        out_mesh->mMaterialIndex = GetDefaultMaterial();
 1237|    761|    } else {
 1238|    761|        ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
 1239|    761|    }
 1240|       |
 1241|    786|    if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && !doc.Settings().useSkeleton) {
  ------------------
  |  Branch (1241:9): [True: 786, False: 0]
  |  Branch (1241:39): [True: 68, False: 718]
  |  Branch (1241:73): [True: 68, False: 0]
  ------------------
 1242|     68|        ConvertWeights(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr);
 1243|    718|    } else if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && doc.Settings().useSkeleton) {
  ------------------
  |  Branch (1243:16): [True: 718, False: 0]
  |  Branch (1243:46): [True: 0, False: 718]
  |  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|    786|    std::vector<aiAnimMesh *> animMeshes;
 1253|    786|    for (const BlendShape *blendShape : mesh.GetBlendShapes()) {
  ------------------
  |  Branch (1253:39): [True: 0, False: 786]
  ------------------
 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|    786|    const size_t numAnimMeshes = animMeshes.size();
 1293|    786|    if (numAnimMeshes > 0) {
  ------------------
  |  Branch (1293:9): [True: 0, False: 786]
  ------------------
 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|    786|    return static_cast<unsigned int>(mMeshes.size() - 1);
 1301|    786|}
_ZN6Assimp3FBX12FBXConverter14ConvertWeightsEP6aiMeshRKNS0_12MeshGeometryERK12aiMatrix4x4tIfEP6aiNodejPNSt3__16vectorIjNSD_9allocatorIjEEEE:
 1571|     68|        std::vector<unsigned int> *outputVertStartIndices) {
 1572|     68|    ai_assert(geo.DeformerSkin());
 1573|       |
 1574|     68|    std::vector<size_t> out_indices, index_out_indices, count_out_indices;
 1575|       |
 1576|     68|    const Skin &sk = *geo.DeformerSkin();
 1577|       |
 1578|     68|    std::vector<aiBone*> bones;
 1579|     68|    const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
 1580|     68|    ai_assert(no_mat_check || outputVertStartIndices);
 1581|       |
 1582|     68|    try {
 1583|       |        // iterate over the sub deformers
 1584|    627|        for (const Cluster *cluster : sk.Clusters()) {
  ------------------
  |  Branch (1584:37): [True: 627, False: 68]
  ------------------
 1585|    627|            ai_assert(cluster);
 1586|       |
 1587|    627|            const WeightIndexArray &indices = cluster->GetIndices();
 1588|       |
 1589|    627|            const MatIndexArray &mats = geo.GetMaterialIndices();
 1590|       |
 1591|    627|            const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
 1592|       |
 1593|    627|            count_out_indices.clear();
 1594|    627|            index_out_indices.clear();
 1595|    627|            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|   220k|            for (WeightIndexArray::value_type index : indices) {
  ------------------
  |  Branch (1599:53): [True: 220k, False: 627]
  ------------------
 1600|       |
 1601|   220k|                unsigned int count = 0;
 1602|   220k|                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|   220k|                ai_assert(out_idx != nullptr);
 1606|       |
 1607|   220k|                index_out_indices.push_back(no_index_sentinel);
 1608|   220k|                count_out_indices.push_back(0);
 1609|       |
 1610|  1.09M|                for (unsigned int i = 0; i < count; ++i) {
  ------------------
  |  Branch (1610:42): [True: 879k, False: 220k]
  ------------------
 1611|   879k|                    if (no_mat_check || static_cast<size_t>(mats[geo.FaceForVertexIndex(out_idx[i])]) == materialIndex) {
  ------------------
  |  Branch (1611:25): [True: 879k, False: 0]
  |  Branch (1611:41): [True: 0, False: 0]
  ------------------
 1612|       |
 1613|   879k|                        if (index_out_indices.back() == no_index_sentinel) {
  ------------------
  |  Branch (1613:29): [True: 220k, False: 659k]
  ------------------
 1614|   220k|                            index_out_indices.back() = out_indices.size();
 1615|   220k|                        }
 1616|       |
 1617|   879k|                        if (no_mat_check) {
  ------------------
  |  Branch (1617:29): [True: 879k, False: 0]
  ------------------
 1618|   879k|                            out_indices.push_back(out_idx[i]);
 1619|   879k|                        } 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|   879k|                        ++count_out_indices.back();
 1630|   879k|                    }
 1631|   879k|                }
 1632|   220k|            }
 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|    627|            ConvertCluster(bones, cluster, out_indices, index_out_indices,
 1638|    627|                    count_out_indices, absolute_transform, parent);
 1639|    627|        }
 1640|       |
 1641|     68|        bone_map.clear();
 1642|     68|    } catch (std::exception &) {
 1643|      0|        std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>());
 1644|      0|        throw;
 1645|      0|    }
 1646|       |
 1647|     68|    if (bones.empty()) {
  ------------------
  |  Branch (1647:9): [True: 1, False: 67]
  ------------------
 1648|      1|        out->mBones = nullptr;
 1649|      1|        out->mNumBones = 0;
 1650|      1|        return;
 1651|      1|    }
 1652|       |
 1653|     67|    out->mBones = new aiBone *[bones.size()]();
 1654|     67|    out->mNumBones = static_cast<unsigned int>(bones.size());
 1655|     67|    std::swap_ranges(bones.begin(), bones.end(), out->mBones);
 1656|     67|}
_ZN6Assimp3FBX12FBXConverter14ConvertClusterERNSt3__16vectorIP6aiBoneNS2_9allocatorIS5_EEEEPKNS0_7ClusterERNS3_ImNS6_ImEEEESF_SF_RK12aiMatrix4x4tIfEP6aiNode:
 1661|    627|        aiNode *) {
 1662|    627|    ai_assert(cluster != nullptr); // make sure cluster valid
 1663|       |
 1664|    627|    std::string deformer_name = cluster->TargetNode()->Name();
 1665|    627|    aiString bone_name = aiString(FixNodeName(deformer_name));
 1666|       |
 1667|    627|    aiBone *bone = nullptr;
 1668|       |
 1669|    627|    if (bone_map.count(deformer_name)) {
  ------------------
  |  Branch (1669:9): [True: 0, False: 627]
  ------------------
 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|    627|    } else {
 1673|    627|        ASSIMP_LOG_VERBOSE_DEBUG("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
 1674|    627|        bone = new aiBone();
 1675|    627|        bone->mName = bone_name;
 1676|       |
 1677|       |        //bone->mOffsetMatrix = cluster->Transform();
 1678|       |        // store local transform link for post processing
 1679|       |
 1680|    627|        bone->mOffsetMatrix = cluster->TransformLink();
 1681|    627|        bone->mOffsetMatrix.Inverse();
 1682|       |
 1683|    627|        const aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
 1684|       |
 1685|    627|        bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
 1686|       |
 1687|       |        //
 1688|       |        // Now calculate the aiVertexWeights
 1689|       |        //
 1690|       |
 1691|    627|        aiVertexWeight *cursor = nullptr;
 1692|       |
 1693|    627|        bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
 1694|    627|        cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
 1695|       |
 1696|    627|        const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
 1697|    627|        const WeightArray &weights = cluster->GetWeights();
 1698|       |
 1699|    627|        const size_t c = index_out_indices.size();
 1700|   220k|        for (size_t i = 0; i < c; ++i) {
  ------------------
  |  Branch (1700:28): [True: 220k, False: 627]
  ------------------
 1701|   220k|            const size_t index_index = index_out_indices[i];
 1702|       |
 1703|   220k|            if (index_index == no_index_sentinel) {
  ------------------
  |  Branch (1703:17): [True: 0, False: 220k]
  ------------------
 1704|      0|                continue;
 1705|      0|            }
 1706|       |
 1707|   220k|            const size_t cc = count_out_indices[i];
 1708|  1.09M|            for (size_t j = 0; j < cc; ++j) {
  ------------------
  |  Branch (1708:32): [True: 879k, False: 220k]
  ------------------
 1709|       |                // cursor runs from first element relative to the start
 1710|       |                // or relative to the start of the next indexes.
 1711|   879k|                aiVertexWeight &out_weight = *cursor++;
 1712|       |
 1713|   879k|                out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]);
 1714|   879k|                out_weight.mWeight = weights[i];
 1715|   879k|            }
 1716|   220k|        }
 1717|       |
 1718|    627|        bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone));
 1719|    627|    }
 1720|       |
 1721|    627|    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|    627|    local_mesh_bones.push_back(bone);
 1726|    627|}
_ZN6Assimp3FBX12FBXConverter22ConvertMaterialForMeshEP6aiMeshRKNS0_5ModelERKNS0_12MeshGeometryEi:
 1729|    761|        MatIndexArray::value_type materialIndex) {
 1730|       |    // locate source materials for this mesh
 1731|    761|    const std::vector<const Material *> &mats = model.GetMaterials();
 1732|    761|    if (static_cast<unsigned int>(materialIndex) >= mats.size() || materialIndex < 0) {
  ------------------
  |  Branch (1732:9): [True: 25, False: 736]
  |  Branch (1732:68): [True: 0, False: 736]
  ------------------
 1733|     25|        FBXImporter::LogError("material index out of bounds, setting default material");
 1734|     25|        out->mMaterialIndex = GetDefaultMaterial();
 1735|     25|        return;
 1736|     25|    }
 1737|       |
 1738|    736|    const Material *const mat = mats[materialIndex];
 1739|    736|    MaterialMap::const_iterator it = materials_converted.find(mat);
 1740|    736|    if (it != materials_converted.end()) {
  ------------------
  |  Branch (1740:9): [True: 423, False: 313]
  ------------------
 1741|    423|        out->mMaterialIndex = (*it).second;
 1742|    423|        return;
 1743|    423|    }
 1744|       |
 1745|    313|    out->mMaterialIndex = ConvertMaterial(*mat, &geo);
 1746|    313|    materials_converted[mat] = out->mMaterialIndex;
 1747|    313|}
_ZN6Assimp3FBX12FBXConverter18GetDefaultMaterialEv:
 1749|     50|unsigned int FBXConverter::GetDefaultMaterial() {
 1750|     50|    if (defaultMaterialIndex) {
  ------------------
  |  Branch (1750:9): [True: 19, False: 31]
  ------------------
 1751|     19|        return defaultMaterialIndex - 1;
 1752|     19|    }
 1753|       |
 1754|     31|    aiMaterial *out_mat = new aiMaterial();
 1755|     31|    materials.push_back(out_mat);
 1756|       |
 1757|     31|    const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f);
 1758|     31|    out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
 1759|       |
 1760|     31|    aiString s;
 1761|     31|    s.Set(AI_DEFAULT_MATERIAL_NAME);
 1762|       |
 1763|     31|    out_mat->AddProperty(&s, AI_MATKEY_NAME);
 1764|       |
 1765|     31|    defaultMaterialIndex = static_cast<unsigned int>(materials.size());
 1766|     31|    return defaultMaterialIndex - 1;
 1767|     50|}
_ZN6Assimp3FBX12FBXConverter15ConvertMaterialERKNS0_8MaterialEPKNS0_12MeshGeometryE:
 1769|    313|unsigned int FBXConverter::ConvertMaterial(const Material &material, const MeshGeometry *const mesh) {
 1770|    313|    const PropertyTable &props = material.Props();
 1771|       |
 1772|       |    // generate empty output material
 1773|    313|    aiMaterial *out_mat = new aiMaterial();
 1774|    313|    materials_converted[&material] = static_cast<unsigned int>(materials.size());
 1775|       |
 1776|    313|    materials.push_back(out_mat);
 1777|       |
 1778|    313|    aiString str;
 1779|       |
 1780|       |    // strip Material:: prefix
 1781|    313|    std::string name = material.Name();
 1782|    313|    if (name.substr(0, 10) == "Material::") {
  ------------------
  |  Branch (1782:9): [True: 313, False: 0]
  ------------------
 1783|    313|        name = name.substr(10);
 1784|    313|    }
 1785|       |
 1786|       |    // set material name if not empty - this could happen
 1787|       |    // and there should be no key for it in this case.
 1788|    313|    if (name.length()) {
  ------------------
  |  Branch (1788:9): [True: 313, False: 0]
  ------------------
 1789|    313|        str.Set(name);
 1790|    313|        out_mat->AddProperty(&str, AI_MATKEY_NAME);
 1791|    313|    }
 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|    313|    if (material.GetShadingModel() == "phong") {
  ------------------
  |  Branch (1794:9): [True: 305, False: 8]
  ------------------
 1795|    305|        aiShadingMode shadingMode = aiShadingMode_Phong;
 1796|    305|        out_mat->AddProperty<aiShadingMode>(&shadingMode, 1, AI_MATKEY_SHADING_MODEL);
 1797|    305|    }
 1798|       |
 1799|       |    // shading stuff and colors
 1800|    313|    SetShadingPropertiesCommon(out_mat, props);
 1801|    313|    SetShadingPropertiesRaw(out_mat, props, material.Textures(), mesh);
 1802|       |
 1803|       |    // texture assignments
 1804|    313|    SetTextureProperties(out_mat, material.Textures(), mesh);
 1805|    313|    SetTextureProperties(out_mat, material.LayeredTextures(), mesh);
 1806|       |
 1807|    313|    return static_cast<unsigned int>(materials.size() - 1);
 1808|    313|}
_ZN6Assimp3FBX12FBXConverter12ConvertVideoERKNS0_5VideoE:
 1810|      6|unsigned int FBXConverter::ConvertVideo(const Video &video) {
 1811|       |    // generate empty output texture
 1812|      6|    aiTexture *out_tex = new aiTexture();
 1813|      6|    textures.push_back(out_tex);
 1814|       |
 1815|       |    // assuming the texture is compressed
 1816|      6|    out_tex->mWidth = static_cast<unsigned int>(video.ContentLength()); // total data size
 1817|      6|    out_tex->mHeight = 0; // fixed to 0
 1818|       |
 1819|       |    // steal the data from the Video to avoid an additional copy
 1820|      6|    out_tex->pcData = reinterpret_cast<aiTexel *>(const_cast<Video &>(video).RelinquishContent());
 1821|       |
 1822|       |    // try to extract a hint from the file extension
 1823|      6|    const std::string &filename = video.RelativeFilename().empty() ? video.FileName() : video.RelativeFilename();
  ------------------
  |  Branch (1823:35): [True: 0, False: 6]
  ------------------
 1824|      6|    std::string ext = BaseImporter::GetExtension(filename);
 1825|       |
 1826|      6|    if (ext == "jpeg") {
  ------------------
  |  Branch (1826:9): [True: 0, False: 6]
  ------------------
 1827|      0|        ext = "jpg";
 1828|      0|    }
 1829|       |
 1830|      6|    if (ext.size() <= 3) {
  ------------------
  |  Branch (1830:9): [True: 6, False: 0]
  ------------------
 1831|      6|        memcpy(out_tex->achFormatHint, ext.c_str(), ext.size());
 1832|      6|    }
 1833|       |
 1834|      6|    out_tex->mFilename.Set(filename.c_str());
 1835|       |
 1836|      6|    return static_cast<unsigned int>(textures.size() - 1);
 1837|      6|}
_ZN6Assimp3FBX12FBXConverter14GetTexturePathEPKNS0_7TextureE:
 1839|    239|aiString FBXConverter::GetTexturePath(const Texture *tex) {
 1840|    239|    aiString path;
 1841|    239|    path.Set(tex->RelativeFilename());
 1842|       |
 1843|    239|    const Video *media = tex->Media();
 1844|    239|    if (media != nullptr) {
  ------------------
  |  Branch (1844:9): [True: 216, False: 23]
  ------------------
 1845|    216|        bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
 1846|    216|        unsigned int index=0;
 1847|       |
 1848|    216|        VideoMap::const_iterator it = textures_converted.find(media);
 1849|    216|        if (it != textures_converted.end()) {
  ------------------
  |  Branch (1849:13): [True: 4, False: 212]
  ------------------
 1850|      4|            index = (*it).second;
 1851|      4|            textureReady = true;
 1852|    212|        } else {
 1853|    212|            if (media->ContentLength() > 0) {
  ------------------
  |  Branch (1853:17): [True: 0, False: 212]
  ------------------
 1854|      0|                index = ConvertVideo(*media);
 1855|      0|                textures_converted[media] = index;
 1856|      0|                textureReady = true;
 1857|      0|            }
 1858|    212|        }
 1859|       |
 1860|       |        // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
 1861|    216|        if (doc.Settings().useLegacyEmbeddedTextureNaming) {
  ------------------
  |  Branch (1861:13): [True: 0, False: 216]
  ------------------
 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|    216|    }
 1873|       |
 1874|    239|    return path;
 1875|    239|}
_ZN6Assimp3FBX12FBXConverter23TrySetTexturePropertiesEP10aiMaterialRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_7TextureENS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SE_EEEEEERSK_13aiTextureTypePKNS0_12MeshGeometryE:
 1879|  14.4k|        aiTextureType target, const MeshGeometry *const mesh) {
 1880|  14.4k|    TextureMap::const_iterator it = _textures.find(propName);
 1881|  14.4k|    if (it == _textures.end()) {
  ------------------
  |  Branch (1881:9): [True: 14.1k, False: 239]
  ------------------
 1882|  14.1k|        return;
 1883|  14.1k|    }
 1884|       |
 1885|    239|    const Texture *const tex = (*it).second;
 1886|    239|    if (tex != nullptr) {
  ------------------
  |  Branch (1886:9): [True: 239, False: 0]
  ------------------
 1887|    239|        aiString path = GetTexturePath(tex);
 1888|    239|        out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, 0);
 1889|       |
 1890|    239|        aiUVTransform uvTrafo;
 1891|       |        // XXX handle all kinds of UV transformations
 1892|    239|        uvTrafo.mScaling = tex->UVScaling();
 1893|    239|        uvTrafo.mTranslation = tex->UVTranslation();
 1894|    239|        uvTrafo.mRotation = tex->UVRotation();
 1895|    239|        out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0);
 1896|       |
 1897|    239|        const PropertyTable &props = tex->Props();
 1898|       |
 1899|    239|        int uvIndex = 0;
 1900|       |
 1901|    239|        bool ok;
 1902|    239|        const std::string &uvSet = PropertyGet<std::string>(props, "UVSet", ok);
 1903|    239|        if (ok) {
  ------------------
  |  Branch (1903:13): [True: 239, False: 0]
  ------------------
 1904|       |            // "default" is the name which usually appears in the FbxFileTexture template
 1905|    239|            if (uvSet != "default" && uvSet.length()) {
  ------------------
  |  Branch (1905:17): [True: 239, False: 0]
  |  Branch (1905:39): [True: 17, False: 222]
  ------------------
 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|     17|                const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(),
 1918|     17|                        std::find(materials.begin(), materials.end(), out_mat)));
 1919|       |
 1920|     17|                uvIndex = -1;
 1921|     17|                if (!mesh) {
  ------------------
  |  Branch (1921:21): [True: 0, False: 17]
  ------------------
 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|     17|                } else {
 1958|     17|                    int index = -1;
 1959|     27|                    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (1959:46): [True: 27, False: 0]
  ------------------
 1960|     27|                        if (mesh->GetTextureCoords(i).empty()) {
  ------------------
  |  Branch (1960:29): [True: 10, False: 17]
  ------------------
 1961|     10|                            break;
 1962|     10|                        }
 1963|     17|                        const std::string &name = mesh->GetTextureCoordChannelName(i);
 1964|     17|                        if (name == uvSet) {
  ------------------
  |  Branch (1964:29): [True: 7, False: 10]
  ------------------
 1965|      7|                            index = static_cast<int>(i);
 1966|      7|                            break;
 1967|      7|                        }
 1968|     17|                    }
 1969|     17|                    if (index == -1) {
  ------------------
  |  Branch (1969:25): [True: 10, False: 7]
  ------------------
 1970|     10|                        FBXImporter::LogWarn("did not find UV channel named ", uvSet, " in a mesh using this material");
 1971|     10|                    }
 1972|       |
 1973|     17|                    if (uvIndex == -1) {
  ------------------
  |  Branch (1973:25): [True: 17, False: 0]
  ------------------
 1974|     17|                        uvIndex = index;
 1975|     17|                    }
 1976|     17|                }
 1977|       |
 1978|     17|                if (uvIndex == -1) {
  ------------------
  |  Branch (1978:21): [True: 10, False: 7]
  ------------------
 1979|     10|                    FBXImporter::LogWarn("failed to resolve UV channel ", uvSet, ", using first UV channel");
 1980|     10|                    uvIndex = 0;
 1981|     10|                }
 1982|     17|            }
 1983|    239|        }
 1984|       |
 1985|       |        out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0);
 1986|    239|    }
 1987|    239|}
_ZN6Assimp3FBX12FBXConverter23TrySetTexturePropertiesEP10aiMaterialRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_14LayeredTextureENS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SE_EEEEEERSK_13aiTextureTypePKNS0_12MeshGeometryE:
 1991|  4.38k|        aiTextureType target, const MeshGeometry *const mesh) {
 1992|  4.38k|    LayeredTextureMap::const_iterator it = layeredTextures.find(propName);
 1993|  4.38k|    if (it == layeredTextures.end()) {
  ------------------
  |  Branch (1993:9): [True: 4.38k, False: 0]
  ------------------
 1994|  4.38k|        return;
 1995|  4.38k|    }
 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|    313|void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const TextureMap &_textures, const MeshGeometry *const mesh) {
 2110|    313|    TrySetTextureProperties(out_mat, _textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
 2111|    313|    TrySetTextureProperties(out_mat, _textures, "AmbientColor", aiTextureType_AMBIENT, mesh);
 2112|    313|    TrySetTextureProperties(out_mat, _textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
 2113|    313|    TrySetTextureProperties(out_mat, _textures, "SpecularColor", aiTextureType_SPECULAR, mesh);
 2114|    313|    TrySetTextureProperties(out_mat, _textures, "SpecularFactor", aiTextureType_SPECULAR, mesh);
 2115|    313|    TrySetTextureProperties(out_mat, _textures, "TransparentColor", aiTextureType_OPACITY, mesh);
 2116|    313|    TrySetTextureProperties(out_mat, _textures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
 2117|    313|    TrySetTextureProperties(out_mat, _textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
 2118|    313|    TrySetTextureProperties(out_mat, _textures, "NormalMap", aiTextureType_NORMALS, mesh);
 2119|    313|    TrySetTextureProperties(out_mat, _textures, "Bump", aiTextureType_HEIGHT, mesh);
 2120|    313|    TrySetTextureProperties(out_mat, _textures, "ShininessExponent", aiTextureType_SHININESS, mesh);
 2121|    313|    TrySetTextureProperties(out_mat, _textures, "TransparencyFactor", aiTextureType_OPACITY, mesh);
 2122|    313|    TrySetTextureProperties(out_mat, _textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh);
 2123|    313|    TrySetTextureProperties(out_mat, _textures, "ReflectionFactor", aiTextureType_METALNESS, mesh);
 2124|       |    //Maya counterparts
 2125|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh);
 2126|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh);
 2127|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh);
 2128|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh);
 2129|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh);
 2130|       |
 2131|       |    // Maya PBR
 2132|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|baseColor", aiTextureType_BASE_COLOR, mesh);
 2133|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|normalCamera", aiTextureType_NORMAL_CAMERA, mesh);
 2134|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|emissionColor", aiTextureType_EMISSION_COLOR, mesh);
 2135|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|metalness", aiTextureType_METALNESS, mesh);
 2136|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|diffuseRoughness", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2137|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|base", aiTextureType_MAYA_BASE, mesh);
 2138|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|specular", aiTextureType_MAYA_SPECULAR, mesh);
 2139|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|specularColor", aiTextureType_MAYA_SPECULAR_COLOR, mesh);
 2140|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|specularRoughness", aiTextureType_MAYA_SPECULAR_ROUGHNESS, mesh);
 2141|       |
 2142|       |    // Maya stingray
 2143|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_color_map", aiTextureType_BASE_COLOR, mesh);
 2144|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_normal_map", aiTextureType_NORMAL_CAMERA, mesh);
 2145|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_emissive_map", aiTextureType_EMISSION_COLOR, mesh);
 2146|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_metallic_map", aiTextureType_METALNESS, mesh);
 2147|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2148|    313|    TrySetTextureProperties(out_mat, _textures, "Maya|TEX_ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh);
 2149|       |
 2150|       |    // 3DSMax Physical material
 2151|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh);
 2152|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh);
 2153|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh);
 2154|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh);
 2155|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2156|       |
 2157|       |    // 3DSMax PBR materials
 2158|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|base_color_map", aiTextureType_BASE_COLOR, mesh);
 2159|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|norm_map", aiTextureType_NORMAL_CAMERA, mesh);
 2160|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|emit_color_map", aiTextureType_EMISSION_COLOR, mesh);
 2161|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh);
 2162|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|opacity_map", aiTextureType_OPACITY, mesh);
 2163|       |    // Metalness/Roughness material type
 2164|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|metalness_map", aiTextureType_METALNESS, mesh);
 2165|       |    // Specular/Gloss material type
 2166|    313|    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|specular_map", aiTextureType_SPECULAR, mesh);
 2167|       |
 2168|       |    // Glossiness vs roughness in 3ds Max Pbr Materials
 2169|    313|    int useGlossiness;
 2170|    313|    if (out_mat->Get("$raw.3dsMax|main|useGlossiness", aiTextureType_NONE, 0, useGlossiness) == aiReturn_SUCCESS) {
  ------------------
  |  Branch (2170:9): [True: 2, False: 311]
  ------------------
 2171|       |        // These textures swap meaning if ((useGlossiness == 1) != (material type is Specular/Gloss))
 2172|      2|        if (useGlossiness == 1) {
  ------------------
  |  Branch (2172:13): [True: 0, False: 2]
  ------------------
 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|      2|        else if (useGlossiness == 2) {
  ------------------
  |  Branch (2176:18): [True: 2, False: 0]
  ------------------
 2177|      2|            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2178|      2|            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|glossiness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
 2179|      2|        }
 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|      2|    }
 2184|    313|}
_ZN6Assimp3FBX12FBXConverter20SetTexturePropertiesEP10aiMaterialRKNSt3__113unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_14LayeredTextureENS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SE_EEEEEEPKNS0_12MeshGeometryE:
 2186|    313|void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const LayeredTextureMap &layeredTextures, const MeshGeometry *const mesh) {
 2187|    313|    TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
 2188|    313|    TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh);
 2189|    313|    TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
 2190|    313|    TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh);
 2191|    313|    TrySetTextureProperties(out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh);
 2192|    313|    TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh);
 2193|    313|    TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
 2194|    313|    TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
 2195|    313|    TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh);
 2196|    313|    TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh);
 2197|    313|    TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh);
 2198|    313|    TrySetTextureProperties(out_mat, layeredTextures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh);
 2199|    313|    TrySetTextureProperties(out_mat, layeredTextures, "TransparencyFactor", aiTextureType_OPACITY, mesh);
 2200|    313|    TrySetTextureProperties(out_mat, layeredTextures, "ReflectionFactor", aiTextureType_METALNESS, mesh);
 2201|    313|}
_ZN6Assimp3FBX12FBXConverter24GetColorPropertyFactoredERKNS0_13PropertyTableERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEESD_Rbb:
 2204|  1.25k|        const std::string &factorName, bool &result, bool useTemplate) {
 2205|  1.25k|    result = true;
 2206|       |
 2207|  1.25k|    bool ok;
 2208|  1.25k|    aiVector3D BaseColor = PropertyGet<aiVector3D>(props, colorName, ok, useTemplate);
 2209|  1.25k|    if (!ok) {
  ------------------
  |  Branch (2209:9): [True: 27, False: 1.22k]
  ------------------
 2210|     27|        result = false;
 2211|     27|        return aiColor3D(0.0f, 0.0f, 0.0f);
 2212|     27|    }
 2213|       |
 2214|       |    // if no factor name, return the colour as is
 2215|  1.22k|    if (factorName.empty()) {
  ------------------
  |  Branch (2215:9): [True: 0, False: 1.22k]
  ------------------
 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|  1.22k|    float factor = PropertyGet<float>(props, factorName, ok, useTemplate);
 2221|  1.22k|    if (ok) {
  ------------------
  |  Branch (2221:9): [True: 1.18k, False: 39]
  ------------------
 2222|  1.18k|        BaseColor *= factor;
 2223|  1.18k|    }
 2224|  1.22k|    return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z);
 2225|  1.22k|}
_ZN6Assimp3FBX12FBXConverter28GetColorPropertyFromMaterialERKNS0_13PropertyTableERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERb:
 2228|    939|        bool &result) {
 2229|    939|    return GetColorPropertyFactored(props, baseName + "Color", baseName + "Factor", result, true);
 2230|    939|}
_ZN6Assimp3FBX12FBXConverter16GetColorPropertyERKNS0_13PropertyTableERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEERbb:
 2233|    947|        bool &result, bool useTemplate) {
 2234|    947|    result = true;
 2235|    947|    bool ok;
 2236|    947|    const aiVector3D &ColorVec = PropertyGet<aiVector3D>(props, colorName, ok, useTemplate);
 2237|    947|    if (!ok) {
  ------------------
  |  Branch (2237:9): [True: 342, False: 605]
  ------------------
 2238|    342|        result = false;
 2239|    342|        return aiColor3D(0.0f, 0.0f, 0.0f);
 2240|    342|    }
 2241|    605|    return aiColor3D(ColorVec.x, ColorVec.y, ColorVec.z);
 2242|    947|}
_ZN6Assimp3FBX12FBXConverter26SetShadingPropertiesCommonEP10aiMaterialRKNS0_13PropertyTableE:
 2244|    313|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|    313|    bool ok;
 2254|       |
 2255|    313|    const aiColor3D &Diffuse = GetColorPropertyFromMaterial(props, "Diffuse", ok);
 2256|    313|    if (ok) {
  ------------------
  |  Branch (2256:9): [True: 308, False: 5]
  ------------------
 2257|    308|        out_mat->AddProperty(&Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
 2258|    308|    }
 2259|       |
 2260|    313|    const aiColor3D &Emissive = GetColorPropertyFromMaterial(props, "Emissive", ok);
 2261|    313|    if (ok) {
  ------------------
  |  Branch (2261:9): [True: 305, False: 8]
  ------------------
 2262|    305|        out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE);
 2263|    305|    } else {
 2264|      8|        const aiColor3D &emissiveColor = GetColorProperty(props, "Maya|emissive", ok);
 2265|      8|        if (ok) {
  ------------------
  |  Branch (2265:13): [True: 0, False: 8]
  ------------------
 2266|      0|            out_mat->AddProperty(&emissiveColor, 1, AI_MATKEY_COLOR_EMISSIVE);
 2267|      0|        }
 2268|      8|     }
 2269|       |
 2270|    313|    const aiColor3D &Ambient = GetColorPropertyFromMaterial(props, "Ambient", ok);
 2271|    313|    if (ok) {
  ------------------
  |  Branch (2271:9): [True: 310, False: 3]
  ------------------
 2272|    310|        out_mat->AddProperty(&Ambient, 1, AI_MATKEY_COLOR_AMBIENT);
 2273|    310|    }
 2274|       |
 2275|       |    // we store specular factor as SHININESS_STRENGTH, so just get the color
 2276|    313|    const aiColor3D &Specular = GetColorProperty(props, "SpecularColor", ok, true);
 2277|    313|    if (ok) {
  ------------------
  |  Branch (2277:9): [True: 304, False: 9]
  ------------------
 2278|    304|        out_mat->AddProperty(&Specular, 1, AI_MATKEY_COLOR_SPECULAR);
 2279|    304|    }
 2280|       |
 2281|       |    // and also try to get SHININESS_STRENGTH
 2282|    313|    const float SpecularFactor = PropertyGet<float>(props, "SpecularFactor", ok, true);
 2283|    313|    if (ok) {
  ------------------
  |  Branch (2283:9): [True: 304, False: 9]
  ------------------
 2284|    304|        out_mat->AddProperty(&SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH);
 2285|    304|    }
 2286|       |
 2287|       |    // and the specular exponent
 2288|    313|    const float ShininessExponent = PropertyGet<float>(props, "ShininessExponent", ok);
 2289|    313|    if (ok) {
  ------------------
  |  Branch (2289:9): [True: 303, False: 10]
  ------------------
 2290|    303|        out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS);
 2291|       |         // Match Blender behavior to extract roughness when only shininess is present
 2292|    303|        const float roughness = 1.0f - (sqrt(ShininessExponent) / 10.0f);
 2293|    303|        out_mat->AddProperty(&roughness, 1, AI_MATKEY_ROUGHNESS_FACTOR);
 2294|    303|    }
 2295|       |
 2296|       |    // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
 2297|    313|    const aiColor3D &Transparent = GetColorPropertyFactored(props, "TransparentColor", "TransparencyFactor", ok);
 2298|    313|    float CalculatedOpacity = 1.0f;
 2299|    313|    if (ok) {
  ------------------
  |  Branch (2299:9): [True: 302, False: 11]
  ------------------
 2300|    302|        out_mat->AddProperty(&Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
 2301|       |        // as calculated by FBX SDK 2017:
 2302|    302|        CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f);
 2303|    302|    }
 2304|       |
 2305|       |    // try to get the transparency factor
 2306|    313|    const float TransparencyFactor = PropertyGet<float>(props, "TransparencyFactor", ok);
 2307|    313|    if (ok) {
  ------------------
  |  Branch (2307:9): [True: 290, False: 23]
  ------------------
 2308|    290|        out_mat->AddProperty(&TransparencyFactor, 1, AI_MATKEY_TRANSPARENCYFACTOR);
 2309|    290|    }
 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|    313|    const float Opacity = PropertyGet<float>(props, "Opacity", ok);
 2326|    313|    if (ok) {
  ------------------
  |  Branch (2326:9): [True: 287, False: 26]
  ------------------
 2327|    287|        out_mat->AddProperty(&Opacity, 1, AI_MATKEY_OPACITY);
 2328|    287|    } else if (CalculatedOpacity != 1.0) {
  ------------------
  |  Branch (2328:16): [True: 15, False: 11]
  ------------------
 2329|     15|        out_mat->AddProperty(&CalculatedOpacity, 1, AI_MATKEY_OPACITY);
 2330|     15|    }
 2331|       |
 2332|       |    // reflection color and factor are stored separately
 2333|    313|    const aiColor3D &Reflection = GetColorProperty(props, "ReflectionColor", ok, true);
 2334|    313|    if (ok) {
  ------------------
  |  Branch (2334:9): [True: 301, False: 12]
  ------------------
 2335|    301|        out_mat->AddProperty(&Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE);
 2336|    301|    }
 2337|       |
 2338|    313|    float ReflectionFactor = PropertyGet<float>(props, "ReflectionFactor", ok, true);
 2339|    313|    if (ok) {
  ------------------
  |  Branch (2339:9): [True: 301, False: 12]
  ------------------
 2340|    301|        out_mat->AddProperty(&ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY);
 2341|    301|    }
 2342|       |
 2343|    313|    const float BumpFactor = PropertyGet<float>(props, "BumpFactor", ok);
 2344|    313|    if (ok) {
  ------------------
  |  Branch (2344:9): [True: 291, False: 22]
  ------------------
 2345|    291|        out_mat->AddProperty(&BumpFactor, 1, AI_MATKEY_BUMPSCALING);
 2346|    291|    }
 2347|       |
 2348|    313|    const float DispFactor = PropertyGet<float>(props, "DisplacementFactor", ok);
 2349|    313|    if (ok) {
  ------------------
  |  Branch (2349:9): [True: 287, False: 26]
  ------------------
 2350|    287|        out_mat->AddProperty(&DispFactor, 1, "$mat.displacementscaling", 0, 0);
 2351|    287|    }
 2352|       |
 2353|       |    // PBR material information
 2354|    313|    const aiColor3D &baseColor = GetColorProperty(props, "Maya|base_color", ok);
 2355|    313|    if (ok) {
  ------------------
  |  Branch (2355:9): [True: 0, False: 313]
  ------------------
 2356|      0|        out_mat->AddProperty(&baseColor, 1, AI_MATKEY_BASE_COLOR);
 2357|      0|    }
 2358|       |
 2359|    313|    const float useColorMap = PropertyGet<float>(props, "Maya|use_color_map", ok);
 2360|    313|    if (ok) {
  ------------------
  |  Branch (2360:9): [True: 0, False: 313]
  ------------------
 2361|      0|        out_mat->AddProperty(&useColorMap, 1, AI_MATKEY_USE_COLOR_MAP);
 2362|      0|    }
 2363|       |
 2364|    313|    const float useMetallicMap = PropertyGet<float>(props, "Maya|use_metallic_map", ok);
 2365|    313|    if (ok) {
  ------------------
  |  Branch (2365:9): [True: 0, False: 313]
  ------------------
 2366|      0|        out_mat->AddProperty(&useMetallicMap, 1, AI_MATKEY_USE_METALLIC_MAP);
 2367|      0|    }
 2368|       |
 2369|    313|    const float metallicFactor = PropertyGet<float>(props, "Maya|metallic", ok);
 2370|    313|    if (ok) {
  ------------------
  |  Branch (2370:9): [True: 0, False: 313]
  ------------------
 2371|      0|        out_mat->AddProperty(&metallicFactor, 1, AI_MATKEY_METALLIC_FACTOR);
 2372|      0|    }
 2373|       |
 2374|    313|    const float useRoughnessMap = PropertyGet<float>(props, "Maya|use_roughness_map", ok);
 2375|    313|    if (ok) {
  ------------------
  |  Branch (2375:9): [True: 0, False: 313]
  ------------------
 2376|      0|        out_mat->AddProperty(&useRoughnessMap, 1, AI_MATKEY_USE_ROUGHNESS_MAP);
 2377|      0|    }
 2378|       |
 2379|    313|    const float roughnessFactor = PropertyGet<float>(props, "Maya|roughness", ok);
 2380|    313|    if (ok) {
  ------------------
  |  Branch (2380:9): [True: 0, False: 313]
  ------------------
 2381|      0|        out_mat->AddProperty(&roughnessFactor, 1, AI_MATKEY_ROUGHNESS_FACTOR);
 2382|      0|    }
 2383|       |
 2384|    313|    const float useEmissiveMap = PropertyGet<float>(props, "Maya|use_emissive_map", ok);
 2385|    313|    if (ok) {
  ------------------
  |  Branch (2385:9): [True: 0, False: 313]
  ------------------
 2386|      0|        out_mat->AddProperty(&useEmissiveMap, 1, AI_MATKEY_USE_EMISSIVE_MAP);
 2387|      0|    }
 2388|       |
 2389|    313|    const float emissiveIntensity = PropertyGet<float>(props, "Maya|emissive_intensity", ok);
 2390|    313|    if (ok) {
  ------------------
  |  Branch (2390:9): [True: 0, False: 313]
  ------------------
 2391|      0|        out_mat->AddProperty(&emissiveIntensity, 1, AI_MATKEY_EMISSIVE_INTENSITY);
 2392|      0|    }
 2393|       |
 2394|    313|    const float useAOMap = PropertyGet<float>(props, "Maya|use_ao_map", ok);
 2395|    313|    if (ok) {
  ------------------
  |  Branch (2395:9): [True: 0, False: 313]
  ------------------
 2396|       |        out_mat->AddProperty(&useAOMap, 1, AI_MATKEY_USE_AO_MAP);
 2397|      0|    }
 2398|    313|}
_ZN6Assimp3FBX12FBXConverter23SetShadingPropertiesRawEP10aiMaterialRKNS0_13PropertyTableERKNSt3__113unordered_mapINS7_12basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEPKNS0_7TextureENS7_4hashISE_EENS7_8equal_toISE_EENSC_INS7_4pairIKSE_SH_EEEEEEPKNS0_12MeshGeometryE:
 2400|    313|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|    313|    const std::string prefix = "$raw.";
 2404|       |
 2405|    566|    for (const DirectPropertyMap::value_type &prop : props.GetUnparsedProperties()) {
  ------------------
  |  Branch (2405:52): [True: 566, False: 313]
  ------------------
 2406|       |
 2407|    566|        std::string name = prefix + prop.first;
 2408|       |
 2409|    566|        if (const TypedProperty<aiVector3D> *interpretedVec3 = prop.second->As<TypedProperty<aiVector3D>>()) {
  ------------------
  |  Branch (2409:46): [True: 145, False: 421]
  ------------------
 2410|    145|            out_mat->AddProperty(&interpretedVec3->Value(), 1, name.c_str(), 0, 0);
 2411|    421|        } else if (const TypedProperty<aiColor3D> *interpretedCol3 = prop.second->As<TypedProperty<aiColor3D>>()) {
  ------------------
  |  Branch (2411:52): [True: 0, False: 421]
  ------------------
 2412|      0|            out_mat->AddProperty(&interpretedCol3->Value(), 1, name.c_str(), 0, 0);
 2413|    421|        } else if (const TypedProperty<aiColor4D> *interpretedCol4 = prop.second->As<TypedProperty<aiColor4D>>()) {
  ------------------
  |  Branch (2413:52): [True: 4, False: 417]
  ------------------
 2414|      4|            out_mat->AddProperty(&interpretedCol4->Value(), 1, name.c_str(), 0, 0);
 2415|    417|        } else if (const TypedProperty<float> *interpretedFloat = prop.second->As<TypedProperty<float>>()) {
  ------------------
  |  Branch (2415:48): [True: 344, False: 73]
  ------------------
 2416|    344|            out_mat->AddProperty(&interpretedFloat->Value(), 1, name.c_str(), 0, 0);
 2417|    344|        } else if (const TypedProperty<int> *interpretedInt = prop.second->As<TypedProperty<int>>()) {
  ------------------
  |  Branch (2417:46): [True: 8, False: 65]
  ------------------
 2418|      8|            out_mat->AddProperty(&interpretedInt->Value(), 1, name.c_str(), 0, 0);
 2419|     65|        } else if (const TypedProperty<bool> *interpretedBool = prop.second->As<TypedProperty<bool>>()) {
  ------------------
  |  Branch (2419:47): [True: 32, False: 33]
  ------------------
 2420|     32|            int value = interpretedBool->Value() ? 1 : 0;
  ------------------
  |  Branch (2420:25): [True: 4, False: 28]
  ------------------
 2421|     32|            out_mat->AddProperty(&value, 1, name.c_str(), 0, 0);
 2422|     33|        } else if (const TypedProperty<std::string> *interpretedString = prop.second->As<TypedProperty<std::string>>()) {
  ------------------
  |  Branch (2422:54): [True: 33, False: 0]
  ------------------
 2423|     33|            const aiString value = aiString(interpretedString->Value());
 2424|     33|            out_mat->AddProperty(&value, name.c_str(), 0, 0);
 2425|     33|        }
 2426|    566|    }
 2427|       |
 2428|       |    // Add the textures' properties
 2429|       |
 2430|    552|    for (TextureMap::const_iterator it = _textures.begin(); it != _textures.end(); ++it) {
  ------------------
  |  Branch (2430:61): [True: 239, False: 313]
  ------------------
 2431|       |
 2432|    239|        std::string name = prefix + it->first;
 2433|       |
 2434|    239|        const Texture *const tex = it->second;
 2435|    239|        if (tex != nullptr) {
  ------------------
  |  Branch (2435:13): [True: 239, False: 0]
  ------------------
 2436|    239|            aiString path;
 2437|    239|            path.Set(tex->RelativeFilename());
 2438|       |
 2439|    239|            const Video *media = tex->Media();
 2440|    239|            if (media != nullptr && media->ContentLength() > 0) {
  ------------------
  |  Branch (2440:17): [True: 216, False: 23]
  |  Branch (2440:37): [True: 4, False: 212]
  ------------------
 2441|      4|                unsigned int index;
 2442|       |
 2443|      4|                VideoMap::const_iterator videoIt = textures_converted.find(media);
 2444|      4|                if (videoIt != textures_converted.end()) {
  ------------------
  |  Branch (2444:21): [True: 0, False: 4]
  ------------------
 2445|      0|                    index = videoIt->second;
 2446|      4|                } else {
 2447|      4|                    index = ConvertVideo(*media);
 2448|      4|                    textures_converted[media] = index;
 2449|      4|                }
 2450|       |
 2451|       |                // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
 2452|      4|                path.data[0] = '*';
 2453|      4|                path.length = 1 + ASSIMP_itoa10(path.data + 1, AI_MAXLEN - 1, index);
 2454|      4|            }
 2455|       |
 2456|    239|            out_mat->AddProperty(&path, (name + "|file").c_str(), aiTextureType_UNKNOWN, 0);
 2457|       |
 2458|    239|            aiUVTransform uvTrafo;
 2459|       |            // XXX handle all kinds of UV transformations
 2460|    239|            uvTrafo.mScaling = tex->UVScaling();
 2461|    239|            uvTrafo.mTranslation = tex->UVTranslation();
 2462|    239|            uvTrafo.mRotation = tex->UVRotation();
 2463|    239|            out_mat->AddProperty(&uvTrafo, 1, (name + "|uvtrafo").c_str(), aiTextureType_UNKNOWN, 0);
 2464|       |
 2465|    239|            int uvIndex = 0;
 2466|       |
 2467|    239|            bool uvFound = false;
 2468|    239|            const std::string &uvSet = PropertyGet<std::string>(tex->Props(), "UVSet", uvFound);
 2469|    239|            if (uvFound) {
  ------------------
  |  Branch (2469:17): [True: 239, False: 0]
  ------------------
 2470|       |                // "default" is the name which usually appears in the FbxFileTexture template
 2471|    239|                if (uvSet != "default" && uvSet.length()) {
  ------------------
  |  Branch (2471:21): [True: 239, False: 0]
  |  Branch (2471:43): [True: 17, False: 222]
  ------------------
 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|     17|                    std::vector<aiMaterial *>::iterator materialIt = std::find(materials.begin(), materials.end(), out_mat);
 2484|     17|                    const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), materialIt));
 2485|       |
 2486|     17|                    uvIndex = -1;
 2487|     17|                    if (!mesh) {
  ------------------
  |  Branch (2487:25): [True: 0, False: 17]
  ------------------
 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|     17|                    } else {
 2522|     17|                        int index = -1;
 2523|     27|                        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (2523:50): [True: 27, False: 0]
  ------------------
 2524|     27|                            if (mesh->GetTextureCoords(i).empty()) {
  ------------------
  |  Branch (2524:33): [True: 10, False: 17]
  ------------------
 2525|     10|                                break;
 2526|     10|                            }
 2527|     17|                            const std::string &curName = mesh->GetTextureCoordChannelName(i);
 2528|     17|                            if (curName == uvSet) {
  ------------------
  |  Branch (2528:33): [True: 7, False: 10]
  ------------------
 2529|      7|                                index = static_cast<int>(i);
 2530|      7|                                break;
 2531|      7|                            }
 2532|     17|                        }
 2533|     17|                        if (index == -1) {
  ------------------
  |  Branch (2533:29): [True: 10, False: 7]
  ------------------
 2534|     10|                            FBXImporter::LogWarn("did not find UV channel named ", uvSet, " in a mesh using this material");
 2535|     10|                        }
 2536|       |
 2537|     17|                        if (uvIndex == -1) {
  ------------------
  |  Branch (2537:29): [True: 17, False: 0]
  ------------------
 2538|     17|                            uvIndex = index;
 2539|     17|                        }
 2540|     17|                    }
 2541|       |
 2542|     17|                    if (uvIndex == -1) {
  ------------------
  |  Branch (2542:25): [True: 10, False: 7]
  ------------------
 2543|     10|                        FBXImporter::LogWarn("failed to resolve UV channel ", uvSet, ", using first UV channel");
 2544|     10|                        uvIndex = 0;
 2545|     10|                    }
 2546|     17|                }
 2547|    239|            }
 2548|       |
 2549|    239|            out_mat->AddProperty(&uvIndex, 1, (name + "|uvwsrc").c_str(), aiTextureType_UNKNOWN, 0);
 2550|    239|        }
 2551|    239|    }
 2552|    313|}
_ZN6Assimp3FBX12FBXConverter17FrameRateToDoubleENS0_18FileGlobalSettings9FrameRateEd:
 2554|    355|double FBXConverter::FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal) {
 2555|    355|    switch (fp) {
  ------------------
  |  Branch (2555:13): [True: 355, False: 0]
  ------------------
 2556|     39|        case FileGlobalSettings::FrameRate_DEFAULT:
  ------------------
  |  Branch (2556:9): [True: 39, False: 316]
  ------------------
 2557|     39|            return 1.0;
 2558|       |
 2559|      0|        case FileGlobalSettings::FrameRate_120:
  ------------------
  |  Branch (2559:9): [True: 0, False: 355]
  ------------------
 2560|      0|            return 120.0;
 2561|       |
 2562|      0|        case FileGlobalSettings::FrameRate_100:
  ------------------
  |  Branch (2562:9): [True: 0, False: 355]
  ------------------
 2563|      0|            return 100.0;
 2564|       |
 2565|      0|        case FileGlobalSettings::FrameRate_60:
  ------------------
  |  Branch (2565:9): [True: 0, False: 355]
  ------------------
 2566|      0|            return 60.0;
 2567|       |
 2568|      0|        case FileGlobalSettings::FrameRate_50:
  ------------------
  |  Branch (2568:9): [True: 0, False: 355]
  ------------------
 2569|      0|            return 50.0;
 2570|       |
 2571|      0|        case FileGlobalSettings::FrameRate_48:
  ------------------
  |  Branch (2571:9): [True: 0, False: 355]
  ------------------
 2572|      0|            return 48.0;
 2573|       |
 2574|     19|        case FileGlobalSettings::FrameRate_30:
  ------------------
  |  Branch (2574:9): [True: 19, False: 336]
  ------------------
 2575|     19|        case FileGlobalSettings::FrameRate_30_DROP:
  ------------------
  |  Branch (2575:9): [True: 0, False: 355]
  ------------------
 2576|     19|            return 30.0;
 2577|       |
 2578|      0|        case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME:
  ------------------
  |  Branch (2578:9): [True: 0, False: 355]
  ------------------
 2579|      0|        case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME:
  ------------------
  |  Branch (2579:9): [True: 0, False: 355]
  ------------------
 2580|      0|            return 29.9700262;
 2581|       |
 2582|      0|        case FileGlobalSettings::FrameRate_PAL:
  ------------------
  |  Branch (2582:9): [True: 0, False: 355]
  ------------------
 2583|      0|            return 25.0;
 2584|       |
 2585|    297|        case FileGlobalSettings::FrameRate_CINEMA:
  ------------------
  |  Branch (2585:9): [True: 297, False: 58]
  ------------------
 2586|    297|            return 24.0;
 2587|       |
 2588|      0|        case FileGlobalSettings::FrameRate_1000:
  ------------------
  |  Branch (2588:9): [True: 0, False: 355]
  ------------------
 2589|      0|            return 1000.0;
 2590|       |
 2591|      0|        case FileGlobalSettings::FrameRate_CINEMA_ND:
  ------------------
  |  Branch (2591:9): [True: 0, False: 355]
  ------------------
 2592|      0|            return 23.976;
 2593|       |
 2594|      0|        case FileGlobalSettings::FrameRate_CUSTOM:
  ------------------
  |  Branch (2594:9): [True: 0, False: 355]
  ------------------
 2595|      0|            return customFPSVal;
 2596|       |
 2597|      0|        case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings
  ------------------
  |  Branch (2597:9): [True: 0, False: 355]
  ------------------
 2598|      0|            break;
 2599|    355|    }
 2600|       |
 2601|    355|    ai_assert(false);
 2602|       |
 2603|      0|    return -1.0f;
 2604|    355|}
_ZN6Assimp3FBX12FBXConverter17ConvertAnimationsEv:
 2606|    355|void FBXConverter::ConvertAnimations() {
 2607|       |    // first of all determine framerate
 2608|    355|    const FileGlobalSettings::FrameRate fps = doc.GlobalSettings().TimeMode();
 2609|    355|    const float custom = doc.GlobalSettings().CustomFrameRate();
 2610|    355|    anim_fps = FrameRateToDouble(fps, custom);
 2611|       |
 2612|    355|    const std::vector<const AnimationStack *> &curAnimations = doc.AnimationStacks();
 2613|    355|    for (const AnimationStack *stack : curAnimations) {
  ------------------
  |  Branch (2613:38): [True: 247, False: 355]
  ------------------
 2614|    247|        ConvertAnimationStack(*stack);
 2615|    247|    }
 2616|    355|}
_ZN6Assimp3FBX12FBXConverter11FixNodeNameERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
 2618|  14.7k|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.7k|    if (name.substr(0, 7) == "Model::") {
  ------------------
  |  Branch (2623:9): [True: 14.6k, False: 83]
  ------------------
 2624|  14.6k|        std::string temp = name.substr(7);
 2625|  14.6k|        return temp;
 2626|  14.6k|    }
 2627|       |
 2628|     83|    return name;
 2629|  14.7k|}
_ZN6Assimp3FBX12FBXConverter21ConvertAnimationStackERKNS0_14AnimationStackE:
 2641|    247|void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
 2642|    247|    const AnimationLayerList &layers = st.Layers();
 2643|    247|    if (layers.empty()) {
  ------------------
  |  Branch (2643:9): [True: 16, False: 231]
  ------------------
 2644|     16|        return;
 2645|     16|    }
 2646|       |
 2647|    231|    aiAnimation *const anim = new aiAnimation();
 2648|    231|    animations.push_back(anim);
 2649|       |
 2650|       |    // strip AnimationStack:: prefix
 2651|    231|    std::string name = st.Name();
 2652|    231|    if (name.substr(0, 16) == "AnimationStack::") {
  ------------------
  |  Branch (2652:9): [True: 0, False: 231]
  ------------------
 2653|      0|        name = name.substr(16);
 2654|    231|    } else if (name.substr(0, 11) == "AnimStack::") {
  ------------------
  |  Branch (2654:16): [True: 229, False: 2]
  ------------------
 2655|    229|        name = name.substr(11);
 2656|    229|    }
 2657|       |
 2658|    231|    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|    231|    NodeMap node_map;
 2663|       |
 2664|       |    // reverse mapping from curves to layers, much faster than querying
 2665|       |    // the FBX DOM for it.
 2666|    231|    LayerMap layer_map;
 2667|       |
 2668|    231|    const char *prop_whitelist[] = {
 2669|    231|        "Lcl Scaling",
 2670|    231|        "Lcl Rotation",
 2671|    231|        "Lcl Translation",
 2672|    231|        "DeformPercent"
 2673|    231|    };
 2674|       |
 2675|    231|    std::map<std::string, morphAnimData *> morphAnimDatas;
 2676|       |
 2677|    231|    for (const AnimationLayer *layer : layers) {
  ------------------
  |  Branch (2677:38): [True: 231, False: 231]
  ------------------
 2678|    231|        ai_assert(layer);
 2679|    231|        const AnimationCurveNodeList &nodes = layer->Nodes(prop_whitelist, 4);
 2680|  9.18k|        for (const AnimationCurveNode *node : nodes) {
  ------------------
  |  Branch (2680:45): [True: 9.18k, False: 231]
  ------------------
 2681|  9.18k|            ai_assert(node);
 2682|  9.18k|            const Model *const model = dynamic_cast<const Model *>(node->Target());
 2683|  9.18k|            if (model) {
  ------------------
  |  Branch (2683:17): [True: 9.18k, False: 0]
  ------------------
 2684|  9.18k|                const std::string &curName = FixNodeName(model->Name());
 2685|  9.18k|                node_map[curName].push_back(node);
 2686|  9.18k|                layer_map[node] = layer;
 2687|  9.18k|                continue;
 2688|  9.18k|            }
 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|    231|    }
 2695|       |
 2696|       |    // generate node animations
 2697|    231|    std::vector<aiNodeAnim *> node_anims;
 2698|       |
 2699|    231|    double min_time = 1e10;
 2700|    231|    double max_time = -1e10;
 2701|       |
 2702|    231|    int64_t start_time = st.LocalStart();
 2703|    231|    int64_t stop_time = st.LocalStop();
 2704|    231|    bool has_local_startstop = start_time != 0 || stop_time != 0;
  ------------------
  |  Branch (2704:32): [True: 17, False: 214]
  |  Branch (2704:51): [True: 210, False: 4]
  ------------------
 2705|    231|    if (!has_local_startstop) {
  ------------------
  |  Branch (2705:9): [True: 4, False: 227]
  ------------------
 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|      4|        start_time = -9223372036854775807ll + 20000;
 2709|      4|        stop_time = 9223372036854775807ll - 20000;
 2710|      4|    }
 2711|       |
 2712|    231|    try {
 2713|  3.08k|        for (const NodeMap::value_type &kv : node_map) {
  ------------------
  |  Branch (2713:44): [True: 3.08k, False: 231]
  ------------------
 2714|  3.08k|            GenerateNodeAnimations(node_anims,
 2715|  3.08k|                    kv.first,
 2716|  3.08k|                    kv.second,
 2717|  3.08k|                    layer_map,
 2718|  3.08k|                    start_time, stop_time,
 2719|  3.08k|                    max_time,
 2720|  3.08k|                    min_time);
 2721|  3.08k|        }
 2722|    231|    } catch (std::exception &) {
 2723|      6|        std::for_each(node_anims.begin(), node_anims.end(), Util::delete_fun<aiNodeAnim>());
 2724|      6|        throw;
 2725|      6|    }
 2726|       |
 2727|    221|    if (node_anims.size() || morphAnimDatas.size()) {
  ------------------
  |  Branch (2727:9): [True: 218, False: 3]
  |  Branch (2727:30): [True: 0, False: 3]
  ------------------
 2728|    218|        if (node_anims.size()) {
  ------------------
  |  Branch (2728:13): [True: 218, False: 0]
  ------------------
 2729|    218|            anim->mChannels = new aiNodeAnim *[node_anims.size()]();
 2730|    218|            anim->mNumChannels = static_cast<unsigned int>(node_anims.size());
 2731|    218|            std::swap_ranges(node_anims.begin(), node_anims.end(), anim->mChannels);
 2732|    218|        }
 2733|    218|        if (morphAnimDatas.size()) {
  ------------------
  |  Branch (2733:13): [True: 0, False: 218]
  ------------------
 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|    218|    } 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|    218|    double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time;
  ------------------
  |  |   77|    214|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
  |  Branch (2770:29): [True: 214, False: 4]
  ------------------
 2771|    218|    double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time;
  ------------------
  |  |   77|    214|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
  |  Branch (2771:28): [True: 214, False: 4]
  ------------------
 2772|       |
 2773|       |    // adjust relative timing for animation
 2774|  3.98k|    for (unsigned int c = 0; c < anim->mNumChannels; c++) {
  ------------------
  |  Branch (2774:30): [True: 3.76k, False: 218]
  ------------------
 2775|  3.76k|        aiNodeAnim *channel = anim->mChannels[c];
 2776|  3.95M|        for (uint32_t i = 0; i < channel->mNumPositionKeys; i++) {
  ------------------
  |  Branch (2776:30): [True: 3.95M, False: 3.76k]
  ------------------
 2777|  3.95M|            channel->mPositionKeys[i].mTime -= start_time_fps;
 2778|  3.95M|        }
 2779|  4.38M|        for (uint32_t i = 0; i < channel->mNumRotationKeys; i++) {
  ------------------
  |  Branch (2779:30): [True: 4.37M, False: 3.76k]
  ------------------
 2780|  4.37M|            channel->mRotationKeys[i].mTime -= start_time_fps;
 2781|  4.37M|        }
 2782|  3.95M|        for (uint32_t i = 0; i < channel->mNumScalingKeys; i++) {
  ------------------
  |  Branch (2782:30): [True: 3.95M, False: 3.76k]
  ------------------
 2783|  3.95M|            channel->mScalingKeys[i].mTime -= start_time_fps;
 2784|  3.95M|        }
 2785|  3.76k|    }
 2786|    218|    for (unsigned int c = 0; c < anim->mNumMorphMeshChannels; c++) {
  ------------------
  |  Branch (2786:30): [True: 0, False: 218]
  ------------------
 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|    218|    anim->mDuration = stop_time_fps - start_time_fps;
 2796|    218|    anim->mTicksPerSecond = anim_fps;
 2797|    218|}
_ZN6Assimp3FBX12FBXConverter22GenerateNodeAnimationsERNSt3__16vectorIP10aiNodeAnimNS2_9allocatorIS5_EEEERKNS2_12basic_stringIcNS2_11char_traitsIcEENS6_IcEEEERKNS3_IPKNS0_18AnimationCurveNodeENS6_ISJ_EEEERKNS2_3mapISJ_PKNS0_14AnimationLayerENS2_4lessISJ_EENS6_INS2_4pairIKSJ_SR_EEEEEEllRdS11_:
 2886|  3.08k|        double &min_time) {
 2887|       |
 2888|  3.08k|    NodeMap node_property_map;
 2889|  3.08k|    ai_assert(curves.size());
 2890|       |
 2891|  3.08k|#ifdef ASSIMP_BUILD_DEBUG
 2892|  3.08k|    validateAnimCurveNodes(curves, doc.Settings().strictMode);
 2893|  3.08k|#endif
 2894|  3.08k|    const AnimationCurveNode *curve_node = nullptr;
 2895|  9.03k|    for (const AnimationCurveNode *node : curves) {
  ------------------
  |  Branch (2895:41): [True: 9.03k, False: 3.08k]
  ------------------
 2896|  9.03k|        ai_assert(node);
 2897|       |
 2898|  9.03k|        if (node->TargetProperty().empty()) {
  ------------------
  |  Branch (2898:13): [True: 0, False: 9.03k]
  ------------------
 2899|      0|            FBXImporter::LogWarn("target property for animation curve not set: ", node->Name());
 2900|      0|            continue;
 2901|      0|        }
 2902|       |
 2903|  9.03k|        curve_node = node;
 2904|  9.03k|        if (node->Curves().empty()) {
  ------------------
  |  Branch (2904:13): [True: 1, False: 9.03k]
  ------------------
 2905|      1|            FBXImporter::LogWarn("no animation curves assigned to AnimationCurveNode: ", node->Name());
 2906|      1|            continue;
 2907|      1|        }
 2908|       |
 2909|  9.03k|        node_property_map[node->TargetProperty()].push_back(node);
 2910|  9.03k|    }
 2911|       |
 2912|  3.08k|    ai_assert(curve_node);
 2913|  3.08k|    ai_assert(curve_node->TargetAsModel());
 2914|       |
 2915|  3.08k|    const Model &target = *curve_node->TargetAsModel();
 2916|       |
 2917|       |    // check for all possible transformation components
 2918|  3.08k|    NodeMap::const_iterator chain[TransformationComp_MAXIMUM];
 2919|       |
 2920|  3.08k|    bool has_any = false;
 2921|  3.08k|    bool has_complex = false;
 2922|       |
 2923|  55.4k|    for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
  ------------------
  |  Branch (2923:24): [True: 52.3k, False: 3.08k]
  ------------------
 2924|  52.3k|        const TransformationComp comp = static_cast<TransformationComp>(i);
 2925|       |
 2926|       |        // inverse pivots don't exist in the input, we just generate them
 2927|  52.3k|        if (comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse) {
  ------------------
  |  Branch (2927:13): [True: 3.07k, False: 49.2k]
  |  Branch (2927:64): [True: 3.07k, False: 46.1k]
  ------------------
 2928|  6.15k|            chain[i] = node_property_map.end();
 2929|  6.15k|            continue;
 2930|  6.15k|        }
 2931|       |
 2932|  46.1k|        chain[i] = node_property_map.find(NameTransformationCompProperty(comp));
 2933|  46.1k|        if (chain[i] != node_property_map.end()) {
  ------------------
  |  Branch (2933:13): [True: 8.83k, False: 37.3k]
  ------------------
 2934|       |
 2935|       |            // check if this curves contains redundant information by looking
 2936|       |            // up the corresponding node's transformation chain.
 2937|  8.83k|            if (doc.Settings().optimizeEmptyAnimationCurves &&
  ------------------
  |  Branch (2937:17): [True: 8.83k, False: 0]
  ------------------
 2938|  8.83k|                    IsRedundantAnimationData(target, comp, (chain[i]->second))) {
  ------------------
  |  Branch (2938:21): [True: 0, False: 8.83k]
  ------------------
 2939|       |
 2940|      0|                FBXImporter::LogVerboseDebug("dropping redundant animation channel for node ", target.Name());
 2941|      0|                continue;
 2942|      0|            }
 2943|       |
 2944|  8.83k|            has_any = true;
 2945|       |
 2946|  8.83k|            if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation) {
  ------------------
  |  Branch (2946:17): [True: 5.90k, False: 2.93k]
  |  Branch (2946:56): [True: 2.92k, False: 2.97k]
  |  Branch (2946:94): [True: 0, False: 2.92k]
  ------------------
 2947|      0|                has_complex = true;
 2948|      0|            }
 2949|  8.83k|        }
 2950|  46.1k|    }
 2951|       |
 2952|  3.08k|    if (!has_any) {
  ------------------
  |  Branch (2952:9): [True: 0, False: 3.08k]
  ------------------
 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.08k|    if (!doc.Settings().preservePivots || (!has_complex && !NeedsComplexTransformationChain(target))) {
  ------------------
  |  Branch (2961:9): [True: 4, False: 3.07k]
  |  Branch (2961:44): [True: 3.07k, False: 0]
  |  Branch (2961:60): [True: 2.63k, False: 443]
  ------------------
 2962|  2.63k|        aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain,
 2963|  2.63k|                node_property_map.end(),
 2964|  2.63k|                start, stop,
 2965|  2.63k|                max_time,
 2966|  2.63k|                min_time
 2967|  2.63k|        );
 2968|       |
 2969|  2.63k|        ai_assert(nd);
 2970|  2.63k|        if (nd->mNumPositionKeys == 0 && nd->mNumRotationKeys == 0 && nd->mNumScalingKeys == 0) {
  ------------------
  |  Branch (2970:13): [True: 1, False: 2.63k]
  |  Branch (2970:42): [True: 1, False: 0]
  |  Branch (2970:71): [True: 1, False: 0]
  ------------------
 2971|      1|            delete nd;
 2972|  2.63k|        } else {
 2973|  2.63k|            node_anims.push_back(nd);
 2974|  2.63k|        }
 2975|  2.63k|        return;
 2976|  2.63k|    }
 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|    447|    unsigned int flags = 0, bit = 0x1;
 2984|  7.97k|    for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) {
  ------------------
  |  Branch (2984:24): [True: 7.53k, False: 447]
  ------------------
 2985|  7.53k|        const TransformationComp comp = static_cast<TransformationComp>(i);
 2986|       |
 2987|  7.53k|        if (chain[i] != node_property_map.end()) {
  ------------------
  |  Branch (2987:13): [True: 1.20k, False: 6.32k]
  ------------------
 2988|  1.20k|            flags |= bit;
 2989|       |
 2990|  1.20k|            ai_assert(comp != TransformationComp_RotationPivotInverse);
 2991|  1.20k|            ai_assert(comp != TransformationComp_ScalingPivotInverse);
 2992|       |
 2993|  1.20k|            const std::string &chain_name = NameTransformationChainNode(fixed_name, comp);
 2994|       |
 2995|  1.20k|            aiNodeAnim *na = nullptr;
 2996|  1.20k|            switch (comp) {
 2997|    405|                case TransformationComp_Rotation:
  ------------------
  |  Branch (2997:17): [True: 405, False: 799]
  ------------------
 2998|    405|                case TransformationComp_PreRotation:
  ------------------
  |  Branch (2998:17): [True: 0, False: 1.20k]
  ------------------
 2999|    405|                case TransformationComp_PostRotation:
  ------------------
  |  Branch (2999:17): [True: 0, False: 1.20k]
  ------------------
 3000|    405|                case TransformationComp_GeometricRotation:
  ------------------
  |  Branch (3000:17): [True: 0, False: 1.20k]
  ------------------
 3001|    405|                    na = GenerateRotationNodeAnim(chain_name,
 3002|    405|                            target,
 3003|    405|                            (*chain[i]).second,
 3004|    405|                            layer_map,
 3005|    405|                            start, stop,
 3006|    405|                            max_time,
 3007|    405|                            min_time);
 3008|       |
 3009|    405|                    break;
 3010|       |
 3011|      0|                case TransformationComp_RotationOffset:
  ------------------
  |  Branch (3011:17): [True: 0, False: 1.20k]
  ------------------
 3012|      0|                case TransformationComp_RotationPivot:
  ------------------
  |  Branch (3012:17): [True: 0, False: 1.20k]
  ------------------
 3013|      0|                case TransformationComp_ScalingOffset:
  ------------------
  |  Branch (3013:17): [True: 0, False: 1.20k]
  ------------------
 3014|      0|                case TransformationComp_ScalingPivot:
  ------------------
  |  Branch (3014:17): [True: 0, False: 1.20k]
  ------------------
 3015|    402|                case TransformationComp_Translation:
  ------------------
  |  Branch (3015:17): [True: 402, False: 802]
  ------------------
 3016|    402|                case TransformationComp_GeometricTranslation:
  ------------------
  |  Branch (3016:17): [True: 0, False: 1.20k]
  ------------------
 3017|    402|                    na = GenerateTranslationNodeAnim(chain_name,
 3018|    402|                            target,
 3019|    402|                            (*chain[i]).second,
 3020|    402|                            layer_map,
 3021|    402|                            start, stop,
 3022|    402|                            max_time,
 3023|    402|                            min_time);
 3024|       |
 3025|       |                    // pivoting requires us to generate an implicit inverse channel to undo the pivot translation
 3026|    402|                    if (comp == TransformationComp_RotationPivot) {
  ------------------
  |  Branch (3026:25): [True: 0, False: 402]
  ------------------
 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|    402|                    } else if (comp == TransformationComp_ScalingPivot) {
  ------------------
  |  Branch (3048:32): [True: 0, False: 402]
  ------------------
 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|    402|                    break;
 3073|       |
 3074|    397|                case TransformationComp_Scaling:
  ------------------
  |  Branch (3074:17): [True: 397, False: 807]
  ------------------
 3075|    397|                case TransformationComp_GeometricScaling:
  ------------------
  |  Branch (3075:17): [True: 0, False: 1.20k]
  ------------------
 3076|    397|                    na = GenerateScalingNodeAnim(chain_name,
 3077|    397|                            target,
 3078|    397|                            (*chain[i]).second,
 3079|    397|                            layer_map,
 3080|    397|                            start, stop,
 3081|    397|                            max_time,
 3082|    397|                            min_time);
 3083|       |
 3084|    397|                    break;
 3085|       |
 3086|      0|                default:
  ------------------
  |  Branch (3086:17): [True: 0, False: 1.20k]
  ------------------
 3087|      0|                    ai_assert(false);
 3088|  1.20k|            }
 3089|       |
 3090|  1.20k|            ai_assert(na);
 3091|  1.20k|            if (na->mNumPositionKeys == 0 && na->mNumRotationKeys == 0 && na->mNumScalingKeys == 0) {
  ------------------
  |  Branch (3091:17): [True: 48, False: 1.15k]
  |  Branch (3091:46): [True: 0, False: 48]
  |  Branch (3091:75): [True: 0, False: 0]
  ------------------
 3092|      0|                delete na;
 3093|  1.20k|            } else {
 3094|  1.20k|                node_anims.push_back(na);
 3095|  1.20k|            }
 3096|  1.20k|            continue;
 3097|  1.20k|        }
 3098|  7.53k|    }
 3099|       |
 3100|    447|    node_anim_chain_bits[fixed_name] = flags;
 3101|    447|}
_ZN6Assimp3FBX12FBXConverter24IsRedundantAnimationDataERKNS0_5ModelENS1_18TransformationCompERKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS6_9allocatorISA_EEEE:
 3105|  8.83k|        const std::vector<const AnimationCurveNode *> &curves) {
 3106|  8.83k|    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|  8.83k|    if (curves.size() > 1) {
  ------------------
  |  Branch (3114:9): [True: 174, False: 8.66k]
  ------------------
 3115|    174|        return false;
 3116|    174|    }
 3117|       |
 3118|  8.66k|    const AnimationCurveNode &nd = *curves.front();
 3119|  8.66k|    const AnimationCurveMap &sub_curves = nd.Curves();
 3120|       |
 3121|  8.66k|    const AnimationCurveMap::const_iterator dx = sub_curves.find("d|X");
 3122|  8.66k|    const AnimationCurveMap::const_iterator dy = sub_curves.find("d|Y");
 3123|  8.66k|    const AnimationCurveMap::const_iterator dz = sub_curves.find("d|Z");
 3124|       |
 3125|  8.66k|    if (dx == sub_curves.end() || dy == sub_curves.end() || dz == sub_curves.end()) {
  ------------------
  |  Branch (3125:9): [True: 330, False: 8.33k]
  |  Branch (3125:9): [True: 837, False: 7.82k]
  |  Branch (3125:35): [True: 231, False: 8.10k]
  |  Branch (3125:61): [True: 276, False: 7.82k]
  ------------------
 3126|    837|        return false;
 3127|    837|    }
 3128|       |
 3129|  7.82k|    const KeyValueList &vx = (*dx).second->GetValues();
 3130|  7.82k|    const KeyValueList &vy = (*dy).second->GetValues();
 3131|  7.82k|    const KeyValueList &vz = (*dz).second->GetValues();
 3132|       |
 3133|  7.82k|    if (vx.size() != 1 || vy.size() != 1 || vz.size() != 1) {
  ------------------
  |  Branch (3133:9): [True: 7.82k, False: 0]
  |  Branch (3133:27): [True: 0, False: 0]
  |  Branch (3133:45): [True: 0, False: 0]
  ------------------
 3134|  7.82k|        return false;
 3135|  7.82k|    }
 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|  7.82k|}
_ZN6Assimp3FBX12FBXConverter24GenerateRotationNodeAnimERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5ModelERKNS2_6vectorIPKNS0_18AnimationCurveNodeENS6_ISH_EEEERKNS2_3mapISH_PKNS0_14AnimationLayerENS2_4lessISH_EENS6_INS2_4pairIKSH_SP_EEEEEEllRdSZ_:
 3152|    405|        double &min_time) {
 3153|    405|    std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
 3154|    405|    na->mNodeName.Set(name);
 3155|       |
 3156|    405|    ConvertRotationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time, target.RotationOrder());
 3157|       |
 3158|       |    // dummy scaling key
 3159|    405|    na->mScalingKeys = new aiVectorKey[1];
 3160|    405|    na->mNumScalingKeys = 1;
 3161|       |
 3162|    405|    na->mScalingKeys[0].mTime = 0.;
 3163|    405|    na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f);
 3164|       |
 3165|       |    // dummy position key
 3166|    405|    na->mPositionKeys = new aiVectorKey[1];
 3167|    405|    na->mNumPositionKeys = 1;
 3168|       |
 3169|    405|    na->mPositionKeys[0].mTime = 0.;
 3170|    405|    na->mPositionKeys[0].mValue = aiVector3D();
 3171|       |
 3172|    405|    return na.release();
 3173|    405|}
_ZN6Assimp3FBX12FBXConverter23GenerateScalingNodeAnimERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5ModelERKNS2_6vectorIPKNS0_18AnimationCurveNodeENS6_ISH_EEEERKNS2_3mapISH_PKNS0_14AnimationLayerENS2_4lessISH_EENS6_INS2_4pairIKSH_SP_EEEEEEllRdSZ_:
 3181|    397|        double &min_time) {
 3182|    397|    std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
 3183|    397|    na->mNodeName.Set(name);
 3184|       |
 3185|    397|    ConvertScaleKeys(na.get(), curves, layer_map, start, stop, max_time, min_time);
 3186|       |
 3187|       |    // dummy rotation key
 3188|    397|    na->mRotationKeys = new aiQuatKey[1];
 3189|    397|    na->mNumRotationKeys = 1;
 3190|       |
 3191|    397|    na->mRotationKeys[0].mTime = 0.;
 3192|    397|    na->mRotationKeys[0].mValue = aiQuaternion();
 3193|       |
 3194|       |    // dummy position key
 3195|    397|    na->mPositionKeys = new aiVectorKey[1];
 3196|    397|    na->mNumPositionKeys = 1;
 3197|       |
 3198|    397|    na->mPositionKeys[0].mTime = 0.;
 3199|    397|    na->mPositionKeys[0].mValue = aiVector3D();
 3200|       |
 3201|    397|    return na.release();
 3202|    397|}
_ZN6Assimp3FBX12FBXConverter27GenerateTranslationNodeAnimERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_5ModelERKNS2_6vectorIPKNS0_18AnimationCurveNodeENS6_ISH_EEEERKNS2_3mapISH_PKNS0_14AnimationLayerENS2_4lessISH_EENS6_INS2_4pairIKSH_SP_EEEEEEllRdSZ_b:
 3211|    402|        bool inverse) {
 3212|    402|    std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
 3213|    402|    na->mNodeName.Set(name);
 3214|       |
 3215|    402|    ConvertTranslationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time);
 3216|       |
 3217|    402|    if (inverse) {
  ------------------
  |  Branch (3217:9): [True: 0, False: 402]
  ------------------
 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|    402|    na->mScalingKeys = new aiVectorKey[1];
 3225|    402|    na->mNumScalingKeys = 1;
 3226|       |
 3227|    402|    na->mScalingKeys[0].mTime = 0.;
 3228|    402|    na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f);
 3229|       |
 3230|       |    // dummy rotation key
 3231|    402|    na->mRotationKeys = new aiQuatKey[1];
 3232|    402|    na->mNumRotationKeys = 1;
 3233|       |
 3234|    402|    na->mRotationKeys[0].mTime = 0.;
 3235|    402|    na->mRotationKeys[0].mValue = aiQuaternion();
 3236|       |
 3237|    402|    return na.release();
 3238|    402|}
_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.63k|{
 3248|  2.63k|    std::unique_ptr<aiNodeAnim> na(new aiNodeAnim());
 3249|  2.63k|    na->mNodeName.Set(name);
 3250|       |
 3251|  2.63k|    const PropertyTable &props = target.Props();
 3252|       |
 3253|       |    // collect unique times and keyframe lists
 3254|  2.63k|    KeyFrameListList keyframeLists[TransformationComp_MAXIMUM];
 3255|  2.63k|    KeyTimeList keytimes;
 3256|       |
 3257|  47.4k|    for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
  ------------------
  |  Branch (3257:24): [True: 44.8k, False: 2.63k]
  ------------------
 3258|  44.8k|        if (chain[i] == iterEnd)
  ------------------
  |  Branch (3258:13): [True: 37.1k, False: 7.63k]
  ------------------
 3259|  37.1k|            continue;
 3260|       |
 3261|  7.63k|        if (i == TransformationComp_Rotation || i == TransformationComp_PreRotation
  ------------------
  |  Branch (3261:13): [True: 2.53k, False: 5.10k]
  |  Branch (3261:49): [True: 0, False: 5.10k]
  ------------------
 3262|  5.10k|                || i == TransformationComp_PostRotation || i == TransformationComp_GeometricRotation) {
  ------------------
  |  Branch (3262:20): [True: 0, False: 5.10k]
  |  Branch (3262:60): [True: 0, False: 5.10k]
  ------------------
 3263|  2.53k|            keyframeLists[i] = GetRotationKeyframeList((*chain[i]).second, start, stop);
 3264|  5.10k|        } else {
 3265|  5.10k|            keyframeLists[i] = GetKeyframeList((*chain[i]).second, start, stop);
 3266|  5.10k|        }
 3267|       |
 3268|  30.2k|        for (KeyFrameListList::const_iterator it = keyframeLists[i].begin(); it != keyframeLists[i].end(); ++it) {
  ------------------
  |  Branch (3268:78): [True: 22.5k, False: 7.63k]
  ------------------
 3269|  22.5k|            const KeyTimeList& times = *std::get<0>(*it);
 3270|  22.5k|            keytimes.insert(keytimes.end(), times.begin(), times.end());
 3271|  22.5k|        }
 3272|       |
 3273|       |        // remove duplicates
 3274|  7.63k|        std::sort(keytimes.begin(), keytimes.end());
 3275|       |
 3276|  7.63k|        auto last = std::unique(keytimes.begin(), keytimes.end());
 3277|  7.63k|        keytimes.erase(last, keytimes.end());
 3278|  7.63k|    }
 3279|       |
 3280|  2.63k|    const Model::RotOrder rotOrder = target.RotationOrder();
 3281|  2.63k|    const size_t keyCount = keytimes.size();
 3282|       |
 3283|  2.63k|    aiVector3D defTranslate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f));
 3284|  2.63k|    aiVector3D defRotation = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f));
 3285|  2.63k|    aiVector3D defScale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f));
 3286|       |
 3287|  2.63k|    aiVectorKey* outTranslations = new aiVectorKey[keyCount];
 3288|  2.63k|    aiQuatKey* outRotations = new aiQuatKey[keyCount];
 3289|  2.63k|    aiVectorKey* outScales = new aiVectorKey[keyCount];
 3290|       |
 3291|  2.63k|    if (keyframeLists[TransformationComp_Translation].size() > 0) {
  ------------------
  |  Branch (3291:9): [True: 2.52k, False: 116]
  ------------------
 3292|  2.52k|        InterpolateKeys(outTranslations, keytimes, keyframeLists[TransformationComp_Translation], defTranslate, maxTime, minTime);
 3293|  2.52k|    } else {
 3294|    819|        for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3294:28): [True: 703, False: 116]
  ------------------
 3295|    703|            outTranslations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
  ------------------
  |  |   77|    703|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 3296|    703|            outTranslations[i].mValue = defTranslate;
 3297|    703|        }
 3298|    116|    }
 3299|       |
 3300|  2.63k|    if (keyframeLists[TransformationComp_Rotation].size() > 0) {
  ------------------
  |  Branch (3300:9): [True: 2.52k, False: 107]
  ------------------
 3301|  2.52k|        InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder);
 3302|  2.52k|    } else {
 3303|    107|        aiQuaternion defQuat = EulerToQuaternion(defRotation, rotOrder);
 3304|    313|        for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3304:28): [True: 206, False: 107]
  ------------------
 3305|    206|            outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
  ------------------
  |  |   77|    206|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 3306|    206|            outRotations[i].mValue = defQuat;
 3307|    206|        }
 3308|    107|    }
 3309|       |
 3310|  2.63k|    if (keyframeLists[TransformationComp_Scaling].size() > 0) {
  ------------------
  |  Branch (3310:9): [True: 2.57k, False: 60]
  ------------------
 3311|  2.57k|        InterpolateKeys(outScales, keytimes, keyframeLists[TransformationComp_Scaling], defScale, maxTime, minTime);
 3312|  2.57k|    } else {
 3313|    200|        for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3313:28): [True: 140, False: 60]
  ------------------
 3314|    140|            outScales[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
  ------------------
  |  |   77|    140|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 3315|    140|            outScales[i].mValue = defScale;
 3316|    140|        }
 3317|     60|    }
 3318|       |
 3319|  2.63k|    bool ok = false;
 3320|       |
 3321|  2.63k|    const auto zero_epsilon = ai_epsilon;
 3322|       |
 3323|  2.63k|    const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
 3324|  2.63k|    if (ok && preRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (3324:9): [True: 2.47k, False: 159]
  |  Branch (3324:15): [True: 0, False: 2.47k]
  ------------------
 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.63k|    const aiVector3D& postRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok);
 3332|  2.63k|    if (ok && postRotation.SquareLength() > zero_epsilon) {
  ------------------
  |  Branch (3332:9): [True: 2.47k, False: 161]
  |  Branch (3332:15): [True: 0, False: 2.47k]
  ------------------
 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|  3.95M|    for (size_t i = 0; i < keyCount; ++i) {
  ------------------
  |  Branch (3340:24): [True: 3.94M, False: 2.63k]
  ------------------
 3341|  3.94M|        aiQuaternion& r = outRotations[i].mValue;
 3342|  3.94M|        aiVector3D& s = outScales[i].mValue;
 3343|  3.94M|        aiVector3D& t = outTranslations[i].mValue;
 3344|       |
 3345|  3.94M|        aiMatrix4x4 mat, temp;
 3346|  3.94M|        aiMatrix4x4::Translation(t, mat);
 3347|  3.94M|        mat *= aiMatrix4x4(r.GetMatrix());
 3348|  3.94M|        mat *= aiMatrix4x4::Scaling(s, temp);
 3349|       |
 3350|  3.94M|        mat.Decompose(s, r, t);
 3351|  3.94M|    }
 3352|       |
 3353|  2.63k|    na->mNumScalingKeys = static_cast<unsigned int>(keyCount);
 3354|  2.63k|    na->mNumRotationKeys = na->mNumScalingKeys;
 3355|  2.63k|    na->mNumPositionKeys = na->mNumScalingKeys;
 3356|       |
 3357|  2.63k|    na->mScalingKeys = outScales;
 3358|  2.63k|    na->mRotationKeys = outRotations;
 3359|  2.63k|    na->mPositionKeys = outTranslations;
 3360|       |
 3361|  2.63k|    return na.release();
 3362|  2.63k|}
_ZN6Assimp3FBX12FBXConverter15GetKeyframeListERKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS2_9allocatorIS6_EEEEll:
 3364|  5.90k|FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector<const AnimationCurveNode *> &nodes, int64_t start, int64_t stop) {
 3365|  5.90k|    KeyFrameListList inputs;
 3366|  5.90k|    inputs.reserve(nodes.size() * 3);
 3367|       |
 3368|       |    //give some breathing room for rounding errors
 3369|  5.90k|    int64_t adj_start = start - 10000;
 3370|  5.90k|    int64_t adj_stop = stop + 10000;
 3371|       |
 3372|  6.02k|    for (const AnimationCurveNode *node : nodes) {
  ------------------
  |  Branch (3372:41): [True: 6.02k, False: 5.90k]
  ------------------
 3373|  6.02k|        ai_assert(node);
 3374|       |
 3375|  6.02k|        const AnimationCurveMap &curves = node->Curves();
 3376|  17.5k|        for (const AnimationCurveMap::value_type &kv : curves) {
  ------------------
  |  Branch (3376:54): [True: 17.5k, False: 6.02k]
  ------------------
 3377|       |
 3378|  17.5k|            unsigned int mapto;
 3379|  17.5k|            if (kv.first == "d|X") {
  ------------------
  |  Branch (3379:17): [True: 5.80k, False: 11.7k]
  ------------------
 3380|  5.80k|                mapto = 0;
 3381|  11.7k|            } else if (kv.first == "d|Y") {
  ------------------
  |  Branch (3381:24): [True: 5.88k, False: 5.87k]
  ------------------
 3382|  5.88k|                mapto = 1;
 3383|  5.88k|            } else if (kv.first == "d|Z") {
  ------------------
  |  Branch (3383:24): [True: 5.82k, False: 49]
  ------------------
 3384|  5.82k|                mapto = 2;
 3385|  5.82k|            } else {
 3386|     49|                FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component");
 3387|     49|                continue;
 3388|     49|            }
 3389|       |
 3390|  17.5k|            const AnimationCurve *const curve = kv.second;
 3391|  17.5k|            ai_assert(curve->GetKeys().size() == curve->GetValues().size());
 3392|  17.5k|            ai_assert(curve->GetKeys().size());
 3393|       |
 3394|       |            //get values within the start/stop time window
 3395|  17.5k|            std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
 3396|  17.5k|            std::shared_ptr<KeyValueList> Values(new KeyValueList());
 3397|  17.5k|            const size_t count = curve->GetKeys().size();
 3398|  17.5k|            Keys->reserve(count);
 3399|  17.5k|            Values->reserve(count);
 3400|  52.5k|            for (size_t n = 0; n < count; n++) {
  ------------------
  |  Branch (3400:32): [True: 35.0k, False: 17.5k]
  ------------------
 3401|  35.0k|                int64_t k = curve->GetKeys().at(n);
 3402|  35.0k|                if (k >= adj_start && k <= adj_stop) {
  ------------------
  |  Branch (3402:21): [True: 34.0k, False: 998]
  |  Branch (3402:39): [True: 33.9k, False: 78]
  ------------------
 3403|  33.9k|                    Keys->push_back(k);
 3404|  33.9k|                    Values->push_back(curve->GetValues().at(n));
 3405|  33.9k|                }
 3406|  35.0k|            }
 3407|       |
 3408|  17.5k|            inputs.emplace_back(Keys, Values, mapto);
 3409|  17.5k|        }
 3410|  6.02k|    }
 3411|  5.90k|    return inputs; // pray for NRVO :-)
 3412|  5.90k|}
_ZN6Assimp3FBX12FBXConverter23GetRotationKeyframeListERKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS2_9allocatorIS6_EEEEll:
 3415|  2.93k|                                                                     int64_t start, int64_t stop) {
 3416|  2.93k|    KeyFrameListList inputs;
 3417|  2.93k|    inputs.reserve(nodes.size() * 3);
 3418|       |
 3419|       |    // give some breathing room for rounding errors
 3420|  2.93k|    const int64_t adj_start = start - 10000;
 3421|  2.93k|    const int64_t adj_stop = stop + 10000;
 3422|       |
 3423|  2.99k|    for (const AnimationCurveNode *node : nodes) {
  ------------------
  |  Branch (3423:41): [True: 2.99k, False: 2.93k]
  ------------------
 3424|  2.99k|        ai_assert(node);
 3425|       |
 3426|  2.99k|        const AnimationCurveMap &curves = node->Curves();
 3427|  8.71k|        for (const AnimationCurveMap::value_type &kv : curves) {
  ------------------
  |  Branch (3427:54): [True: 8.71k, False: 2.99k]
  ------------------
 3428|       |
 3429|  8.71k|            unsigned int mapto;
 3430|  8.71k|            if (kv.first == "d|X") {
  ------------------
  |  Branch (3430:17): [True: 2.88k, False: 5.83k]
  ------------------
 3431|  2.88k|                mapto = 0;
 3432|  5.83k|            } else if (kv.first == "d|Y") {
  ------------------
  |  Branch (3432:24): [True: 2.89k, False: 2.94k]
  ------------------
 3433|  2.89k|                mapto = 1;
 3434|  2.94k|            } else if (kv.first == "d|Z") {
  ------------------
  |  Branch (3434:24): [True: 2.87k, False: 69]
  ------------------
 3435|  2.87k|                mapto = 2;
 3436|  2.87k|            } else {
 3437|     69|                FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component");
 3438|     69|                continue;
 3439|     69|            }
 3440|       |
 3441|  8.64k|            const AnimationCurve *const curve = kv.second;
 3442|  8.64k|            ai_assert(curve->GetKeys().size() == curve->GetValues().size());
 3443|  8.64k|            ai_assert(curve->GetKeys().size());
 3444|       |
 3445|       |            // get values within the start/stop time window
 3446|  8.64k|            std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
 3447|  8.64k|            std::shared_ptr<KeyValueList> Values(new KeyValueList());
 3448|  8.64k|            const size_t count = curve->GetKeys().size();
 3449|       |
 3450|  8.64k|            int64_t tp = curve->GetKeys().at(0);
 3451|  8.64k|            float vp = curve->GetValues().at(0);
 3452|  8.64k|            Keys->push_back(tp);
 3453|  8.64k|            Values->push_back(vp);
 3454|  8.64k|            if (count > 1) {
  ------------------
  |  Branch (3454:17): [True: 8.64k, False: 0]
  ------------------
 3455|  8.64k|                int64_t tc = curve->GetKeys().at(1);
 3456|  8.64k|                float vc = curve->GetValues().at(1);
 3457|  19.3k|                for (size_t n = 1; n < count; n++) {
  ------------------
  |  Branch (3457:36): [True: 10.6k, False: 8.64k]
  ------------------
 3458|  4.38M|                    while (std::abs(vc - vp) >= 180.0f) {
  ------------------
  |  Branch (3458:28): [True: 4.37M, False: 10.6k]
  ------------------
 3459|  4.37M|                        double step = std::floor(double(tc - tp) / std::abs(vc - vp) * 179.0f);
 3460|  4.37M|                        int64_t tnew = tp + int64_t(step);
 3461|  4.37M|                        float vnew = vp + (vc - vp) * float(step / (tc - tp));
 3462|  4.37M|                        if (tnew >= adj_start && tnew <= adj_stop) {
  ------------------
  |  Branch (3462:29): [True: 4.37M, False: 0]
  |  Branch (3462:50): [True: 4.37M, False: 1]
  ------------------
 3463|  4.37M|                            Keys->push_back(tnew);
 3464|  4.37M|                            Values->push_back(vnew);
 3465|  4.37M|                        } else {
 3466|       |                            // Something broke
 3467|      1|                            break;
 3468|      1|                        }
 3469|  4.37M|                        tp = tnew;
 3470|  4.37M|                        vp = vnew;
 3471|  4.37M|                    }
 3472|  10.6k|                    if (tc >= adj_start && tc <= adj_stop) {
  ------------------
  |  Branch (3472:25): [True: 10.5k, False: 162]
  |  Branch (3472:44): [True: 10.4k, False: 17]
  ------------------
 3473|  10.4k|                        Keys->push_back(tc);
 3474|  10.4k|                        Values->push_back(vc);
 3475|  10.4k|                    }
 3476|  10.6k|                    if (n + 1 < count) {
  ------------------
  |  Branch (3476:25): [True: 2.02k, False: 8.64k]
  ------------------
 3477|  2.02k|                        tp = tc;
 3478|  2.02k|                        vp = vc;
 3479|  2.02k|                        tc = curve->GetKeys().at(n + 1);
 3480|  2.02k|                        vc = curve->GetValues().at(n + 1);
 3481|  2.02k|                    }
 3482|  10.6k|                }
 3483|  8.64k|            }
 3484|  8.64k|            inputs.emplace_back(Keys, Values, mapto);
 3485|  8.64k|        }
 3486|  2.99k|    }
 3487|  2.93k|    return inputs;
 3488|  2.93k|}
_ZN6Assimp3FBX12FBXConverter14GetKeyTimeListERKNSt3__16vectorINS2_5tupleIJNS2_10shared_ptrINS3_IlNS2_9allocatorIlEEEEEENS5_INS3_IfNS6_IfEEEEEEjEEENS6_ISD_EEEE:
 3490|  1.20k|KeyTimeList FBXConverter::GetKeyTimeList(const KeyFrameListList &inputs) {
 3491|  1.20k|    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.20k|    KeyTimeList keys;
 3497|       |
 3498|  1.20k|    size_t estimate = 0;
 3499|  3.58k|    for (const KeyFrameList &kfl : inputs) {
  ------------------
  |  Branch (3499:34): [True: 3.58k, False: 1.20k]
  ------------------
 3500|  3.58k|        estimate = std::max(estimate, std::get<0>(kfl)->size());
 3501|  3.58k|    }
 3502|       |
 3503|  1.20k|    keys.reserve(estimate);
 3504|       |
 3505|  1.20k|    std::vector<unsigned int> next_pos;
 3506|  1.20k|    next_pos.resize(inputs.size(), 0);
 3507|       |
 3508|  1.20k|    const size_t count = inputs.size();
 3509|   432k|    while (true) {
  ------------------
  |  Branch (3509:12): [True: 432k, Folded]
  ------------------
 3510|       |
 3511|   432k|        int64_t min_tick = std::numeric_limits<int64_t>::max();
 3512|  1.73M|        for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (3512:28): [True: 1.29M, False: 432k]
  ------------------
 3513|  1.29M|            const KeyFrameList &kfl = inputs[i];
 3514|       |
 3515|  1.29M|            if (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) < min_tick) {
  ------------------
  |  Branch (3515:17): [True: 1.29M, False: 3.62k]
  |  Branch (3515:59): [True: 431k, False: 863k]
  ------------------
 3516|   431k|                min_tick = std::get<0>(kfl)->at(next_pos[i]);
 3517|   431k|            }
 3518|  1.29M|        }
 3519|       |
 3520|   432k|        if (min_tick == std::numeric_limits<int64_t>::max()) {
  ------------------
  |  Branch (3520:13): [True: 1.20k, False: 431k]
  ------------------
 3521|  1.20k|            break;
 3522|  1.20k|        }
 3523|   431k|        keys.push_back(min_tick);
 3524|       |
 3525|  1.72M|        for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (3525:28): [True: 1.29M, False: 431k]
  ------------------
 3526|  1.29M|            const KeyFrameList &kfl = inputs[i];
 3527|       |
 3528|  1.73M|            while (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == min_tick) {
  ------------------
  |  Branch (3528:20): [True: 1.72M, False: 3.37k]
  |  Branch (3528:62): [True: 435k, False: 1.29M]
  ------------------
 3529|   435k|                ++next_pos[i];
 3530|   435k|            }
 3531|  1.29M|        }
 3532|   431k|    }
 3533|       |
 3534|  1.20k|    return keys;
 3535|  1.20k|}
_ZN6Assimp3FBX12FBXConverter15InterpolateKeysEP11aiVectorKeyRKNSt3__16vectorIlNS4_9allocatorIlEEEERKNS5_INS4_5tupleIJNS4_10shared_ptrIS8_EENSC_INS5_IfNS6_IfEEEEEEjEEENS6_ISH_EEEERK10aiVector3tIfERdSQ_:
 3540|  8.74k|        double &min_time) {
 3541|  8.74k|    ai_assert(!keys.empty());
 3542|  8.74k|    ai_assert(nullptr != valOut);
 3543|       |
 3544|  8.74k|    std::vector<unsigned int> next_pos;
 3545|  8.74k|    const size_t count(inputs.size());
 3546|       |
 3547|  8.74k|    next_pos.resize(inputs.size(), 0);
 3548|       |
 3549|  12.2M|    for (KeyTimeList::value_type time : keys) {
  ------------------
  |  Branch (3549:39): [True: 12.2M, False: 8.74k]
  ------------------
 3550|  12.2M|        ai_real result[3] = { def_value.x, def_value.y, def_value.z };
 3551|       |
 3552|  50.3M|        for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (3552:28): [True: 38.0M, False: 12.2M]
  ------------------
 3553|  38.0M|            const KeyFrameList &kfl = inputs[i];
 3554|       |
 3555|  38.0M|            const size_t ksize = std::get<0>(kfl)->size();
 3556|  38.0M|            if (ksize == 0) {
  ------------------
  |  Branch (3556:17): [True: 156k, False: 37.8M]
  ------------------
 3557|   156k|                continue;
 3558|   156k|            }
 3559|  37.8M|            if (ksize > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == time) {
  ------------------
  |  Branch (3559:17): [True: 37.8M, False: 262]
  |  Branch (3559:40): [True: 4.42M, False: 33.4M]
  ------------------
 3560|  4.42M|                ++next_pos[i];
 3561|  4.42M|            }
 3562|       |
 3563|  37.8M|            const size_t id0 = next_pos[i] > 0 ? next_pos[i] - 1 : 0;
  ------------------
  |  Branch (3563:32): [True: 37.8M, False: 487]
  ------------------
 3564|  37.8M|            const size_t id1 = next_pos[i] == ksize ? ksize - 1 : next_pos[i];
  ------------------
  |  Branch (3564:32): [True: 26.0k, False: 37.8M]
  ------------------
 3565|       |
 3566|       |            // use lerp for interpolation
 3567|  37.8M|            const KeyValueList::value_type valueA = std::get<1>(kfl)->at(id0);
 3568|  37.8M|            const KeyValueList::value_type valueB = std::get<1>(kfl)->at(id1);
 3569|       |
 3570|  37.8M|            const KeyTimeList::value_type timeA = std::get<0>(kfl)->at(id0);
 3571|  37.8M|            const KeyTimeList::value_type timeB = std::get<0>(kfl)->at(id1);
 3572|       |
 3573|  37.8M|            const ai_real factor = timeB == timeA ? ai_real(0.) : static_cast<ai_real>((time - timeA)) / (timeB - timeA);
  ------------------
  |  Branch (3573:36): [True: 26.5k, False: 37.8M]
  ------------------
 3574|  37.8M|            const ai_real interpValue = static_cast<ai_real>(valueA + (valueB - valueA) * factor);
 3575|       |
 3576|  37.8M|            result[std::get<2>(kfl)] = interpValue;
 3577|  37.8M|        }
 3578|       |
 3579|       |        // magic value to convert fbx times to seconds
 3580|  12.2M|        valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps;
  ------------------
  |  |   77|  12.2M|#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
  ------------------
 3581|       |
 3582|  12.2M|        min_time = std::min(min_time, valOut->mTime);
 3583|  12.2M|        max_time = std::max(max_time, valOut->mTime);
 3584|       |
 3585|  12.2M|        valOut->mValue.x = result[0];
 3586|  12.2M|        valOut->mValue.y = result[1];
 3587|  12.2M|        valOut->mValue.z = result[2];
 3588|       |
 3589|  12.2M|        ++valOut;
 3590|  12.2M|    }
 3591|  8.74k|}
_ZN6Assimp3FBX12FBXConverter15InterpolateKeysEP9aiQuatKeyRKNSt3__16vectorIlNS4_9allocatorIlEEEERKNS5_INS4_5tupleIJNS4_10shared_ptrIS8_EENSC_INS5_IfNS6_IfEEEEEEjEEENS6_ISH_EEEERK10aiVector3tIfERdSQ_NS0_5Model8RotOrderE:
 3597|  2.93k|        Model::RotOrder order) {
 3598|  2.93k|    ai_assert(!keys.empty());
 3599|  2.93k|    ai_assert(nullptr != valOut);
 3600|       |
 3601|  2.93k|    std::unique_ptr<aiVectorKey[]> temp(new aiVectorKey[keys.size()]);
 3602|  2.93k|    InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime);
 3603|       |
 3604|  2.93k|    aiMatrix4x4 m;
 3605|       |
 3606|  2.93k|    aiQuaternion lastq;
 3607|       |
 3608|  4.38M|    for (size_t i = 0, c = keys.size(); i < c; ++i) {
  ------------------
  |  Branch (3608:41): [True: 4.37M, False: 2.93k]
  ------------------
 3609|       |
 3610|  4.37M|        valOut[i].mTime = temp[i].mTime;
 3611|       |
 3612|  4.37M|        GetRotationMatrix(order, temp[i].mValue, m);
 3613|  4.37M|        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.37M|        if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) {
  ------------------
  |  Branch (3617:13): [True: 2.10M, False: 2.27M]
  ------------------
 3618|  2.10M|            quat.Conjugate();
 3619|  2.10M|            quat.w = -quat.w;
 3620|  2.10M|        }
 3621|  4.37M|        lastq = quat;
 3622|       |
 3623|  4.37M|        valOut[i].mValue = quat;
 3624|  4.37M|    }
 3625|  2.93k|}
_ZN6Assimp3FBX12FBXConverter17EulerToQuaternionERK10aiVector3tIfENS0_5Model8RotOrderE:
 3627|    105|aiQuaternion FBXConverter::EulerToQuaternion(const aiVector3D &rot, Model::RotOrder order) {
 3628|    105|    aiMatrix4x4 m;
 3629|    105|    GetRotationMatrix(order, rot, m);
 3630|       |
 3631|    105|    return aiQuaternion(aiMatrix3x3(m));
 3632|    105|}
_ZN6Assimp3FBX12FBXConverter16ConvertScaleKeysEP10aiNodeAnimRKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS4_9allocatorIS8_EEEERKNS4_3mapIS8_PKNS0_14AnimationLayerENS4_4lessIS8_EENS9_INS4_4pairIKS8_SH_EEEEEEllRdSR_:
 3637|    397|        double &minTime) {
 3638|    397|    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|    397|    const KeyFrameListList &inputs = GetKeyframeList(nodes, start, stop);
 3645|    397|    const KeyTimeList &keys = GetKeyTimeList(inputs);
 3646|       |
 3647|    397|    na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
 3648|    397|    na->mScalingKeys = new aiVectorKey[keys.size()];
 3649|    397|    if (keys.size() > 0) {
  ------------------
  |  Branch (3649:9): [True: 357, False: 40]
  ------------------
 3650|    357|        InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime);
 3651|    357|    }
 3652|    397|}
_ZN6Assimp3FBX12FBXConverter22ConvertTranslationKeysEP10aiNodeAnimRKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS4_9allocatorIS8_EEEERKNS4_3mapIS8_PKNS0_14AnimationLayerENS4_4lessIS8_EENS9_INS4_4pairIKS8_SH_EEEEEEllRdSR_:
 3658|    402|        double &minTime) {
 3659|    402|    ai_assert(nodes.size());
 3660|       |
 3661|       |    // XXX see notes in ConvertScaleKeys()
 3662|    402|    const KeyFrameListList &inputs = GetKeyframeList(nodes, start, stop);
 3663|    402|    const KeyTimeList &keys = GetKeyTimeList(inputs);
 3664|       |
 3665|    402|    na->mNumPositionKeys = static_cast<unsigned int>(keys.size());
 3666|    402|    na->mPositionKeys = new aiVectorKey[keys.size()];
 3667|    402|    if (keys.size() > 0)
  ------------------
  |  Branch (3667:9): [True: 354, False: 48]
  ------------------
 3668|    354|        InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime);
 3669|    402|}
_ZN6Assimp3FBX12FBXConverter19ConvertRotationKeysEP10aiNodeAnimRKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS4_9allocatorIS8_EEEERKNS4_3mapIS8_PKNS0_14AnimationLayerENS4_4lessIS8_EENS9_INS4_4pairIKS8_SH_EEEEEEllRdSR_NS0_5Model8RotOrderE:
 3676|    405|        Model::RotOrder order) {
 3677|    405|    ai_assert(nodes.size());
 3678|       |
 3679|       |    // XXX see notes in ConvertScaleKeys()
 3680|    405|    const std::vector<KeyFrameList> &inputs = GetRotationKeyframeList(nodes, start, stop);
 3681|    405|    const KeyTimeList &keys = GetKeyTimeList(inputs);
 3682|       |
 3683|    405|    na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
 3684|    405|    na->mRotationKeys = new aiQuatKey[keys.size()];
 3685|    405|    if (!keys.empty()) {
  ------------------
  |  Branch (3685:9): [True: 405, False: 0]
  ------------------
 3686|    405|        InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order);
 3687|    405|    }
 3688|    405|}
_ZN6Assimp3FBX12FBXConverter21ConvertGlobalSettingsEv:
 3690|    337|void FBXConverter::ConvertGlobalSettings() {
 3691|    337|    if (nullptr == mSceneOut) {
  ------------------
  |  Branch (3691:9): [True: 0, False: 337]
  ------------------
 3692|      0|        return;
 3693|      0|    }
 3694|       |
 3695|    337|    const bool hasGenerator = !doc.Creator().empty();
 3696|       |
 3697|    337|    mSceneOut->mMetaData = aiMetadata::Alloc(16 + (hasGenerator ? 1 : 0));
  ------------------
  |  Branch (3697:52): [True: 317, False: 20]
  ------------------
 3698|    337|    mSceneOut->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis());
 3699|    337|    mSceneOut->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign());
 3700|    337|    mSceneOut->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis());
 3701|    337|    mSceneOut->mMetaData->Set(3, "FrontAxisSign", doc.GlobalSettings().FrontAxisSign());
 3702|    337|    mSceneOut->mMetaData->Set(4, "CoordAxis", doc.GlobalSettings().CoordAxis());
 3703|    337|    mSceneOut->mMetaData->Set(5, "CoordAxisSign", doc.GlobalSettings().CoordAxisSign());
 3704|    337|    mSceneOut->mMetaData->Set(6, "OriginalUpAxis", doc.GlobalSettings().OriginalUpAxis());
 3705|    337|    mSceneOut->mMetaData->Set(7, "OriginalUpAxisSign", doc.GlobalSettings().OriginalUpAxisSign());
 3706|       |    //const double unitScaleFactor = (double)doc.GlobalSettings().UnitScaleFactor();
 3707|    337|    mSceneOut->mMetaData->Set(8, "UnitScaleFactor", doc.GlobalSettings().UnitScaleFactor());
 3708|    337|    mSceneOut->mMetaData->Set(9, "OriginalUnitScaleFactor", doc.GlobalSettings().OriginalUnitScaleFactor());
 3709|    337|    mSceneOut->mMetaData->Set(10, "AmbientColor", doc.GlobalSettings().AmbientColor());
 3710|    337|    mSceneOut->mMetaData->Set(11, "FrameRate", (int)doc.GlobalSettings().TimeMode());
 3711|    337|    mSceneOut->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart());
 3712|    337|    mSceneOut->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop());
 3713|    337|    mSceneOut->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate());
 3714|    337|    mSceneOut->mMetaData->Set(15, AI_METADATA_SOURCE_FORMAT_VERSION, aiString(ai_to_string(doc.FBXVersion())));
 3715|    337|    if (hasGenerator) {
  ------------------
  |  Branch (3715:9): [True: 317, False: 20]
  ------------------
 3716|       |        mSceneOut->mMetaData->Set(16, AI_METADATA_SOURCE_GENERATOR, aiString(doc.Creator()));
 3717|    317|    }
 3718|    337|}
_ZN6Assimp3FBX12FBXConverter19TransferDataToSceneEv:
 3720|    337|void FBXConverter::TransferDataToScene() {
 3721|    337|    ai_assert(!mSceneOut->mMeshes);
 3722|    337|    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|    337|    if (!mMeshes.empty()) {
  ------------------
  |  Branch (3728:9): [True: 159, False: 178]
  ------------------
 3729|    159|        mSceneOut->mMeshes = new aiMesh *[mMeshes.size()]();
 3730|    159|        mSceneOut->mNumMeshes = static_cast<unsigned int>(mMeshes.size());
 3731|       |
 3732|    159|        std::swap_ranges(mMeshes.begin(), mMeshes.end(), mSceneOut->mMeshes);
 3733|    159|    }
 3734|       |
 3735|    337|    if (!materials.empty()) {
  ------------------
  |  Branch (3735:9): [True: 159, False: 178]
  ------------------
 3736|    159|        mSceneOut->mMaterials = new aiMaterial *[materials.size()]();
 3737|    159|        mSceneOut->mNumMaterials = static_cast<unsigned int>(materials.size());
 3738|       |
 3739|    159|        std::swap_ranges(materials.begin(), materials.end(), mSceneOut->mMaterials);
 3740|    159|    }
 3741|       |
 3742|    337|    if (!animations.empty()) {
  ------------------
  |  Branch (3742:9): [True: 215, False: 122]
  ------------------
 3743|    215|        mSceneOut->mAnimations = new aiAnimation *[animations.size()]();
 3744|    215|        mSceneOut->mNumAnimations = static_cast<unsigned int>(animations.size());
 3745|       |
 3746|    215|        std::swap_ranges(animations.begin(), animations.end(), mSceneOut->mAnimations);
 3747|    215|    }
 3748|       |
 3749|    337|    if (!lights.empty()) {
  ------------------
  |  Branch (3749:9): [True: 272, False: 65]
  ------------------
 3750|    272|        mSceneOut->mLights = new aiLight *[lights.size()]();
 3751|    272|        mSceneOut->mNumLights = static_cast<unsigned int>(lights.size());
 3752|       |
 3753|    272|        std::swap_ranges(lights.begin(), lights.end(), mSceneOut->mLights);
 3754|    272|    }
 3755|       |
 3756|    337|    if (!cameras.empty()) {
  ------------------
  |  Branch (3756:9): [True: 286, False: 51]
  ------------------
 3757|    286|        mSceneOut->mCameras = new aiCamera *[cameras.size()]();
 3758|    286|        mSceneOut->mNumCameras = static_cast<unsigned int>(cameras.size());
 3759|       |
 3760|    286|        std::swap_ranges(cameras.begin(), cameras.end(), mSceneOut->mCameras);
 3761|    286|    }
 3762|       |
 3763|    337|    if (!textures.empty()) {
  ------------------
  |  Branch (3763:9): [True: 6, False: 331]
  ------------------
 3764|      6|        mSceneOut->mTextures = new aiTexture *[textures.size()]();
 3765|      6|        mSceneOut->mNumTextures = static_cast<unsigned int>(textures.size());
 3766|       |
 3767|      6|        std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures);
 3768|      6|    }
 3769|       |
 3770|    337|    if (!mSkeletons.empty()) {
  ------------------
  |  Branch (3770:9): [True: 0, False: 337]
  ------------------
 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|    337|}
_ZN6Assimp3FBX12FBXConverter31ConvertOrphanedEmbeddedTexturesEv:
 3777|    344|void FBXConverter::ConvertOrphanedEmbeddedTextures() {
 3778|       |    // in C++14 it could be:
 3779|       |    // for (auto&& [id, object] : objects)
 3780|  58.1k|    for (auto &&id_and_object : doc.Objects()) {
  ------------------
  |  Branch (3780:31): [True: 58.1k, False: 344]
  ------------------
 3781|  58.1k|        auto &&id = std::get<0>(id_and_object);
 3782|  58.1k|        auto &&object = std::get<1>(id_and_object);
 3783|       |        // If an object doesn't have parent
 3784|  58.1k|        if (doc.ConnectionsBySource().count(id) == 0) {
  ------------------
  |  Branch (3784:13): [True: 2.48k, False: 55.6k]
  ------------------
 3785|  2.48k|            const Texture *realTexture = nullptr;
 3786|  2.48k|            try {
 3787|  2.48k|                const auto &element = object->GetElement();
 3788|  2.48k|                const Token &key = element.KeyToken();
 3789|  2.48k|                const char *obtype = key.begin();
 3790|  2.48k|                const size_t length = static_cast<size_t>(key.end() - key.begin());
 3791|  2.48k|                if (strncmp(obtype, "Texture", length) == 0) {
  ------------------
  |  Branch (3791:21): [True: 27, False: 2.46k]
  ------------------
 3792|     27|                    if (const Texture *texture = static_cast<const Texture *>(object->Get())) {
  ------------------
  |  Branch (3792:40): [True: 24, False: 3]
  ------------------
 3793|     24|                        if (texture->Media() && texture->Media()->ContentLength() > 0) {
  ------------------
  |  Branch (3793:29): [True: 16, False: 8]
  |  Branch (3793:49): [True: 2, False: 14]
  ------------------
 3794|      2|                            realTexture = texture;
 3795|      2|                        }
 3796|     24|                    }
 3797|     27|                }
 3798|  2.48k|            } catch (...) {
 3799|       |                // do nothing
 3800|      0|            }
 3801|  2.48k|            if (realTexture) {
  ------------------
  |  Branch (3801:17): [True: 2, False: 2.48k]
  ------------------
 3802|      2|                const Video *media = realTexture->Media();
 3803|      2|                unsigned int index = ConvertVideo(*media);
 3804|      2|                textures_converted[media] = index;
 3805|      2|            }
 3806|  2.48k|        }
 3807|  58.1k|    }
 3808|    344|}
_ZN6Assimp3FBX20ConvertToAssimpSceneEP7aiSceneRKNS0_8DocumentEb:
 3811|    355|void ConvertToAssimpScene(aiScene *out, const Document &doc, bool removeEmptyBones) {
 3812|    355|    FBXConverter converter(out, doc, removeEmptyBones);
 3813|    355|}
FBXConverter.cpp:_ZN6Assimp3FBXL20correctRootTransformEPK7aiScene:
   79|    159|static void correctRootTransform(const aiScene *scene) {
   80|    159|    if (scene == nullptr) {
  ------------------
  |  Branch (80:9): [True: 0, False: 159]
  ------------------
   81|      0|        return;
   82|      0|    }
   83|       |
   84|    159|    if (scene->mMetaData == nullptr) {
  ------------------
  |  Branch (84:9): [True: 0, False: 159]
  ------------------
   85|      0|        return;
   86|      0|    }
   87|       |
   88|    159|    int32_t UpAxis = 1, UpAxisSign = 1, FrontAxis = 2, FrontAxisSign = 1, CoordAxis = 0, CoordAxisSign = 1;
   89|    159|    double UnitScaleFactor = 1.0;
   90|  2.86k|    for (unsigned MetadataIndex = 0; MetadataIndex < scene->mMetaData->mNumProperties; ++MetadataIndex) {
  ------------------
  |  Branch (90:38): [True: 2.70k, False: 159]
  ------------------
   91|  2.70k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UpAxis") == 0) {
  ------------------
  |  Branch (91:13): [True: 159, False: 2.54k]
  ------------------
   92|    159|            scene->mMetaData->Get<int32_t>(MetadataIndex, UpAxis);
   93|    159|        }
   94|  2.70k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UpAxisSign") == 0) {
  ------------------
  |  Branch (94:13): [True: 159, False: 2.54k]
  ------------------
   95|    159|            scene->mMetaData->Get<int32_t>(MetadataIndex, UpAxisSign);
   96|    159|        }
   97|  2.70k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "FrontAxis") == 0) {
  ------------------
  |  Branch (97:13): [True: 159, False: 2.54k]
  ------------------
   98|    159|            scene->mMetaData->Get<int32_t>(MetadataIndex, FrontAxis);
   99|    159|        }
  100|  2.70k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "FrontAxisSign") == 0) {
  ------------------
  |  Branch (100:13): [True: 159, False: 2.54k]
  ------------------
  101|    159|            scene->mMetaData->Get<int32_t>(MetadataIndex, FrontAxisSign);
  102|    159|        }
  103|  2.70k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "CoordAxis") == 0) {
  ------------------
  |  Branch (103:13): [True: 159, False: 2.54k]
  ------------------
  104|    159|            scene->mMetaData->Get<int32_t>(MetadataIndex, CoordAxis);
  105|    159|        }
  106|  2.70k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "CoordAxisSign") == 0) {
  ------------------
  |  Branch (106:13): [True: 159, False: 2.54k]
  ------------------
  107|    159|            scene->mMetaData->Get<int32_t>(MetadataIndex, CoordAxisSign);
  108|    159|        }
  109|  2.70k|        if (strcmp(scene->mMetaData->mKeys[MetadataIndex].C_Str(), "UnitScaleFactor") == 0) {
  ------------------
  |  Branch (109:13): [True: 159, False: 2.54k]
  ------------------
  110|    159|            scene->mMetaData->Get<double>(MetadataIndex, UnitScaleFactor);
  111|    159|        }
  112|  2.70k|    }
  113|       |
  114|    159|    aiVector3D upVec, forwardVec, rightVec;
  115|    159|    upVec[UpAxis] = UpAxisSign * static_cast<float>(UnitScaleFactor);
  116|    159|    forwardVec[FrontAxis] = FrontAxisSign * static_cast<float>(UnitScaleFactor);
  117|    159|    rightVec[CoordAxis] = CoordAxisSign * (float)UnitScaleFactor;
  118|       |
  119|    159|    aiMatrix4x4 mat(rightVec.x, rightVec.y, rightVec.z, 0.0f,
  120|    159|                    upVec.x, upVec.y, upVec.z, 0.0f,
  121|    159|                    forwardVec.x, forwardVec.y, forwardVec.z, 0.0f,
  122|    159|                    0.0f, 0.0f, 0.0f, 1.0f);
  123|    159|    scene->mRootNode->mTransformation *= mat;
  124|    159|}
_ZN6Assimp3FBX12FBXConverter13PotentialNodeptEv:
  241|   147k|    aiNode* operator->() { return mNode; }
_ZN6Assimp3FBX12FBXConverter13PotentialNodeC2Ev:
  239|  6.38k|    PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
FBXConverter.cpp:_ZN6Assimp3FBXL22validateAnimCurveNodesERKNSt3__16vectorIPKNS0_18AnimationCurveNodeENS1_9allocatorIS5_EEEEb:
 2863|  3.08k|        bool strictMode) {
 2864|  3.08k|    const Object *target(nullptr);
 2865|  9.03k|    for (const AnimationCurveNode *node : curves) {
  ------------------
  |  Branch (2865:41): [True: 9.03k, False: 3.08k]
  ------------------
 2866|  9.03k|        if (!target) {
  ------------------
  |  Branch (2866:13): [True: 3.08k, False: 5.95k]
  ------------------
 2867|  3.08k|            target = node->Target();
 2868|  3.08k|        }
 2869|  9.03k|        if (node->Target() != target) {
  ------------------
  |  Branch (2869:13): [True: 200, False: 8.83k]
  ------------------
 2870|    200|            FBXImporter::LogWarn("Node target is nullptr type.");
 2871|    200|        }
 2872|  9.03k|        if (strictMode) {
  ------------------
  |  Branch (2872:13): [True: 0, False: 9.03k]
  ------------------
 2873|       |            ai_assert(node->Target() == target);
 2874|      0|        }
 2875|  9.03k|    }
 2876|  3.08k|}
_ZN6Assimp3FBX12FBXConverter13PotentialNodeC2ERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
  240|    416|    explicit PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}

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

_ZN6Assimp3FBX10LazyObjectC2EmRKNS0_7ElementERKNS0_8DocumentE:
   71|  65.4k|        doc(doc), element(element), id(id), flags() {
   72|       |    // empty
   73|  65.4k|}
_ZN6Assimp3FBX10LazyObject3GetEb:
   76|  74.4k|const Object* LazyObject::Get(bool dieOnError) {
   77|  74.4k|    if(IsBeingConstructed() || FailedToConstruct()) {
  ------------------
  |  Branch (77:8): [True: 0, False: 74.4k]
  |  Branch (77:32): [True: 18, False: 74.4k]
  ------------------
   78|     18|        return nullptr;
   79|     18|    }
   80|       |
   81|  74.4k|    if (object) {
  ------------------
  |  Branch (81:9): [True: 20.8k, False: 53.5k]
  ------------------
   82|  20.8k|        return object.get();
   83|  20.8k|    }
   84|       |
   85|  53.5k|    const Token& key = element.KeyToken();
   86|  53.5k|    const TokenList& tokens = element.Tokens();
   87|       |
   88|  53.5k|    if(tokens.size() < 3) {
  ------------------
  |  Branch (88:8): [True: 4, False: 53.5k]
  ------------------
   89|      4|        DOMError("expected at least 3 tokens: id, name and class tag",&element);
   90|      4|    }
   91|       |
   92|  53.5k|    const char* err;
   93|  53.5k|    std::string name = ParseTokenAsString(*tokens[1],err);
   94|  53.5k|    if (err) {
  ------------------
  |  Branch (94:9): [True: 0, False: 53.5k]
  ------------------
   95|      0|        DOMError(err,&element);
   96|      0|    }
   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|  53.5k|    if(tokens[1]->IsBinary()) {
  ------------------
  |  Branch (103:8): [True: 52.8k, False: 753]
  ------------------
  104|   807k|        for (size_t i = 0; i < name.length(); ++i) {
  ------------------
  |  Branch (104:28): [True: 754k, False: 52.8k]
  ------------------
  105|   754k|            if (name[i] == 0x0 && name[i+1] == 0x1) {
  ------------------
  |  Branch (105:17): [True: 52.8k, False: 701k]
  |  Branch (105:35): [True: 52.7k, False: 84]
  ------------------
  106|  52.7k|                name = name.substr(i+2) + "::" + name.substr(0,i);
  107|  52.7k|            }
  108|   754k|        }
  109|  52.8k|    }
  110|       |
  111|  53.5k|    const std::string classtag = ParseTokenAsString(*tokens[2],err);
  112|  53.5k|    if (err) {
  ------------------
  |  Branch (112:9): [True: 10, False: 53.5k]
  ------------------
  113|     10|        DOMError(err,&element);
  114|     10|    }
  115|       |
  116|       |    // prevent recursive calls
  117|  53.5k|    flags |= BEING_CONSTRUCTED;
  118|       |
  119|  53.5k|    try {
  120|       |        // this needs to be relatively fast since it happens a lot,
  121|       |        // so avoid constructing strings all the time.
  122|  53.5k|        const char* obtype = key.begin();
  123|  53.5k|        const size_t length = static_cast<size_t>(key.end()-key.begin());
  124|       |
  125|       |        // For debugging
  126|       |        //dumpObjectClassInfo( objtype, classtag );
  127|       |
  128|  53.5k|        if (!strncmp(obtype,"Geometry",length)) {
  ------------------
  |  Branch (128:13): [True: 1.69k, False: 51.8k]
  ------------------
  129|  1.69k|            if (!strcmp(classtag.c_str(),"Mesh")) {
  ------------------
  |  Branch (129:17): [True: 1.68k, False: 2]
  ------------------
  130|  1.68k|                object.reset(new MeshGeometry(id,element,name,doc));
  131|  1.68k|            }
  132|  1.69k|            if (!strcmp(classtag.c_str(), "Shape")) {
  ------------------
  |  Branch (132:17): [True: 0, False: 1.69k]
  ------------------
  133|      0|                object.reset(new ShapeGeometry(id, element, name, doc));
  134|      0|            }
  135|  1.69k|            if (!strcmp(classtag.c_str(), "Line")) {
  ------------------
  |  Branch (135:17): [True: 0, False: 1.69k]
  ------------------
  136|      0|                object.reset(new LineGeometry(id, element, name, doc));
  137|      0|            }
  138|  1.69k|        }
  139|  51.8k|        else if (!strncmp(obtype,"NodeAttribute",length)) {
  ------------------
  |  Branch (139:18): [True: 4.08k, False: 47.7k]
  ------------------
  140|  4.08k|            if (!strcmp(classtag.c_str(),"Camera")) {
  ------------------
  |  Branch (140:17): [True: 298, False: 3.79k]
  ------------------
  141|    298|                object.reset(new Camera(id,element,doc,name));
  142|    298|            }
  143|  3.79k|            else if (!strcmp(classtag.c_str(),"CameraSwitcher")) {
  ------------------
  |  Branch (143:22): [True: 0, False: 3.79k]
  ------------------
  144|      0|                object.reset(new CameraSwitcher(id,element,doc,name));
  145|      0|            }
  146|  3.79k|            else if (!strcmp(classtag.c_str(),"Light")) {
  ------------------
  |  Branch (146:22): [True: 277, False: 3.51k]
  ------------------
  147|    277|                object.reset(new Light(id,element,doc,name));
  148|    277|            }
  149|  3.51k|            else if (!strcmp(classtag.c_str(),"Null")) {
  ------------------
  |  Branch (149:22): [True: 184, False: 3.33k]
  ------------------
  150|    184|                object.reset(new Null(id,element,doc,name));
  151|    184|            }
  152|  3.33k|            else if (!strcmp(classtag.c_str(),"LimbNode")) {
  ------------------
  |  Branch (152:22): [True: 3.27k, False: 60]
  ------------------
  153|  3.27k|                object.reset(new LimbNode(id,element,doc,name));
  154|  3.27k|            }
  155|  4.08k|        }
  156|  47.7k|        else if (!strncmp(obtype,"Deformer",length)) {
  ------------------
  |  Branch (156:18): [True: 3.01k, False: 44.7k]
  ------------------
  157|  3.01k|            if (!strcmp(classtag.c_str(),"Cluster")) {
  ------------------
  |  Branch (157:17): [True: 2.80k, False: 211]
  ------------------
  158|  2.80k|                object.reset(new Cluster(id,element,doc,name));
  159|  2.80k|            }
  160|    211|            else if (!strcmp(classtag.c_str(),"Skin")) {
  ------------------
  |  Branch (160:22): [True: 207, False: 4]
  ------------------
  161|    207|                object.reset(new Skin(id,element,doc,name));
  162|    207|            }
  163|      4|            else if (!strcmp(classtag.c_str(), "BlendShape")) {
  ------------------
  |  Branch (163:22): [True: 0, False: 4]
  ------------------
  164|      0|                object.reset(new BlendShape(id, element, doc, name));
  165|      0|            }
  166|      4|            else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) {
  ------------------
  |  Branch (166:22): [True: 0, False: 4]
  ------------------
  167|      0|                object.reset(new BlendShapeChannel(id, element, doc, name));
  168|      0|            }
  169|  3.01k|        }
  170|  44.7k|        else if ( !strncmp( obtype, "Model", length ) ) {
  ------------------
  |  Branch (170:19): [True: 5.88k, False: 38.8k]
  ------------------
  171|       |            // FK and IK effectors are not supported
  172|  5.88k|            if ( strcmp( classtag.c_str(), "IKEffector" ) && strcmp( classtag.c_str(), "FKEffector" ) ) {
  ------------------
  |  Branch (172:18): [True: 5.88k, False: 0]
  |  Branch (172:62): [True: 5.88k, False: 0]
  ------------------
  173|  5.88k|                object.reset( new Model( id, element, doc, name ) );
  174|  5.88k|            }
  175|  5.88k|        }
  176|  38.8k|        else if (!strncmp(obtype,"Material",length)) {
  ------------------
  |  Branch (176:18): [True: 546, False: 38.3k]
  ------------------
  177|    546|            object.reset(new Material(id,element,doc,name));
  178|    546|        }
  179|  38.3k|        else if (!strncmp(obtype,"Texture",length)) {
  ------------------
  |  Branch (179:18): [True: 359, False: 37.9k]
  ------------------
  180|    359|            object.reset(new Texture(id,element,doc,name));
  181|    359|        }
  182|  37.9k|        else if (!strncmp(obtype,"LayeredTexture",length)) {
  ------------------
  |  Branch (182:18): [True: 0, False: 37.9k]
  ------------------
  183|      0|            object.reset(new LayeredTexture(id,element,doc,name));
  184|      0|        }
  185|  37.9k|        else if (!strncmp(obtype,"Video",length)) {
  ------------------
  |  Branch (185:18): [True: 309, False: 37.6k]
  ------------------
  186|    309|            object.reset(new Video(id,element,doc,name));
  187|    309|        }
  188|  37.6k|        else if (!strncmp(obtype,"AnimationStack",length)) {
  ------------------
  |  Branch (188:18): [True: 247, False: 37.4k]
  ------------------
  189|    247|            object.reset(new AnimationStack(id,element,name,doc));
  190|    247|        }
  191|  37.4k|        else if (!strncmp(obtype,"AnimationLayer",length)) {
  ------------------
  |  Branch (191:18): [True: 231, False: 37.1k]
  ------------------
  192|    231|            object.reset(new AnimationLayer(id,element,name,doc));
  193|    231|        }
  194|       |        // note: order matters for these two
  195|  37.1k|        else if (!strncmp(obtype,"AnimationCurve",length)) {
  ------------------
  |  Branch (195:18): [True: 26.6k, False: 10.5k]
  ------------------
  196|  26.6k|            object.reset(new AnimationCurve(id,element,name,doc));
  197|  26.6k|        }
  198|  10.5k|        else if (!strncmp(obtype,"AnimationCurveNode",length)) {
  ------------------
  |  Branch (198:18): [True: 10.0k, False: 515]
  ------------------
  199|  10.0k|            object.reset(new AnimationCurveNode(id,element,name,doc));
  200|  10.0k|        }
  201|  53.5k|    }
  202|  53.5k|    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|  53.5k|    catch(std::exception& ex) {
  211|  2.76k|        flags &= ~BEING_CONSTRUCTED;
  212|  2.76k|        flags |= FAILED_TO_CONSTRUCT;
  213|       |
  214|  2.76k|        if(dieOnError || doc.Settings().strictMode) {
  ------------------
  |  Branch (214:12): [True: 0, False: 2.76k]
  |  Branch (214:26): [True: 0, False: 2.76k]
  ------------------
  215|      0|            throw;
  216|      0|        }
  217|       |
  218|       |        // note: the error message is already formatted, so raw logging is ok
  219|  2.76k|        if(!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (219:12): [True: 0, False: 2.76k]
  ------------------
  220|      0|            ASSIMP_LOG_ERROR(ex.what());
  221|      0|        }
  222|  2.76k|        return nullptr;
  223|  2.76k|    }
  224|       |
  225|  50.7k|    if (!object) {
  ------------------
  |  Branch (225:9): [True: 581, False: 50.2k]
  ------------------
  226|       |        //DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element);
  227|    581|    }
  228|       |
  229|  50.7k|    flags &= ~BEING_CONSTRUCTED;
  230|  50.7k|    return object.get();
  231|  53.5k|}
_ZN6Assimp3FBX6ObjectC2EmRKNS0_7ElementERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
  235|  52.9k|        element(element), name(name), id(id) {
  236|       |    // empty
  237|  52.9k|}
_ZN6Assimp3FBX18FileGlobalSettingsC2ERKNS0_8DocumentENSt3__110shared_ptrIKNS0_13PropertyTableEEE:
  241|    365|        props(std::move(props)), doc(doc) {
  242|       |    // empty
  243|    365|}
_ZN6Assimp3FBX8DocumentC2ERNS0_6ParserERKNS0_14ImportSettingsE:
  247|    371|     settings(settings), parser(parser) {
  248|    371|	ASSIMP_LOG_DEBUG("Creating FBX Document");
  249|       |
  250|       |    // Cannot use array default initialization syntax because vc8 fails on it
  251|  2.59k|    for (auto &timeStamp : creationTimeStamp) {
  ------------------
  |  Branch (251:26): [True: 2.59k, False: 371]
  ------------------
  252|  2.59k|        timeStamp = 0;
  253|  2.59k|    }
  254|       |
  255|    371|    ReadHeader();
  256|    371|    ReadPropertyTemplates();
  257|       |
  258|    371|    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|    371|    ReadObjects();
  264|    371|    ReadConnections();
  265|    371|}
_ZN6Assimp3FBX8DocumentD2Ev:
  269|    355|{
  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.5k|    for (ObjectMap::value_type &v : objects) {
  ------------------
  |  Branch (273:35): [True: 60.5k, False: 355]
  ------------------
  274|  60.5k|        delete_LazyObject(v.second);
  ------------------
  |  |   91|  60.5k|#define delete_LazyObject(_p) (_p)->~LazyObject()
  ------------------
  275|  60.5k|    }
  276|       |
  277|  90.4k|    for (ConnectionMap::value_type &v : src_connections) {
  ------------------
  |  Branch (277:39): [True: 90.4k, False: 355]
  ------------------
  278|  90.4k|        delete_Connection(v.second);
  ------------------
  |  |   92|  90.4k|#define delete_Connection(_p) (_p)->~Connection()
  ------------------
  279|  90.4k|    }
  280|       |    // |dest_connections| contain the same Connection objects as the |src_connections|
  281|    355|}
_ZN6Assimp3FBX8Document10ReadHeaderEv:
  287|    371|void Document::ReadHeader() {
  288|       |    // Read ID objects from "Objects" section
  289|    371|    const Scope& sc = parser.GetRootScope();
  290|    371|    const Element* const ehead = sc["FBXHeaderExtension"];
  291|    371|    if(!ehead || !ehead->Compound()) {
  ------------------
  |  Branch (291:8): [True: 4, False: 367]
  |  Branch (291:18): [True: 0, False: 367]
  ------------------
  292|      4|        DOMError("no FBXHeaderExtension dictionary found");
  293|      4|    }
  294|       |
  295|    367|    const Scope& shead = *ehead->Compound();
  296|    367|    fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
  297|    367|	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|    367|    if(fbxVersion < LowerSupportedVersion ) {
  ------------------
  |  Branch (301:8): [True: 0, False: 367]
  ------------------
  302|      0|        DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013");
  303|      0|    }
  304|    367|    if(fbxVersion > UpperSupportedVersion ) {
  ------------------
  |  Branch (304:8): [True: 46, False: 321]
  ------------------
  305|     46|        if(Settings().strictMode) {
  ------------------
  |  Branch (305:12): [True: 0, False: 46]
  ------------------
  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|     46|        else {
  310|     46|            DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013,"
  311|     46|                " trying to read it nevertheless");
  312|     46|        }
  313|     46|    }
  314|       |
  315|    367|    const Element* const ecreator = shead["Creator"];
  316|    367|    if(ecreator) {
  ------------------
  |  Branch (316:8): [True: 333, False: 34]
  ------------------
  317|    333|        creator = ParseTokenAsString(GetRequiredToken(*ecreator,0));
  318|    333|    }
  319|       |
  320|    367|    const Element* const etimestamp = shead["CreationTimeStamp"];
  321|    367|    if(etimestamp && etimestamp->Compound()) {
  ------------------
  |  Branch (321:8): [True: 343, False: 24]
  |  Branch (321:22): [True: 343, False: 0]
  ------------------
  322|    343|        const Scope& stimestamp = *etimestamp->Compound();
  323|    343|        creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0));
  324|    343|        creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0));
  325|    343|        creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0));
  326|    343|        creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0));
  327|    343|        creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0));
  328|    343|        creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0));
  329|    343|        creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0));
  330|    343|    }
  331|    367|}
_ZN6Assimp3FBX8Document18ReadGlobalSettingsEv:
  334|    365|void Document::ReadGlobalSettings() {
  335|    365|    const Scope& sc = parser.GetRootScope();
  336|    365|    const Element* const ehead = sc["GlobalSettings"];
  337|    365|    if ( nullptr == ehead || !ehead->Compound() ) {
  ------------------
  |  Branch (337:10): [True: 39, False: 326]
  |  Branch (337:30): [True: 0, False: 326]
  ------------------
  338|     39|        DOMWarning( "no GlobalSettings dictionary found" );
  339|     39|        globals.reset(new FileGlobalSettings(*this, std::make_shared<const PropertyTable>()));
  340|     39|        return;
  341|     39|    }
  342|       |
  343|    326|    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|    326|    if(!props) {
  ------------------
  |  Branch (347:8): [True: 0, False: 326]
  ------------------
  348|      0|        DOMError("GlobalSettings dictionary contains no property table");
  349|      0|    }
  350|       |
  351|    326|    globals.reset(new FileGlobalSettings(*this, std::move(props)));
  352|    326|}
_ZN6Assimp3FBX8Document11ReadObjectsEv:
  355|    365|void Document::ReadObjects() {
  356|       |    // read ID objects from "Objects" section
  357|    365|    const Scope& sc = parser.GetRootScope();
  358|    365|    const Element* const eobjects = sc["Objects"];
  359|    365|    if(!eobjects || !eobjects->Compound()) {
  ------------------
  |  Branch (359:8): [True: 7, False: 358]
  |  Branch (359:21): [True: 0, False: 358]
  ------------------
  360|      7|        DOMError("no Objects dictionary found");
  361|      7|    }
  362|       |
  363|    358|    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|    358|    objects[0] = new_LazyObject(0L, *eobjects, *this);
  ------------------
  |  |   89|    716|#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject
  ------------------
  368|       |
  369|    358|    const Scope& sobjects = *eobjects->Compound();
  370|  65.1k|    for(const ElementMap::value_type& el : sobjects.Elements()) {
  ------------------
  |  Branch (370:42): [True: 65.1k, False: 358]
  ------------------
  371|       |
  372|       |        // extract ID
  373|  65.1k|        const TokenList& tok = el.second->Tokens();
  374|       |
  375|  65.1k|        if (tok.empty()) {
  ------------------
  |  Branch (375:13): [True: 0, False: 65.1k]
  ------------------
  376|      0|            DOMError("expected ID after object key",el.second);
  377|      0|        }
  378|       |
  379|  65.1k|        const char* err;
  380|  65.1k|        const uint64_t id = ParseTokenAsID(*tok[0], err);
  381|  65.1k|        if(err) {
  ------------------
  |  Branch (381:12): [True: 0, False: 65.1k]
  ------------------
  382|      0|            DOMError(err,el.second);
  383|      0|        }
  384|       |
  385|       |        // id=0 is normally implicit
  386|  65.1k|        if(id == 0L) {
  ------------------
  |  Branch (386:12): [True: 0, False: 65.1k]
  ------------------
  387|      0|            DOMError("encountered object with implicitly defined id 0",el.second);
  388|      0|        }
  389|       |
  390|  65.1k|        const auto foundObject = objects.find(id);
  391|  65.1k|        if(foundObject != objects.end()) {
  ------------------
  |  Branch (391:12): [True: 4.96k, False: 60.1k]
  ------------------
  392|  4.96k|            DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second);
  393|  4.96k|            delete_LazyObject(foundObject->second);
  ------------------
  |  |   91|  4.96k|#define delete_LazyObject(_p) (_p)->~LazyObject()
  ------------------
  394|  4.96k|        }
  395|       |
  396|  65.1k|        objects[id] = new_LazyObject(id, *el.second, *this);
  ------------------
  |  |   89|   130k|#define new_LazyObject new (allocator.Allocate(sizeof(LazyObject))) LazyObject
  ------------------
  397|       |
  398|       |        // grab all animation stacks upfront since there is no listing of them
  399|  65.1k|        if(!strcmp(el.first.c_str(),"AnimationStack")) {
  ------------------
  |  Branch (399:12): [True: 1.46k, False: 63.6k]
  ------------------
  400|  1.46k|            animationStacks.push_back(id);
  401|  1.46k|        }
  402|  65.1k|    }
  403|    358|}
_ZN6Assimp3FBX8Document21ReadPropertyTemplatesEv:
  406|    365|void Document::ReadPropertyTemplates() {
  407|    365|    const Scope& sc = parser.GetRootScope();
  408|       |    // read property templates from "Definitions" section
  409|    365|    const Element* const edefs = sc["Definitions"];
  410|    365|    if(!edefs || !edefs->Compound()) {
  ------------------
  |  Branch (410:8): [True: 30, False: 335]
  |  Branch (410:18): [True: 0, False: 335]
  ------------------
  411|     30|        DOMWarning("no Definitions dictionary found");
  412|     30|        return;
  413|     30|    }
  414|       |
  415|    335|    const Scope& sdefs = *edefs->Compound();
  416|    335|    const ElementCollection otypes = sdefs.GetCollection("ObjectType");
  417|  4.14k|    for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
  ------------------
  |  Branch (417:55): [True: 3.81k, False: 335]
  ------------------
  418|  3.81k|        const Element& el = *(*it).second;
  419|  3.81k|        const Scope* curSc = el.Compound();
  420|  3.81k|        if (!curSc) {
  ------------------
  |  Branch (420:13): [True: 0, False: 3.81k]
  ------------------
  421|      0|            DOMWarning("expected nested scope in ObjectType, ignoring",&el);
  422|      0|            continue;
  423|      0|        }
  424|       |
  425|  3.81k|        const TokenList& tok = el.Tokens();
  426|  3.81k|        if(tok.empty()) {
  ------------------
  |  Branch (426:12): [True: 0, False: 3.81k]
  ------------------
  427|      0|            DOMWarning("expected name for ObjectType element, ignoring",&el);
  428|      0|            continue;
  429|      0|        }
  430|       |
  431|  3.81k|        const std::string& oname = ParseTokenAsString(*tok[0]);
  432|       |
  433|  3.81k|        const ElementCollection templs = curSc->GetCollection("PropertyTemplate");
  434|  6.60k|        for (ElementMap::const_iterator elemIt = templs.first; elemIt != templs.second; ++elemIt) {
  ------------------
  |  Branch (434:64): [True: 2.79k, False: 3.81k]
  ------------------
  435|  2.79k|            const Element &innerEl = *(*elemIt).second;
  436|  2.79k|            const Scope *innerSc = innerEl.Compound();
  437|  2.79k|            if (!innerSc) {
  ------------------
  |  Branch (437:17): [True: 0, False: 2.79k]
  ------------------
  438|      0|                DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el);
  439|      0|                continue;
  440|      0|            }
  441|       |
  442|  2.79k|            const TokenList &curTok = innerEl.Tokens();
  443|  2.79k|            if (curTok.empty()) {
  ------------------
  |  Branch (443:17): [True: 0, False: 2.79k]
  ------------------
  444|      0|                DOMWarning("expected name for PropertyTemplate element, ignoring",&el);
  445|      0|                continue;
  446|      0|            }
  447|       |
  448|  2.79k|            const std::string &pname = ParseTokenAsString(*curTok[0]);
  449|       |
  450|  2.79k|            const Element *Properties70 = (*innerSc)["Properties70"];
  451|  2.79k|            if(Properties70) {
  ------------------
  |  Branch (451:16): [True: 2.75k, False: 35]
  ------------------
  452|  2.75k|                std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>(
  453|  2.75k|                        *Properties70, std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable *>(nullptr))
  454|  2.75k|                );
  455|       |
  456|  2.75k|                templates[oname+"."+pname] = props;
  457|  2.75k|            }
  458|  2.79k|        }
  459|  3.81k|    }
  460|    335|}
_ZN6Assimp3FBX8Document15ReadConnectionsEv:
  464|    356|{
  465|    356|    StackAllocator &allocator = parser.GetAllocator();
  466|    356|    const Scope &sc = parser.GetRootScope();
  467|       |    // read property templates from "Definitions" section
  468|    356|    const Element* const econns = sc["Connections"];
  469|    356|    if(!econns || !econns->Compound()) {
  ------------------
  |  Branch (469:8): [True: 1, False: 355]
  |  Branch (469:19): [True: 0, False: 355]
  ------------------
  470|      1|        DOMError("no Connections dictionary found");
  471|      1|    }
  472|       |
  473|    355|    uint64_t insertionOrder = 0l;
  474|    355|    const Scope& sconns = *econns->Compound();
  475|    355|    const ElementCollection conns = sconns.GetCollection("C");
  476|  94.1k|    for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
  ------------------
  |  Branch (476:54): [True: 93.7k, False: 355]
  ------------------
  477|  93.7k|        const Element& el = *(*it).second;
  478|  93.7k|        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|  93.7k|        if ( type == "PP" ) {
  ------------------
  |  Branch (482:14): [True: 1, False: 93.7k]
  ------------------
  483|      1|            continue;
  484|      1|        }
  485|       |
  486|  93.7k|        const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
  487|  93.7k|        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|  93.7k|        const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : "");
  ------------------
  |  Branch (491:36): [True: 46.2k, False: 47.5k]
  ------------------
  492|       |
  493|  93.7k|        if(objects.find(src) == objects.end()) {
  ------------------
  |  Branch (493:12): [True: 1.49k, False: 92.2k]
  ------------------
  494|  1.49k|            DOMWarning("source object for connection does not exist",&el);
  495|  1.49k|            continue;
  496|  1.49k|        }
  497|       |
  498|       |        // dest may be 0 (root node) but we added a dummy object before
  499|  92.2k|        if(objects.find(dest) == objects.end()) {
  ------------------
  |  Branch (499:12): [True: 1.83k, False: 90.4k]
  ------------------
  500|  1.83k|            DOMWarning("destination object for connection does not exist",&el);
  501|  1.83k|            continue;
  502|  1.83k|        }
  503|       |
  504|       |        // add new connection
  505|  90.4k|        const Connection* const c = new_Connection(insertionOrder++,src,dest,prop,*this);
  ------------------
  |  |   90|   180k|#define new_Connection new (allocator.Allocate(sizeof(Connection))) Connection
  ------------------
  506|  90.4k|        src_connections.insert(ConnectionMap::value_type(src,c));
  507|  90.4k|        dest_connections.insert(ConnectionMap::value_type(dest,c));
  508|  90.4k|    }
  509|    355|}
_ZNK6Assimp3FBX8Document15AnimationStacksEv:
  512|    355|const std::vector<const AnimationStack*>& Document::AnimationStacks() const {
  513|    355|    if (!animationStacksResolved.empty() || animationStacks.empty()) {
  ------------------
  |  Branch (513:9): [True: 0, False: 355]
  |  Branch (513:45): [True: 106, False: 249]
  ------------------
  514|    106|        return animationStacksResolved;
  515|    106|    }
  516|       |
  517|    249|    animationStacksResolved.reserve(animationStacks.size());
  518|    763|    for(uint64_t id : animationStacks) {
  ------------------
  |  Branch (518:21): [True: 763, False: 249]
  ------------------
  519|    763|        LazyObject* const lazy = GetObject(id);
  520|    763|        const AnimationStack *stack = lazy->Get<AnimationStack>();
  521|    763|        if(!lazy || nullptr == stack ) {
  ------------------
  |  Branch (521:12): [True: 1, False: 762]
  |  Branch (521:21): [True: 515, False: 247]
  ------------------
  522|    515|            DOMWarning("failed to read AnimationStack object");
  523|    515|            continue;
  524|    515|        }
  525|    248|        animationStacksResolved.push_back(stack);
  526|    248|    }
  527|       |
  528|    249|    return animationStacksResolved;
  529|    355|}
_ZNK6Assimp3FBX8Document9GetObjectEm:
  532|   193k|LazyObject* Document::GetObject(uint64_t id) const {
  533|   193k|    ObjectMap::const_iterator it = objects.find(id);
  534|   193k|    return it == objects.end() ? nullptr : (*it).second;
  ------------------
  |  Branch (534:12): [True: 0, False: 193k]
  ------------------
  535|   193k|}
_ZNK6Assimp3FBX8Document23GetConnectionsSequencedEmRKNSt3__118unordered_multimapImPKNS0_10ConnectionENS2_4hashImEENS2_8equal_toImEENS2_9allocatorINS2_4pairIKmS6_EEEEEE:
  540|    897|std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const {
  541|    897|    std::vector<const Connection*> temp;
  542|       |
  543|    897|    const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
  544|    897|        conns.equal_range(id);
  545|       |
  546|    897|    temp.reserve(std::distance(range.first,range.second));
  547|  13.3k|    for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
  ------------------
  |  Branch (547:58): [True: 12.4k, False: 897]
  ------------------
  548|  12.4k|        temp.push_back((*it).second);
  549|  12.4k|    }
  550|       |
  551|    897|    std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
  552|       |
  553|    897|    return temp; // NRVO should handle this
  554|    897|}
_ZNK6Assimp3FBX8Document23GetConnectionsSequencedEmbRKNSt3__118unordered_multimapImPKNS0_10ConnectionENS2_4hashImEENS2_8equal_toImEENS2_9allocatorINS2_4pairIKmS6_EEEEEEPKPKcm:
  560|  38.8k|        size_t count) const {
  561|  38.8k|    ai_assert(classnames);
  562|  38.8k|    ai_assert( count != 0 );
  563|  38.8k|    ai_assert( count <= MAX_CLASSNAMES);
  564|       |
  565|  38.8k|    size_t lengths[MAX_CLASSNAMES] = {};
  566|       |
  567|  38.8k|    const size_t c = count;
  568|   109k|    for (size_t i = 0; i < c; ++i) {
  ------------------
  |  Branch (568:24): [True: 70.5k, False: 38.8k]
  ------------------
  569|  70.5k|        lengths[ i ] = strlen(classnames[i]);
  570|  70.5k|    }
  571|       |
  572|  38.8k|    std::vector<const Connection*> temp;
  573|  38.8k|    const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range =
  574|  38.8k|        conns.equal_range(id);
  575|       |
  576|  38.8k|    temp.reserve(std::distance(range.first,range.second));
  577|   157k|    for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) {
  ------------------
  |  Branch (577:58): [True: 118k, False: 38.8k]
  ------------------
  578|   118k|        const Token& key = (is_src
  ------------------
  |  Branch (578:29): [True: 19.5k, False: 99.2k]
  ------------------
  579|   118k|            ? (*it).second->LazyDestinationObject()
  580|   118k|            : (*it).second->LazySourceObject()
  581|   118k|        ).GetElement().KeyToken();
  582|       |
  583|   118k|        const char* obtype = key.begin();
  584|       |
  585|   225k|        for (size_t i = 0; i < c; ++i) {
  ------------------
  |  Branch (585:28): [True: 174k, False: 50.5k]
  ------------------
  586|   174k|            ai_assert(classnames[i]);
  587|   174k|            if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lengths[i] && !strncmp(classnames[i],obtype,lengths[i])) {
  ------------------
  |  Branch (587:16): [True: 71.0k, False: 103k]
  |  Branch (587:91): [True: 68.1k, False: 2.91k]
  ------------------
  588|  68.1k|                obtype = nullptr;
  589|  68.1k|                break;
  590|  68.1k|            }
  591|   174k|        }
  592|       |
  593|   118k|        if(obtype) {
  ------------------
  |  Branch (593:12): [True: 50.5k, False: 68.1k]
  ------------------
  594|  50.5k|            continue;
  595|  50.5k|        }
  596|       |
  597|  68.1k|        temp.push_back((*it).second);
  598|  68.1k|    }
  599|       |
  600|  38.8k|    std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare));
  601|  38.8k|    return temp; // NRVO should handle this
  602|  38.8k|}
_ZNK6Assimp3FBX8Document31GetConnectionsBySourceSequencedEmPKPKcm:
  617|  10.0k|        const char* const* classnames, size_t count) const {
  618|  10.0k|    return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count);
  619|  10.0k|}
_ZNK6Assimp3FBX8Document36GetConnectionsByDestinationSequencedEmPKc:
  623|  22.9k|        const char* classname) const {
  624|  22.9k|    const char* arr[] = {classname};
  625|  22.9k|    return GetConnectionsByDestinationSequenced(dest, arr,1);
  626|  22.9k|}
_ZNK6Assimp3FBX8Document36GetConnectionsByDestinationSequencedEm:
  629|    897|std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const {
  630|    897|    return GetConnectionsSequenced(dest, ConnectionsByDestination());
  631|    897|}
_ZNK6Assimp3FBX8Document36GetConnectionsByDestinationSequencedEmPKPKcm:
  635|  28.8k|        const char* const* classnames, size_t count) const {
  636|  28.8k|    return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count);
  637|  28.8k|}
_ZN6Assimp3FBX10ConnectionC2EmmmRKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERKNS0_8DocumentE:
  642|  90.4k|            insertionOrder(insertionOrder), prop(prop), src(src), dest(dest), doc(doc) {
  643|  90.4k|    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|  90.4k|}
_ZNK6Assimp3FBX10Connection16LazySourceObjectEv:
  649|  99.2k|LazyObject& Connection::LazySourceObject() const {
  650|  99.2k|    LazyObject* const lazy = doc.GetObject(src);
  651|       |    ai_assert(lazy);
  652|  99.2k|    return *lazy;
  653|  99.2k|}
_ZNK6Assimp3FBX10Connection21LazyDestinationObjectEv:
  656|  19.5k|LazyObject& Connection::LazyDestinationObject() const {
  657|  19.5k|    LazyObject* const lazy = doc.GetObject(dest);
  658|       |    ai_assert(lazy);
  659|  19.5k|    return *lazy;
  660|  19.5k|}
_ZNK6Assimp3FBX10Connection12SourceObjectEv:
  663|  64.1k|const Object* Connection::SourceObject() const {
  664|  64.1k|    LazyObject* const lazy = doc.GetObject(src);
  665|  64.1k|    ai_assert(lazy);
  666|  64.1k|    if (lazy == nullptr) {
  ------------------
  |  Branch (666:9): [True: 0, False: 64.1k]
  ------------------
  667|      0|        return nullptr;
  668|      0|    }
  669|       |
  670|  64.1k|    return lazy->Get();
  671|  64.1k|}
_ZNK6Assimp3FBX10Connection17DestinationObjectEv:
  674|  9.47k|const Object* Connection::DestinationObject() const {
  675|  9.47k|    LazyObject* const lazy = doc.GetObject(dest);
  676|  9.47k|    ai_assert(lazy);
  677|  9.47k|    if (lazy == nullptr) {
  ------------------
  |  Branch (677:9): [True: 0, False: 9.47k]
  ------------------
  678|      0|        return nullptr;
  679|      0|    }
  680|       |
  681|  9.47k|    return lazy->Get();
  682|  9.47k|}

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

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

_ZN6Assimp3FBX4Util23ProcessSimpleConnectionINS0_4SkinEEEPKT_RKNS0_10ConnectionEbPKcRKNS0_7ElementEPSB_:
   80|    207|        const char** propNameOut = nullptr) {
   81|    207|    if (is_object_property_conn && !con.PropertyName().length()) {
  ------------------
  |  Branch (81:9): [True: 0, False: 207]
  |  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|    207|    else if (!is_object_property_conn && con.PropertyName().length()) {
  ------------------
  |  Branch (88:14): [True: 207, False: 0]
  |  Branch (88:42): [True: 0, False: 207]
  ------------------
   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|    207|    if(is_object_property_conn && propNameOut) {
  ------------------
  |  Branch (96:8): [True: 0, False: 207]
  |  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|    207|    const Object* const ob = con.SourceObject();
  103|    207|    if(!ob) {
  ------------------
  |  Branch (103:8): [True: 0, False: 207]
  ------------------
  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|    207|    return dynamic_cast<const T*>(ob);
  111|    207|}
_ZN6Assimp3FBX4Util23ProcessSimpleConnectionINS0_10BlendShapeEEEPKT_RKNS0_10ConnectionEbPKcRKNS0_7ElementEPSB_:
   80|    207|        const char** propNameOut = nullptr) {
   81|    207|    if (is_object_property_conn && !con.PropertyName().length()) {
  ------------------
  |  Branch (81:9): [True: 0, False: 207]
  |  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|    207|    else if (!is_object_property_conn && con.PropertyName().length()) {
  ------------------
  |  Branch (88:14): [True: 207, False: 0]
  |  Branch (88:42): [True: 0, False: 207]
  ------------------
   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|    207|    if(is_object_property_conn && propNameOut) {
  ------------------
  |  Branch (96:8): [True: 0, False: 207]
  |  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|    207|    const Object* const ob = con.SourceObject();
  103|    207|    if(!ob) {
  ------------------
  |  Branch (103:8): [True: 0, False: 207]
  ------------------
  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|    207|    return dynamic_cast<const T*>(ob);
  111|    207|}
_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: 1, False: 1.32k]
  ------------------
  104|      1|        DOMWarning("failed to read source object for incoming " + std::string(name) +
  105|      1|            " link, ignoring",
  106|      1|            &element);
  107|      1|        return nullptr;
  108|      1|    }
  109|       |
  110|  1.32k|    return dynamic_cast<const T*>(ob);
  111|  1.32k|}
_ZN6Assimp3FBX4Util23ProcessSimpleConnectionINS0_7ClusterEEEPKT_RKNS0_10ConnectionEbPKcRKNS0_7ElementEPSB_:
   80|  2.81k|        const char** propNameOut = nullptr) {
   81|  2.81k|    if (is_object_property_conn && !con.PropertyName().length()) {
  ------------------
  |  Branch (81:9): [True: 0, False: 2.81k]
  |  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.81k|    else if (!is_object_property_conn && con.PropertyName().length()) {
  ------------------
  |  Branch (88:14): [True: 2.81k, False: 0]
  |  Branch (88:42): [True: 0, False: 2.81k]
  ------------------
   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.81k|    if(is_object_property_conn && propNameOut) {
  ------------------
  |  Branch (96:8): [True: 0, False: 2.81k]
  |  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.81k|    const Object* const ob = con.SourceObject();
  103|  2.81k|    if(!ob) {
  ------------------
  |  Branch (103:8): [True: 1.48k, False: 1.32k]
  ------------------
  104|  1.48k|        DOMWarning("failed to read source object for incoming " + std::string(name) +
  105|  1.48k|            " link, ignoring",
  106|  1.48k|            &element);
  107|  1.48k|        return nullptr;
  108|  1.48k|    }
  109|       |
  110|  1.32k|    return dynamic_cast<const T*>(ob);
  111|  2.81k|}

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

_ZNK6Assimp11FBXImporter7GetInfoEv:
   99|  1.20k|const aiImporterDesc *FBXImporter::GetInfo() const {
  100|  1.20k|	return &desc;
  101|  1.20k|}
_ZN6Assimp11FBXImporter15SetupPropertiesEPKNS_8ImporterE:
  105|    402|void FBXImporter::SetupProperties(const Importer *pImp) {
  106|    402|    mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
  107|    402|    mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
  108|    402|    mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
  109|    402|    mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
  110|    402|    mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
  111|    402|    mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
  112|    402|    mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
  113|    402|    mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
  114|    402|    mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
  115|    402|    mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
  116|    402|    mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
  117|    402|    mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
  118|    402|    mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
  119|    402|    mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
  120|    402|    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|    402|}
_ZN6Assimp11FBXImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  126|    402|void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  127|    402|	auto streamCloser = [&](IOStream *pStream) {
  128|    402|		pIOHandler->Close(pStream);
  129|    402|	};
  130|    402|	std::unique_ptr<IOStream, decltype(streamCloser)> stream(pIOHandler->Open(pFile, "rb"), streamCloser);
  131|    402|	if (!stream) {
  ------------------
  |  Branch (131:6): [True: 0, False: 402]
  ------------------
  132|      0|		ThrowException("Could not open file for reading");
  133|      0|	}
  134|       |
  135|    402|    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|    402|	std::vector<char> contents;
  143|    402|	contents.resize(stream->FileSize() + 1);
  144|    402|	stream->Read(&*contents.begin(), 1, contents.size() - 1);
  145|    402|	contents[contents.size() - 1] = 0;
  146|    402|	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|    402|	TokenList tokens;
  151|    402|    Assimp::StackAllocator tempAllocator;
  152|    402|    try {
  153|    402|		bool is_binary = false;
  154|    402|		if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
  ------------------
  |  Branch (154:7): [True: 325, False: 77]
  ------------------
  155|    325|			is_binary = true;
  156|    325|            TokenizeBinary(tokens, begin, contents.size(), tempAllocator);
  157|    325|		} else {
  158|     77|            Tokenize(tokens, begin, tempAllocator);
  159|     77|		}
  160|       |
  161|       |		// use this information to construct a very rudimentary
  162|       |		// parse-tree representing the FBX scope structure
  163|    402|        Parser parser(tokens, tempAllocator, is_binary);
  164|       |
  165|       |		// take the raw parse-tree and convert it to a FBX DOM
  166|    402|		Document doc(parser, mSettings);
  167|       |
  168|       |		// convert the FBX DOM to aiScene
  169|    402|		ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
  170|       |
  171|       |		// size relative to cm
  172|    402|		float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
  173|    402|        if (size_relative_to_cm == 0.0) {
  ------------------
  |  Branch (173:13): [True: 0, False: 402]
  ------------------
  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|    402|		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|    402|        std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
  184|       |
  185|    402|    } catch (std::exception &) {
  186|     65|        std::for_each(tokens.begin(), tokens.end(), Util::destructor_fun<Token>());
  187|     65|        throw;
  188|     65|	}
  189|    402|}
FBXImporter.cpp:_ZZN6Assimp11FBXImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemEENK3$_0clEPNS_8IOStreamE:
  127|    402|	auto streamCloser = [&](IOStream *pStream) {
  128|    402|		pIOHandler->Close(pStream);
  129|    402|	};

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

_ZN6Assimp3FBX8MaterialC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   66|    546|        Object(id,element,name) {
   67|    546|    const Scope& sc = GetRequiredScope(element);
   68|       |
   69|    546|    const Element* const ShadingModel = sc["ShadingModel"];
   70|    546|    const Element* const MultiLayer = sc["MultiLayer"];
   71|       |
   72|    546|    if(MultiLayer) {
  ------------------
  |  Branch (72:8): [True: 545, False: 1]
  ------------------
   73|    545|        multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0));
   74|    545|    }
   75|       |
   76|    546|    if(ShadingModel) {
  ------------------
  |  Branch (76:8): [True: 544, False: 2]
  ------------------
   77|    544|        shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0));
   78|    544|    } else {
   79|      2|        DOMWarning("shading mode not specified, assuming phong",&element);
   80|      2|        shading = "phong";
   81|      2|    }
   82|       |
   83|       |    // lower-case shading because Blender (for example) writes "Phong"
   84|  3.31k|    for (size_t i = 0; i < shading.length(); ++i) {
  ------------------
  |  Branch (84:24): [True: 2.76k, False: 546]
  ------------------
   85|  2.76k|        shading[i] = static_cast<char>(tolower(static_cast<unsigned char>(shading[i])));
   86|  2.76k|    }
   87|    546|    std::string templateName;
   88|    546|    if(shading == "phong") {
  ------------------
  |  Branch (88:8): [True: 528, False: 18]
  ------------------
   89|    528|        templateName = "Material.FbxSurfacePhong";
   90|    528|    } else if(shading == "lambert") {
  ------------------
  |  Branch (90:15): [True: 12, False: 6]
  ------------------
   91|     12|        templateName = "Material.FbxSurfaceLambert";
   92|     12|    } else {
   93|      6|        DOMWarning("shading mode not recognized: " + shading,&element);
   94|      6|    }
   95|       |
   96|    546|    props = GetPropertyTable(doc,templateName,element,sc);
   97|       |
   98|       |    // resolve texture links
   99|    546|    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
  100|  4.17k|    for(const Connection* con : conns) {
  ------------------
  |  Branch (100:31): [True: 4.17k, False: 546]
  ------------------
  101|       |        // texture link to properties, not objects
  102|  4.17k|        if ( 0 == con->PropertyName().length()) {
  ------------------
  |  Branch (102:14): [True: 2, False: 4.17k]
  ------------------
  103|      2|            continue;
  104|      2|        }
  105|       |
  106|  4.17k|        const Object* const ob = con->SourceObject();
  107|  4.17k|        if(nullptr == ob) {
  ------------------
  |  Branch (107:12): [True: 8, False: 4.16k]
  ------------------
  108|      8|            DOMWarning("failed to read source object for texture link, ignoring",&element);
  109|      8|            continue;
  110|      8|        }
  111|       |
  112|  4.16k|        const Texture* const tex = dynamic_cast<const Texture*>(ob);
  113|  4.16k|        if(nullptr == tex) {
  ------------------
  |  Branch (113:12): [True: 7, False: 4.15k]
  ------------------
  114|      7|            const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
  115|      7|            if(!layeredTexture) {
  ------------------
  |  Branch (115:16): [True: 7, False: 0]
  ------------------
  116|      7|                DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
  117|      7|                continue;
  118|      7|            }
  119|      0|            const std::string& prop = con->PropertyName();
  120|      0|            if (layeredTextures.find(prop) != layeredTextures.end()) {
  ------------------
  |  Branch (120:17): [True: 0, False: 0]
  ------------------
  121|      0|                DOMWarning("duplicate layered texture link: " + prop,&element);
  122|      0|            }
  123|       |
  124|      0|            layeredTextures[prop] = layeredTexture;
  125|      0|            ((LayeredTexture*)layeredTexture)->fillTexture(doc);
  126|  4.15k|        } else {
  127|  4.15k|            const std::string& prop = con->PropertyName();
  128|  4.15k|            if (textures.find(prop) != textures.end()) {
  ------------------
  |  Branch (128:17): [True: 3.80k, False: 347]
  ------------------
  129|  3.80k|                DOMWarning("duplicate texture link: " + prop,&element);
  130|  3.80k|            }
  131|       |
  132|  4.15k|            textures[prop] = tex;
  133|  4.15k|        }
  134|  4.16k|    }
  135|    546|}
_ZN6Assimp3FBX7TextureC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  139|    359|        Object(id,element,name),
  140|    359|        uvTrans(0.0f, 0.0f),
  141|    359|        uvScaling(1.0f,1.0f),
  142|    359|        uvRotation(0.0f),
  143|    359|        type(),
  144|    359|        relativeFileName(),
  145|    359|        fileName(),
  146|    359|        alphaSource(),
  147|    359|        props(),
  148|    359|        media(nullptr) {
  149|    359|    const Scope& sc = GetRequiredScope(element);
  150|       |
  151|    359|    const Element* const Type = sc["Type"];
  152|    359|    const Element* const FileName = sc["FileName"];
  153|    359|    const Element* const RelativeFilename = sc["RelativeFilename"];
  154|    359|    const Element* const ModelUVTranslation = sc["ModelUVTranslation"];
  155|    359|    const Element* const ModelUVScaling = sc["ModelUVScaling"];
  156|    359|    const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"];
  157|    359|    const Element* const Cropping = sc["Cropping"];
  158|       |
  159|    359|    if(Type) {
  ------------------
  |  Branch (159:8): [True: 349, False: 10]
  ------------------
  160|    349|        type = ParseTokenAsString(GetRequiredToken(*Type,0));
  161|    349|    }
  162|       |
  163|    359|    if(FileName) {
  ------------------
  |  Branch (163:8): [True: 359, False: 0]
  ------------------
  164|    359|        fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
  165|    359|    }
  166|       |
  167|    359|    if(RelativeFilename) {
  ------------------
  |  Branch (167:8): [True: 359, False: 0]
  ------------------
  168|    359|        relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
  169|    359|    }
  170|       |
  171|    359|    if(ModelUVTranslation) {
  ------------------
  |  Branch (171:8): [True: 49, False: 310]
  ------------------
  172|     49|        uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)),
  173|     49|            ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1))
  174|     49|        );
  175|     49|    }
  176|       |
  177|    359|    if(ModelUVScaling) {
  ------------------
  |  Branch (177:8): [True: 49, False: 310]
  ------------------
  178|     49|        uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)),
  179|     49|            ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1))
  180|     49|        );
  181|     49|    }
  182|       |
  183|    359|    if(Cropping) {
  ------------------
  |  Branch (183:8): [True: 49, False: 310]
  ------------------
  184|     49|        crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0));
  185|     49|        crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1));
  186|     49|        crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2));
  187|     49|        crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3));
  188|    310|    } else {
  189|       |        // vc8 doesn't support the crop() syntax in initialization lists
  190|       |        // (and vc9 WARNS about the new (i.e. compliant) behaviour).
  191|    310|        crop[0] = crop[1] = crop[2] = crop[3] = 0;
  192|    310|    }
  193|       |
  194|    359|    if(Texture_Alpha_Source) {
  ------------------
  |  Branch (194:8): [True: 49, False: 310]
  ------------------
  195|     49|        alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0));
  196|     49|    }
  197|       |
  198|    359|    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|    359|    bool ok;
  202|    359|    const aiVector3D& scaling = PropertyGet<aiVector3D>(*props, "Scaling", ok);
  203|    359|    if (ok) {
  ------------------
  |  Branch (203:9): [True: 323, False: 36]
  ------------------
  204|    323|        uvScaling.x = scaling.x;
  205|    323|        uvScaling.y = scaling.y;
  206|    323|    }
  207|       |
  208|    359|    const aiVector3D& trans = PropertyGet<aiVector3D>(*props, "Translation", ok);
  209|    359|    if (ok) {
  ------------------
  |  Branch (209:9): [True: 319, False: 40]
  ------------------
  210|    319|        uvTrans.x = trans.x;
  211|    319|        uvTrans.y = trans.y;
  212|    319|    }
  213|       |
  214|    359|    const aiVector3D &rotation = PropertyGet<aiVector3D>(*props, "Rotation", ok);
  215|    359|    if (ok) {
  ------------------
  |  Branch (215:9): [True: 319, False: 40]
  ------------------
  216|    319|        uvRotation = rotation.z;
  217|    319|    }
  218|       |
  219|       |    // resolve video links
  220|    359|    if(doc.Settings().readTextures) {
  ------------------
  |  Branch (220:8): [True: 351, False: 8]
  ------------------
  221|    351|        const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
  222|  6.18k|        for(const Connection* con : conns) {
  ------------------
  |  Branch (222:35): [True: 6.18k, False: 351]
  ------------------
  223|  6.18k|            const Object* const ob = con->SourceObject();
  224|  6.18k|            if (nullptr == ob) {
  ------------------
  |  Branch (224:17): [True: 0, False: 6.18k]
  ------------------
  225|      0|                DOMWarning("failed to read source object for texture link, ignoring",&element);
  226|      0|                continue;
  227|      0|            }
  228|       |
  229|  6.18k|            const Video* const video = dynamic_cast<const Video*>(ob);
  230|  6.18k|            if(video) {
  ------------------
  |  Branch (230:16): [True: 6.18k, False: 3]
  ------------------
  231|  6.18k|                media = video;
  232|  6.18k|            }
  233|  6.18k|        }
  234|    351|    }
  235|    359|}
_ZN6Assimp3FBX7TextureD2Ev:
  238|    348|Texture::~Texture() = default;
_ZN6Assimp3FBX5VideoC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  278|    309|        Object(id, element, name),
  279|    309|        contentLength(0),
  280|    309|        content(nullptr) {
  281|    309|    const Scope& sc = GetRequiredScope(element);
  282|       |
  283|    309|    const Element* const Type = sc["Type"];
  284|    309|    const Element* const FileName = sc.FindElementCaseInsensitive("FileName");  //some files retain the information as "Filename", others "FileName", who knows
  285|    309|    const Element* const RelativeFilename = sc["RelativeFilename"];
  286|    309|    const Element* const Content = sc["Content"];
  287|       |
  288|    309|    if(Type) {
  ------------------
  |  Branch (288:8): [True: 309, False: 0]
  ------------------
  289|    309|        type = ParseTokenAsString(GetRequiredToken(*Type,0));
  290|    309|    }
  291|       |
  292|    309|    if(FileName) {
  ------------------
  |  Branch (292:8): [True: 309, False: 0]
  ------------------
  293|    309|        fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
  294|    309|    }
  295|       |
  296|    309|    if(RelativeFilename) {
  ------------------
  |  Branch (296:8): [True: 309, False: 0]
  ------------------
  297|    309|        relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
  298|    309|    }
  299|       |
  300|    309|    if(Content && !Content->Tokens().empty()) {
  ------------------
  |  Branch (300:8): [True: 11, False: 298]
  |  Branch (300:19): [True: 11, False: 0]
  ------------------
  301|       |        //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
  302|     11|        try {
  303|     11|            const Token& token = GetRequiredToken(*Content, 0);
  304|     11|            const char* data = token.begin();
  305|     11|            if (!token.IsBinary()) {
  ------------------
  |  Branch (305:17): [True: 11, False: 0]
  ------------------
  306|     11|                if (*data != '"') {
  ------------------
  |  Branch (306:21): [True: 0, False: 11]
  ------------------
  307|      0|                    DOMError("embedded content is not surrounded by quotation marks", &element);
  308|     11|                } else {
  309|     11|                    size_t targetLength = 0;
  310|     11|                    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|     22|                    for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
  ------------------
  |  Branch (312:49): [True: 11, False: 11]
  ------------------
  313|     11|                        const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
  314|     11|                        size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
  315|     11|                        const char* base64data = dataToken.begin() + 1;
  316|     11|                        const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
  317|     11|                        if (outLength == 0) {
  ------------------
  |  Branch (317:29): [True: 0, False: 11]
  ------------------
  318|      0|                            DOMError("Corrupted embedded content found", &element);
  319|      0|                        }
  320|     11|                        targetLength += outLength;
  321|     11|                    }
  322|     11|                    if (targetLength == 0) {
  ------------------
  |  Branch (322:25): [True: 0, False: 11]
  ------------------
  323|      0|                        DOMError("Corrupted embedded content found", &element);
  324|      0|                    }
  325|     11|                    content = new uint8_t[targetLength];
  326|     11|                    contentLength = static_cast<uint64_t>(targetLength);
  327|     11|                    size_t dst_offset = 0;
  328|     22|                    for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) {
  ------------------
  |  Branch (328:49): [True: 11, False: 11]
  ------------------
  329|     11|                        const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
  330|     11|                        size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
  331|     11|                        const char* base64data = dataToken.begin() + 1;
  332|     11|                        dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
  333|     11|                    }
  334|     11|                    if (targetLength != dst_offset) {
  ------------------
  |  Branch (334:25): [True: 5, False: 6]
  ------------------
  335|      5|                        delete[] content;
  336|      5|                        contentLength = 0;
  337|      5|                        DOMError("Corrupted embedded content found", &element);
  338|      5|                    }
  339|     11|                }
  340|     11|            } 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|     11|        } catch (const runtime_error& runtimeError) {
  356|       |            //we don't need the content data for contents that has already been loaded
  357|      5|            ASSIMP_LOG_VERBOSE_DEBUG("Caught exception in FBXMaterial (likely because content was already loaded): ",
  358|      5|                    runtimeError.what());
  359|      5|        }
  360|     11|    }
  361|       |
  362|    309|    props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
  363|    309|}
_ZN6Assimp3FBX5VideoD2Ev:
  365|    309|Video::~Video() {
  366|    309|    if (contentLength > 0) {
  ------------------
  |  Branch (366:9): [True: 6, False: 303]
  ------------------
  367|      6|        delete[] content;
  368|      6|    }
  369|    309|}

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

_ZN6Assimp3FBX8GeometryD2Ev:
   67|  1.68k|    virtual ~Geometry() = default;
_ZN6Assimp3FBX12MeshGeometryD2Ev:
   98|    789|    virtual ~MeshGeometry() = default;

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

_ZN6Assimp3FBX13NodeAttributeC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   60|  4.02k|        Object(id, element, name), props() {
   61|  4.02k|    const Scope &sc = GetRequiredScope(element);
   62|       |
   63|  4.02k|    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.02k|    const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
  ------------------
  |  Branch (68:34): [True: 184, False: 3.84k]
  |  Branch (68:72): [True: 3.27k, False: 575]
  ------------------
   69|  4.02k|    props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
   70|  4.02k|}
_ZN6Assimp3FBX6CameraC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
   95|    298|        NodeAttribute(id, element, doc, name) {
   96|       |    // empty
   97|    298|}
_ZN6Assimp3FBX5LightC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  101|    277|        NodeAttribute(id, element, doc, name) {
  102|       |    // empty
  103|    277|}
_ZN6Assimp3FBX4NullC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  107|    184|        NodeAttribute(id, element, doc, name) {
  108|       |    // empty
  109|    184|}
_ZN6Assimp3FBX8LimbNodeC2EmRKNS0_7ElementERKNS0_8DocumentERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEE:
  113|  3.27k|        NodeAttribute(id, element, doc, name) {
  114|       |    // empty
  115|  3.27k|}

_ZN6Assimp3FBX7ElementC2ERKNS0_5TokenERNS0_6ParserE:
  115|   749k|    key_token(key_token), compound(nullptr)
  116|   749k|{
  117|   749k|    TokenPtr n = nullptr;
  118|   749k|    StackAllocator &allocator = parser.GetAllocator();
  119|  2.61M|    do {
  120|  2.61M|        n = parser.AdvanceToNextToken();
  121|  2.61M|        if(!n) {
  ------------------
  |  Branch (121:12): [True: 2, False: 2.61M]
  ------------------
  122|      2|            ParseError("unexpected end of file, expected closing bracket",parser.LastToken());
  123|      2|        }
  124|       |
  125|  2.61M|        if (n->Type() == TokenType_DATA) {
  ------------------
  |  Branch (125:13): [True: 2.57M, False: 44.5k]
  ------------------
  126|  2.57M|            tokens.push_back(n);
  127|  2.57M|			TokenPtr prev = n;
  128|  2.57M|            n = parser.AdvanceToNextToken();
  129|  2.57M|            if(!n) {
  ------------------
  |  Branch (129:16): [True: 1, False: 2.57M]
  ------------------
  130|      1|                ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken());
  131|      1|            }
  132|       |
  133|  2.57M|			const TokenType ty = n->Type();
  134|       |
  135|       |			// some exporters are missing a comma on the next line
  136|  2.57M|			if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) {
  ------------------
  |  Branch (136:8): [True: 2.05k, False: 2.57M]
  |  Branch (136:32): [True: 2.05k, False: 0]
  |  Branch (136:66): [True: 2.05k, False: 0]
  ------------------
  137|  2.05k|				tokens.push_back(n);
  138|  2.05k|				continue;
  139|  2.05k|			}
  140|       |
  141|  2.57M|            if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
  ------------------
  |  Branch (141:17): [True: 2.49M, False: 76.2k]
  |  Branch (141:49): [True: 2.40M, False: 87.0k]
  |  Branch (141:82): [True: 541k, False: 1.86M]
  |  Branch (141:107): [True: 0, False: 541k]
  ------------------
  142|      0|                ParseError("unexpected token; expected bracket, comma or key",n);
  143|      0|            }
  144|  2.57M|        }
  145|       |
  146|  2.61M|        if (n->Type() == TokenType_OPEN_BRACKET) {
  ------------------
  |  Branch (146:13): [True: 117k, False: 2.50M]
  ------------------
  147|   117k|            compound = new_Scope(parser);
  ------------------
  |  |   70|   235k|#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope
  ------------------
  148|       |
  149|       |            // current token should be a TOK_CLOSE_BRACKET
  150|   117k|            n = parser.CurrentToken();
  151|   117k|            ai_assert(n);
  ------------------
  |  |   67|   117k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 117k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  152|       |
  153|   117k|            if (n->Type() != TokenType_CLOSE_BRACKET) {
  ------------------
  |  Branch (153:17): [True: 0, False: 117k]
  ------------------
  154|      0|                ParseError("expected closing bracket",n);
  155|      0|            }
  156|       |
  157|   117k|            parser.AdvanceToNextToken();
  158|   117k|            return;
  159|   117k|        }
  160|  2.61M|    }
  161|  2.50M|    while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
  ------------------
  |  Branch (161:11): [True: 1.95M, False: 544k]
  |  Branch (161:41): [True: 1.87M, False: 87.3k]
  ------------------
  162|   749k|}
_ZN6Assimp3FBX7ElementD2Ev:
  166|   749k|{
  167|   749k|    if (compound) {
  ------------------
  |  Branch (167:9): [True: 117k, False: 632k]
  ------------------
  168|   117k|        delete_Scope(compound);
  ------------------
  |  |   72|   117k|#define delete_Scope(_p) (_p)->~Scope()
  ------------------
  169|   117k|    }
  170|       |
  171|       |     // no need to delete tokens, they are owned by the parser
  172|   749k|}
_ZN6Assimp3FBX5ScopeC2ERNS0_6ParserEb:
  175|   117k|{
  176|   117k|    if(!topLevel) {
  ------------------
  |  Branch (176:8): [True: 117k, False: 384]
  ------------------
  177|   117k|        TokenPtr t = parser.CurrentToken();
  178|   117k|        if (t->Type() != TokenType_OPEN_BRACKET) {
  ------------------
  |  Branch (178:13): [True: 0, False: 117k]
  ------------------
  179|      0|            ParseError("expected open bracket",t);
  180|      0|        }
  181|   117k|    }
  182|       |
  183|   117k|    StackAllocator &allocator = parser.GetAllocator();
  184|   117k|    TokenPtr n = parser.AdvanceToNextToken();
  185|   117k|    if (n == nullptr) {
  ------------------
  |  Branch (185:9): [True: 2, False: 117k]
  ------------------
  186|      2|        ParseError("unexpected end of file");
  187|      2|    }
  188|       |
  189|       |    // note: empty scopes are allowed
  190|   867k|    while(n->Type() != TokenType_CLOSE_BRACKET) {
  ------------------
  |  Branch (190:11): [True: 749k, False: 117k]
  ------------------
  191|   749k|        if (n->Type() != TokenType_KEY) {
  ------------------
  |  Branch (191:13): [True: 8, False: 749k]
  ------------------
  192|      8|            ParseError("unexpected token, expected TOK_KEY",n);
  193|      8|        }
  194|       |
  195|   749k|        const std::string& str = n->StringContents();
  196|   749k|        if (str.empty()) {
  ------------------
  |  Branch (196:13): [True: 0, False: 749k]
  ------------------
  197|      0|            ParseError("unexpected content: empty string.");
  198|      0|        }
  199|       |
  200|   749k|        auto *element = new_Element(*n, parser);
  ------------------
  |  |   71|  1.49M|#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|   749k|        n = parser.CurrentToken();
  204|   749k|        if (n == nullptr) {
  ------------------
  |  Branch (204:13): [True: 350, False: 749k]
  ------------------
  205|    350|            if (topLevel) {
  ------------------
  |  Branch (205:17): [True: 350, False: 0]
  ------------------
  206|    350|                elements.insert(ElementMap::value_type(str, element));
  207|    350|                return;
  208|    350|            }
  209|      0|            delete_Element(element);
  ------------------
  |  |   73|      0|#define delete_Element(_p) (_p)->~Element()
  ------------------
  210|      0|            ParseError("unexpected end of file",parser.LastToken());
  211|   749k|        } else {
  212|   749k|            elements.insert(ElementMap::value_type(str, element));
  213|   749k|        }
  214|   749k|    }
  215|   117k|}
_ZN6Assimp3FBX5ScopeD2Ev:
  219|   117k|{
  220|       |	// This collection does not own the memory for the elements, but we need to call their d'tor:
  221|       |
  222|   749k|    for (ElementMap::value_type &v : elements) {
  ------------------
  |  Branch (222:36): [True: 749k, False: 117k]
  ------------------
  223|   749k|        delete_Element(v.second);
  ------------------
  |  |   73|   749k|#define delete_Element(_p) (_p)->~Element()
  ------------------
  224|   749k|    }
  225|   117k|}
_ZN6Assimp3FBX6ParserC2ERKNSt3__16vectorIPKNS0_5TokenENS2_9allocatorIS6_EEEERNS_14StackAllocatorEb:
  229|    384|        tokens(tokens), allocator(allocator), last(), current(), cursor(tokens.begin()), is_binary(is_binary)
  230|    384|{
  231|    384|    ASSIMP_LOG_DEBUG("Parsing FBX tokens");
  232|    384|    root = new_Scope(*this, true);
  ------------------
  |  |   70|    768|#define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope
  ------------------
  233|    384|}
_ZN6Assimp3FBX6ParserD2Ev:
  237|    371|{
  238|    371|    delete_Scope(root);
  ------------------
  |  |   72|    371|#define delete_Scope(_p) (_p)->~Scope()
  ------------------
  239|    371|}
_ZN6Assimp3FBX6Parser18AdvanceToNextTokenEv:
  243|  5.43M|{
  244|  5.43M|    last = current;
  245|  5.43M|    if (cursor == tokens.end()) {
  ------------------
  |  Branch (245:9): [True: 355, False: 5.43M]
  ------------------
  246|    355|        current = nullptr;
  247|  5.43M|    } else {
  248|  5.43M|        current = *cursor++;
  249|  5.43M|    }
  250|  5.43M|    return current;
  251|  5.43M|}
_ZNK6Assimp3FBX6Parser12CurrentTokenEv:
  255|   984k|{
  256|   984k|    return current;
  257|   984k|}
_ZNK6Assimp3FBX6Parser9LastTokenEv:
  261|      3|{
  262|      3|    return last;
  263|      3|}
_ZN6Assimp3FBX14ParseTokenAsIDERKNS0_5TokenERPKc:
  267|   252k|{
  268|   252k|    err_out = nullptr;
  269|       |
  270|   252k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (270:9): [True: 0, False: 252k]
  ------------------
  271|      0|        err_out = "expected TOK_DATA token";
  272|      0|        return 0L;
  273|      0|    }
  274|       |
  275|   252k|    if(t.IsBinary())
  ------------------
  |  Branch (275:8): [True: 208k, False: 43.9k]
  ------------------
  276|   208k|    {
  277|   208k|        const char* data = t.begin();
  278|   208k|        if (data[0] != 'L') {
  ------------------
  |  Branch (278:13): [True: 0, False: 208k]
  ------------------
  279|      0|            err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
  280|      0|            return 0L;
  281|      0|        }
  282|       |
  283|   208k|        BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
  284|   208k|        AI_SWAP8(id);
  285|   208k|        return id;
  286|   208k|    }
  287|       |
  288|       |    // XXX: should use size_t here
  289|  43.9k|    unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
  290|  43.9k|    ai_assert(length > 0);
  ------------------
  |  |   67|  43.9k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 43.9k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  291|       |
  292|  43.9k|    const char* out = nullptr;
  293|  43.9k|    const uint64_t id = strtoul10_64(t.begin(),&out,&length);
  294|  43.9k|    if (out > t.end()) {
  ------------------
  |  Branch (294:9): [True: 0, False: 43.9k]
  ------------------
  295|      0|        err_out = "failed to parse ID (text)";
  296|      0|        return 0L;
  297|      0|    }
  298|       |
  299|  43.9k|    return id;
  300|  43.9k|}
_ZN6Assimp3FBX15ParseTokenAsDimERKNS0_5TokenERPKc:
  304|    196|{
  305|       |    // same as ID parsing, except there is a trailing asterisk
  306|    196|    err_out = nullptr;
  307|       |
  308|    196|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (308:9): [True: 0, False: 196]
  ------------------
  309|      0|        err_out = "expected TOK_DATA token";
  310|      0|        return 0;
  311|      0|    }
  312|       |
  313|    196|    if(t.IsBinary())
  ------------------
  |  Branch (313:8): [True: 0, False: 196]
  ------------------
  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|    196|    if(*t.begin() != '*') {
  ------------------
  |  Branch (326:8): [True: 0, False: 196]
  ------------------
  327|      0|        err_out = "expected asterisk before array dimension";
  328|      0|        return 0;
  329|      0|    }
  330|       |
  331|       |    // XXX: should use size_t here
  332|    196|    unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
  333|    196|    if(length == 0) {
  ------------------
  |  Branch (333:8): [True: 0, False: 196]
  ------------------
  334|      0|        err_out = "expected valid integer number after asterisk";
  335|      0|        return 0;
  336|      0|    }
  337|       |
  338|    196|    const char* out = nullptr;
  339|    196|    const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length));
  340|    196|    if (out > t.end()) {
  ------------------
  |  Branch (340:9): [True: 0, False: 196]
  ------------------
  341|      0|        err_out = "failed to parse ID";
  342|      0|        return 0;
  343|      0|    }
  344|       |
  345|    196|    return id;
  346|    196|}
_ZN6Assimp3FBX17ParseTokenAsFloatERKNS0_5TokenERPKc:
  351|   102k|{
  352|   102k|    err_out = nullptr;
  353|       |
  354|   102k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (354:9): [True: 0, False: 102k]
  ------------------
  355|      0|        err_out = "expected TOK_DATA token";
  356|      0|        return 0.0f;
  357|      0|    }
  358|       |
  359|   102k|    if(t.IsBinary())
  ------------------
  |  Branch (359:8): [True: 68.2k, False: 33.8k]
  ------------------
  360|  68.2k|    {
  361|  68.2k|        const char* data = t.begin();
  362|  68.2k|        if (data[0] != 'F' && data[0] != 'D') {
  ------------------
  |  Branch (362:13): [True: 68.2k, False: 0]
  |  Branch (362:31): [True: 7, False: 68.2k]
  ------------------
  363|      7|            err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
  364|      7|            return 0.0f;
  365|      7|        }
  366|       |
  367|  68.2k|        if (data[0] == 'F') {
  ------------------
  |  Branch (367:13): [True: 0, False: 68.2k]
  ------------------
  368|      0|            BE_NCONST float id = SafeParse<float>(data+1, t.end());
  369|      0|            AI_SWAP4(id);
  370|      0|            return id;
  371|      0|        }
  372|  68.2k|        else {
  373|  68.2k|            BE_NCONST double id = SafeParse<double>(data+1, t.end());
  374|  68.2k|            AI_SWAP8(id);
  375|  68.2k|            return static_cast<float>(id);
  376|  68.2k|        }
  377|  68.2k|    }
  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|  33.8k|#define MAX_FLOAT_LENGTH 31
  383|  33.8k|    const size_t length = static_cast<size_t>(t.end()-t.begin());
  384|  33.8k|    if (length > MAX_FLOAT_LENGTH) {
  ------------------
  |  |  382|  33.8k|#define MAX_FLOAT_LENGTH 31
  ------------------
  |  Branch (384:9): [True: 32, False: 33.8k]
  ------------------
  385|     32|        return 0.f;
  386|     32|    }
  387|       |
  388|  33.8k|    char temp[MAX_FLOAT_LENGTH + 1];
  389|  33.8k|    std::copy(t.begin(), t.end(), temp);
  390|  33.8k|    temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0';
  ------------------
  |  |  382|  33.8k|#define MAX_FLOAT_LENGTH 31
  ------------------
  391|       |
  392|  33.8k|    return fast_atof(temp);
  393|  33.8k|}
_ZN6Assimp3FBX15ParseTokenAsIntERKNS0_5TokenERPKc:
  398|   443k|{
  399|   443k|    err_out = nullptr;
  400|       |
  401|   443k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (401:9): [True: 0, False: 443k]
  ------------------
  402|      0|        err_out = "expected TOK_DATA token";
  403|      0|        return 0;
  404|      0|    }
  405|       |
  406|   443k|    if(t.IsBinary())
  ------------------
  |  Branch (406:8): [True: 25.4k, False: 417k]
  ------------------
  407|  25.4k|    {
  408|  25.4k|        const char* data = t.begin();
  409|  25.4k|        if (data[0] != 'I') {
  ------------------
  |  Branch (409:13): [True: 1, False: 25.4k]
  ------------------
  410|      1|            err_out = "failed to parse I(nt), unexpected data type (binary)";
  411|      1|            return 0;
  412|      1|        }
  413|       |
  414|  25.4k|        BE_NCONST int32_t ival = SafeParse<int32_t>(data+1, t.end());
  415|  25.4k|        AI_SWAP4(ival);
  416|  25.4k|        return static_cast<int>(ival);
  417|  25.4k|    }
  418|       |
  419|   417k|    ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0);
  ------------------
  |  |   67|   417k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 417k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  420|       |
  421|   417k|    const char* out;
  422|   417k|    const int intval = strtol10(t.begin(),&out);
  423|   417k|    if (out != t.end()) {
  ------------------
  |  Branch (423:9): [True: 2, False: 417k]
  ------------------
  424|      2|        err_out = "failed to parse ID";
  425|      2|        return 0;
  426|      2|    }
  427|       |
  428|   417k|    return intval;
  429|   417k|}
_ZN6Assimp3FBX17ParseTokenAsInt64ERKNS0_5TokenERPKc:
  434|  1.05k|{
  435|  1.05k|    err_out = nullptr;
  436|       |
  437|  1.05k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (437:9): [True: 0, False: 1.05k]
  ------------------
  438|      0|        err_out = "expected TOK_DATA token";
  439|      0|        return 0L;
  440|      0|    }
  441|       |
  442|  1.05k|    if (t.IsBinary())
  ------------------
  |  Branch (442:9): [True: 1.00k, False: 52]
  ------------------
  443|  1.00k|    {
  444|  1.00k|        const char* data = t.begin();
  445|  1.00k|        if (data[0] != 'L') {
  ------------------
  |  Branch (445:13): [True: 0, False: 1.00k]
  ------------------
  446|      0|            err_out = "failed to parse Int64, unexpected data type";
  447|      0|            return 0L;
  448|      0|        }
  449|       |
  450|  1.00k|        BE_NCONST int64_t id = SafeParse<int64_t>(data + 1, t.end());
  451|  1.00k|        AI_SWAP8(id);
  452|  1.00k|        return id;
  453|  1.00k|    }
  454|       |
  455|       |    // XXX: should use size_t here
  456|     52|    unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
  457|     52|    ai_assert(length > 0);
  ------------------
  |  |   67|     52|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 52, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  458|       |
  459|     52|    const char* out = nullptr;
  460|     52|    const int64_t id = strtol10_64(t.begin(), &out, &length);
  461|     52|    if (out > t.end()) {
  ------------------
  |  Branch (461:9): [True: 0, False: 52]
  ------------------
  462|      0|        err_out = "failed to parse Int64 (text)";
  463|      0|        return 0L;
  464|      0|    }
  465|       |
  466|     52|    return id;
  467|     52|}
_ZN6Assimp3FBX18ParseTokenAsStringERKNS0_5TokenERPKc:
  471|   481k|{
  472|   481k|    err_out = nullptr;
  473|       |
  474|   481k|    if (t.Type() != TokenType_DATA) {
  ------------------
  |  Branch (474:9): [True: 0, False: 481k]
  ------------------
  475|      0|        err_out = "expected TOK_DATA token";
  476|      0|        return std::string();
  477|      0|    }
  478|       |
  479|   481k|    if(t.IsBinary())
  ------------------
  |  Branch (479:8): [True: 441k, False: 40.0k]
  ------------------
  480|   441k|    {
  481|   441k|        const char* data = t.begin();
  482|   441k|        if (data[0] != 'S') {
  ------------------
  |  Branch (482:13): [True: 21, False: 441k]
  ------------------
  483|     21|            err_out = "failed to parse S(tring), unexpected data type (binary)";
  484|     21|            return std::string();
  485|     21|        }
  486|       |
  487|       |        // read string length
  488|   441k|        BE_NCONST int32_t len = SafeParse<int32_t>(data+1, t.end());
  489|   441k|        AI_SWAP4(len);
  490|       |
  491|   441k|        ai_assert(t.end() - data == 5 + len);
  ------------------
  |  |   67|   441k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 441k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  492|   441k|        return std::string(data + 5, len);
  493|   441k|    }
  494|       |
  495|  40.0k|    const size_t length = static_cast<size_t>(t.end() - t.begin());
  496|  40.0k|    if(length < 2) {
  ------------------
  |  Branch (496:8): [True: 0, False: 40.0k]
  ------------------
  497|      0|        err_out = "token is too short to hold a string";
  498|      0|        return std::string();
  499|      0|    }
  500|       |
  501|  40.0k|    const char* s = t.begin(), *e = t.end() - 1;
  502|  40.0k|    if (*s != '\"' || *e != '\"') {
  ------------------
  |  Branch (502:9): [True: 1, False: 40.0k]
  |  Branch (502:23): [True: 0, False: 40.0k]
  ------------------
  503|      1|        err_out = "expected double quoted string";
  504|      1|        return std::string();
  505|      1|    }
  506|       |
  507|  40.0k|    return std::string(s+1,length-2);
  508|  40.0k|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEERKNS0_7ElementE:
  602|  2.79k|{
  603|  2.79k|    out.resize( 0 );
  604|       |
  605|  2.79k|    const TokenList& tok = el.Tokens();
  606|  2.79k|    if(tok.empty()) {
  ------------------
  |  Branch (606:8): [True: 0, False: 2.79k]
  ------------------
  607|      0|        ParseError("unexpected empty element",&el);
  608|      0|    }
  609|       |
  610|  2.79k|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (610:8): [True: 2.69k, False: 95]
  ------------------
  611|  2.69k|        const char* data = tok[0]->begin(), *end = tok[0]->end();
  612|       |
  613|  2.69k|        char type;
  614|  2.69k|        uint32_t count;
  615|  2.69k|        ReadBinaryDataArrayHead(data, end, type, count, el);
  616|       |
  617|  2.69k|        if(count % 3 != 0) {
  ------------------
  |  Branch (617:12): [True: 1, False: 2.69k]
  ------------------
  618|      1|            ParseError("number of floats is not a multiple of three (3) (binary)",&el);
  619|      1|        }
  620|       |
  621|  2.69k|        if(!count) {
  ------------------
  |  Branch (621:12): [True: 0, False: 2.69k]
  ------------------
  622|      0|            return;
  623|      0|        }
  624|       |
  625|  2.69k|        if (type != 'd' && type != 'f') {
  ------------------
  |  Branch (625:13): [True: 2, False: 2.69k]
  |  Branch (625:28): [True: 0, False: 2]
  ------------------
  626|      0|            ParseError("expected float or double array (binary)",&el);
  627|      0|        }
  628|       |
  629|  2.69k|        std::vector<char> buff;
  630|  2.69k|        ReadBinaryDataArray(type, count, data, end, buff, el);
  631|       |
  632|  2.69k|        ai_assert(data == end);
  ------------------
  |  |   67|  2.69k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 2.69k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  633|  2.69k|        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
  ------------------
  |  Branch (633:63): [True: 2.11k, False: 578]
  ------------------
  634|  2.69k|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (634:13): [True: 1, False: 2.69k]
  ------------------
  635|      1|            ParseError("Invalid read size (binary)",&el);
  636|      1|        }
  637|       |
  638|  2.69k|        const uint32_t count3 = count / 3;
  639|  2.69k|        out.reserve(count3);
  640|       |
  641|  2.69k|        if (type == 'd') {
  ------------------
  |  Branch (641:13): [True: 2.11k, False: 578]
  ------------------
  642|  2.11k|            const double* d = reinterpret_cast<const double*>(&buff[0]);
  643|   441k|            for (unsigned int i = 0; i < count3; ++i, d += 3) {
  ------------------
  |  Branch (643:38): [True: 439k, False: 2.11k]
  ------------------
  644|   439k|                BE_NCONST double val1 = d[0];
  645|   439k|                BE_NCONST double val2 = d[1];
  646|   439k|                BE_NCONST double val3 = d[2];
  647|   439k|                AI_SWAP8(val1);
  648|   439k|                AI_SWAP8(val2);
  649|   439k|                AI_SWAP8(val3);
  650|   439k|                out.emplace_back(static_cast<ai_real>(val1),
  651|   439k|                    static_cast<ai_real>(val2),
  652|   439k|                    static_cast<ai_real>(val3));
  653|   439k|            }
  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|  2.11k|        }
  662|    578|        else if (type == 'f') {
  ------------------
  |  Branch (662:18): [True: 0, False: 578]
  ------------------
  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|  2.69k|        return;
  676|  2.69k|    }
  677|       |
  678|     95|    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|     95|    out.reserve(dim);
  684|       |
  685|     95|    const Scope& scope = GetRequiredScope(el);
  686|     95|    const Element& a = GetRequiredElement(scope,"a",&el);
  687|       |
  688|     95|    if (a.Tokens().size() % 3 != 0) {
  ------------------
  |  Branch (688:9): [True: 2, False: 93]
  ------------------
  689|      2|        ParseError("number of floats is not a multiple of three (3)",&el);
  690|      2|    }
  691|  5.30k|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
  ------------------
  |  Branch (691:85): [True: 5.21k, False: 93]
  ------------------
  692|  5.21k|        aiVector3D v;
  693|  5.21k|        v.x = ParseTokenAsFloat(**it++);
  694|  5.21k|        v.y = ParseTokenAsFloat(**it++);
  695|  5.21k|        v.z = ParseTokenAsFloat(**it++);
  696|       |
  697|  5.21k|        out.push_back(v);
  698|  5.21k|    }
  699|     93|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorI10aiVector2tIfENS1_9allocatorIS4_EEEERKNS0_7ElementE:
  801|    852|void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) {
  802|    852|    out.resize( 0 );
  803|    852|    const TokenList& tok = el.Tokens();
  804|    852|    if(tok.empty()) {
  ------------------
  |  Branch (804:8): [True: 0, False: 852]
  ------------------
  805|      0|        ParseError("unexpected empty element",&el);
  806|      0|    }
  807|       |
  808|    852|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (808:8): [True: 830, False: 22]
  ------------------
  809|    830|        const char* data = tok[0]->begin(), *end = tok[0]->end();
  810|       |
  811|    830|        char type;
  812|    830|        uint32_t count;
  813|    830|        ReadBinaryDataArrayHead(data, end, type, count, el);
  814|       |
  815|    830|        if(count % 2 != 0) {
  ------------------
  |  Branch (815:12): [True: 3, False: 827]
  ------------------
  816|      3|            ParseError("number of floats is not a multiple of two (2) (binary)",&el);
  817|      3|        }
  818|       |
  819|    827|        if(!count) {
  ------------------
  |  Branch (819:12): [True: 2, False: 825]
  ------------------
  820|      2|            return;
  821|      2|        }
  822|       |
  823|    825|        if (type != 'd' && type != 'f') {
  ------------------
  |  Branch (823:13): [True: 2, False: 823]
  |  Branch (823:28): [True: 1, False: 1]
  ------------------
  824|      1|            ParseError("expected float or double array (binary)",&el);
  825|      1|        }
  826|       |
  827|    824|        std::vector<char> buff;
  828|    824|        ReadBinaryDataArray(type, count, data, end, buff, el);
  829|       |
  830|    824|        ai_assert(data == end);
  ------------------
  |  |   67|    824|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 824, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  831|    824|        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
  ------------------
  |  Branch (831:63): [True: 779, False: 45]
  ------------------
  832|    824|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (832:13): [True: 0, False: 824]
  ------------------
  833|      0|            ParseError("Invalid read size (binary)",&el);
  834|      0|        }
  835|       |
  836|    824|        const uint32_t count2 = count / 2;
  837|    824|        out.reserve(count2);
  838|       |
  839|    824|        if (type == 'd') {
  ------------------
  |  Branch (839:13): [True: 779, False: 45]
  ------------------
  840|    779|            const double* d = reinterpret_cast<const double*>(&buff[0]);
  841|  8.50M|            for (unsigned int i = 0; i < count2; ++i, d += 2) {
  ------------------
  |  Branch (841:38): [True: 8.50M, False: 779]
  ------------------
  842|  8.50M|                BE_NCONST double val1 = d[0];
  843|  8.50M|                BE_NCONST double val2 = d[1];
  844|  8.50M|                AI_SWAP8(val1);
  845|  8.50M|                AI_SWAP8(val2);
  846|  8.50M|                out.emplace_back(static_cast<float>(val1),
  847|  8.50M|                    static_cast<float>(val2));
  848|  8.50M|            }
  849|    779|        } else if (type == 'f') {
  ------------------
  |  Branch (849:20): [True: 0, False: 45]
  ------------------
  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|    824|        return;
  861|    824|    }
  862|       |
  863|     22|    const size_t dim = ParseTokenAsDim(*tok[0]);
  864|       |
  865|       |    // see notes in ParseVectorDataArray() above
  866|     22|    out.reserve(dim);
  867|       |
  868|     22|    const Scope& scope = GetRequiredScope(el);
  869|     22|    const Element& a = GetRequiredElement(scope,"a",&el);
  870|       |
  871|     22|    if (a.Tokens().size() % 2 != 0) {
  ------------------
  |  Branch (871:9): [True: 0, False: 22]
  ------------------
  872|      0|        ParseError("number of floats is not a multiple of two (2)",&el);
  873|      0|    }
  874|  8.25k|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
  ------------------
  |  Branch (874:85): [True: 8.22k, False: 22]
  ------------------
  875|  8.22k|        aiVector2D v;
  876|  8.22k|        v.x = ParseTokenAsFloat(**it++);
  877|  8.22k|        v.y = ParseTokenAsFloat(**it++);
  878|       |
  879|  8.22k|        out.push_back(v);
  880|  8.22k|    }
  881|     22|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorIiNS1_9allocatorIiEEEERKNS0_7ElementE:
  886|  2.93k|void ParseVectorDataArray(std::vector<int>& out, const Element& el) {
  887|  2.93k|    out.resize( 0 );
  888|  2.93k|    const TokenList& tok = el.Tokens();
  889|  2.93k|    if(tok.empty()) {
  ------------------
  |  Branch (889:8): [True: 0, False: 2.93k]
  ------------------
  890|      0|        ParseError("unexpected empty element",&el);
  891|      0|    }
  892|       |
  893|  2.93k|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (893:8): [True: 2.85k, False: 79]
  ------------------
  894|  2.85k|        const char* data = tok[0]->begin(), *end = tok[0]->end();
  895|       |
  896|  2.85k|        char type;
  897|  2.85k|        uint32_t count;
  898|  2.85k|        ReadBinaryDataArrayHead(data, end, type, count, el);
  899|       |
  900|  2.85k|        if(!count) {
  ------------------
  |  Branch (900:12): [True: 0, False: 2.85k]
  ------------------
  901|      0|            return;
  902|      0|        }
  903|       |
  904|  2.85k|        if (type != 'i') {
  ------------------
  |  Branch (904:13): [True: 1, False: 2.85k]
  ------------------
  905|      1|            ParseError("expected int array (binary)",&el);
  906|      1|        }
  907|       |
  908|  2.85k|        std::vector<char> buff;
  909|  2.85k|        ReadBinaryDataArray(type, count, data, end, buff, el);
  910|       |
  911|  2.85k|        ai_assert(data == end);
  ------------------
  |  |   67|  2.85k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 2.85k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  912|  2.85k|        uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
  913|  2.85k|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (913:13): [True: 1, False: 2.85k]
  ------------------
  914|      1|            ParseError("Invalid read size (binary)",&el);
  915|      1|        }
  916|       |
  917|  2.85k|        out.reserve(count);
  918|       |
  919|  2.85k|        const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
  920|   115M|        for (unsigned int i = 0; i < count; ++i, ++ip) {
  ------------------
  |  Branch (920:34): [True: 115M, False: 2.85k]
  ------------------
  921|   115M|            BE_NCONST int32_t val = *ip;
  922|   115M|            AI_SWAP4(val);
  923|   115M|            out.push_back(val);
  924|   115M|        }
  925|       |
  926|  2.85k|        return;
  927|  2.85k|    }
  928|       |
  929|     79|    const size_t dim = ParseTokenAsDim(*tok[0]);
  930|       |
  931|       |    // see notes in ParseVectorDataArray()
  932|     79|    out.reserve(dim);
  933|       |
  934|     79|    const Scope& scope = GetRequiredScope(el);
  935|     79|    const Element& a = GetRequiredElement(scope,"a",&el);
  936|       |
  937|   415k|    for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
  ------------------
  |  Branch (937:85): [True: 415k, False: 79]
  ------------------
  938|   415k|        const int ival = ParseTokenAsInt(**it++);
  939|   415k|        out.push_back(ival);
  940|   415k|    }
  941|     79|}
_ZN6Assimp3FBX20ParseVectorDataArrayERNSt3__16vectorIfNS1_9allocatorIfEEEERKNS0_7ElementE:
  947|  60.4k|{
  948|  60.4k|    out.resize( 0 );
  949|  60.4k|    const TokenList& tok = el.Tokens();
  950|  60.4k|    if(tok.empty()) {
  ------------------
  |  Branch (950:8): [True: 0, False: 60.4k]
  ------------------
  951|      0|        ParseError("unexpected empty element",&el);
  952|      0|    }
  953|       |
  954|  60.4k|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (954:8): [True: 60.4k, False: 0]
  ------------------
  955|  60.4k|        const char* data = tok[0]->begin(), *end = tok[0]->end();
  956|       |
  957|  60.4k|        char type;
  958|  60.4k|        uint32_t count;
  959|  60.4k|        ReadBinaryDataArrayHead(data, end, type, count, el);
  960|       |
  961|  60.4k|        if(!count) {
  ------------------
  |  Branch (961:12): [True: 0, False: 60.4k]
  ------------------
  962|      0|            return;
  963|      0|        }
  964|       |
  965|  60.4k|        if (type != 'd' && type != 'f') {
  ------------------
  |  Branch (965:13): [True: 52.7k, False: 7.69k]
  |  Branch (965:28): [True: 1, False: 52.7k]
  ------------------
  966|      1|            ParseError("expected float or double array (binary)",&el);
  967|      1|        }
  968|       |
  969|  60.4k|        std::vector<char> buff;
  970|  60.4k|        ReadBinaryDataArray(type, count, data, end, buff, el);
  971|       |
  972|  60.4k|        ai_assert(data == end);
  ------------------
  |  |   67|  60.4k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 60.4k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  973|  60.4k|        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
  ------------------
  |  Branch (973:63): [True: 6.87k, False: 53.5k]
  ------------------
  974|  60.4k|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (974:13): [True: 9, False: 60.4k]
  ------------------
  975|      9|            ParseError("Invalid read size (binary)",&el);
  976|      9|        }
  977|       |
  978|  60.4k|        if (type == 'd') {
  ------------------
  |  Branch (978:13): [True: 6.87k, False: 53.5k]
  ------------------
  979|  6.87k|            const double* d = reinterpret_cast<const double*>(&buff[0]);
  980|  35.7M|            for (unsigned int i = 0; i < count; ++i, ++d) {
  ------------------
  |  Branch (980:38): [True: 35.7M, False: 6.87k]
  ------------------
  981|  35.7M|                BE_NCONST double val = *d;
  982|  35.7M|                AI_SWAP8(val);
  983|  35.7M|                out.push_back(static_cast<float>(val));
  984|  35.7M|            }
  985|  6.87k|        }
  986|  53.5k|        else if (type == 'f') {
  ------------------
  |  Branch (986:18): [True: 52.7k, False: 816]
  ------------------
  987|  52.7k|            const float* f = reinterpret_cast<const float*>(&buff[0]);
  988|   212k|            for (unsigned int i = 0; i < count; ++i, ++f) {
  ------------------
  |  Branch (988:38): [True: 159k, False: 52.7k]
  ------------------
  989|   159k|                BE_NCONST float val = *f;
  990|   159k|                AI_SWAP4(val);
  991|   159k|                out.push_back(val);
  992|   159k|            }
  993|  52.7k|        }
  994|       |
  995|  60.4k|        return;
  996|  60.4k|    }
  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|  28.9k|void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) {
 1015|  28.9k|    out.resize( 0 );
 1016|  28.9k|    const TokenList& tok = el.Tokens();
 1017|  28.9k|    if(tok.empty()) {
  ------------------
  |  Branch (1017:8): [True: 0, False: 28.9k]
  ------------------
 1018|      0|        ParseError("unexpected empty element",&el);
 1019|      0|    }
 1020|       |
 1021|  28.9k|    if(tok[0]->IsBinary()) {
  ------------------
  |  Branch (1021:8): [True: 28.9k, False: 0]
  ------------------
 1022|  28.9k|        const char* data = tok[0]->begin(), *end = tok[0]->end();
 1023|       |
 1024|  28.9k|        char type;
 1025|  28.9k|        uint32_t count;
 1026|  28.9k|        ReadBinaryDataArrayHead(data, end, type, count, el);
 1027|       |
 1028|  28.9k|        if(!count) {
  ------------------
  |  Branch (1028:12): [True: 1, False: 28.9k]
  ------------------
 1029|      1|            return;
 1030|      1|        }
 1031|       |
 1032|  28.9k|        if (type != 'i') {
  ------------------
  |  Branch (1032:13): [True: 1, False: 28.9k]
  ------------------
 1033|      1|            ParseError("expected (u)int array (binary)",&el);
 1034|      1|        }
 1035|       |
 1036|  28.9k|        std::vector<char> buff;
 1037|  28.9k|        ReadBinaryDataArray(type, count, data, end, buff, el);
 1038|       |
 1039|  28.9k|        ai_assert(data == end);
  ------------------
  |  |   67|  28.9k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 28.9k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1040|  28.9k|        uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
 1041|  28.9k|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (1041:13): [True: 1, False: 28.9k]
  ------------------
 1042|      1|            ParseError("Invalid read size (binary)",&el);
 1043|      1|        }
 1044|       |
 1045|  28.9k|        out.reserve(count);
 1046|       |
 1047|  28.9k|        const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
 1048|  1.09M|        for (unsigned int i = 0; i < count; ++i, ++ip) {
  ------------------
  |  Branch (1048:34): [True: 1.06M, False: 28.9k]
  ------------------
 1049|  1.06M|            BE_NCONST int32_t val = *ip;
 1050|  1.06M|            if(val < 0) {
  ------------------
  |  Branch (1050:16): [True: 3, False: 1.06M]
  ------------------
 1051|      3|                ParseError("encountered negative integer index (binary)");
 1052|      3|            }
 1053|       |
 1054|  1.06M|            AI_SWAP4(val);
 1055|  1.06M|            out.push_back(val);
 1056|  1.06M|        }
 1057|       |
 1058|  28.9k|        return;
 1059|  28.9k|    }
 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|  26.4k|{
 1144|  26.4k|    out.resize( 0 );
 1145|  26.4k|    const TokenList& tok = el.Tokens();
 1146|  26.4k|    if (tok.empty()) {
  ------------------
  |  Branch (1146:9): [True: 0, False: 26.4k]
  ------------------
 1147|      0|        ParseError("unexpected empty element", &el);
 1148|      0|    }
 1149|       |
 1150|  26.4k|    if (tok[0]->IsBinary()) {
  ------------------
  |  Branch (1150:9): [True: 26.4k, False: 0]
  ------------------
 1151|  26.4k|        const char* data = tok[0]->begin(), *end = tok[0]->end();
 1152|       |
 1153|  26.4k|        char type;
 1154|  26.4k|        uint32_t count;
 1155|  26.4k|        ReadBinaryDataArrayHead(data, end, type, count, el);
 1156|       |
 1157|  26.4k|        if (!count) {
  ------------------
  |  Branch (1157:13): [True: 0, False: 26.4k]
  ------------------
 1158|      0|            return;
 1159|      0|        }
 1160|       |
 1161|  26.4k|        if (type != 'l') {
  ------------------
  |  Branch (1161:13): [True: 15, False: 26.4k]
  ------------------
 1162|     15|            ParseError("expected long array (binary)", &el);
 1163|     15|        }
 1164|       |
 1165|  26.4k|        std::vector<char> buff;
 1166|  26.4k|        ReadBinaryDataArray(type, count, data, end, buff, el);
 1167|       |
 1168|  26.4k|        ai_assert(data == end);
  ------------------
  |  |   67|  26.4k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 26.4k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1169|  26.4k|        uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
 1170|  26.4k|        if (dataToRead != buff.size()) {
  ------------------
  |  Branch (1170:13): [True: 0, False: 26.4k]
  ------------------
 1171|      0|            ParseError("Invalid read size (binary)",&el);
 1172|      0|        }
 1173|       |
 1174|  26.4k|        out.reserve(count);
 1175|       |
 1176|  26.4k|        const int64_t* ip = reinterpret_cast<const int64_t*>(&buff[0]);
 1177|  81.4k|        for (unsigned int i = 0; i < count; ++i, ++ip) {
  ------------------
  |  Branch (1177:34): [True: 55.0k, False: 26.4k]
  ------------------
 1178|  55.0k|            BE_NCONST int64_t val = *ip;
 1179|  55.0k|            AI_SWAP8(val);
 1180|  55.0k|            out.push_back(val);
 1181|  55.0k|        }
 1182|       |
 1183|  26.4k|        return;
 1184|  26.4k|    }
 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.51k|{
 1204|  5.51k|    std::vector<float> values;
 1205|  5.51k|    ParseVectorDataArray(values,element);
 1206|       |
 1207|  5.51k|    if(values.size() != 16) {
  ------------------
  |  Branch (1207:8): [True: 0, False: 5.51k]
  ------------------
 1208|      0|        ParseError("expected 16 matrix elements");
 1209|      0|    }
 1210|       |
 1211|  5.51k|    aiMatrix4x4 result;
 1212|       |
 1213|       |
 1214|  5.51k|    result.a1 = values[0];
 1215|  5.51k|    result.a2 = values[1];
 1216|  5.51k|    result.a3 = values[2];
 1217|  5.51k|    result.a4 = values[3];
 1218|       |
 1219|  5.51k|    result.b1 = values[4];
 1220|  5.51k|    result.b2 = values[5];
 1221|  5.51k|    result.b3 = values[6];
 1222|  5.51k|    result.b4 = values[7];
 1223|       |
 1224|  5.51k|    result.c1 = values[8];
 1225|  5.51k|    result.c2 = values[9];
 1226|  5.51k|    result.c3 = values[10];
 1227|  5.51k|    result.c4 = values[11];
 1228|       |
 1229|  5.51k|    result.d1 = values[12];
 1230|  5.51k|    result.d2 = values[13];
 1231|  5.51k|    result.d3 = values[14];
 1232|  5.51k|    result.d4 = values[15];
 1233|       |
 1234|  5.51k|    result.Transpose();
 1235|  5.51k|    return result;
 1236|  5.51k|}
_ZN6Assimp3FBX18ParseTokenAsStringERKNS0_5TokenE:
 1241|   374k|{
 1242|   374k|    const char* err;
 1243|   374k|    const std::string& i = ParseTokenAsString(t,err);
 1244|   374k|    if(err) {
  ------------------
  |  Branch (1244:8): [True: 12, False: 374k]
  ------------------
 1245|     12|        ParseError(err,t);
 1246|     12|    }
 1247|   374k|    return i;
 1248|   374k|}
_ZN6Assimp3FBX10HasElementERKNS0_5ScopeERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE:
 1250|  3.96k|bool HasElement( const Scope& sc, const std::string& index ) {
 1251|  3.96k|    const Element* el = sc[ index ];
 1252|  3.96k|    if ( nullptr == el ) {
  ------------------
  |  Branch (1252:10): [True: 1.12k, False: 2.84k]
  ------------------
 1253|  1.12k|        return false;
 1254|  1.12k|    }
 1255|       |
 1256|  2.84k|    return true;
 1257|  3.96k|}
_ZN6Assimp3FBX18GetRequiredElementERKNS0_5ScopeERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPKNS0_7ElementE:
 1262|  80.3k|{
 1263|  80.3k|    const Element* el = sc[index];
 1264|  80.3k|    if(!el) {
  ------------------
  |  Branch (1264:8): [True: 243, False: 80.1k]
  ------------------
 1265|    243|        ParseError("did not find required element \"" + index + "\"",element);
 1266|    243|    }
 1267|  80.1k|    return *el;
 1268|  80.3k|}
_ZN6Assimp3FBX16GetRequiredScopeERKNS0_7ElementE:
 1274|  88.8k|{
 1275|  88.8k|    const Scope* const s = el.Compound();
 1276|  88.8k|    if(!s) {
  ------------------
  |  Branch (1276:8): [True: 0, False: 88.8k]
  ------------------
 1277|      0|        ParseError("expected compound scope",&el);
 1278|      0|    }
 1279|       |
 1280|  88.8k|    return *s;
 1281|  88.8k|}
_ZN6Assimp3FBX16GetRequiredTokenERKNS0_7ElementEj:
 1287|   368k|{
 1288|   368k|    const TokenList& t = el.Tokens();
 1289|   368k|    if(index >= t.size()) {
  ------------------
  |  Branch (1289:8): [True: 0, False: 368k]
  ------------------
 1290|      0|        ParseError(Formatter::format( "missing token at index " ) << index,&el);
 1291|      0|    }
 1292|       |
 1293|   368k|    return *t[index];
 1294|   368k|}
_ZN6Assimp3FBX14ParseTokenAsIDERKNS0_5TokenE:
 1300|   187k|{
 1301|   187k|    const char* err;
 1302|   187k|    const uint64_t i = ParseTokenAsID(t,err);
 1303|   187k|    if(err) {
  ------------------
  |  Branch (1303:8): [True: 0, False: 187k]
  ------------------
 1304|      0|        ParseError(err,t);
 1305|      0|    }
 1306|   187k|    return i;
 1307|   187k|}
_ZN6Assimp3FBX15ParseTokenAsDimERKNS0_5TokenE:
 1313|    196|{
 1314|    196|    const char* err;
 1315|    196|    const size_t i = ParseTokenAsDim(t,err);
 1316|    196|    if(err) {
  ------------------
  |  Branch (1316:8): [True: 0, False: 196]
  ------------------
 1317|      0|        ParseError(err,t);
 1318|      0|    }
 1319|    196|    return i;
 1320|    196|}
_ZN6Assimp3FBX17ParseTokenAsFloatERKNS0_5TokenE:
 1326|   102k|{
 1327|   102k|    const char* err;
 1328|   102k|    const float i = ParseTokenAsFloat(t,err);
 1329|   102k|    if(err) {
  ------------------
  |  Branch (1329:8): [True: 7, False: 102k]
  ------------------
 1330|      7|        ParseError(err,t);
 1331|      7|    }
 1332|   102k|    return i;
 1333|   102k|}
_ZN6Assimp3FBX15ParseTokenAsIntERKNS0_5TokenE:
 1338|   441k|{
 1339|   441k|    const char* err;
 1340|   441k|    const int i = ParseTokenAsInt(t,err);
 1341|   441k|    if(err) {
  ------------------
  |  Branch (1341:8): [True: 3, False: 441k]
  ------------------
 1342|      3|        ParseError(err,t);
 1343|      3|    }
 1344|   441k|    return i;
 1345|   441k|}
_ZN6Assimp3FBX17ParseTokenAsInt64ERKNS0_5TokenE:
 1350|  1.05k|{
 1351|  1.05k|    const char* err;
 1352|  1.05k|    const int64_t i = ParseTokenAsInt64(t, err);
 1353|  1.05k|    if (err) {
  ------------------
  |  Branch (1353:9): [True: 0, False: 1.05k]
  ------------------
 1354|      0|        ParseError(err, t);
 1355|      0|    }
 1356|  1.05k|    return i;
 1357|  1.05k|}
FBXParser.cpp:_ZN12_GLOBAL__N_110ParseErrorERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEPKN6Assimp3FBX5TokenE:
   88|     11|    {
   89|     11|        if(token) {
  ------------------
  |  Branch (89:12): [True: 11, False: 0]
  ------------------
   90|     11|            ParseError(message, *token);
   91|     11|        }
   92|      0|        ParseError(message);
   93|     11|    }
FBXParser.cpp:_ZN12_GLOBAL__N_110ParseErrorERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEPKN6Assimp3FBX7ElementE:
   77|    285|    {
   78|    285|        if(element) {
  ------------------
  |  Branch (78:12): [True: 103, False: 182]
  ------------------
   79|    103|            ParseError(message,element->KeyToken());
   80|    103|        }
   81|    182|        throw DeadlyImportError("FBX-Parser ", message);
   82|    285|    }
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|  52.7k|        case 'f':
  ------------------
  |  Branch (553:9): [True: 52.7k, False: 69.5k]
  ------------------
  554|  84.5k|        case 'i':
  ------------------
  |  Branch (554:9): [True: 31.8k, False: 90.4k]
  ------------------
  555|  84.5k|            stride = 4;
  556|  84.5k|            break;
  557|       |
  558|  11.2k|        case 'd':
  ------------------
  |  Branch (558:9): [True: 11.2k, False: 111k]
  ------------------
  559|  37.6k|        case 'l':
  ------------------
  |  Branch (559:9): [True: 26.4k, False: 95.7k]
  ------------------
  560|  37.6k|            stride = 8;
  561|  37.6k|            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: 111k, False: 10.5k]
  ------------------
  571|   111k|        ai_assert(full_length == comp_len);
  ------------------
  |  |   67|   111k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 111k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  572|       |
  573|       |        // plain data, no compression
  574|   111k|        std::copy(data, end, buff.begin());
  575|   111k|    }
  576|  10.5k|    else if(encmode == 1) {
  ------------------
  |  Branch (576:13): [True: 10.5k, False: 0]
  ------------------
  577|       |        // zlib/deflate, next comes ZIP head (0x78 0x01)
  578|       |        // see http://www.ietf.org/rfc/rfc1950.txt
  579|  10.5k|         Compression compress;
  580|  10.5k|        if (compress.open(Compression::Format::Binary, Compression::FlushMode::Finish, 0)) {
  ------------------
  |  Branch (580:13): [True: 10.5k, False: 0]
  ------------------
  581|  10.5k|            compress.decompress(data, comp_len, buff);
  582|  10.5k|            compress.close();
  583|  10.5k|        }
  584|  10.5k|    }
  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|    136|    {
   71|    136|        throw DeadlyImportError("FBX-Parser", Util::GetTokenText(&token), message);
   72|    136|    }
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseImEET_PKcS3_:
   99|   208k|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|   208k|        (void)(end);
  103|   208k|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|   208k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 208k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|   208k|        T result = static_cast<T>(0);
  105|   208k|        ::memcpy(&result, data, sizeof(T));
  106|   208k|        return result;
  107|   208k|    }
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseIdEET_PKcS3_:
   99|  68.2k|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|  68.2k|        (void)(end);
  103|  68.2k|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|  68.2k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 68.2k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|  68.2k|        T result = static_cast<T>(0);
  105|  68.2k|        ::memcpy(&result, data, sizeof(T));
  106|  68.2k|        return result;
  107|  68.2k|    }
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseIiEET_PKcS3_:
   99|   466k|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|   466k|        (void)(end);
  103|   466k|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|   466k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 466k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|   466k|        T result = static_cast<T>(0);
  105|   466k|        ::memcpy(&result, data, sizeof(T));
  106|   466k|        return result;
  107|   466k|    }
FBXParser.cpp:_ZN12_GLOBAL__N_19SafeParseIlEET_PKcS3_:
   99|  1.00k|    T SafeParse(const char* data, const char* end) {
  100|       |        // Actual size validation happens during Tokenization so
  101|       |        // this is valid as an assertion.
  102|  1.00k|        (void)(end);
  103|  1.00k|        ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
  ------------------
  |  |   67|  1.00k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 1.00k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  104|  1.00k|        T result = static_cast<T>(0);
  105|  1.00k|        ::memcpy(&result, data, sizeof(T));
  106|  1.00k|        return result;
  107|  1.00k|    }

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

_ZN6Assimp3FBX13PropertyTableC2ERKNS0_7ElementENSt3__110shared_ptrIKS1_EE:
  160|  24.0k|        templateProps(std::move(templateProps)), element(&element) {
  161|  24.0k|    const Scope& scope = GetRequiredScope(element);
  162|   156k|    for(const ElementMap::value_type& v : scope.Elements()) {
  ------------------
  |  Branch (162:41): [True: 156k, False: 24.0k]
  ------------------
  163|   156k|        if(v.first != "P") {
  ------------------
  |  Branch (163:12): [True: 737, False: 155k]
  ------------------
  164|    737|            DOMWarning("expected only P elements in property table",v.second);
  165|    737|            continue;
  166|    737|        }
  167|       |
  168|   155k|        const std::string& name = PeekPropertyName(*v.second);
  169|   155k|        if(!name.length()) {
  ------------------
  |  Branch (169:12): [True: 246, False: 155k]
  ------------------
  170|    246|            DOMWarning("could not read property name",v.second);
  171|    246|            continue;
  172|    246|        }
  173|       |
  174|   155k|        LazyPropertyMap::const_iterator it = lazyProps.find(name);
  175|   155k|        if (it != lazyProps.end()) {
  ------------------
  |  Branch (175:13): [True: 106, False: 155k]
  ------------------
  176|    106|            DOMWarning("duplicate property name, will hide previous value: " + name,v.second);
  177|    106|            continue;
  178|    106|        }
  179|       |
  180|   155k|        lazyProps[name] = v.second;
  181|   155k|    }
  182|  24.0k|}
_ZN6Assimp3FBX13PropertyTableD2Ev:
  186|  27.2k|{
  187|  30.3k|    for(PropertyMap::value_type& v : props) {
  ------------------
  |  Branch (187:36): [True: 30.3k, False: 27.2k]
  ------------------
  188|  30.3k|        delete v.second;
  189|  30.3k|    }
  190|  27.2k|}
_ZNK6Assimp3FBX13PropertyTable3GetERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  195|   250k|{
  196|   250k|    PropertyMap::const_iterator it = props.find(name);
  197|   250k|    if (it == props.end()) {
  ------------------
  |  Branch (197:9): [True: 163k, False: 87.3k]
  ------------------
  198|       |        // hasn't been parsed yet?
  199|   163k|        LazyPropertyMap::const_iterator lit = lazyProps.find(name);
  200|   163k|        if(lit != lazyProps.end()) {
  ------------------
  |  Branch (200:12): [True: 30.3k, False: 133k]
  ------------------
  201|  30.3k|            props[name] = ReadTypedProperty(*(*lit).second);
  202|  30.3k|            it = props.find(name);
  203|       |
  204|  30.3k|            ai_assert(it != props.end());
  ------------------
  |  |   67|  30.3k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 30.3k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  205|  30.3k|        }
  206|       |
  207|   163k|        if (it == props.end()) {
  ------------------
  |  Branch (207:13): [True: 133k, False: 30.3k]
  ------------------
  208|       |            // check property template
  209|   133k|            if(templateProps) {
  ------------------
  |  Branch (209:16): [True: 105k, False: 27.9k]
  ------------------
  210|   105k|                return templateProps->Get(name);
  211|   105k|            }
  212|       |
  213|  27.9k|            return nullptr;
  214|   133k|        }
  215|   163k|    }
  216|       |
  217|   117k|    return (*it).second;
  218|   250k|}
_ZNK6Assimp3FBX13PropertyTable21GetUnparsedPropertiesEv:
  221|  5.22k|{
  222|  5.22k|    DirectPropertyMap result;
  223|       |
  224|       |    // Loop through all the lazy properties (which is all the properties)
  225|  32.3k|    for(const LazyPropertyMap::value_type& currentElement : lazyProps) {
  ------------------
  |  Branch (225:59): [True: 32.3k, False: 5.22k]
  ------------------
  226|       |
  227|       |        // Skip parsed properties
  228|  32.3k|        if (props.end() != props.find(currentElement.first)) {
  ------------------
  |  Branch (228:13): [True: 16.5k, False: 15.7k]
  ------------------
  229|  16.5k|            continue;
  230|  16.5k|        }
  231|       |
  232|       |        // Read the element's value.
  233|       |        // Wrap the naked pointer (since the call site is required to acquire ownership)
  234|  15.7k|        std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*currentElement.second));
  235|       |
  236|       |        // Element could not be read. Skip it.
  237|  15.7k|        if (!prop) {
  ------------------
  |  Branch (237:13): [True: 327, False: 15.4k]
  ------------------
  238|    327|            continue;
  239|    327|        }
  240|       |
  241|       |        // Add to result
  242|  15.4k|        result[currentElement.first] = prop;
  243|  15.4k|    }
  244|       |
  245|  5.22k|    return result;
  246|  5.22k|}
FBXProperties.cpp:_ZN6Assimp3FBX12_GLOBAL__N_116PeekPropertyNameERKNS0_7ElementE:
  144|   155k|std::string PeekPropertyName(const Element& element) {
  145|   155k|    ai_assert(element.KeyToken().StringContents() == "P");
  ------------------
  |  |   67|   155k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 155k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  146|       |
  147|   155k|    const TokenList& tok = element.Tokens();
  148|   155k|    if(tok.size() < 4) {
  ------------------
  |  Branch (148:8): [True: 246, False: 155k]
  ------------------
  149|    246|        return std::string();
  150|    246|    }
  151|       |
  152|   155k|    return ParseTokenAsString(*tok[0]);
  153|   155k|}
FBXProperties.cpp:_ZN6Assimp3FBX12_GLOBAL__N_117ReadTypedPropertyERKNS0_7ElementE:
   80|  46.1k|{
   81|  46.1k|    ai_assert(element.KeyToken().StringContents() == "P");
  ------------------
  |  |   67|  46.1k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 46.1k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   82|       |
   83|  46.1k|    const TokenList& tok = element.Tokens();
   84|  46.1k|    if (tok.size() < 2) {
  ------------------
  |  Branch (84:9): [True: 0, False: 46.1k]
  ------------------
   85|      0|        return nullptr;
   86|      0|    }
   87|       |
   88|  46.1k|    const std::string& s = ParseTokenAsString(*tok[1]);
   89|  46.1k|    const char* const cs = s.c_str();
   90|  46.1k|    if (!strcmp(cs,"KString")) {
  ------------------
  |  Branch (90:9): [True: 297, False: 45.8k]
  ------------------
   91|    297|        checkTokenCount(tok, 5);
   92|    297|        return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
   93|    297|    }
   94|  45.8k|    else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
  ------------------
  |  Branch (94:14): [True: 2.28k, False: 43.5k]
  |  Branch (94:36): [True: 9, False: 43.5k]
  ------------------
   95|  2.29k|        checkTokenCount(tok, 5);
   96|  2.29k|        return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
   97|  2.29k|    }
   98|  43.5k|    else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum") || !strcmp(cs, "Integer")) {
  ------------------
  |  Branch (98:14): [True: 7.34k, False: 36.2k]
  |  Branch (98:36): [True: 0, False: 36.2k]
  |  Branch (98:58): [True: 6.69k, False: 29.5k]
  |  Branch (98:81): [True: 0, False: 29.5k]
  |  Branch (98:104): [True: 2, False: 29.5k]
  ------------------
   99|  14.0k|        checkTokenCount(tok, 5);
  100|  14.0k|        return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
  101|  14.0k|    }
  102|  29.5k|    else if (!strcmp(cs, "ULongLong")) {
  ------------------
  |  Branch (102:14): [True: 9, False: 29.5k]
  ------------------
  103|      9|        checkTokenCount(tok, 5);
  104|      9|        return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
  105|      9|    }
  106|  29.5k|    else if (!strcmp(cs, "KTime")) {
  ------------------
  |  Branch (106:14): [True: 1.05k, False: 28.4k]
  ------------------
  107|  1.05k|        checkTokenCount(tok, 5);
  108|  1.05k|        return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
  109|  1.05k|    }
  110|  28.4k|    else if (!strcmp(cs,"Vector3D") ||
  ------------------
  |  Branch (110:14): [True: 3.48k, False: 24.9k]
  ------------------
  111|  24.9k|        !strcmp(cs,"ColorRGB") ||
  ------------------
  |  Branch (111:9): [True: 359, False: 24.6k]
  ------------------
  112|  24.6k|        !strcmp(cs,"Vector") ||
  ------------------
  |  Branch (112:9): [True: 39, False: 24.6k]
  ------------------
  113|  24.6k|        !strcmp(cs,"Color") ||
  ------------------
  |  Branch (113:9): [True: 2.05k, False: 22.5k]
  ------------------
  114|  22.5k|        !strcmp(cs,"Lcl Translation") ||
  ------------------
  |  Branch (114:9): [True: 4.14k, False: 18.4k]
  ------------------
  115|  18.4k|        !strcmp(cs,"Lcl Rotation") ||
  ------------------
  |  Branch (115:9): [True: 5.34k, False: 13.0k]
  ------------------
  116|  13.0k|        !strcmp(cs,"Lcl Scaling")
  ------------------
  |  Branch (116:9): [True: 5.38k, False: 7.67k]
  ------------------
  117|  28.4k|        ) {
  118|  20.8k|        checkTokenCount(tok, 7);
  119|  20.8k|        return new TypedProperty<aiVector3D>(aiVector3D(
  120|  20.8k|            ParseTokenAsFloat(*tok[4]),
  121|  20.8k|            ParseTokenAsFloat(*tok[5]),
  122|  20.8k|            ParseTokenAsFloat(*tok[6]))
  123|  20.8k|        );
  124|  20.8k|    }
  125|  7.68k|    else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"float") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) {
  ------------------
  |  Branch (125:14): [True: 4.47k, False: 3.21k]
  |  Branch (125:38): [True: 2.48k, False: 729]
  |  Branch (125:62): [True: 2, False: 727]
  |  Branch (125:85): [True: 6, False: 721]
  |  Branch (125:108): [True: 290, False: 431]
  |  Branch (125:137): [True: 0, False: 431]
  ------------------
  126|  7.24k|        checkTokenCount(tok, 5);
  127|  7.24k|        return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
  128|  7.24k|    }
  129|    437|    else if (!strcmp(cs, "ColorAndAlpha")) {
  ------------------
  |  Branch (129:14): [True: 4, False: 433]
  ------------------
  130|      4|        checkTokenCount(tok, 8);
  131|      4|        return new TypedProperty<aiColor4D>(aiColor4D(
  132|      4|            ParseTokenAsFloat(*tok[4]),
  133|      4|            ParseTokenAsFloat(*tok[5]),
  134|      4|            ParseTokenAsFloat(*tok[6]),
  135|      4|            ParseTokenAsFloat(*tok[7]))
  136|      4|        );
  137|      4|    }
  138|    433|    return nullptr;
  139|  46.1k|}
FBXProperties.cpp:_ZN6Assimp3FBX12_GLOBAL__N_115checkTokenCountERKNSt3__16vectorIPKNS0_5TokenENS2_9allocatorIS6_EEEEj:
   65|  45.7k|    void checkTokenCount(const TokenList &tok, unsigned int expectedCount) {
   66|  45.7k|        ai_assert(expectedCount >= 2);
  ------------------
  |  |   67|  45.7k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 45.7k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   67|  45.7k|        if (tok.size() < expectedCount) {
  ------------------
  |  Branch (67:13): [True: 3, False: 45.7k]
  ------------------
   68|      3|            const std::string &s = ParseTokenAsString(*tok[1]);
   69|      3|            if (tok[1]->IsBinary()) {
  ------------------
  |  Branch (69:17): [True: 1, False: 2]
  ------------------
   70|      1|                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|      3|        }
   75|  45.7k|}

_ZN6Assimp3FBX13PropertyTableC2Ev:
  104|  3.19k|    PropertyTable() : element() {}
_ZNK6Assimp3FBX13PropertyTable13TemplatePropsEv:
  115|    433|    const PropertyTable* TemplateProps() const {
  116|    433|        return templateProps.get();
  117|    433|    }
_ZN6Assimp3FBX11PropertyGetI10aiVector3tIfEEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEERKS4_:
  130|  8.51k|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|  8.51k|    const Property* const prop = in.Get(name);
  132|  8.51k|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 74, False: 8.44k]
  ------------------
  133|     74|        return defaultValue;
  134|     74|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|  8.44k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|  8.44k|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 2, False: 8.44k]
  ------------------
  139|      2|        return defaultValue;
  140|      2|    }
  141|       |
  142|  8.44k|    return tprop->Value();
  143|  8.44k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyI10aiVector3tIfEEEEEPKT_v:
   73|  98.5k|    const T* As() const {
   74|  98.5k|        return dynamic_cast<const T*>(this);
   75|  98.5k|    }
_ZNK6Assimp3FBX13TypedPropertyI10aiVector3tIfEE5ValueEv:
   86|  98.1k|    const T& Value() const {
   87|  98.1k|        return value;
   88|  98.1k|    }
_ZN6Assimp3FBX11PropertyGetIfEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERKS2_:
  130|  3.70k|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|  3.70k|    const Property* const prop = in.Get(name);
  132|  3.70k|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 191, False: 3.51k]
  ------------------
  133|    191|        return defaultValue;
  134|    191|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|  3.51k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|  3.51k|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 0, False: 3.51k]
  ------------------
  139|      0|        return defaultValue;
  140|      0|    }
  141|       |
  142|  3.51k|    return tprop->Value();
  143|  3.51k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIfEEEEPKT_v:
   73|  9.38k|    const T* As() const {
   74|  9.38k|        return dynamic_cast<const T*>(this);
   75|  9.38k|    }
_ZNK6Assimp3FBX13TypedPropertyIfE5ValueEv:
   86|  8.86k|    const T& Value() const {
   87|  8.86k|        return value;
   88|  8.86k|    }
_ZN6Assimp3FBX11PropertyGetIiEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERKS2_:
  130|  11.8k|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|  11.8k|    const Property* const prop = in.Get(name);
  132|  11.8k|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 733, False: 11.1k]
  ------------------
  133|    733|        return defaultValue;
  134|    733|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|  11.1k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|  11.1k|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 35, False: 11.1k]
  ------------------
  139|     35|        return defaultValue;
  140|     35|    }
  141|       |
  142|  11.1k|    return tprop->Value();
  143|  11.1k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIiEEEEPKT_v:
   73|  23.8k|    const T* As() const {
   74|  23.8k|        return dynamic_cast<const T*>(this);
   75|  23.8k|    }
_ZNK6Assimp3FBX13TypedPropertyIiE5ValueEv:
   86|  21.5k|    const T& Value() const {
   87|  21.5k|        return value;
   88|  21.5k|    }
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIbEEEEPKT_v:
   73|  14.9k|    const T* As() const {
   74|  14.9k|        return dynamic_cast<const T*>(this);
   75|  14.9k|    }
_ZNK6Assimp3FBX13TypedPropertyIbE5ValueEv:
   86|  2.27k|    const T& Value() const {
   87|  2.27k|        return value;
   88|  2.27k|    }
_ZN6Assimp3FBX11PropertyGetINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEET_RKNS0_13PropertyTableERKS8_RKS9_:
  130|  4.90k|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|  4.90k|    const Property* const prop = in.Get(name);
  132|  4.90k|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 4.90k, False: 0]
  ------------------
  133|  4.90k|        return defaultValue;
  134|  4.90k|    }
  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|    957|    const T* As() const {
   74|    957|        return dynamic_cast<const T*>(this);
   75|    957|    }
_ZNK6Assimp3FBX13TypedPropertyINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEE5ValueEv:
   86|    536|    const T& Value() const {
   87|    536|        return value;
   88|    536|    }
_ZN6Assimp3FBX11PropertyGetIlEET_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: 8, False: 446]
  ------------------
  133|      8|        return defaultValue;
  134|      8|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|    446|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|    446|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 0, False: 446]
  ------------------
  139|      0|        return defaultValue;
  140|      0|    }
  141|       |
  142|    446|    return tprop->Value();
  143|    446|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIlEEEEPKT_v:
   73|  2.65k|    const T* As() const {
   74|  2.65k|        return dynamic_cast<const T*>(this);
   75|  2.65k|    }
_ZNK6Assimp3FBX13TypedPropertyIlE5ValueEv:
   86|    446|    const T& Value() const {
   87|    446|        return value;
   88|    446|    }
_ZN6Assimp3FBX11PropertyGetImEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERKS2_:
  130|    674|inline T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) {
  131|    674|    const Property* const prop = in.Get(name);
  132|    674|    if( nullptr == prop) {
  ------------------
  |  Branch (132:9): [True: 64, False: 610]
  ------------------
  133|     64|        return defaultValue;
  134|     64|    }
  135|       |
  136|       |    // strong typing, no need to be lenient
  137|    610|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  138|    610|    if( nullptr == tprop) {
  ------------------
  |  Branch (138:9): [True: 610, False: 0]
  ------------------
  139|    610|        return defaultValue;
  140|    610|    }
  141|       |
  142|      0|    return tprop->Value();
  143|    610|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyImEEEEPKT_v:
   73|  2.82k|    const T* As() const {
   74|  2.82k|        return dynamic_cast<const T*>(this);
   75|  2.82k|    }
_ZNK6Assimp3FBX13TypedPropertyImE5ValueEv:
   86|      9|    const T& Value() const {
   87|      9|        return value;
   88|      9|    }
_ZN6Assimp3FBX11PropertyGetI10aiVector3tIfEEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEERbb:
  147|   108k|inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
  148|   108k|    const Property* prop = in.Get(name);
  149|   108k|    if( nullptr == prop) {
  ------------------
  |  Branch (149:9): [True: 19.6k, False: 89.1k]
  ------------------
  150|  19.6k|        if ( ! useTemplate ) {
  ------------------
  |  Branch (150:14): [True: 19.2k, False: 373]
  ------------------
  151|  19.2k|            result = false;
  152|  19.2k|            return T();
  153|  19.2k|        }
  154|    373|        const PropertyTable* templ = in.TemplateProps();
  155|    373|        if ( nullptr == templ ) {
  ------------------
  |  Branch (155:14): [True: 96, False: 277]
  ------------------
  156|     96|            result = false;
  157|     96|            return T();
  158|     96|        }
  159|    277|        prop = templ->Get(name);
  160|    277|        if ( nullptr == prop ) {
  ------------------
  |  Branch (160:14): [True: 273, False: 4]
  ------------------
  161|    273|            result = false;
  162|    273|            return T();
  163|    273|        }
  164|    277|    }
  165|       |
  166|       |    // strong typing, no need to be lenient
  167|  89.1k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  168|  89.1k|    if( nullptr == tprop) {
  ------------------
  |  Branch (168:9): [True: 1, False: 89.1k]
  ------------------
  169|      1|        result = false;
  170|      1|        return T();
  171|      1|    }
  172|       |
  173|  89.1k|    result = true;
  174|  89.1k|    return tprop->Value();
  175|  89.1k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyIjEEEEPKT_v:
   73|  2.21k|    const T* As() const {
   74|  2.21k|        return dynamic_cast<const T*>(this);
   75|  2.21k|    }
_ZN6Assimp3FBX11PropertyGetINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEET_RKNS0_13PropertyTableERKS8_Rbb:
  147|    478|inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
  148|    478|    const Property* prop = in.Get(name);
  149|    478|    if( nullptr == prop) {
  ------------------
  |  Branch (149:9): [True: 0, False: 478]
  ------------------
  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|    478|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  168|    478|    if( nullptr == tprop) {
  ------------------
  |  Branch (168:9): [True: 0, False: 478]
  ------------------
  169|      0|        result = false;
  170|      0|        return T();
  171|      0|    }
  172|       |
  173|    478|    result = true;
  174|    478|    return tprop->Value();
  175|    478|}
_ZN6Assimp3FBX11PropertyGetIfEET_RKNS0_13PropertyTableERKNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEERbb:
  147|  5.92k|inline T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) {
  148|  5.92k|    const Property* prop = in.Get(name);
  149|  5.92k|    if( nullptr == prop) {
  ------------------
  |  Branch (149:9): [True: 2.67k, False: 3.24k]
  ------------------
  150|  2.67k|        if ( ! useTemplate ) {
  ------------------
  |  Branch (150:14): [True: 2.61k, False: 60]
  ------------------
  151|  2.61k|            result = false;
  152|  2.61k|            return T();
  153|  2.61k|        }
  154|     60|        const PropertyTable* templ = in.TemplateProps();
  155|     60|        if ( nullptr == templ ) {
  ------------------
  |  Branch (155:14): [True: 50, False: 10]
  ------------------
  156|     50|            result = false;
  157|     50|            return T();
  158|     50|        }
  159|     10|        prop = templ->Get(name);
  160|     10|        if ( nullptr == prop ) {
  ------------------
  |  Branch (160:14): [True: 10, False: 0]
  ------------------
  161|     10|            result = false;
  162|     10|            return T();
  163|     10|        }
  164|     10|    }
  165|       |
  166|       |    // strong typing, no need to be lenient
  167|  3.24k|    const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >();
  168|  3.24k|    if( nullptr == tprop) {
  ------------------
  |  Branch (168:9): [True: 0, False: 3.24k]
  ------------------
  169|      0|        result = false;
  170|      0|        return T();
  171|      0|    }
  172|       |
  173|  3.24k|    result = true;
  174|  3.24k|    return tprop->Value();
  175|  3.24k|}
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyI9aiColor3DEEEEPKT_v:
   73|    421|    const T* As() const {
   74|    421|        return dynamic_cast<const T*>(this);
   75|    421|    }
_ZNK6Assimp3FBX8Property2AsINS0_13TypedPropertyI9aiColor4tIfEEEEEPKT_v:
   73|    421|    const T* As() const {
   74|    421|        return dynamic_cast<const T*>(this);
   75|    421|    }
_ZNK6Assimp3FBX13TypedPropertyI9aiColor4tIfEE5ValueEv:
   86|      4|    const T& Value() const {
   87|      4|        return value;
   88|      4|    }
_ZN6Assimp3FBX13TypedPropertyINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEC2ERKS8_:
   84|    297|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX8PropertyC2Ev:
   78|  45.7k|    Property() = default;
_ZN6Assimp3FBX8PropertyD2Ev:
   70|  45.7k|    virtual ~Property() = default;
_ZN6Assimp3FBX13TypedPropertyIbEC2ERKb:
   84|  2.29k|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyIiEC2ERKi:
   84|  14.0k|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyImEC2ERKm:
   84|      9|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyIlEC2ERKl:
   84|  1.05k|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyI10aiVector3tIfEEC2ERKS3_:
   84|  20.7k|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyIfEC2ERKf:
   84|  7.24k|    explicit TypedProperty(const T& value) : value(value) {}
_ZN6Assimp3FBX13TypedPropertyI9aiColor4tIfEEC2ERKS3_:
   84|      4|    explicit TypedProperty(const T& value) : value(value) {}

_ZN6Assimp3FBX5TokenC2EPKcS3_NS0_9TokenTypeEjj:
   67|  2.85M|    sbegin(sbegin)
   68|  2.85M|    , send(send)
   69|  2.85M|    , type(type)
   70|  2.85M|    , line(line)
   71|  2.85M|    , column(column)
   72|  2.85M|{
   73|  2.85M|    ai_assert(sbegin);
   74|  2.85M|    ai_assert(send);
   75|       |
   76|       |    // tokens must be of non-zero length
   77|       |    ai_assert(static_cast<size_t>(send-sbegin) > 0);
   78|  2.85M|}
_ZN6Assimp3FBX8TokenizeERNSt3__16vectorIPKNS0_5TokenENS1_9allocatorIS5_EEEEPKcRNS_14StackAllocatorE:
  134|     77|void Tokenize(TokenList &output_tokens, const char *input, StackAllocator &token_allocator) {
  135|     77|	ai_assert(input);
  136|     77|	ASSIMP_LOG_DEBUG("Tokenizing ASCII FBX file");
  137|       |
  138|       |    // line and column numbers numbers are one-based
  139|     77|    unsigned int line = 1;
  140|     77|    unsigned int column = 1;
  141|       |
  142|     77|    bool comment = false;
  143|     77|    bool in_double_quotes = false;
  144|     77|    bool pending_data_token = false;
  145|       |
  146|     77|    const char *token_begin = nullptr, *token_end = nullptr;
  147|  21.0M|    for (const char* cur = input;*cur;column += (*cur == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1), ++cur) {
  ------------------
  |  |   49|   167k|#define ASSIMP_FBX_TAB_WIDTH 4
  ------------------
  |  Branch (147:34): [True: 21.0M, False: 75]
  |  Branch (147:50): [True: 167k, False: 20.8M]
  ------------------
  148|  21.0M|        const char c = *cur;
  149|       |
  150|  21.0M|        if (IsLineEnd(c)) {
  ------------------
  |  Branch (150:13): [True: 116k, False: 20.8M]
  ------------------
  151|   116k|            comment = false;
  152|       |
  153|   116k|            column = 0;
  154|   116k|            ++line;
  155|   116k|        }
  156|       |
  157|  21.0M|        if(comment) {
  ------------------
  |  Branch (157:12): [True: 952k, False: 20.0M]
  ------------------
  158|   952k|            continue;
  159|   952k|        }
  160|       |
  161|  20.0M|        if(in_double_quotes) {
  ------------------
  |  Branch (161:12): [True: 8.85M, False: 11.1M]
  ------------------
  162|  8.85M|            if (c == '\"') {
  ------------------
  |  Branch (162:17): [True: 82.3k, False: 8.77M]
  ------------------
  163|  82.3k|                in_double_quotes = false;
  164|  82.3k|                token_end = cur;
  165|       |
  166|  82.3k|                ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
  167|  82.3k|                pending_data_token = false;
  168|  82.3k|            }
  169|  8.85M|            continue;
  170|  8.85M|        }
  171|       |
  172|  11.1M|        switch(c)
  ------------------
  |  Branch (172:16): [True: 2.01M, False: 9.18M]
  ------------------
  173|  11.1M|        {
  174|  82.3k|        case '\"':
  ------------------
  |  Branch (174:9): [True: 82.3k, False: 11.1M]
  ------------------
  175|  82.3k|            if (token_begin) {
  ------------------
  |  Branch (175:17): [True: 1, False: 82.3k]
  ------------------
  176|      1|                TokenizeError("unexpected double-quote", line, column);
  177|      1|            }
  178|  82.3k|            token_begin = cur;
  179|  82.3k|            in_double_quotes = true;
  180|  82.3k|            continue;
  181|       |
  182|  31.9k|        case ';':
  ------------------
  |  Branch (182:9): [True: 31.9k, False: 11.1M]
  ------------------
  183|  31.9k|            ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
  184|  31.9k|            comment = true;
  185|  31.9k|            continue;
  186|       |
  187|   970k|        case '{':
  ------------------
  |  Branch (187:9): [True: 970k, False: 10.2M]
  ------------------
  188|   970k|            ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
  189|   970k|            output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column));
  ------------------
  |  |  160|  1.94M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  190|   970k|            continue;
  191|       |
  192|  5.96k|        case '}':
  ------------------
  |  Branch (192:9): [True: 5.96k, False: 11.1M]
  ------------------
  193|  5.96k|            ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column);
  194|  5.96k|            output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column));
  ------------------
  |  |  160|  11.9k|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  195|  5.96k|            continue;
  196|       |
  197|   868k|        case ',':
  ------------------
  |  Branch (197:9): [True: 868k, False: 10.3M]
  ------------------
  198|   868k|            if (pending_data_token) {
  ------------------
  |  Branch (198:17): [True: 788k, False: 80.3k]
  ------------------
  199|   788k|                ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_DATA, true);
  200|   788k|            }
  201|   868k|            output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column));
  ------------------
  |  |  160|  1.73M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  202|   868k|            continue;
  203|       |
  204|  52.0k|        case ':':
  ------------------
  |  Branch (204:9): [True: 52.0k, False: 11.1M]
  ------------------
  205|  52.0k|            if (pending_data_token) {
  ------------------
  |  Branch (205:17): [True: 52.0k, False: 1]
  ------------------
  206|  52.0k|                ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, TokenType_KEY, true);
  207|  52.0k|            }
  208|      1|            else {
  209|      1|                TokenizeError("unexpected colon", line, column);
  210|      1|            }
  211|  52.0k|            continue;
  212|  11.1M|        }
  213|       |
  214|  9.18M|        if (IsSpaceOrNewLine(c)) {
  ------------------
  |  Branch (214:13): [True: 377k, False: 8.80M]
  ------------------
  215|       |
  216|   377k|            if (token_begin) {
  ------------------
  |  Branch (216:17): [True: 39.4k, False: 338k]
  ------------------
  217|       |                // peek ahead and check if the next token is a colon in which
  218|       |                // case this counts as KEY token.
  219|  39.4k|                TokenType type = TokenType_DATA;
  220|   183k|                for (const char* peek = cur;  *peek && IsSpaceOrNewLine(*peek); ++peek) {
  ------------------
  |  Branch (220:47): [True: 183k, False: 6]
  |  Branch (220:56): [True: 143k, False: 39.4k]
  ------------------
  221|   143k|                    if (*peek == ':') {
  ------------------
  |  Branch (221:25): [True: 0, False: 143k]
  ------------------
  222|      0|                        type = TokenType_KEY;
  223|      0|                        cur = peek;
  224|      0|                        break;
  225|      0|                    }
  226|   143k|                }
  227|       |
  228|  39.4k|                ProcessDataToken(output_tokens, token_allocator, token_begin, token_end, line, column, type);
  229|  39.4k|            }
  230|       |
  231|   377k|            pending_data_token = false;
  232|   377k|        }
  233|  8.80M|        else {
  234|  8.80M|            token_end = cur;
  235|  8.80M|            if (!token_begin) {
  ------------------
  |  Branch (235:17): [True: 931k, False: 7.87M]
  ------------------
  236|   931k|                token_begin = cur;
  237|   931k|            }
  238|       |
  239|  8.80M|            pending_data_token = true;
  240|  8.80M|        }
  241|  9.18M|    }
  242|     77|}
FBXTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_116ProcessDataTokenERNSt3__16vectorIPKNS0_5TokenENS2_9allocatorIS6_EEEERNS_14StackAllocatorERPKcSF_jjNS0_9TokenTypeEb:
  102|  1.97M|{
  103|  1.97M|    if (start && end) {
  ------------------
  |  Branch (103:9): [True: 1.01M, False: 957k]
  |  Branch (103:18): [True: 1.01M, 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|  1.01M|        bool in_double_quotes = false;
  108|  18.3M|        for (const char* c = start; c != end + 1; ++c) {
  ------------------
  |  Branch (108:37): [True: 17.3M, False: 1.01M]
  ------------------
  109|  17.3M|            if (*c == '\"') {
  ------------------
  |  Branch (109:17): [True: 164k, False: 17.1M]
  ------------------
  110|   164k|                in_double_quotes = !in_double_quotes;
  111|   164k|            }
  112|       |
  113|  17.3M|            if (!in_double_quotes && IsSpaceOrNewLine(*c)) {
  ------------------
  |  Branch (113:17): [True: 8.48M, False: 8.85M]
  |  Branch (113:38): [True: 0, False: 8.48M]
  ------------------
  114|      0|                TokenizeError("unexpected whitespace in token", line, column);
  115|      0|            }
  116|  17.3M|        }
  117|       |
  118|  1.01M|        if (in_double_quotes) {
  ------------------
  |  Branch (118:13): [True: 0, False: 1.01M]
  ------------------
  119|      0|            TokenizeError("non-terminated double quotes", line, column);
  120|      0|        }
  121|       |
  122|  1.01M|        output_tokens.push_back(new_Token(start,end + 1,type,line,column));
  ------------------
  |  |  160|  2.02M|#define new_Token new (token_allocator.Allocate(sizeof(Token))) Token
  ------------------
  123|  1.01M|    }
  124|   957k|    else if (must_have_token) {
  ------------------
  |  Branch (124:14): [True: 0, False: 957k]
  ------------------
  125|      0|        TokenizeError("unexpected character, expected data token", line, column);
  126|      0|    }
  127|       |
  128|  1.97M|    start = end = nullptr;
  129|  1.97M|}
FBXTokenizer.cpp:_ZN6Assimp3FBX12_GLOBAL__N_113TokenizeErrorERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEjj:
   89|      2|{
   90|      2|    throw DeadlyImportError("FBX-Tokenize", Util::GetLineAndColumnText(line,column), message);
   91|      2|}

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

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

_ZN6Assimp3FBX4Util14destructor_funINS0_5TokenEEclEPVKS3_:
   66|  6.53M|    void operator()(const volatile T* del) {
   67|  6.53M|        if (del) {
  ------------------
  |  Branch (67:13): [True: 6.53M, False: 0]
  ------------------
   68|  6.53M|            del->~T();
   69|  6.53M|        }
   70|  6.53M|    }
_ZN6Assimp3FBX4Util10delete_funI6aiMeshEclEPVKS3_:
   58|    765|    void operator()(const volatile T* del) {
   59|    765|        delete del;
   60|    765|    }
_ZN6Assimp3FBX4Util10delete_funI10aiMaterialEclEPVKS3_:
   58|    336|    void operator()(const volatile T* del) {
   59|    336|        delete del;
   60|    336|    }
_ZN6Assimp3FBX4Util10delete_funI11aiAnimationEclEPVKS3_:
   58|    215|    void operator()(const volatile T* del) {
   59|    215|        delete del;
   60|    215|    }
_ZN6Assimp3FBX4Util10delete_funI7aiLightEclEPVKS3_:
   58|    272|    void operator()(const volatile T* del) {
   59|    272|        delete del;
   60|    272|    }
_ZN6Assimp3FBX4Util10delete_funI8aiCameraEclEPVKS3_:
   58|    286|    void operator()(const volatile T* del) {
   59|    286|        delete del;
   60|    286|    }
_ZN6Assimp3FBX4Util10delete_funI9aiTextureEclEPVKS3_:
   58|      6|    void operator()(const volatile T* del) {
   59|      6|        delete del;
   60|      6|    }
_ZN6Assimp3FBX4Util10delete_funI10aiNodeAnimEclEPVKS3_:
   58|     69|    void operator()(const volatile T* del) {
   59|     69|        delete del;
   60|     69|    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp17Q3BSPFileImporterC2Ev:
  137|    402|        m_pCurrentMesh(nullptr), m_pCurrentFace(nullptr) {
  138|       |    // empty
  139|    402|}
_ZN6Assimp17Q3BSPFileImporterD2Ev:
  143|    402|Q3BSPFileImporter::~Q3BSPFileImporter() {
  144|    402|    clear();
  145|    402|}
_ZN6Assimp17Q3BSPFileImporter5clearEv:
  148|    402|void Q3BSPFileImporter::clear() {
  149|    402|    for (FaceMap::iterator it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it) {
  ------------------
  |  Branch (149:62): [True: 0, False: 402]
  ------------------
  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|    402|}
_ZNK6Assimp17Q3BSPFileImporter7GetInfoEv:
  168|    402|const aiImporterDesc *Q3BSPFileImporter::GetInfo() const {
  169|    402|    return &desc;
  170|    402|}

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp11X3DImporterC2Ev:
  192|    402|        mNodeElementCur(nullptr),
  193|    402|        mScene(nullptr),
  194|    402|        mpIOHandler(nullptr) {
  195|       |    // empty
  196|    402|}
_ZN6Assimp11X3DImporterD2Ev:
  198|    402|X3DImporter::~X3DImporter() {
  199|       |    // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
  200|    402|    Clear();
  201|    402|}
_ZN6Assimp11X3DImporter5ClearEv:
  203|    402|void X3DImporter::Clear() {
  204|    402|    mNodeElementCur = nullptr;
  205|       |    // Delete all elements
  206|    402|    if (!NodeElement_List.empty()) {
  ------------------
  |  Branch (206:9): [True: 0, False: 402]
  ------------------
  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|    402|}
_ZNK6Assimp11X3DImporter7GetInfoEv:
  340|    402|const aiImporterDesc *X3DImporter::GetInfo() const {
  341|    402|    return &Description;
  342|    402|}

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

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

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

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

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

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

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

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

_ZN6Assimp11CompressionC2Ev:
   62|  10.5k|        mImpl(new impl) {
   63|       |    // empty
   64|  10.5k|}
_ZN6Assimp11CompressionD2Ev:
   66|  10.5k|Compression::~Compression() {
   67|  10.5k|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|  10.5k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 10.5k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   68|       |
   69|  10.5k|    if (mImpl->mOpen) {
  ------------------
  |  Branch (69:9): [True: 2.21k, False: 8.33k]
  ------------------
   70|  2.21k|        close();
   71|  2.21k|    }
   72|       |
   73|  10.5k|    delete mImpl;
   74|  10.5k|}
_ZN6Assimp11Compression4openENS0_6FormatENS0_9FlushModeEi:
   76|  10.5k|bool Compression::open(Format format, FlushMode flush, int windowBits) {
   77|  10.5k|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|  10.5k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 10.5k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   78|       |
   79|  10.5k|    if (mImpl->mOpen) {
  ------------------
  |  Branch (79:9): [True: 0, False: 10.5k]
  ------------------
   80|      0|        return false;
   81|      0|    }
   82|       |
   83|       |    // build a zlib stream
   84|  10.5k|    mImpl->mZSstream.opaque = Z_NULL;
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   85|  10.5k|    mImpl->mZSstream.zalloc = Z_NULL;
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   86|  10.5k|    mImpl->mZSstream.zfree = Z_NULL;
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
   87|  10.5k|    mImpl->mFlushMode = flush;
   88|  10.5k|    if (format == Format::Binary) {
  ------------------
  |  Branch (88:9): [True: 10.5k, False: 0]
  ------------------
   89|  10.5k|        mImpl->mZSstream.data_type = Z_BINARY;
  ------------------
  |  |  203|  10.5k|#define Z_BINARY   0
  ------------------
   90|  10.5k|    } 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|  10.5k|    if (windowBits == 0) {
  ------------------
  |  Branch (95:9): [True: 10.5k, False: 0]
  ------------------
   96|  10.5k|        inflateInit(&mImpl->mZSstream);
  ------------------
  |  | 1813|  10.5k|          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
  |  |  ------------------
  |  |  |  |   40|  10.5k|#define ZLIB_VERSION "1.2.13"
  |  |  ------------------
  ------------------
   97|  10.5k|    } 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|  10.5k|    mImpl->mOpen = true;
  101|       |
  102|  10.5k|    return mImpl->mOpen;
  103|  10.5k|}
_ZN6Assimp11Compression10decompressEPKvmRNSt3__16vectorIcNS3_9allocatorIcEEEE:
  133|  10.5k|size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
  134|  10.5k|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|  10.5k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 10.5k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  135|  10.5k|    if (data == nullptr || in == 0) {
  ------------------
  |  Branch (135:9): [True: 0, False: 10.5k]
  |  Branch (135:28): [True: 0, False: 10.5k]
  ------------------
  136|      0|        return 0l;
  137|      0|    }
  138|       |
  139|  10.5k|    mImpl->mZSstream.next_in = (Bytef*)(data);
  140|  10.5k|    mImpl->mZSstream.avail_in = (uInt)in;
  141|       |
  142|  10.5k|    int ret = 0;
  143|  10.5k|    size_t total = 0l;
  144|  10.5k|    const int flushMode = getFlushMode(mImpl->mFlushMode);
  145|  10.5k|    if (flushMode == Z_FINISH) {
  ------------------
  |  |  172|  10.5k|#define Z_FINISH        4
  ------------------
  |  Branch (145:9): [True: 10.5k, False: 0]
  ------------------
  146|  10.5k|        mImpl->mZSstream.avail_out = static_cast<uInt>(uncompressed.size());
  147|  10.5k|        mImpl->mZSstream.next_out = reinterpret_cast<Bytef *>(&*uncompressed.begin());
  148|  10.5k|        ret = inflate(&mImpl->mZSstream, Z_FINISH);
  ------------------
  |  |  172|  10.5k|#define Z_FINISH        4
  ------------------
  149|       |
  150|  10.5k|        if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  178|  21.1k|#define Z_STREAM_END    1
  ------------------
                      if (ret != Z_STREAM_END && ret != Z_OK) {
  ------------------
  |  |  177|  2.21k|#define Z_OK            0
  ------------------
  |  Branch (150:13): [True: 2.21k, False: 8.33k]
  |  Branch (150:36): [True: 2.21k, False: 0]
  ------------------
  151|  2.21k|            throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
  152|  2.21k|        }
  153|  8.33k|        total = mImpl->mZSstream.avail_out;
  154|  8.33k|    } 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|  8.33k|    return total;
  173|  10.5k|}
_ZN6Assimp11Compression5closeEv:
  205|  10.5k|bool Compression::close() {
  206|  10.5k|    ai_assert(mImpl != nullptr);
  ------------------
  |  |   67|  10.5k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 10.5k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  207|       |
  208|  10.5k|    if (!mImpl->mOpen) {
  ------------------
  |  Branch (208:9): [True: 0, False: 10.5k]
  ------------------
  209|      0|        return false;
  210|      0|    }
  211|       |
  212|  10.5k|    inflateEnd(&mImpl->mZSstream);
  213|  10.5k|    mImpl->mOpen = false;
  214|       |
  215|  10.5k|    return true;
  216|  10.5k|}
_ZN6Assimp11Compression4implC2Ev:
   54|  10.5k|            mOpen(false),
   55|  10.5k|            mZSstream(),
   56|  10.5k|            mFlushMode(Compression::FlushMode::NoFlush) {
   57|       |        // empty
   58|  10.5k|    }
Compression.cpp:_ZN6AssimpL12getFlushModeENS_11Compression9FlushModeE:
  105|  10.5k|static int getFlushMode(Compression::FlushMode flush) {
  106|  10.5k|    int z_flush = 0;
  107|  10.5k|    switch (flush) {
  108|      0|        case Compression::FlushMode::NoFlush:
  ------------------
  |  Branch (108:9): [True: 0, False: 10.5k]
  ------------------
  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: 10.5k]
  ------------------
  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: 10.5k]
  ------------------
  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: 10.5k]
  ------------------
  118|      0|            z_flush = Z_SYNC_FLUSH;
  ------------------
  |  |  170|      0|#define Z_SYNC_FLUSH    2
  ------------------
  119|      0|            break;
  120|  10.5k|        case Compression::FlushMode::Finish:
  ------------------
  |  Branch (120:9): [True: 10.5k, False: 0]
  ------------------
  121|  10.5k|            z_flush = Z_FINISH;
  ------------------
  |  |  172|  10.5k|#define Z_FINISH        4
  ------------------
  122|  10.5k|            break;
  123|      0|        default:
  ------------------
  |  Branch (123:9): [True: 0, False: 10.5k]
  ------------------
  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|  10.5k|    }
  127|       |
  128|  10.5k|    return z_flush;
  129|  10.5k|}

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

_ZN6Assimp6Logger5debugEPKc:
  166|  11.3k|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|  11.3k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (171:9): [True: 0, False: 11.3k]
  ------------------
  172|      0|        return OnDebug("<fixme: long message discarded>");
  173|      0|    }
  174|  11.3k|    return OnDebug(message);
  175|  11.3k|}
_ZN6Assimp6Logger12verboseDebugEPKc:
  178|    695|void Logger::verboseDebug(const char *message) {
  179|       |
  180|       |    // SECURITY FIX: see above
  181|    695|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (181:9): [True: 0, False: 695]
  ------------------
  182|      0|        return OnVerboseDebug("<fixme: long message discarded>");
  183|      0|    }
  184|    695|    return OnVerboseDebug(message);
  185|    695|}
_ZN6Assimp6Logger4infoEPKc:
  188|  21.6k|void Logger::info(const char *message) {
  189|       |
  190|       |    // SECURITY FIX: see above
  191|  21.6k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (191:9): [True: 0, False: 21.6k]
  ------------------
  192|      0|        return OnInfo("<fixme: long message discarded>");
  193|      0|    }
  194|  21.6k|    return OnInfo(message);
  195|  21.6k|}
_ZN6Assimp6Logger4warnEPKc:
  198|   234k|void Logger::warn(const char *message) {
  199|       |
  200|       |    // SECURITY FIX: see above
  201|   234k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (201:9): [True: 965, False: 233k]
  ------------------
  202|    965|        return OnWarn("<fixme: long message discarded>");
  203|    965|    }
  204|   233k|    return OnWarn(message);
  205|   234k|}
_ZN6Assimp6Logger5errorEPKc:
  208|    630|void Logger::error(const char *message) {
  209|       |    // SECURITY FIX: see above
  210|    630|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (210:9): [True: 1, False: 629]
  ------------------
  211|      1|        return OnError("<fixme: long message discarded>");
  212|      1|    }
  213|    629|    return OnError(message);
  214|    630|}
_ZN6Assimp13DefaultLogger12isNullLoggerEv:
  232|  7.21k|bool DefaultLogger::isNullLogger() {
  233|  7.21k|    return m_pLogger == &s_pNullLogger;
  234|  7.21k|}
_ZN6Assimp13DefaultLogger3getEv:
  237|   286k|Logger *DefaultLogger::get() {
  238|   286k|    return m_pLogger;
  239|   286k|}

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

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

_ZN6Assimp16FileSystemFilterC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
   68|    402|    : mWrapped  (old)
   69|    402|    , mSrc_file(file)
   70|    402|    , mSep(mWrapped->getOsSeparator()) {
   71|    402|        ai_assert(nullptr != mWrapped);
   72|       |
   73|       |        // Determine base directory
   74|    402|        mBase = mSrc_file;
   75|    402|        std::string::size_type ss2;
   76|    402|        if (std::string::npos != (ss2 = mBase.find_last_of("\\/")))  {
  ------------------
  |  Branch (76:13): [True: 0, False: 402]
  ------------------
   77|      0|            mBase.erase(ss2,mBase.length()-ss2);
   78|    402|        } else {
   79|    402|            mBase = std::string();
   80|    402|        }
   81|       |
   82|       |        // make sure the directory is terminated properly
   83|    402|        char s;
   84|       |
   85|    402|        if ( mBase.empty() ) {
  ------------------
  |  Branch (85:14): [True: 402, False: 0]
  ------------------
   86|    402|            mBase = ".";
   87|    402|            mBase += getOsSeparator();
   88|    402|        } 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|    402|        DefaultLogger::get()->info("Import root directory is \'", mBase, "\'");
   93|    402|    }
_ZNK6Assimp16FileSystemFilter14getOsSeparatorEv:
  116|    402|    char getOsSeparator() const {
  117|    402|        return mSep;
  118|    402|    }
_ZN6Assimp16FileSystemFilter4OpenEPKcS2_:
  122|    402|    IOStream* Open( const char* pFile, const char* pMode = "rb") {
  123|    402|        ai_assert( nullptr != mWrapped );
  124|    402|        if ( nullptr == pFile || nullptr == pMode ) {
  ------------------
  |  Branch (124:14): [True: 0, False: 402]
  |  Branch (124:34): [True: 0, False: 402]
  ------------------
  125|      0|            return nullptr;
  126|      0|        }
  127|       |
  128|    402|        ai_assert( nullptr != pFile );
  129|    402|        ai_assert( nullptr != pMode );
  130|       |
  131|       |        // First try the unchanged path
  132|    402|        IOStream* s = mWrapped->Open(pFile,pMode);
  133|       |
  134|    402|        if (nullptr == s) {
  ------------------
  |  Branch (134:13): [True: 0, False: 402]
  ------------------
  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|    402|        return s;
  153|    402|    }
_ZN6Assimp16FileSystemFilter5CloseEPNS_8IOStreamE:
  157|    402|    void Close( IOStream* pFile) {
  158|       |        ai_assert( nullptr != mWrapped );
  159|    402|        return mWrapped->Close(pFile);
  160|    402|    }
_ZN6Assimp16FileSystemFilterD2Ev:
   96|    402|    ~FileSystemFilter() = default;

_ZN6Assimp6Intern22AllocateFromAssimpHeapnwEm:
  114|  2.01k|void* AllocateFromAssimpHeap::operator new ( size_t num_bytes)  {
  115|  2.01k|    return ::operator new(num_bytes);
  116|  2.01k|}
_ZN6Assimp6Intern22AllocateFromAssimpHeapdlEPv:
  127|  2.01k|void AllocateFromAssimpHeap::operator delete ( void* data)  {
  128|  2.01k|    return ::operator delete(data);
  129|  2.01k|}
_ZN6Assimp8ImporterC2Ev:
  150|    402| : pimpl( new ImporterPimpl ) {
  151|    402|    pimpl->mScene = nullptr;
  152|    402|    pimpl->mErrorString = std::string();
  153|       |
  154|       |    // Allocate a default IO handler
  155|    402|    pimpl->mIOHandler = new DefaultIOSystem;
  156|    402|    pimpl->mIsDefaultHandler = true;
  157|    402|    pimpl->bExtraVerbose     = false; // disable extra verbose mode by default
  158|       |
  159|    402|    pimpl->mProgressHandler = new DefaultProgressHandler();
  160|    402|    pimpl->mIsDefaultProgressHandler = true;
  161|       |
  162|    402|    GetImporterInstanceList(pimpl->mImporter);
  163|    402|    GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps);
  164|       |
  165|       |    // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list.
  166|    402|    pimpl->mPPShared = new SharedPostProcessInfo();
  167|    402|    for (std::vector<BaseProcess*>::iterator it =  pimpl->mPostProcessingSteps.begin();
  168|  13.6k|        it != pimpl->mPostProcessingSteps.end();
  ------------------
  |  Branch (168:9): [True: 13.2k, False: 402]
  ------------------
  169|  13.2k|        ++it)   {
  170|       |
  171|  13.2k|        (*it)->SetSharedData(pimpl->mPPShared);
  172|  13.2k|    }
  173|    402|}
_ZN6Assimp8ImporterD2Ev:
  177|    402|Importer::~Importer() {
  178|       |    // Delete all import plugins
  179|    402|	DeleteImporterInstanceList(pimpl->mImporter);
  180|       |
  181|       |    // Delete all post-processing plug-ins
  182|  13.6k|    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
  ------------------
  |  Branch (182:30): [True: 13.2k, False: 402]
  ------------------
  183|  13.2k|        delete pimpl->mPostProcessingSteps[a];
  184|  13.2k|    }
  185|       |
  186|       |    // Delete the assigned IO and progress handler
  187|    402|    delete pimpl->mIOHandler;
  188|    402|    delete pimpl->mProgressHandler;
  189|       |
  190|       |    // Kill imported scene. Destructor's should do that recursively
  191|    402|    delete pimpl->mScene;
  192|       |
  193|       |    // Delete shared post-processing data
  194|    402|    delete pimpl->mPPShared;
  195|       |
  196|       |    // and finally the pimpl itself
  197|    402|    delete pimpl;
  198|    402|}
_ZN6Assimp8Importer16UnregisterLoaderEPNS_12BaseImporterE:
  251|  18.8k|aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
  252|  18.8k|    if(!pImp) {
  ------------------
  |  Branch (252:8): [True: 0, False: 18.8k]
  ------------------
  253|       |        // unregistering a nullptr importer is no problem for us ... really!
  254|      0|        return AI_SUCCESS;
  255|      0|    }
  256|       |
  257|  18.8k|    ASSIMP_BEGIN_EXCEPTION_REGION();
  258|  18.8k|    std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),
  259|  18.8k|        pimpl->mImporter.end(),pImp);
  260|       |
  261|  18.8k|    if (it != pimpl->mImporter.end())   {
  ------------------
  |  Branch (261:9): [True: 18.8k, False: 0]
  ------------------
  262|  18.8k|        pimpl->mImporter.erase(it);
  263|  18.8k|        ASSIMP_LOG_INFO("Unregistering custom importer: ");
  264|  18.8k|        return AI_SUCCESS;
  265|  18.8k|    }
  266|  18.8k|    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|  18.8k|}
_ZN6Assimp8Importer12SetIOHandlerEPNS_8IOSystemE:
  297|    804|void Importer::SetIOHandler( IOSystem* pIOHandler) {
  298|    804|    ai_assert(nullptr != pimpl);
  299|       |
  300|    804|    ASSIMP_BEGIN_EXCEPTION_REGION();
  301|       |    // If the new handler is zero, allocate a default IO implementation.
  302|    804|    if (!pIOHandler) {
  ------------------
  |  Branch (302:9): [True: 0, False: 804]
  ------------------
  303|       |        // Release pointer in the possession of the caller
  304|      0|        pimpl->mIOHandler = new DefaultIOSystem();
  305|      0|        pimpl->mIsDefaultHandler = true;
  306|    804|    } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
  ------------------
  |  Branch (306:16): [True: 804, False: 0]
  ------------------
  307|    804|        delete pimpl->mIOHandler;
  308|    804|        pimpl->mIOHandler = pIOHandler;
  309|    804|        pimpl->mIsDefaultHandler = false;
  310|    804|    }
  311|    804|    ASSIMP_END_EXCEPTION_REGION(void);
  312|    804|}
_ZNK6Assimp8Importer18GetProgressHandlerEv:
  352|  5.52k|ProgressHandler* Importer::GetProgressHandler() const {
  353|  5.52k|    ai_assert(nullptr != pimpl);
  354|       |
  355|  5.52k|    return pimpl->mProgressHandler;
  356|  5.52k|}
_Z14_ValidateFlagsj:
  368|    319|bool _ValidateFlags(unsigned int pFlags) {
  369|    319|    if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals)   {
  ------------------
  |  Branch (369:9): [True: 319, False: 0]
  |  Branch (369:48): [True: 0, False: 319]
  ------------------
  370|      0|        ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
  371|      0|        return false;
  372|      0|    }
  373|    319|    if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices)    {
  ------------------
  |  Branch (373:9): [True: 0, False: 319]
  |  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|    319|    return true;
  378|    319|}
_ZN6Assimp8Importer18ReadFileFromMemoryEPKvmjPKc:
  485|    402|const aiScene* Importer::ReadFileFromMemory(const void* pBuffer, size_t pLength, unsigned int pFlags, const char* pHint ) {
  486|    402|    ai_assert(nullptr != pimpl);
  487|       |
  488|    402|    IOSystem* io = pimpl->mIOHandler;
  489|    402|    try {
  490|    402|        if (pHint == nullptr) {
  ------------------
  |  Branch (490:13): [True: 0, False: 402]
  ------------------
  491|      0|            pHint = "";
  492|      0|        }
  493|    402|        if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
  ------------------
  |  Branch (493:13): [True: 0, False: 402]
  |  Branch (493:25): [True: 0, False: 402]
  |  Branch (493:37): [True: 0, False: 402]
  ------------------
  494|      0|            pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
  495|      0|            return nullptr;
  496|      0|        }
  497|       |        // prevent deletion of the previous IOHandler
  498|    402|        pimpl->mIOHandler = nullptr;
  499|       |
  500|    402|        SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
  501|       |
  502|       |        // read the file and recover the previous IOSystem
  503|    402|        static const size_t BufSize(Importer::MaxLenHint + 28);
  504|    402|        char fbuff[BufSize];
  505|    402|        ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
  506|       |
  507|    402|        ReadFile(fbuff,pFlags);
  508|    402|        SetIOHandler(io);
  509|    402|    } 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|    402|    return pimpl->mScene;
  523|    402|}
_Z15WriteLogOpeningRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
  526|    402|void WriteLogOpening(const std::string& file) {
  527|       |
  528|    402|    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|    402|    const unsigned int flags = aiGetCompileFlags();
  535|    402|    std::stringstream stream;
  536|    402|    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|    402|           << " "
  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|    402|#ifdef ASSIMP_BUILD_DEBUG
  574|    402|           << " debug"
  575|    402|#endif
  576|       |
  577|    402|           << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
  ------------------
  |  |  105|    402|#define ASSIMP_CFLAGS_NOBOOST           0x8
  ------------------
  |  Branch (577:16): [True: 0, False: 402]
  ------------------
  578|    402|           << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "")
  ------------------
  |  |   98|    402|#define ASSIMP_CFLAGS_SHARED  0x1
  ------------------
  |  Branch (578:16): [True: 0, False: 402]
  ------------------
  579|    402|           << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "")
  ------------------
  |  |  107|    402|#define ASSIMP_CFLAGS_SINGLETHREADED    0x10
  ------------------
  |  Branch (579:16): [True: 402, False: 0]
  ------------------
  580|    402|           << (flags & ASSIMP_CFLAGS_DOUBLE_SUPPORT ? " double : " : "single : ");
  ------------------
  |  |  109|    402|#define ASSIMP_CFLAGS_DOUBLE_SUPPORT 0x20
  ------------------
  |  Branch (580:16): [True: 0, False: 402]
  ------------------
  581|       |
  582|       |    ASSIMP_LOG_DEBUG(stream.str());
  583|    402|}
_ZN6Assimp8Importer8ReadFileEPKcj:
  587|    402|const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
  588|    402|    ai_assert(nullptr != pimpl);
  589|       |
  590|    402|    ASSIMP_BEGIN_EXCEPTION_REGION();
  591|    402|    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|    402|    WriteLogOpening(pFile);
  600|       |
  601|       |#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  602|       |    try
  603|       |#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
  604|    402|    {
  605|       |        // Check whether this Importer instance has already loaded
  606|       |        // a scene. In this case we need to delete the old one
  607|    402|        if (pimpl->mScene)  {
  ------------------
  |  Branch (607:13): [True: 0, False: 402]
  ------------------
  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|    402|        if( !pimpl->mIOHandler->Exists( pFile)) {
  ------------------
  |  Branch (614:13): [True: 0, False: 402]
  ------------------
  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|    402|        std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
  ------------------
  |  Branch (621:44): [True: 0, False: 402]
  ------------------
  622|    402|        if (profiler) {
  ------------------
  |  Branch (622:13): [True: 0, False: 402]
  ------------------
  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|    402|        SetPropertyInteger("importerIndex", -1);
  629|    402|        struct ImporterAndIndex {
  630|    402|            BaseImporter * importer;
  631|    402|            unsigned int   index;
  632|    402|        };
  633|    402|        std::vector<ImporterAndIndex> possibleImporters;
  634|    804|        for (unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
  ------------------
  |  Branch (634:34): [True: 402, False: 402]
  ------------------
  635|       |
  636|       |            // Every importer has a list of supported extensions.
  637|    402|            std::set<std::string> extensions;
  638|    402|            pimpl->mImporter[a]->GetExtensionList(extensions);
  639|       |
  640|    402|            if (BaseImporter::HasExtension(pFile, extensions)) {
  ------------------
  |  Branch (640:17): [True: 402, False: 0]
  ------------------
  641|    402|                ImporterAndIndex candidate = { pimpl->mImporter[a], a };
  642|    402|                possibleImporters.push_back(candidate);
  643|    402|            }
  644|    402|        }
  645|       |
  646|       |        // If just one importer supports this extension, pick it and close the case.
  647|    402|        BaseImporter* imp = nullptr;
  648|    402|        if (1 == possibleImporters.size()) {
  ------------------
  |  Branch (648:13): [True: 402, False: 0]
  ------------------
  649|    402|            imp = possibleImporters[0].importer;
  650|    402|            SetPropertyInteger("importerIndex", possibleImporters[0].index);
  651|    402|        }
  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|    402|        if (!imp)   {
  ------------------
  |  Branch (669:13): [True: 0, False: 402]
  ------------------
  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|    402|        IOStream * fileIO = pimpl->mIOHandler->Open( pFile );
  689|    402|        uint32_t fileSize = 0;
  690|    402|        if (fileIO)
  ------------------
  |  Branch (690:13): [True: 402, False: 0]
  ------------------
  691|    402|        {
  692|    402|            fileSize = static_cast<uint32_t>(fileIO->FileSize());
  693|    402|            pimpl->mIOHandler->Close( fileIO );
  694|    402|        }
  695|       |
  696|       |        // Dispatch the reading to the worker class for this format
  697|    402|        const aiImporterDesc *desc( imp->GetInfo() );
  698|    402|        std::string ext( "unknown" );
  699|    402|        if ( nullptr != desc ) {
  ------------------
  |  Branch (699:14): [True: 402, False: 0]
  ------------------
  700|    402|            ext = desc->mName;
  701|    402|        }
  702|    402|        ASSIMP_LOG_INFO("Found a matching importer for this file format: ", ext, "." );
  703|    402|        pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
  704|       |
  705|    402|        if (profiler) {
  ------------------
  |  Branch (705:13): [True: 0, False: 402]
  ------------------
  706|      0|            profiler->BeginRegion("import");
  707|      0|        }
  708|       |
  709|    402|        pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
  710|    402|        pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize );
  711|       |
  712|    402|        if (profiler) {
  ------------------
  |  Branch (712:13): [True: 0, False: 402]
  ------------------
  713|      0|            profiler->EndRegion("import");
  714|      0|        }
  715|       |
  716|    402|        SetPropertyString("sourceFilePath", pFile);
  717|       |
  718|       |        // If successful, apply all active post processing steps to the imported data
  719|    402|        if( pimpl->mScene)  {
  ------------------
  |  Branch (719:13): [True: 337, False: 65]
  ------------------
  720|    337|            if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
  ------------------
  |  Branch (720:17): [True: 0, False: 337]
  |  Branch (720:46): [True: 337, False: 0]
  ------------------
  721|    337|                if (!pimpl->mScene->mMetaData) {
  ------------------
  |  Branch (721:21): [True: 0, False: 337]
  ------------------
  722|      0|                    pimpl->mScene->mMetaData = new aiMetadata;
  723|      0|                }
  724|    337|                pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
  725|    337|            }
  726|       |
  727|    337|#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  728|       |            // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
  729|    337|            if (pFlags & aiProcess_ValidateDataStructure) {
  ------------------
  |  Branch (729:17): [True: 337, False: 0]
  ------------------
  730|    337|                ValidateDSProcess ds;
  731|    337|                ds.ExecuteOnScene (this);
  732|    337|                if (!pimpl->mScene) {
  ------------------
  |  Branch (732:21): [True: 18, False: 319]
  ------------------
  733|     18|                    return nullptr;
  734|     18|                }
  735|    337|            }
  736|    319|#endif // ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  737|       |
  738|       |            // Preprocess the scene and prepare it for post-processing
  739|    319|            if (profiler) {
  ------------------
  |  Branch (739:17): [True: 0, False: 319]
  ------------------
  740|      0|                profiler->BeginRegion("preprocess");
  741|      0|            }
  742|       |
  743|    319|            ScenePreprocessor pre(pimpl->mScene);
  744|    319|            pre.ProcessScene();
  745|       |
  746|    319|            if (profiler) {
  ------------------
  |  Branch (746:17): [True: 0, False: 319]
  ------------------
  747|      0|                profiler->EndRegion("preprocess");
  748|      0|            }
  749|       |
  750|       |            // Ensure that the validation process won't be called twice
  751|    319|            ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
  752|    319|        }
  753|       |        // if failed, extract the error string
  754|     65|        else if( !pimpl->mScene) {
  ------------------
  |  Branch (754:18): [True: 65, False: 0]
  ------------------
  755|     65|            pimpl->mErrorString = imp->GetErrorText();
  756|     65|            pimpl->mException = imp->GetException();
  757|     65|        }
  758|       |
  759|       |        // clear any data allocated by post-process steps
  760|    384|        pimpl->mPPShared->Clean();
  761|       |
  762|    384|        if (profiler) {
  ------------------
  |  Branch (762:13): [True: 0, False: 384]
  ------------------
  763|      0|            profiler->EndRegion("total");
  764|      0|        }
  765|    384|    }
  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|    384|    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
  783|       |
  784|    384|    return pimpl->mScene;
  785|    402|}
_ZN6Assimp8Importer19ApplyPostProcessingEj:
  790|    319|const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
  791|    319|    ai_assert(nullptr != pimpl);
  792|       |
  793|    319|    ASSIMP_BEGIN_EXCEPTION_REGION();
  794|       |    // Return immediately if no scene is active
  795|    319|    if (!pimpl->mScene) {
  ------------------
  |  Branch (795:9): [True: 0, False: 319]
  ------------------
  796|      0|        return nullptr;
  797|      0|    }
  798|       |
  799|       |    // If no flags are given, return the current scene with no further action
  800|    319|    if (!pFlags) {
  ------------------
  |  Branch (800:9): [True: 0, False: 319]
  ------------------
  801|      0|        return pimpl->mScene;
  802|      0|    }
  803|       |
  804|       |    // In debug builds: run basic flag validation
  805|    319|    ai_assert(_ValidateFlags(pFlags));
  806|    319|    ASSIMP_LOG_INFO("Entering post processing pipeline");
  807|       |
  808|    319|#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|    319|    if (pFlags & aiProcess_ValidateDataStructure) {
  ------------------
  |  Branch (811:9): [True: 0, False: 319]
  ------------------
  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|    319|#endif // no validation
  819|    319|#ifdef ASSIMP_BUILD_DEBUG
  820|    319|    if (pimpl->bExtraVerbose)
  ------------------
  |  Branch (820:9): [True: 0, False: 319]
  ------------------
  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|    319|    std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
  ------------------
  |  Branch (833:40): [True: 0, False: 319]
  ------------------
  834|  10.8k|    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)   {
  ------------------
  |  Branch (834:30): [True: 10.5k, False: 319]
  ------------------
  835|  10.5k|        BaseProcess* process = pimpl->mPostProcessingSteps[a];
  836|  10.5k|        pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
  837|  10.5k|        if( process->IsActive( pFlags)) {
  ------------------
  |  Branch (837:13): [True: 4.78k, False: 5.74k]
  ------------------
  838|  4.78k|            if (profiler) {
  ------------------
  |  Branch (838:17): [True: 0, False: 4.78k]
  ------------------
  839|      0|                profiler->BeginRegion("postprocess");
  840|      0|            }
  841|       |
  842|  4.78k|            process->ExecuteOnScene ( this );
  843|       |
  844|  4.78k|            if (profiler) {
  ------------------
  |  Branch (844:17): [True: 0, False: 4.78k]
  ------------------
  845|      0|                profiler->EndRegion("postprocess");
  846|      0|            }
  847|  4.78k|        }
  848|  10.5k|        if( !pimpl->mScene) {
  ------------------
  |  Branch (848:13): [True: 0, False: 10.5k]
  ------------------
  849|      0|            break;
  850|      0|        }
  851|  10.5k|#ifdef ASSIMP_BUILD_DEBUG
  852|  10.5k|#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
  853|       |        // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
  854|  10.5k|        if (pimpl->bExtraVerbose)   {
  ------------------
  |  Branch (854:13): [True: 0, False: 10.5k]
  ------------------
  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|  10.5k|#endif  // no validation
  865|  10.5k|#endif // ! DEBUG
  866|  10.5k|    }
  867|    319|    pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
  868|    319|        static_cast<int>(pimpl->mPostProcessingSteps.size()) );
  869|       |
  870|       |    // update private scene flags
  871|    319|    if( pimpl->mScene ) {
  ------------------
  |  Branch (871:9): [True: 319, False: 0]
  ------------------
  872|    319|      ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
  873|    319|    }
  874|       |
  875|       |    // clear any data allocated by post-process steps
  876|    319|    pimpl->mPPShared->Clean();
  877|    319|    ASSIMP_LOG_INFO("Leaving post processing pipeline");
  878|       |
  879|    319|    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
  880|       |
  881|    319|    return pimpl->mScene;
  882|    319|}
_ZNK6Assimp8Importer16GetImporterCountEv:
  969|    402|size_t Importer::GetImporterCount() const {
  970|    402|    ai_assert(nullptr != pimpl);
  971|       |
  972|    402|    return pimpl->mImporter.size();
  973|    402|}
_ZNK6Assimp8Importer15GetImporterInfoEm:
  976|  19.2k|const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
  977|  19.2k|    ai_assert(nullptr != pimpl);
  978|       |
  979|  19.2k|    if (index >= pimpl->mImporter.size()) {
  ------------------
  |  Branch (979:9): [True: 0, False: 19.2k]
  ------------------
  980|      0|        return nullptr;
  981|      0|    }
  982|  19.2k|    return pimpl->mImporter[index]->GetInfo();
  983|  19.2k|}
_ZNK6Assimp8Importer11GetImporterEm:
  987|  19.2k|BaseImporter* Importer::GetImporter (size_t index) const {
  988|  19.2k|    ai_assert(nullptr != pimpl);
  989|       |
  990|  19.2k|    if (index >= pimpl->mImporter.size()) {
  ------------------
  |  Branch (990:9): [True: 0, False: 19.2k]
  ------------------
  991|      0|        return nullptr;
  992|      0|    }
  993|  19.2k|    return pimpl->mImporter[index];
  994|  19.2k|}
_ZN6Assimp8Importer18SetPropertyIntegerEPKci:
 1063|    804|bool Importer::SetPropertyInteger(const char* szName, int iValue) {
 1064|    804|    ai_assert(nullptr != pimpl);
 1065|       |
 1066|    804|    bool existing;
 1067|    804|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1068|    804|        existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
 1069|    804|    ASSIMP_END_EXCEPTION_REGION(bool);
 1070|    804|    return existing;
 1071|    804|}
_ZN6Assimp8Importer16SetPropertyFloatEPKcf:
 1075|    337|bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
 1076|    337|    ai_assert(nullptr != pimpl);
 1077|       |
 1078|    337|    bool existing;
 1079|    337|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1080|    337|        existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
 1081|    337|    ASSIMP_END_EXCEPTION_REGION(bool);
 1082|    337|    return existing;
 1083|    337|}
_ZN6Assimp8Importer17SetPropertyStringEPKcRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
 1087|    402|bool Importer::SetPropertyString(const char* szName, const std::string& value) {
 1088|    402|    ai_assert(nullptr != pimpl);
 1089|       |
 1090|    402|    bool existing;
 1091|    402|    ASSIMP_BEGIN_EXCEPTION_REGION();
 1092|    402|        existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
 1093|    402|    ASSIMP_END_EXCEPTION_REGION(bool);
 1094|    402|    return existing;
 1095|    402|}
_ZNK6Assimp8Importer18GetPropertyIntegerEPKci:
 1123|  10.3k|int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
 1124|  10.3k|    ai_assert(nullptr != pimpl);
 1125|       |
 1126|  10.3k|    return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
 1127|  10.3k|}
_ZNK6Assimp8Importer16GetPropertyFloatEPKcf:
 1131|    957|ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
 1132|    957|    ai_assert(nullptr != pimpl);
 1133|       |
 1134|    957|    return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
 1135|    957|}
_ZNK6Assimp8Importer17GetPropertyStringEPKcRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE:
 1139|    319|std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
 1140|    319|    ai_assert(nullptr != pimpl);
 1141|       |
 1142|    319|    return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 1143|    319|}

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

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

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

_ZN6Assimp33GetPostProcessingStepInstanceListERNSt3__16vectorIPNS_11BaseProcessENS0_9allocatorIS3_EEEE:
  147|    402|{
  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|    402|    out.reserve(31);
  154|    402|#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
  155|    402|    out.push_back( new MakeLeftHandedProcess());
  156|    402|#endif
  157|    402|#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS)
  158|    402|    out.push_back( new FlipUVsProcess());
  159|    402|#endif
  160|    402|#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
  161|    402|    out.push_back( new FlipWindingOrderProcess());
  162|    402|#endif
  163|    402|#if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS)
  164|    402|    out.push_back( new RemoveVCProcess());
  165|    402|#endif
  166|    402|#if (!defined ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS)
  167|    402|    out.push_back( new RemoveRedundantMatsProcess());
  168|    402|#endif
  169|    402|#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS)
  170|    402|    out.push_back( new EmbedTexturesProcess());
  171|    402|#endif
  172|    402|#if (!defined ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS)
  173|    402|    out.push_back( new FindInstancesProcess());
  174|    402|#endif
  175|    402|#if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
  176|    402|    out.push_back( new OptimizeGraphProcess());
  177|    402|#endif
  178|    402|#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS
  179|    402|    out.push_back( new ComputeUVMappingProcess());
  180|    402|#endif
  181|    402|#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
  182|    402|    out.push_back( new TextureTransformStep());
  183|    402|#endif
  184|    402|#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
  185|    402|    out.push_back( new ScaleProcess());
  186|    402|#endif
  187|    402|#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
  188|    402|    out.push_back( new ArmaturePopulate());
  189|    402|#endif
  190|    402|#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
  191|    402|    out.push_back( new PretransformVertices());
  192|    402|#endif
  193|    402|#if (!defined ASSIMP_BUILD_NO_TRIANGULATE_PROCESS)
  194|    402|    out.push_back( new TriangulateProcess());
  195|    402|#endif
  196|    402|#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|    402|    out.push_back( new FindDegeneratesProcess());
  201|    402|#endif
  202|    402|#if (!defined ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS)
  203|    402|    out.push_back( new SortByPTypeProcess());
  204|    402|#endif
  205|    402|#if (!defined ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS)
  206|    402|    out.push_back( new FindInvalidDataProcess());
  207|    402|#endif
  208|    402|#if (!defined ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS)
  209|    402|    out.push_back( new OptimizeMeshesProcess());
  210|    402|#endif
  211|    402|#if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
  212|    402|    out.push_back( new FixInfacingNormalsProcess());
  213|    402|#endif
  214|    402|#if (!defined ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS)
  215|    402|    out.push_back( new SplitByBoneCountProcess());
  216|    402|#endif
  217|    402|#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
  218|    402|    out.push_back( new SplitLargeMeshesProcess_Triangle());
  219|    402|#endif
  220|    402|#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
  221|    402|    out.push_back( new DropFaceNormalsProcess());
  222|    402|#endif
  223|    402|#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
  224|    402|    out.push_back( new GenFaceNormalsProcess());
  225|    402|#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|    402|    out.push_back( new ComputeSpatialSortProcess());
  232|       |    // .........................................................................
  233|       |
  234|    402|#if (!defined ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS)
  235|    402|    out.push_back( new GenVertexNormalsProcess());
  236|    402|#endif
  237|    402|#if (!defined ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS)
  238|    402|    out.push_back( new CalcTangentsProcess());
  239|    402|#endif
  240|    402|#if (!defined ASSIMP_BUILD_NO_JOINVERTICES_PROCESS)
  241|    402|    out.push_back( new JoinVerticesProcess());
  242|    402|#endif
  243|       |
  244|       |    // .........................................................................
  245|    402|    out.push_back( new DestroySpatialSortProcess());
  246|       |    // .........................................................................
  247|       |
  248|    402|#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
  249|    402|    out.push_back( new SplitLargeMeshesProcess_Vertex());
  250|    402|#endif
  251|    402|#if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS)
  252|    402|    out.push_back( new DeboneProcess());
  253|    402|#endif
  254|    402|#if (!defined ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS)
  255|    402|    out.push_back( new LimitBoneWeightsProcess());
  256|    402|#endif
  257|    402|#if (!defined ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
  258|    402|    out.push_back( new ImproveCacheLocalityProcess());
  259|    402|#endif
  260|    402|#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
  261|    402|    out.push_back(new GenBoundingBoxesProcess);
  262|    402|#endif
  263|    402|}

_ZN6Assimp17ScenePreprocessor12ProcessSceneEv:
   50|    319|void ScenePreprocessor::ProcessScene() {
   51|    319|    ai_assert(scene != nullptr);
  ------------------
  |  |   67|    319|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 319, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   52|       |
   53|       |    // Process all meshes
   54|    991|    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (54:30): [True: 672, False: 319]
  ------------------
   55|    672|        if (nullptr == scene->mMeshes[i]) {
  ------------------
  |  Branch (55:13): [True: 0, False: 672]
  ------------------
   56|      0|            continue;
   57|      0|        }
   58|    672|        ProcessMesh(scene->mMeshes[i]);
   59|    672|    }
   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|    524|    for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
  ------------------
  |  Branch (67:30): [True: 205, False: 319]
  ------------------
   68|    205|        if (nullptr == scene->mAnimations[i]) {
  ------------------
  |  Branch (68:13): [True: 0, False: 205]
  ------------------
   69|      0|            continue;
   70|      0|        }
   71|    205|        ProcessAnimation(scene->mAnimations[i]);
   72|    205|    }
   73|       |
   74|       |    // Generate a default material if none was specified
   75|    319|    if (!scene->mNumMaterials && scene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 169, False: 150]
  |  Branch (75:34): [True: 0, False: 169]
  ------------------
   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|    319|}
_ZN6Assimp17ScenePreprocessor11ProcessMeshEP6aiMesh:
  103|    672|void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
  104|       |    // If aiMesh::mNumUVComponents is *not* set assign the default value of 2
  105|  6.04k|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (105:30): [True: 5.37k, False: 672]
  ------------------
  106|  5.37k|        if (!mesh->mTextureCoords[i]) {
  ------------------
  |  Branch (106:13): [True: 4.74k, False: 635]
  ------------------
  107|  4.74k|            mesh->mNumUVComponents[i] = 0;
  108|  4.74k|            continue;
  109|  4.74k|        }
  110|       |
  111|    635|        if (!mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (111:13): [True: 0, False: 635]
  ------------------
  112|      0|            mesh->mNumUVComponents[i] = 2;
  113|      0|        }
  114|       |
  115|    635|        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|    635|        if (2 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (120:13): [True: 635, False: 0]
  ------------------
  121|   361k|            for (; p != end; ++p) {
  ------------------
  |  Branch (121:20): [True: 360k, False: 635]
  ------------------
  122|   360k|                p->z = 0.f;
  123|   360k|            }
  124|    635|        } 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|    635|    }
  141|       |
  142|       |    // If the information which primitive types are there in the
  143|       |    // mesh is currently not available, compute it.
  144|    672|    if (!mesh->mPrimitiveTypes) {
  ------------------
  |  Branch (144:9): [True: 0, False: 672]
  ------------------
  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|    672|    if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
  ------------------
  |  Branch (169:9): [True: 12, False: 660]
  |  Branch (169:28): [True: 12, False: 0]
  |  Branch (169:46): [True: 0, False: 12]
  ------------------
  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|    672|}
_ZN6Assimp17ScenePreprocessor16ProcessAnimationEP11aiAnimation:
  178|    205|void ScenePreprocessor::ProcessAnimation(aiAnimation *anim) {
  179|    205|    double first = 10e10, last = -10e10;
  180|  3.70k|    for (unsigned int i = 0; i < anim->mNumChannels; ++i) {
  ------------------
  |  Branch (180:30): [True: 3.49k, False: 205]
  ------------------
  181|  3.49k|        aiNodeAnim *channel = anim->mChannels[i];
  182|       |
  183|       |        //  If the exact duration of the animation is not given
  184|       |        //  compute it now.
  185|  3.49k|        if (anim->mDuration == -1.) {
  ------------------
  |  Branch (185:13): [True: 0, False: 3.49k]
  ------------------
  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.49k|        if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) {
  ------------------
  |  Branch (212:13): [True: 0, False: 3.49k]
  |  Branch (212:43): [True: 48, False: 3.44k]
  |  Branch (212:73): [True: 40, False: 3.40k]
  ------------------
  213|       |            // Find the node that belongs to this animation
  214|     88|            aiNode *node = scene->mRootNode->FindNode(channel->mNodeName);
  215|     88|            if (node) // ValidateDS will complain later if 'node' is nullptr
  ------------------
  |  Branch (215:17): [True: 63, False: 25]
  ------------------
  216|     63|            {
  217|       |                // Decompose the transformation matrix of the node
  218|     63|                aiVector3D scaling, position;
  219|     63|                aiQuaternion rotation;
  220|       |
  221|     63|                node->mTransformation.Decompose(scaling, rotation, position);
  222|       |
  223|       |                // No rotation keys? Generate a dummy track
  224|     63|                if (!channel->mNumRotationKeys) {
  ------------------
  |  Branch (224:21): [True: 0, False: 63]
  ------------------
  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|     63|                } else {
  239|     63|                    ai_assert(channel->mRotationKeys);
  ------------------
  |  |   67|     63|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 63, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  240|     63|                }
  241|       |
  242|       |                // No scaling keys? Generate a dummy track
  243|     63|                if (!channel->mNumScalingKeys) {
  ------------------
  |  Branch (243:21): [True: 30, False: 33]
  ------------------
  244|     30|                    if (channel->mScalingKeys) {
  ------------------
  |  Branch (244:25): [True: 30, False: 0]
  ------------------
  245|     30|                        delete[] channel->mScalingKeys;
  246|     30|                        channel->mScalingKeys = nullptr;
  247|     30|                    }
  248|     30|                    ai_assert(!channel->mScalingKeys);
  ------------------
  |  |   67|     30|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 30, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  249|     30|                    channel->mNumScalingKeys = 1;
  250|     30|                    channel->mScalingKeys = new aiVectorKey[1];
  251|     30|                    aiVectorKey &q = channel->mScalingKeys[0];
  252|       |
  253|     30|                    q.mTime = 0.;
  254|     30|                    q.mValue = scaling;
  255|       |
  256|     30|                    ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy scaling track has been generated");
  257|     33|                } else {
  258|     33|                    ai_assert(channel->mScalingKeys);
  ------------------
  |  |   67|     33|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 33, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  259|     33|                }
  260|       |
  261|       |                // No position keys? Generate a dummy track
  262|     63|                if (!channel->mNumPositionKeys) {
  ------------------
  |  Branch (262:21): [True: 33, False: 30]
  ------------------
  263|     33|                    if (channel->mPositionKeys) {
  ------------------
  |  Branch (263:25): [True: 33, False: 0]
  ------------------
  264|     33|                        delete[] channel->mPositionKeys;
  265|     33|                        channel->mPositionKeys = nullptr;
  266|     33|                    }
  267|     33|                    ai_assert(!channel->mPositionKeys);
  ------------------
  |  |   67|     33|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 33, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  268|     33|                    channel->mNumPositionKeys = 1;
  269|     33|                    channel->mPositionKeys = new aiVectorKey[1];
  270|     33|                    aiVectorKey &q = channel->mPositionKeys[0];
  271|       |
  272|     33|                    q.mTime = 0.;
  273|     33|                    q.mValue = position;
  274|       |
  275|     33|                    ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Dummy position track has been generated");
  276|     33|                } else {
  277|     30|                    ai_assert(channel->mPositionKeys);
  ------------------
  |  |   67|     30|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 30, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  278|     30|                }
  279|     63|            }
  280|     88|        }
  281|  3.49k|    }
  282|       |
  283|    205|    if (anim->mDuration == -1.) {
  ------------------
  |  Branch (283:9): [True: 0, False: 205]
  ------------------
  284|       |        ASSIMP_LOG_VERBOSE_DEBUG("ScenePreprocessor: Setting animation duration");
  285|      0|        anim->mDuration = last - std::min(first, 0.);
  286|      0|    }
  287|    205|}

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

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

_ZN6Assimp11SpatialSortC2Ev:
   69|  1.53k|        mPlaneNormal(PlaneInit),
   70|  1.53k|        mFinalized(false) {
   71|  1.53k|    mPlaneNormal.Normalize();
   72|  1.53k|}
_ZN6Assimp11SpatialSort4FillEPK10aiVector3tIfEjjb:
   77|    843|        bool pFinalize /*= true */) {
   78|    843|    mPositions.clear();
   79|    843|    mFinalized = false;
   80|    843|    Append(pPositions, pNumPositions, pElementOffset, pFinalize);
   81|    843|    mFinalized = pFinalize;
   82|    843|}
_ZNK6Assimp11SpatialSort17CalculateDistanceERK10aiVector3tIfE:
   85|  24.5M|ai_real SpatialSort::CalculateDistance(const aiVector3D &pPosition) const {
   86|  24.5M|    return (pPosition - mCentroid) * mPlaneNormal;
   87|  24.5M|}
_ZN6Assimp11SpatialSort8FinalizeEv:
   90|    843|void SpatialSort::Finalize() {
   91|    843|    const ai_real scale = 1.0f / mPositions.size();
   92|  24.3M|    for (unsigned int i = 0; i < mPositions.size(); i++) {
  ------------------
  |  Branch (92:30): [True: 24.3M, False: 843]
  ------------------
   93|  24.3M|        mCentroid += scale * mPositions[i].mPosition;
   94|  24.3M|    }
   95|  24.3M|    for (unsigned int i = 0; i < mPositions.size(); i++) {
  ------------------
  |  Branch (95:30): [True: 24.3M, False: 843]
  ------------------
   96|  24.3M|        mPositions[i].mDistance = CalculateDistance(mPositions[i].mPosition);
   97|  24.3M|    }
   98|    843|    std::sort(mPositions.begin(), mPositions.end());
   99|    843|    mFinalized = true;
  100|    843|}
_ZN6Assimp11SpatialSort6AppendEPK10aiVector3tIfEjjb:
  105|    843|        bool pFinalize /*= true */) {
  106|    843|    ai_assert(!mFinalized && "You cannot add positions to the SpatialSort object after it has been finalized.");
  ------------------
  |  |   67|  1.68k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:45): [True: 843, 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|    843|    const size_t initial = mPositions.size();
  109|    843|    mPositions.reserve(initial + pNumPositions);
  110|  24.3M|    for (unsigned int a = 0; a < pNumPositions; a++) {
  ------------------
  |  Branch (110:30): [True: 24.3M, False: 843]
  ------------------
  111|  24.3M|        const char *tempPointer = reinterpret_cast<const char *>(pPositions);
  112|  24.3M|        const aiVector3D *vec = reinterpret_cast<const aiVector3D *>(tempPointer + a * pElementOffset);
  113|  24.3M|        mPositions.emplace_back(static_cast<unsigned int>(a + initial), *vec);
  114|  24.3M|    }
  115|       |
  116|    843|    if (pFinalize) {
  ------------------
  |  Branch (116:9): [True: 843, False: 0]
  ------------------
  117|       |        // now sort the array ascending by distance.
  118|    843|        Finalize();
  119|    843|    }
  120|    843|}
_ZNK6Assimp11SpatialSort13FindPositionsERK10aiVector3tIfEfRNSt3__16vectorIjNS5_9allocatorIjEEEE:
  125|   184k|        ai_real pRadius, std::vector<unsigned int> &poResults) const {
  126|   184k|    ai_assert(mFinalized && "The SpatialSort object must be finalized before FindPositions can be called.");
  ------------------
  |  |   67|   369k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:45): [True: 184k, False: 0]
  |  |  |  Branch (67:45): [True: 0, Folded]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  127|   184k|    const ai_real dist = CalculateDistance(pPosition);
  128|   184k|    const ai_real minDist = dist - pRadius, maxDist = dist + pRadius;
  129|       |
  130|       |    // clear the array
  131|   184k|    poResults.clear();
  132|       |
  133|       |    // quick check for positions outside the range
  134|   184k|    if (mPositions.size() == 0)
  ------------------
  |  Branch (134:9): [True: 0, False: 184k]
  ------------------
  135|      0|        return;
  136|   184k|    if (maxDist < mPositions.front().mDistance)
  ------------------
  |  Branch (136:9): [True: 0, False: 184k]
  ------------------
  137|      0|        return;
  138|   184k|    if (minDist > mPositions.back().mDistance)
  ------------------
  |  Branch (138:9): [True: 0, False: 184k]
  ------------------
  139|      0|        return;
  140|       |
  141|       |    // do a binary search for the minimal distance to start the iteration there
  142|   184k|    unsigned int index = (unsigned int)mPositions.size() / 2;
  143|   184k|    unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4;
  144|  1.85M|    while (binaryStepSize > 1) {
  ------------------
  |  Branch (144:12): [True: 1.66M, False: 184k]
  ------------------
  145|  1.66M|        if (mPositions[index].mDistance < minDist)
  ------------------
  |  Branch (145:13): [True: 835k, False: 832k]
  ------------------
  146|   835k|            index += binaryStepSize;
  147|   832k|        else
  148|   832k|            index -= binaryStepSize;
  149|       |
  150|  1.66M|        binaryStepSize /= 2;
  151|  1.66M|    }
  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|   368k|    while (index > 0 && mPositions[index].mDistance > minDist)
  ------------------
  |  Branch (155:12): [True: 366k, False: 2.20k]
  |  Branch (155:25): [True: 184k, False: 182k]
  ------------------
  156|   184k|        index--;
  157|   391k|    while (index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist)
  ------------------
  |  Branch (157:12): [True: 391k, False: 0]
  |  Branch (157:47): [True: 206k, False: 184k]
  ------------------
  158|   206k|        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|   184k|    std::vector<Entry>::const_iterator it = mPositions.begin() + index;
  163|   184k|    const ai_real pSquared = pRadius * pRadius;
  164|  25.0M|    while (it->mDistance < maxDist) {
  ------------------
  |  Branch (164:12): [True: 24.8M, False: 183k]
  ------------------
  165|  24.8M|        if ((it->mPosition - pPosition).SquareLength() < pSquared)
  ------------------
  |  Branch (165:13): [True: 24.7M, False: 154k]
  ------------------
  166|  24.7M|            poResults.push_back(it->mIndex);
  167|  24.8M|        ++it;
  168|  24.8M|        if (it == mPositions.end())
  ------------------
  |  Branch (168:13): [True: 1.56k, False: 24.8M]
  ------------------
  169|  1.56k|            break;
  170|  24.8M|    }
  171|       |
  172|       |    // that's it
  173|   184k|}

_ZN6Assimp14StackAllocator8AllocateEm:
   54|  7.56M|inline void *StackAllocator::Allocate(size_t byteSize) {
   55|  7.56M|    if (m_subIndex + byteSize > m_blockAllocationSize) // start a new block
  ------------------
  |  Branch (55:9): [True: 1.74k, False: 7.55M]
  ------------------
   56|  1.74k|    {
   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.74k|        m_blockAllocationSize = std::max<std::size_t>(std::min<std::size_t>(m_blockAllocationSize * 2, g_maxBytesPerBlock), byteSize);
   60|  1.74k|        uint8_t *data = new uint8_t[m_blockAllocationSize];
   61|  1.74k|        m_storageBlocks.emplace_back(data);
   62|  1.74k|        m_subIndex = byteSize;
   63|  1.74k|        return data;
   64|  1.74k|    }
   65|       |
   66|  7.55M|    uint8_t *data = m_storageBlocks.back();
   67|  7.55M|    data += m_subIndex;
   68|  7.55M|    m_subIndex += byteSize;
   69|       |
   70|  7.55M|    return data;
   71|  7.56M|}
_ZN6Assimp14StackAllocator7FreeAllEv:
   73|    402|inline void StackAllocator::FreeAll() {
   74|  2.15k|    for (size_t i = 0; i < m_storageBlocks.size(); i++) {
  ------------------
  |  Branch (74:24): [True: 1.74k, False: 402]
  ------------------
   75|  1.74k|        delete [] m_storageBlocks[i];
   76|  1.74k|    }
   77|    402|    std::vector<uint8_t *> empty;
   78|    402|    m_storageBlocks.swap(empty);
   79|       |    // start over:
   80|    402|    m_blockAllocationSize = g_startBytesPerBlock;
   81|    402|    m_subIndex = g_maxBytesPerBlock;
   82|    402|}
_ZN6Assimp14StackAllocatorC2Ev:
   48|    402|inline StackAllocator::StackAllocator() : m_storageBlocks() {}
_ZN6Assimp14StackAllocatorD2Ev:
   50|    402|inline StackAllocator::~StackAllocator() {
   51|    402|    FreeAll();
   52|    402|}

aiGetVersionMinor:
   72|    402|ASSIMP_API unsigned int aiGetVersionMinor() {
   73|    402|    return VER_MINOR;
  ------------------
  |  |    8|    402|#define VER_MINOR 0
  ------------------
   74|    402|}
aiGetVersionMajor:
   78|    402|ASSIMP_API unsigned int aiGetVersionMajor() {
   79|    402|    return VER_MAJOR;
  ------------------
  |  |    7|    402|#define VER_MAJOR 6
  ------------------
   80|    402|}
aiGetCompileFlags:
   84|    402|ASSIMP_API unsigned int aiGetCompileFlags() {
   85|       |
   86|    402|    unsigned int flags = 0;
   87|       |
   88|       |#ifdef ASSIMP_BUILD_BOOST_WORKAROUND
   89|       |    flags |= ASSIMP_CFLAGS_NOBOOST;
   90|       |#endif
   91|    402|#ifdef ASSIMP_BUILD_SINGLETHREADED
   92|    402|    flags |= ASSIMP_CFLAGS_SINGLETHREADED;
  ------------------
  |  |  107|    402|#define ASSIMP_CFLAGS_SINGLETHREADED    0x10
  ------------------
   93|    402|#endif
   94|    402|#ifdef ASSIMP_BUILD_DEBUG
   95|    402|    flags |= ASSIMP_CFLAGS_DEBUG;
  ------------------
  |  |  102|    402|#define ASSIMP_CFLAGS_DEBUG   0x4
  ------------------
   96|    402|#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|    402|    return flags;
  108|    402|}
aiGetVersionRevision:
  111|    402|ASSIMP_API unsigned int aiGetVersionRevision() {
  112|    402|    return GitVersion;
  ------------------
  |  |    4|    402|#define GitVersion 0x8ff00557
  ------------------
  113|    402|}

_ZN6Assimp23VertexTriangleAdjacencyC2EP6aiFacejjb:
   55|    671|        bool bComputeNumTriangles /*= false*/) {
   56|       |    // compute the number of referenced vertices if it wasn't specified by the caller
   57|    671|    const aiFace *const pcFaceEnd = pcFaces + iNumFaces;
   58|    671|    if (0 == iNumVertices) {
  ------------------
  |  Branch (58:9): [True: 0, False: 671]
  ------------------
   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|    671|    mNumVertices = iNumVertices + 1;
   69|       |
   70|    671|    unsigned int *pi;
   71|       |
   72|       |    // allocate storage
   73|    671|    if (bComputeNumTriangles) {
  ------------------
  |  Branch (73:9): [True: 671, False: 0]
  ------------------
   74|    671|        pi = mLiveTriangles = new unsigned int[iNumVertices + 1];
   75|    671|        ::memset(mLiveTriangles, 0, sizeof(unsigned int) * (iNumVertices + 1));
   76|    671|        mOffsetTable = new unsigned int[iNumVertices + 2] + 1;
   77|    671|    } 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|    671|    unsigned int *piEnd = pi + iNumVertices;
   85|    671|    *piEnd++ = 0u;
   86|       |
   87|       |    // first pass: compute the number of faces referencing each vertex
   88|   180k|    for (aiFace *pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
  ------------------
  |  Branch (88:36): [True: 179k, False: 671]
  ------------------
   89|   179k|        unsigned nind = pcFace->mNumIndices;
   90|   179k|        unsigned *ind = pcFace->mIndices;
   91|   179k|        if (nind > 0) pi[ind[0]]++;
  ------------------
  |  Branch (91:13): [True: 179k, False: 0]
  ------------------
   92|   179k|        if (nind > 1) pi[ind[1]]++;
  ------------------
  |  Branch (92:13): [True: 179k, False: 0]
  ------------------
   93|   179k|        if (nind > 2) pi[ind[2]]++;
  ------------------
  |  Branch (93:13): [True: 179k, False: 0]
  ------------------
   94|   179k|    }
   95|       |
   96|       |    // second pass: compute the final offset table
   97|    671|    unsigned int iSum = 0;
   98|    671|    unsigned int *piCurOut = this->mOffsetTable;
   99|   165k|    for (unsigned int *piCur = pi; piCur != piEnd; ++piCur, ++piCurOut) {
  ------------------
  |  Branch (99:36): [True: 164k, False: 671]
  ------------------
  100|       |
  101|   164k|        unsigned int iLastSum = iSum;
  102|   164k|        iSum += *piCur;
  103|   164k|        *piCurOut = iLastSum;
  104|   164k|    }
  105|    671|    pi = this->mOffsetTable;
  106|       |
  107|       |    // third pass: compute the final table
  108|    671|    this->mAdjacencyTable = new unsigned int[iSum];
  109|    671|    iSum = 0;
  110|   180k|    for (aiFace *pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace, ++iSum) {
  ------------------
  |  Branch (110:36): [True: 179k, False: 671]
  ------------------
  111|   179k|        unsigned nind = pcFace->mNumIndices;
  112|   179k|        unsigned *ind = pcFace->mIndices;
  113|       |
  114|   179k|        if (nind > 0) mAdjacencyTable[pi[ind[0]]++] = iSum;
  ------------------
  |  Branch (114:13): [True: 179k, False: 0]
  ------------------
  115|   179k|        if (nind > 1) mAdjacencyTable[pi[ind[1]]++] = iSum;
  ------------------
  |  Branch (115:13): [True: 179k, False: 0]
  ------------------
  116|   179k|        if (nind > 2) mAdjacencyTable[pi[ind[2]]++] = iSum;
  ------------------
  |  Branch (116:13): [True: 179k, False: 0]
  ------------------
  117|   179k|    }
  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|    671|    --mOffsetTable;
  121|    671|    *mOffsetTable = 0u;
  122|    671|}
_ZN6Assimp23VertexTriangleAdjacencyD2Ev:
  124|    671|VertexTriangleAdjacency::~VertexTriangleAdjacency() {
  125|       |    // delete allocated storage
  126|    671|    delete[] mOffsetTable;
  127|    671|    delete[] mAdjacencyTable;
  128|    671|    delete[] mLiveTriangles;
  129|    671|}

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

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

_ZN7aiSceneC2Ev:
   46|    402|        mFlags(0),
   47|    402|        mRootNode(nullptr),
   48|    402|        mNumMeshes(0),
   49|    402|        mMeshes(nullptr),
   50|    402|        mNumMaterials(0),
   51|    402|        mMaterials(nullptr),
   52|    402|        mNumAnimations(0),
   53|    402|        mAnimations(nullptr),
   54|    402|        mNumTextures(0),
   55|    402|        mTextures(nullptr),
   56|    402|        mNumLights(0),
   57|    402|        mLights(nullptr),
   58|    402|        mNumCameras(0),
   59|    402|        mCameras(nullptr),
   60|    402|        mMetaData(nullptr),
   61|    402|        mName(),
   62|    402|        mNumSkeletons(0),
   63|    402|        mSkeletons(nullptr),
   64|    402|        mPrivate(new Assimp::ScenePrivateData()) {
   65|       |    // empty
   66|    402|}
_ZN7aiSceneD2Ev:
   68|    402|aiScene::~aiScene() {
   69|       |    // delete all sub-objects recursively
   70|    402|    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|    402|    if (mNumMeshes && mMeshes) {
  ------------------
  |  Branch (75:9): [True: 159, False: 243]
  |  Branch (75:23): [True: 159, False: 0]
  ------------------
   76|  1.09k|        for (unsigned int a = 0; a < mNumMeshes; ++a) {
  ------------------
  |  Branch (76:34): [True: 936, False: 159]
  ------------------
   77|    936|            delete mMeshes[a];
   78|    936|        }
   79|    159|    }
   80|    402|    delete[] mMeshes;
   81|       |
   82|    402|    if (mNumMaterials && mMaterials) {
  ------------------
  |  Branch (82:9): [True: 159, False: 243]
  |  Branch (82:26): [True: 159, False: 0]
  ------------------
   83|    495|        for (unsigned int a = 0; a < mNumMaterials; ++a) {
  ------------------
  |  Branch (83:34): [True: 336, False: 159]
  ------------------
   84|    336|            delete mMaterials[a];
   85|    336|        }
   86|    159|    }
   87|    402|    delete[] mMaterials;
   88|       |
   89|    402|    if (mNumAnimations && mAnimations) {
  ------------------
  |  Branch (89:9): [True: 215, False: 187]
  |  Branch (89:27): [True: 215, False: 0]
  ------------------
   90|    430|        for (unsigned int a = 0; a < mNumAnimations; ++a) {
  ------------------
  |  Branch (90:34): [True: 215, False: 215]
  ------------------
   91|    215|            delete mAnimations[a];
   92|    215|        }
   93|    215|    }
   94|    402|    delete[] mAnimations;
   95|       |
   96|    402|    if (mNumTextures && mTextures) {
  ------------------
  |  Branch (96:9): [True: 6, False: 396]
  |  Branch (96:25): [True: 6, False: 0]
  ------------------
   97|     12|        for (unsigned int a = 0; a < mNumTextures; ++a) {
  ------------------
  |  Branch (97:34): [True: 6, False: 6]
  ------------------
   98|      6|            delete mTextures[a];
   99|      6|        }
  100|      6|    }
  101|    402|    delete[] mTextures;
  102|       |
  103|    402|    if (mNumLights && mLights) {
  ------------------
  |  Branch (103:9): [True: 272, False: 130]
  |  Branch (103:23): [True: 272, False: 0]
  ------------------
  104|    544|        for (unsigned int a = 0; a < mNumLights; ++a) {
  ------------------
  |  Branch (104:34): [True: 272, False: 272]
  ------------------
  105|    272|            delete mLights[a];
  106|    272|        }
  107|    272|    }
  108|    402|    delete[] mLights;
  109|       |
  110|    402|    if (mNumCameras && mCameras) {
  ------------------
  |  Branch (110:9): [True: 286, False: 116]
  |  Branch (110:24): [True: 286, False: 0]
  ------------------
  111|    572|        for (unsigned int a = 0; a < mNumCameras; ++a) {
  ------------------
  |  Branch (111:34): [True: 286, False: 286]
  ------------------
  112|    286|            delete mCameras[a];
  113|    286|        }
  114|    286|    }
  115|    402|    delete[] mCameras;
  116|       |
  117|    402|    aiMetadata::Dealloc(mMetaData);
  118|       |
  119|    402|    delete[] mSkeletons;
  120|       |
  121|    402|    delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
  122|    402|}
_ZN6aiNodeC2Ev:
  125|  6.72k|        mName(""),
  126|  6.72k|        mParent(nullptr),
  127|  6.72k|        mNumChildren(0),
  128|  6.72k|        mChildren(nullptr),
  129|  6.72k|        mNumMeshes(0),
  130|  6.72k|        mMeshes(nullptr),
  131|  6.72k|        mMetaData(nullptr) {
  132|       |    // empty
  133|  6.72k|}
_ZN6aiNodeC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  136|    416|        mName(name),
  137|    416|        mParent(nullptr),
  138|    416|        mNumChildren(0),
  139|    416|        mChildren(nullptr),
  140|    416|        mNumMeshes(0),
  141|    416|        mMeshes(nullptr),
  142|    416|        mMetaData(nullptr) {
  143|       |    // empty
  144|    416|}
_ZN6aiNodeD2Ev:
  147|  7.14k|aiNode::~aiNode() {
  148|       |    // delete all children recursively
  149|       |    // to make sure we won't crash if the data is invalid ...
  150|  7.14k|    if (mNumChildren && mChildren) {
  ------------------
  |  Branch (150:9): [True: 4.33k, False: 2.80k]
  |  Branch (150:25): [True: 4.33k, False: 0]
  ------------------
  151|  10.9k|        for (unsigned int a = 0; a < mNumChildren; a++)
  ------------------
  |  Branch (151:34): [True: 6.63k, False: 4.33k]
  ------------------
  152|  6.63k|            delete mChildren[a];
  153|  4.33k|    }
  154|  7.14k|    delete[] mChildren;
  155|  7.14k|    delete[] mMeshes;
  156|  7.14k|    delete mMetaData;
  157|  7.14k|}
_ZN6aiNode8FindNodeEPKc:
  176|  4.24k|aiNode *aiNode::FindNode(const char *name) {
  177|  4.24k|    if (!::strcmp(mName.data, name)) return this;
  ------------------
  |  Branch (177:9): [True: 63, False: 4.17k]
  ------------------
  178|  7.15k|    for (unsigned int i = 0; i < mNumChildren; ++i) {
  ------------------
  |  Branch (178:30): [True: 4.15k, False: 3.00k]
  ------------------
  179|  4.15k|        aiNode *const p = mChildren[i]->FindNode(name);
  180|  4.15k|        if (p) {
  ------------------
  |  Branch (180:13): [True: 1.17k, False: 2.97k]
  ------------------
  181|  1.17k|            return p;
  182|  1.17k|        }
  183|  4.15k|    }
  184|       |    // there is definitely no sub-node with this name
  185|  3.00k|    return nullptr;
  186|  4.17k|}

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

aiGetMaterialProperty:
   63|  1.45k|        const aiMaterialProperty **pPropOut) {
   64|  1.45k|    ai_assert(pMat != nullptr);
   65|  1.45k|    ai_assert(pKey != nullptr);
   66|  1.45k|    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|  15.3k|    for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
  ------------------
  |  Branch (72:30): [True: 14.9k, False: 387]
  ------------------
   73|  14.9k|        aiMaterialProperty *prop = pMat->mProperties[i];
   74|       |
   75|  14.9k|        if (prop /* just for safety ... */
  ------------------
  |  Branch (75:13): [True: 14.9k, False: 0]
  ------------------
   76|  14.9k|                && 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: 1.06k, False: 13.9k]
  |  Branch (76:74): [True: 0, False: 1.06k]
  |  Branch (76:94): [True: 1.06k, False: 0]
  ------------------
   77|  1.06k|                && (UINT_MAX == index || prop->mIndex == index)) {
  ------------------
  |  Branch (77:21): [True: 0, False: 1.06k]
  |  Branch (77:42): [True: 1.06k, False: 0]
  ------------------
   78|  1.06k|            *pPropOut = pMat->mProperties[i];
   79|  1.06k|            return AI_SUCCESS;
   80|  1.06k|        }
   81|  14.9k|    }
   82|    387|    *pPropOut = nullptr;
   83|       |
   84|       |    return AI_FAILURE;
   85|  1.45k|}
aiGetMaterialFloatArray:
  194|    840|        unsigned int *pMax) {
  195|    840|    return GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
  196|    840|}
aiGetMaterialIntegerArray:
  205|    615|        unsigned int *pMax) {
  206|    615|    ai_assert(pOut != nullptr);
  207|    615|    ai_assert(pMat != nullptr);
  208|       |
  209|    615|    const aiMaterialProperty *prop;
  210|    615|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  211|    615|    if (!prop) {
  ------------------
  |  Branch (211:9): [True: 344, False: 271]
  ------------------
  212|    344|        return AI_FAILURE;
  213|    344|    }
  214|       |
  215|       |    // data is given in ints, simply copy it
  216|    271|    unsigned int iWrite = 0;
  217|    271|    if (aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) {
  ------------------
  |  Branch (217:9): [True: 2, False: 269]
  |  Branch (217:41): [True: 269, False: 0]
  ------------------
  218|    271|        iWrite = std::max(static_cast<unsigned int>(prop->mDataLength / sizeof(int32_t)), 1u);
  219|    271|        if (pMax) {
  ------------------
  |  Branch (219:13): [True: 0, False: 271]
  ------------------
  220|      0|            iWrite = std::min(*pMax, iWrite);
  221|      0|        }
  222|    271|        if (1 == prop->mDataLength) {
  ------------------
  |  Branch (222:13): [True: 0, False: 271]
  ------------------
  223|       |            // bool type, 1 byte
  224|      0|            *pOut = static_cast<int>(*prop->mData);
  225|    271|        } else {
  226|    542|            for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (226:38): [True: 271, False: 271]
  ------------------
  227|    271|                pOut[a] = static_cast<int>(reinterpret_cast<int32_t *>(prop->mData)[a]);
  228|    271|            }
  229|    271|        }
  230|    271|        if (pMax) {
  ------------------
  |  Branch (230:13): [True: 0, False: 271]
  ------------------
  231|      0|            *pMax = iWrite;
  232|      0|        }
  233|    271|    }
  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|    271|    return AI_SUCCESS;
  274|    271|}
_ZN10aiMaterialC2Ev:
  418|    344|aiMaterial::aiMaterial() : mProperties(nullptr), mNumProperties(0), mNumAllocated(DefaultNumAllocated) {
  419|       |    // Allocate 5 entries by default
  420|    344|    mProperties = new aiMaterialProperty *[DefaultNumAllocated];
  421|    344|}
_ZN10aiMaterialD2Ev:
  424|    336|aiMaterial::~aiMaterial() {
  425|    336|    Clear();
  426|       |
  427|    336|    delete[] mProperties;
  428|    336|}
_ZN10aiMaterial5ClearEv:
  439|    336|void aiMaterial::Clear() {
  440|  7.07k|    for (unsigned int i = 0; i < mNumProperties; ++i) {
  ------------------
  |  Branch (440:30): [True: 6.74k, False: 336]
  ------------------
  441|       |        // delete this entry
  442|  6.74k|        delete mProperties[i];
  443|  6.74k|        AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
  444|  6.74k|    }
  445|    336|    mNumProperties = 0;
  446|       |
  447|       |    // The array remains allocated, we just invalidated its contents
  448|    336|}
_ZN10aiMaterial17AddBinaryPropertyEPKvjPKcjj18aiPropertyTypeInfo:
  480|  6.89k|        aiPropertyTypeInfo pType) {
  481|  6.89k|    ai_assert(pInput != nullptr);
  482|  6.89k|    ai_assert(pKey != nullptr);
  483|  6.89k|    ai_assert(0 != pSizeInBytes);
  484|       |
  485|  6.89k|    if (0 == pSizeInBytes) {
  ------------------
  |  Branch (485:9): [True: 0, False: 6.89k]
  ------------------
  486|      0|        return AI_FAILURE;
  487|      0|    }
  488|       |
  489|       |    // first search the list whether there is already an entry with this key
  490|  6.89k|    unsigned int iOutIndex(UINT_MAX);
  491|  81.3k|    for (unsigned int i = 0; i < mNumProperties; ++i) {
  ------------------
  |  Branch (491:30): [True: 74.5k, False: 6.89k]
  ------------------
  492|  74.5k|        aiMaterialProperty *prop(mProperties[i]);
  493|       |
  494|  74.5k|        if (prop /* just for safety */ && !strcmp(prop->mKey.data, pKey) &&
  ------------------
  |  Branch (494:13): [True: 74.5k, False: 0]
  |  Branch (494:43): [True: 60, False: 74.4k]
  ------------------
  495|     60|                prop->mSemantic == type && prop->mIndex == index) {
  ------------------
  |  Branch (495:17): [True: 0, False: 60]
  |  Branch (495:44): [True: 0, False: 0]
  ------------------
  496|       |
  497|      0|            delete mProperties[i];
  498|      0|            iOutIndex = i;
  499|      0|        }
  500|  74.5k|    }
  501|       |
  502|       |    // Allocate a new material property
  503|  6.89k|    auto pcNew = std::make_unique<aiMaterialProperty>();
  504|       |
  505|       |    // .. and fill it
  506|  6.89k|    pcNew->mType = pType;
  507|  6.89k|    pcNew->mSemantic = type;
  508|  6.89k|    pcNew->mIndex = index;
  509|       |
  510|  6.89k|    pcNew->mDataLength = pSizeInBytes;
  511|  6.89k|    pcNew->mData = new char[pSizeInBytes];
  512|  6.89k|    memcpy(pcNew->mData, pInput, pSizeInBytes);
  513|       |
  514|  6.89k|    pcNew->mKey.length = static_cast<ai_uint32>(::strlen(pKey));
  515|  6.89k|    ai_assert(AI_MAXLEN > pcNew->mKey.length);
  516|  6.89k|    strcpy(pcNew->mKey.data, pKey);
  517|       |
  518|  6.89k|    if (UINT_MAX != iOutIndex) {
  ------------------
  |  Branch (518:9): [True: 0, False: 6.89k]
  ------------------
  519|      0|        mProperties[iOutIndex] = pcNew.release();
  520|      0|        return AI_SUCCESS;
  521|      0|    }
  522|       |
  523|       |    // resize the array ... double the storage allocated
  524|  6.89k|    if (mNumProperties == mNumAllocated) {
  ------------------
  |  Branch (524:9): [True: 845, False: 6.04k]
  ------------------
  525|    845|        const unsigned int iOld = mNumAllocated;
  526|    845|        mNumAllocated *= 2;
  527|       |
  528|    845|        aiMaterialProperty **ppTemp;
  529|    845|        try {
  530|    845|            ppTemp = new aiMaterialProperty *[mNumAllocated];
  531|    845|        } catch (std::bad_alloc &) {
  532|      0|            return AI_OUTOFMEMORY;
  533|      0|        }
  534|       |
  535|       |        // just copy all items over; then replace the old array
  536|    845|        memcpy(ppTemp, mProperties, iOld * sizeof(void *));
  537|       |
  538|    845|        delete[] mProperties;
  539|    845|        mProperties = ppTemp;
  540|    845|    }
  541|       |    // push back ...
  542|  6.89k|    mProperties[mNumProperties++] = pcNew.release();
  543|       |
  544|       |    return AI_SUCCESS;
  545|  6.89k|}
_ZN10aiMaterial11AddPropertyEPK8aiStringPKcjj:
  551|    855|        unsigned int index) {
  552|       |    ai_assert(sizeof(ai_uint32) == 4);
  553|    855|    return AddBinaryProperty(pInput,
  554|    855|            static_cast<unsigned int>(pInput->length + 1 + 4),
  555|    855|            pKey,
  556|    855|            type,
  557|    855|            index,
  558|    855|            aiPTI_String);
  559|    855|}
_ZN6Assimp19ComputeMaterialHashEPK10aiMaterialb:
  562|    302|uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName /*= false*/) {
  563|    302|    uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
  564|  6.35k|    for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
  ------------------
  |  Branch (564:30): [True: 6.05k, False: 302]
  ------------------
  565|       |        // Exclude all properties whose first character is '?' from the hash
  566|       |        // See doc for aiMaterialProperty.
  567|  6.05k|        const aiMaterialProperty *prop = mat->mProperties[i];
  568|  6.05k|        if (nullptr != prop && (includeMatName || prop->mKey.data[0] != '?')) {
  ------------------
  |  Branch (568:13): [True: 6.05k, False: 0]
  |  Branch (568:33): [True: 0, False: 6.05k]
  |  Branch (568:51): [True: 5.74k, False: 302]
  ------------------
  569|       |
  570|  5.74k|            hash = SuperFastHash(prop->mKey.data, (unsigned int)prop->mKey.length, hash);
  571|  5.74k|            hash = SuperFastHash(prop->mData, prop->mDataLength, hash);
  572|       |
  573|       |            // Combine the semantic and the index with the hash
  574|  5.74k|            hash = SuperFastHash((const char *)&prop->mSemantic, sizeof(unsigned int), hash);
  575|  5.74k|            hash = SuperFastHash((const char *)&prop->mIndex, sizeof(unsigned int), hash);
  576|  5.74k|        }
  577|  6.05k|    }
  578|    302|    return hash;
  579|    302|}
MaterialSystem.cpp:_ZN12_GLOBAL__N_121GetMaterialFloatArrayIfEE8aiReturnPK10aiMaterialPKcjjPT_Pj:
   97|    840|        unsigned int *pMax) {
   98|    840|    ai_assert(pOut != nullptr);
   99|    840|    ai_assert(pMat != nullptr);
  100|       |
  101|    840|    const aiMaterialProperty *prop{nullptr};
  102|    840|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  103|    840|    if (nullptr == prop) {
  ------------------
  |  Branch (103:9): [True: 43, False: 797]
  ------------------
  104|     43|        return AI_FAILURE;
  105|     43|    }
  106|       |
  107|       |    // data is given in floats, convert to TReal
  108|    797|    unsigned int iWrite = 0;
  109|    797|    if (aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) {
  ------------------
  |  Branch (109:9): [True: 797, False: 0]
  |  Branch (109:39): [True: 0, False: 0]
  ------------------
  110|    797|        iWrite = prop->mDataLength / sizeof(float);
  111|    797|        if (pMax) {
  ------------------
  |  Branch (111:13): [True: 0, False: 797]
  ------------------
  112|      0|            iWrite = std::min(*pMax, iWrite);
  113|      0|        }
  114|       |
  115|  1.59k|        for (unsigned int a = 0; a < iWrite; ++a) {
  ------------------
  |  Branch (115:34): [True: 797, False: 797]
  ------------------
  116|    797|            pOut[a] = static_cast<TReal>(reinterpret_cast<float *>(prop->mData)[a]);
  117|    797|        }
  118|       |
  119|    797|        if (pMax) {
  ------------------
  |  Branch (119:13): [True: 0, False: 797]
  ------------------
  120|      0|            *pMax = iWrite;
  121|      0|        }
  122|    797|    } 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|    797|    return AI_SUCCESS;
  172|    797|}

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

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

_ZN6Assimp19CalcTangentsProcessC2Ev:
   59|    402|        configMaxAngle(float(AI_DEG_TO_RAD(45.f))), configSourceUV(0) {
   60|       |    // nothing to do here
   61|    402|}
_ZNK6Assimp19CalcTangentsProcess8IsActiveEj:
   65|    319|bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
   66|    319|    return (pFlags & aiProcess_CalcTangentSpace) != 0;
   67|    319|}
_ZN6Assimp19CalcTangentsProcess15SetupPropertiesEPKNS_8ImporterE:
   71|    319|void CalcTangentsProcess::SetupProperties(const Importer *pImp) {
   72|    319|    ai_assert(nullptr != pImp);
   73|       |
   74|       |    // get the current value of the property
   75|    319|    configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 45.f);
   76|    319|    configMaxAngle = std::max(std::min(configMaxAngle, 45.0f), 0.0f);
   77|    319|    configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
   78|       |
   79|       |    configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX, 0);
   80|    319|}
_ZN6Assimp19CalcTangentsProcess7ExecuteEP7aiScene:
   84|    319|void CalcTangentsProcess::Execute(aiScene *pScene) {
   85|    319|    ai_assert(nullptr != pScene);
   86|       |
   87|    319|    ASSIMP_LOG_DEBUG("CalcTangentsProcess begin");
   88|       |
   89|    319|    bool bHas = false;
   90|  1.16k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (90:30): [True: 843, False: 319]
  ------------------
   91|    843|        if (ProcessMesh(pScene->mMeshes[a], a)) bHas = true;
  ------------------
  |  Branch (91:13): [True: 624, False: 219]
  ------------------
   92|    843|    }
   93|       |
   94|    319|    if (bHas) {
  ------------------
  |  Branch (94:9): [True: 131, False: 188]
  ------------------
   95|    131|        ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated");
   96|    188|    } else {
   97|       |        ASSIMP_LOG_DEBUG("CalcTangentsProcess finished");
   98|    188|    }
   99|    319|}
_ZN6Assimp19CalcTangentsProcess11ProcessMeshEP6aiMeshj:
  103|    843|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|    843|    if (pMesh->mTangents) // this implies that mBitangents is also there
  ------------------
  |  Branch (109:9): [True: 12, False: 831]
  ------------------
  110|     12|        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|    831|    if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
  ------------------
  |  Branch (115:9): [True: 171, False: 660]
  ------------------
  116|    171|        ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes");
  117|    171|        return false;
  118|    171|    }
  119|       |
  120|       |    // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
  121|    660|    if (pMesh->mNormals == nullptr) {
  ------------------
  |  Branch (121:9): [True: 0, False: 660]
  ------------------
  122|      0|        ASSIMP_LOG_ERROR("Failed to compute tangents; need normals");
  123|      0|        return false;
  124|      0|    }
  125|    660|    if (configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV]) {
  ------------------
  |  Branch (125:9): [True: 0, False: 660]
  |  Branch (125:61): [True: 36, False: 624]
  ------------------
  126|     36|        ASSIMP_LOG_ERROR("Failed to compute tangents; need UV data in channel", configSourceUV);
  127|     36|        return false;
  128|     36|    }
  129|       |
  130|    624|    const float angleEpsilon = 0.9999f;
  131|       |
  132|    624|    std::vector<bool> vertexDone(pMesh->mNumVertices, false);
  133|    624|    const float qnan = get_qnan();
  134|       |
  135|       |    // create space for the tangents and bitangents
  136|    624|    pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  137|    624|    pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  138|       |
  139|    624|    const aiVector3D *meshPos = pMesh->mVertices;
  140|    624|    const aiVector3D *meshNorm = pMesh->mNormals;
  141|    624|    const aiVector3D *meshTex = pMesh->mTextureCoords[configSourceUV];
  142|    624|    aiVector3D *meshTang = pMesh->mTangents;
  143|    624|    aiVector3D *meshBitang = pMesh->mBitangents;
  144|       |
  145|       |    // calculate the tangent and bitangent for every face
  146|   159k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (146:30): [True: 158k, False: 624]
  ------------------
  147|   158k|        const aiFace &face = pMesh->mFaces[a];
  148|   158k|        if (face.mNumIndices < 3) {
  ------------------
  |  Branch (148:13): [True: 0, False: 158k]
  ------------------
  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|   158k|        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|   158k|        aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0];
  169|       |
  170|       |        // texture offset p1->p2 and p1->p3
  171|   158k|        float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
  172|   158k|        float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
  173|   158k|        float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
  ------------------
  |  Branch (173:31): [True: 139k, False: 19.1k]
  ------------------
  174|       |        // when t1, t2, t3 in same position in UV space, just use default UV direction.
  175|   158k|        if (sx * ty == sy * tx) {
  ------------------
  |  Branch (175:13): [True: 3.08k, False: 155k]
  ------------------
  176|  3.08k|            sx = 0.0;
  177|  3.08k|            sy = 1.0;
  178|  3.08k|            tx = 1.0;
  179|  3.08k|            ty = 0.0;
  180|  3.08k|        }
  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|   158k|        aiVector3D tangent, bitangent;
  185|   158k|        tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
  186|   158k|        tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
  187|   158k|        tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
  188|   158k|        bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
  189|   158k|        bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
  190|   158k|        bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
  191|       |
  192|       |        // store for every vertex of that face
  193|   634k|        for (unsigned int b = 0; b < face.mNumIndices; ++b) {
  ------------------
  |  Branch (193:34): [True: 476k, False: 158k]
  ------------------
  194|   476k|            unsigned int p = face.mIndices[b];
  195|       |
  196|       |            // project tangent and bitangent into the plane formed by the vertex' normal
  197|   476k|            aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
  198|   476k|            aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
  199|   476k|            localTangent.NormalizeSafe();
  200|   476k|            localBitangent.NormalizeSafe();
  201|       |
  202|       |            // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
  203|   476k|            bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z)
  ------------------
  |  Branch (203:36): [True: 0, False: 476k]
  |  Branch (203:72): [True: 0, False: 476k]
  |  Branch (203:108): [True: 0, False: 476k]
  ------------------
  204|   476k|                || (-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: 354k, False: 121k]
  |  Branch (204:47): [True: 221k, False: 132k]
  |  Branch (204:72): [True: 180k, False: 41.4k]
  |  Branch (204:98): [True: 138k, False: 41.9k]
  |  Branch (204:123): [True: 131k, False: 7.36k]
  |  Branch (204:149): [True: 0, False: 131k]
  ------------------
  205|   476k|            bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z)
  ------------------
  |  Branch (205:38): [True: 0, False: 476k]
  |  Branch (205:76): [True: 0, False: 476k]
  |  Branch (205:114): [True: 0, False: 476k]
  ------------------
  206|   476k|                || (-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: 367k, False: 108k]
  |  Branch (206:49): [True: 259k, False: 108k]
  |  Branch (206:76): [True: 222k, False: 36.5k]
  |  Branch (206:104): [True: 18.8k, False: 203k]
  |  Branch (206:131): [True: 12.2k, False: 6.58k]
  |  Branch (206:159): [True: 0, False: 12.2k]
  ------------------
  207|   476k|            if (invalid_tangent != invalid_bitangent) {
  ------------------
  |  Branch (207:17): [True: 0, False: 476k]
  ------------------
  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|   476k|            meshTang[p] = localTangent;
  219|   476k|            meshBitang[p] = localBitangent;
  220|   476k|        }
  221|   158k|    }
  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|    624|    SpatialSort *vertexFinder = nullptr;
  226|    624|    SpatialSort _vertexFinder;
  227|    624|    float posEpsilon = 10e-6f;
  228|    624|    if (shared) {
  ------------------
  |  Branch (228:9): [True: 624, False: 0]
  ------------------
  229|    624|        std::vector<std::pair<SpatialSort, float>> *avf;
  230|    624|        shared->GetProperty(AI_SPP_SPATIAL_SORT, avf);
  ------------------
  |  |  166|    624|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  231|    624|        if (avf) {
  ------------------
  |  Branch (231:13): [True: 624, False: 0]
  ------------------
  232|    624|            std::pair<SpatialSort, float> &blubb = avf->operator[](meshIndex);
  233|    624|            vertexFinder = &blubb.first;
  234|    624|            posEpsilon = blubb.second;
  235|    624|            ;
  236|    624|        }
  237|    624|    }
  238|    624|    if (!vertexFinder) {
  ------------------
  |  Branch (238:9): [True: 0, False: 624]
  ------------------
  239|      0|        _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof(aiVector3D));
  240|      0|        vertexFinder = &_vertexFinder;
  241|      0|        posEpsilon = ComputePositionEpsilon(pMesh);
  242|      0|    }
  243|    624|    std::vector<unsigned int> verticesFound;
  244|       |
  245|    624|    const float fLimit = std::cos(configMaxAngle);
  246|    624|    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|   354k|    for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
  ------------------
  |  Branch (250:30): [True: 353k, False: 624]
  ------------------
  251|   353k|        if (vertexDone[a])
  ------------------
  |  Branch (251:13): [True: 209k, False: 143k]
  ------------------
  252|   209k|            continue;
  253|       |
  254|   143k|        const aiVector3D &origPos = pMesh->mVertices[a];
  255|   143k|        const aiVector3D &origNorm = pMesh->mNormals[a];
  256|   143k|        const aiVector3D &origTang = pMesh->mTangents[a];
  257|   143k|        const aiVector3D &origBitang = pMesh->mBitangents[a];
  258|   143k|        closeVertices.resize(0);
  259|       |
  260|       |        // find all vertices close to that position
  261|   143k|        vertexFinder->FindPositions(origPos, posEpsilon, verticesFound);
  262|       |
  263|   143k|        closeVertices.reserve(verticesFound.size() + 5);
  264|   143k|        closeVertices.push_back(a);
  265|       |
  266|       |        // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
  267|   776k|        for (unsigned int b = 0; b < verticesFound.size(); b++) {
  ------------------
  |  Branch (267:34): [True: 632k, False: 143k]
  ------------------
  268|   632k|            unsigned int idx = verticesFound[b];
  269|   632k|            if (vertexDone[idx])
  ------------------
  |  Branch (269:17): [True: 143k, False: 489k]
  ------------------
  270|   143k|                continue;
  271|   489k|            if (meshNorm[idx] * origNorm < angleEpsilon)
  ------------------
  |  Branch (271:17): [True: 89.7k, False: 399k]
  ------------------
  272|  89.7k|                continue;
  273|   399k|            if (meshTang[idx] * origTang < fLimit)
  ------------------
  |  Branch (273:17): [True: 41.0k, False: 358k]
  ------------------
  274|  41.0k|                continue;
  275|   358k|            if (meshBitang[idx] * origBitang < fLimit)
  ------------------
  |  Branch (275:17): [True: 6.56k, False: 352k]
  ------------------
  276|  6.56k|                continue;
  277|       |
  278|       |            // it's similar enough -> add it to the smoothing group
  279|   352k|            closeVertices.push_back(idx);
  280|   352k|            vertexDone[idx] = true;
  281|   352k|        }
  282|       |
  283|       |        // smooth the tangents and bitangents of all vertices that were found to be close enough
  284|   143k|        aiVector3D smoothTangent(0, 0, 0), smoothBitangent(0, 0, 0);
  285|   639k|        for (unsigned int b = 0; b < closeVertices.size(); ++b) {
  ------------------
  |  Branch (285:34): [True: 496k, False: 143k]
  ------------------
  286|   496k|            smoothTangent += meshTang[closeVertices[b]];
  287|   496k|            smoothBitangent += meshBitang[closeVertices[b]];
  288|   496k|        }
  289|   143k|        smoothTangent.Normalize();
  290|   143k|        smoothBitangent.Normalize();
  291|       |
  292|       |        // and write it back into all affected tangents
  293|   639k|        for (unsigned int b = 0; b < closeVertices.size(); ++b) {
  ------------------
  |  Branch (293:34): [True: 496k, False: 143k]
  ------------------
  294|   496k|            meshTang[closeVertices[b]] = smoothTangent;
  295|   496k|            meshBitang[closeVertices[b]] = smoothBitangent;
  296|   496k|        }
  297|   143k|    }
  298|    624|    return true;
  299|    660|}

_ZNK6Assimp23ComputeUVMappingProcess8IsActiveEj:
   61|    319|bool ComputeUVMappingProcess::IsActive(unsigned int pFlags) const {
   62|    319|    return (pFlags & aiProcess_GenUVCoords) != 0;
   63|    319|}
_ZN6Assimp23ComputeUVMappingProcess7ExecuteEP7aiScene:
  345|    319|void ComputeUVMappingProcess::Execute(aiScene *pScene) {
  346|    319|    ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
  347|    319|    char buffer[1024];
  348|       |
  349|    319|    if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
  ------------------
  |  Branch (349:9): [True: 0, False: 319]
  ------------------
  350|      0|        throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
  351|      0|    }
  352|       |
  353|    319|    std::list<MappingInfo> mappingStack;
  354|       |
  355|       |    // Iterate through all materials and search for non-UV mapped textures
  356|    621|    for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
  ------------------
  |  Branch (356:30): [True: 302, False: 319]
  ------------------
  357|    302|        mappingStack.clear();
  358|    302|        aiMaterial *mat = pScene->mMaterials[i];
  359|    302|        if (mat == nullptr) {
  ------------------
  |  Branch (359:13): [True: 0, False: 302]
  ------------------
  360|      0|            ASSIMP_LOG_INFO("Material pointer in nullptr, skipping.");
  361|      0|            continue;
  362|      0|        }
  363|  6.35k|        for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
  ------------------
  |  Branch (363:34): [True: 6.05k, False: 302]
  ------------------
  364|  6.05k|            aiMaterialProperty *prop = mat->mProperties[a];
  365|  6.05k|            if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
  ------------------
  |  Branch (365:17): [True: 0, False: 6.05k]
  ------------------
  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|  6.05k|        }
  448|    302|    }
  449|    319|    ASSIMP_LOG_DEBUG("GenUVCoordsProcess finished");
  450|    319|}

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

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

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

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

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

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

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

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

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

_ZN6Assimp22FindDegeneratesProcessC2Ev:
   62|    402|        mConfigRemoveDegenerates(false),
   63|    402|        mConfigCheckAreaOfTriangle(false) {
   64|       |    // empty
   65|    402|}
_ZNK6Assimp22FindDegeneratesProcess8IsActiveEj:
   69|    319|bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const {
   70|    319|    return 0 != (pFlags & aiProcess_FindDegenerates);
   71|    319|}
_ZN6Assimp22FindDegeneratesProcess15SetupPropertiesEPKNS_8ImporterE:
   75|    319|void FindDegeneratesProcess::SetupProperties(const Importer *pImp) {
   76|       |    // Get the current value of AI_CONFIG_PP_FD_REMOVE
   77|    319|    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0));
   78|       |    mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA));
   79|    319|}
_ZN6Assimp22FindDegeneratesProcess7ExecuteEP7aiScene:
   83|    319|void FindDegeneratesProcess::Execute(aiScene *pScene) {
   84|    319|    ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
   85|    319|    if (nullptr == pScene) {
  ------------------
  |  Branch (85:9): [True: 0, False: 319]
  ------------------
   86|      0|        return;
   87|      0|    }
   88|       |
   89|    319|    std::unordered_map<unsigned int, unsigned int> meshMap;
   90|    319|    meshMap.reserve(pScene->mNumMeshes);
   91|       |
   92|    319|    const unsigned int originalNumMeshes = pScene->mNumMeshes;
   93|    319|    unsigned int targetIndex = 0;
   94|    991|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (94:30): [True: 672, False: 319]
  ------------------
   95|       |        // Do not process point cloud, ExecuteOnMesh works only with faces data
   96|    672|        if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
  ------------------
  |  Branch (96:13): [True: 672, False: 0]
  |  Branch (96:96): [True: 0, False: 672]
  ------------------
   97|      0|            delete pScene->mMeshes[i];
   98|       |            // Not strictly required, but clean:
   99|      0|            pScene->mMeshes[i] = nullptr;
  100|    672|        } else {
  101|    672|            meshMap[i] = targetIndex;
  102|    672|            pScene->mMeshes[targetIndex] = pScene->mMeshes[i];
  103|    672|            ++targetIndex;
  104|    672|        }
  105|    672|    }
  106|    319|    pScene->mNumMeshes = targetIndex;
  107|       |
  108|    319|    if (meshMap.size() < originalNumMeshes) {
  ------------------
  |  Branch (108:9): [True: 0, False: 319]
  ------------------
  109|      0|        updateSceneGraph(pScene->mRootNode, meshMap);
  110|      0|    }
  111|       |
  112|       |    ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
  113|    319|}
_ZN6Assimp22FindDegeneratesProcess13ExecuteOnMeshEP6aiMesh:
  134|    672|bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
  135|    672|    mesh->mPrimitiveTypes = 0;
  136|       |
  137|    672|    std::vector<bool> remove_me;
  138|    672|    if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (138:9): [True: 0, False: 672]
  ------------------
  139|      0|        remove_me.resize(mesh->mNumFaces, false);
  140|      0|    }
  141|       |
  142|    672|    unsigned int deg = 0, limit;
  143|   182k|    for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (143:30): [True: 182k, False: 672]
  ------------------
  144|   182k|        aiFace &face = mesh->mFaces[a];
  145|   182k|        bool first = true;
  146|   182k|        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|   725k|        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (149:34): [True: 542k, False: 182k]
  ------------------
  150|   542k|            if (!std::all_of(face.mIndices, face.mIndices + face.mNumIndices, vertex_in_range))
  ------------------
  |  Branch (150:17): [True: 0, False: 542k]
  ------------------
  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|   542k|            limit = face.mNumIndices;
  157|   542k|            if (face.mNumIndices > 4) {
  ------------------
  |  Branch (157:17): [True: 0, False: 542k]
  ------------------
  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: 542k]
  ------------------
  162|   544k|                if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) {
  ------------------
  |  Branch (162:21): [True: 3.56k, False: 540k]
  ------------------
  163|       |                    // we have found a matching vertex position
  164|       |                    // remove the corresponding index from the array
  165|  3.56k|                    --face.mNumIndices;
  166|  3.56k|                    --limit;
  167|  4.75k|                    for (unsigned int m = t; m < face.mNumIndices; ++m) {
  ------------------
  |  Branch (167:46): [True: 1.19k, False: 3.56k]
  ------------------
  168|  1.19k|                        face.mIndices[m] = face.mIndices[m + 1];
  169|  1.19k|                    }
  170|  3.56k|                    --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|  3.56k|                    face.mIndices[face.mNumIndices] = 0xdeadbeef;
  176|       |
  177|  3.56k|                    if (first) {
  ------------------
  |  Branch (177:25): [True: 2.37k, False: 1.18k]
  ------------------
  178|  2.37k|                        ++deg;
  179|  2.37k|                        first = false;
  180|  2.37k|                    }
  181|       |
  182|  3.56k|                    if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (182:25): [True: 0, False: 3.56k]
  ------------------
  183|      0|                        remove_me[a] = true;
  184|      0|                        goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
  185|      0|                    }
  186|  3.56k|                }
  187|   544k|            }
  188|       |
  189|   542k|            if (mConfigCheckAreaOfTriangle) {
  ------------------
  |  Branch (189:17): [True: 542k, False: 0]
  ------------------
  190|   542k|                if (face.mNumIndices == 3) {
  ------------------
  |  Branch (190:21): [True: 539k, False: 3.55k]
  ------------------
  191|   539k|                    ai_real area = GeometryUtils::calculateAreaOfTriangle(face, mesh);
  192|   539k|                    if (area < ai_epsilon) {
  ------------------
  |  Branch (192:25): [True: 30, False: 539k]
  ------------------
  193|     30|                        if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (193:29): [True: 0, False: 30]
  ------------------
  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|     30|                    }
  201|   539k|                }
  202|   542k|            }
  203|   542k|        }
  204|       |
  205|       |        // We need to update the primitive flags array of the mesh.
  206|   182k|        switch (face.mNumIndices) {
  207|  1.18k|        case 1u:
  ------------------
  |  Branch (207:9): [True: 1.18k, False: 180k]
  ------------------
  208|  1.18k|            mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  209|  1.18k|            break;
  210|  1.18k|        case 2u:
  ------------------
  |  Branch (210:9): [True: 1.18k, False: 180k]
  ------------------
  211|  1.18k|            mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  212|  1.18k|            break;
  213|   179k|        case 3u:
  ------------------
  |  Branch (213:9): [True: 179k, False: 2.37k]
  ------------------
  214|   179k|            mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  215|   179k|            break;
  216|      0|        default:
  ------------------
  |  Branch (216:9): [True: 0, False: 182k]
  ------------------
  217|      0|            mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  218|      0|            break;
  219|   182k|        };
  220|   182k|    evil_jump_outside:
  221|   182k|        continue;
  222|   182k|    }
  223|       |
  224|       |    // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
  225|    672|    if (mConfigRemoveDegenerates && deg) {
  ------------------
  |  Branch (225:9): [True: 0, False: 672]
  |  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|    672|    if (deg && !DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (258:9): [True: 171, False: 501]
  |  Branch (258:16): [True: 0, False: 171]
  ------------------
  259|       |        ASSIMP_LOG_WARN("Found ", deg, " degenerated primitives");
  260|      0|    }
  261|    672|    return false;
  262|    672|}
FindDegenerates.cpp:_ZZN6Assimp22FindDegeneratesProcess13ExecuteOnMeshEP6aiMeshENK3$_0clEj:
  146|  1.62M|        auto vertex_in_range = [numVertices = mesh->mNumVertices](unsigned int vertex_idx) { return vertex_idx < numVertices; };

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

_ZN6Assimp22FindInvalidDataProcessC2Ev:
   59|    402|        configEpsilon(0.0), mIgnoreTexCoods(false) {
   60|       |    // nothing to do here
   61|    402|}
_ZNK6Assimp22FindInvalidDataProcess8IsActiveEj:
   65|    319|bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {
   66|    319|    return 0 != (pFlags & aiProcess_FindInvalidData);
   67|    319|}
_ZN6Assimp22FindInvalidDataProcess15SetupPropertiesEPKNS_8ImporterE:
   71|    319|void FindInvalidDataProcess::SetupProperties(const Importer *pImp) {
   72|       |    // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
   73|    319|    configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY, 0.f));
   74|       |    mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false);
   75|    319|}
_Z20UpdateMeshReferencesP6aiNodeRKNSt3__16vectorIjNS1_9allocatorIjEEEE:
   79|  1.32k|void UpdateMeshReferences(aiNode *node, const std::vector<unsigned int> &meshMapping) {
   80|  1.32k|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 572, False: 753]
  ------------------
   81|    572|        unsigned int out = 0;
   82|  1.48k|        for (unsigned int a = 0; a < node->mNumMeshes; ++a) {
  ------------------
  |  Branch (82:34): [True: 917, False: 572]
  ------------------
   83|       |
   84|    917|            unsigned int ref = node->mMeshes[a];
   85|    917|            if (ref >= meshMapping.size())
  ------------------
  |  Branch (85:17): [True: 0, False: 917]
  ------------------
   86|      0|                throw DeadlyImportError("Invalid mesh ref");
   87|       |
   88|    917|            if (UINT_MAX != (ref = meshMapping[ref])) {
  ------------------
  |  Branch (88:17): [True: 745, False: 172]
  ------------------
   89|    745|                node->mMeshes[out++] = ref;
   90|    745|            }
   91|    917|        }
   92|       |        // just let the members that are unused, that's much cheaper
   93|       |        // than a full array realloc'n'copy party ...
   94|    572|        node->mNumMeshes = out;
   95|    572|        if (0 == out) {
  ------------------
  |  Branch (95:13): [True: 0, False: 572]
  ------------------
   96|      0|            delete[] node->mMeshes;
   97|      0|            node->mMeshes = nullptr;
   98|      0|        }
   99|    572|    }
  100|       |    // recursively update all children
  101|  2.58k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 1.26k, False: 1.32k]
  ------------------
  102|  1.26k|        UpdateMeshReferences(node->mChildren[i], meshMapping);
  103|  1.26k|    }
  104|  1.32k|}
_ZN6Assimp22FindInvalidDataProcess7ExecuteEP7aiScene:
  108|    319|void FindInvalidDataProcess::Execute(aiScene *pScene) {
  109|    319|    ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin");
  110|       |
  111|    319|    bool out = false;
  112|    319|    std::vector<unsigned int> meshMapping(pScene->mNumMeshes);
  113|    319|    unsigned int real = 0;
  114|       |
  115|       |    // Process meshes
  116|  1.33k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (116:30): [True: 1.01k, False: 319]
  ------------------
  117|  1.01k|        int result = ProcessMesh(pScene->mMeshes[a]);
  118|  1.01k|        if (0 == result) {
  ------------------
  |  Branch (118:13): [True: 843, False: 170]
  ------------------
  119|    843|            out = true;
  120|    843|        }
  121|  1.01k|        if (2 == result) {
  ------------------
  |  Branch (121:13): [True: 170, False: 843]
  ------------------
  122|       |            // remove this mesh
  123|    170|            delete pScene->mMeshes[a];
  124|    170|            pScene->mMeshes[a] = nullptr;
  125|       |
  126|    170|            meshMapping[a] = UINT_MAX;
  127|    170|            out = true;
  128|    170|            continue;
  129|    170|        }
  130|       |
  131|    843|        pScene->mMeshes[real] = pScene->mMeshes[a];
  132|    843|        meshMapping[a] = real++;
  133|    843|    }
  134|       |
  135|       |    // Process animations
  136|    524|    for (unsigned int animIdx = 0; animIdx < pScene->mNumAnimations; ++animIdx) {
  ------------------
  |  Branch (136:36): [True: 205, False: 319]
  ------------------
  137|    205|        ProcessAnimation(pScene->mAnimations[animIdx]);
  138|    205|    }
  139|       |
  140|    319|    if (out) {
  ------------------
  |  Branch (140:9): [True: 150, False: 169]
  ------------------
  141|    150|        if (real != pScene->mNumMeshes) {
  ------------------
  |  Branch (141:13): [True: 62, False: 88]
  ------------------
  142|     62|            if (!real) {
  ------------------
  |  Branch (142:17): [True: 0, False: 62]
  ------------------
  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|     62|            try {
  150|     62|                UpdateMeshReferences(pScene->mRootNode, meshMapping);
  151|     62|            } 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|     62|            pScene->mNumMeshes = real;
  157|     62|        }
  158|       |
  159|    150|        ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ...");
  160|    169|    } else {
  161|       |        ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK.");
  162|    169|    }
  163|    319|}
_ZN6Assimp22FindInvalidDataProcess16ProcessAnimationEP11aiAnimation:
  265|    205|void FindInvalidDataProcess::ProcessAnimation(aiAnimation *anim) {
  266|       |    // Process all animation channels
  267|  3.70k|    for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
  ------------------
  |  Branch (267:30): [True: 3.49k, False: 205]
  ------------------
  268|  3.49k|        ProcessAnimationChannel(anim->mChannels[a]);
  269|  3.49k|    }
  270|    205|}
_ZN6Assimp22FindInvalidDataProcess23ProcessAnimationChannelEP10aiNodeAnim:
  273|  3.49k|void FindInvalidDataProcess::ProcessAnimationChannel(aiNodeAnim *anim) {
  274|  3.49k|    ai_assert(nullptr != anim);
  275|  3.49k|    if (anim->mNumPositionKeys == 0 && anim->mNumRotationKeys == 0 && anim->mNumScalingKeys == 0) {
  ------------------
  |  Branch (275:9): [True: 15, False: 3.48k]
  |  Branch (275:40): [True: 0, False: 15]
  |  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.49k|    int i = 0;
  285|  3.49k|    if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys, anim->mNumPositionKeys, configEpsilon)) {
  ------------------
  |  Branch (285:9): [True: 2.76k, False: 734]
  |  Branch (285:39): [True: 2.55k, False: 209]
  ------------------
  286|  2.55k|        aiVectorKey v = anim->mPositionKeys[0];
  287|       |
  288|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  289|  2.55k|        delete[] anim->mPositionKeys;
  290|  2.55k|        anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = 1];
  291|  2.55k|        anim->mPositionKeys[0] = v;
  292|  2.55k|        i = 1;
  293|  2.55k|    }
  294|       |
  295|       |    // ROTATIONS
  296|  3.49k|    if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys, anim->mNumRotationKeys, configEpsilon)) {
  ------------------
  |  Branch (296:9): [True: 2.78k, False: 708]
  |  Branch (296:39): [True: 2.36k, False: 427]
  ------------------
  297|  2.36k|        aiQuatKey v = anim->mRotationKeys[0];
  298|       |
  299|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  300|  2.36k|        delete[] anim->mRotationKeys;
  301|  2.36k|        anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = 1];
  302|  2.36k|        anim->mRotationKeys[0] = v;
  303|  2.36k|        i = 1;
  304|  2.36k|    }
  305|       |
  306|       |    // SCALINGS
  307|  3.49k|    if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys, anim->mNumScalingKeys, configEpsilon)) {
  ------------------
  |  Branch (307:9): [True: 2.76k, False: 731]
  |  Branch (307:38): [True: 2.43k, False: 329]
  ------------------
  308|  2.43k|        aiVectorKey v = anim->mScalingKeys[0];
  309|       |
  310|       |        // Reallocate ... we need just ONE element, it makes no sense to reuse the array
  311|  2.43k|        delete[] anim->mScalingKeys;
  312|  2.43k|        anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = 1];
  313|  2.43k|        anim->mScalingKeys[0] = v;
  314|  2.43k|        i = 1;
  315|  2.43k|    }
  316|  3.49k|    if (1 == i) {
  ------------------
  |  Branch (316:9): [True: 3.09k, False: 405]
  ------------------
  317|       |        ASSIMP_LOG_WARN("Simplified dummy tracks with just one key");
  318|  3.09k|    }
  319|  3.49k|}
_ZN6Assimp22FindInvalidDataProcess11ProcessMeshEP6aiMesh:
  323|  1.01k|int FindInvalidDataProcess::ProcessMesh(aiMesh *pMesh) {
  324|  1.01k|    bool ret = false;
  325|  1.01k|    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|   183k|    for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
  ------------------
  |  Branch (329:30): [True: 182k, False: 1.01k]
  ------------------
  330|   182k|        const aiFace &f = pMesh->mFaces[m];
  331|       |
  332|   725k|        for (unsigned int i = 0; i < f.mNumIndices; ++i) {
  ------------------
  |  Branch (332:34): [True: 542k, False: 182k]
  ------------------
  333|   542k|            dirtyMask[f.mIndices[i]] = false;
  334|   542k|        }
  335|   182k|    }
  336|       |
  337|       |    // Process vertex positions
  338|  1.01k|    if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) {
  ------------------
  |  Branch (338:9): [True: 1.01k, False: 0]
  |  Branch (338:29): [True: 170, False: 843]
  ------------------
  339|    170|        ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions");
  340|       |
  341|    170|        return 2;
  342|    170|    }
  343|       |
  344|       |    // process texture coordinates
  345|    843|    if (!mIgnoreTexCoods) {
  ------------------
  |  Branch (345:9): [True: 843, False: 0]
  ------------------
  346|  1.64k|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) {
  ------------------
  |  Branch (346:34): [True: 1.64k, False: 0]
  |  Branch (346:72): [True: 801, False: 843]
  ------------------
  347|    801|            if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) {
  ------------------
  |  Branch (347:17): [True: 0, False: 801]
  ------------------
  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|    801|        }
  360|    843|    }
  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|    843|    if (pMesh->mNormals || pMesh->mTangents) {
  ------------------
  |  Branch (366:9): [True: 772, False: 71]
  |  Branch (366:28): [True: 0, False: 71]
  ------------------
  367|       |
  368|    772|        if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (368:13): [True: 0, False: 772]
  ------------------
  369|    772|                aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (369:17): [True: 166, False: 606]
  ------------------
  370|    166|            if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (370:17): [True: 0, False: 166]
  ------------------
  371|    166|                    aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (371:21): [True: 0, False: 166]
  ------------------
  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|    166|            else {
  387|    166|                return ret;
  388|    166|            }
  389|    166|        }
  390|       |
  391|       |        // Process mesh normals
  392|    606|        if (pMesh->mNormals && ProcessArray(pMesh->mNormals, pMesh->mNumVertices,
  ------------------
  |  Branch (392:13): [True: 606, False: 0]
  |  Branch (392:32): [True: 0, False: 606]
  ------------------
  393|    606|                                       "normals", dirtyMask, true, false))
  394|      0|            ret = true;
  395|       |
  396|       |        // Process mesh tangents
  397|    606|        if (pMesh->mTangents && ProcessArray(pMesh->mTangents, pMesh->mNumVertices, "tangents", dirtyMask)) {
  ------------------
  |  Branch (397:13): [True: 12, False: 594]
  |  Branch (397:33): [True: 0, False: 12]
  ------------------
  398|      0|            delete[] pMesh->mBitangents;
  399|      0|            pMesh->mBitangents = nullptr;
  400|      0|            ret = true;
  401|      0|        }
  402|       |
  403|       |        // Process mesh bitangents
  404|    606|        if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents, pMesh->mNumVertices, "bitangents", dirtyMask)) {
  ------------------
  |  Branch (404:13): [True: 12, False: 594]
  |  Branch (404:35): [True: 0, False: 12]
  ------------------
  405|      0|            delete[] pMesh->mTangents;
  406|      0|            pMesh->mTangents = nullptr;
  407|      0|            ret = true;
  408|      0|        }
  409|    606|    }
  410|    677|    return ret ? 1 : 0;
  ------------------
  |  Branch (410:12): [True: 0, False: 677]
  ------------------
  411|    843|}
_Z12AllIdenticalI11aiVectorKeyEbPT_jf:
  242|  5.52k|inline bool AllIdentical(T *in, unsigned int num, ai_real epsilon) {
  243|  5.52k|    if (num <= 1) {
  ------------------
  |  Branch (243:9): [True: 0, False: 5.52k]
  ------------------
  244|      0|        return true;
  245|      0|    }
  246|       |
  247|  5.52k|    if (fabs(epsilon) > 0.f) {
  ------------------
  |  Branch (247:9): [True: 0, False: 5.52k]
  ------------------
  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.52k|    } else {
  254|  4.11M|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (254:34): [True: 4.10M, False: 4.99k]
  ------------------
  255|  4.10M|            if (in[i] != in[i + 1]) {
  ------------------
  |  Branch (255:17): [True: 538, False: 4.10M]
  ------------------
  256|    538|                return false;
  257|    538|            }
  258|  4.10M|        }
  259|  5.52k|    }
  260|  4.99k|    return true;
  261|  5.52k|}
_Z12AllIdenticalI9aiQuatKeyEbPT_jf:
  242|  2.78k|inline bool AllIdentical(T *in, unsigned int num, ai_real epsilon) {
  243|  2.78k|    if (num <= 1) {
  ------------------
  |  Branch (243:9): [True: 0, False: 2.78k]
  ------------------
  244|      0|        return true;
  245|      0|    }
  246|       |
  247|  2.78k|    if (fabs(epsilon) > 0.f) {
  ------------------
  |  Branch (247:9): [True: 0, False: 2.78k]
  ------------------
  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.78k|    } else {
  254|   161k|        for (unsigned int i = 0; i < num - 1; ++i) {
  ------------------
  |  Branch (254:34): [True: 159k, False: 2.36k]
  ------------------
  255|   159k|            if (in[i] != in[i + 1]) {
  ------------------
  |  Branch (255:17): [True: 427, False: 158k]
  ------------------
  256|    427|                return false;
  257|    427|            }
  258|   159k|        }
  259|  2.78k|    }
  260|  2.36k|    return true;
  261|  2.78k|}
_Z12ProcessArrayI10aiVector3tIfEEbRPT_jPKcRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  203|  2.44k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) {
  204|  2.44k|    const char *err = ValidateArrayContents(in, num, dirtyMask, mayBeIdentical, mayBeZero);
  205|  2.44k|    if (err) {
  ------------------
  |  Branch (205:9): [True: 170, False: 2.27k]
  ------------------
  206|    170|        ASSIMP_LOG_ERROR("FindInvalidDataProcess fails on mesh ", name, ": ", err);
  207|    170|        delete[] in;
  208|    170|        in = nullptr;
  209|    170|        return true;
  210|    170|    }
  211|  2.27k|    return false;
  212|  2.44k|}
_Z21ValidateArrayContentsI10aiVector3tIfEEPKcPKT_jRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  175|  2.44k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical, bool mayBeZero) {
  176|  2.44k|    bool b = false;
  177|  2.44k|    unsigned int cnt = 0;
  178|  24.9M|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (178:30): [True: 24.9M, False: 2.44k]
  ------------------
  179|       |
  180|  24.9M|        if (dirtyMask.size() && dirtyMask[i]) {
  ------------------
  |  Branch (180:13): [True: 24.9M, False: 0]
  |  Branch (180:13): [True: 23.9M, False: 990k]
  |  Branch (180:33): [True: 23.9M, False: 990k]
  ------------------
  181|  23.9M|            continue;
  182|  23.9M|        }
  183|   990k|        ++cnt;
  184|       |
  185|   990k|        const aiVector3D &v = arr[i];
  186|   990k|        if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
  ------------------
  |  Branch (186:13): [True: 0, False: 990k]
  |  Branch (186:38): [True: 0, False: 990k]
  |  Branch (186:63): [True: 0, False: 990k]
  ------------------
  187|      0|            return "INF/NAN was found in a vector component";
  188|      0|        }
  189|   990k|        if (!mayBeZero && !v.x && !v.y && !v.z) {
  ------------------
  |  Branch (189:13): [True: 232k, False: 757k]
  |  Branch (189:27): [True: 15.5k, False: 217k]
  |  Branch (189:35): [True: 136, False: 15.4k]
  |  Branch (189:43): [True: 0, False: 136]
  ------------------
  190|      0|            return "Found zero-length vector";
  191|      0|        }
  192|   990k|        if (i && v != arr[i - 1]) b = true;
  ------------------
  |  Branch (192:13): [True: 988k, False: 2.44k]
  |  Branch (192:18): [True: 859k, False: 129k]
  ------------------
  193|   990k|    }
  194|  2.44k|    if (cnt > 1 && !b && !mayBeIdentical) {
  ------------------
  |  Branch (194:9): [True: 2.44k, False: 0]
  |  Branch (194:20): [True: 170, False: 2.27k]
  |  Branch (194:26): [True: 170, False: 0]
  ------------------
  195|    170|        return "All vectors are identical";
  196|    170|    }
  197|  2.27k|    return nullptr;
  198|  2.44k|}

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

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

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

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

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

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

_ZN6Assimp23GenVertexNormalsProcessC2Ev:
   57|    402|        configMaxAngle(AI_DEG_TO_RAD(175.f)) {
   58|       |    // empty
   59|    402|}
_ZNK6Assimp23GenVertexNormalsProcess8IsActiveEj:
   63|    319|bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const {
   64|    319|    force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
   65|    319|    flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
   66|    319|    leftHanded_ = (pFlags & aiProcess_MakeLeftHanded) != 0;
   67|    319|    return (pFlags & aiProcess_GenSmoothNormals) != 0;
   68|    319|}
_ZN6Assimp23GenVertexNormalsProcess15SetupPropertiesEPKNS_8ImporterE:
   72|    319|void GenVertexNormalsProcess::SetupProperties(const Importer *pImp) {
   73|       |    // Get the current value of the AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE property
   74|    319|    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|    319|}
_ZN6Assimp23GenVertexNormalsProcess7ExecuteEP7aiScene:
   80|    319|void GenVertexNormalsProcess::Execute(aiScene *pScene) {
   81|    319|    ASSIMP_LOG_DEBUG("GenVertexNormalsProcess begin");
   82|       |
   83|    319|    if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
  ------------------
  |  Branch (83:9): [True: 0, False: 319]
  ------------------
   84|      0|        throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
   85|      0|    }
   86|       |
   87|    319|    bool bHas = false;
   88|  1.16k|    for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (88:30): [True: 843, False: 319]
  ------------------
   89|    843|        if (GenMeshVertexNormals(pScene->mMeshes[a], a))
  ------------------
  |  Branch (89:13): [True: 66, False: 777]
  ------------------
   90|     66|            bHas = true;
   91|    843|    }
   92|       |
   93|    319|    if (bHas) {
  ------------------
  |  Branch (93:9): [True: 62, False: 257]
  ------------------
   94|     62|        ASSIMP_LOG_INFO("GenVertexNormalsProcess finished. "
   95|     62|                        "Vertex normals have been calculated");
   96|    257|    } else {
   97|       |        ASSIMP_LOG_DEBUG("GenVertexNormalsProcess finished. "
   98|    257|                         "Normals are already there");
   99|    257|    }
  100|    319|}
_ZN6Assimp23GenVertexNormalsProcess20GenMeshVertexNormalsEP6aiMeshj:
  104|    843|bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int meshIndex) {
  105|    843|    if (nullptr != pMesh->mNormals) {
  ------------------
  |  Branch (105:9): [True: 772, False: 71]
  ------------------
  106|    772|        if (!force_) {
  ------------------
  |  Branch (106:13): [True: 772, False: 0]
  ------------------
  107|    772|            return false;
  108|    772|        }
  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|     71|    if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
  ------------------
  |  Branch (116:9): [True: 5, False: 66]
  ------------------
  117|      5|        ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes");
  118|      5|        return false;
  119|      5|    }
  120|       |
  121|       |    // Allocate the array to hold the output normals
  122|     66|    const float qnan = std::numeric_limits<ai_real>::quiet_NaN();
  123|     66|    pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  124|       |
  125|       |    // Compute per-face normals but store them per-vertex
  126|  81.7k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (126:30): [True: 81.7k, False: 66]
  ------------------
  127|  81.7k|        const aiFace &face = pMesh->mFaces[a];
  128|  81.7k|        if (face.mNumIndices < 3) {
  ------------------
  |  Branch (128:13): [True: 0, False: 81.7k]
  ------------------
  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|  81.7k|        const aiVector3D *pV1 = &pMesh->mVertices[face.mIndices[0]];
  138|  81.7k|        const aiVector3D *pV2 = &pMesh->mVertices[face.mIndices[1]];
  139|  81.7k|        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|  81.7k|        if (flippedWindingOrder_ != leftHanded_) {
  ------------------
  |  Branch (142:13): [True: 0, False: 81.7k]
  ------------------
  143|      0|            std::swap(pV2, pV3);
  144|      0|        }
  145|  81.7k|        const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
  146|       |
  147|   326k|        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (147:34): [True: 245k, False: 81.7k]
  ------------------
  148|   245k|            pMesh->mNormals[face.mIndices[i]] = vNor;
  149|   245k|        }
  150|  81.7k|    }
  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|     66|    SpatialSort *vertexFinder = nullptr;
  155|     66|    SpatialSort _vertexFinder;
  156|     66|    ai_real posEpsilon = ai_real(1e-5);
  157|     66|    if (shared) {
  ------------------
  |  Branch (157:9): [True: 66, False: 0]
  ------------------
  158|     66|        std::vector<std::pair<SpatialSort, ai_real>> *avf;
  159|     66|        shared->GetProperty(AI_SPP_SPATIAL_SORT, avf);
  ------------------
  |  |  166|     66|#define AI_SPP_SPATIAL_SORT "$Spat"
  ------------------
  160|     66|        if (avf) {
  ------------------
  |  Branch (160:13): [True: 66, False: 0]
  ------------------
  161|     66|            std::pair<SpatialSort, ai_real> &blubb = avf->operator[](meshIndex);
  162|     66|            vertexFinder = &blubb.first;
  163|     66|            posEpsilon = blubb.second;
  164|     66|        }
  165|     66|    }
  166|     66|    if (!vertexFinder) {
  ------------------
  |  Branch (166:9): [True: 0, False: 66]
  ------------------
  167|      0|        _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof(aiVector3D));
  168|      0|        vertexFinder = &_vertexFinder;
  169|      0|        posEpsilon = ComputePositionEpsilon(pMesh);
  170|      0|    }
  171|     66|    std::vector<unsigned int> verticesFound;
  172|     66|    aiVector3D *pcNew = new aiVector3D[pMesh->mNumVertices];
  173|       |
  174|     66|    if (configMaxAngle >= AI_DEG_TO_RAD(175.f)) {
  ------------------
  |  Branch (174:9): [True: 66, 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|     66|        std::vector<bool> abHad(pMesh->mNumVertices, false);
  179|  24.1M|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (179:34): [True: 24.1M, False: 66]
  ------------------
  180|  24.1M|            if (abHad[i]) {
  ------------------
  |  Branch (180:17): [True: 24.0M, False: 41.0k]
  ------------------
  181|  24.0M|                continue;
  182|  24.0M|            }
  183|       |
  184|       |            // Get all vertices that share this one ...
  185|  41.0k|            vertexFinder->FindPositions(pMesh->mVertices[i], posEpsilon, verticesFound);
  186|       |
  187|  41.0k|            aiVector3D pcNor;
  188|  24.1M|            for (unsigned int a = 0; a < verticesFound.size(); ++a) {
  ------------------
  |  Branch (188:38): [True: 24.1M, False: 41.0k]
  ------------------
  189|  24.1M|                const aiVector3D &v = pMesh->mNormals[verticesFound[a]];
  190|  24.1M|                if (is_not_qnan(v.x)) pcNor += v;
  ------------------
  |  Branch (190:21): [True: 24.1M, False: 0]
  ------------------
  191|  24.1M|            }
  192|  41.0k|            pcNor.NormalizeSafe();
  193|       |
  194|       |            // Write the smoothed normal back to all affected normals
  195|  24.1M|            for (unsigned int a = 0; a < verticesFound.size(); ++a) {
  ------------------
  |  Branch (195:38): [True: 24.1M, False: 41.0k]
  ------------------
  196|  24.1M|                unsigned int vidx = verticesFound[a];
  197|  24.1M|                pcNew[vidx] = pcNor;
  198|  24.1M|                abHad[vidx] = true;
  199|  24.1M|            }
  200|  41.0k|        }
  201|     66|    }
  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|     66|    delete[] pMesh->mNormals;
  227|     66|    pMesh->mNormals = pcNew;
  228|       |
  229|     66|    return true;
  230|     71|}

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

_ZNK6Assimp19JoinVerticesProcess8IsActiveEj:
   63|    319|bool JoinVerticesProcess::IsActive( unsigned int pFlags) const {
   64|    319|    return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
   65|    319|}
_ZN6Assimp19JoinVerticesProcess7ExecuteEP7aiScene:
   68|    319|void JoinVerticesProcess::Execute( aiScene* pScene) {
   69|    319|    ASSIMP_LOG_DEBUG("JoinVerticesProcess begin");
   70|       |
   71|       |    // get the total number of vertices BEFORE the step is executed
   72|    319|    int iNumOldVertices = 0;
   73|    319|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (73:9): [True: 0, False: 319]
  ------------------
   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|    319|    int iNumVertices = 0;
   81|  1.16k|    for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (81:30): [True: 843, False: 319]
  ------------------
   82|    843|        iNumVertices += ProcessMesh( pScene->mMeshes[a],a);
   83|    843|    }
   84|       |
   85|    319|    pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
   86|       |
   87|       |    // if logging is active, print detailed statistics
   88|    319|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (88:9): [True: 0, False: 319]
  ------------------
   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|    319|}
_ZN6Assimp19JoinVerticesProcess11ProcessMeshEP6aiMeshj:
  225|    843|int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
  226|    843|    static_assert( AI_MAX_NUMBER_OF_COLOR_SETS    == 8, "AI_MAX_NUMBER_OF_COLOR_SETS    == 8");
  227|    843|	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|    843|    if (!pMesh->HasPositions() || !pMesh->HasFaces()) {
  ------------------
  |  Branch (230:9): [True: 0, False: 843]
  |  Branch (230:35): [True: 0, False: 843]
  ------------------
  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|    843|    std::vector<bool> usedVertexIndicesMask;
  238|    843|    usedVertexIndicesMask.resize(pMesh->mNumVertices, false);
  239|   181k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (239:30): [True: 180k, False: 843]
  ------------------
  240|   180k|        aiFace& face = pMesh->mFaces[a];
  241|   722k|        for (unsigned int b = 0; b < face.mNumIndices; b++) {
  ------------------
  |  Branch (241:34): [True: 541k, False: 180k]
  ------------------
  242|   541k|            usedVertexIndicesMask[face.mIndices[b]] = true;
  243|   541k|        }
  244|   180k|    }
  245|       |
  246|       |    // We'll never have more vertices afterwards.
  247|    843|    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|    843|    static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
  255|    843|    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|    843|    const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
  260|       |
  261|       |    // We'll never have more vertices afterwards.
  262|    843|    std::vector<std::vector<int>> uniqueAnimatedVertices;
  263|    843|    if (hasAnimMeshes) {
  ------------------
  |  Branch (263:9): [True: 0, False: 843]
  ------------------
  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|    843|    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|    843|    int newIndex = 0;
  274|  24.3M|    for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
  ------------------
  |  Branch (274:30): [True: 24.3M, False: 843]
  ------------------
  275|       |        // if the vertex is unused Do nothing
  276|  24.3M|        if (!usedVertexIndicesMask[a]) {
  ------------------
  |  Branch (276:13): [True: 23.9M, False: 399k]
  ------------------
  277|  23.9M|            continue;
  278|  23.9M|        }
  279|       |        // collect the vertex data
  280|   399k|        Vertex v(pMesh,a);
  281|       |        // is the vertex already in the map?
  282|   399k|        auto it = vertex2Index.find(v);
  283|       |        // if the vertex is not in the map then it is a new vertex add it.
  284|   399k|        if (it == vertex2Index.end()) {
  ------------------
  |  Branch (284:13): [True: 165k, False: 234k]
  ------------------
  285|       |            // this is a new vertex give it a new index
  286|   165k|            vertex2Index.emplace(v, newIndex);
  287|       |            // keep track of its index and increment 1
  288|   165k|            replaceIndex[a] = newIndex++;
  289|       |            // add the vertex to the unique vertices
  290|   165k|            uniqueVertices.push_back(a);
  291|   165k|            if (hasAnimMeshes) {
  ------------------
  |  Branch (291:17): [True: 0, False: 165k]
  ------------------
  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|   234k|        } 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|   234k|            replaceIndex[a] = it->second | JOINED_VERTICES_MARK;
  300|   234k|        }
  301|   399k|    }
  302|       |
  303|    843|    if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE)    {
  ------------------
  |  Branch (303:9): [True: 0, False: 843]
  |  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|    843|    updateXMeshVertices(pMesh, uniqueVertices);
  318|    843|    if (hasAnimMeshes) {
  ------------------
  |  Branch (318:9): [True: 0, False: 843]
  ------------------
  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: 180k, False: 843]
  ------------------
  326|   180k|        aiFace& face = pMesh->mFaces[a];
  327|   722k|        for( unsigned int b = 0; b < face.mNumIndices; b++) {
  ------------------
  |  Branch (327:34): [True: 541k, False: 180k]
  ------------------
  328|   541k|            face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~JOINED_VERTICES_MARK;
  329|   541k|        }
  330|   180k|    }
  331|       |
  332|       |    // adjust bone vertex weights.
  333|  1.46k|    for( int a = 0; a < (int)pMesh->mNumBones; a++) {
  ------------------
  |  Branch (333:21): [True: 621, False: 843]
  ------------------
  334|    621|        aiBone* bone = pMesh->mBones[a];
  335|    621|        std::vector<aiVertexWeight> newWeights;
  336|    621|        newWeights.reserve( bone->mNumWeights);
  337|       |
  338|    621|        if (nullptr != bone->mWeights) {
  ------------------
  |  Branch (338:13): [True: 621, False: 0]
  ------------------
  339|   870k|            for ( unsigned int b = 0; b < bone->mNumWeights; b++ ) {
  ------------------
  |  Branch (339:39): [True: 869k, False: 621]
  ------------------
  340|   869k|                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|   869k|                if ( !( replaceIndex[ ow.mVertexId ] & JOINED_VERTICES_MARK ) ) {
  ------------------
  |  Branch (343:22): [True: 366k, False: 503k]
  ------------------
  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|   869k|            }
  350|    621|        } else {
  351|      0|            ASSIMP_LOG_ERROR( "X-Export: aiBone shall contain weights, but pointer to them is nullptr." );
  352|      0|        }
  353|       |
  354|    621|        if (newWeights.size() > 0) {
  ------------------
  |  Branch (354:13): [True: 621, False: 0]
  ------------------
  355|       |            // kill the old and replace them with the translated weights
  356|    621|            delete [] bone->mWeights;
  357|    621|            bone->mNumWeights = (unsigned int)newWeights.size();
  358|       |
  359|    621|            bone->mWeights = new aiVertexWeight[bone->mNumWeights];
  360|    621|            memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
  361|    621|        }
  362|    621|    }
  363|    843|    return pMesh->mNumVertices;
  364|    843|}
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_110HashVertexclERKN6Assimp6VertexE:
  151|   564k|    size_t operator () (const Vertex & v) const {
  152|   564k|        size_t hash = 0;
  153|       |
  154|   564k|        hash_combine(hash, v.position.x);
  155|   564k|        hash_combine(hash, v.position.y);
  156|   564k|        hash_combine(hash, v.position.z);
  157|       |
  158|   564k|        return hash;
  159|   564k|    }
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_110HashVertex12hash_combineERmRKf:
  146|  1.69M|    inline void hash_combine(std::size_t& seed, const ai_real& v) const {
  147|  1.69M|        std::hash<ai_real> hasher;
  148|  1.69M|        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  149|  1.69M|    }
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_126CompareVerticesAlmostEqualclERKN6Assimp6VertexES4_:
  104|   473k|    bool operator () (const Vertex & a, const Vertex & b) const {
  105|   473k|        static const float epsilon = 1e-5f;
  106|   473k|        static const float squareEpsilon = epsilon * epsilon;
  107|       |
  108|   473k|        if ((a.position - b.position).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (108:13): [True: 0, False: 473k]
  ------------------
  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|   473k|        if ((a.normal - b.normal).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (116:13): [True: 157k, False: 315k]
  ------------------
  117|   157k|            return false;
  118|   157k|        }
  119|       |
  120|   315k|        if ((a.tangent - b.tangent).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (120:13): [True: 76.2k, False: 239k]
  ------------------
  121|  76.2k|            return false;
  122|  76.2k|        }
  123|       |
  124|   239k|        if ((a.bitangent - b.bitangent).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (124:13): [True: 2.02k, False: 237k]
  ------------------
  125|  2.02k|            return false;
  126|  2.02k|        }
  127|       |
  128|  2.11M|        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i ++) {
  ------------------
  |  Branch (128:30): [True: 1.87M, False: 234k]
  ------------------
  129|  1.87M|            if ((a.texcoords[i] - b.texcoords[i]).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (129:17): [True: 3.26k, False: 1.87M]
  ------------------
  130|  3.26k|                return false;
  131|  3.26k|            }
  132|  1.87M|        }
  133|       |
  134|  2.11M|        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; i ++) {
  ------------------
  |  Branch (134:30): [True: 1.87M, False: 234k]
  ------------------
  135|  1.87M|            if (GetColorDifference(a.colors[i], b.colors[i]) > squareEpsilon) {
  ------------------
  |  Branch (135:17): [True: 0, False: 1.87M]
  ------------------
  136|      0|                return false;
  137|      0|            }
  138|  1.87M|        }
  139|       |
  140|       |        // If reached this point, they are ~equal
  141|   234k|        return true;
  142|   234k|    }
JoinVerticesProcess.cpp:_ZN12_GLOBAL__N_119updateXMeshVerticesI6aiMeshEEvPT_RNSt3__16vectorIiNS4_9allocatorIiEEEE:
  163|    843|void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
  164|       |    // replace vertex data with the unique data sets
  165|    843|    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|    843|    if (pMesh->mVertices) {
  ------------------
  |  Branch (174:9): [True: 843, False: 0]
  ------------------
  175|    843|        std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
  176|    843|        pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  177|   166k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (177:34): [True: 165k, False: 843]
  ------------------
  178|   165k|            pMesh->mVertices[a] = oldVertices[uniqueVertices[a]];
  179|    843|    }
  180|       |
  181|       |    // Normals, if present
  182|    843|    if (pMesh->mNormals) {
  ------------------
  |  Branch (182:9): [True: 838, False: 5]
  ------------------
  183|    838|        std::unique_ptr<aiVector3D[]> oldNormals(pMesh->mNormals);
  184|    838|        pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  185|   166k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (185:34): [True: 165k, False: 838]
  ------------------
  186|   165k|            pMesh->mNormals[a] = oldNormals[uniqueVertices[a]];
  187|    838|    }
  188|       |    // Tangents, if present
  189|    843|    if (pMesh->mTangents) {
  ------------------
  |  Branch (189:9): [True: 636, False: 207]
  ------------------
  190|    636|        std::unique_ptr<aiVector3D[]> oldTangents(pMesh->mTangents);
  191|    636|        pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  192|   148k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (192:34): [True: 147k, False: 636]
  ------------------
  193|   147k|            pMesh->mTangents[a] = oldTangents[uniqueVertices[a]];
  194|    636|    }
  195|       |    // Bitangents as well
  196|    843|    if (pMesh->mBitangents) {
  ------------------
  |  Branch (196:9): [True: 636, False: 207]
  ------------------
  197|    636|        std::unique_ptr<aiVector3D[]> oldBitangents(pMesh->mBitangents);
  198|    636|        pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  199|   148k|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (199:34): [True: 147k, False: 636]
  ------------------
  200|   147k|            pMesh->mBitangents[a] = oldBitangents[uniqueVertices[a]];
  201|    636|    }
  202|       |    // Vertex colors
  203|    843|    for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) {
  ------------------
  |  Branch (203:30): [True: 0, False: 843]
  ------------------
  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|  1.64k|    for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) {
  ------------------
  |  Branch (210:30): [True: 801, False: 843]
  ------------------
  211|    801|        std::unique_ptr<aiVector3D[]> oldTextureCoords(pMesh->mTextureCoords[a]);
  212|    801|        pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
  213|   149k|        for (unsigned int b = 0; b < pMesh->mNumVertices; b++)
  ------------------
  |  Branch (213:34): [True: 148k, False: 801]
  ------------------
  214|   148k|            pMesh->mTextureCoords[a][b] = oldTextureCoords[uniqueVertices[b]];
  215|    801|    }
  216|    843|}

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

_ZN6Assimp23LimitBoneWeightsProcessC2Ev:
   57|    402|        mMaxWeights(AI_LMW_MAX_WEIGHTS), mRemoveEmptyBones(true) {
   58|       |    // empty
   59|    402|}
_ZNK6Assimp23LimitBoneWeightsProcess8IsActiveEj:
   63|    319|bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const {
   64|    319|    return (pFlags & aiProcess_LimitBoneWeights) != 0;
   65|    319|}
_ZN6Assimp23LimitBoneWeightsProcess7ExecuteEP7aiScene:
   69|    319|void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
   70|    319|    ai_assert(pScene != nullptr);
   71|       |
   72|    319|    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin");
   73|       |
   74|  1.16k|    for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
  ------------------
  |  Branch (74:30): [True: 843, False: 319]
  ------------------
   75|    843|        ProcessMesh(pScene->mMeshes[m]);
   76|    843|    }
   77|       |
   78|       |    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end");
   79|    319|}
_ZN6Assimp23LimitBoneWeightsProcess15SetupPropertiesEPKNS_8ImporterE:
   83|    319|void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) {
   84|    319|    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|    319|}
_ZN6Assimp23LimitBoneWeightsProcess11ProcessMeshEP6aiMesh:
  107|    843|void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) {
  108|    843|    if (!pMesh->HasBones())
  ------------------
  |  Branch (108:9): [True: 777, False: 66]
  ------------------
  109|    777|        return;
  110|       |
  111|       |    // collect all bone weights per vertex
  112|     66|    typedef SmallVector<Weight,8> VertexWeightArray;
  113|     66|    typedef std::vector<VertexWeightArray> WeightsPerVertex;
  114|     66|    WeightsPerVertex vertexWeights(pMesh->mNumVertices);
  115|     66|    size_t maxVertexWeights = 0;
  116|       |
  117|    687|    for (unsigned int b = 0; b < pMesh->mNumBones; ++b) {
  ------------------
  |  Branch (117:30): [True: 621, False: 66]
  ------------------
  118|    621|        const aiBone* bone = pMesh->mBones[b];
  119|   366k|        for (unsigned int w = 0; w < bone->mNumWeights; ++w) {
  ------------------
  |  Branch (119:34): [True: 366k, False: 621]
  ------------------
  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|    621|    }
  129|       |
  130|     66|    if (maxVertexWeights <= mMaxWeights)
  ------------------
  |  Branch (130:9): [True: 15, False: 51]
  ------------------
  131|     15|        return;
  132|       |
  133|     51|    unsigned int removed = 0, old_bones = pMesh->mNumBones;
  134|       |
  135|       |    // now cut the weight count if it exceeds the maximum
  136|  93.9k|    for (WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) {
  ------------------
  |  Branch (136:66): [True: 93.8k, False: 51]
  ------------------
  137|  93.8k|        if (vit->size() <= mMaxWeights)
  ------------------
  |  Branch (137:13): [True: 73.0k, False: 20.8k]
  ------------------
  138|  73.0k|            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|  20.8k|        std::sort(vit->begin(), vit->end());
  143|       |
  144|       |        // now kill everything beyond the maximum count
  145|  20.8k|        unsigned int m = static_cast<unsigned int>(vit->size());
  146|  20.8k|        vit->resize(mMaxWeights);
  147|  20.8k|        removed += static_cast<unsigned int>(m - vit->size());
  148|       |
  149|       |        // and renormalize the weights
  150|  20.8k|        float sum = 0.0f;
  151|   104k|        for(const Weight* it = vit->begin(); it != vit->end(); ++it) {
  ------------------
  |  Branch (151:46): [True: 83.2k, False: 20.8k]
  ------------------
  152|  83.2k|            sum += it->mWeight;
  153|  83.2k|        }
  154|  20.8k|        if (0.0f != sum) {
  ------------------
  |  Branch (154:13): [True: 20.8k, False: 0]
  ------------------
  155|  20.8k|            const float invSum = 1.0f / sum;
  156|   104k|            for(Weight* it = vit->begin(); it != vit->end(); ++it) {
  ------------------
  |  Branch (156:44): [True: 83.2k, False: 20.8k]
  ------------------
  157|  83.2k|                it->mWeight *= invSum;
  158|  83.2k|            }
  159|  20.8k|        }
  160|  20.8k|    }
  161|       |
  162|       |    // clear weight count for all bone
  163|    580|    for (unsigned int a = 0; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (163:30): [True: 529, False: 51]
  ------------------
  164|    529|        pMesh->mBones[a]->mNumWeights = 0;
  165|    529|    }
  166|       |
  167|       |    // rebuild the vertex weight array for all bones
  168|  93.9k|    for (unsigned int a = 0; a < vertexWeights.size(); ++a) {
  ------------------
  |  Branch (168:30): [True: 93.8k, False: 51]
  ------------------
  169|  93.8k|        const VertexWeightArray& vw = vertexWeights[a];
  170|   392k|        for (const Weight* it = vw.begin(); it != vw.end(); ++it) {
  ------------------
  |  Branch (170:45): [True: 299k, False: 93.8k]
  ------------------
  171|   299k|            aiBone* bone = pMesh->mBones[it->mBone];
  172|   299k|            bone->mWeights[bone->mNumWeights++] = aiVertexWeight(a, it->mWeight);
  173|   299k|        }
  174|  93.8k|    }
  175|       |
  176|       |    // remove empty bones
  177|     51|    if (mRemoveEmptyBones) {
  ------------------
  |  Branch (177:9): [True: 51, False: 0]
  ------------------
  178|     51|        pMesh->mNumBones = removeEmptyBones(pMesh);
  179|     51|    }
  180|       |
  181|     51|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (181:9): [True: 0, False: 51]
  ------------------
  182|       |        ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones);
  183|      0|    }
  184|     51|}
LimitBoneWeightsProcess.cpp:_ZN6AssimpL16removeEmptyBonesEP6aiMesh:
   89|     51|static unsigned int removeEmptyBones(aiMesh *pMesh) {
   90|     51|    ai_assert(pMesh != nullptr);
   91|       |
   92|     51|    unsigned int writeBone = 0;
   93|    580|    for (unsigned int readBone = 0; readBone< pMesh->mNumBones; ++readBone) {
  ------------------
  |  Branch (93:37): [True: 529, False: 51]
  ------------------
   94|    529|        aiBone* bone = pMesh->mBones[readBone];
   95|    529|        if (bone->mNumWeights > 0) {
  ------------------
  |  Branch (95:13): [True: 515, False: 14]
  ------------------
   96|    515|            pMesh->mBones[writeBone++] = bone;
   97|    515|        } else {
   98|     14|            delete bone;
   99|     14|        }
  100|    529|    }
  101|       |
  102|     51|    return writeBone;
  103|     51|}

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

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

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

_ZN6Assimp21OptimizeMeshesProcessC2Ev:
   66|    402|    , pts(false)
   67|    402|    , max_verts( NotSet )
   68|    402|    , max_faces( NotSet ) {
   69|       |    // empty
   70|    402|}
_ZNK6Assimp21OptimizeMeshesProcess8IsActiveEj:
   75|    319|{
   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|    319|    if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
  ------------------
  |  Branch (80:9): [True: 0, False: 319]
  ------------------
   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|    319|    return false;
   86|    319|}

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

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

_ZN6Assimp22ComputePositionEpsilonEPK6aiMesh:
  136|    843|ai_real ComputePositionEpsilon(const aiMesh *pMesh) {
  137|    843|    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|    843|    aiVector3D minVec, maxVec;
  141|    843|    ArrayBounds(pMesh->mVertices, pMesh->mNumVertices, minVec, maxVec);
  142|    843|    return (maxVec - minVec).Length() * epsilon;
  143|    843|}
_ZN6Assimp28ComputeVertexBoneWeightTableEPK6aiMesh:
  199|    171|VertexWeightTable *ComputeVertexBoneWeightTable(const aiMesh *pMesh) {
  200|    171|    if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
  ------------------
  |  Branch (200:9): [True: 0, False: 171]
  |  Branch (200:19): [True: 0, False: 171]
  |  Branch (200:43): [True: 171, False: 0]
  ------------------
  201|    171|        return nullptr;
  202|    171|    }
  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|    171|}

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

_ZN6Assimp26RemoveRedundantMatsProcessC2Ev:
   57|    402|RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() : mConfigFixedMaterials() {}
_ZNK6Assimp26RemoveRedundantMatsProcess8IsActiveEj:
   61|    319|bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const {
   62|    319|    return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
   63|    319|}
_ZN6Assimp26RemoveRedundantMatsProcess15SetupPropertiesEPKNS_8ImporterE:
   67|    319|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|    319|}
_ZN6Assimp26RemoveRedundantMatsProcess7ExecuteEP7aiScene:
   74|    319|void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
   75|    319|    ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
   76|       |
   77|    319|    unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
   78|    319|    if (pScene->mNumMaterials == 0) {
  ------------------
  |  Branch (78:9): [True: 169, False: 150]
  ------------------
   79|    169|        return;
   80|    169|    }
   81|       |
   82|       |    // Find out which materials are referenced by meshes
   83|    150|    std::vector<bool> abReferenced(pScene->mNumMaterials,false);
   84|    822|    for (unsigned int i = 0;i < pScene->mNumMeshes;++i) {
  ------------------
  |  Branch (84:29): [True: 672, False: 150]
  ------------------
   85|    672|        abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
   86|    672|    }
   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|    150|    if (mConfigFixedMaterials.length()) {
  ------------------
  |  Branch (91:9): [True: 0, False: 150]
  ------------------
   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|    150|    unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials];
  119|    452|    for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) {
  ------------------
  |  Branch (119:29): [True: 302, False: 150]
  ------------------
  120|    302|        aiMappingTable[ i ] = 0;
  121|    302|    }
  122|    150|    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|    150|    uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];
  129|    452|    for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
  ------------------
  |  Branch (129:30): [True: 302, False: 150]
  ------------------
  130|       |        // No mesh is referencing this material, remove it.
  131|    302|        if (!abReferenced[i]) {
  ------------------
  |  Branch (131:13): [True: 0, False: 302]
  ------------------
  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|    302|        uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
  141|    575|        for (unsigned int a = 0; a < i;++a) {
  ------------------
  |  Branch (141:34): [True: 273, False: 302]
  ------------------
  142|    273|            if (abReferenced[a] && me == aiHashes[a]) {
  ------------------
  |  Branch (142:17): [True: 273, False: 0]
  |  Branch (142:17): [True: 0, False: 273]
  |  Branch (142:36): [True: 0, False: 273]
  ------------------
  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|    273|        }
  151|       |        // This is a new material that is referenced, add to the map.
  152|    302|        if (me) {
  ------------------
  |  Branch (152:13): [True: 302, False: 0]
  ------------------
  153|    302|            aiMappingTable[i] = iNewNum++;
  154|    302|        }
  155|    302|    }
  156|       |    // If the new material count differs from the original,
  157|       |    // we need to rebuild the material list and remap mesh material indexes.
  158|    150|    if (iNewNum < 1) {
  ------------------
  |  Branch (158:9): [True: 0, False: 150]
  ------------------
  159|      0|        delete [] aiMappingTable;
  160|      0|        delete [] aiHashes;
  161|      0|        pScene->mNumMaterials = 0;
  162|      0|        return;
  163|      0|    }
  164|    150|    if (iNewNum != pScene->mNumMaterials) {
  ------------------
  |  Branch (164:9): [True: 0, False: 150]
  ------------------
  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|    150|    delete[] aiHashes;
  199|    150|    delete[] aiMappingTable;
  200|       |
  201|    150|    if (redundantRemoved == 0 && unreferencedRemoved == 0) {
  ------------------
  |  Branch (201:9): [True: 150, False: 0]
  |  Branch (201:34): [True: 150, False: 0]
  ------------------
  202|    150|        ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
  203|    150|    } else {
  204|       |        ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
  205|      0|            unreferencedRemoved, " unused materials.");
  206|      0|    }
  207|    150|}

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

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

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

_ZN6Assimp18SortByPTypeProcessC2Ev:
   55|    402|SortByPTypeProcess::SortByPTypeProcess() : mConfigRemoveMeshes(0) {}
_ZNK6Assimp18SortByPTypeProcess8IsActiveEj:
   59|    319|bool SortByPTypeProcess::IsActive(unsigned int pFlags) const {
   60|    319|    return (pFlags & aiProcess_SortByPType) != 0;
   61|    319|}
_ZN6Assimp18SortByPTypeProcess15SetupPropertiesEPKNS_8ImporterE:
   64|    319|void SortByPTypeProcess::SetupProperties(const Importer *pImp) {
   65|       |    mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, 0);
   66|    319|}
_Z11UpdateNodesRKNSt3__16vectorIjNS_9allocatorIjEEEEP6aiNode:
   77|  1.32k|void UpdateNodes(const std::vector<unsigned int> &replaceMeshIndex, aiNode *node) {
   78|  1.32k|    ai_assert(node != nullptr);
   79|       |
   80|  1.32k|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 572, False: 753]
  ------------------
   81|    572|        unsigned int newSize = 0;
   82|  1.14k|        for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
  ------------------
  |  Branch (82:34): [True: 572, False: 572]
  ------------------
   83|    572|            unsigned int add = node->mMeshes[m] << 2;
   84|  2.86k|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (84:38): [True: 2.28k, False: 572]
  ------------------
   85|  2.28k|                if (UINT_MAX != replaceMeshIndex[add + i]) {
  ------------------
  |  Branch (85:21): [True: 917, False: 1.37k]
  ------------------
   86|    917|                    ++newSize;
   87|    917|                }
   88|  2.28k|            }
   89|    572|        }
   90|    572|        if (newSize == 0) {
  ------------------
  |  Branch (90:13): [True: 0, False: 572]
  ------------------
   91|      0|            clearMeshesInNode(node);
   92|      0|            return;
   93|      0|        }
   94|       |
   95|       |        // Try to reuse the old array if possible
   96|    572|        unsigned int *newMeshes = (newSize > node->mNumMeshes ? new unsigned int[newSize] : node->mMeshes);
  ------------------
  |  Branch (96:36): [True: 173, False: 399]
  ------------------
   97|  1.14k|        for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
  ------------------
  |  Branch (97:34): [True: 572, False: 572]
  ------------------
   98|    572|            unsigned int add = node->mMeshes[m] << 2;
   99|  2.86k|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (99:38): [True: 2.28k, False: 572]
  ------------------
  100|  2.28k|                if (UINT_MAX != replaceMeshIndex[add + i]) {
  ------------------
  |  Branch (100:21): [True: 917, False: 1.37k]
  ------------------
  101|    917|                    *newMeshes++ = replaceMeshIndex[add + i];
  102|    917|                }
  103|  2.28k|            }
  104|    572|        }
  105|    572|        if (newSize > node->mNumMeshes) {
  ------------------
  |  Branch (105:13): [True: 173, False: 399]
  ------------------
  106|    173|            clearMeshesInNode(node);
  107|    173|        }
  108|    572|        node->mMeshes = newMeshes - (node->mNumMeshes = newSize);
  109|    572|    }
  110|       |
  111|       |    // call all subnodes recursively
  112|  2.58k|    for (unsigned int m = 0; m < node->mNumChildren; ++m) {
  ------------------
  |  Branch (112:30): [True: 1.26k, False: 1.32k]
  ------------------
  113|  1.26k|        UpdateNodes(replaceMeshIndex, node->mChildren[m]);
  114|  1.26k|    }
  115|  1.32k|}
_ZN6Assimp18SortByPTypeProcess7ExecuteEP7aiScene:
  119|    319|void SortByPTypeProcess::Execute(aiScene *pScene) {
  120|    319|    if (0 == pScene->mNumMeshes) {
  ------------------
  |  Branch (120:9): [True: 169, False: 150]
  ------------------
  121|    169|        ASSIMP_LOG_DEBUG("SortByPTypeProcess skipped, there are no meshes");
  122|    169|        return;
  123|    169|    }
  124|       |
  125|    319|    ASSIMP_LOG_DEBUG("SortByPTypeProcess begin");
  126|       |
  127|    150|    unsigned int aiNumMeshesPerPType[4] = { 0, 0, 0, 0 };
  128|       |
  129|    150|    std::vector<aiMesh *> outMeshes;
  130|    150|    outMeshes.reserve(static_cast<size_t>(pScene->mNumMeshes) << 1u);
  131|       |
  132|    150|    bool bAnyChanges = false;
  133|       |
  134|    150|    std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes * 4, UINT_MAX);
  135|    150|    std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin();
  136|    822|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (136:30): [True: 672, False: 150]
  ------------------
  137|    672|        aiMesh *const mesh = pScene->mMeshes[i];
  138|    672|        if (mesh->mPrimitiveTypes == 0) {
  ------------------
  |  Branch (138:13): [True: 0, False: 672]
  ------------------
  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|    672|        unsigned int num = 0;
  147|    672|        if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) {
  ------------------
  |  Branch (147:13): [True: 170, False: 502]
  ------------------
  148|    170|            ++aiNumMeshesPerPType[0];
  149|    170|            ++num;
  150|    170|        }
  151|    672|        if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) {
  ------------------
  |  Branch (151:13): [True: 171, False: 501]
  ------------------
  152|    171|            ++aiNumMeshesPerPType[1];
  153|    171|            ++num;
  154|    171|        }
  155|    672|        if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) {
  ------------------
  |  Branch (155:13): [True: 672, False: 0]
  ------------------
  156|    672|            ++aiNumMeshesPerPType[2];
  157|    672|            ++num;
  158|    672|        }
  159|    672|        if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) {
  ------------------
  |  Branch (159:13): [True: 0, False: 672]
  ------------------
  160|      0|            ++aiNumMeshesPerPType[3];
  161|      0|            ++num;
  162|      0|        }
  163|       |
  164|    672|        if (1 == num) {
  ------------------
  |  Branch (164:13): [True: 501, False: 171]
  ------------------
  165|    501|            if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) {
  ------------------
  |  Branch (165:17): [True: 501, False: 0]
  ------------------
  166|    501|                *meshIdx = static_cast<unsigned int>(outMeshes.size());
  167|    501|                outMeshes.emplace_back(mesh);
  168|    501|                pScene->mMeshes[i] = nullptr; // Indicate ownership transfer
  169|    501|            } else {
  170|      0|                delete mesh;
  171|      0|                pScene->mMeshes[i] = nullptr;
  172|      0|                bAnyChanges = true;
  173|      0|            }
  174|       |
  175|    501|            meshIdx += 4;
  176|    501|            continue;
  177|    501|        }
  178|    171|        bAnyChanges = true;
  179|       |
  180|       |        // reuse our current mesh arrays for the submesh
  181|       |        // with the largest number of primitives
  182|    171|        unsigned int aiNumPerPType[4] = { 0, 0, 0, 0 };
  183|    171|        aiFace *pFirstFace = mesh->mFaces;
  184|    171|        if (pFirstFace == nullptr) {
  ------------------
  |  Branch (184:13): [True: 0, False: 171]
  ------------------
  185|      0|            continue;
  186|      0|        }
  187|       |
  188|    171|        aiFace *const pLastFace = pFirstFace + mesh->mNumFaces;
  189|       |
  190|    171|        unsigned int numPolyVerts = 0;
  191|  7.53k|        for (; pFirstFace != pLastFace; ++pFirstFace) {
  ------------------
  |  Branch (191:16): [True: 7.36k, False: 171]
  ------------------
  192|  7.36k|            if (pFirstFace->mNumIndices >= 1 && pFirstFace->mNumIndices <= 3)
  ------------------
  |  Branch (192:17): [True: 7.36k, False: 0]
  |  Branch (192:49): [True: 7.36k, False: 0]
  ------------------
  193|  7.36k|                ++aiNumPerPType[pFirstFace->mNumIndices - 1];
  194|      0|            else {
  195|      0|                ++aiNumPerPType[3];
  196|      0|                numPolyVerts += pFirstFace->mNumIndices;
  197|      0|            }
  198|  7.36k|            if (pFirstFace->mNumIndices == 0) {
  ------------------
  |  Branch (198:17): [True: 0, False: 7.36k]
  ------------------
  199|      0|                ASSIMP_LOG_WARN("Face with 0 indices treated as polygon");
  200|      0|            }
  201|  7.36k|        }
  202|       |
  203|    171|        VertexWeightTable *avw = ComputeVertexBoneWeightTable(mesh);
  204|    855|        for (unsigned int real = 0; real < 4; ++real, ++meshIdx) {
  ------------------
  |  Branch (204:37): [True: 684, False: 171]
  ------------------
  205|    684|            if (!aiNumPerPType[real] || mConfigRemoveMeshes & (1u << real)) {
  ------------------
  |  Branch (205:17): [True: 172, False: 512]
  |  Branch (205:41): [True: 0, False: 512]
  ------------------
  206|    172|                continue;
  207|    172|            }
  208|       |
  209|    512|            *meshIdx = (unsigned int)outMeshes.size();
  210|    512|            outMeshes.push_back(new aiMesh());
  211|    512|            aiMesh *out = outMeshes.back();
  212|       |
  213|       |            // the name carries the adjacency information between the meshes
  214|    512|            out->mName = mesh->mName;
  215|       |
  216|       |            // copy data members
  217|    512|            out->mPrimitiveTypes = 1u << real;
  218|    512|            out->mMaterialIndex = mesh->mMaterialIndex;
  219|       |
  220|       |            // allocate output storage
  221|    512|            out->mNumFaces = aiNumPerPType[real];
  222|    512|            aiFace *outFaces = out->mFaces = new aiFace[out->mNumFaces];
  223|       |
  224|    512|            out->mNumVertices = (3 == real ? numPolyVerts : out->mNumFaces * (real + 1));
  ------------------
  |  Branch (224:34): [True: 0, False: 512]
  ------------------
  225|       |
  226|    512|            aiVector3D *vert(nullptr), *nor(nullptr), *tan(nullptr), *bit(nullptr);
  227|    512|            aiVector3D *uv[AI_MAX_NUMBER_OF_TEXTURECOORDS];
  228|    512|            aiColor4D *cols[AI_MAX_NUMBER_OF_COLOR_SETS];
  229|       |
  230|    512|            if (mesh->mVertices) {
  ------------------
  |  Branch (230:17): [True: 512, False: 0]
  ------------------
  231|    512|                vert = out->mVertices = new aiVector3D[out->mNumVertices];
  232|    512|            }
  233|       |
  234|    512|            if (mesh->mNormals) {
  ------------------
  |  Branch (234:17): [True: 498, False: 14]
  ------------------
  235|    498|                nor = out->mNormals = new aiVector3D[out->mNumVertices];
  236|    498|            }
  237|       |
  238|    512|            if (mesh->mTangents) {
  ------------------
  |  Branch (238:17): [True: 0, False: 512]
  ------------------
  239|      0|                tan = out->mTangents = new aiVector3D[out->mNumVertices];
  240|      0|                bit = out->mBitangents = new aiVector3D[out->mNumVertices];
  241|      0|            }
  242|       |
  243|  4.60k|            for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++j) {
  ------------------
  |  Branch (243:38): [True: 4.09k, False: 512]
  ------------------
  244|  4.09k|                uv[j] = nullptr;
  245|  4.09k|                if (mesh->mTextureCoords[j]) {
  ------------------
  |  Branch (245:21): [True: 497, False: 3.59k]
  ------------------
  246|    497|                    uv[j] = out->mTextureCoords[j] = new aiVector3D[out->mNumVertices];
  247|    497|                }
  248|       |
  249|  4.09k|                out->mNumUVComponents[j] = mesh->mNumUVComponents[j];
  250|  4.09k|            }
  251|       |
  252|  4.60k|            for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_COLOR_SETS; ++j) {
  ------------------
  |  Branch (252:38): [True: 4.09k, False: 512]
  ------------------
  253|  4.09k|                cols[j] = nullptr;
  254|  4.09k|                if (mesh->mColors[j]) {
  ------------------
  |  Branch (254:21): [True: 0, False: 4.09k]
  ------------------
  255|      0|                    cols[j] = out->mColors[j] = new aiColor4D[out->mNumVertices];
  256|      0|                }
  257|  4.09k|            }
  258|       |
  259|    512|            if (mesh->mNumAnimMeshes > 0 && mesh->mAnimMeshes) {
  ------------------
  |  Branch (259:17): [True: 0, False: 512]
  |  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|    512|            for (unsigned int j = 0; j < mesh->mNumAnimMeshes; ++j) {
  ------------------
  |  Branch (264:38): [True: 0, False: 512]
  ------------------
  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|    512|            typedef std::vector<aiVertexWeight> TempBoneInfo;
  299|    512|            std::vector<TempBoneInfo> tempBones(mesh->mNumBones);
  300|       |
  301|       |            // try to guess how much storage we'll need
  302|    512|            for (unsigned int q = 0; q < mesh->mNumBones; ++q) {
  ------------------
  |  Branch (302:38): [True: 0, False: 512]
  ------------------
  303|      0|                tempBones[q].reserve(mesh->mBones[q]->mNumWeights / (num - 1));
  304|      0|            }
  305|       |
  306|    512|            unsigned int outIdx = 0;
  307|    512|            unsigned int amIdx = 0; // AnimMesh index
  308|  22.6k|            for (unsigned int m = 0; m < mesh->mNumFaces; ++m) {
  ------------------
  |  Branch (308:38): [True: 22.0k, False: 512]
  ------------------
  309|  22.0k|                aiFace &in = mesh->mFaces[m];
  310|  22.0k|                if ((real == 3 && in.mNumIndices <= 3) || (real != 3 && in.mNumIndices != real + 1)) {
  ------------------
  |  Branch (310:22): [True: 0, False: 22.0k]
  |  Branch (310:35): [True: 0, False: 0]
  |  Branch (310:60): [True: 22.0k, False: 0]
  |  Branch (310:73): [True: 14.7k, False: 7.36k]
  ------------------
  311|  14.7k|                    continue;
  312|  14.7k|                }
  313|       |
  314|  7.36k|                outFaces->mNumIndices = in.mNumIndices;
  315|  7.36k|                outFaces->mIndices = in.mIndices;
  316|       |
  317|  25.9k|                for (unsigned int q = 0; q < in.mNumIndices; ++q) {
  ------------------
  |  Branch (317:42): [True: 18.5k, False: 7.36k]
  ------------------
  318|  18.5k|                    unsigned int idx = in.mIndices[q];
  319|       |
  320|       |                    // process all bones of this index
  321|  18.5k|                    if (avw) {
  ------------------
  |  Branch (321:25): [True: 0, False: 18.5k]
  ------------------
  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.5k|                    if (vert) {
  ------------------
  |  Branch (329:25): [True: 18.5k, False: 0]
  ------------------
  330|  18.5k|                        *vert++ = mesh->mVertices[idx];
  331|  18.5k|                    }
  332|  18.5k|                    if (nor)
  ------------------
  |  Branch (332:25): [True: 17.4k, False: 1.11k]
  ------------------
  333|  17.4k|                        *nor++ = mesh->mNormals[idx];
  334|  18.5k|                    if (tan) {
  ------------------
  |  Branch (334:25): [True: 0, False: 18.5k]
  ------------------
  335|      0|                        *tan++ = mesh->mTangents[idx];
  336|      0|                        *bit++ = mesh->mBitangents[idx];
  337|      0|                    }
  338|       |
  339|  35.9k|                    for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) {
  ------------------
  |  Branch (339:47): [True: 35.9k, False: 0]
  ------------------
  340|  35.9k|                        if (!uv[pp])
  ------------------
  |  Branch (340:29): [True: 18.5k, False: 17.3k]
  ------------------
  341|  18.5k|                            break;
  342|  17.3k|                        *uv[pp]++ = mesh->mTextureCoords[pp][idx];
  343|  17.3k|                    }
  344|       |
  345|  18.5k|                    for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) {
  ------------------
  |  Branch (345:47): [True: 18.5k, False: 0]
  ------------------
  346|  18.5k|                        if (!cols[pp])
  ------------------
  |  Branch (346:29): [True: 18.5k, False: 0]
  ------------------
  347|  18.5k|                            break;
  348|      0|                        *cols[pp]++ = mesh->mColors[pp][idx];
  349|      0|                    }
  350|       |
  351|  18.5k|                    unsigned int pp = 0;
  352|  18.5k|                    for (; pp < mesh->mNumAnimMeshes; ++pp) {
  ------------------
  |  Branch (352:28): [True: 0, False: 18.5k]
  ------------------
  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.5k|                    if (pp == mesh->mNumAnimMeshes)
  ------------------
  |  Branch (372:25): [True: 18.5k, False: 0]
  ------------------
  373|  18.5k|                        ++amIdx;
  374|       |
  375|  18.5k|                    in.mIndices[q] = outIdx++;
  376|  18.5k|                }
  377|       |
  378|  7.36k|                in.mIndices = nullptr;
  379|  7.36k|                ++outFaces;
  380|  7.36k|            }
  381|    512|            ai_assert(outFaces == out->mFaces + out->mNumFaces);
  382|       |
  383|       |            // now generate output bones
  384|    512|            for (unsigned int q = 0; q < mesh->mNumBones; ++q) {
  ------------------
  |  Branch (384:38): [True: 0, False: 512]
  ------------------
  385|      0|                if (!tempBones[q].empty()) {
  ------------------
  |  Branch (385:21): [True: 0, False: 0]
  ------------------
  386|      0|                    ++out->mNumBones;
  387|      0|                }
  388|      0|            }
  389|       |
  390|    512|            if (out->mNumBones) {
  ------------------
  |  Branch (390:17): [True: 0, False: 512]
  ------------------
  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|    512|        }
  413|       |
  414|       |        // delete the per-vertex bone weights table
  415|    171|        delete[] avw;
  416|       |
  417|       |        // delete the input mesh
  418|    171|        delete mesh;
  419|       |
  420|       |        // avoid invalid pointer
  421|    171|        pScene->mMeshes[i] = nullptr;
  422|    171|    }
  423|       |
  424|    150|    if (outMeshes.empty()) {
  ------------------
  |  Branch (424:9): [True: 0, False: 150]
  ------------------
  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|    150|    if (bAnyChanges) {
  ------------------
  |  Branch (431:9): [True: 62, False: 88]
  ------------------
  432|     62|        UpdateNodes(replaceMeshIndex, pScene->mRootNode);
  433|     62|    }
  434|       |
  435|    150|    if (outMeshes.size() != pScene->mNumMeshes) {
  ------------------
  |  Branch (435:9): [True: 62, False: 88]
  ------------------
  436|     62|        delete[] pScene->mMeshes;
  437|     62|        pScene->mNumMeshes = (unsigned int)outMeshes.size();
  438|     62|        pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
  439|     62|    }
  440|    150|    ::memcpy(pScene->mMeshes, &outMeshes[0], pScene->mNumMeshes * sizeof(void *));
  441|       |
  442|    150|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (442:9): [True: 0, False: 150]
  ------------------
  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|    150|}
SortByPTypeProcess.cpp:_ZL17clearMeshesInNodeP6aiNode:
   69|    173|static void clearMeshesInNode(aiNode *node) {
   70|    173|    delete[] node->mMeshes;
   71|    173|    node->mNumMeshes = 0;
   72|    173|    node->mMeshes = nullptr;
   73|    173|}

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

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

_ZN6Assimp32SplitLargeMeshesProcess_TriangleC2Ev:
   51|    402|SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() {
   52|       |    LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
   53|    402|}
_ZNK6Assimp32SplitLargeMeshesProcess_Triangle8IsActiveEj:
   57|    319|bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const {
   58|    319|    return (pFlags & aiProcess_SplitLargeMeshes) != 0;
   59|    319|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle7ExecuteEP7aiScene:
   63|    319|void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) {
   64|    319|    if (0xffffffff == this->LIMIT || nullptr == pScene ) {
  ------------------
  |  Branch (64:9): [True: 0, False: 319]
  |  Branch (64:38): [True: 0, False: 319]
  ------------------
   65|      0|        return;
   66|      0|    }
   67|       |
   68|    319|    ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle begin");
   69|    319|    std::vector<std::pair<aiMesh*, unsigned int> > avList;
   70|       |
   71|  1.16k|    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (71:30): [True: 843, False: 319]
  ------------------
   72|    843|        this->SplitMesh(a, pScene->mMeshes[a],avList);
   73|    843|    }
   74|       |
   75|    319|    if (avList.size() == pScene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 319, False: 0]
  ------------------
   76|    319|        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
   77|    319|    }
   78|       |
   79|       |    // it seems something has been split. rebuild the mesh list
   80|    319|    delete[] pScene->mMeshes;
   81|    319|    pScene->mNumMeshes = (unsigned int)avList.size();
   82|    319|    pScene->mMeshes = new aiMesh*[avList.size()];
   83|       |
   84|  1.16k|    for (unsigned int i = 0; i < avList.size();++i) {
  ------------------
  |  Branch (84:30): [True: 843, False: 319]
  ------------------
   85|    843|        pScene->mMeshes[i] = avList[i].first;
   86|    843|    }
   87|       |
   88|       |    // now we need to update all nodes
   89|    319|    this->UpdateNode(pScene->mRootNode,avList);
   90|       |    ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
   91|    319|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle15SetupPropertiesEPKNS_8ImporterE:
   95|    319|void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) {
   96|       |    // get the current value of the split property
   97|    319|    this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
   98|    319|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle10UpdateNodeEP6aiNodeRKNSt3__16vectorINS3_4pairIP6aiMeshjEENS3_9allocatorIS8_EEEE:
  102|  6.39k|void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  103|  6.39k|    if (pcNode == nullptr) {
  ------------------
  |  Branch (103:9): [True: 0, False: 6.39k]
  ------------------
  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|  6.39k|    std::vector<unsigned int> aiEntries;
  110|  6.39k|    aiEntries.reserve(pcNode->mNumMeshes + 1);
  111|  7.24k|    for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) {
  ------------------
  |  Branch (111:30): [True: 847, False: 6.39k]
  ------------------
  112|  11.6k|        for (unsigned int a = 0; a < avList.size();++a) {
  ------------------
  |  Branch (112:34): [True: 10.7k, False: 847]
  ------------------
  113|  10.7k|            if (avList[a].second == pcNode->mMeshes[i]) {
  ------------------
  |  Branch (113:17): [True: 847, False: 9.90k]
  ------------------
  114|    847|                aiEntries.push_back(a);
  115|    847|            }
  116|  10.7k|        }
  117|    847|    }
  118|       |
  119|       |    // now build the new list
  120|  6.39k|    delete[] pcNode->mMeshes;
  121|  6.39k|    pcNode->mNumMeshes = (unsigned int)aiEntries.size();
  122|  6.39k|    pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
  123|       |
  124|  7.24k|    for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) {
  ------------------
  |  Branch (124:30): [True: 847, False: 6.39k]
  ------------------
  125|    847|        pcNode->mMeshes[b] = aiEntries[b];
  126|    847|    }
  127|       |
  128|       |    // recursively update all other nodes
  129|  12.4k|    for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
  ------------------
  |  Branch (129:30): [True: 6.08k, False: 6.39k]
  ------------------
  130|  6.08k|        UpdateNode ( pcNode->mChildren[i], avList );
  131|  6.08k|    }
  132|  6.39k|}
_ZN6Assimp32SplitLargeMeshesProcess_Triangle9SplitMeshEjP6aiMeshRNSt3__16vectorINS3_4pairIS2_jEENS3_9allocatorIS6_EEEE:
  139|    843|        std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  140|    843|    if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT) {
  ------------------
  |  Branch (140:9): [True: 0, False: 843]
  ------------------
  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|    843|    } else {
  321|    843|        avList.emplace_back(pMesh,a);
  322|    843|    }
  323|    843|}
_ZN6Assimp30SplitLargeMeshesProcess_VertexC2Ev:
  326|    402|SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() {
  327|       |    LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
  328|    402|}
_ZNK6Assimp30SplitLargeMeshesProcess_Vertex8IsActiveEj:
  332|    319|bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const {
  333|    319|    return (pFlags & aiProcess_SplitLargeMeshes) != 0;
  334|    319|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex7ExecuteEP7aiScene:
  338|    319|void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) {
  339|    319|    if (0xffffffff == this->LIMIT || nullptr == pScene ) {
  ------------------
  |  Branch (339:9): [True: 0, False: 319]
  |  Branch (339:38): [True: 0, False: 319]
  ------------------
  340|      0|        return;
  341|      0|    }
  342|       |
  343|    319|    ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex begin");
  344|       |
  345|    319|    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|  1.16k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (349:30): [True: 843, False: 319]
  ------------------
  350|    843|        if ( pScene->mMeshes[a]->mPrimitiveTypes == aiPrimitiveType_POINT ) {
  ------------------
  |  Branch (350:14): [True: 0, False: 843]
  ------------------
  351|      0|            return;
  352|      0|        }
  353|    843|    }
  354|       |
  355|  1.16k|    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
  ------------------
  |  Branch (355:30): [True: 843, False: 319]
  ------------------
  356|    843|        this->SplitMesh(a, pScene->mMeshes[a], avList);
  357|    843|    }
  358|       |
  359|    319|    if (avList.size() != pScene->mNumMeshes) {
  ------------------
  |  Branch (359:9): [True: 0, False: 319]
  ------------------
  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|    319|    } else {
  373|       |        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex finished. There was nothing to do");
  374|    319|    }
  375|    319|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex15SetupPropertiesEPKNS_8ImporterE:
  379|    319|void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) {
  380|    319|    this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
  381|    319|}
_ZN6Assimp30SplitLargeMeshesProcess_Vertex9SplitMeshEjP6aiMeshRNSt3__16vectorINS3_4pairIS2_jEENS3_9allocatorIS6_EEEE:
  388|    843|        std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
  389|    843|    if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT) {
  ------------------
  |  Branch (389:9): [True: 0, False: 843]
  ------------------
  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|    843|    avList.emplace_back(pMesh,a);
  615|    843|}

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

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

_ZNK6Assimp18TriangulateProcess8IsActiveEj:
  179|    319|bool TriangulateProcess::IsActive( unsigned int pFlags) const {
  180|    319|    return (pFlags & aiProcess_Triangulate) != 0;
  181|    319|}
_ZN6Assimp18TriangulateProcess7ExecuteEP7aiScene:
  185|    319|void TriangulateProcess::Execute( aiScene* pScene) {
  186|    319|    ASSIMP_LOG_DEBUG("TriangulateProcess begin");
  187|       |
  188|    319|    bool bHas = false;
  189|    991|    for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
  ------------------
  |  Branch (189:30): [True: 672, False: 319]
  ------------------
  190|    672|    {
  191|    672|        if (pScene->mMeshes[ a ]) {
  ------------------
  |  Branch (191:13): [True: 672, False: 0]
  ------------------
  192|    672|            if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
  ------------------
  |  Branch (192:18): [True: 89, False: 583]
  ------------------
  193|     89|                bHas = true;
  194|     89|            }
  195|    672|        }
  196|    672|    }
  197|    319|    if ( bHas ) {
  ------------------
  |  Branch (197:10): [True: 82, False: 237]
  ------------------
  198|     82|        ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." );
  199|    237|    } else {
  200|       |        ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." );
  201|    237|    }
  202|    319|}
_ZN6Assimp18TriangulateProcess15TriangulateMeshEP6aiMesh:
  206|    672|bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) {
  207|       |    // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
  208|    672|    if (!pMesh->mPrimitiveTypes)    {
  ------------------
  |  Branch (208:9): [True: 0, False: 672]
  ------------------
  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|    672|    else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (221:14): [True: 583, False: 89]
  ------------------
  222|    583|        return false;
  223|    583|    }
  224|       |
  225|       |    // Find out how many output faces we'll get
  226|     89|    uint32_t numOut = 0, max_out = 0;
  227|     89|    bool get_normals = true;
  228|  71.1k|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (228:30): [True: 71.0k, False: 89]
  ------------------
  229|  71.0k|        aiFace& face = pMesh->mFaces[a];
  230|  71.0k|        if (face.mNumIndices <= 4) {
  ------------------
  |  Branch (230:13): [True: 71.0k, False: 4]
  ------------------
  231|  71.0k|            get_normals = false;
  232|  71.0k|        }
  233|  71.0k|        if( face.mNumIndices <= 3) {
  ------------------
  |  Branch (233:13): [True: 13, False: 71.0k]
  ------------------
  234|     13|            ++numOut;
  235|  71.0k|        } else {
  236|  71.0k|            numOut += face.mNumIndices-2;
  237|  71.0k|            max_out = std::max<uint32_t>(max_out,face.mNumIndices);
  238|  71.0k|        }
  239|  71.0k|    }
  240|       |
  241|       |    // Just another check whether aiMesh::mPrimitiveTypes is correct
  242|     89|    if (numOut == pMesh->mNumFaces) {
  ------------------
  |  Branch (242:9): [True: 0, False: 89]
  ------------------
  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|     89|    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|     89|    if (!pMesh->mNormals && get_normals) {
  ------------------
  |  Branch (251:9): [True: 43, False: 46]
  |  Branch (251:29): [True: 0, False: 43]
  ------------------
  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|     89|    pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  258|     89|    pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
  259|       |
  260|       |    // The mesh becomes NGON encoded now, during the triangulation process.
  261|     89|    pMesh->mPrimitiveTypes |= aiPrimitiveType_NGONEncodingFlag;
  262|       |
  263|     89|    aiFace* out = new aiFace[numOut](), *curOut = out;
  264|     89|    std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */
  265|     89|    std::vector<std::vector<aiVector2D>> temp_poly(1); /* temporary storage for earcut.hpp */
  266|     89|    std::vector<aiVector2D>& temp_verts = temp_poly[0];
  267|     89|    temp_verts.reserve(max_out + 2);
  268|       |
  269|     89|    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|     89|    const aiVector3D* verts = pMesh->mVertices;
  286|       |
  287|  71.1k|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (287:30): [True: 71.0k, False: 89]
  ------------------
  288|  71.0k|        aiFace& face = pMesh->mFaces[a];
  289|       |
  290|  71.0k|        unsigned int* idx = face.mIndices;
  291|  71.0k|        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|  71.0k|        aiFace* const last_face = curOut;
  303|       |
  304|       |        // if it's a simple point,line or triangle: just copy it
  305|  71.0k|        if( face.mNumIndices <= 3)
  ------------------
  |  Branch (305:13): [True: 13, False: 71.0k]
  ------------------
  306|     13|        {
  307|     13|            aiFace& nface = *curOut++;
  308|     13|            nface.mNumIndices = face.mNumIndices;
  309|     13|            nface.mIndices    = face.mIndices;
  310|     13|            face.mIndices = nullptr;
  311|       |
  312|       |            // points and lines don't require ngon encoding (and are not supported either!)
  313|     13|            if (nface.mNumIndices == 3) ngonEncoder.ngonEncodeTriangle(&nface);
  ------------------
  |  Branch (313:17): [True: 13, False: 0]
  ------------------
  314|       |
  315|     13|            continue;
  316|     13|        }
  317|       |        // optimized code for quadrilaterals
  318|  71.0k|        else if ( face.mNumIndices == 4) {
  ------------------
  |  Branch (318:19): [True: 71.0k, False: 4]
  ------------------
  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|  71.0k|            unsigned int start_vertex = 0;
  324|   354k|            for (unsigned int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (324:38): [True: 283k, False: 70.9k]
  ------------------
  325|   283k|                const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]];
  326|   283k|                const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]];
  327|   283k|                const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]];
  328|       |
  329|   283k|                const aiVector3D& v = verts[face.mIndices[i]];
  330|       |
  331|   283k|                aiVector3D left = (v0-v);
  332|   283k|                aiVector3D diag = (v1-v);
  333|   283k|                aiVector3D right = (v2-v);
  334|       |
  335|   283k|                left.Normalize();
  336|   283k|                diag.Normalize();
  337|   283k|                right.Normalize();
  338|       |
  339|   283k|                const float angle = std::acos(left*diag) + std::acos(right*diag);
  340|   283k|                if (angle > AI_MATH_PI_F) {
  ------------------
  |  Branch (340:21): [True: 35, False: 283k]
  ------------------
  341|       |                    // this is the concave point
  342|     35|                    start_vertex = i;
  343|     35|                    break;
  344|     35|                }
  345|   283k|            }
  346|       |
  347|  71.0k|            const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]};
  348|       |
  349|  71.0k|            aiFace& nface = *curOut++;
  350|  71.0k|            nface.mNumIndices = 3;
  351|  71.0k|            nface.mIndices = face.mIndices;
  352|       |
  353|  71.0k|            nface.mIndices[0] = temp[start_vertex];
  354|  71.0k|            nface.mIndices[1] = temp[(start_vertex + 1) % 4];
  355|  71.0k|            nface.mIndices[2] = temp[(start_vertex + 2) % 4];
  356|       |
  357|  71.0k|            aiFace& sface = *curOut++;
  358|  71.0k|            sface.mNumIndices = 3;
  359|  71.0k|            sface.mIndices = new unsigned int[3];
  360|       |
  361|  71.0k|            sface.mIndices[0] = temp[start_vertex];
  362|  71.0k|            sface.mIndices[1] = temp[(start_vertex + 2) % 4];
  363|  71.0k|            sface.mIndices[2] = temp[(start_vertex + 3) % 4];
  364|       |
  365|       |            // prevent double deletion of the indices field
  366|  71.0k|            face.mIndices = nullptr;
  367|       |
  368|  71.0k|            ngonEncoder.ngonEncodeQuad(&nface, &sface);
  369|       |
  370|  71.0k|            continue;
  371|  71.0k|        }
  372|      4|        else
  373|      4|        {
  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|    144|            for (unsigned int tmp = 0; tmp < num; ++tmp) {
  ------------------
  |  Branch (384:40): [True: 140, False: 4]
  ------------------
  385|    140|                temp_verts3d[tmp] = verts[idx[tmp]];
  386|    140|            }
  387|       |
  388|       |            // Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh
  389|      4|            aiVector3D n;
  390|      4|            NewellNormal<3, 3, 3>(n, num, &temp_verts3d.front().x, &temp_verts3d.front().y, &temp_verts3d.front().z);
  391|      4|            if (nor_out) {
  ------------------
  |  Branch (391:17): [True: 0, False: 4]
  ------------------
  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|      4|            const float ax = (n.x>0 ? n.x : -n.x);
  ------------------
  |  Branch (397:31): [True: 0, False: 4]
  ------------------
  398|      4|            const float ay = (n.y>0 ? n.y : -n.y);
  ------------------
  |  Branch (398:31): [True: 2, False: 2]
  ------------------
  399|      4|            const float az = (n.z>0 ? n.z : -n.z);
  ------------------
  |  Branch (399:31): [True: 0, False: 4]
  ------------------
  400|       |
  401|      4|            unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */
  402|      4|            float inv = n.z;
  403|      4|            if (ax > ay) {
  ------------------
  |  Branch (403:17): [True: 1, False: 3]
  ------------------
  404|      1|                if (ax > az) { /* no x coord. projection to yz */
  ------------------
  |  Branch (404:21): [True: 0, False: 1]
  ------------------
  405|      0|                    ac = 1; bc = 2;
  406|      0|                    inv = n.x;
  407|      0|                }
  408|      1|            }
  409|      3|            else if (ay > az) { /* no y coord. projection to zy */
  ------------------
  |  Branch (409:22): [True: 1, False: 2]
  ------------------
  410|      1|                ac = 2; bc = 0;
  411|      1|                inv = n.y;
  412|      1|            }
  413|       |
  414|       |            // Swap projection axes to take the negated projection vector into account
  415|      4|            if (inv < 0.f) {
  ------------------
  |  Branch (415:17): [True: 2, False: 2]
  ------------------
  416|      2|                std::swap(ac,bc);
  417|      2|            }
  418|       |
  419|      4|            temp_verts.resize(num);
  420|    144|            for (unsigned int tmp = 0; tmp < num; ++tmp) {
  ------------------
  |  Branch (420:40): [True: 140, False: 4]
  ------------------
  421|    140|                temp_verts[tmp].x = verts[idx[tmp]][ac];
  422|    140|                temp_verts[tmp].y = verts[idx[tmp]][bc];
  423|    140|            }
  424|       |
  425|      4|            auto indices = mapbox::earcut(temp_poly);
  426|     10|            for (size_t i = 0; i < indices.size(); i += 3) {
  ------------------
  |  Branch (426:32): [True: 6, False: 4]
  ------------------
  427|      6|                aiFace& nface = *curOut++;
  428|      6|                nface.mIndices = new unsigned int[3];
  429|      6|                nface.mNumIndices = 3;
  430|      6|                nface.mIndices[0] = indices[i];
  431|      6|                nface.mIndices[1] = indices[i + 1];
  432|      6|                nface.mIndices[2] = indices[i + 2];
  433|      6|            }
  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|      4|        }
  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|     10|        for(aiFace* f = last_face; f != curOut; ) {
  ------------------
  |  Branch (476:36): [True: 6, False: 4]
  ------------------
  477|      6|            unsigned int* i = f->mIndices;
  478|       |
  479|      6|            i[0] = idx[i[0]];
  480|      6|            i[1] = idx[i[1]];
  481|      6|            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|      6|            ngonEncoder.ngonEncodeTriangle(f);
  487|      6|            ++f;
  488|      6|        }
  489|       |
  490|      4|        delete[] face.mIndices;
  491|      4|        face.mIndices = nullptr;
  492|      4|    }
  493|       |
  494|       |#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
  495|       |    fclose(fout);
  496|       |#endif
  497|       |
  498|       |    // kill the old faces
  499|     89|    delete [] pMesh->mFaces;
  500|       |
  501|       |    // ... and store the new ones
  502|     89|    pMesh->mFaces    = out;
  503|     89|    pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */
  504|     89|    return true;
  505|     89|}
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoderC2Ev:
  103|     89|        NGONEncoder() : mLastNGONFirstIndex((unsigned int)-1) {}
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoder18ngonEncodeTriangleEP6aiFace:
  114|     19|        void ngonEncodeTriangle(aiFace * tri) {
  115|     19|            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|     19|            if (isConsideredSameAsLastNgon(tri)) {
  ------------------
  |  Branch (119:17): [True: 0, False: 19]
  ------------------
  120|      0|                std::swap(tri->mIndices[0], tri->mIndices[2]);
  121|      0|                std::swap(tri->mIndices[1], tri->mIndices[2]);
  122|      0|            }
  123|       |
  124|     19|            mLastNGONFirstIndex = tri->mIndices[0];
  125|     19|        }
TriangulateProcess.cpp:_ZNK12_GLOBAL__N_111NGONEncoder26isConsideredSameAsLastNgonEPK6aiFace:
  166|  71.0k|        bool isConsideredSameAsLastNgon(const aiFace * tri) const {
  167|       |            ai_assert(tri->mNumIndices == 3);
  168|  71.0k|            return tri->mIndices[0] == mLastNGONFirstIndex;
  169|  71.0k|        }
TriangulateProcess.cpp:_ZN12_GLOBAL__N_111NGONEncoder14ngonEncodeQuadEP6aiFaceS2_:
  135|  71.0k|        void ngonEncodeQuad(aiFace *tri1, aiFace *tri2) {
  136|  71.0k|            ai_assert(tri1->mNumIndices == 3);
  137|  71.0k|            ai_assert(tri2->mNumIndices == 3);
  138|  71.0k|            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|  71.0k|            if (isConsideredSameAsLastNgon(tri1)) {
  ------------------
  |  Branch (144:17): [True: 0, False: 71.0k]
  ------------------
  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|  71.0k|            mLastNGONFirstIndex = tri1->mIndices[0];
  157|  71.0k|        }
_ZN6mapbox4util3nthILm0E10aiVector2tIfEE3getERKS3_:
   82|    420|    inline static auto get(const aiVector2D& t) {
   83|    420|        return t.x;
   84|    420|    }
_ZN6mapbox4util3nthILm1E10aiVector2tIfEE3getERKS3_:
   88|    420|    inline static auto get(const aiVector2D& t) {
   89|    420|        return t.y;
   90|    420|    }

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

_ZN6Assimp17ValidateDSProcessC2Ev:
   61|    337|ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {}
_ZN6Assimp17ValidateDSProcess11ReportErrorEPKcz:
   69|     18|AI_WONT_RETURN void ValidateDSProcess::ReportError(const char *msg, ...) {
   70|     18|    ai_assert(nullptr != msg);
   71|       |
   72|     18|    va_list args;
   73|     18|    va_start(args, msg);
   74|       |
   75|     18|    char szBuffer[3000];
   76|     18|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   77|     18|    ai_assert(iLen > 0);
   78|       |
   79|     18|    va_end(args);
   80|       |
   81|     18|    throw DeadlyImportError("Validation failed: ", std::string(szBuffer, iLen));
   82|     18|}
_ZN6Assimp17ValidateDSProcess13ReportWarningEPKcz:
   84|   212k|void ValidateDSProcess::ReportWarning(const char *msg, ...) {
   85|   212k|    ai_assert(nullptr != msg);
   86|       |
   87|   212k|    va_list args;
   88|   212k|    va_start(args, msg);
   89|       |
   90|   212k|    char szBuffer[3000];
   91|   212k|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   92|   212k|    ai_assert(iLen > 0);
   93|       |
   94|   212k|    va_end(args);
   95|       |    ASSIMP_LOG_WARN("Validation warning: ", std::string(szBuffer, iLen));
   96|   212k|}
_ZN6Assimp17ValidateDSProcess7ExecuteEP7aiScene:
  183|    337|void ValidateDSProcess::Execute(aiScene *pScene) {
  184|    337|    mScene = pScene;
  185|    337|    ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin");
  186|       |
  187|       |    // validate the node graph of the scene
  188|    337|    Validate(pScene->mRootNode);
  189|       |
  190|       |    // validate all meshes
  191|    337|    if (pScene->mNumMeshes) {
  ------------------
  |  Branch (191:9): [True: 151, False: 186]
  ------------------
  192|    151|        DoValidation(pScene->mMeshes, pScene->mNumMeshes, "mMeshes", "mNumMeshes");
  193|    186|    } else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
  ------------------
  |  Branch (193:16): [True: 0, False: 186]
  ------------------
  194|      0|        ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
  195|    186|    } else if (pScene->mMeshes) {
  ------------------
  |  Branch (195:16): [True: 0, False: 186]
  ------------------
  196|      0|        ReportError("aiScene::mMeshes is non-null although there are no meshes");
  197|      0|    }
  198|       |
  199|       |    // validate all animations
  200|    337|    if (pScene->mNumAnimations) {
  ------------------
  |  Branch (200:9): [True: 213, False: 124]
  ------------------
  201|    213|        DoValidation(pScene->mAnimations, pScene->mNumAnimations,
  202|    213|                "mAnimations", "mNumAnimations");
  203|    213|    } else if (pScene->mAnimations) {
  ------------------
  |  Branch (203:16): [True: 0, False: 124]
  ------------------
  204|      0|        ReportError("aiScene::mAnimations is non-null although there are no animations");
  205|      0|    }
  206|       |
  207|       |    // validate all cameras
  208|    337|    if (pScene->mNumCameras) {
  ------------------
  |  Branch (208:9): [True: 269, False: 68]
  ------------------
  209|    269|        DoValidationWithNameCheck(pScene->mCameras, pScene->mNumCameras,
  210|    269|                "mCameras", "mNumCameras");
  211|    269|    } else if (pScene->mCameras) {
  ------------------
  |  Branch (211:16): [True: 0, False: 68]
  ------------------
  212|      0|        ReportError("aiScene::mCameras is non-null although there are no cameras");
  213|      0|    }
  214|       |
  215|       |    // validate all lights
  216|    337|    if (pScene->mNumLights) {
  ------------------
  |  Branch (216:9): [True: 255, False: 82]
  ------------------
  217|    255|        DoValidationWithNameCheck(pScene->mLights, pScene->mNumLights,
  218|    255|                "mLights", "mNumLights");
  219|    255|    } else if (pScene->mLights) {
  ------------------
  |  Branch (219:16): [True: 0, False: 82]
  ------------------
  220|      0|        ReportError("aiScene::mLights is non-null although there are no lights");
  221|      0|    }
  222|       |
  223|       |    // validate all textures
  224|    337|    if (pScene->mNumTextures) {
  ------------------
  |  Branch (224:9): [True: 6, False: 331]
  ------------------
  225|      6|        DoValidation(pScene->mTextures, pScene->mNumTextures,
  226|      6|                "mTextures", "mNumTextures");
  227|    331|    } else if (pScene->mTextures) {
  ------------------
  |  Branch (227:16): [True: 0, False: 331]
  ------------------
  228|      0|        ReportError("aiScene::mTextures is non-null although there are no textures");
  229|      0|    }
  230|       |
  231|       |    // validate all materials
  232|    337|    if (pScene->mNumMaterials) {
  ------------------
  |  Branch (232:9): [True: 150, False: 187]
  ------------------
  233|    150|        DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials");
  234|    150|    }
  235|    187|    else if (pScene->mMaterials) {
  ------------------
  |  Branch (235:14): [True: 0, False: 187]
  ------------------
  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|    337|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK7aiLight:
  244|    255|void ValidateDSProcess::Validate(const aiLight *pLight) {
  245|    255|    if (pLight->mType == aiLightSource_UNDEFINED)
  ------------------
  |  Branch (245:9): [True: 0, False: 255]
  ------------------
  246|      0|        ReportWarning("aiLight::mType is aiLightSource_UNDEFINED");
  247|       |
  248|    255|    if (!pLight->mAttenuationConstant &&
  ------------------
  |  Branch (248:9): [True: 255, False: 0]
  ------------------
  249|    255|            !pLight->mAttenuationLinear &&
  ------------------
  |  Branch (249:13): [True: 255, False: 0]
  ------------------
  250|    255|            !pLight->mAttenuationQuadratic) {
  ------------------
  |  Branch (250:13): [True: 1, False: 254]
  ------------------
  251|      1|        ReportWarning("aiLight::mAttenuationXXX - all are zero");
  252|      1|    }
  253|       |
  254|    255|    if (pLight->mAngleInnerCone > pLight->mAngleOuterCone)
  ------------------
  |  Branch (254:9): [True: 0, False: 255]
  ------------------
  255|      0|        ReportError("aiLight::mAngleInnerCone is larger than aiLight::mAngleOuterCone");
  256|       |
  257|    255|    if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack() && pLight->mColorSpecular.IsBlack()) {
  ------------------
  |  Branch (257:9): [True: 0, False: 255]
  |  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|    255|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiCamera:
  263|    269|void ValidateDSProcess::Validate(const aiCamera *pCamera) {
  264|    269|    if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear)
  ------------------
  |  Branch (264:9): [True: 0, False: 269]
  ------------------
  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|    269|    if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI)
  ------------------
  |  Branch (268:9): [True: 0, False: 269]
  |  Branch (268:37): [True: 0, False: 269]
  ------------------
  269|      0|        ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV);
  270|    269|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMesh:
  273|    673|void ValidateDSProcess::Validate(const aiMesh *pMesh) {
  274|       |    // validate the material index of the mesh
  275|    673|    if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) {
  ------------------
  |  Branch (275:9): [True: 673, False: 0]
  |  Branch (275:34): [True: 0, False: 673]
  ------------------
  276|      0|        ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)",
  277|      0|                pMesh->mMaterialIndex, mScene->mNumMaterials - 1);
  278|      0|    }
  279|       |
  280|    673|    Validate(&pMesh->mName);
  281|       |
  282|   112k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (282:30): [True: 112k, False: 673]
  ------------------
  283|   112k|        aiFace &face = pMesh->mFaces[i];
  284|       |
  285|   112k|        if (pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (285:13): [True: 112k, False: 0]
  ------------------
  286|   112k|            switch (face.mNumIndices) {
  287|      0|            case 0:
  ------------------
  |  Branch (287:13): [True: 0, False: 112k]
  ------------------
  288|      0|                ReportError("aiMesh::mFaces[%i].mNumIndices is 0", i);
  289|      0|            case 1:
  ------------------
  |  Branch (289:13): [True: 0, False: 112k]
  ------------------
  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|      0|            case 2:
  ------------------
  |  Branch (296:13): [True: 0, False: 112k]
  ------------------
  297|      0|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE)) {
  ------------------
  |  Branch (297:21): [True: 0, False: 0]
  ------------------
  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|      0|                break;
  303|  40.1k|            case 3:
  ------------------
  |  Branch (303:13): [True: 40.1k, False: 72.0k]
  ------------------
  304|  40.1k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) {
  ------------------
  |  Branch (304:21): [True: 0, False: 40.1k]
  ------------------
  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|  40.1k|                break;
  310|  72.0k|            default:
  ------------------
  |  Branch (310:13): [True: 72.0k, False: 40.1k]
  ------------------
  311|  72.0k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (311:21): [True: 0, False: 72.0k]
  ------------------
  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|  72.0k|                break;
  317|   112k|            };
  318|   112k|        }
  319|       |
  320|   112k|        if (!face.mIndices)
  ------------------
  |  Branch (320:13): [True: 0, False: 112k]
  ------------------
  321|      0|            ReportError("aiMesh::mFaces[%i].mIndices is nullptr", i);
  322|   112k|    }
  323|       |
  324|       |    // positions must always be there ...
  325|    673|    if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) {
  ------------------
  |  Branch (325:9): [True: 0, False: 673]
  |  Branch (325:34): [True: 0, False: 673]
  |  Branch (325:55): [True: 0, False: 0]
  ------------------
  326|      0|        ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str());
  327|      0|    }
  328|       |
  329|    673|    if (pMesh->mNumVertices > AI_MAX_VERTICES) {
  ------------------
  |  Branch (329:9): [True: 0, False: 673]
  ------------------
  330|      0|        ReportError("Mesh has too many vertices: %u, but the limit is %u", pMesh->mNumVertices, AI_MAX_VERTICES);
  331|      0|    }
  332|    673|    if (pMesh->mNumFaces > AI_MAX_FACES) {
  ------------------
  |  Branch (332:9): [True: 0, False: 673]
  ------------------
  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|    673|    if ((pMesh->mTangents != nullptr) != (pMesh->mBitangents != nullptr)) {
  ------------------
  |  Branch (337:9): [True: 0, False: 673]
  ------------------
  338|      0|        ReportError("If there are tangents, bitangent vectors must be present as well");
  339|      0|    }
  340|       |
  341|       |    // faces, too
  342|    673|    if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) {
  ------------------
  |  Branch (342:9): [True: 0, False: 673]
  |  Branch (342:31): [True: 0, False: 673]
  |  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|    673|    std::vector<bool> abRefList;
  349|    673|    abRefList.resize(pMesh->mNumVertices, false);
  350|   112k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (350:30): [True: 112k, False: 673]
  ------------------
  351|   112k|        aiFace &face = pMesh->mFaces[i];
  352|   112k|        if (face.mNumIndices > AI_MAX_FACE_INDICES) {
  ------------------
  |  Branch (352:13): [True: 0, False: 112k]
  ------------------
  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|   520k|        for (unsigned int a = 0; a < face.mNumIndices; ++a) {
  ------------------
  |  Branch (356:34): [True: 408k, False: 112k]
  ------------------
  357|   408k|            if (face.mIndices[a] >= pMesh->mNumVertices) {
  ------------------
  |  Branch (357:17): [True: 0, False: 408k]
  ------------------
  358|      0|                ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a);
  359|      0|            }
  360|   408k|            abRefList[face.mIndices[a]] = true;
  361|   408k|        }
  362|   112k|    }
  363|       |
  364|       |    // check whether there are vertices that aren't referenced by a face
  365|    673|    bool b = false;
  366|  24.4M|    for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (366:30): [True: 24.4M, False: 673]
  ------------------
  367|  24.4M|        if (!abRefList[i]) b = true;
  ------------------
  |  Branch (367:13): [True: 23.9M, False: 408k]
  ------------------
  368|  24.4M|    }
  369|    673|    abRefList.clear();
  370|    673|    if (b) {
  ------------------
  |  Branch (370:9): [True: 7, False: 666]
  ------------------
  371|      7|        ReportWarning("There are unreferenced vertices");
  372|      7|    }
  373|       |
  374|       |    // vertex color channel 2 may not be set if channel 1 is zero ...
  375|    673|    {
  376|    673|        unsigned int i = 0;
  377|    673|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
  ------------------
  |  Branch (377:16): [True: 673, False: 0]
  ------------------
  378|    673|            if (!pMesh->HasVertexColors(i)) break;
  ------------------
  |  Branch (378:17): [True: 673, False: 0]
  ------------------
  379|    673|        }
  380|  6.05k|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i)
  ------------------
  |  Branch (380:16): [True: 5.38k, False: 673]
  ------------------
  381|  5.38k|            if (pMesh->HasVertexColors(i)) {
  ------------------
  |  Branch (381:17): [True: 0, False: 5.38k]
  ------------------
  382|      0|                ReportError("Vertex color channel %i is exists "
  383|      0|                            "although the previous channel was nullptr.",
  384|      0|                        i);
  385|      0|            }
  386|    673|    }
  387|       |
  388|       |    // now validate all bones
  389|    673|    if (pMesh->mNumBones) {
  ------------------
  |  Branch (389:9): [True: 67, False: 606]
  ------------------
  390|     67|        if (!pMesh->mBones) {
  ------------------
  |  Branch (390:13): [True: 0, False: 67]
  ------------------
  391|      0|            ReportError("aiMesh::mBones is nullptr (aiMesh::mNumBones is %i)",
  392|      0|                    pMesh->mNumBones);
  393|      0|        }
  394|     67|        std::unique_ptr<float[]> afSum(nullptr);
  395|     67|        if (pMesh->mNumVertices) {
  ------------------
  |  Branch (395:13): [True: 67, False: 0]
  ------------------
  396|     67|            afSum.reset(new float[pMesh->mNumVertices]);
  397|   283k|            for (unsigned int i = 0; i < pMesh->mNumVertices; ++i)
  ------------------
  |  Branch (397:38): [True: 283k, False: 67]
  ------------------
  398|   283k|                afSum[i] = 0.0f;
  399|     67|        }
  400|       |
  401|       |        // check whether there are duplicate bone names
  402|    694|        for (unsigned int i = 0; i < pMesh->mNumBones; ++i) {
  ------------------
  |  Branch (402:34): [True: 627, False: 67]
  ------------------
  403|    627|            const aiBone *bone = pMesh->mBones[i];
  404|    627|            if (bone->mNumWeights > AI_MAX_BONE_WEIGHTS) {
  ------------------
  |  Branch (404:17): [True: 0, False: 627]
  ------------------
  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|    627|            if (!pMesh->mBones[i]) {
  ------------------
  |  Branch (408:17): [True: 0, False: 627]
  ------------------
  409|      0|                ReportError("aiMesh::mBones[%i] is nullptr (aiMesh::mNumBones is %i)",
  410|      0|                        i, pMesh->mNumBones);
  411|      0|            }
  412|    627|            Validate(pMesh, pMesh->mBones[i], afSum.get());
  413|       |
  414|  3.50k|            for (unsigned int a = i + 1; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (414:42): [True: 2.87k, False: 627]
  ------------------
  415|  2.87k|                if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName) {
  ------------------
  |  Branch (415:21): [True: 0, False: 2.87k]
  ------------------
  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.87k|            }
  425|    627|        }
  426|       |        // check whether all bone weights for a vertex sum to 1.0 ...
  427|   283k|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (427:34): [True: 283k, False: 67]
  ------------------
  428|   283k|            if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) {
  ------------------
  |  Branch (428:17): [True: 269k, False: 13.2k]
  |  Branch (428:30): [True: 206k, False: 63.5k]
  |  Branch (428:50): [True: 6.42k, False: 57.1k]
  ------------------
  429|   212k|                ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)", i, afSum[i]);
  430|   212k|            }
  431|   283k|        }
  432|    606|    } else if (pMesh->mBones) {
  ------------------
  |  Branch (432:16): [True: 0, False: 606]
  ------------------
  433|      0|        ReportError("aiMesh::mBones is non-null although there are no bones");
  434|      0|    }
  435|    673|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMeshPK6aiBonePf:
  438|    627|void ValidateDSProcess::Validate(const aiMesh *pMesh, const aiBone *pBone, float *afSum) {
  439|    627|    this->Validate(&pBone->mName);
  440|       |
  441|    627|    if (!pBone->mNumWeights) {
  ------------------
  |  Branch (441:9): [True: 0, False: 627]
  ------------------
  442|      0|        ReportWarning("aiBone::mNumWeights is zero");
  443|      0|    }
  444|       |
  445|       |    // check whether all vertices affected by this bone are valid
  446|   879k|    for (unsigned int i = 0; i < pBone->mNumWeights; ++i) {
  ------------------
  |  Branch (446:30): [True: 879k, False: 627]
  ------------------
  447|   879k|        if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) {
  ------------------
  |  Branch (447:13): [True: 0, False: 879k]
  ------------------
  448|      0|            ReportError("aiBone::mWeights[%i].mVertexId is out of range", i);
  449|   879k|        } else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) {
  ------------------
  |  Branch (449:20): [True: 0, False: 879k]
  |  Branch (449:51): [True: 0, False: 879k]
  ------------------
  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|   879k|        afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight;
  453|   879k|    }
  454|    627|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK11aiAnimation:
  457|    213|void ValidateDSProcess::Validate(const aiAnimation *pAnimation) {
  458|    213|    Validate(&pAnimation->mName);
  459|       |
  460|       |    // validate all animations
  461|    213|    if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels) {
  ------------------
  |  Branch (461:9): [True: 213, False: 0]
  |  Branch (461:37): [True: 0, False: 0]
  ------------------
  462|    211|        if (!pAnimation->mChannels && pAnimation->mNumChannels) {
  ------------------
  |  Branch (462:13): [True: 0, False: 211]
  |  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|    211|        if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) {
  ------------------
  |  Branch (466:13): [True: 211, False: 0]
  |  Branch (466:48): [True: 0, False: 211]
  ------------------
  467|      0|            ReportError("aiAnimation::mMorphMeshChannels is nullptr (aiAnimation::mNumMorphMeshChannels is %i)",
  468|      0|                    pAnimation->mNumMorphMeshChannels);
  469|      0|        }
  470|  3.74k|        for (unsigned int i = 0; i < pAnimation->mNumChannels; ++i) {
  ------------------
  |  Branch (470:34): [True: 3.53k, False: 211]
  ------------------
  471|  3.53k|            if (!pAnimation->mChannels[i]) {
  ------------------
  |  Branch (471:17): [True: 0, False: 3.53k]
  ------------------
  472|      0|                ReportError("aiAnimation::mChannels[%i] is nullptr (aiAnimation::mNumChannels is %i)",
  473|      0|                        i, pAnimation->mNumChannels);
  474|      0|            }
  475|  3.53k|            Validate(pAnimation, pAnimation->mChannels[i]);
  476|  3.53k|        }
  477|    211|        for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels; ++i) {
  ------------------
  |  Branch (477:34): [True: 0, False: 211]
  ------------------
  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|    211|    } else {
  485|      2|        ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there.");
  486|      2|    }
  487|    213|}
_ZN6Assimp17ValidateDSProcess24SearchForInvalidTexturesEPK10aiMaterial13aiTextureType:
  491|  5.13k|        aiTextureType type) {
  492|  5.13k|    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|  5.13k|    int iNumIndices = 0;
  501|  5.13k|    int iIndex = -1;
  502|   107k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (502:30): [True: 102k, False: 5.13k]
  ------------------
  503|   102k|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  504|   102k|        ai_assert(nullptr != prop);
  505|   102k|        if (!::strcmp(prop->mKey.data, "$tex.file") && prop->mSemantic == static_cast<unsigned int>(type)) {
  ------------------
  |  Branch (505:13): [True: 3.46k, False: 99.3k]
  |  Branch (505:56): [True: 204, False: 3.26k]
  ------------------
  506|    204|            iIndex = std::max(iIndex, (int)prop->mIndex);
  507|    204|            ++iNumIndices;
  508|       |
  509|    204|            if (aiPTI_String != prop->mType) {
  ------------------
  |  Branch (509:17): [True: 0, False: 204]
  ------------------
  510|      0|                ReportError("Material property %s is expected to be a string", prop->mKey.data);
  511|      0|            }
  512|    204|        }
  513|   102k|    }
  514|  5.13k|    if (iIndex + 1 != iNumIndices) {
  ------------------
  |  Branch (514:9): [True: 0, False: 5.13k]
  ------------------
  515|      0|        ReportError("%s #%i is set, but there are only %i %s textures",
  516|      0|                szType, iIndex, iNumIndices, szType);
  517|      0|    }
  518|  5.13k|    if (!iNumIndices) {
  ------------------
  |  Branch (518:9): [True: 4.93k, False: 204]
  ------------------
  519|  4.93k|        return;
  520|  4.93k|    }
  521|    204|    std::vector<aiTextureMapping> mappings(iNumIndices);
  522|       |
  523|       |    // Now check whether all UV indices are valid ...
  524|    204|    bool bNoSpecified = true;
  525|  5.24k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (525:30): [True: 5.03k, False: 204]
  ------------------
  526|  5.03k|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  527|  5.03k|        if (static_cast<aiTextureType>(prop->mSemantic) != type) {
  ------------------
  |  Branch (527:13): [True: 4.42k, False: 612]
  ------------------
  528|  4.42k|            continue;
  529|  4.42k|        }
  530|       |
  531|    612|        if ((int)prop->mIndex >= iNumIndices) {
  ------------------
  |  Branch (531:13): [True: 0, False: 612]
  ------------------
  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|    612|        if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
  ------------------
  |  Branch (537:13): [True: 0, False: 612]
  ------------------
  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|    612|        } else if (!::strcmp(prop->mKey.data, "$tex.uvtrafo")) {
  ------------------
  |  Branch (543:20): [True: 204, False: 408]
  ------------------
  544|    204|            if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform)) {
  ------------------
  |  Branch (544:17): [True: 0, False: 204]
  |  Branch (544:47): [True: 0, False: 204]
  ------------------
  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|    408|        } else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
  ------------------
  |  Branch (549:20): [True: 204, False: 204]
  ------------------
  550|    204|            if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) {
  ------------------
  |  Branch (550:17): [True: 0, False: 204]
  |  Branch (550:49): [True: 0, False: 204]
  ------------------
  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|    204|            bNoSpecified = false;
  555|       |
  556|       |            // Ignore UV indices for texture channels that are not there ...
  557|       |
  558|       |            // Get the value
  559|    204|            iIndex = *((unsigned int *)prop->mData);
  560|       |
  561|       |            // Check whether there is a mesh using this material
  562|       |            // which has not enough UV channels ...
  563|  2.04k|            for (unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (563:38): [True: 1.84k, False: 204]
  ------------------
  564|  1.84k|                aiMesh *mesh = this->mScene->mMeshes[a];
  565|  1.84k|                if (mesh->mMaterialIndex == (unsigned int)i) {
  ------------------
  |  Branch (565:21): [True: 0, False: 1.84k]
  ------------------
  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|  1.84k|            }
  575|    204|        }
  576|    612|    }
  577|    204|    if (bNoSpecified) {
  ------------------
  |  Branch (577:9): [True: 0, False: 204]
  ------------------
  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|    204|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK10aiMaterial:
  593|    302|void ValidateDSProcess::Validate(const aiMaterial *pMaterial) {
  594|       |    // check whether there are material keys that are obviously not legal
  595|  6.35k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (595:30): [True: 6.05k, False: 302]
  ------------------
  596|  6.05k|        const aiMaterialProperty *prop = pMaterial->mProperties[i];
  597|  6.05k|        if (!prop) {
  ------------------
  |  Branch (597:13): [True: 0, False: 6.05k]
  ------------------
  598|      0|            ReportError("aiMaterial::mProperties[%i] is nullptr (aiMaterial::mNumProperties is %i)",
  599|      0|                    i, pMaterial->mNumProperties);
  600|      0|        }
  601|  6.05k|        if (!prop->mDataLength || !prop->mData) {
  ------------------
  |  Branch (601:13): [True: 0, False: 6.05k]
  |  Branch (601:35): [True: 0, False: 6.05k]
  ------------------
  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|  6.05k|        if (aiPTI_String == prop->mType) {
  ------------------
  |  Branch (607:13): [True: 742, False: 5.30k]
  ------------------
  608|       |            // FIX: strings are now stored in a less expensive way, but we can't use the
  609|       |            // validation routine for 'normal' aiStrings
  610|    742|            if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast<uint32_t *>(prop->mData)) + 1) {
  ------------------
  |  Branch (610:17): [True: 0, False: 742]
  |  Branch (610:42): [True: 0, False: 742]
  ------------------
  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|    742|            if (prop->mData[prop->mDataLength - 1]) {
  ------------------
  |  Branch (615:17): [True: 0, False: 742]
  ------------------
  616|      0|                ReportError("Missing null-terminator in string material property");
  617|      0|            }
  618|       |            //  Validate((const aiString*)prop->mData);
  619|  5.30k|        } else if (aiPTI_Float == prop->mType) {
  ------------------
  |  Branch (619:20): [True: 4.59k, False: 716]
  ------------------
  620|  4.59k|            if (prop->mDataLength < sizeof(float)) {
  ------------------
  |  Branch (620:17): [True: 0, False: 4.59k]
  ------------------
  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|  4.59k|        } else if (aiPTI_Integer == prop->mType) {
  ------------------
  |  Branch (625:20): [True: 447, False: 269]
  ------------------
  626|    447|            if (prop->mDataLength < sizeof(int)) {
  ------------------
  |  Branch (626:17): [True: 0, False: 447]
  ------------------
  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|    447|        }
  632|       |        // TODO: check whether there is a key with an unknown name ...
  633|  6.05k|    }
  634|       |
  635|       |    // make some more specific tests
  636|    302|    ai_real fTemp;
  637|    302|    int iShading;
  638|    302|    if (AI_SUCCESS == aiGetMaterialInteger(pMaterial, AI_MATKEY_SHADING_MODEL, &iShading)) {
  ------------------
  |  Branch (638:9): [True: 269, False: 33]
  ------------------
  639|    269|        switch ((aiShadingMode)iShading) {
  640|      0|        case aiShadingMode_Blinn:
  ------------------
  |  Branch (640:9): [True: 0, False: 269]
  ------------------
  641|      0|        case aiShadingMode_CookTorrance:
  ------------------
  |  Branch (641:9): [True: 0, False: 269]
  ------------------
  642|    269|        case aiShadingMode_Phong:
  ------------------
  |  Branch (642:9): [True: 269, False: 0]
  ------------------
  643|       |
  644|    269|            if (AI_SUCCESS != aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS, &fTemp)) {
  ------------------
  |  Branch (644:17): [True: 4, False: 265]
  ------------------
  645|      4|                ReportWarning("A specular shading model is specified but there is no "
  646|      4|                              "AI_MATKEY_SHININESS key");
  647|      4|            }
  648|    269|            if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS_STRENGTH, &fTemp) && !fTemp) {
  ------------------
  |  Branch (648:17): [True: 266, False: 3]
  |  Branch (648:102): [True: 7, False: 259]
  ------------------
  649|      7|                ReportWarning("A specular shading model is specified but the value of the "
  650|      7|                              "AI_MATKEY_SHININESS_STRENGTH key is 0.0");
  651|      7|            }
  652|    269|            break;
  653|      0|        default:
  ------------------
  |  Branch (653:9): [True: 0, False: 269]
  ------------------
  654|      0|            break;
  655|    269|        }
  656|    269|    }
  657|       |
  658|    302|    if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_OPACITY, &fTemp) && (!fTemp || fTemp > 1.01)) {
  ------------------
  |  Branch (658:9): [True: 266, False: 36]
  |  Branch (658:84): [True: 15, False: 251]
  |  Branch (658:94): [True: 0, False: 251]
  ------------------
  659|     15|        ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)");
  660|     15|    }
  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|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE);
  666|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_SPECULAR);
  667|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT);
  668|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSIVE);
  669|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_OPACITY);
  670|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_SHININESS);
  671|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_HEIGHT);
  672|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMALS);
  673|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_DISPLACEMENT);
  674|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_LIGHTMAP);
  675|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_REFLECTION);
  676|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_BASE_COLOR);
  677|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMAL_CAMERA);
  678|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSION_COLOR);
  679|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_METALNESS);
  680|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE_ROUGHNESS);
  681|    302|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT_OCCLUSION);
  682|    302|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK9aiTexture:
  685|      6|void ValidateDSProcess::Validate(const aiTexture *pTexture) {
  686|       |    // the data section may NEVER be nullptr
  687|      6|    if (nullptr == pTexture->pcData) {
  ------------------
  |  Branch (687:9): [True: 0, False: 6]
  ------------------
  688|      0|        ReportError("aiTexture::pcData is nullptr");
  689|      0|    }
  690|      6|    if (pTexture->mHeight) {
  ------------------
  |  Branch (690:9): [True: 0, False: 6]
  ------------------
  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|      6|    } else {
  696|      6|        if (!pTexture->mWidth) {
  ------------------
  |  Branch (696:13): [True: 0, False: 6]
  ------------------
  697|      0|            ReportError("aiTexture::mWidth is zero (compressed texture)");
  698|      0|        }
  699|      6|        if ('\0' != pTexture->achFormatHint[HINTMAXTEXTURELEN - 1]) {
  ------------------
  |  Branch (699:13): [True: 0, False: 6]
  ------------------
  700|      0|            ReportWarning("aiTexture::achFormatHint must be zero-terminated");
  701|      6|        } else if ('.' == pTexture->achFormatHint[0]) {
  ------------------
  |  Branch (701:20): [True: 0, False: 6]
  ------------------
  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|      6|    }
  707|       |
  708|      6|    const char *sz = pTexture->achFormatHint;
  709|      6|    if ((sz[0] >= 'A' && sz[0] <= 'Z') ||
  ------------------
  |  Branch (709:10): [True: 6, False: 0]
  |  Branch (709:26): [True: 0, False: 6]
  ------------------
  710|      6|            (sz[1] >= 'A' && sz[1] <= 'Z') ||
  ------------------
  |  Branch (710:14): [True: 6, False: 0]
  |  Branch (710:30): [True: 0, False: 6]
  ------------------
  711|      6|            (sz[2] >= 'A' && sz[2] <= 'Z') ||
  ------------------
  |  Branch (711:14): [True: 6, False: 0]
  |  Branch (711:30): [True: 0, False: 6]
  ------------------
  712|      6|            (sz[3] >= 'A' && sz[3] <= 'Z')) {
  ------------------
  |  Branch (712:14): [True: 0, False: 6]
  |  Branch (712:30): [True: 0, False: 0]
  ------------------
  713|      0|        ReportError("aiTexture::achFormatHint contains non-lowercase letters");
  714|      0|    }
  715|      6|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK11aiAnimationPK10aiNodeAnim:
  719|  3.53k|        const aiNodeAnim *pNodeAnim) {
  720|  3.53k|    Validate(&pNodeAnim->mNodeName);
  721|       |
  722|  3.53k|    if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys) {
  ------------------
  |  Branch (722:9): [True: 48, False: 3.48k]
  |  Branch (722:41): [True: 0, False: 48]
  |  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.53k|    if (pNodeAnim->mNumPositionKeys) {
  ------------------
  |  Branch (726:9): [True: 3.48k, False: 53]
  ------------------
  727|  3.48k|        if (!pNodeAnim->mPositionKeys) {
  ------------------
  |  Branch (727:13): [True: 0, False: 3.48k]
  ------------------
  728|      0|            ReportError("aiNodeAnim::mPositionKeys is nullptr (aiNodeAnim::mNumPositionKeys is %i)",
  729|      0|                    pNodeAnim->mNumPositionKeys);
  730|      0|        }
  731|  3.48k|        double dLast = -10e10;
  732|  3.95M|        for (unsigned int i = 0; i < pNodeAnim->mNumPositionKeys; ++i) {
  ------------------
  |  Branch (732:34): [True: 3.94M, False: 3.48k]
  ------------------
  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|  3.94M|            if (pAnimation->mDuration > 0. && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (736:17): [True: 3.94M, False: 94]
  |  Branch (736:47): [True: 1, False: 3.94M]
  ------------------
  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|  3.94M|            if (i && pNodeAnim->mPositionKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (743:17): [True: 3.94M, False: 3.48k]
  |  Branch (743:22): [True: 1, False: 3.94M]
  ------------------
  744|      1|                ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller "
  745|      1|                              "than aiAnimation::mPositionKeys[%i] (which is %.5f)",
  746|      1|                        i,
  747|      1|                        (float)pNodeAnim->mPositionKeys[i].mTime,
  748|      1|                        i - 1, (float)dLast);
  749|      1|            }
  750|  3.94M|            dLast = pNodeAnim->mPositionKeys[i].mTime;
  751|  3.94M|        }
  752|  3.48k|    }
  753|       |    // rotation keys
  754|  3.53k|    if (pNodeAnim->mNumRotationKeys) {
  ------------------
  |  Branch (754:9): [True: 3.53k, False: 6]
  ------------------
  755|  3.53k|        if (!pNodeAnim->mRotationKeys) {
  ------------------
  |  Branch (755:13): [True: 0, False: 3.53k]
  ------------------
  756|      0|            ReportError("aiNodeAnim::mRotationKeys is nullptr (aiNodeAnim::mNumRotationKeys is %i)",
  757|      0|                    pNodeAnim->mNumRotationKeys);
  758|      0|        }
  759|  3.53k|        double dLast = -10e10;
  760|  4.38M|        for (unsigned int i = 0; i < pNodeAnim->mNumRotationKeys; ++i) {
  ------------------
  |  Branch (760:34): [True: 4.37M, False: 3.53k]
  ------------------
  761|  4.37M|            if (pAnimation->mDuration > 0. && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (761:17): [True: 4.37M, False: 147]
  |  Branch (761:47): [True: 0, False: 4.37M]
  ------------------
  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.37M|            if (i && pNodeAnim->mRotationKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (768:17): [True: 4.37M, False: 3.53k]
  |  Branch (768:22): [True: 1, False: 4.37M]
  ------------------
  769|      1|                ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller "
  770|      1|                              "than aiAnimation::mRotationKeys[%i] (which is %.5f)",
  771|      1|                        i,
  772|      1|                        (float)pNodeAnim->mRotationKeys[i].mTime,
  773|      1|                        i - 1, (float)dLast);
  774|      1|            }
  775|  4.37M|            dLast = pNodeAnim->mRotationKeys[i].mTime;
  776|  4.37M|        }
  777|  3.53k|    }
  778|       |    // scaling keys
  779|  3.53k|    if (pNodeAnim->mNumScalingKeys) {
  ------------------
  |  Branch (779:9): [True: 3.49k, False: 46]
  ------------------
  780|  3.49k|        if (!pNodeAnim->mScalingKeys) {
  ------------------
  |  Branch (780:13): [True: 0, False: 3.49k]
  ------------------
  781|      0|            ReportError("aiNodeAnim::mScalingKeys is nullptr (aiNodeAnim::mNumScalingKeys is %i)",
  782|      0|                    pNodeAnim->mNumScalingKeys);
  783|      0|        }
  784|  3.49k|        double dLast = -10e10;
  785|  3.95M|        for (unsigned int i = 0; i < pNodeAnim->mNumScalingKeys; ++i) {
  ------------------
  |  Branch (785:34): [True: 3.94M, False: 3.49k]
  ------------------
  786|  3.94M|            if (pAnimation->mDuration > 0. && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration + 0.001) {
  ------------------
  |  Branch (786:17): [True: 3.94M, False: 102]
  |  Branch (786:47): [True: 0, False: 3.94M]
  ------------------
  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|  3.94M|            if (i && pNodeAnim->mScalingKeys[i].mTime <= dLast) {
  ------------------
  |  Branch (793:17): [True: 3.94M, False: 3.49k]
  |  Branch (793:22): [True: 1, False: 3.94M]
  ------------------
  794|      1|                ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller "
  795|      1|                              "than aiAnimation::mScalingKeys[%i] (which is %.5f)",
  796|      1|                        i,
  797|      1|                        (float)pNodeAnim->mScalingKeys[i].mTime,
  798|      1|                        i - 1, (float)dLast);
  799|      1|            }
  800|  3.94M|            dLast = pNodeAnim->mScalingKeys[i].mTime;
  801|  3.94M|        }
  802|  3.49k|    }
  803|       |
  804|  3.53k|    if (!pNodeAnim->mNumScalingKeys && !pNodeAnim->mNumRotationKeys &&
  ------------------
  |  Branch (804:9): [True: 40, False: 3.49k]
  |  Branch (804:40): [True: 0, False: 40]
  ------------------
  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.53k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiNode:
  850|  6.82k|void ValidateDSProcess::Validate(const aiNode *pNode) {
  851|  6.82k|    if (!pNode) {
  ------------------
  |  Branch (851:9): [True: 0, False: 6.82k]
  ------------------
  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|  6.82k|    this->Validate(&pNode->mName);
  856|  6.82k|    const char *nodeName = (&pNode->mName)->C_Str();
  857|  6.82k|    if (pNode != mScene->mRootNode && !pNode->mParent) {
  ------------------
  |  Branch (857:9): [True: 6.47k, False: 347]
  |  Branch (857:39): [True: 0, False: 6.47k]
  ------------------
  858|      0|        ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is nullptr) ", nodeName);
  859|      0|    }
  860|       |
  861|       |    // validate all meshes
  862|  6.82k|    if (pNode->mNumMeshes) {
  ------------------
  |  Branch (862:9): [True: 764, False: 6.06k]
  ------------------
  863|    764|        if (!pNode->mMeshes) {
  ------------------
  |  Branch (863:13): [True: 0, False: 764]
  ------------------
  864|      0|            ReportError("aiNode::mMeshes is nullptr for node %s (aiNode::mNumMeshes is %i)",
  865|      0|                    nodeName, pNode->mNumMeshes);
  866|      0|        }
  867|    764|        std::vector<bool> abHadMesh;
  868|    764|        abHadMesh.resize(mScene->mNumMeshes, false);
  869|  1.52k|        for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) {
  ------------------
  |  Branch (869:34): [True: 764, False: 764]
  ------------------
  870|    764|            if (pNode->mMeshes[i] >= mScene->mNumMeshes) {
  ------------------
  |  Branch (870:17): [True: 0, False: 764]
  ------------------
  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|    764|            if (abHadMesh[pNode->mMeshes[i]]) {
  ------------------
  |  Branch (874:17): [True: 0, False: 764]
  ------------------
  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|    764|            abHadMesh[pNode->mMeshes[i]] = true;
  879|    764|        }
  880|    764|    }
  881|  6.82k|    if (pNode->mNumChildren) {
  ------------------
  |  Branch (881:9): [True: 4.20k, False: 2.62k]
  ------------------
  882|  4.20k|        if (!pNode->mChildren) {
  ------------------
  |  Branch (882:13): [True: 0, False: 4.20k]
  ------------------
  883|      0|            ReportError("aiNode::mChildren is nullptr for node %s (aiNode::mNumChildren is %i)",
  884|      0|                    nodeName, pNode->mNumChildren);
  885|      0|        }
  886|  10.6k|        for (unsigned int i = 0; i < pNode->mNumChildren; ++i) {
  ------------------
  |  Branch (886:34): [True: 6.48k, False: 4.20k]
  ------------------
  887|  6.48k|            const aiNode *pChild = pNode->mChildren[i];
  888|  6.48k|            Validate(pChild);
  889|  6.48k|            if (pChild->mParent != pNode) {
  ------------------
  |  Branch (889:17): [True: 0, False: 6.48k]
  ------------------
  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|  6.48k|        }
  894|  4.20k|    } else if (pNode->mChildren) {
  ------------------
  |  Branch (894:16): [True: 0, False: 2.62k]
  ------------------
  895|      0|        ReportError("aiNode::mChildren is not nullptr for empty node %s (aiNode::mNumChildren is %i)",
  896|      0|                nodeName, pNode->mNumChildren);
  897|      0|    }
  898|  6.82k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiString:
  901|  11.8k|void ValidateDSProcess::Validate(const aiString *pString) {
  902|  11.8k|    if (pString->length > AI_MAXLEN) {
  ------------------
  |  Branch (902:9): [True: 0, False: 11.8k]
  ------------------
  903|      0|        ReportError("aiString::length is too large (%u, maximum is %lu)",
  904|      0|                pString->length, AI_MAXLEN);
  905|      0|    }
  906|  11.8k|    const char *sz = pString->data;
  907|   165k|    while (true) {
  ------------------
  |  Branch (907:12): [True: 165k, Folded]
  ------------------
  908|   165k|        if ('\0' == *sz) {
  ------------------
  |  Branch (908:13): [True: 11.8k, False: 153k]
  ------------------
  909|  11.8k|            if (pString->length != (unsigned int)(sz - pString->data)) {
  ------------------
  |  Branch (909:17): [True: 17, False: 11.8k]
  ------------------
  910|     17|                ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
  911|     17|            }
  912|  11.8k|            break;
  913|   153k|        } else if (sz >= &pString->data[AI_MAXLEN]) {
  ------------------
  |  Branch (913:20): [True: 0, False: 153k]
  ------------------
  914|      0|            ReportError("aiString::data is invalid. There is no terminal character");
  915|      0|        }
  916|   153k|        ++sz;
  917|   153k|    }
  918|  11.8k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI6aiMeshEEvPPT_jPKcS7_:
  109|    151|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|    151|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 151]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|    151|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 151]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|    824|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 673, False: 151]
  ------------------
  121|    673|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 673]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|    673|        Validate(parray[i]);
  126|    673|    }
  127|    151|}
_ZN6Assimp17ValidateDSProcess12DoValidationI11aiAnimationEEvPPT_jPKcS7_:
  109|    213|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|    213|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 213]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|    213|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 213]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|    426|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 213, False: 213]
  ------------------
  121|    213|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 213]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|    213|        Validate(parray[i]);
  126|    213|    }
  127|    213|}
_ZN6Assimp17ValidateDSProcess25DoValidationWithNameCheckI8aiCameraEEvPPT_jPKcS7_:
  163|    269|        const char *secondName) {
  164|       |    // validate all entries
  165|    269|    DoValidationEx(array, size, firstName, secondName);
  166|       |
  167|    538|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (167:30): [True: 269, False: 269]
  ------------------
  168|    269|        int res = HasNameMatch(array[i]->mName, mScene->mRootNode);
  169|    269|        if (0 == res) {
  ------------------
  |  Branch (169:13): [True: 0, False: 269]
  ------------------
  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|    269|        } else if (1 != res) {
  ------------------
  |  Branch (173:20): [True: 0, False: 269]
  ------------------
  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|    269|    }
  179|    269|}
_ZN6Assimp17ValidateDSProcess14DoValidationExI8aiCameraEEvPPT_jPKcS7_:
  132|    269|        const char *firstName, const char *secondName) {
  133|       |    // validate all entries
  134|    269|    if (size == 0) {
  ------------------
  |  Branch (134:9): [True: 0, False: 269]
  ------------------
  135|      0|        return;
  136|      0|    }
  137|       |
  138|    269|    if (!parray) {
  ------------------
  |  Branch (138:9): [True: 0, False: 269]
  ------------------
  139|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  140|      0|                firstName, secondName, size);
  141|      0|    }
  142|    538|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (142:30): [True: 269, False: 269]
  ------------------
  143|    269|        if (!parray[i]) {
  ------------------
  |  Branch (143:13): [True: 0, False: 269]
  ------------------
  144|      0|            ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
  145|      0|                    firstName, i, secondName, size);
  146|      0|        }
  147|    269|        Validate(parray[i]);
  148|       |
  149|       |        // check whether there are duplicate names
  150|    269|        for (unsigned int a = i + 1; a < size; ++a) {
  ------------------
  |  Branch (150:38): [True: 0, False: 269]
  ------------------
  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|    269|    }
  158|    269|}
_Z12HasNameMatchRK8aiStringP6aiNode:
   99|  12.1k|inline int HasNameMatch(const aiString &in, aiNode *node) {
  100|  12.1k|    int result = (node->mName == in ? 1 : 0);
  ------------------
  |  Branch (100:19): [True: 524, False: 11.6k]
  ------------------
  101|  23.7k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 11.6k, False: 12.1k]
  ------------------
  102|  11.6k|        result += HasNameMatch(in, node->mChildren[i]);
  103|  11.6k|    }
  104|  12.1k|    return result;
  105|  12.1k|}
_ZN6Assimp17ValidateDSProcess25DoValidationWithNameCheckI7aiLightEEvPPT_jPKcS7_:
  163|    255|        const char *secondName) {
  164|       |    // validate all entries
  165|    255|    DoValidationEx(array, size, firstName, secondName);
  166|       |
  167|    510|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (167:30): [True: 255, False: 255]
  ------------------
  168|    255|        int res = HasNameMatch(array[i]->mName, mScene->mRootNode);
  169|    255|        if (0 == res) {
  ------------------
  |  Branch (169:13): [True: 0, False: 255]
  ------------------
  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|    255|        } else if (1 != res) {
  ------------------
  |  Branch (173:20): [True: 0, False: 255]
  ------------------
  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|    255|    }
  179|    255|}
_ZN6Assimp17ValidateDSProcess14DoValidationExI7aiLightEEvPPT_jPKcS7_:
  132|    255|        const char *firstName, const char *secondName) {
  133|       |    // validate all entries
  134|    255|    if (size == 0) {
  ------------------
  |  Branch (134:9): [True: 0, False: 255]
  ------------------
  135|      0|        return;
  136|      0|    }
  137|       |
  138|    255|    if (!parray) {
  ------------------
  |  Branch (138:9): [True: 0, False: 255]
  ------------------
  139|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  140|      0|                firstName, secondName, size);
  141|      0|    }
  142|    510|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (142:30): [True: 255, False: 255]
  ------------------
  143|    255|        if (!parray[i]) {
  ------------------
  |  Branch (143:13): [True: 0, False: 255]
  ------------------
  144|      0|            ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
  145|      0|                    firstName, i, secondName, size);
  146|      0|        }
  147|    255|        Validate(parray[i]);
  148|       |
  149|       |        // check whether there are duplicate names
  150|    255|        for (unsigned int a = i + 1; a < size; ++a) {
  ------------------
  |  Branch (150:38): [True: 0, False: 255]
  ------------------
  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|    255|    }
  158|    255|}
_ZN6Assimp17ValidateDSProcess12DoValidationI9aiTextureEEvPPT_jPKcS7_:
  109|      6|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|      6|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 6]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|      6|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 6]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|     12|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 6, False: 6]
  ------------------
  121|      6|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 6]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|      6|        Validate(parray[i]);
  126|      6|    }
  127|      6|}
_ZN6Assimp17ValidateDSProcess12DoValidationI10aiMaterialEEvPPT_jPKcS7_:
  109|    150|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|    150|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 150]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|    150|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 150]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|    452|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 302, False: 150]
  ------------------
  121|    302|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 302]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|    302|        Validate(parray[i]);
  126|    302|    }
  127|    150|}

_ZN6mapbox6earcutIjNSt3__16vectorINS2_I10aiVector2tIfENS1_9allocatorIS4_EEEENS5_IS7_EEEEEENS2_IT_NS5_ISA_EEEERKT0_:
  809|      4|std::vector<N> earcut(const Polygon& poly) {
  810|      4|    mapbox::detail::Earcut<N> earcut;
  811|      4|    earcut(poly);
  812|      4|    return std::move(earcut.indices);
  813|      4|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEEC2Ev:
   99|      4|        ObjectPool() { }
_ZN6mapbox6detail6EarcutIjEclINSt3__16vectorINS5_I10aiVector2tIfENS4_9allocatorIS7_EEEENS8_ISA_EEEEEEvRKT_:
  139|      4|void Earcut<N>::operator()(const Polygon& points) {
  140|       |    // reset
  141|      4|    indices.clear();
  142|      4|    vertices = 0;
  143|       |
  144|      4|    if (points.empty()) return;
  ------------------
  |  Branch (144:9): [True: 0, False: 4]
  ------------------
  145|       |
  146|      4|    double x;
  147|      4|    double y;
  148|      4|    int threshold = 80;
  149|      4|    std::size_t len = 0;
  150|       |
  151|      8|    for (size_t i = 0; threshold >= 0 && i < points.size(); i++) {
  ------------------
  |  Branch (151:24): [True: 7, False: 1]
  |  Branch (151:42): [True: 4, False: 3]
  ------------------
  152|      4|        threshold -= static_cast<int>(points[i].size());
  153|      4|        len += points[i].size();
  154|      4|    }
  155|       |
  156|       |    //estimate size of nodes and indices
  157|      4|    nodes.reset(len * 3 / 2);
  158|      4|    indices.reserve(len + points[0].size());
  159|       |
  160|      4|    Node* outerNode = linkedList(points[0], true);
  161|      4|    if (!outerNode || outerNode->prev == outerNode->next) return;
  ------------------
  |  Branch (161:9): [True: 0, False: 4]
  |  Branch (161:23): [True: 0, False: 4]
  ------------------
  162|       |
  163|      4|    if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
  ------------------
  |  Branch (163:9): [True: 0, False: 4]
  ------------------
  164|       |
  165|       |    // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
  166|      4|    hashing = threshold < 0;
  167|      4|    if (hashing) {
  ------------------
  |  Branch (167:9): [True: 1, False: 3]
  ------------------
  168|      1|        Node* p = outerNode->next;
  169|      1|        minX = maxX = outerNode->x;
  170|      1|        minY = maxY = outerNode->y;
  171|     95|        do {
  172|     95|            x = p->x;
  173|     95|            y = p->y;
  174|     95|            minX = std::min<double>(minX, x);
  175|     95|            minY = std::min<double>(minY, y);
  176|     95|            maxX = std::max<double>(maxX, x);
  177|     95|            maxY = std::max<double>(maxY, y);
  178|     95|            p = p->next;
  179|     95|        } while (p != outerNode);
  ------------------
  |  Branch (179:18): [True: 94, False: 1]
  ------------------
  180|       |
  181|       |        // minX, minY and inv_size are later used to transform coords into integers for z-order calculation
  182|      1|        inv_size = std::max<double>(maxX - minX, maxY - minY);
  183|      1|        inv_size = inv_size != .0 ? (32767. / inv_size) : .0;
  ------------------
  |  Branch (183:20): [True: 1, False: 0]
  ------------------
  184|      1|    }
  185|       |
  186|      4|    earcutLinked(outerNode);
  187|       |
  188|      4|    nodes.clear();
  189|      4|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE5resetEm:
  117|     12|        void reset(std::size_t newBlockSize) {
  118|     12|            for (auto allocation : allocations) {
  ------------------
  |  Branch (118:34): [True: 4, False: 12]
  ------------------
  119|      4|                alloc_traits::deallocate(alloc, allocation, blockSize);
  120|      4|            }
  121|     12|            allocations.clear();
  122|     12|            blockSize = std::max<std::size_t>(1, newBlockSize);
  123|     12|            currentBlock = nullptr;
  124|     12|            currentIndex = blockSize;
  125|     12|        }
_ZN6mapbox6detail6EarcutIjE10linkedListINSt3__16vectorI10aiVector2tIfENS4_9allocatorIS7_EEEEEEPNS2_4NodeERKT_b:
  194|      4|Earcut<N>::linkedList(const Ring& points, const bool clockwise) {
  195|      4|    using Point = typename Ring::value_type;
  196|      4|    double sum = 0;
  197|      4|    const std::size_t len = points.size();
  198|      4|    std::size_t i, j;
  199|      4|    Node* last = nullptr;
  200|       |
  201|       |    // calculate original winding order of a polygon ring
  202|    144|    for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) {
  ------------------
  |  Branch (202:21): [True: 4, False: 0]
  |  Branch (202:44): [True: 140, False: 4]
  ------------------
  203|    140|        const auto& p1 = points[i];
  204|    140|        const auto& p2 = points[j];
  205|    140|        const double p20 = util::nth<0, Point>::get(p2);
  206|    140|        const double p10 = util::nth<0, Point>::get(p1);
  207|    140|        const double p11 = util::nth<1, Point>::get(p1);
  208|    140|        const double p21 = util::nth<1, Point>::get(p2);
  209|    140|        sum += (p20 - p10) * (p11 + p21);
  210|    140|    }
  211|       |
  212|       |    // link points into circular doubly-linked list in the specified winding order
  213|      4|    if (clockwise == (sum > 0)) {
  ------------------
  |  Branch (213:9): [True: 3, False: 1]
  ------------------
  214|    112|        for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
  ------------------
  |  Branch (214:21): [True: 109, False: 3]
  ------------------
  215|      3|    } else {
  216|     32|        for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
  ------------------
  |  Branch (216:23): [True: 31, False: 1]
  ------------------
  217|      1|    }
  218|       |
  219|      4|    if (last && equals(last, last->next)) {
  ------------------
  |  Branch (219:9): [True: 4, False: 0]
  |  Branch (219:17): [True: 0, False: 4]
  ------------------
  220|      0|        removeNode(last);
  221|      0|        last = last->next;
  222|      0|    }
  223|       |
  224|      4|    vertices += len;
  225|       |
  226|      4|    return last;
  227|      4|}
_ZN6mapbox6detail6EarcutIjE10insertNodeI10aiVector2tIfEEEPNS2_4NodeEmRKT_S7_:
  781|    140|Earcut<N>::insertNode(std::size_t i, const Point& pt, Node* last) {
  782|    140|    Node* p = nodes.construct(static_cast<N>(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt));
  783|       |
  784|    140|    if (!last) {
  ------------------
  |  Branch (784:9): [True: 4, False: 136]
  ------------------
  785|      4|        p->prev = p;
  786|      4|        p->next = p;
  787|       |
  788|    136|    } else {
  789|    136|        assert(last);
  ------------------
  |  Branch (789:9): [True: 136, False: 0]
  ------------------
  790|    136|        p->next = last->next;
  791|    136|        p->prev = last;
  792|    136|        last->next->prev = p;
  793|    136|        last->next = p;
  794|    136|    }
  795|    140|    return p;
  796|    140|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE9constructIJjffEEEPS4_DpOT_:
  107|    140|        T* construct(Args&&... args) {
  108|    140|            if (currentIndex >= blockSize) {
  ------------------
  |  Branch (108:17): [True: 4, False: 136]
  ------------------
  109|      4|                currentBlock = alloc_traits::allocate(alloc, blockSize);
  110|      4|                allocations.emplace_back(currentBlock);
  111|      4|                currentIndex = 0;
  112|      4|            }
  113|    140|            T* object = &currentBlock[currentIndex++];
  114|    140|            alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
  115|    140|            return object;
  116|    140|        }
_ZN6mapbox6detail6EarcutIjE4NodeC2Ejdd:
   37|    140|        Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {}
_ZN6mapbox6detail6EarcutIjE6equalsEPKNS2_4NodeES5_:
  678|    250|bool Earcut<N>::equals(const Node* p1, const Node* p2) {
  679|    250|    return p1->x == p2->x && p1->y == p2->y;
  ------------------
  |  Branch (679:12): [True: 168, False: 82]
  |  Branch (679:30): [True: 76, False: 92]
  ------------------
  680|    250|}
_ZN6mapbox6detail6EarcutIjE10removeNodeEPNS2_4NodeE:
  799|    131|void Earcut<N>::removeNode(Node* p) {
  800|    131|    p->next->prev = p->prev;
  801|    131|    p->prev->next = p->next;
  802|       |
  803|    131|    if (p->prevZ) p->prevZ->nextZ = p->nextZ;
  ------------------
  |  Branch (803:9): [True: 34, False: 97]
  ------------------
  804|    131|    if (p->nextZ) p->nextZ->prevZ = p->prevZ;
  ------------------
  |  Branch (804:9): [True: 93, False: 38]
  ------------------
  805|    131|}
_ZNK6mapbox6detail6EarcutIjE15pointInTriangleEdddddddd:
  655|     52|bool Earcut<N>::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const {
  656|     52|    return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
  ------------------
  |  Branch (656:12): [True: 18, False: 34]
  ------------------
  657|     18|           (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
  ------------------
  |  Branch (657:12): [True: 13, False: 5]
  ------------------
  658|     13|           (bx - px) * (cy - py) >= (cx - px) * (by - py);
  ------------------
  |  Branch (658:12): [True: 10, False: 3]
  ------------------
  659|     52|}
_ZNK6mapbox6detail6EarcutIjE4areaEPKNS2_4NodeES5_S5_:
  672|    340|double Earcut<N>::area(const Node* p, const Node* q, const Node* r) const {
  673|    340|    return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y);
  674|    340|}
_ZN6mapbox6detail6EarcutIjE12filterPointsEPNS2_4NodeES4_:
  232|      8|Earcut<N>::filterPoints(Node* start, Node* end) {
  233|      8|    if (!end) end = start;
  ------------------
  |  Branch (233:9): [True: 8, False: 0]
  ------------------
  234|       |
  235|      8|    Node* p = start;
  236|      8|    bool again;
  237|    240|    do {
  238|    240|        again = false;
  239|       |
  240|    240|        if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
  ------------------
  |  Branch (240:13): [True: 240, False: 0]
  |  Branch (240:29): [True: 70, False: 170]
  |  Branch (240:51): [True: 55, False: 115]
  ------------------
  241|    125|            removeNode(p);
  242|    125|            p = end = p->prev;
  243|       |
  244|    125|            if (p == p->next) break;
  ------------------
  |  Branch (244:17): [True: 1, False: 124]
  ------------------
  245|    124|            again = true;
  246|       |
  247|    124|        } else {
  248|    115|            p = p->next;
  249|    115|        }
  250|    240|    } while (again || p != end);
  ------------------
  |  Branch (250:14): [True: 124, False: 115]
  |  Branch (250:23): [True: 108, False: 7]
  ------------------
  251|       |
  252|      8|    return end;
  253|      8|}
_ZN6mapbox6detail6EarcutIjE12earcutLinkedEPNS2_4NodeEi:
  257|     10|void Earcut<N>::earcutLinked(Node* ear, int pass) {
  258|     10|    if (!ear) return;
  ------------------
  |  Branch (258:9): [True: 0, False: 10]
  ------------------
  259|       |
  260|       |    // interlink polygon nodes in z-order
  261|     10|    if (!pass && hashing) indexCurve(ear);
  ------------------
  |  Branch (261:9): [True: 4, False: 6]
  |  Branch (261:18): [True: 1, False: 3]
  ------------------
  262|       |
  263|     10|    Node* stop = ear;
  264|     10|    Node* prev;
  265|     10|    Node* next;
  266|       |
  267|       |    // iterate through ears, slicing them one by one
  268|    162|    while (ear->prev != ear->next) {
  ------------------
  |  Branch (268:12): [True: 160, False: 2]
  ------------------
  269|    160|        prev = ear->prev;
  270|    160|        next = ear->next;
  271|       |
  272|    160|        if (hashing ? isEarHashed(ear) : isEar(ear)) {
  ------------------
  |  Branch (272:13): [True: 98, False: 62]
  |  Branch (272:13): [True: 6, False: 154]
  ------------------
  273|       |            // cut off the triangle
  274|      6|            indices.emplace_back(prev->i);
  275|      6|            indices.emplace_back(ear->i);
  276|      6|            indices.emplace_back(next->i);
  277|       |
  278|      6|            removeNode(ear);
  279|       |
  280|       |            // skipping the next vertice leads to less sliver triangles
  281|      6|            ear = next->next;
  282|      6|            stop = next->next;
  283|       |
  284|      6|            continue;
  285|      6|        }
  286|       |
  287|    154|        ear = next;
  288|       |
  289|       |        // if we looped through the whole remaining polygon and can't find any more ears
  290|    154|        if (ear == stop) {
  ------------------
  |  Branch (290:13): [True: 8, False: 146]
  ------------------
  291|       |            // try filtering points and slicing again
  292|      8|            if (!pass) earcutLinked(filterPoints(ear), 1);
  ------------------
  |  Branch (292:17): [True: 4, False: 4]
  ------------------
  293|       |
  294|       |            // if this didn't work, try curing all small self-intersections locally
  295|      4|            else if (pass == 1) {
  ------------------
  |  Branch (295:22): [True: 2, False: 2]
  ------------------
  296|      2|                ear = cureLocalIntersections(filterPoints(ear));
  297|      2|                earcutLinked(ear, 2);
  298|       |
  299|       |            // as a last resort, try splitting the remaining polygon into two
  300|      2|            } else if (pass == 2) splitEarcut(ear);
  ------------------
  |  Branch (300:24): [True: 2, False: 0]
  ------------------
  301|       |
  302|      8|            break;
  303|      8|        }
  304|    154|    }
  305|     10|}
_ZN6mapbox6detail6EarcutIjE10indexCurveEPNS2_4NodeE:
  532|      1|void Earcut<N>::indexCurve(Node* start) {
  533|      1|    assert(start);
  ------------------
  |  Branch (533:5): [True: 1, False: 0]
  ------------------
  534|      1|    Node* p = start;
  535|       |
  536|     96|    do {
  537|     96|        p->z = p->z ? p->z : zOrder(p->x, p->y);
  ------------------
  |  Branch (537:16): [True: 0, False: 96]
  ------------------
  538|     96|        p->prevZ = p->prev;
  539|     96|        p->nextZ = p->next;
  540|     96|        p = p->next;
  541|     96|    } while (p != start);
  ------------------
  |  Branch (541:14): [True: 95, False: 1]
  ------------------
  542|       |
  543|      1|    p->prevZ->nextZ = nullptr;
  544|      1|    p->prevZ = nullptr;
  545|       |
  546|      1|    sortLinked(p);
  547|      1|}
_ZN6mapbox6detail6EarcutIjE6zOrderEdd:
  620|    104|int32_t Earcut<N>::zOrder(const double x_, const double y_) {
  621|       |    // coords are transformed into non-negative 15-bit integer range
  622|    104|    int32_t x = static_cast<int32_t>((x_ - minX) * inv_size);
  623|    104|    int32_t y = static_cast<int32_t>((y_ - minY) * inv_size);
  624|       |
  625|    104|    x = (x | (x << 8)) & 0x00FF00FF;
  626|    104|    x = (x | (x << 4)) & 0x0F0F0F0F;
  627|    104|    x = (x | (x << 2)) & 0x33333333;
  628|    104|    x = (x | (x << 1)) & 0x55555555;
  629|       |
  630|    104|    y = (y | (y << 8)) & 0x00FF00FF;
  631|    104|    y = (y | (y << 4)) & 0x0F0F0F0F;
  632|    104|    y = (y | (y << 2)) & 0x33333333;
  633|    104|    y = (y | (y << 1)) & 0x55555555;
  634|       |
  635|    104|    return x | (y << 1);
  636|    104|}
_ZN6mapbox6detail6EarcutIjE10sortLinkedEPNS2_4NodeE:
  553|      1|Earcut<N>::sortLinked(Node* list) {
  554|      1|    assert(list);
  ------------------
  |  Branch (554:5): [True: 1, False: 0]
  ------------------
  555|      1|    Node* p;
  556|      1|    Node* q;
  557|      1|    Node* e;
  558|      1|    Node* tail;
  559|      1|    int i, numMerges, pSize, qSize;
  560|      1|    int inSize = 1;
  561|       |
  562|      7|    for (;;) {
  563|      7|        p = list;
  564|      7|        list = nullptr;
  565|      7|        tail = nullptr;
  566|      7|        numMerges = 0;
  567|       |
  568|    103|        while (p) {
  ------------------
  |  Branch (568:16): [True: 96, False: 7]
  ------------------
  569|     96|            numMerges++;
  570|     96|            q = p;
  571|     96|            pSize = 0;
  572|    463|            for (i = 0; i < inSize; i++) {
  ------------------
  |  Branch (572:25): [True: 368, False: 95]
  ------------------
  573|    368|                pSize++;
  574|    368|                q = q->nextZ;
  575|    368|                if (!q) break;
  ------------------
  |  Branch (575:21): [True: 1, False: 367]
  ------------------
  576|    368|            }
  577|       |
  578|     96|            qSize = inSize;
  579|       |
  580|    768|            while (pSize > 0 || (qSize > 0 && q)) {
  ------------------
  |  Branch (580:20): [True: 579, False: 189]
  |  Branch (580:34): [True: 95, False: 94]
  |  Branch (580:47): [True: 93, False: 2]
  ------------------
  581|       |
  582|    672|                if (pSize == 0) {
  ------------------
  |  Branch (582:21): [True: 93, False: 579]
  ------------------
  583|     93|                    e = q;
  584|     93|                    q = q->nextZ;
  585|     93|                    qSize--;
  586|    579|                } else if (qSize == 0 || !q) {
  ------------------
  |  Branch (586:28): [True: 29, False: 550]
  |  Branch (586:42): [True: 33, False: 517]
  ------------------
  587|     62|                    e = p;
  588|     62|                    p = p->nextZ;
  589|     62|                    pSize--;
  590|    517|                } else if (p->z <= q->z) {
  ------------------
  |  Branch (590:28): [True: 306, False: 211]
  ------------------
  591|    306|                    e = p;
  592|    306|                    p = p->nextZ;
  593|    306|                    pSize--;
  594|    306|                } else {
  595|    211|                    e = q;
  596|    211|                    q = q->nextZ;
  597|    211|                    qSize--;
  598|    211|                }
  599|       |
  600|    672|                if (tail) tail->nextZ = e;
  ------------------
  |  Branch (600:21): [True: 665, False: 7]
  ------------------
  601|      7|                else list = e;
  602|       |
  603|    672|                e->prevZ = tail;
  604|    672|                tail = e;
  605|    672|            }
  606|       |
  607|     96|            p = q;
  608|     96|        }
  609|       |
  610|      7|        tail->nextZ = nullptr;
  611|       |
  612|      7|        if (numMerges <= 1) return list;
  ------------------
  |  Branch (612:13): [True: 1, False: 6]
  ------------------
  613|       |
  614|      6|        inSize *= 2;
  615|      6|    }
  616|      1|}
_ZN6mapbox6detail6EarcutIjE11isEarHashedEPNS2_4NodeE:
  329|     98|bool Earcut<N>::isEarHashed(Node* ear) {
  330|     98|    const Node* a = ear->prev;
  331|     98|    const Node* b = ear;
  332|     98|    const Node* c = ear->next;
  333|       |
  334|     98|    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  ------------------
  |  Branch (334:9): [True: 94, False: 4]
  ------------------
  335|       |
  336|       |    // triangle bbox; min & max are calculated like this for speed
  337|      4|    const double minTX = std::min<double>(a->x, std::min<double>(b->x, c->x));
  338|      4|    const double minTY = std::min<double>(a->y, std::min<double>(b->y, c->y));
  339|      4|    const double maxTX = std::max<double>(a->x, std::max<double>(b->x, c->x));
  340|      4|    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|      4|    const int32_t minZ = zOrder(minTX, minTY);
  344|      4|    const int32_t maxZ = zOrder(maxTX, maxTY);
  345|       |
  346|       |    // first look for points inside the triangle in increasing z-order
  347|      4|    Node* p = ear->nextZ;
  348|       |
  349|     38|    while (p && p->z <= maxZ) {
  ------------------
  |  Branch (349:12): [True: 34, False: 4]
  |  Branch (349:17): [True: 34, False: 0]
  ------------------
  350|     34|        if (p != ear->prev && p != ear->next &&
  ------------------
  |  Branch (350:13): [True: 33, False: 1]
  |  Branch (350:31): [True: 31, False: 2]
  ------------------
  351|     31|            pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (351:13): [True: 0, False: 31]
  ------------------
  352|      0|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (352:13): [True: 0, False: 0]
  ------------------
  353|     34|        p = p->nextZ;
  354|     34|    }
  355|       |
  356|       |    // then look for points in decreasing z-order
  357|      4|    p = ear->prevZ;
  358|       |
  359|      7|    while (p && p->z >= minZ) {
  ------------------
  |  Branch (359:12): [True: 5, False: 2]
  |  Branch (359:17): [True: 5, False: 0]
  ------------------
  360|      5|        if (p != ear->prev && p != ear->next &&
  ------------------
  |  Branch (360:13): [True: 4, False: 1]
  |  Branch (360:31): [True: 3, False: 1]
  ------------------
  361|      3|            pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (361:13): [True: 2, False: 1]
  ------------------
  362|      2|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (362:13): [True: 2, False: 0]
  ------------------
  363|      3|        p = p->prevZ;
  364|      3|    }
  365|       |
  366|      2|    return true;
  367|      4|}
_ZN6mapbox6detail6EarcutIjE5isEarEPNS2_4NodeE:
  309|     62|bool Earcut<N>::isEar(Node* ear) {
  310|     62|    const Node* a = ear->prev;
  311|     62|    const Node* b = ear;
  312|     62|    const Node* c = ear->next;
  313|       |
  314|     62|    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  ------------------
  |  Branch (314:9): [True: 54, False: 8]
  ------------------
  315|       |
  316|       |    // now make sure we don't have other points inside the potential ear
  317|      8|    Node* p = ear->next->next;
  318|       |
  319|     22|    while (p != ear->prev) {
  ------------------
  |  Branch (319:12): [True: 18, False: 4]
  ------------------
  320|     18|        if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (320:13): [True: 8, False: 10]
  ------------------
  321|      8|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (321:13): [True: 4, False: 4]
  ------------------
  322|     14|        p = p->next;
  323|     14|    }
  324|       |
  325|      4|    return true;
  326|      8|}
_ZN6mapbox6detail6EarcutIjE22cureLocalIntersectionsEPNS2_4NodeE:
  372|      2|Earcut<N>::cureLocalIntersections(Node* start) {
  373|      2|    Node* p = start;
  374|      6|    do {
  375|      6|        Node* a = p->prev;
  376|      6|        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|      6|        if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) {
  ------------------
  |  Branch (379:13): [True: 0, False: 6]
  |  Branch (379:30): [True: 0, False: 0]
  |  Branch (379:62): [True: 0, False: 0]
  |  Branch (379:85): [True: 0, False: 0]
  ------------------
  380|      0|            indices.emplace_back(a->i);
  381|      0|            indices.emplace_back(p->i);
  382|      0|            indices.emplace_back(b->i);
  383|       |
  384|       |            // remove two nodes involved
  385|      0|            removeNode(p);
  386|      0|            removeNode(p->next);
  387|       |
  388|      0|            p = start = b;
  389|      0|        }
  390|      6|        p = p->next;
  391|      6|    } while (p != start);
  ------------------
  |  Branch (391:14): [True: 4, False: 2]
  ------------------
  392|       |
  393|      2|    return filterPoints(p);
  394|      2|}
_ZN6mapbox6detail6EarcutIjE11splitEarcutEPNS2_4NodeE:
  398|      2|void Earcut<N>::splitEarcut(Node* start) {
  399|       |    // look for a valid diagonal that divides the polygon into two
  400|      2|    Node* a = start;
  401|      6|    do {
  402|      6|        Node* b = a->next->next;
  403|      6|        while (b != a->prev) {
  ------------------
  |  Branch (403:16): [True: 0, False: 6]
  ------------------
  404|      0|            if (a->i != b->i && isValidDiagonal(a, b)) {
  ------------------
  |  Branch (404:17): [True: 0, False: 0]
  |  Branch (404:33): [True: 0, False: 0]
  ------------------
  405|       |                // split the polygon in two by the diagonal
  406|      0|                Node* c = splitPolygon(a, b);
  407|       |
  408|       |                // filter colinear points around the cuts
  409|      0|                a = filterPoints(a, a->next);
  410|      0|                c = filterPoints(c, c->next);
  411|       |
  412|       |                // run earcut on each half
  413|      0|                earcutLinked(a);
  414|      0|                earcutLinked(c);
  415|      0|                return;
  416|      0|            }
  417|      0|            b = b->next;
  418|      0|        }
  419|      6|        a = a->next;
  420|      6|    } while (a != start);
  ------------------
  |  Branch (420:14): [True: 4, False: 2]
  ------------------
  421|      2|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE5clearEv:
  126|      8|        void clear() { reset(blockSize); }
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEED2Ev:
  103|      4|        ~ObjectPool() {
  104|      4|            clear();
  105|      4|        }

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

inflate_fast:
   53|  9.77k|{
   54|  9.77k|    struct inflate_state FAR *state;
   55|  9.77k|    z_const unsigned char FAR *in;      /* local strm->next_in */
   56|  9.77k|    z_const unsigned char FAR *last;    /* have enough input while in < last */
   57|  9.77k|    unsigned char FAR *out;     /* local strm->next_out */
   58|  9.77k|    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
   59|  9.77k|    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|  9.77k|    unsigned wsize;             /* window size or zero if not using window */
   64|  9.77k|    unsigned whave;             /* valid bytes in the window */
   65|  9.77k|    unsigned wnext;             /* window write index */
   66|  9.77k|    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
   67|  9.77k|    unsigned long hold;         /* local strm->hold */
   68|  9.77k|    unsigned bits;              /* local strm->bits */
   69|  9.77k|    code const FAR *lcode;      /* local strm->lencode */
   70|  9.77k|    code const FAR *dcode;      /* local strm->distcode */
   71|  9.77k|    unsigned lmask;             /* mask for first level of length codes */
   72|  9.77k|    unsigned dmask;             /* mask for first level of distance codes */
   73|  9.77k|    code const *here;           /* retrieved table entry */
   74|  9.77k|    unsigned op;                /* code bits, operation, extra bits, or */
   75|       |                                /*  window position, window bytes to copy */
   76|  9.77k|    unsigned len;               /* match length, unused bytes */
   77|  9.77k|    unsigned dist;              /* match distance */
   78|  9.77k|    unsigned char FAR *from;    /* where to copy match from */
   79|       |
   80|       |    /* copy state to local variables */
   81|  9.77k|    state = (struct inflate_state FAR *)strm->state;
   82|  9.77k|    in = strm->next_in;
   83|  9.77k|    last = in + (strm->avail_in - 5);
   84|  9.77k|    out = strm->next_out;
   85|  9.77k|    beg = out - (start - strm->avail_out);
   86|  9.77k|    end = out + (strm->avail_out - 257);
   87|       |#ifdef INFLATE_STRICT
   88|       |    dmax = state->dmax;
   89|       |#endif
   90|  9.77k|    wsize = state->wsize;
   91|  9.77k|    whave = state->whave;
   92|  9.77k|    wnext = state->wnext;
   93|  9.77k|    window = state->window;
   94|  9.77k|    hold = state->hold;
   95|  9.77k|    bits = state->bits;
   96|  9.77k|    lcode = state->lencode;
   97|  9.77k|    dcode = state->distcode;
   98|  9.77k|    lmask = (1U << state->lenbits) - 1;
   99|  9.77k|    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|  6.87M|    do {
  104|  6.87M|        if (bits < 15) {
  ------------------
  |  Branch (104:13): [True: 3.17M, False: 3.69M]
  ------------------
  105|  3.17M|            hold += (unsigned long)(*in++) << bits;
  106|  3.17M|            bits += 8;
  107|  3.17M|            hold += (unsigned long)(*in++) << bits;
  108|  3.17M|            bits += 8;
  109|  3.17M|        }
  110|  6.87M|        here = lcode + (hold & lmask);
  111|  7.29M|      dolen:
  112|  7.29M|        op = (unsigned)(here->bits);
  113|  7.29M|        hold >>= op;
  114|  7.29M|        bits -= op;
  115|  7.29M|        op = (unsigned)(here->op);
  116|  7.29M|        if (op == 0) {                          /* literal */
  ------------------
  |  Branch (116:13): [True: 3.43M, False: 3.85M]
  ------------------
  117|  3.43M|            Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
  118|  3.43M|                    "inflate:         literal '%c'\n" :
  119|  3.43M|                    "inflate:         literal 0x%02x\n", here->val));
  120|  3.43M|            *out++ = (unsigned char)(here->val);
  121|  3.43M|        }
  122|  3.85M|        else if (op & 16) {                     /* length base */
  ------------------
  |  Branch (122:18): [True: 3.44M, False: 414k]
  ------------------
  123|  3.44M|            len = (unsigned)(here->val);
  124|  3.44M|            op &= 15;                           /* number of extra bits */
  125|  3.44M|            if (op) {
  ------------------
  |  Branch (125:17): [True: 353k, False: 3.08M]
  ------------------
  126|   353k|                if (bits < op) {
  ------------------
  |  Branch (126:21): [True: 11, False: 353k]
  ------------------
  127|     11|                    hold += (unsigned long)(*in++) << bits;
  128|     11|                    bits += 8;
  129|     11|                }
  130|   353k|                len += (unsigned)hold & ((1U << op) - 1);
  131|   353k|                hold >>= op;
  132|   353k|                bits -= op;
  133|   353k|            }
  134|  3.44M|            Tracevv((stderr, "inflate:         length %u\n", len));
  135|  3.44M|            if (bits < 15) {
  ------------------
  |  Branch (135:17): [True: 632k, False: 2.80M]
  ------------------
  136|   632k|                hold += (unsigned long)(*in++) << bits;
  137|   632k|                bits += 8;
  138|   632k|                hold += (unsigned long)(*in++) << bits;
  139|   632k|                bits += 8;
  140|   632k|            }
  141|  3.44M|            here = dcode + (hold & dmask);
  142|  3.48M|          dodist:
  143|  3.48M|            op = (unsigned)(here->bits);
  144|  3.48M|            hold >>= op;
  145|  3.48M|            bits -= op;
  146|  3.48M|            op = (unsigned)(here->op);
  147|  3.48M|            if (op & 16) {                      /* distance base */
  ------------------
  |  Branch (147:17): [True: 3.44M, False: 43.6k]
  ------------------
  148|  3.44M|                dist = (unsigned)(here->val);
  149|  3.44M|                op &= 15;                       /* number of extra bits */
  150|  3.44M|                if (bits < op) {
  ------------------
  |  Branch (150:21): [True: 12.1k, False: 3.42M]
  ------------------
  151|  12.1k|                    hold += (unsigned long)(*in++) << bits;
  152|  12.1k|                    bits += 8;
  153|  12.1k|                    if (bits < op) {
  ------------------
  |  Branch (153:25): [True: 0, False: 12.1k]
  ------------------
  154|      0|                        hold += (unsigned long)(*in++) << bits;
  155|      0|                        bits += 8;
  156|      0|                    }
  157|  12.1k|                }
  158|  3.44M|                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.44M|                hold >>= op;
  167|  3.44M|                bits -= op;
  168|  3.44M|                Tracevv((stderr, "inflate:         distance %u\n", dist));
  169|  3.44M|                op = (unsigned)(out - beg);     /* max distance in output */
  170|  3.44M|                if (dist > op) {                /* see if copy from window */
  ------------------
  |  Branch (170:21): [True: 622, False: 3.44M]
  ------------------
  171|    622|                    op = dist - op;             /* distance back in window */
  172|    622|                    if (op > whave) {
  ------------------
  |  Branch (172:25): [True: 622, False: 0]
  ------------------
  173|    622|                        if (state->sane) {
  ------------------
  |  Branch (173:29): [True: 622, False: 0]
  ------------------
  174|    622|                            strm->msg =
  175|    622|                                (char *)"invalid distance too far back";
  176|    622|                            state->mode = BAD;
  177|    622|                            break;
  178|    622|                        }
  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|    622|                    }
  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.44M|                else {
  252|  3.44M|                    from = out - dist;          /* copy direct from output */
  253|  6.77M|                    do {                        /* minimum length is three */
  254|  6.77M|                        *out++ = *from++;
  255|  6.77M|                        *out++ = *from++;
  256|  6.77M|                        *out++ = *from++;
  257|  6.77M|                        len -= 3;
  258|  6.77M|                    } while (len > 2);
  ------------------
  |  Branch (258:30): [True: 3.33M, False: 3.44M]
  ------------------
  259|  3.44M|                    if (len) {
  ------------------
  |  Branch (259:25): [True: 1.71M, False: 1.72M]
  ------------------
  260|  1.71M|                        *out++ = *from++;
  261|  1.71M|                        if (len > 1)
  ------------------
  |  Branch (261:29): [True: 702k, False: 1.01M]
  ------------------
  262|   702k|                            *out++ = *from++;
  263|  1.71M|                    }
  264|  3.44M|                }
  265|  3.44M|            }
  266|  43.6k|            else if ((op & 64) == 0) {          /* 2nd level distance code */
  ------------------
  |  Branch (266:22): [True: 43.6k, False: 7]
  ------------------
  267|  43.6k|                here = dcode + here->val + (hold & ((1U << op) - 1));
  268|  43.6k|                goto dodist;
  269|  43.6k|            }
  270|      7|            else {
  271|      7|                strm->msg = (char *)"invalid distance code";
  272|      7|                state->mode = BAD;
  273|      7|                break;
  274|      7|            }
  275|  3.48M|        }
  276|   414k|        else if ((op & 64) == 0) {              /* 2nd level length code */
  ------------------
  |  Branch (276:18): [True: 414k, False: 41]
  ------------------
  277|   414k|            here = lcode + here->val + (hold & ((1U << op) - 1));
  278|   414k|            goto dolen;
  279|   414k|        }
  280|     41|        else if (op & 32) {                     /* end-of-block */
  ------------------
  |  Branch (280:18): [True: 41, False: 0]
  ------------------
  281|     41|            Tracevv((stderr, "inflate:         end of block\n"));
  282|     41|            state->mode = TYPE;
  283|     41|            break;
  284|     41|        }
  285|      0|        else {
  286|      0|            strm->msg = (char *)"invalid literal/length code";
  287|      0|            state->mode = BAD;
  288|      0|            break;
  289|      0|        }
  290|  7.29M|    } while (in < last && out < end);
  ------------------
  |  Branch (290:14): [True: 6.87M, False: 92]
  |  Branch (290:27): [True: 6.86M, False: 9.00k]
  ------------------
  291|       |
  292|       |    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
  293|  9.77k|    len = bits >> 3;
  294|  9.77k|    in -= len;
  295|  9.77k|    bits -= len << 3;
  296|  9.77k|    hold &= (1U << bits) - 1;
  297|       |
  298|       |    /* update state and return */
  299|  9.77k|    strm->next_in = in;
  300|  9.77k|    strm->next_out = out;
  301|  9.77k|    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
  ------------------
  |  Branch (301:33): [True: 9.73k, False: 39]
  ------------------
  302|  9.77k|    strm->avail_out = (unsigned)(out < end ?
  ------------------
  |  Branch (302:34): [True: 760, False: 9.01k]
  ------------------
  303|  9.01k|                                 257 + (end - out) : 257 - (out - end));
  304|  9.77k|    state->hold = hold;
  305|  9.77k|    state->bits = bits;
  306|  9.77k|    return;
  307|  9.77k|}

inflateResetKeep:
  121|  10.5k|{
  122|  10.5k|    struct inflate_state FAR *state;
  123|       |
  124|  10.5k|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (124:9): [True: 0, False: 10.5k]
  ------------------
  125|  10.5k|    state = (struct inflate_state FAR *)strm->state;
  126|  10.5k|    strm->total_in = strm->total_out = state->total = 0;
  127|  10.5k|    strm->msg = Z_NULL;
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  128|  10.5k|    if (state->wrap)        /* to support ill-conceived Java test suite */
  ------------------
  |  Branch (128:9): [True: 10.5k, False: 0]
  ------------------
  129|  10.5k|        strm->adler = state->wrap & 1;
  130|  10.5k|    state->mode = HEAD;
  131|  10.5k|    state->last = 0;
  132|  10.5k|    state->havedict = 0;
  133|  10.5k|    state->flags = -1;
  134|  10.5k|    state->dmax = 32768U;
  135|  10.5k|    state->head = Z_NULL;
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  136|  10.5k|    state->hold = 0;
  137|  10.5k|    state->bits = 0;
  138|  10.5k|    state->lencode = state->distcode = state->next = state->codes;
  139|  10.5k|    state->sane = 1;
  140|  10.5k|    state->back = -1;
  141|  10.5k|    Tracev((stderr, "inflate: reset\n"));
  142|  10.5k|    return Z_OK;
  ------------------
  |  |  177|  10.5k|#define Z_OK            0
  ------------------
  143|  10.5k|}
inflateReset:
  147|  10.5k|{
  148|  10.5k|    struct inflate_state FAR *state;
  149|       |
  150|  10.5k|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (150:9): [True: 0, False: 10.5k]
  ------------------
  151|  10.5k|    state = (struct inflate_state FAR *)strm->state;
  152|  10.5k|    state->wsize = 0;
  153|  10.5k|    state->whave = 0;
  154|  10.5k|    state->wnext = 0;
  155|  10.5k|    return inflateResetKeep(strm);
  156|  10.5k|}
inflateReset2:
  161|  10.5k|{
  162|  10.5k|    int wrap;
  163|  10.5k|    struct inflate_state FAR *state;
  164|       |
  165|       |    /* get the state */
  166|  10.5k|    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  |  Branch (166:9): [True: 0, False: 10.5k]
  ------------------
  167|  10.5k|    state = (struct inflate_state FAR *)strm->state;
  168|       |
  169|       |    /* extract wrap request from windowBits parameter */
  170|  10.5k|    if (windowBits < 0) {
  ------------------
  |  Branch (170:9): [True: 0, False: 10.5k]
  ------------------
  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|  10.5k|    else {
  177|  10.5k|        wrap = (windowBits >> 4) + 5;
  178|  10.5k|#ifdef GUNZIP
  179|  10.5k|        if (windowBits < 48)
  ------------------
  |  Branch (179:13): [True: 10.5k, False: 0]
  ------------------
  180|  10.5k|            windowBits &= 15;
  181|  10.5k|#endif
  182|  10.5k|    }
  183|       |
  184|       |    /* set number of window bits, free window if different */
  185|  10.5k|    if (windowBits && (windowBits < 8 || windowBits > 15))
  ------------------
  |  Branch (185:9): [True: 10.5k, False: 0]
  |  Branch (185:24): [True: 0, False: 10.5k]
  |  Branch (185:42): [True: 0, False: 10.5k]
  ------------------
  186|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  187|  10.5k|    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
  ------------------
  |  |  212|  21.1k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (187:9): [True: 0, False: 10.5k]
  |  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|  10.5k|    state->wrap = wrap;
  194|  10.5k|    state->wbits = (unsigned)windowBits;
  195|  10.5k|    return inflateReset(strm);
  196|  10.5k|}
inflateInit2_:
  203|  10.5k|{
  204|  10.5k|    int ret;
  205|  10.5k|    struct inflate_state FAR *state;
  206|       |
  207|  10.5k|    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
  ------------------
  |  |  212|  21.1k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
  ------------------
  |  |   40|  10.5k|#define ZLIB_VERSION "1.2.13"
  ------------------
  |  Branch (207:9): [True: 0, False: 10.5k]
  |  Branch (207:30): [True: 0, False: 10.5k]
  ------------------
  208|  10.5k|        stream_size != (int)(sizeof(z_stream)))
  ------------------
  |  Branch (208:9): [True: 0, False: 10.5k]
  ------------------
  209|      0|        return Z_VERSION_ERROR;
  ------------------
  |  |  185|      0|#define Z_VERSION_ERROR (-6)
  ------------------
  210|  10.5k|    if (strm == Z_NULL) return Z_STREAM_ERROR;
  ------------------
  |  |  212|  10.5k|#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: 10.5k]
  ------------------
  211|  10.5k|    strm->msg = Z_NULL;                 /* in case we return an error */
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  212|  10.5k|    if (strm->zalloc == (alloc_func)0) {
  ------------------
  |  Branch (212:9): [True: 10.5k, False: 0]
  ------------------
  213|       |#ifdef Z_SOLO
  214|       |        return Z_STREAM_ERROR;
  215|       |#else
  216|  10.5k|        strm->zalloc = zcalloc;
  217|  10.5k|        strm->opaque = (voidpf)0;
  218|  10.5k|#endif
  219|  10.5k|    }
  220|  10.5k|    if (strm->zfree == (free_func)0)
  ------------------
  |  Branch (220:9): [True: 10.5k, False: 0]
  ------------------
  221|       |#ifdef Z_SOLO
  222|       |        return Z_STREAM_ERROR;
  223|       |#else
  224|  10.5k|        strm->zfree = zcfree;
  225|  10.5k|#endif
  226|  10.5k|    state = (struct inflate_state FAR *)
  227|  10.5k|            ZALLOC(strm, 1, sizeof(struct inflate_state));
  ------------------
  |  |  267|  10.5k|           (*((strm)->zalloc))((strm)->opaque, (items), (size))
  ------------------
  228|  10.5k|    if (state == Z_NULL) return Z_MEM_ERROR;
  ------------------
  |  |  212|  10.5k|#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: 10.5k]
  ------------------
  229|  10.5k|    Tracev((stderr, "inflate: allocated\n"));
  230|  10.5k|    strm->state = (struct internal_state FAR *)state;
  231|  10.5k|    state->strm = strm;
  232|  10.5k|    state->window = Z_NULL;
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  233|  10.5k|    state->mode = HEAD;     /* to pass state test in inflateReset2() */
  234|  10.5k|    ret = inflateReset2(strm, windowBits);
  235|  10.5k|    if (ret != Z_OK) {
  ------------------
  |  |  177|  10.5k|#define Z_OK            0
  ------------------
  |  Branch (235:9): [True: 0, False: 10.5k]
  ------------------
  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|  10.5k|    return ret;
  240|  10.5k|}
inflateInit_:
  246|  10.5k|{
  247|  10.5k|    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
  ------------------
  |  |   68|  10.5k|#  define DEF_WBITS MAX_WBITS
  |  |  ------------------
  |  |  |  |  275|  10.5k|#  define MAX_WBITS   15 /* 32K LZ77 window */
  |  |  ------------------
  ------------------
  248|  10.5k|}
inflate:
  628|  10.5k|{
  629|  10.5k|    struct inflate_state FAR *state;
  630|  10.5k|    z_const unsigned char FAR *next;    /* next input */
  631|  10.5k|    unsigned char FAR *put;     /* next output */
  632|  10.5k|    unsigned have, left;        /* available input and output */
  633|  10.5k|    unsigned long hold;         /* bit buffer */
  634|  10.5k|    unsigned bits;              /* bits in bit buffer */
  635|  10.5k|    unsigned in, out;           /* save starting available input and output */
  636|  10.5k|    unsigned copy;              /* number of stored or match bytes to copy */
  637|  10.5k|    unsigned char FAR *from;    /* where to copy match bytes from */
  638|  10.5k|    code here;                  /* current decoding table entry */
  639|  10.5k|    code last;                  /* parent table entry */
  640|  10.5k|    unsigned len;               /* length to copy for repeats, bits to drop */
  641|  10.5k|    int ret;                    /* return code */
  642|  10.5k|#ifdef GUNZIP
  643|  10.5k|    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
  644|  10.5k|#endif
  645|  10.5k|    static const unsigned short order[19] = /* permutation of code lengths */
  646|  10.5k|        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
  647|       |
  648|  10.5k|    if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||
  ------------------
  |  |  212|  21.1k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (648:9): [True: 0, False: 10.5k]
  |  Branch (648:36): [True: 0, False: 10.5k]
  ------------------
  649|  10.5k|        (strm->next_in == Z_NULL && strm->avail_in != 0))
  ------------------
  |  |  212|  21.1k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (649:10): [True: 0, False: 10.5k]
  |  Branch (649:37): [True: 0, False: 0]
  ------------------
  650|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
  651|       |
  652|  10.5k|    state = (struct inflate_state FAR *)strm->state;
  653|  10.5k|    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
  ------------------
  |  Branch (653:9): [True: 0, False: 10.5k]
  ------------------
  654|  10.5k|    LOAD();
  ------------------
  |  |  480|  10.5k|    do { \
  |  |  481|  10.5k|        put = strm->next_out; \
  |  |  482|  10.5k|        left = strm->avail_out; \
  |  |  483|  10.5k|        next = strm->next_in; \
  |  |  484|  10.5k|        have = strm->avail_in; \
  |  |  485|  10.5k|        hold = state->hold; \
  |  |  486|  10.5k|        bits = state->bits; \
  |  |  487|  10.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (487:14): [Folded, False: 10.5k]
  |  |  ------------------
  ------------------
  655|  10.5k|    in = have;
  656|  10.5k|    out = left;
  657|  10.5k|    ret = Z_OK;
  ------------------
  |  |  177|  10.5k|#define Z_OK            0
  ------------------
  658|  10.5k|    for (;;)
  659|  1.24M|        switch (state->mode) {
  660|  10.5k|        case HEAD:
  ------------------
  |  Branch (660:9): [True: 10.5k, False: 1.23M]
  ------------------
  661|  10.5k|            if (state->wrap == 0) {
  ------------------
  |  Branch (661:17): [True: 0, False: 10.5k]
  ------------------
  662|      0|                state->mode = TYPEDO;
  663|      0|                break;
  664|      0|            }
  665|  10.5k|            NEEDBITS(16);
  ------------------
  |  |  520|  10.5k|    do { \
  |  |  521|  31.6k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 21.1k, False: 10.5k]
  |  |  ------------------
  |  |  522|  21.1k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  21.1k|    do { \
  |  |  |  |  511|  21.1k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 21.1k]
  |  |  |  |  ------------------
  |  |  |  |  512|  21.1k|        have--; \
  |  |  |  |  513|  21.1k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  21.1k|        bits += 8; \
  |  |  |  |  515|  21.1k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 21.1k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  10.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 10.5k]
  |  |  ------------------
  ------------------
  666|  10.5k|#ifdef GUNZIP
  667|  10.5k|            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
  ------------------
  |  Branch (667:17): [True: 0, False: 10.5k]
  |  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|  10.5k|            if (state->head != Z_NULL)
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (676:17): [True: 0, False: 10.5k]
  ------------------
  677|      0|                state->head->done = -1;
  678|  10.5k|            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
  ------------------
  |  Branch (678:17): [True: 0, False: 10.5k]
  ------------------
  679|       |#else
  680|       |            if (
  681|       |#endif
  682|  10.5k|                ((BITS(8) << 8) + (hold >> 8)) % 31) {
  ------------------
  |  |  527|  10.5k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  |  Branch (682:17): [True: 8, False: 10.5k]
  ------------------
  683|      8|                strm->msg = (char *)"incorrect header check";
  684|      8|                state->mode = BAD;
  685|      8|                break;
  686|      8|            }
  687|  10.5k|            if (BITS(4) != Z_DEFLATED) {
  ------------------
  |  |  527|  10.5k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
                          if (BITS(4) != Z_DEFLATED) {
  ------------------
  |  |  209|  10.5k|#define Z_DEFLATED   8
  ------------------
  |  Branch (687:17): [True: 2, False: 10.5k]
  ------------------
  688|      2|                strm->msg = (char *)"unknown compression method";
  689|      2|                state->mode = BAD;
  690|      2|                break;
  691|      2|            }
  692|  10.5k|            DROPBITS(4);
  ------------------
  |  |  531|  10.5k|    do { \
  |  |  532|  10.5k|        hold >>= (n); \
  |  |  533|  10.5k|        bits -= (unsigned)(n); \
  |  |  534|  10.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 10.5k]
  |  |  ------------------
  ------------------
  693|  10.5k|            len = BITS(4) + 8;
  ------------------
  |  |  527|  10.5k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  694|  10.5k|            if (state->wbits == 0)
  ------------------
  |  Branch (694:17): [True: 0, False: 10.5k]
  ------------------
  695|      0|                state->wbits = len;
  696|  10.5k|            if (len > 15 || len > state->wbits) {
  ------------------
  |  Branch (696:17): [True: 1, False: 10.5k]
  |  Branch (696:29): [True: 0, False: 10.5k]
  ------------------
  697|      1|                strm->msg = (char *)"invalid window size";
  698|      1|                state->mode = BAD;
  699|      1|                break;
  700|      1|            }
  701|  10.5k|            state->dmax = 1U << len;
  702|  10.5k|            state->flags = 0;               /* indicate zlib header */
  703|  10.5k|            Tracev((stderr, "inflate:   zlib header ok\n"));
  704|  10.5k|            strm->adler = state->check = adler32(0L, Z_NULL, 0);
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  705|  10.5k|            state->mode = hold & 0x200 ? DICTID : TYPE;
  ------------------
  |  Branch (705:27): [True: 1, False: 10.5k]
  ------------------
  706|  10.5k|            INITBITS();
  ------------------
  |  |  502|  10.5k|    do { \
  |  |  503|  10.5k|        hold = 0; \
  |  |  504|  10.5k|        bits = 0; \
  |  |  505|  10.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 10.5k]
  |  |  ------------------
  ------------------
  707|  10.5k|            break;
  708|      0|#ifdef GUNZIP
  709|      0|        case FLAGS:
  ------------------
  |  Branch (709:9): [True: 0, False: 1.24M]
  ------------------
  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: 1.24M]
  ------------------
  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: 1.24M]
  ------------------
  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: 1.24M]
  ------------------
  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: 1.24M]
  ------------------
  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: 1.24M]
  ------------------
  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: 1.24M]
  ------------------
  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: 1.24M]
  ------------------
  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|      1|        case DICTID:
  ------------------
  |  Branch (848:9): [True: 1, False: 1.24M]
  ------------------
  849|      1|            NEEDBITS(32);
  ------------------
  |  |  520|      1|    do { \
  |  |  521|      5|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 4, False: 1]
  |  |  ------------------
  |  |  522|      4|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|      4|    do { \
  |  |  |  |  511|      4|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 4]
  |  |  |  |  ------------------
  |  |  |  |  512|      4|        have--; \
  |  |  |  |  513|      4|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|      4|        bits += 8; \
  |  |  |  |  515|      4|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 4]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      1|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 1]
  |  |  ------------------
  ------------------
  850|      1|            strm->adler = state->check = ZSWAP32(hold);
  ------------------
  |  |  272|      1|#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
  |  |  273|      1|                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
  ------------------
  851|      1|            INITBITS();
  ------------------
  |  |  502|      1|    do { \
  |  |  503|      1|        hold = 0; \
  |  |  504|      1|        bits = 0; \
  |  |  505|      1|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 1]
  |  |  ------------------
  ------------------
  852|      1|            state->mode = DICT;
  853|       |                /* fallthrough */
  854|      1|        case DICT:
  ------------------
  |  Branch (854:9): [True: 0, False: 1.24M]
  ------------------
  855|      1|            if (state->havedict == 0) {
  ------------------
  |  Branch (855:17): [True: 1, False: 0]
  ------------------
  856|      1|                RESTORE();
  ------------------
  |  |  491|      1|    do { \
  |  |  492|      1|        strm->next_out = put; \
  |  |  493|      1|        strm->avail_out = left; \
  |  |  494|      1|        strm->next_in = next; \
  |  |  495|      1|        strm->avail_in = have; \
  |  |  496|      1|        state->hold = hold; \
  |  |  497|      1|        state->bits = bits; \
  |  |  498|      1|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 1]
  |  |  ------------------
  ------------------
  857|      1|                return Z_NEED_DICT;
  ------------------
  |  |  179|      1|#define Z_NEED_DICT     2
  ------------------
  858|      1|            }
  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|  19.7k|        case TYPE:
  ------------------
  |  Branch (862:9): [True: 19.7k, False: 1.22M]
  ------------------
  863|  19.7k|            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  173|  39.4k|#define Z_BLOCK         5
  ------------------
                          if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  174|  19.7k|#define Z_TREES         6
  ------------------
  |  Branch (863:17): [True: 0, False: 19.7k]
  |  Branch (863:37): [True: 0, False: 19.7k]
  ------------------
  864|       |                /* fallthrough */
  865|  19.7k|        case TYPEDO:
  ------------------
  |  Branch (865:9): [True: 0, False: 1.24M]
  ------------------
  866|  19.7k|            if (state->last) {
  ------------------
  |  Branch (866:17): [True: 9.18k, False: 10.5k]
  ------------------
  867|  9.18k|                BYTEBITS();
  ------------------
  |  |  538|  9.18k|    do { \
  |  |  539|  9.18k|        hold >>= bits & 7; \
  |  |  540|  9.18k|        bits -= bits & 7; \
  |  |  541|  9.18k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (541:14): [Folded, False: 9.18k]
  |  |  ------------------
  ------------------
  868|  9.18k|                state->mode = CHECK;
  869|  9.18k|                break;
  870|  9.18k|            }
  871|  10.5k|            NEEDBITS(3);
  ------------------
  |  |  520|  10.5k|    do { \
  |  |  521|  21.0k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 10.5k, False: 10.5k]
  |  |  ------------------
  |  |  522|  10.5k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  10.5k|    do { \
  |  |  |  |  511|  10.5k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 10.5k]
  |  |  |  |  ------------------
  |  |  |  |  512|  10.5k|        have--; \
  |  |  |  |  513|  10.5k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  10.5k|        bits += 8; \
  |  |  |  |  515|  10.5k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 10.5k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  10.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 10.5k]
  |  |  ------------------
  ------------------
  872|  10.5k|            state->last = BITS(1);
  ------------------
  |  |  527|  10.5k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  873|  10.5k|            DROPBITS(1);
  ------------------
  |  |  531|  10.5k|    do { \
  |  |  532|  10.5k|        hold >>= (n); \
  |  |  533|  10.5k|        bits -= (unsigned)(n); \
  |  |  534|  10.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 10.5k]
  |  |  ------------------
  ------------------
  874|  10.5k|            switch (BITS(2)) {
  ------------------
  |  |  527|  10.5k|    ((unsigned)hold & ((1U << (n)) - 1))
  |  |  ------------------
  |  |  |  Branch (527:5): [True: 10.5k, False: 0]
  |  |  ------------------
  ------------------
  875|      3|            case 0:                             /* stored block */
  ------------------
  |  Branch (875:13): [True: 3, False: 10.5k]
  ------------------
  876|      3|                Tracev((stderr, "inflate:     stored block%s\n",
  877|      3|                        state->last ? " (last)" : ""));
  878|      3|                state->mode = STORED;
  879|      3|                break;
  880|    978|            case 1:                             /* fixed block */
  ------------------
  |  Branch (880:13): [True: 978, False: 9.56k]
  ------------------
  881|    978|                fixedtables(state);
  882|    978|                Tracev((stderr, "inflate:     fixed codes block%s\n",
  883|    978|                        state->last ? " (last)" : ""));
  884|    978|                state->mode = LEN_;             /* decode codes */
  885|    978|                if (flush == Z_TREES) {
  ------------------
  |  |  174|    978|#define Z_TREES         6
  ------------------
  |  Branch (885:21): [True: 0, False: 978]
  ------------------
  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|    978|                break;
  890|  9.56k|            case 2:                             /* dynamic block */
  ------------------
  |  Branch (890:13): [True: 9.56k, False: 981]
  ------------------
  891|  9.56k|                Tracev((stderr, "inflate:     dynamic codes block%s\n",
  892|  9.56k|                        state->last ? " (last)" : ""));
  893|  9.56k|                state->mode = TABLE;
  894|  9.56k|                break;
  895|      0|            case 3:
  ------------------
  |  Branch (895:13): [True: 0, False: 10.5k]
  ------------------
  896|      0|                strm->msg = (char *)"invalid block type";
  897|      0|                state->mode = BAD;
  898|  10.5k|            }
  899|  10.5k|            DROPBITS(2);
  ------------------
  |  |  531|  10.5k|    do { \
  |  |  532|  10.5k|        hold >>= (n); \
  |  |  533|  10.5k|        bits -= (unsigned)(n); \
  |  |  534|  10.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 10.5k]
  |  |  ------------------
  ------------------
  900|  10.5k|            break;
  901|      3|        case STORED:
  ------------------
  |  Branch (901:9): [True: 3, False: 1.24M]
  ------------------
  902|      3|            BYTEBITS();                         /* go to byte boundary */
  ------------------
  |  |  538|      3|    do { \
  |  |  539|      3|        hold >>= bits & 7; \
  |  |  540|      3|        bits -= bits & 7; \
  |  |  541|      3|    } while (0)
  |  |  ------------------
  |  |  |  Branch (541:14): [Folded, False: 3]
  |  |  ------------------
  ------------------
  903|      3|            NEEDBITS(32);
  ------------------
  |  |  520|      3|    do { \
  |  |  521|     14|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 12, False: 2]
  |  |  ------------------
  |  |  522|     12|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|     12|    do { \
  |  |  |  |  511|     12|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 1, False: 11]
  |  |  |  |  ------------------
  |  |  |  |  512|     12|        have--; \
  |  |  |  |  513|     11|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|     11|        bits += 8; \
  |  |  |  |  515|     11|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 11]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|      3|    } 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: 1.24M]
  ------------------
  917|      0|            state->mode = COPY;
  918|       |                /* fallthrough */
  919|      0|        case COPY:
  ------------------
  |  Branch (919:9): [True: 0, False: 1.24M]
  ------------------
  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|  9.56k|        case TABLE:
  ------------------
  |  Branch (936:9): [True: 9.56k, False: 1.23M]
  ------------------
  937|  9.56k|            NEEDBITS(14);
  ------------------
  |  |  520|  9.56k|    do { \
  |  |  521|  28.6k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 19.1k, False: 9.56k]
  |  |  ------------------
  |  |  522|  19.1k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  19.1k|    do { \
  |  |  |  |  511|  19.1k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 19.1k]
  |  |  |  |  ------------------
  |  |  |  |  512|  19.1k|        have--; \
  |  |  |  |  513|  19.1k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  19.1k|        bits += 8; \
  |  |  |  |  515|  19.1k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 19.1k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  9.56k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 9.56k]
  |  |  ------------------
  ------------------
  938|  9.56k|            state->nlen = BITS(5) + 257;
  ------------------
  |  |  527|  9.56k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  939|  9.56k|            DROPBITS(5);
  ------------------
  |  |  531|  9.56k|    do { \
  |  |  532|  9.56k|        hold >>= (n); \
  |  |  533|  9.56k|        bits -= (unsigned)(n); \
  |  |  534|  9.56k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 9.56k]
  |  |  ------------------
  ------------------
  940|  9.56k|            state->ndist = BITS(5) + 1;
  ------------------
  |  |  527|  9.56k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  941|  9.56k|            DROPBITS(5);
  ------------------
  |  |  531|  9.56k|    do { \
  |  |  532|  9.56k|        hold >>= (n); \
  |  |  533|  9.56k|        bits -= (unsigned)(n); \
  |  |  534|  9.56k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 9.56k]
  |  |  ------------------
  ------------------
  942|  9.56k|            state->ncode = BITS(4) + 4;
  ------------------
  |  |  527|  9.56k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  943|  9.56k|            DROPBITS(4);
  ------------------
  |  |  531|  9.56k|    do { \
  |  |  532|  9.56k|        hold >>= (n); \
  |  |  533|  9.56k|        bits -= (unsigned)(n); \
  |  |  534|  9.56k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 9.56k]
  |  |  ------------------
  ------------------
  944|  9.56k|#ifndef PKZIP_BUG_WORKAROUND
  945|  9.56k|            if (state->nlen > 286 || state->ndist > 30) {
  ------------------
  |  Branch (945:17): [True: 0, False: 9.56k]
  |  Branch (945:38): [True: 1, False: 9.55k]
  ------------------
  946|      1|                strm->msg = (char *)"too many length or distance symbols";
  947|      1|                state->mode = BAD;
  948|      1|                break;
  949|      1|            }
  950|  9.55k|#endif
  951|  9.55k|            Tracev((stderr, "inflate:       table sizes ok\n"));
  952|  9.55k|            state->have = 0;
  953|  9.55k|            state->mode = LENLENS;
  954|       |                /* fallthrough */
  955|  9.55k|        case LENLENS:
  ------------------
  |  Branch (955:9): [True: 0, False: 1.24M]
  ------------------
  956|   170k|            while (state->have < state->ncode) {
  ------------------
  |  Branch (956:20): [True: 160k, False: 9.55k]
  ------------------
  957|   160k|                NEEDBITS(3);
  ------------------
  |  |  520|   160k|    do { \
  |  |  521|   217k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 56.7k, False: 160k]
  |  |  ------------------
  |  |  522|   160k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  56.7k|    do { \
  |  |  |  |  511|  56.7k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 56.7k]
  |  |  |  |  ------------------
  |  |  |  |  512|  56.7k|        have--; \
  |  |  |  |  513|  56.7k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  56.7k|        bits += 8; \
  |  |  |  |  515|  56.7k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 56.7k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|   160k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 160k]
  |  |  ------------------
  ------------------
  958|   160k|                state->lens[order[state->have++]] = (unsigned short)BITS(3);
  ------------------
  |  |  527|   160k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  959|   160k|                DROPBITS(3);
  ------------------
  |  |  531|   160k|    do { \
  |  |  532|   160k|        hold >>= (n); \
  |  |  533|   160k|        bits -= (unsigned)(n); \
  |  |  534|   160k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 160k]
  |  |  ------------------
  ------------------
  960|   160k|            }
  961|  30.7k|            while (state->have < 19)
  ------------------
  |  Branch (961:20): [True: 21.1k, False: 9.55k]
  ------------------
  962|  21.1k|                state->lens[order[state->have++]] = 0;
  963|  9.55k|            state->next = state->codes;
  964|  9.55k|            state->lencode = (const code FAR *)(state->next);
  965|  9.55k|            state->lenbits = 7;
  966|  9.55k|            ret = inflate_table(CODES, state->lens, 19, &(state->next),
  967|  9.55k|                                &(state->lenbits), state->work);
  968|  9.55k|            if (ret) {
  ------------------
  |  Branch (968:17): [True: 29, False: 9.53k]
  ------------------
  969|     29|                strm->msg = (char *)"invalid code lengths set";
  970|     29|                state->mode = BAD;
  971|     29|                break;
  972|     29|            }
  973|  9.53k|            Tracev((stderr, "inflate:       code lengths ok\n"));
  974|  9.53k|            state->have = 0;
  975|  9.53k|            state->mode = CODELENS;
  976|       |                /* fallthrough */
  977|  9.53k|        case CODELENS:
  ------------------
  |  Branch (977:9): [True: 0, False: 1.24M]
  ------------------
  978|  1.59M|            while (state->have < state->nlen + state->ndist) {
  ------------------
  |  Branch (978:20): [True: 1.58M, False: 9.48k]
  ------------------
  979|  2.11M|                for (;;) {
  980|  2.11M|                    here = state->lencode[BITS(state->lenbits)];
  ------------------
  |  |  527|  2.11M|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  981|  2.11M|                    if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (981:25): [True: 1.58M, False: 523k]
  ------------------
  982|   523k|                    PULLBYTE();
  ------------------
  |  |  510|   523k|    do { \
  |  |  511|   523k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 523k]
  |  |  ------------------
  |  |  512|   523k|        have--; \
  |  |  513|   523k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|   523k|        bits += 8; \
  |  |  515|   523k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 523k]
  |  |  ------------------
  ------------------
  983|   523k|                }
  984|  1.58M|                if (here.val < 16) {
  ------------------
  |  Branch (984:21): [True: 1.40M, False: 178k]
  ------------------
  985|  1.40M|                    DROPBITS(here.bits);
  ------------------
  |  |  531|  1.40M|    do { \
  |  |  532|  1.40M|        hold >>= (n); \
  |  |  533|  1.40M|        bits -= (unsigned)(n); \
  |  |  534|  1.40M|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 1.40M]
  |  |  ------------------
  ------------------
  986|  1.40M|                    state->lens[state->have++] = here.val;
  987|  1.40M|                }
  988|   178k|                else {
  989|   178k|                    if (here.val == 16) {
  ------------------
  |  Branch (989:25): [True: 119k, False: 59.6k]
  ------------------
  990|   119k|                        NEEDBITS(here.bits + 2);
  ------------------
  |  |  520|   119k|    do { \
  |  |  521|   148k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 29.7k, False: 119k]
  |  |  ------------------
  |  |  522|   119k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  29.7k|    do { \
  |  |  |  |  511|  29.7k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 29.7k]
  |  |  |  |  ------------------
  |  |  |  |  512|  29.7k|        have--; \
  |  |  |  |  513|  29.7k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  29.7k|        bits += 8; \
  |  |  |  |  515|  29.7k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 29.7k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|   119k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 119k]
  |  |  ------------------
  ------------------
  991|   119k|                        DROPBITS(here.bits);
  ------------------
  |  |  531|   119k|    do { \
  |  |  532|   119k|        hold >>= (n); \
  |  |  533|   119k|        bits -= (unsigned)(n); \
  |  |  534|   119k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 119k]
  |  |  ------------------
  ------------------
  992|   119k|                        if (state->have == 0) {
  ------------------
  |  Branch (992:29): [True: 1, False: 119k]
  ------------------
  993|      1|                            strm->msg = (char *)"invalid bit length repeat";
  994|      1|                            state->mode = BAD;
  995|      1|                            break;
  996|      1|                        }
  997|   119k|                        len = state->lens[state->have - 1];
  998|   119k|                        copy = 3 + BITS(2);
  ------------------
  |  |  527|   119k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
  999|   119k|                        DROPBITS(2);
  ------------------
  |  |  531|   119k|    do { \
  |  |  532|   119k|        hold >>= (n); \
  |  |  533|   119k|        bits -= (unsigned)(n); \
  |  |  534|   119k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 119k]
  |  |  ------------------
  ------------------
 1000|   119k|                    }
 1001|  59.6k|                    else if (here.val == 17) {
  ------------------
  |  Branch (1001:30): [True: 48.1k, False: 11.4k]
  ------------------
 1002|  48.1k|                        NEEDBITS(here.bits + 3);
  ------------------
  |  |  520|  48.1k|    do { \
  |  |  521|  65.1k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 17.0k, False: 48.1k]
  |  |  ------------------
  |  |  522|  48.1k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  17.0k|    do { \
  |  |  |  |  511|  17.0k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 17.0k]
  |  |  |  |  ------------------
  |  |  |  |  512|  17.0k|        have--; \
  |  |  |  |  513|  17.0k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  17.0k|        bits += 8; \
  |  |  |  |  515|  17.0k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 17.0k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  48.1k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 48.1k]
  |  |  ------------------
  ------------------
 1003|  48.1k|                        DROPBITS(here.bits);
  ------------------
  |  |  531|  48.1k|    do { \
  |  |  532|  48.1k|        hold >>= (n); \
  |  |  533|  48.1k|        bits -= (unsigned)(n); \
  |  |  534|  48.1k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 48.1k]
  |  |  ------------------
  ------------------
 1004|  48.1k|                        len = 0;
 1005|  48.1k|                        copy = 3 + BITS(3);
  ------------------
  |  |  527|  48.1k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1006|  48.1k|                        DROPBITS(3);
  ------------------
  |  |  531|  48.1k|    do { \
  |  |  532|  48.1k|        hold >>= (n); \
  |  |  533|  48.1k|        bits -= (unsigned)(n); \
  |  |  534|  48.1k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 48.1k]
  |  |  ------------------
  ------------------
 1007|  48.1k|                    }
 1008|  11.4k|                    else {
 1009|  11.4k|                        NEEDBITS(here.bits + 7);
  ------------------
  |  |  520|  11.4k|    do { \
  |  |  521|  21.4k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 10.0k, False: 11.4k]
  |  |  ------------------
  |  |  522|  11.4k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  10.0k|    do { \
  |  |  |  |  511|  10.0k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 10.0k]
  |  |  |  |  ------------------
  |  |  |  |  512|  10.0k|        have--; \
  |  |  |  |  513|  10.0k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  10.0k|        bits += 8; \
  |  |  |  |  515|  10.0k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 10.0k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  11.4k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 11.4k]
  |  |  ------------------
  ------------------
 1010|  11.4k|                        DROPBITS(here.bits);
  ------------------
  |  |  531|  11.4k|    do { \
  |  |  532|  11.4k|        hold >>= (n); \
  |  |  533|  11.4k|        bits -= (unsigned)(n); \
  |  |  534|  11.4k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 11.4k]
  |  |  ------------------
  ------------------
 1011|  11.4k|                        len = 0;
 1012|  11.4k|                        copy = 11 + BITS(7);
  ------------------
  |  |  527|  11.4k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1013|  11.4k|                        DROPBITS(7);
  ------------------
  |  |  531|  11.4k|    do { \
  |  |  532|  11.4k|        hold >>= (n); \
  |  |  533|  11.4k|        bits -= (unsigned)(n); \
  |  |  534|  11.4k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 11.4k]
  |  |  ------------------
  ------------------
 1014|  11.4k|                    }
 1015|   178k|                    if (state->have + copy > state->nlen + state->ndist) {
  ------------------
  |  Branch (1015:25): [True: 46, False: 178k]
  ------------------
 1016|     46|                        strm->msg = (char *)"invalid bit length repeat";
 1017|     46|                        state->mode = BAD;
 1018|     46|                        break;
 1019|     46|                    }
 1020|  1.49M|                    while (copy--)
  ------------------
  |  Branch (1020:28): [True: 1.31M, False: 178k]
  ------------------
 1021|  1.31M|                        state->lens[state->have++] = (unsigned short)len;
 1022|   178k|                }
 1023|  1.58M|            }
 1024|       |
 1025|       |            /* handle error breaks in while */
 1026|  9.53k|            if (state->mode == BAD) break;
  ------------------
  |  Branch (1026:17): [True: 47, False: 9.48k]
  ------------------
 1027|       |
 1028|       |            /* check for end-of-block code (better have one) */
 1029|  9.48k|            if (state->lens[256] == 0) {
  ------------------
  |  Branch (1029:17): [True: 18, False: 9.46k]
  ------------------
 1030|     18|                strm->msg = (char *)"invalid code -- missing end-of-block";
 1031|     18|                state->mode = BAD;
 1032|     18|                break;
 1033|     18|            }
 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|  9.46k|            state->next = state->codes;
 1039|  9.46k|            state->lencode = (const code FAR *)(state->next);
 1040|  9.46k|            state->lenbits = 9;
 1041|  9.46k|            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
 1042|  9.46k|                                &(state->lenbits), state->work);
 1043|  9.46k|            if (ret) {
  ------------------
  |  Branch (1043:17): [True: 209, False: 9.25k]
  ------------------
 1044|    209|                strm->msg = (char *)"invalid literal/lengths set";
 1045|    209|                state->mode = BAD;
 1046|    209|                break;
 1047|    209|            }
 1048|  9.25k|            state->distcode = (const code FAR *)(state->next);
 1049|  9.25k|            state->distbits = 6;
 1050|  9.25k|            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
 1051|  9.25k|                            &(state->next), &(state->distbits), state->work);
 1052|  9.25k|            if (ret) {
  ------------------
  |  Branch (1052:17): [True: 20, False: 9.23k]
  ------------------
 1053|     20|                strm->msg = (char *)"invalid distances set";
 1054|     20|                state->mode = BAD;
 1055|     20|                break;
 1056|     20|            }
 1057|  9.23k|            Tracev((stderr, "inflate:       codes ok\n"));
 1058|  9.23k|            state->mode = LEN_;
 1059|  9.23k|            if (flush == Z_TREES) goto inf_leave;
  ------------------
  |  |  174|  9.23k|#define Z_TREES         6
  ------------------
  |  Branch (1059:17): [True: 0, False: 9.23k]
  ------------------
 1060|       |                /* fallthrough */
 1061|  10.2k|        case LEN_:
  ------------------
  |  Branch (1061:9): [True: 978, False: 1.24M]
  ------------------
 1062|  10.2k|            state->mode = LEN;
 1063|       |                /* fallthrough */
 1064|   805k|        case LEN:
  ------------------
  |  Branch (1064:9): [True: 795k, False: 448k]
  ------------------
 1065|   805k|            if (have >= 6 && left >= 258) {
  ------------------
  |  Branch (1065:17): [True: 795k, False: 10.0k]
  |  Branch (1065:30): [True: 9.77k, False: 785k]
  ------------------
 1066|  9.77k|                RESTORE();
  ------------------
  |  |  491|  9.77k|    do { \
  |  |  492|  9.77k|        strm->next_out = put; \
  |  |  493|  9.77k|        strm->avail_out = left; \
  |  |  494|  9.77k|        strm->next_in = next; \
  |  |  495|  9.77k|        strm->avail_in = have; \
  |  |  496|  9.77k|        state->hold = hold; \
  |  |  497|  9.77k|        state->bits = bits; \
  |  |  498|  9.77k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 9.77k]
  |  |  ------------------
  ------------------
 1067|  9.77k|                inflate_fast(strm, out);
 1068|  9.77k|                LOAD();
  ------------------
  |  |  480|  9.77k|    do { \
  |  |  481|  9.77k|        put = strm->next_out; \
  |  |  482|  9.77k|        left = strm->avail_out; \
  |  |  483|  9.77k|        next = strm->next_in; \
  |  |  484|  9.77k|        have = strm->avail_in; \
  |  |  485|  9.77k|        hold = state->hold; \
  |  |  486|  9.77k|        bits = state->bits; \
  |  |  487|  9.77k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (487:14): [Folded, False: 9.77k]
  |  |  ------------------
  ------------------
 1069|  9.77k|                if (state->mode == TYPE)
  ------------------
  |  Branch (1069:21): [True: 41, False: 9.73k]
  ------------------
 1070|     41|                    state->back = -1;
 1071|  9.77k|                break;
 1072|  9.77k|            }
 1073|   795k|            state->back = 0;
 1074|  1.32M|            for (;;) {
 1075|  1.32M|                here = state->lencode[BITS(state->lenbits)];
  ------------------
  |  |  527|  1.32M|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1076|  1.32M|                if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (1076:21): [True: 795k, False: 524k]
  ------------------
 1077|   524k|                PULLBYTE();
  ------------------
  |  |  510|   524k|    do { \
  |  |  511|   524k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 5, False: 524k]
  |  |  ------------------
  |  |  512|   524k|        have--; \
  |  |  513|   524k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|   524k|        bits += 8; \
  |  |  515|   524k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 524k]
  |  |  ------------------
  ------------------
 1078|   524k|            }
 1079|   795k|            if (here.op && (here.op & 0xf0) == 0) {
  ------------------
  |  Branch (1079:17): [True: 420k, False: 375k]
  |  Branch (1079:28): [True: 24.3k, False: 396k]
  ------------------
 1080|  24.3k|                last = here;
 1081|  26.7k|                for (;;) {
 1082|  26.7k|                    here = state->lencode[last.val +
 1083|  26.7k|                            (BITS(last.bits + last.op) >> last.bits)];
  ------------------
  |  |  527|  26.7k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1084|  26.7k|                    if ((unsigned)(last.bits + here.bits) <= bits) break;
  ------------------
  |  Branch (1084:25): [True: 24.3k, False: 2.45k]
  ------------------
 1085|  2.45k|                    PULLBYTE();
  ------------------
  |  |  510|  2.45k|    do { \
  |  |  511|  2.45k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 2.45k]
  |  |  ------------------
  |  |  512|  2.45k|        have--; \
  |  |  513|  2.45k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|  2.45k|        bits += 8; \
  |  |  515|  2.45k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 2.45k]
  |  |  ------------------
  ------------------
 1086|  2.45k|                }
 1087|  24.3k|                DROPBITS(last.bits);
  ------------------
  |  |  531|  24.3k|    do { \
  |  |  532|  24.3k|        hold >>= (n); \
  |  |  533|  24.3k|        bits -= (unsigned)(n); \
  |  |  534|  24.3k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 24.3k]
  |  |  ------------------
  ------------------
 1088|  24.3k|                state->back += last.bits;
 1089|  24.3k|            }
 1090|   795k|            DROPBITS(here.bits);
  ------------------
  |  |  531|   795k|    do { \
  |  |  532|   795k|        hold >>= (n); \
  |  |  533|   795k|        bits -= (unsigned)(n); \
  |  |  534|   795k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 795k]
  |  |  ------------------
  ------------------
 1091|   795k|            state->back += here.bits;
 1092|   795k|            state->length = (unsigned)here.val;
 1093|   795k|            if ((int)(here.op) == 0) {
  ------------------
  |  Branch (1093:17): [True: 396k, False: 399k]
  ------------------
 1094|   396k|                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
 1095|   396k|                        "inflate:         literal '%c'\n" :
 1096|   396k|                        "inflate:         literal 0x%02x\n", here.val));
 1097|   396k|                state->mode = LIT;
 1098|   396k|                break;
 1099|   396k|            }
 1100|   399k|            if (here.op & 32) {
  ------------------
  |  Branch (1100:17): [True: 9.14k, False: 390k]
  ------------------
 1101|  9.14k|                Tracevv((stderr, "inflate:         end of block\n"));
 1102|  9.14k|                state->back = -1;
 1103|  9.14k|                state->mode = TYPE;
 1104|  9.14k|                break;
 1105|  9.14k|            }
 1106|   390k|            if (here.op & 64) {
  ------------------
  |  Branch (1106:17): [True: 0, False: 390k]
  ------------------
 1107|      0|                strm->msg = (char *)"invalid literal/length code";
 1108|      0|                state->mode = BAD;
 1109|      0|                break;
 1110|      0|            }
 1111|   390k|            state->extra = (unsigned)(here.op) & 15;
 1112|   390k|            state->mode = LENEXT;
 1113|       |                /* fallthrough */
 1114|   390k|        case LENEXT:
  ------------------
  |  Branch (1114:9): [True: 0, False: 1.24M]
  ------------------
 1115|   390k|            if (state->extra) {
  ------------------
  |  Branch (1115:17): [True: 20.7k, False: 369k]
  ------------------
 1116|  20.7k|                NEEDBITS(state->extra);
  ------------------
  |  |  520|  20.7k|    do { \
  |  |  521|  24.9k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 4.14k, False: 20.7k]
  |  |  ------------------
  |  |  522|  20.7k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  4.14k|    do { \
  |  |  |  |  511|  4.14k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 1, False: 4.14k]
  |  |  |  |  ------------------
  |  |  |  |  512|  4.14k|        have--; \
  |  |  |  |  513|  4.14k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  4.14k|        bits += 8; \
  |  |  |  |  515|  4.14k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 4.14k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  20.7k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 20.7k]
  |  |  ------------------
  ------------------
 1117|  20.7k|                state->length += BITS(state->extra);
  ------------------
  |  |  527|  20.7k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1118|  20.7k|                DROPBITS(state->extra);
  ------------------
  |  |  531|  20.7k|    do { \
  |  |  532|  20.7k|        hold >>= (n); \
  |  |  533|  20.7k|        bits -= (unsigned)(n); \
  |  |  534|  20.7k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 20.7k]
  |  |  ------------------
  ------------------
 1119|  20.7k|                state->back += state->extra;
 1120|  20.7k|            }
 1121|   390k|            Tracevv((stderr, "inflate:         length %u\n", state->length));
 1122|   390k|            state->was = state->length;
 1123|   390k|            state->mode = DIST;
 1124|       |                /* fallthrough */
 1125|   390k|        case DIST:
  ------------------
  |  Branch (1125:9): [True: 0, False: 1.24M]
  ------------------
 1126|   512k|            for (;;) {
 1127|   512k|                here = state->distcode[BITS(state->distbits)];
  ------------------
  |  |  527|   512k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1128|   512k|                if ((unsigned)(here.bits) <= bits) break;
  ------------------
  |  Branch (1128:21): [True: 390k, False: 122k]
  ------------------
 1129|   122k|                PULLBYTE();
  ------------------
  |  |  510|   122k|    do { \
  |  |  511|   122k|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 6, False: 122k]
  |  |  ------------------
  |  |  512|   122k|        have--; \
  |  |  513|   122k|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|   122k|        bits += 8; \
  |  |  515|   122k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 122k]
  |  |  ------------------
  ------------------
 1130|   122k|            }
 1131|   390k|            if ((here.op & 0xf0) == 0) {
  ------------------
  |  Branch (1131:17): [True: 1.34k, False: 389k]
  ------------------
 1132|  1.34k|                last = here;
 1133|  1.50k|                for (;;) {
 1134|  1.50k|                    here = state->distcode[last.val +
 1135|  1.50k|                            (BITS(last.bits + last.op) >> last.bits)];
  ------------------
  |  |  527|  1.50k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1136|  1.50k|                    if ((unsigned)(last.bits + here.bits) <= bits) break;
  ------------------
  |  Branch (1136:25): [True: 1.34k, False: 160]
  ------------------
 1137|    160|                    PULLBYTE();
  ------------------
  |  |  510|    160|    do { \
  |  |  511|    160|        if (have == 0) goto inf_leave; \
  |  |  ------------------
  |  |  |  Branch (511:13): [True: 0, False: 160]
  |  |  ------------------
  |  |  512|    160|        have--; \
  |  |  513|    160|        hold += (unsigned long)(*next++) << bits; \
  |  |  514|    160|        bits += 8; \
  |  |  515|    160|    } while (0)
  |  |  ------------------
  |  |  |  Branch (515:14): [Folded, False: 160]
  |  |  ------------------
  ------------------
 1138|    160|                }
 1139|  1.34k|                DROPBITS(last.bits);
  ------------------
  |  |  531|  1.34k|    do { \
  |  |  532|  1.34k|        hold >>= (n); \
  |  |  533|  1.34k|        bits -= (unsigned)(n); \
  |  |  534|  1.34k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 1.34k]
  |  |  ------------------
  ------------------
 1140|  1.34k|                state->back += last.bits;
 1141|  1.34k|            }
 1142|   390k|            DROPBITS(here.bits);
  ------------------
  |  |  531|   390k|    do { \
  |  |  532|   390k|        hold >>= (n); \
  |  |  533|   390k|        bits -= (unsigned)(n); \
  |  |  534|   390k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 390k]
  |  |  ------------------
  ------------------
 1143|   390k|            state->back += here.bits;
 1144|   390k|            if (here.op & 64) {
  ------------------
  |  Branch (1144:17): [True: 2, False: 390k]
  ------------------
 1145|      2|                strm->msg = (char *)"invalid distance code";
 1146|      2|                state->mode = BAD;
 1147|      2|                break;
 1148|      2|            }
 1149|   390k|            state->offset = (unsigned)here.val;
 1150|   390k|            state->extra = (unsigned)(here.op) & 15;
 1151|   390k|            state->mode = DISTEXT;
 1152|       |                /* fallthrough */
 1153|   390k|        case DISTEXT:
  ------------------
  |  Branch (1153:9): [True: 0, False: 1.24M]
  ------------------
 1154|   390k|            if (state->extra) {
  ------------------
  |  Branch (1154:17): [True: 226k, False: 163k]
  ------------------
 1155|   226k|                NEEDBITS(state->extra);
  ------------------
  |  |  520|   226k|    do { \
  |  |  521|   360k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 134k, False: 226k]
  |  |  ------------------
  |  |  522|   226k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|   134k|    do { \
  |  |  |  |  511|   134k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 3, False: 134k]
  |  |  |  |  ------------------
  |  |  |  |  512|   134k|        have--; \
  |  |  |  |  513|   134k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|   134k|        bits += 8; \
  |  |  |  |  515|   134k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 134k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|   226k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 226k]
  |  |  ------------------
  ------------------
 1156|   226k|                state->offset += BITS(state->extra);
  ------------------
  |  |  527|   226k|    ((unsigned)hold & ((1U << (n)) - 1))
  ------------------
 1157|   226k|                DROPBITS(state->extra);
  ------------------
  |  |  531|   226k|    do { \
  |  |  532|   226k|        hold >>= (n); \
  |  |  533|   226k|        bits -= (unsigned)(n); \
  |  |  534|   226k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (534:14): [Folded, False: 226k]
  |  |  ------------------
  ------------------
 1158|   226k|                state->back += state->extra;
 1159|   226k|            }
 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|   390k|            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
 1168|   390k|            state->mode = MATCH;
 1169|       |                /* fallthrough */
 1170|   390k|        case MATCH:
  ------------------
  |  Branch (1170:9): [True: 233, False: 1.24M]
  ------------------
 1171|   390k|            if (left == 0) goto inf_leave;
  ------------------
  |  Branch (1171:17): [True: 271, False: 390k]
  ------------------
 1172|   390k|            copy = out - left;
 1173|   390k|            if (state->offset > copy) {         /* copy from window */
  ------------------
  |  Branch (1173:17): [True: 18, False: 390k]
  ------------------
 1174|     18|                copy = state->offset - copy;
 1175|     18|                if (copy > state->whave) {
  ------------------
  |  Branch (1175:21): [True: 18, False: 0]
  ------------------
 1176|     18|                    if (state->sane) {
  ------------------
  |  Branch (1176:25): [True: 18, False: 0]
  ------------------
 1177|     18|                        strm->msg = (char *)"invalid distance too far back";
 1178|     18|                        state->mode = BAD;
 1179|     18|                        break;
 1180|     18|                    }
 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|     18|                }
 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|   390k|            else {                              /* copy from output */
 1204|   390k|                from = put - state->offset;
 1205|   390k|                copy = state->length;
 1206|   390k|            }
 1207|   390k|            if (copy > left) copy = left;
  ------------------
  |  Branch (1207:17): [True: 233, False: 390k]
  ------------------
 1208|   390k|            left -= copy;
 1209|   390k|            state->length -= copy;
 1210|  1.96M|            do {
 1211|  1.96M|                *put++ = *from++;
 1212|  1.96M|            } while (--copy);
  ------------------
  |  Branch (1212:22): [True: 1.57M, False: 390k]
  ------------------
 1213|   390k|            if (state->length == 0) state->mode = LEN;
  ------------------
  |  Branch (1213:17): [True: 390k, False: 233]
  ------------------
 1214|   390k|            break;
 1215|   396k|        case LIT:
  ------------------
  |  Branch (1215:9): [True: 396k, False: 847k]
  ------------------
 1216|   396k|            if (left == 0) goto inf_leave;
  ------------------
  |  Branch (1216:17): [True: 91, False: 396k]
  ------------------
 1217|   396k|            *put++ = (unsigned char)(state->length);
 1218|   396k|            left--;
 1219|   396k|            state->mode = LEN;
 1220|   396k|            break;
 1221|  9.18k|        case CHECK:
  ------------------
  |  Branch (1221:9): [True: 9.18k, False: 1.23M]
  ------------------
 1222|  9.18k|            if (state->wrap) {
  ------------------
  |  Branch (1222:17): [True: 9.18k, False: 0]
  ------------------
 1223|  9.18k|                NEEDBITS(32);
  ------------------
  |  |  520|  9.18k|    do { \
  |  |  521|  45.9k|        while (bits < (unsigned)(n)) \
  |  |  ------------------
  |  |  |  Branch (521:16): [True: 36.7k, False: 9.18k]
  |  |  ------------------
  |  |  522|  36.7k|            PULLBYTE(); \
  |  |  ------------------
  |  |  |  |  510|  36.7k|    do { \
  |  |  |  |  511|  36.7k|        if (have == 0) goto inf_leave; \
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (511:13): [True: 0, False: 36.7k]
  |  |  |  |  ------------------
  |  |  |  |  512|  36.7k|        have--; \
  |  |  |  |  513|  36.7k|        hold += (unsigned long)(*next++) << bits; \
  |  |  |  |  514|  36.7k|        bits += 8; \
  |  |  |  |  515|  36.7k|    } while (0)
  |  |  |  |  ------------------
  |  |  |  |  |  Branch (515:14): [Folded, False: 36.7k]
  |  |  |  |  ------------------
  |  |  ------------------
  |  |  523|  9.18k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (523:14): [Folded, False: 9.18k]
  |  |  ------------------
  ------------------
 1224|  9.18k|                out -= left;
 1225|  9.18k|                strm->total_out += out;
 1226|  9.18k|                state->total += out;
 1227|  9.18k|                if ((state->wrap & 4) && out)
  ------------------
  |  Branch (1227:21): [True: 9.18k, False: 0]
  |  Branch (1227:42): [True: 9.18k, False: 0]
  ------------------
 1228|  9.18k|                    strm->adler = state->check =
 1229|  9.18k|                        UPDATE_CHECK(state->check, put - out, out);
  ------------------
  |  |  454|  9.18k|    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
  |  |  ------------------
  |  |  |  Branch (454:6): [True: 0, False: 9.18k]
  |  |  ------------------
  ------------------
 1230|  9.18k|                out = left;
 1231|  9.18k|                if ((state->wrap & 4) && (
  ------------------
  |  Branch (1231:21): [True: 9.18k, False: 0]
  |  Branch (1231:42): [True: 854, False: 8.33k]
  ------------------
 1232|  9.18k|#ifdef GUNZIP
 1233|  9.18k|                     state->flags ? hold :
  ------------------
  |  Branch (1233:22): [True: 0, False: 9.18k]
  ------------------
 1234|  9.18k|#endif
 1235|  9.18k|                     ZSWAP32(hold)) != state->check) {
  ------------------
  |  |  272|  9.18k|#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
  |  |  273|  9.18k|                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
  ------------------
 1236|    854|                    strm->msg = (char *)"incorrect data check";
 1237|    854|                    state->mode = BAD;
 1238|    854|                    break;
 1239|    854|                }
 1240|  8.33k|                INITBITS();
  ------------------
  |  |  502|  8.33k|    do { \
  |  |  503|  8.33k|        hold = 0; \
  |  |  504|  8.33k|        bits = 0; \
  |  |  505|  8.33k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (505:14): [Folded, False: 8.33k]
  |  |  ------------------
  ------------------
 1241|  8.33k|                Tracev((stderr, "inflate:   check matches trailer\n"));
 1242|  8.33k|            }
 1243|  8.33k|#ifdef GUNZIP
 1244|  8.33k|            state->mode = LENGTH;
 1245|       |                /* fallthrough */
 1246|  8.33k|        case LENGTH:
  ------------------
  |  Branch (1246:9): [True: 0, False: 1.24M]
  ------------------
 1247|  8.33k|            if (state->wrap && state->flags) {
  ------------------
  |  Branch (1247:17): [True: 8.33k, False: 0]
  |  Branch (1247:32): [True: 0, False: 8.33k]
  ------------------
 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|  8.33k|#endif
 1258|  8.33k|            state->mode = DONE;
 1259|       |                /* fallthrough */
 1260|  8.33k|        case DONE:
  ------------------
  |  Branch (1260:9): [True: 0, False: 1.24M]
  ------------------
 1261|  8.33k|            ret = Z_STREAM_END;
  ------------------
  |  |  178|  8.33k|#define Z_STREAM_END    1
  ------------------
 1262|  8.33k|            goto inf_leave;
 1263|  1.84k|        case BAD:
  ------------------
  |  Branch (1263:9): [True: 1.84k, False: 1.24M]
  ------------------
 1264|  1.84k|            ret = Z_DATA_ERROR;
  ------------------
  |  |  182|  1.84k|#define Z_DATA_ERROR   (-3)
  ------------------
 1265|  1.84k|            goto inf_leave;
 1266|      0|        case MEM:
  ------------------
  |  Branch (1266:9): [True: 0, False: 1.24M]
  ------------------
 1267|      0|            return Z_MEM_ERROR;
  ------------------
  |  |  183|      0|#define Z_MEM_ERROR    (-4)
  ------------------
 1268|      0|        case SYNC:
  ------------------
  |  Branch (1268:9): [True: 0, False: 1.24M]
  ------------------
 1269|       |                /* fallthrough */
 1270|      0|        default:
  ------------------
  |  Branch (1270:9): [True: 0, False: 1.24M]
  ------------------
 1271|      0|            return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
 1272|  1.24M|        }
 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|  10.5k|  inf_leave:
 1281|  10.5k|    RESTORE();
  ------------------
  |  |  491|  10.5k|    do { \
  |  |  492|  10.5k|        strm->next_out = put; \
  |  |  493|  10.5k|        strm->avail_out = left; \
  |  |  494|  10.5k|        strm->next_in = next; \
  |  |  495|  10.5k|        strm->avail_in = have; \
  |  |  496|  10.5k|        state->hold = hold; \
  |  |  497|  10.5k|        state->bits = bits; \
  |  |  498|  10.5k|    } while (0)
  |  |  ------------------
  |  |  |  Branch (498:14): [Folded, False: 10.5k]
  |  |  ------------------
  ------------------
 1282|  10.5k|    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
  ------------------
  |  Branch (1282:9): [True: 0, False: 10.5k]
  |  Branch (1282:26): [True: 1.02k, False: 9.52k]
  |  Branch (1282:52): [True: 378, False: 648]
  ------------------
 1283|    378|            (state->mode < CHECK || flush != Z_FINISH)))
  ------------------
  |  |  172|      0|#define Z_FINISH        4
  ------------------
  |  Branch (1283:14): [True: 378, False: 0]
  |  Branch (1283:37): [True: 0, False: 0]
  ------------------
 1284|    378|        if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
  ------------------
  |  Branch (1284:13): [True: 0, False: 378]
  ------------------
 1285|      0|            state->mode = MEM;
 1286|      0|            return Z_MEM_ERROR;
  ------------------
  |  |  183|      0|#define Z_MEM_ERROR    (-4)
  ------------------
 1287|      0|        }
 1288|  10.5k|    in -= strm->avail_in;
 1289|  10.5k|    out -= strm->avail_out;
 1290|  10.5k|    strm->total_in += in;
 1291|  10.5k|    strm->total_out += out;
 1292|  10.5k|    state->total += out;
 1293|  10.5k|    if ((state->wrap & 4) && out)
  ------------------
  |  Branch (1293:9): [True: 10.5k, False: 0]
  |  Branch (1293:30): [True: 1.02k, False: 9.52k]
  ------------------
 1294|  1.02k|        strm->adler = state->check =
 1295|  1.02k|            UPDATE_CHECK(state->check, strm->next_out - out, out);
  ------------------
  |  |  454|  1.02k|    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
  |  |  ------------------
  |  |  |  Branch (454:6): [True: 0, False: 1.02k]
  |  |  ------------------
  ------------------
 1296|  10.5k|    strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
  ------------------
  |  Branch (1296:43): [True: 10.5k, False: 16]
  ------------------
 1297|  10.5k|                      (state->mode == TYPE ? 128 : 0) +
  ------------------
  |  Branch (1297:24): [True: 0, False: 10.5k]
  ------------------
 1298|  10.5k|                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
  ------------------
  |  Branch (1298:24): [True: 0, False: 10.5k]
  |  Branch (1298:47): [True: 0, False: 10.5k]
  ------------------
 1299|  10.5k|    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
  ------------------
  |  |  172|  10.5k|#define Z_FINISH        4
  ------------------
                  if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
  ------------------
  |  |  177|  10.5k|#define Z_OK            0
  ------------------
  |  Branch (1299:11): [True: 0, False: 10.5k]
  |  Branch (1299:22): [True: 0, False: 0]
  |  Branch (1299:35): [True: 10.5k, False: 0]
  |  Branch (1299:57): [True: 378, False: 10.1k]
  ------------------
 1300|    378|        ret = Z_BUF_ERROR;
  ------------------
  |  |  184|    378|#define Z_BUF_ERROR    (-5)
  ------------------
 1301|  10.5k|    return ret;
 1302|  10.5k|}
inflateEnd:
 1306|  10.5k|{
 1307|  10.5k|    struct inflate_state FAR *state;
 1308|  10.5k|    if (inflateStateCheck(strm))
  ------------------
  |  Branch (1308:9): [True: 0, False: 10.5k]
  ------------------
 1309|      0|        return Z_STREAM_ERROR;
  ------------------
  |  |  181|      0|#define Z_STREAM_ERROR (-2)
  ------------------
 1310|  10.5k|    state = (struct inflate_state FAR *)strm->state;
 1311|  10.5k|    if (state->window != Z_NULL) ZFREE(strm, state->window);
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
                  if (state->window != Z_NULL) ZFREE(strm, state->window);
  ------------------
  |  |  268|    378|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
  |  Branch (1311:9): [True: 378, False: 10.1k]
  ------------------
 1312|  10.5k|    ZFREE(strm, strm->state);
  ------------------
  |  |  268|  10.5k|#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
  ------------------
 1313|  10.5k|    strm->state = Z_NULL;
  ------------------
  |  |  212|  10.5k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
 1314|  10.5k|    Tracev((stderr, "inflate: end\n"));
 1315|  10.5k|    return Z_OK;
  ------------------
  |  |  177|  10.5k|#define Z_OK            0
  ------------------
 1316|  10.5k|}
inflate.c:inflateStateCheck:
  107|  52.7k|{
  108|  52.7k|    struct inflate_state FAR *state;
  109|  52.7k|    if (strm == Z_NULL ||
  ------------------
  |  |  212|   105k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (109:9): [True: 0, False: 52.7k]
  ------------------
  110|  52.7k|        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
  ------------------
  |  Branch (110:9): [True: 0, False: 52.7k]
  |  Branch (110:42): [True: 0, False: 52.7k]
  ------------------
  111|      0|        return 1;
  112|  52.7k|    state = (struct inflate_state FAR *)strm->state;
  113|  52.7k|    if (state == Z_NULL || state->strm != strm ||
  ------------------
  |  |  212|   105k|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (113:9): [True: 0, False: 52.7k]
  |  Branch (113:28): [True: 0, False: 52.7k]
  ------------------
  114|  52.7k|        state->mode < HEAD || state->mode > SYNC)
  ------------------
  |  Branch (114:9): [True: 0, False: 52.7k]
  |  Branch (114:31): [True: 0, False: 52.7k]
  ------------------
  115|      0|        return 1;
  116|  52.7k|    return 0;
  117|  52.7k|}
inflate.c:fixedtables:
  283|    978|{
  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|    978|#   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|    978|    static const code lenfix[512] = {
  |  |   11|    978|        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
  |  |   12|    978|        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
  |  |   13|    978|        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
  |  |   14|    978|        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
  |  |   15|    978|        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
  |  |   16|    978|        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
  |  |   17|    978|        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
  |  |   18|    978|        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
  |  |   19|    978|        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
  |  |   20|    978|        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
  |  |   21|    978|        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
  |  |   22|    978|        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
  |  |   23|    978|        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
  |  |   24|    978|        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
  |  |   25|    978|        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
  |  |   26|    978|        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
  |  |   27|    978|        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
  |  |   28|    978|        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
  |  |   29|    978|        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
  |  |   30|    978|        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
  |  |   31|    978|        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
  |  |   32|    978|        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
  |  |   33|    978|        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
  |  |   34|    978|        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
  |  |   35|    978|        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
  |  |   36|    978|        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
  |  |   37|    978|        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
  |  |   38|    978|        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
  |  |   39|    978|        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
  |  |   40|    978|        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
  |  |   41|    978|        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
  |  |   42|    978|        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
  |  |   43|    978|        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
  |  |   44|    978|        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
  |  |   45|    978|        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
  |  |   46|    978|        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
  |  |   47|    978|        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
  |  |   48|    978|        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
  |  |   49|    978|        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
  |  |   50|    978|        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
  |  |   51|    978|        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
  |  |   52|    978|        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
  |  |   53|    978|        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
  |  |   54|    978|        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
  |  |   55|    978|        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
  |  |   56|    978|        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
  |  |   57|    978|        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
  |  |   58|    978|        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
  |  |   59|    978|        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
  |  |   60|    978|        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
  |  |   61|    978|        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
  |  |   62|    978|        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
  |  |   63|    978|        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
  |  |   64|    978|        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
  |  |   65|    978|        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
  |  |   66|    978|        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
  |  |   67|    978|        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
  |  |   68|    978|        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
  |  |   69|    978|        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
  |  |   70|    978|        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
  |  |   71|    978|        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
  |  |   72|    978|        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
  |  |   73|    978|        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
  |  |   74|    978|        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
  |  |   75|    978|        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
  |  |   76|    978|        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
  |  |   77|    978|        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
  |  |   78|    978|        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
  |  |   79|    978|        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
  |  |   80|    978|        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
  |  |   81|    978|        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
  |  |   82|    978|        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
  |  |   83|    978|        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
  |  |   84|    978|        {0,9,255}
  |  |   85|    978|    };
  |  |   86|       |
  |  |   87|    978|    static const code distfix[32] = {
  |  |   88|    978|        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
  |  |   89|    978|        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
  |  |   90|    978|        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
  |  |   91|    978|        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
  |  |   92|    978|        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
  |  |   93|    978|        {22,5,193},{64,5,0}
  |  |   94|    978|    };
  ------------------
  317|    978|#endif /* BUILDFIXED */
  318|    978|    state->lencode = lenfix;
  319|    978|    state->lenbits = 9;
  320|    978|    state->distcode = distfix;
  321|    978|    state->distbits = 5;
  322|    978|}
inflate.c:updatewindow:
  403|    378|{
  404|    378|    struct inflate_state FAR *state;
  405|    378|    unsigned dist;
  406|       |
  407|    378|    state = (struct inflate_state FAR *)strm->state;
  408|       |
  409|       |    /* if it hasn't been done already, allocate space for the window */
  410|    378|    if (state->window == Z_NULL) {
  ------------------
  |  |  212|    378|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (410:9): [True: 378, False: 0]
  ------------------
  411|    378|        state->window = (unsigned char FAR *)
  412|    378|                        ZALLOC(strm, 1U << state->wbits,
  ------------------
  |  |  267|    378|           (*((strm)->zalloc))((strm)->opaque, (items), (size))
  ------------------
  413|    378|                               sizeof(unsigned char));
  414|    378|        if (state->window == Z_NULL) return 1;
  ------------------
  |  |  212|    378|#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
  ------------------
  |  Branch (414:13): [True: 0, False: 378]
  ------------------
  415|    378|    }
  416|       |
  417|       |    /* if window not in use yet, initialize */
  418|    378|    if (state->wsize == 0) {
  ------------------
  |  Branch (418:9): [True: 378, False: 0]
  ------------------
  419|    378|        state->wsize = 1U << state->wbits;
  420|    378|        state->wnext = 0;
  421|    378|        state->whave = 0;
  422|    378|    }
  423|       |
  424|       |    /* copy state->wsize or less output bytes into the circular window */
  425|    378|    if (copy >= state->wsize) {
  ------------------
  |  Branch (425:9): [True: 6, False: 372]
  ------------------
  426|      6|        zmemcpy(state->window, end - state->wsize, state->wsize);
  ------------------
  |  |  230|      6|#    define zmemcpy memcpy
  ------------------
  427|      6|        state->wnext = 0;
  428|      6|        state->whave = state->wsize;
  429|      6|    }
  430|    372|    else {
  431|    372|        dist = state->wsize - state->wnext;
  432|    372|        if (dist > copy) dist = copy;
  ------------------
  |  Branch (432:13): [True: 372, False: 0]
  ------------------
  433|    372|        zmemcpy(state->window + state->wnext, end - copy, dist);
  ------------------
  |  |  230|    372|#    define zmemcpy memcpy
  ------------------
  434|    372|        copy -= dist;
  435|    372|        if (copy) {
  ------------------
  |  Branch (435:13): [True: 0, False: 372]
  ------------------
  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|    372|        else {
  441|    372|            state->wnext += dist;
  442|    372|            if (state->wnext == state->wsize) state->wnext = 0;
  ------------------
  |  Branch (442:17): [True: 0, False: 372]
  ------------------
  443|    372|            if (state->whave < state->wsize) state->whave += dist;
  ------------------
  |  Branch (443:17): [True: 372, False: 0]
  ------------------
  444|    372|        }
  445|    372|    }
  446|    378|    return 0;
  447|    378|}

inflate_table:
   39|  28.2k|{
   40|  28.2k|    unsigned len;               /* a code's length in bits */
   41|  28.2k|    unsigned sym;               /* index of code symbols */
   42|  28.2k|    unsigned min, max;          /* minimum and maximum code lengths */
   43|  28.2k|    unsigned root;              /* number of index bits for root table */
   44|  28.2k|    unsigned curr;              /* number of index bits for current table */
   45|  28.2k|    unsigned drop;              /* code bits to drop for sub-table */
   46|  28.2k|    int left;                   /* number of prefix codes available */
   47|  28.2k|    unsigned used;              /* code entries in table used */
   48|  28.2k|    unsigned huff;              /* Huffman code */
   49|  28.2k|    unsigned incr;              /* for incrementing code, index */
   50|  28.2k|    unsigned fill;              /* index for replicating entries */
   51|  28.2k|    unsigned low;               /* low bits for current root entry */
   52|  28.2k|    unsigned mask;              /* mask for low root bits */
   53|  28.2k|    code here;                  /* table entry for duplication */
   54|  28.2k|    code FAR *next;             /* next available space in table */
   55|  28.2k|    const unsigned short FAR *base;     /* base value table to use */
   56|  28.2k|    const unsigned short FAR *extra;    /* extra bits table to use */
   57|  28.2k|    unsigned match;             /* use base and extra for symbol >= match */
   58|  28.2k|    unsigned short count[MAXBITS+1];    /* number of codes of each length */
   59|  28.2k|    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
   60|  28.2k|    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
   61|  28.2k|        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
   62|  28.2k|        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
   63|  28.2k|    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
   64|  28.2k|        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
   65|  28.2k|        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65};
   66|  28.2k|    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
   67|  28.2k|        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
   68|  28.2k|        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
   69|  28.2k|        8193, 12289, 16385, 24577, 0, 0};
   70|  28.2k|    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
   71|  28.2k|        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
   72|  28.2k|        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
   73|  28.2k|        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|   480k|    for (len = 0; len <= MAXBITS; len++)
  ------------------
  |  |    9|   480k|#define MAXBITS 15
  ------------------
  |  Branch (107:19): [True: 452k, False: 28.2k]
  ------------------
  108|   452k|        count[len] = 0;
  109|  2.91M|    for (sym = 0; sym < codes; sym++)
  ------------------
  |  Branch (109:19): [True: 2.88M, False: 28.2k]
  ------------------
  110|  2.88M|        count[lens[sym]]++;
  111|       |
  112|       |    /* bound code lengths, force root to be within code lengths */
  113|  28.2k|    root = *bits;
  114|   256k|    for (max = MAXBITS; max >= 1; max--)
  ------------------
  |  |    9|  28.2k|#define MAXBITS 15
  ------------------
  |  Branch (114:25): [True: 256k, False: 2]
  ------------------
  115|   256k|        if (count[max] != 0) break;
  ------------------
  |  Branch (115:13): [True: 28.2k, False: 228k]
  ------------------
  116|  28.2k|    if (root > max) root = max;
  ------------------
  |  Branch (116:9): [True: 11.1k, False: 17.1k]
  ------------------
  117|  28.2k|    if (max == 0) {                     /* no symbols to code at all */
  ------------------
  |  Branch (117:9): [True: 2, False: 28.2k]
  ------------------
  118|      2|        here.op = (unsigned char)64;    /* invalid code marker */
  119|      2|        here.bits = (unsigned char)1;
  120|      2|        here.val = (unsigned short)0;
  121|      2|        *(*table)++ = here;             /* make a table to force an error */
  122|      2|        *(*table)++ = here;
  123|      2|        *bits = 1;
  124|      2|        return 0;     /* no symbols, but wait for decoding to report error */
  125|      2|    }
  126|  52.7k|    for (min = 1; min < max; min++)
  ------------------
  |  Branch (126:19): [True: 52.1k, False: 586]
  ------------------
  127|  52.1k|        if (count[min] != 0) break;
  ------------------
  |  Branch (127:13): [True: 27.6k, False: 24.4k]
  ------------------
  128|  28.2k|    if (root < min) root = min;
  ------------------
  |  Branch (128:9): [True: 1, False: 28.2k]
  ------------------
  129|       |
  130|       |    /* check for an over-subscribed or incomplete set of lengths */
  131|  28.2k|    left = 1;
  132|   451k|    for (len = 1; len <= MAXBITS; len++) {
  ------------------
  |  |    9|   451k|#define MAXBITS 15
  ------------------
  |  Branch (132:19): [True: 422k, False: 28.1k]
  ------------------
  133|   422k|        left <<= 1;
  134|   422k|        left -= count[len];
  135|   422k|        if (left < 0) return -1;        /* over-subscribed */
  ------------------
  |  Branch (135:13): [True: 177, False: 422k]
  ------------------
  136|   422k|    }
  137|  28.1k|    if (left > 0 && (type == CODES || max != 1))
  ------------------
  |  Branch (137:9): [True: 82, False: 28.0k]
  |  Branch (137:22): [True: 12, False: 70]
  |  Branch (137:39): [True: 69, False: 1]
  ------------------
  138|     81|        return -1;                      /* incomplete set */
  139|       |
  140|       |    /* generate offsets into symbol table for each length for sorting */
  141|  28.0k|    offs[1] = 0;
  142|   420k|    for (len = 1; len < MAXBITS; len++)
  ------------------
  |  |    9|   420k|#define MAXBITS 15
  ------------------
  |  Branch (142:19): [True: 392k, False: 28.0k]
  ------------------
  143|   392k|        offs[len + 1] = offs[len] + count[len];
  144|       |
  145|       |    /* sort symbols by length, by symbol order within each length */
  146|  2.85M|    for (sym = 0; sym < codes; sym++)
  ------------------
  |  Branch (146:19): [True: 2.82M, False: 28.0k]
  ------------------
  147|  2.82M|        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
  ------------------
  |  Branch (147:13): [True: 1.79M, False: 1.03M]
  ------------------
  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|  28.0k|    switch (type) {
  182|  9.52k|    case CODES:
  ------------------
  |  Branch (182:5): [True: 9.52k, False: 18.4k]
  ------------------
  183|  9.52k|        base = extra = work;    /* dummy value--not used */
  184|  9.52k|        match = 20;
  185|  9.52k|        break;
  186|  9.25k|    case LENS:
  ------------------
  |  Branch (186:5): [True: 9.25k, False: 18.7k]
  ------------------
  187|  9.25k|        base = lbase;
  188|  9.25k|        extra = lext;
  189|  9.25k|        match = 257;
  190|  9.25k|        break;
  191|  9.23k|    default:    /* DISTS */
  ------------------
  |  Branch (191:5): [True: 9.23k, False: 18.7k]
  ------------------
  192|  9.23k|        base = dbase;
  193|  9.23k|        extra = dext;
  194|  9.23k|        match = 0;
  195|  28.0k|    }
  196|       |
  197|       |    /* initialize state for loop */
  198|  28.0k|    huff = 0;                   /* starting code */
  199|  28.0k|    sym = 0;                    /* starting code symbol */
  200|  28.0k|    len = min;                  /* starting code length */
  201|  28.0k|    next = *table;              /* current table to fill in */
  202|  28.0k|    curr = root;                /* current table index bits */
  203|  28.0k|    drop = 0;                   /* current bits to drop from code for index */
  204|  28.0k|    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
  205|  28.0k|    used = 1U << root;          /* use root table entries */
  206|  28.0k|    mask = used - 1;            /* mask for comparing low */
  207|       |
  208|       |    /* check available table space */
  209|  28.0k|    if ((type == LENS && used > ENOUGH_LENS) ||
  ------------------
  |  |   49|  9.25k|#define ENOUGH_LENS 852
  ------------------
  |  Branch (209:10): [True: 9.25k, False: 18.7k]
  |  Branch (209:26): [True: 0, False: 9.25k]
  ------------------
  210|  28.0k|        (type == DISTS && used > ENOUGH_DISTS))
  ------------------
  |  |   50|  9.23k|#define ENOUGH_DISTS 592
  ------------------
  |  Branch (210:10): [True: 9.23k, False: 18.7k]
  |  Branch (210:27): [True: 0, False: 9.23k]
  ------------------
  211|      0|        return 1;
  212|       |
  213|       |    /* process all codes and make table entries */
  214|  1.79M|    for (;;) {
  215|       |        /* create table entry */
  216|  1.79M|        here.bits = (unsigned char)(len - drop);
  217|  1.79M|        if (work[sym] + 1U < match) {
  ------------------
  |  Branch (217:13): [True: 1.62M, False: 178k]
  ------------------
  218|  1.62M|            here.op = (unsigned char)0;
  219|  1.62M|            here.val = work[sym];
  220|  1.62M|        }
  221|   178k|        else if (work[sym] >= match) {
  ------------------
  |  Branch (221:18): [True: 169k, False: 9.25k]
  ------------------
  222|   169k|            here.op = (unsigned char)(extra[work[sym] - match]);
  223|   169k|            here.val = base[work[sym] - match];
  224|   169k|        }
  225|  9.25k|        else {
  226|  9.25k|            here.op = (unsigned char)(32 + 64);         /* end of block */
  227|  9.25k|            here.val = 0;
  228|  9.25k|        }
  229|       |
  230|       |        /* replicate for those indices with low len bits equal to huff */
  231|  1.79M|        incr = 1U << (len - drop);
  232|  1.79M|        fill = 1U << curr;
  233|  1.79M|        min = fill;                 /* save offset to next table */
  234|  5.48M|        do {
  235|  5.48M|            fill -= incr;
  236|  5.48M|            next[(huff >> drop) + fill] = here;
  237|  5.48M|        } while (fill != 0);
  ------------------
  |  Branch (237:18): [True: 3.68M, False: 1.79M]
  ------------------
  238|       |
  239|       |        /* backwards increment the len-bit code huff */
  240|  1.79M|        incr = 1U << (len - 1);
  241|  3.56M|        while (huff & incr)
  ------------------
  |  Branch (241:16): [True: 1.77M, False: 1.79M]
  ------------------
  242|  1.77M|            incr >>= 1;
  243|  1.79M|        if (incr != 0) {
  ------------------
  |  Branch (243:13): [True: 1.77M, False: 28.0k]
  ------------------
  244|  1.77M|            huff &= incr - 1;
  245|  1.77M|            huff += incr;
  246|  1.77M|        }
  247|  28.0k|        else
  248|  28.0k|            huff = 0;
  249|       |
  250|       |        /* go to next symbol, update count, len */
  251|  1.79M|        sym++;
  252|  1.79M|        if (--(count[len]) == 0) {
  ------------------
  |  Branch (252:13): [True: 142k, False: 1.65M]
  ------------------
  253|   142k|            if (len == max) break;
  ------------------
  |  Branch (253:17): [True: 28.0k, False: 114k]
  ------------------
  254|   114k|            len = lens[work[sym]];
  255|   114k|        }
  256|       |
  257|       |        /* create new sub-table if needed */
  258|  1.77M|        if (len > root && (huff & mask) != low) {
  ------------------
  |  Branch (258:13): [True: 313k, False: 1.45M]
  |  Branch (258:27): [True: 145k, False: 168k]
  ------------------
  259|       |            /* if first time, transition to sub-tables */
  260|   145k|            if (drop == 0)
  ------------------
  |  Branch (260:17): [True: 7.01k, False: 138k]
  ------------------
  261|  7.01k|                drop = root;
  262|       |
  263|       |            /* increment past last table */
  264|   145k|            next += min;            /* here min is 1 << curr */
  265|       |
  266|       |            /* determine length of next table */
  267|   145k|            curr = len - drop;
  268|   145k|            left = (int)(1 << curr);
  269|   147k|            while (curr + drop < max) {
  ------------------
  |  Branch (269:20): [True: 26.7k, False: 120k]
  ------------------
  270|  26.7k|                left -= count[curr + drop];
  271|  26.7k|                if (left <= 0) break;
  ------------------
  |  Branch (271:21): [True: 24.7k, False: 2.01k]
  ------------------
  272|  2.01k|                curr++;
  273|  2.01k|                left <<= 1;
  274|  2.01k|            }
  275|       |
  276|       |            /* check for enough space */
  277|   145k|            used += 1U << curr;
  278|   145k|            if ((type == LENS && used > ENOUGH_LENS) ||
  ------------------
  |  |   49|   142k|#define ENOUGH_LENS 852
  ------------------
  |  Branch (278:18): [True: 142k, False: 3.52k]
  |  Branch (278:34): [True: 0, False: 142k]
  ------------------
  279|   145k|                (type == DISTS && used > ENOUGH_DISTS))
  ------------------
  |  |   50|  3.52k|#define ENOUGH_DISTS 592
  ------------------
  |  Branch (279:18): [True: 3.52k, False: 142k]
  |  Branch (279:35): [True: 0, False: 3.52k]
  ------------------
  280|      0|                return 1;
  281|       |
  282|       |            /* point entry in root table to sub-table */
  283|   145k|            low = huff & mask;
  284|   145k|            (*table)[low].op = (unsigned char)curr;
  285|   145k|            (*table)[low].bits = (unsigned char)root;
  286|   145k|            (*table)[low].val = (unsigned short)(next - *table);
  287|   145k|        }
  288|  1.77M|    }
  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|  28.0k|    if (huff != 0) {
  ------------------
  |  Branch (293:9): [True: 1, False: 28.0k]
  ------------------
  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|  28.0k|    *table += used;
  302|  28.0k|    *bits = root;
  303|  28.0k|    return 0;
  304|  28.0k|}

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

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

_ZN10AssimpFuzz11ForceFormatERN6Assimp8ImporterEPKc:
   53|    402|inline bool ForceFormat(Assimp::Importer& importer, const char* targetExtension) {
   54|    402|    size_t count = importer.GetImporterCount();
   55|    402|    std::vector<Assimp::BaseImporter*> toRemove;
   56|    402|    bool found = false;
   57|       |
   58|  19.6k|    for (size_t i = 0; i < count; ++i) {
  ------------------
  |  Branch (58:24): [True: 19.2k, False: 402]
  ------------------
   59|  19.2k|        const aiImporterDesc* desc = importer.GetImporterInfo(i);
   60|  19.2k|        Assimp::BaseImporter* imp = importer.GetImporter(i);
   61|       |        
   62|  19.2k|        if (!desc || !imp) continue;
  ------------------
  |  Branch (62:13): [True: 0, False: 19.2k]
  |  Branch (62:22): [True: 0, False: 19.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|  19.2k|        bool isTarget = false;
   72|  19.2k|        const char* extList = desc->mFileExtensions;
   73|  19.2k|        if (!extList) {
  ------------------
  |  Branch (73:13): [True: 0, False: 19.2k]
  ------------------
   74|      0|            toRemove.push_back(imp);
   75|      0|            continue;
   76|      0|        }
   77|  19.2k|        const size_t targetLen = strlen(targetExtension);
   78|       |
   79|  19.2k|        const char* p = extList;
   80|  19.2k|        while ((p = strstr(p, targetExtension)) != nullptr) {
  ------------------
  |  Branch (80:16): [True: 402, False: 18.8k]
  ------------------
   81|       |            // Check boundaries
   82|    402|            const char prev = (p == extList) ? ' ' : *(p - 1);
  ------------------
  |  Branch (82:31): [True: 402, False: 0]
  ------------------
   83|    402|            const char next = *(p + targetLen);
   84|       |            
   85|    402|            if (prev == ' ' && (next == ' ' || next == '\0')) {
  ------------------
  |  Branch (85:17): [True: 402, False: 0]
  |  Branch (85:33): [True: 0, False: 402]
  |  Branch (85:48): [True: 402, False: 0]
  ------------------
   86|    402|                isTarget = true;
   87|    402|                break;
   88|    402|            }
   89|      0|            p++;
   90|      0|        }
   91|       |
   92|  19.2k|        if (isTarget) {
  ------------------
  |  Branch (92:13): [True: 402, False: 18.8k]
  ------------------
   93|    402|            found = true;
   94|  18.8k|        } else {
   95|  18.8k|            toRemove.push_back(imp);
   96|  18.8k|        }
   97|  19.2k|    }
   98|       |
   99|  18.8k|    for (auto* imp : toRemove) {
  ------------------
  |  Branch (99:20): [True: 18.8k, False: 402]
  ------------------
  100|  18.8k|        importer.UnregisterLoader(imp);
  101|  18.8k|        delete imp;  // Free the unregistered importer to prevent memory leaks
  102|  18.8k|    }
  103|       |
  104|    402|    return found;
  105|    402|}

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

