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

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

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

_ZN6Assimp12D3MFImporterC2Ev:
   59|  12.0k|    D3MFImporter() = default;

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

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

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

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

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

_ZN6Assimp11B3DImporterC2Ev:
   66|  12.0k|    B3DImporter() = default;

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

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

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

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

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

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

_ZN6Assimp11COBImporterC2Ev:
   77|  12.0k|    COBImporter() = default;

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

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

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

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

_ZN6Assimp11DXFImporterC2Ev:
   71|  12.0k|    DXFImporter() = default;

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

_ZNK6Assimp11FBXImporter7GetInfoEv:
   99|  12.0k|const aiImporterDesc *FBXImporter::GetInfo() const {
  100|  12.0k|	return &desc;
  101|  12.0k|}

_ZN6Assimp11FBXImporterC2Ev:
   73|  12.0k|    FBXImporter() = default;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp11NDOImporterC2Ev:
   68|  12.0k|    NDOImporter() = default;

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

_ZN6Assimp11NFFImporterC2Ev:
   65|  12.0k|    NFFImporter() = default;

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

_ZN6Assimp11OFFImporterC2Ev:
   60|  12.0k|    OFFImporter() = default;

_ZN6Assimp7ObjFile6ObjectD2Ev:
  110|   190k|    ~Object() {
  111|   190k|        for (std::vector<Object *>::iterator it = m_SubObjects.begin(); it != m_SubObjects.end(); ++it) {
  ------------------
  |  Branch (111:73): [True: 0, False: 190k]
  ------------------
  112|      0|            delete *it;
  113|      0|        }
  114|   190k|    }
_ZN6Assimp7ObjFile5ModelD2Ev:
  324|  12.0k|    ~Model() {
  325|   190k|        for (auto & it : mObjects) {
  ------------------
  |  Branch (325:24): [True: 190k, False: 12.0k]
  ------------------
  326|   190k|            delete it;
  327|   190k|        }
  328|   224k|        for (auto & Meshe : mMeshes) {
  ------------------
  |  Branch (328:27): [True: 224k, False: 12.0k]
  ------------------
  329|   224k|            delete Meshe;
  330|   224k|        }
  331|  17.6k|        for (auto & Group : mGroups) {
  ------------------
  |  Branch (331:27): [True: 17.6k, False: 12.0k]
  ------------------
  332|  17.6k|            delete Group.second;
  333|  17.6k|        }
  334|  37.0k|        for (auto & it : mMaterialMap) {
  ------------------
  |  Branch (334:24): [True: 37.0k, False: 12.0k]
  ------------------
  335|  37.0k|            delete it.second;
  336|  37.0k|        }
  337|  12.0k|    }
_ZN6Assimp7ObjFile4MeshD2Ev:
  258|   224k|    ~Mesh() {
  259|   224k|        for (std::vector<Face *>::iterator it = m_Faces.begin();
  260|   911k|                it != m_Faces.end(); ++it) {
  ------------------
  |  Branch (260:17): [True: 686k, False: 224k]
  ------------------
  261|   686k|            delete *it;
  262|   686k|        }
  263|   224k|    }
_ZN6Assimp7ObjFile4FaceD2Ev:
   84|   704k|    ~Face() = default;
_ZN6Assimp7ObjFile4FaceC2E15aiPrimitiveType:
   79|   704k|            mPrimitiveType(pt), m_vertices(), m_normals(), m_texturCoords(), m_pMaterial(nullptr) {
   80|       |        // empty
   81|   704k|    }
_ZN6Assimp7ObjFile8MaterialC2Ev:
  218|  37.0k|    Material() {
  219|  37.0k|        std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
  220|  37.0k|    }
_ZN6Assimp7ObjFile4MeshC2ERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE:
  249|   224k|            m_name(name),
  250|   224k|            m_pMaterial(nullptr),
  251|   224k|            m_uiNumIndices(0),
  252|   224k|            m_uiMaterialIndex(NoMaterial),
  253|   224k|            m_hasNormals(false) {
  254|       |        memset(m_uiUVCoordinates, 0, sizeof(unsigned int) * AI_MAX_NUMBER_OF_TEXTURECOORDS);
  255|   224k|    }
_ZN6Assimp7ObjFile5ModelC2Ev:
  312|  12.0k|            mModelName(),
  313|  12.0k|            mCurrentObject(nullptr),
  314|  12.0k|            mCurrentMaterial(nullptr),
  315|  12.0k|            mDefaultMaterial(nullptr),
  316|  12.0k|            mGroupFaceIDs(nullptr),
  317|  12.0k|            mActiveGroup(),
  318|  12.0k|            mTextureCoordDim(0),
  319|  12.0k|            mCurrentMesh(nullptr) {
  320|       |        // empty
  321|  12.0k|    }
_ZN6Assimp7ObjFile6ObjectC2Ev:
  107|   190k|    Object() = default;

_ZN6Assimp15ObjFileImporterC2Ev:
   79|  12.0k|        m_Buffer(),
   80|  12.0k|        m_pRootObject(nullptr),
   81|  12.0k|        m_strAbsPath(std::string(1, DefaultIOSystem().getOsSeparator())) {
   82|       |    // empty
   83|  12.0k|}
_ZN6Assimp15ObjFileImporterD2Ev:
   87|  12.0k|ObjFileImporter::~ObjFileImporter() {
   88|  12.0k|    delete m_pRootObject;
   89|  12.0k|}
_ZNK6Assimp15ObjFileImporter7GetInfoEv:
   99|  36.1k|const aiImporterDesc *ObjFileImporter::GetInfo() const {
  100|  36.1k|    return &desc;
  101|  36.1k|}
_ZN6Assimp15ObjFileImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  105|  12.0k|void ObjFileImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
  106|  12.0k|    if (m_pRootObject != nullptr) {
  ------------------
  |  Branch (106:9): [True: 0, False: 12.0k]
  ------------------
  107|      0|        delete m_pRootObject;
  108|      0|        m_pRootObject = nullptr;
  109|      0|    }
  110|       |
  111|       |    // Read file into memory
  112|  12.0k|    static constexpr char mode[] = "rb";
  113|  12.0k|    auto streamCloser = [&](IOStream *pStream) {
  114|  12.0k|        pIOHandler->Close(pStream);
  115|  12.0k|    };
  116|  12.0k|    std::unique_ptr<IOStream, decltype(streamCloser)> fileStream(pIOHandler->Open(file, mode), streamCloser);
  117|  12.0k|    if (!fileStream) {
  ------------------
  |  Branch (117:9): [True: 0, False: 12.0k]
  ------------------
  118|      0|        throw DeadlyImportError("Failed to open file ", file, ".");
  119|      0|    }
  120|       |
  121|       |    // Get the file-size and validate it, throwing an exception when fails
  122|  12.0k|    size_t fileSize = fileStream->FileSize();
  123|  12.0k|    if (fileSize < ObjMinSize) {
  ------------------
  |  Branch (123:9): [True: 6, False: 12.0k]
  ------------------
  124|      6|        throw DeadlyImportError("OBJ-file is too small.");
  125|      6|    }
  126|       |
  127|  12.0k|    IOStreamBuffer<char> streamedBuffer;
  128|  12.0k|    streamedBuffer.open(fileStream.get());
  129|       |
  130|       |    // Allocate buffer and read file into it
  131|       |    //TextFileToBuffer( fileStream.get(),m_Buffer);
  132|       |
  133|       |    // Get the model name
  134|  12.0k|    std::string modelName, folderName;
  135|  12.0k|    std::string::size_type pos = file.find_last_of("\\/");
  136|  12.0k|    if (pos != std::string::npos) {
  ------------------
  |  Branch (136:9): [True: 0, False: 12.0k]
  ------------------
  137|      0|        modelName = file.substr(pos + 1, file.size() - pos - 1);
  138|      0|        folderName = file.substr(0, pos);
  139|      0|        if (!folderName.empty()) {
  ------------------
  |  Branch (139:13): [True: 0, False: 0]
  ------------------
  140|      0|            pIOHandler->PushDirectory(folderName);
  141|      0|        }
  142|  12.0k|    } else {
  143|  12.0k|        modelName = file;
  144|  12.0k|    }
  145|       |
  146|       |    // parse the file into a temporary representation
  147|  12.0k|    ObjFileParser parser(streamedBuffer, modelName, pIOHandler, m_progress, file);
  148|       |
  149|       |    // And create the proper return structures out of it
  150|  12.0k|    CreateDataFromImport(parser.GetModel(), pScene);
  151|       |
  152|  12.0k|    streamedBuffer.close();
  153|       |
  154|       |    // Clean up allocated storage for the next import
  155|  12.0k|    m_Buffer.clear();
  156|       |
  157|       |    // Pop directory stack
  158|  12.0k|    if (pIOHandler->StackSize() > 0) {
  ------------------
  |  Branch (158:9): [True: 0, False: 12.0k]
  ------------------
  159|      0|        pIOHandler->PopDirectory();
  160|      0|    }
  161|  12.0k|}
_ZN6Assimp15ObjFileImporter20CreateDataFromImportEPKNS_7ObjFile5ModelEP7aiScene:
  165|  11.1k|void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene *pScene) {
  166|  11.1k|    if (pModel == nullptr) {
  ------------------
  |  Branch (166:9): [True: 0, False: 11.1k]
  ------------------
  167|      0|        return;
  168|      0|    }
  169|       |
  170|       |    // Create the root node of the scene
  171|  11.1k|    pScene->mRootNode = new aiNode;
  172|  11.1k|    if (!pModel->mModelName.empty()) {
  ------------------
  |  Branch (172:9): [True: 11.1k, False: 0]
  ------------------
  173|       |        // Set the name of the scene
  174|  11.1k|        pScene->mRootNode->mName.Set(pModel->mModelName);
  175|  11.1k|    } else {
  176|       |        // This is a fatal error, so break down the application
  177|      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]
  |  |  ------------------
  ------------------
  178|      0|    }
  179|       |
  180|  11.1k|    if (!pModel->mObjects.empty()) {
  ------------------
  |  Branch (180:9): [True: 5.47k, False: 5.63k]
  ------------------
  181|  5.47k|        unsigned int meshCount = 0;
  182|  5.47k|        unsigned int childCount = 0;
  183|       |
  184|   182k|        for (auto object : pModel->mObjects) {
  ------------------
  |  Branch (184:26): [True: 182k, False: 5.47k]
  ------------------
  185|   182k|            if (object) {
  ------------------
  |  Branch (185:17): [True: 182k, False: 0]
  ------------------
  186|   182k|                ++childCount;
  187|   182k|                meshCount += (unsigned int)object->m_Meshes.size();
  188|   182k|            }
  189|   182k|        }
  190|       |
  191|       |        // Allocate space for the child nodes on the root node
  192|  5.47k|        pScene->mRootNode->mChildren = new aiNode *[childCount];
  193|       |
  194|       |        // Create nodes for the whole scene
  195|  5.47k|        std::vector<std::unique_ptr<aiMesh>> MeshArray;
  196|  5.47k|        MeshArray.reserve(meshCount);
  197|   181k|        for (size_t index = 0; index < pModel->mObjects.size(); ++index) {
  ------------------
  |  Branch (197:32): [True: 175k, False: 5.47k]
  ------------------
  198|   175k|            createNodes(pModel, pModel->mObjects[index], pScene->mRootNode, pScene, MeshArray);
  199|   175k|        }
  200|       |
  201|  5.47k|        ai_assert(pScene->mRootNode->mNumChildren == childCount);
  ------------------
  |  |   67|  5.47k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 5.47k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  202|       |
  203|       |        // Create mesh pointer buffer for this scene
  204|  5.47k|        if (pScene->mNumMeshes > 0) {
  ------------------
  |  Branch (204:13): [True: 3.43k, False: 2.04k]
  ------------------
  205|  3.43k|            pScene->mMeshes = new aiMesh *[MeshArray.size()];
  206|  86.1k|            for (size_t index = 0; index < MeshArray.size(); ++index) {
  ------------------
  |  Branch (206:36): [True: 82.6k, False: 3.43k]
  ------------------
  207|  82.6k|                pScene->mMeshes[index] = MeshArray[index].release();
  208|  82.6k|            }
  209|  3.43k|        }
  210|       |
  211|       |        // Create all materials
  212|  5.47k|        createMaterials(pModel, pScene);
  213|  5.63k|    } else {
  214|  5.63k|        if (pModel->mVertices.empty()) {
  ------------------
  |  Branch (214:13): [True: 5.24k, False: 390]
  ------------------
  215|  5.24k|            return;
  216|  5.24k|        }
  217|       |
  218|    390|        std::unique_ptr<aiMesh> mesh(new aiMesh);
  219|    390|        mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
  220|    390|        unsigned int n = (unsigned int)pModel->mVertices.size();
  221|    390|        mesh->mNumVertices = n;
  222|       |
  223|    390|        mesh->mVertices = new aiVector3D[n];
  224|    390|        memcpy(mesh->mVertices, pModel->mVertices.data(), n * sizeof(aiVector3D));
  225|       |
  226|    390|        if (!pModel->mNormals.empty()) {
  ------------------
  |  Branch (226:13): [True: 11, False: 379]
  ------------------
  227|     11|            mesh->mNormals = new aiVector3D[n];
  228|     11|            if (pModel->mNormals.size() < n) {
  ------------------
  |  Branch (228:17): [True: 2, False: 9]
  ------------------
  229|      2|                throw DeadlyImportError("OBJ: vertex normal index out of range");
  230|      2|            }
  231|      9|            memcpy(mesh->mNormals, pModel->mNormals.data(), n * sizeof(aiVector3D));
  232|      9|        }
  233|       |
  234|    388|        if (!pModel->mVertexColors.empty()) {
  ------------------
  |  Branch (234:13): [True: 132, False: 256]
  ------------------
  235|    132|            mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
  236|  76.3k|            for (unsigned int i = 0; i < n; ++i) {
  ------------------
  |  Branch (236:38): [True: 76.2k, False: 132]
  ------------------
  237|  76.2k|                if (i < pModel->mVertexColors.size()) {
  ------------------
  |  Branch (237:21): [True: 76.2k, False: 0]
  ------------------
  238|  76.2k|                    const aiVector3D &color = pModel->mVertexColors[i];
  239|  76.2k|                    mesh->mColors[0][i] = aiColor4D(color.x, color.y, color.z, 1.0);
  240|  76.2k|                } else {
  241|      0|                    throw DeadlyImportError("OBJ: vertex color index out of range");
  242|      0|                }
  243|  76.2k|            }
  244|    132|        }
  245|       |
  246|    388|        pScene->mRootNode->mNumMeshes = 1;
  247|    388|        pScene->mRootNode->mMeshes = new unsigned int[1];
  248|    388|        pScene->mRootNode->mMeshes[0] = 0;
  249|    388|        pScene->mMeshes = new aiMesh *[1];
  250|    388|        pScene->mNumMeshes = 1;
  251|    388|        pScene->mMeshes[0] = mesh.release();
  252|    388|    }
  253|  11.1k|}
_ZN6Assimp15ObjFileImporter11createNodesEPKNS_7ObjFile5ModelEPKNS1_6ObjectEP6aiNodeP7aiSceneRNSt3__16vectorINSC_10unique_ptrI6aiMeshNSC_14default_deleteISF_EEEENSC_9allocatorISI_EEEE:
  259|   175k|        std::vector<std::unique_ptr<aiMesh>> &MeshArray) {
  260|   175k|    if (nullptr == pObject || pModel == nullptr) {
  ------------------
  |  Branch (260:9): [True: 0, False: 175k]
  |  Branch (260:31): [True: 0, False: 175k]
  ------------------
  261|      0|        return nullptr;
  262|      0|    }
  263|       |
  264|       |    // Store older mesh size to be able to computes mesh offsets for new mesh instances
  265|   175k|    const size_t oldMeshSize = MeshArray.size();
  266|   175k|    aiNode *pNode = new aiNode;
  267|       |
  268|   175k|    pNode->mName = pObject->m_strObjName;
  269|       |
  270|       |    // If we have a parent node, store it
  271|   175k|    ai_assert(nullptr != pParent);
  ------------------
  |  |   67|   175k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 175k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  272|   175k|    appendChildToParentNode(pParent, pNode);
  273|       |
  274|   383k|    for (size_t i = 0; i < pObject->m_Meshes.size(); ++i) {
  ------------------
  |  Branch (274:24): [True: 207k, False: 175k]
  ------------------
  275|   207k|        unsigned int meshId = pObject->m_Meshes[i];
  276|   207k|        std::unique_ptr<aiMesh> pMesh = createTopology(pModel, pObject, meshId);
  277|   207k|        if (pMesh != nullptr) {
  ------------------
  |  Branch (277:13): [True: 83.3k, False: 124k]
  ------------------
  278|  83.3k|            if (pMesh->mNumFaces > 0) {
  ------------------
  |  Branch (278:17): [True: 83.3k, False: 0]
  ------------------
  279|  83.3k|                MeshArray.push_back(std::move(pMesh));
  280|  83.3k|            }
  281|  83.3k|        }
  282|   207k|    }
  283|       |
  284|       |    // Create all nodes from the sub-objects stored in the current object
  285|   175k|    if (!pObject->m_SubObjects.empty()) {
  ------------------
  |  Branch (285:9): [True: 0, False: 175k]
  ------------------
  286|      0|        size_t numChilds = pObject->m_SubObjects.size();
  287|      0|        pNode->mNumChildren = static_cast<unsigned int>(numChilds);
  288|      0|        pNode->mChildren = new aiNode *[numChilds];
  289|      0|        pNode->mNumMeshes = 1;
  290|      0|        pNode->mMeshes = new unsigned int[1];
  291|      0|    }
  292|       |
  293|       |    // Set mesh instances into scene- and node-instances
  294|   175k|    const size_t meshSizeDiff = MeshArray.size() - oldMeshSize;
  295|   175k|    if (meshSizeDiff > 0) {
  ------------------
  |  Branch (295:9): [True: 55.0k, False: 120k]
  ------------------
  296|  55.0k|        pNode->mMeshes = new unsigned int[meshSizeDiff];
  297|  55.0k|        pNode->mNumMeshes = static_cast<unsigned int>(meshSizeDiff);
  298|  55.0k|        size_t index = 0;
  299|   138k|        for (size_t i = oldMeshSize; i < MeshArray.size(); ++i) {
  ------------------
  |  Branch (299:38): [True: 83.2k, False: 55.0k]
  ------------------
  300|  83.2k|            pNode->mMeshes[index] = pScene->mNumMeshes;
  301|  83.2k|            pScene->mNumMeshes++;
  302|  83.2k|            ++index;
  303|  83.2k|        }
  304|  55.0k|    }
  305|       |
  306|   175k|    return pNode;
  307|   175k|}
_ZN6Assimp15ObjFileImporter14createTopologyEPKNS_7ObjFile5ModelEPKNS1_6ObjectEj:
  311|   207k|std::unique_ptr<aiMesh> ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjFile::Object *pData, unsigned int meshIndex) {
  312|   207k|    if (nullptr == pData || pModel == nullptr) {
  ------------------
  |  Branch (312:9): [True: 0, False: 207k]
  |  Branch (312:29): [True: 0, False: 207k]
  ------------------
  313|      0|        return nullptr;
  314|      0|    }
  315|       |
  316|       |    // Create faces
  317|   207k|    ObjFile::Mesh *pObjMesh = pModel->mMeshes[meshIndex];
  318|   207k|    if (pObjMesh == nullptr) {
  ------------------
  |  Branch (318:9): [True: 0, False: 207k]
  ------------------
  319|      0|        return nullptr;
  320|      0|    }
  321|       |
  322|   207k|    if (pObjMesh->m_Faces.empty()) {
  ------------------
  |  Branch (322:9): [True: 123k, False: 83.9k]
  ------------------
  323|   123k|        return nullptr;
  324|   123k|    }
  325|       |
  326|  83.9k|    std::unique_ptr<aiMesh> pMesh(new aiMesh);
  327|  83.9k|    if (!pObjMesh->m_name.empty()) {
  ------------------
  |  Branch (327:9): [True: 82.2k, False: 1.66k]
  ------------------
  328|  82.2k|        pMesh->mName.Set(pObjMesh->m_name);
  329|  82.2k|    }
  330|       |
  331|   755k|    for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
  ------------------
  |  Branch (331:28): [True: 671k, False: 83.9k]
  ------------------
  332|   671k|        const ObjFile::Face *inp = pObjMesh->m_Faces[index];
  333|   671k|        if (inp == nullptr) {
  ------------------
  |  Branch (333:13): [True: 0, False: 671k]
  ------------------
  334|      0|            continue;
  335|      0|        }
  336|       |
  337|   671k|        if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
  ------------------
  |  Branch (337:13): [True: 20.5k, False: 650k]
  ------------------
  338|  20.5k|            pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
  339|  20.5k|            pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  340|   650k|        } else if (inp->mPrimitiveType == aiPrimitiveType_POINT) {
  ------------------
  |  Branch (340:20): [True: 3.99k, False: 646k]
  ------------------
  341|  3.99k|            pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size());
  342|  3.99k|            pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  343|   646k|        } else {
  344|   646k|            ++pMesh->mNumFaces;
  345|   646k|            if (inp->m_vertices.size() > 3) {
  ------------------
  |  Branch (345:17): [True: 97.5k, False: 549k]
  ------------------
  346|  97.5k|                pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  347|   549k|            } else {
  348|   549k|                pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  349|   549k|            }
  350|   646k|        }
  351|   671k|    }
  352|       |
  353|  83.9k|    unsigned int uiIdxCount = 0u;
  354|  83.9k|    if (pMesh->mNumFaces > 0) {
  ------------------
  |  Branch (354:9): [True: 83.8k, False: 25]
  ------------------
  355|  83.8k|        pMesh->mFaces = new aiFace[pMesh->mNumFaces];
  356|  83.8k|        if (pObjMesh->m_uiMaterialIndex != ObjFile::Mesh::NoMaterial) {
  ------------------
  |  Branch (356:13): [True: 76.4k, False: 7.41k]
  ------------------
  357|  76.4k|            pMesh->mMaterialIndex = pObjMesh->m_uiMaterialIndex;
  358|  76.4k|        }
  359|       |
  360|  83.8k|        unsigned int outIndex = 0u;
  361|       |
  362|       |        // Copy all data from all stored meshes
  363|   671k|        for (auto &face : pObjMesh->m_Faces) {
  ------------------
  |  Branch (363:25): [True: 671k, False: 83.8k]
  ------------------
  364|   671k|            const ObjFile::Face *inp = face;
  365|   671k|            if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
  ------------------
  |  Branch (365:17): [True: 20.5k, False: 650k]
  ------------------
  366|   388k|                for (size_t i = 0; i < inp->m_vertices.size() - 1; ++i) {
  ------------------
  |  Branch (366:36): [True: 368k, False: 20.5k]
  ------------------
  367|   368k|                    aiFace &f = pMesh->mFaces[outIndex++];
  368|   368k|                    uiIdxCount += f.mNumIndices = 2;
  369|   368k|                    f.mIndices = new unsigned int[2];
  370|   368k|                }
  371|  20.5k|                continue;
  372|   650k|            } else if (inp->mPrimitiveType == aiPrimitiveType_POINT) {
  ------------------
  |  Branch (372:24): [True: 3.99k, False: 646k]
  ------------------
  373|  36.8k|                for (size_t i = 0; i < inp->m_vertices.size(); ++i) {
  ------------------
  |  Branch (373:36): [True: 32.8k, False: 3.99k]
  ------------------
  374|  32.8k|                    aiFace &f = pMesh->mFaces[outIndex++];
  375|  32.8k|                    uiIdxCount += f.mNumIndices = 1;
  376|  32.8k|                    f.mIndices = new unsigned int[1];
  377|  32.8k|                }
  378|  3.99k|                continue;
  379|  3.99k|            }
  380|       |
  381|   646k|            aiFace *pFace = &pMesh->mFaces[outIndex++];
  382|   646k|            const unsigned int uiNumIndices = (unsigned int)face->m_vertices.size();
  383|   646k|            uiIdxCount += pFace->mNumIndices = (unsigned int)uiNumIndices;
  384|   646k|            if (pFace->mNumIndices > 0) {
  ------------------
  |  Branch (384:17): [True: 646k, False: 0]
  ------------------
  385|   646k|                pFace->mIndices = new unsigned int[uiNumIndices];
  386|   646k|            }
  387|   646k|        }
  388|  83.8k|    }
  389|       |
  390|       |    // Create mesh vertices
  391|  83.9k|    createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount);
  392|       |
  393|  83.9k|    return pMesh;
  394|   207k|}
_ZN6Assimp15ObjFileImporter17createVertexArrayEPKNS_7ObjFile5ModelEPKNS1_6ObjectEjP6aiMeshj:
  402|  83.9k|        unsigned int numIndices) {
  403|       |    // Checking preconditions
  404|  83.9k|    if (pCurrentObject == nullptr || pModel == nullptr || pMesh == nullptr) {
  ------------------
  |  Branch (404:9): [True: 0, False: 83.9k]
  |  Branch (404:38): [True: 0, False: 83.9k]
  |  Branch (404:59): [True: 0, False: 83.9k]
  ------------------
  405|      0|        return;
  406|      0|    }
  407|       |
  408|       |    // Break, if no faces are stored in object
  409|  83.9k|    if (pCurrentObject->m_Meshes.empty()) {
  ------------------
  |  Branch (409:9): [True: 0, False: 83.9k]
  ------------------
  410|      0|        return;
  411|      0|    }
  412|       |
  413|       |    // Get current mesh
  414|  83.9k|    ObjFile::Mesh *pObjMesh = pModel->mMeshes[uiMeshIndex];
  415|  83.9k|    if (nullptr == pObjMesh || pObjMesh->m_uiNumIndices < 1) {
  ------------------
  |  Branch (415:9): [True: 0, False: 83.9k]
  |  Branch (415:32): [True: 0, False: 83.9k]
  ------------------
  416|      0|        return;
  417|      0|    }
  418|       |
  419|       |    // Copy vertices of this mesh instance
  420|  83.9k|    pMesh->mNumVertices = numIndices;
  421|  83.9k|    if (pMesh->mNumVertices == 0) {
  ------------------
  |  Branch (421:9): [True: 25, False: 83.8k]
  ------------------
  422|     25|        throw DeadlyImportError("OBJ: no vertices");
  423|  83.8k|    } else if (pMesh->mNumVertices > AI_MAX_VERTICES) {
  ------------------
  |  Branch (423:16): [True: 0, False: 83.8k]
  ------------------
  424|      0|        throw DeadlyImportError("OBJ: Too many vertices");
  425|      0|    }
  426|  83.8k|    pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  427|       |
  428|       |    // Allocate buffer for normal vectors
  429|  83.8k|    if (!pModel->mNormals.empty() && pObjMesh->m_hasNormals)
  ------------------
  |  Branch (429:9): [True: 31.0k, False: 52.8k]
  |  Branch (429:38): [True: 19.1k, False: 11.8k]
  ------------------
  430|  19.1k|        pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  431|       |
  432|       |    // Allocate buffer for vertex-color vectors
  433|  83.8k|    if (!pModel->mVertexColors.empty())
  ------------------
  |  Branch (433:9): [True: 28.4k, False: 55.4k]
  ------------------
  434|  28.4k|        pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
  435|       |
  436|       |    // Allocate buffer for texture coordinates
  437|  83.8k|    if (!pModel->mTextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0]) {
  ------------------
  |  Branch (437:9): [True: 28.3k, False: 55.5k]
  |  Branch (437:43): [True: 9.29k, False: 19.0k]
  ------------------
  438|  9.29k|        pMesh->mNumUVComponents[0] = pModel->mTextureCoordDim;
  439|  9.29k|        pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices];
  440|  9.29k|    }
  441|       |
  442|       |    // Copy vertices, normals and textures into aiMesh instance
  443|  83.8k|    bool normalsok = true, uvok = true;
  444|  83.8k|    unsigned int newIndex = 0, outIndex = 0;
  445|   658k|    for (auto sourceFace : pObjMesh->m_Faces) {
  ------------------
  |  Branch (445:26): [True: 658k, False: 83.3k]
  ------------------
  446|       |        // Copy all index arrays
  447|  6.37M|        for (size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < sourceFace->m_vertices.size(); vertexIndex++) {
  ------------------
  |  Branch (447:58): [True: 5.71M, False: 657k]
  ------------------
  448|  5.71M|            const unsigned int vertex = sourceFace->m_vertices.at(vertexIndex);
  449|  5.71M|            if (vertex >= pModel->mVertices.size()) {
  ------------------
  |  Branch (449:17): [True: 566, False: 5.71M]
  ------------------
  450|    566|                throw DeadlyImportError("OBJ: vertex index out of range");
  451|    566|            }
  452|       |
  453|  5.71M|            if (pMesh->mNumVertices <= newIndex) {
  ------------------
  |  Branch (453:17): [True: 5, False: 5.71M]
  ------------------
  454|      5|                throw DeadlyImportError("OBJ: bad vertex index");
  455|      5|            }
  456|       |
  457|  5.71M|            pMesh->mVertices[newIndex] = pModel->mVertices[vertex];
  458|       |
  459|       |            // Copy all normals
  460|  5.71M|            if (normalsok && !pModel->mNormals.empty() && vertexIndex < sourceFace->m_normals.size()) {
  ------------------
  |  Branch (460:17): [True: 4.35M, False: 1.35M]
  |  Branch (460:30): [True: 2.42M, False: 1.92M]
  |  Branch (460:59): [True: 1.00M, False: 1.42M]
  ------------------
  461|  1.00M|                const unsigned int normal = sourceFace->m_normals.at(vertexIndex);
  462|  1.00M|                if (normal >= pModel->mNormals.size()) {
  ------------------
  |  Branch (462:21): [True: 2.90k, False: 1.00M]
  ------------------
  463|  2.90k|                    normalsok = false;
  464|  1.00M|                } else {
  465|  1.00M|                    pMesh->mNormals[newIndex] = pModel->mNormals[normal];
  466|  1.00M|                }
  467|  1.00M|            }
  468|       |
  469|       |            // Copy all vertex colors
  470|  5.71M|            if (vertex < pModel->mVertexColors.size()) {
  ------------------
  |  Branch (470:17): [True: 3.13M, False: 2.58M]
  ------------------
  471|  3.13M|                const aiVector3D &color = pModel->mVertexColors[vertex];
  472|  3.13M|                pMesh->mColors[0][newIndex] = aiColor4D(color.x, color.y, color.z, 1.0);
  473|  3.13M|            }
  474|       |
  475|       |            // Copy all texture coordinates
  476|  5.71M|            if (uvok && !pModel->mTextureCoord.empty() && vertexIndex < sourceFace->m_texturCoords.size()) {
  ------------------
  |  Branch (476:17): [True: 5.39M, False: 322k]
  |  Branch (476:25): [True: 2.43M, False: 2.95M]
  |  Branch (476:59): [True: 229k, False: 2.20M]
  ------------------
  477|   229k|                const unsigned int tex = sourceFace->m_texturCoords.at(vertexIndex);
  478|       |
  479|   229k|                if (tex >= pModel->mTextureCoord.size()) {
  ------------------
  |  Branch (479:21): [True: 1.39k, False: 227k]
  ------------------
  480|  1.39k|                    uvok = false;
  481|   227k|                } else {
  482|   227k|                    const aiVector3D &coord3d = pModel->mTextureCoord[tex];
  483|   227k|                    pMesh->mTextureCoords[0][newIndex] = aiVector3D(coord3d.x, coord3d.y, coord3d.z);
  484|   227k|                }
  485|   229k|            }
  486|       |
  487|       |            // Get destination face
  488|  5.71M|            aiFace *pDestFace = &pMesh->mFaces[outIndex];
  489|       |
  490|  5.71M|            const bool last = (vertexIndex == sourceFace->m_vertices.size() - 1);
  491|  5.71M|            if (sourceFace->mPrimitiveType != aiPrimitiveType_LINE || !last) {
  ------------------
  |  Branch (491:17): [True: 5.63M, False: 79.7k]
  |  Branch (491:71): [True: 59.9k, False: 19.7k]
  ------------------
  492|  5.69M|                pDestFace->mIndices[outVertexIndex] = newIndex;
  493|  5.69M|                outVertexIndex++;
  494|  5.69M|            }
  495|       |
  496|  5.71M|            if (sourceFace->mPrimitiveType == aiPrimitiveType_POINT) {
  ------------------
  |  Branch (496:17): [True: 27.4k, False: 5.68M]
  ------------------
  497|  27.4k|                outIndex++;
  498|  27.4k|                outVertexIndex = 0;
  499|  5.68M|            } else if (sourceFace->mPrimitiveType == aiPrimitiveType_LINE) {
  ------------------
  |  Branch (499:24): [True: 79.7k, False: 5.60M]
  ------------------
  500|  79.7k|                outVertexIndex = 0;
  501|       |
  502|  79.7k|                if (!last)
  ------------------
  |  Branch (502:21): [True: 59.9k, False: 19.7k]
  ------------------
  503|  59.9k|                    outIndex++;
  504|       |
  505|  79.7k|                if (vertexIndex) {
  ------------------
  |  Branch (505:21): [True: 59.8k, False: 19.8k]
  ------------------
  506|  59.8k|                    if (!last) {
  ------------------
  |  Branch (506:25): [True: 40.0k, False: 19.7k]
  ------------------
  507|  40.0k|                        if (pMesh->mNumVertices <= newIndex + 1) {
  ------------------
  |  Branch (507:29): [True: 2, False: 40.0k]
  ------------------
  508|      2|                            throw DeadlyImportError("OBJ: bad vertex index");
  509|      2|                        }
  510|       |
  511|  40.0k|                        pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex];
  512|  40.0k|                        if (!sourceFace->m_normals.empty() && !pModel->mNormals.empty()) {
  ------------------
  |  Branch (512:29): [True: 585, False: 39.5k]
  |  Branch (512:63): [True: 298, False: 287]
  ------------------
  513|    298|                            pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex];
  514|    298|                        }
  515|  40.0k|                        if (!pModel->mTextureCoord.empty()) {
  ------------------
  |  Branch (515:29): [True: 26.2k, False: 13.7k]
  ------------------
  516|  46.5k|                            for (size_t i = 0; i < pMesh->GetNumUVChannels(); i++) {
  ------------------
  |  Branch (516:48): [True: 20.2k, False: 26.2k]
  ------------------
  517|  20.2k|                                pMesh->mTextureCoords[i][newIndex + 1] = pMesh->mTextureCoords[i][newIndex];
  518|  20.2k|                            }
  519|  26.2k|                        }
  520|  40.0k|                        ++newIndex;
  521|  40.0k|                    }
  522|       |
  523|  59.8k|                    pDestFace[-1].mIndices[1] = newIndex;
  524|  59.8k|                }
  525|  5.60M|            } else if (last) {
  ------------------
  |  Branch (525:24): [True: 635k, False: 4.97M]
  ------------------
  526|   635k|                outIndex++;
  527|   635k|            }
  528|  5.71M|            ++newIndex;
  529|  5.71M|        }
  530|   658k|    }
  531|       |
  532|  83.3k|    if (!normalsok) {
  ------------------
  |  Branch (532:9): [True: 2.89k, False: 80.4k]
  ------------------
  533|  2.89k|        delete[] pMesh->mNormals;
  534|  2.89k|        pMesh->mNormals = nullptr;
  535|  2.89k|    }
  536|       |
  537|  83.3k|    if (!uvok) {
  ------------------
  |  Branch (537:9): [True: 1.38k, False: 81.9k]
  ------------------
  538|  1.38k|        delete[] pMesh->mTextureCoords[0];
  539|  1.38k|        pMesh->mTextureCoords[0] = nullptr;
  540|  1.38k|    }
  541|  83.3k|}
_ZN6Assimp15ObjFileImporter29addTextureMappingModePropertyEP10aiMaterial13aiTextureTypeii:
  560|    135|void ObjFileImporter::addTextureMappingModeProperty(aiMaterial *mat, aiTextureType type, int clampMode, int index) {
  561|    135|    if (nullptr == mat) {
  ------------------
  |  Branch (561:9): [True: 0, False: 135]
  ------------------
  562|      0|        return;
  563|      0|    }
  564|       |
  565|    135|    mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_U(type, index));
  566|       |    mat->AddProperty<int>(&clampMode, 1, AI_MATKEY_MAPPINGMODE_V(type, index));
  567|    135|}
_ZN6Assimp15ObjFileImporter15createMaterialsEPKNS_7ObjFile5ModelEP7aiScene:
  571|  4.87k|void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pScene) {
  572|  4.87k|    if (nullptr == pScene) {
  ------------------
  |  Branch (572:9): [True: 0, False: 4.87k]
  ------------------
  573|      0|        return;
  574|      0|    }
  575|       |
  576|  4.87k|    const unsigned int numMaterials = (unsigned int)pModel->mMaterialLib.size();
  577|  4.87k|    pScene->mNumMaterials = 0;
  578|  4.87k|    if (pModel->mMaterialLib.empty()) {
  ------------------
  |  Branch (578:9): [True: 0, False: 4.87k]
  ------------------
  579|      0|        ASSIMP_LOG_DEBUG("OBJ: no materials specified");
  580|      0|        return;
  581|      0|    }
  582|       |
  583|  4.87k|    pScene->mMaterials = new aiMaterial *[numMaterials];
  584|  26.5k|    for (unsigned int matIndex = 0; matIndex < numMaterials; matIndex++) {
  ------------------
  |  Branch (584:37): [True: 21.7k, False: 4.87k]
  ------------------
  585|       |        // Store material name
  586|  21.7k|        std::map<std::string, ObjFile::Material *>::const_iterator it;
  587|  21.7k|        it = pModel->mMaterialMap.find(pModel->mMaterialLib[matIndex]);
  588|       |
  589|       |        // No material found, use the default material
  590|  21.7k|        if (pModel->mMaterialMap.end() == it) {
  ------------------
  |  Branch (590:13): [True: 0, False: 21.7k]
  ------------------
  591|      0|            continue;
  592|      0|        }
  593|       |
  594|  21.7k|        aiMaterial *mat = new aiMaterial;
  595|  21.7k|        ObjFile::Material *pCurrentMaterial = it->second;
  596|  21.7k|        mat->AddProperty(&pCurrentMaterial->MaterialName, AI_MATKEY_NAME);
  597|       |
  598|       |        // convert illumination model
  599|  21.7k|        int sm = 0;
  600|  21.7k|        switch (pCurrentMaterial->illumination_model) {
  601|  1.19k|        case 0:
  ------------------
  |  Branch (601:9): [True: 1.19k, False: 20.5k]
  ------------------
  602|  1.19k|            sm = aiShadingMode_NoShading;
  603|  1.19k|            break;
  604|  20.0k|        case 1:
  ------------------
  |  Branch (604:9): [True: 20.0k, False: 1.68k]
  ------------------
  605|  20.0k|            sm = aiShadingMode_Gouraud;
  606|  20.0k|            break;
  607|    148|        case 2:
  ------------------
  |  Branch (607:9): [True: 148, False: 21.5k]
  ------------------
  608|    148|            sm = aiShadingMode_Phong;
  609|    148|            break;
  610|    342|        default:
  ------------------
  |  Branch (610:9): [True: 342, False: 21.3k]
  ------------------
  611|    342|            sm = aiShadingMode_Gouraud;
  612|    342|            ASSIMP_LOG_ERROR("OBJ: unexpected illumination model (0-2 recognized)");
  613|  21.7k|        }
  614|       |
  615|  21.7k|        mat->AddProperty<int>(&sm, 1, AI_MATKEY_SHADING_MODEL);
  616|       |
  617|       |        // Preserve the original illum value
  618|  21.7k|        mat->AddProperty<int>(&pCurrentMaterial->illumination_model, 1, AI_MATKEY_OBJ_ILLUM);
  619|       |
  620|       |        // Adding material colors
  621|  21.7k|        mat->AddProperty(&pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT);
  622|  21.7k|        mat->AddProperty(&pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  623|  21.7k|        mat->AddProperty(&pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR);
  624|  21.7k|        mat->AddProperty(&pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE);
  625|  21.7k|        mat->AddProperty(&pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS);
  626|  21.7k|        mat->AddProperty(&pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY);
  627|  21.7k|        mat->AddProperty(&pCurrentMaterial->transparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
  628|  21.7k|        if (pCurrentMaterial->roughness)
  ------------------
  |  Branch (628:13): [True: 99, False: 21.6k]
  ------------------
  629|     99|            mat->AddProperty(&pCurrentMaterial->roughness.Get(), 1, AI_MATKEY_ROUGHNESS_FACTOR);
  630|  21.7k|        if (pCurrentMaterial->metallic)
  ------------------
  |  Branch (630:13): [True: 111, False: 21.6k]
  ------------------
  631|    111|            mat->AddProperty(&pCurrentMaterial->metallic.Get(), 1, AI_MATKEY_METALLIC_FACTOR);
  632|  21.7k|        if (pCurrentMaterial->sheen)
  ------------------
  |  Branch (632:13): [True: 415, False: 21.3k]
  ------------------
  633|    415|            mat->AddProperty(&pCurrentMaterial->sheen.Get(), 1, AI_MATKEY_SHEEN_COLOR_FACTOR);
  634|  21.7k|        if (pCurrentMaterial->clearcoat_thickness)
  ------------------
  |  Branch (634:13): [True: 145, False: 21.5k]
  ------------------
  635|    145|            mat->AddProperty(&pCurrentMaterial->clearcoat_thickness.Get(), 1, AI_MATKEY_CLEARCOAT_FACTOR);
  636|  21.7k|        if (pCurrentMaterial->clearcoat_roughness)
  ------------------
  |  Branch (636:13): [True: 53, False: 21.6k]
  ------------------
  637|     53|            mat->AddProperty(&pCurrentMaterial->clearcoat_roughness.Get(), 1, AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR);
  638|  21.7k|        mat->AddProperty(&pCurrentMaterial->anisotropy, 1, AI_MATKEY_ANISOTROPY_FACTOR);
  639|       |
  640|       |        // Adding refraction index
  641|  21.7k|        mat->AddProperty(&pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI);
  642|       |
  643|       |        // Adding textures
  644|  21.7k|        const int uvwIndex = 0;
  645|       |
  646|  21.7k|        if (0 != pCurrentMaterial->texture.length) {
  ------------------
  |  Branch (646:13): [True: 549, False: 21.1k]
  ------------------
  647|    549|            mat->AddProperty(&pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0));
  648|    549|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_DIFFUSE(0));
  649|    549|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType]) {
  ------------------
  |  Branch (649:17): [True: 20, False: 529]
  ------------------
  650|     20|                addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE);
  651|     20|            }
  652|    549|        }
  653|       |
  654|  21.7k|        if (0 != pCurrentMaterial->textureAmbient.length) {
  ------------------
  |  Branch (654:13): [True: 156, False: 21.5k]
  ------------------
  655|    156|            mat->AddProperty(&pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0));
  656|    156|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_AMBIENT(0));
  657|    156|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType]) {
  ------------------
  |  Branch (657:17): [True: 38, False: 118]
  ------------------
  658|     38|                addTextureMappingModeProperty(mat, aiTextureType_AMBIENT);
  659|     38|            }
  660|    156|        }
  661|       |
  662|  21.7k|        if (0 != pCurrentMaterial->textureEmissive.length) {
  ------------------
  |  Branch (662:13): [True: 1.11k, False: 20.6k]
  ------------------
  663|  1.11k|            mat->AddProperty(&pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0));
  664|  1.11k|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_EMISSIVE(0));
  665|  1.11k|        }
  666|       |
  667|  21.7k|        if (0 != pCurrentMaterial->textureSpecular.length) {
  ------------------
  |  Branch (667:13): [True: 165, False: 21.5k]
  ------------------
  668|    165|            mat->AddProperty(&pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0));
  669|    165|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_SPECULAR(0));
  670|    165|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType]) {
  ------------------
  |  Branch (670:17): [True: 10, False: 155]
  ------------------
  671|     10|                addTextureMappingModeProperty(mat, aiTextureType_SPECULAR);
  672|     10|            }
  673|    165|        }
  674|       |
  675|  21.7k|        if (0 != pCurrentMaterial->textureBump.length) {
  ------------------
  |  Branch (675:13): [True: 115, False: 21.6k]
  ------------------
  676|    115|            mat->AddProperty(&pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
  677|    115|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_HEIGHT(0));
  678|    115|            if (pCurrentMaterial->bump_multiplier != 1.0) {
  ------------------
  |  Branch (678:17): [True: 47, False: 68]
  ------------------
  679|     47|                mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_HEIGHT(0));
  680|     47|            }
  681|    115|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) {
  ------------------
  |  Branch (681:17): [True: 10, False: 105]
  ------------------
  682|     10|                addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
  683|     10|            }
  684|    115|        }
  685|       |
  686|  21.7k|        if (0 != pCurrentMaterial->textureNormal.length) {
  ------------------
  |  Branch (686:13): [True: 851, False: 20.8k]
  ------------------
  687|    851|            mat->AddProperty(&pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
  688|    851|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_NORMALS(0));
  689|    851|            if (pCurrentMaterial->bump_multiplier != 1.0) {
  ------------------
  |  Branch (689:17): [True: 125, False: 726]
  ------------------
  690|    125|                mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_NORMALS(0));
  691|    125|            }
  692|    851|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) {
  ------------------
  |  Branch (692:17): [True: 38, False: 813]
  ------------------
  693|     38|                addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
  694|     38|            }
  695|    851|        }
  696|       |
  697|  21.7k|        if (0 != pCurrentMaterial->textureReflection[0].length) {
  ------------------
  |  Branch (697:13): [True: 355, False: 21.3k]
  ------------------
  698|    355|            ObjFile::Material::TextureType type = 0 != pCurrentMaterial->textureReflection[1].length ?
  ------------------
  |  Branch (698:51): [True: 240, False: 115]
  ------------------
  699|    240|                                                          ObjFile::Material::TextureReflectionCubeTopType :
  700|    355|                                                          ObjFile::Material::TextureReflectionSphereType;
  701|       |
  702|    355|            unsigned count = type == ObjFile::Material::TextureReflectionSphereType ? 1 : 6;
  ------------------
  |  Branch (702:30): [True: 115, False: 240]
  ------------------
  703|  1.91k|            for (unsigned i = 0; i < count; i++) {
  ------------------
  |  Branch (703:34): [True: 1.55k, False: 355]
  ------------------
  704|  1.55k|                mat->AddProperty(&pCurrentMaterial->textureReflection[i], AI_MATKEY_TEXTURE_REFLECTION(i));
  705|  1.55k|                mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_REFLECTION(i));
  706|       |
  707|  1.55k|                if (pCurrentMaterial->clamp[type])
  ------------------
  |  Branch (707:21): [True: 0, False: 1.55k]
  ------------------
  708|      0|                    addTextureMappingModeProperty(mat, aiTextureType_REFLECTION, 1, i);
  709|  1.55k|            }
  710|    355|        }
  711|       |
  712|  21.7k|        if (0 != pCurrentMaterial->textureDisp.length) {
  ------------------
  |  Branch (712:13): [True: 101, False: 21.6k]
  ------------------
  713|    101|            mat->AddProperty(&pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0));
  714|    101|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_DISPLACEMENT(0));
  715|    101|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType]) {
  ------------------
  |  Branch (715:17): [True: 0, False: 101]
  ------------------
  716|      0|                addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT);
  717|      0|            }
  718|    101|        }
  719|       |
  720|  21.7k|        if (0 != pCurrentMaterial->textureOpacity.length) {
  ------------------
  |  Branch (720:13): [True: 373, False: 21.3k]
  ------------------
  721|    373|            mat->AddProperty(&pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0));
  722|    373|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_OPACITY(0));
  723|    373|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType]) {
  ------------------
  |  Branch (723:17): [True: 19, False: 354]
  ------------------
  724|     19|                addTextureMappingModeProperty(mat, aiTextureType_OPACITY);
  725|     19|            }
  726|    373|        }
  727|       |
  728|  21.7k|        if (0 != pCurrentMaterial->textureSpecularity.length) {
  ------------------
  |  Branch (728:13): [True: 119, False: 21.6k]
  ------------------
  729|    119|            mat->AddProperty(&pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0));
  730|    119|            mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_SHININESS(0));
  731|    119|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType]) {
  ------------------
  |  Branch (731:17): [True: 0, False: 119]
  ------------------
  732|      0|                addTextureMappingModeProperty(mat, aiTextureType_SHININESS);
  733|      0|            }
  734|    119|        }
  735|       |
  736|  21.7k|        if (0 != pCurrentMaterial->textureRoughness.length) {
  ------------------
  |  Branch (736:13): [True: 196, False: 21.5k]
  ------------------
  737|    196|            mat->AddProperty(&pCurrentMaterial->textureRoughness, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE_ROUGHNESS, 0);
  738|    196|            mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_DIFFUSE_ROUGHNESS, 0 );
  739|    196|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureRoughnessType]) {
  ------------------
  |  Branch (739:17): [True: 0, False: 196]
  ------------------
  740|      0|                addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE_ROUGHNESS);
  741|      0|            }
  742|    196|        }
  743|       |
  744|  21.7k|        if (0 != pCurrentMaterial->textureMetallic.length) {
  ------------------
  |  Branch (744:13): [True: 310, False: 21.4k]
  ------------------
  745|    310|            mat->AddProperty(&pCurrentMaterial->textureMetallic, _AI_MATKEY_TEXTURE_BASE, aiTextureType_METALNESS, 0);
  746|    310|            mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_METALNESS, 0 );
  747|    310|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureMetallicType]) {
  ------------------
  |  Branch (747:17): [True: 0, False: 310]
  ------------------
  748|      0|                addTextureMappingModeProperty(mat, aiTextureType_METALNESS);
  749|      0|            }
  750|    310|        }
  751|       |
  752|  21.7k|        if (0 != pCurrentMaterial->textureSheen.length) {
  ------------------
  |  Branch (752:13): [True: 305, False: 21.4k]
  ------------------
  753|    305|            mat->AddProperty(&pCurrentMaterial->textureSheen, _AI_MATKEY_TEXTURE_BASE, aiTextureType_SHEEN, 0);
  754|    305|            mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_SHEEN, 0 );
  755|    305|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureSheenType]) {
  ------------------
  |  Branch (755:17): [True: 0, False: 305]
  ------------------
  756|      0|                addTextureMappingModeProperty(mat, aiTextureType_SHEEN);
  757|      0|            }
  758|    305|        }
  759|       |
  760|  21.7k|        if (0 != pCurrentMaterial->textureRMA.length) {
  ------------------
  |  Branch (760:13): [True: 0, False: 21.7k]
  ------------------
  761|       |            // NOTE: glTF importer places Rough/Metal/AO texture in Unknown so doing the same here for consistency.
  762|      0|            mat->AddProperty(&pCurrentMaterial->textureRMA, _AI_MATKEY_TEXTURE_BASE, aiTextureType_UNKNOWN, 0);
  763|      0|            mat->AddProperty(&uvwIndex, 1, _AI_MATKEY_UVWSRC_BASE, aiTextureType_UNKNOWN, 0 );
  764|      0|            if (pCurrentMaterial->clamp[ObjFile::Material::TextureRMAType]) {
  ------------------
  |  Branch (764:17): [True: 0, False: 0]
  ------------------
  765|      0|                addTextureMappingModeProperty(mat, aiTextureType_UNKNOWN);
  766|      0|            }
  767|      0|        }
  768|       |
  769|       |        // Store material property info in material array in scene
  770|  21.7k|        pScene->mMaterials[pScene->mNumMaterials] = mat;
  771|  21.7k|        pScene->mNumMaterials++;
  772|  21.7k|    }
  773|       |
  774|       |    // Test number of created materials.
  775|  4.87k|    ai_assert(pScene->mNumMaterials == numMaterials);
  ------------------
  |  |   67|  4.87k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 4.87k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  776|  4.87k|}
_ZN6Assimp15ObjFileImporter23appendChildToParentNodeEP6aiNodeS2_:
  780|   175k|void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild) {
  781|       |    // Checking preconditions
  782|   175k|    if (pParent == nullptr || pChild == nullptr) {
  ------------------
  |  Branch (782:9): [True: 0, False: 175k]
  |  Branch (782:31): [True: 0, False: 175k]
  ------------------
  783|      0|        ai_assert(nullptr != pParent);
  ------------------
  |  |   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]
  |  |  ------------------
  ------------------
  784|      0|        ai_assert(nullptr != pChild);
  ------------------
  |  |   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]
  |  |  ------------------
  ------------------
  785|      0|        return;
  786|      0|    }
  787|       |
  788|       |    // Assign parent to child
  789|   175k|    pChild->mParent = pParent;
  790|       |
  791|       |    // Copy node instances into parent node
  792|   175k|    pParent->mNumChildren++;
  793|   175k|    pParent->mChildren[pParent->mNumChildren - 1] = pChild;
  794|   175k|}
ObjFileImporter.cpp:_ZZN6Assimp15ObjFileImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemEENK3$_0clEPNS_8IOStreamE:
  113|  12.0k|    auto streamCloser = [&](IOStream *pStream) {
  114|  12.0k|        pIOHandler->Close(pStream);
  115|  12.0k|    };

_ZN6Assimp18ObjFileMtlImporterC2ERNSt3__16vectorIcNS1_9allocatorIcEEEERKNS1_12basic_stringIcNS1_11char_traitsIcEES4_EEPNS_7ObjFile5ModelE:
   95|  67.6k|        m_strAbsPath(strAbsPath),
   96|  67.6k|        m_DataIt(buffer.begin()),
   97|  67.6k|        m_DataItEnd(buffer.end()),
   98|  67.6k|        m_pModel(pModel),
   99|  67.6k|        m_uiLine(0),
  100|  67.6k|        m_buffer() {
  101|  67.6k|    ai_assert(nullptr != m_pModel);
  ------------------
  |  |   67|  67.6k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 67.6k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  102|  67.6k|    m_buffer.resize(BUFFERSIZE);
  103|  67.6k|    std::fill(m_buffer.begin(), m_buffer.end(), '\0');
  104|  67.6k|    if (nullptr == m_pModel->mDefaultMaterial) {
  ------------------
  |  Branch (104:9): [True: 0, False: 67.6k]
  ------------------
  105|      0|        m_pModel->mDefaultMaterial = new ObjFile::Material;
  106|      0|        m_pModel->mDefaultMaterial->MaterialName.Set("default");
  107|      0|    }
  108|       |
  109|       |    // Try with OS folder separator first
  110|  67.6k|    char folderSeparator = DefaultIOSystem().getOsSeparator();
  111|  67.6k|    std::size_t found = m_strAbsPath.find_last_of(folderSeparator);
  112|  67.6k|    if (found == std::string::npos) {
  ------------------
  |  Branch (112:9): [True: 60.9k, False: 6.66k]
  ------------------
  113|       |        // Not found, try alternative folder separator
  114|  60.9k|        folderSeparator = (folderSeparator == '/' ? '\\' : '/');
  ------------------
  |  Branch (114:28): [True: 60.9k, False: 0]
  ------------------
  115|  60.9k|        found = m_strAbsPath.find_last_of(folderSeparator);
  116|  60.9k|    }
  117|  67.6k|    if (found != std::string::npos) {
  ------------------
  |  Branch (117:9): [True: 8.18k, False: 59.4k]
  ------------------
  118|  8.18k|        m_strAbsPath = m_strAbsPath.substr(0, found + 1);
  119|  59.4k|    } else {
  120|  59.4k|        m_strAbsPath = "";
  121|  59.4k|    }
  122|  67.6k|    load();
  123|  67.6k|}
_ZN6Assimp18ObjFileMtlImporter4loadEv:
  127|  67.6k|void ObjFileMtlImporter::load() {
  128|  67.6k|    if (m_DataIt == m_DataItEnd)
  ------------------
  |  Branch (128:9): [True: 0, False: 67.6k]
  ------------------
  129|      0|        return;
  130|       |
  131|   305M|    while (m_DataIt != m_DataItEnd) {
  ------------------
  |  Branch (131:12): [True: 305M, False: 67.4k]
  ------------------
  132|   305M|        switch (*m_DataIt) {
  133|   154k|            case 'k':
  ------------------
  |  Branch (133:13): [True: 154k, False: 305M]
  ------------------
  134|   365k|            case 'K': {
  ------------------
  |  Branch (134:13): [True: 211k, False: 305M]
  ------------------
  135|   365k|                ++m_DataIt;
  136|   365k|                if (*m_DataIt == 'a') // Ambient color
  ------------------
  |  Branch (136:21): [True: 31.2k, False: 334k]
  ------------------
  137|  31.2k|                {
  138|  31.2k|                    ++m_DataIt;
  139|  31.2k|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (139:25): [True: 30.9k, False: 360]
  ------------------
  140|  30.9k|                        getColorRGBA(&m_pModel->mCurrentMaterial->ambient);
  141|   334k|                } else if (*m_DataIt == 'd') {
  ------------------
  |  Branch (141:28): [True: 76.1k, False: 258k]
  ------------------
  142|       |                    // Diffuse color
  143|  76.1k|                    ++m_DataIt;
  144|  76.1k|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (144:25): [True: 57.1k, False: 19.0k]
  ------------------
  145|  57.1k|                        getColorRGBA(&m_pModel->mCurrentMaterial->diffuse);
  146|   258k|                } else if (*m_DataIt == 's') {
  ------------------
  |  Branch (146:28): [True: 101k, False: 156k]
  ------------------
  147|   101k|                    ++m_DataIt;
  148|   101k|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (148:25): [True: 95.0k, False: 6.00k]
  ------------------
  149|  95.0k|                        getColorRGBA(&m_pModel->mCurrentMaterial->specular);
  150|   156k|                } else if (*m_DataIt == 'e') {
  ------------------
  |  Branch (150:28): [True: 984, False: 155k]
  ------------------
  151|    984|                    ++m_DataIt;
  152|    984|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (152:25): [True: 544, False: 440]
  ------------------
  153|    544|                        getColorRGBA(&m_pModel->mCurrentMaterial->emissive);
  154|    984|                }
  155|   365k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  156|   365k|            } break;
  157|  71.5k|            case 'T': {
  ------------------
  |  Branch (157:13): [True: 71.5k, False: 305M]
  ------------------
  158|  71.5k|                ++m_DataIt;
  159|       |                // Material transmission color
  160|  71.5k|                if (*m_DataIt == 'f')  {
  ------------------
  |  Branch (160:21): [True: 2.76k, False: 68.7k]
  ------------------
  161|  2.76k|                    ++m_DataIt;
  162|  2.76k|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (162:25): [True: 2.41k, False: 354]
  ------------------
  163|  2.41k|                        getColorRGBA(&m_pModel->mCurrentMaterial->transparent);
  164|  68.7k|                } else if (*m_DataIt == 'r')  {
  ------------------
  |  Branch (164:28): [True: 36.6k, False: 32.0k]
  ------------------
  165|       |                    // Material transmission alpha value
  166|  36.6k|                    ++m_DataIt;
  167|  36.6k|                    ai_real d;
  168|  36.6k|                    getFloatValue(d);
  169|  36.6k|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (169:25): [True: 26.7k, False: 9.96k]
  ------------------
  170|  26.7k|                        m_pModel->mCurrentMaterial->alpha = static_cast<ai_real>(1.0) - d;
  171|  36.6k|                }
  172|  71.5k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  173|  71.5k|            } break;
  174|  63.8k|            case 'd': {
  ------------------
  |  Branch (174:13): [True: 63.8k, False: 305M]
  ------------------
  175|  63.8k|                if (*(m_DataIt + 1) == 'i' && *(m_DataIt + 2) == 's' && *(m_DataIt + 3) == 'p') {
  ------------------
  |  Branch (175:21): [True: 3.72k, False: 60.0k]
  |  Branch (175:21): [True: 1.36k, False: 62.4k]
  |  Branch (175:47): [True: 1.57k, False: 2.14k]
  |  Branch (175:73): [True: 1.36k, False: 207]
  ------------------
  176|       |                    // A displacement map
  177|  1.36k|                    getTexture();
  178|  62.4k|                } else {
  179|       |                    // Alpha value
  180|  62.4k|                    ++m_DataIt;
  181|  62.4k|                    if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (181:25): [True: 60.1k, False: 2.28k]
  ------------------
  182|  60.1k|                        getFloatValue(m_pModel->mCurrentMaterial->alpha);
  183|  62.4k|                    m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  184|  62.4k|                }
  185|  63.8k|            } break;
  186|       |
  187|   180k|            case 'N':
  ------------------
  |  Branch (187:13): [True: 180k, False: 305M]
  ------------------
  188|  1.48M|            case 'n': {
  ------------------
  |  Branch (188:13): [True: 1.30M, False: 304M]
  ------------------
  189|  1.48M|                ++m_DataIt;
  190|  1.48M|                switch (*m_DataIt) {
  ------------------
  |  Branch (190:25): [True: 1.26M, False: 221k]
  ------------------
  191|   115k|                    case 's': // Specular exponent
  ------------------
  |  Branch (191:21): [True: 115k, False: 1.36M]
  ------------------
  192|   115k|                        ++m_DataIt;
  193|   115k|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (193:29): [True: 115k, False: 484]
  ------------------
  194|   115k|                            getFloatValue(m_pModel->mCurrentMaterial->shineness);
  195|   115k|                        break;
  196|    924|                    case 'i': // Index Of refraction
  ------------------
  |  Branch (196:21): [True: 924, False: 1.48M]
  ------------------
  197|    924|                        ++m_DataIt;
  198|    924|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (198:29): [True: 582, False: 342]
  ------------------
  199|    582|                            getFloatValue(m_pModel->mCurrentMaterial->ior);
  200|    924|                        break;
  201|  1.06M|                    case 'e': // New material
  ------------------
  |  Branch (201:21): [True: 1.06M, False: 413k]
  ------------------
  202|  1.06M|                        createMaterial();
  203|  1.06M|                        break;
  204|  75.7k|                    case 'o': // Norm texture
  ------------------
  |  Branch (204:21): [True: 75.7k, False: 1.40M]
  ------------------
  205|  75.7k|                        --m_DataIt;
  206|  75.7k|                        getTexture();
  207|  75.7k|                        break;
  208|  1.48M|                }
  209|  1.48M|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  210|  1.48M|            } break;
  211|       |
  212|   243k|            case 'P':
  ------------------
  |  Branch (212:13): [True: 243k, False: 305M]
  ------------------
  213|   243k|                {
  214|   243k|                    ++m_DataIt;
  215|   243k|                    switch(*m_DataIt)
  ------------------
  |  Branch (215:28): [True: 75.7k, False: 167k]
  ------------------
  216|   243k|                    {
  217|  34.8k|                    case 'r':
  ------------------
  |  Branch (217:21): [True: 34.8k, False: 208k]
  ------------------
  218|  34.8k|                        ++m_DataIt;
  219|  34.8k|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (219:29): [True: 34.2k, False: 603]
  ------------------
  220|  34.2k|                            getFloatValue(m_pModel->mCurrentMaterial->roughness);
  221|  34.8k|                        break;
  222|  17.0k|                    case 'm':
  ------------------
  |  Branch (222:21): [True: 17.0k, False: 226k]
  ------------------
  223|  17.0k|                        ++m_DataIt;
  224|  17.0k|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (224:29): [True: 16.7k, False: 285]
  ------------------
  225|  16.7k|                            getFloatValue(m_pModel->mCurrentMaterial->metallic);
  226|  17.0k|                        break;
  227|  10.1k|                    case 's':
  ------------------
  |  Branch (227:21): [True: 10.1k, False: 233k]
  ------------------
  228|  10.1k|                        ++m_DataIt;
  229|  10.1k|                        if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (229:29): [True: 9.71k, False: 410]
  ------------------
  230|  9.71k|                            getColorRGBA(m_pModel->mCurrentMaterial->sheen);
  231|  10.1k|                        break;
  232|  13.8k|                    case 'c':
  ------------------
  |  Branch (232:21): [True: 13.8k, False: 229k]
  ------------------
  233|  13.8k|                        ++m_DataIt;
  234|  13.8k|                        if (*m_DataIt == 'r') {
  ------------------
  |  Branch (234:29): [True: 1.47k, False: 12.3k]
  ------------------
  235|  1.47k|                            ++m_DataIt;
  236|  1.47k|                            if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (236:33): [True: 1.24k, False: 228]
  ------------------
  237|  1.24k|                                getFloatValue(m_pModel->mCurrentMaterial->clearcoat_roughness);
  238|  12.3k|                        } else if (*m_DataIt == 't') {
  ------------------
  |  Branch (238:36): [True: 11.3k, False: 1.03k]
  ------------------
  239|  11.3k|                            ++m_DataIt;
  240|  11.3k|                            if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (240:33): [True: 10.7k, False: 552]
  ------------------
  241|  10.7k|                                getFloatValue(m_pModel->mCurrentMaterial->clearcoat_thickness);
  242|  11.3k|                        } else {
  243|  1.03k|                            if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (243:33): [True: 619, False: 415]
  ------------------
  244|    619|                                getFloatValue(m_pModel->mCurrentMaterial->clearcoat);
  245|  1.03k|                        }
  246|  13.8k|                        break;
  247|   243k|                    }
  248|   243k|                    m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  249|   243k|                }
  250|      0|                break;
  251|       |            
  252|  9.10M|            case 'm': // Texture or metallic
  ------------------
  |  Branch (252:13): [True: 9.10M, False: 296M]
  ------------------
  253|  9.10M|            {
  254|       |                // Save start of token (after 'm')
  255|  9.10M|                auto tokenStart = m_DataIt;  // points to 'm'
  256|  9.10M|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd); // move iterator to end of token
  257|       |
  258|  9.10M|                std::string keyword(tokenStart, tokenEnd);
  259|  9.10M|                m_DataIt = getNextWord(tokenEnd, m_DataItEnd); // advance iterator
  260|       |
  261|  9.10M|                if (keyword.compare(0, 3, "map") == 0) {
  ------------------
  |  Branch (261:21): [True: 770k, False: 8.33M]
  ------------------
  262|       |                    // starts with "map", treat as texture map
  263|   770k|                    m_DataIt = tokenStart;
  264|   770k|                    getTexture();
  265|  8.33M|                } else if (keyword == "metallic" || keyword == "metal" || keyword == "metalness") {
  ------------------
  |  Branch (265:28): [True: 3.41k, False: 8.33M]
  |  Branch (265:53): [True: 7.19k, False: 8.32M]
  |  Branch (265:75): [True: 606, False: 8.32M]
  ------------------
  266|       |                    // parse metallic float value instead of texture
  267|  11.2k|                    getFloatIfMaterialValid(&ObjFile::Material::metallic);
  268|  11.2k|                }
  269|       |
  270|  9.10M|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  271|  9.10M|            } break;
  272|       |
  273|   331k|            case 'b': // quick'n'dirty - for 'bump' sections
  ------------------
  |  Branch (273:13): [True: 331k, False: 305M]
  ------------------
  274|   331k|            {
  275|   331k|                getTexture();
  276|   331k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  277|   331k|            } break;
  278|       |
  279|   255k|            case 'r': // refl (map) or roughness (float)
  ------------------
  |  Branch (279:13): [True: 255k, False: 305M]
  ------------------
  280|   255k|            {
  281|   255k|                auto tokenStart = m_DataIt;  // points to 'r'
  282|   255k|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd);
  283|   255k|                std::string keyword(tokenStart, tokenEnd);
  284|   255k|                m_DataIt = getNextWord(tokenEnd, m_DataItEnd);
  285|       |
  286|   255k|                if (keyword == "roughness" || keyword == "rough") {
  ------------------
  |  Branch (286:21): [True: 569, False: 254k]
  |  Branch (286:47): [True: 1.33k, False: 253k]
  ------------------
  287|  1.90k|                    getFloatIfMaterialValid(&ObjFile::Material::roughness);
  288|   253k|                } else if (keyword == "refl" || keyword == "reflection") {
  ------------------
  |  Branch (288:28): [True: 279, False: 253k]
  |  Branch (288:49): [True: 746, False: 252k]
  ------------------
  289|  1.02k|                    m_DataIt = tokenStart;
  290|  1.02k|                    getTexture();
  291|  1.02k|                }
  292|       |
  293|   255k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  294|   255k|            } break;
  295|       |
  296|   446k|            case 'i': // Illumination model
  ------------------
  |  Branch (296:13): [True: 446k, False: 305M]
  ------------------
  297|   446k|            {
  298|   446k|                m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  299|   446k|                if (m_pModel->mCurrentMaterial != nullptr)
  ------------------
  |  Branch (299:21): [True: 345k, False: 100k]
  ------------------
  300|   345k|                    getIlluminationModel(m_pModel->mCurrentMaterial->illumination_model);
  301|   446k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  302|   446k|            } break;
  303|       |
  304|  1.11M|            case 'a': {
  ------------------
  |  Branch (304:13): [True: 1.11M, False: 304M]
  ------------------
  305|  1.11M|                auto tokenStart = m_DataIt;
  306|  1.11M|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd);
  307|  1.11M|                std::string keyword(tokenStart, tokenEnd);
  308|  1.11M|                m_DataIt = getNextWord(tokenEnd, m_DataItEnd);
  309|       |
  310|  1.11M|                if (keyword == "aniso" || keyword == "anisotropy") {
  ------------------
  |  Branch (310:21): [True: 4.54k, False: 1.10M]
  |  Branch (310:43): [True: 1.78k, False: 1.10M]
  ------------------
  311|  6.33k|                    getFloatIfMaterialValid(&ObjFile::Material::anisotropy);
  312|  1.10M|                } else if (keyword == "ao") {
  ------------------
  |  Branch (312:28): [True: 1.25k, False: 1.10M]
  ------------------
  313|  1.25k|                    getFloatIfMaterialValid(&ObjFile::Material::ambient_occlusion);
  314|  1.10M|                } else if (keyword == "anisor" || ai_stdStrToLower(keyword) == "anisotropicrotation") {
  ------------------
  |  Branch (314:28): [True: 1.88k, False: 1.10M]
  |  Branch (314:28): [True: 4.64k, False: 1.10M]
  |  Branch (314:51): [True: 2.75k, False: 1.10M]
  ------------------
  315|  4.64k|                    getFloatIfMaterialValid(&ObjFile::Material::anisotropy_rotation);
  316|  1.10M|                } else {
  317|  1.10M|                    ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
  318|  1.10M|                }
  319|       |
  320|  1.11M|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  321|  1.11M|            } break;
  322|       |
  323|  1.44M|            case 's': {
  ------------------
  |  Branch (323:13): [True: 1.44M, False: 304M]
  ------------------
  324|  1.44M|                auto tokenStart = m_DataIt;
  325|  1.44M|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd);
  326|  1.44M|                std::string keyword(tokenStart, tokenEnd);
  327|  1.44M|                m_DataIt = getNextWord(tokenEnd,m_DataItEnd);
  328|       |
  329|  1.44M|                if (keyword == "subsurface" || keyword == "scattering") {
  ------------------
  |  Branch (329:21): [True: 5.57k, False: 1.43M]
  |  Branch (329:48): [True: 254, False: 1.43M]
  ------------------
  330|  5.82k|                    getFloatIfMaterialValid(&ObjFile::Material::subsurface_scattering);
  331|  1.43M|                } else if (ai_stdStrToLower(keyword) == "speculartint") {
  ------------------
  |  Branch (331:28): [True: 4.53k, False: 1.43M]
  ------------------
  332|  4.53k|                    getFloatIfMaterialValid(&ObjFile::Material::specular_tint);
  333|  1.43M|                } else if (keyword == "sheen") {
  ------------------
  |  Branch (333:28): [True: 8.68k, False: 1.42M]
  ------------------
  334|  8.68k|                    getFloatIfMaterialValid(&ObjFile::Material::sheen_grazing);
  335|  1.42M|                } else if (ai_stdStrToLower(keyword) == "sheentint") {
  ------------------
  |  Branch (335:28): [True: 1.26k, False: 1.42M]
  ------------------
  336|  1.26k|                    getFloatIfMaterialValid(&ObjFile::Material::sheen_tint);
  337|  1.42M|                } else {
  338|  1.42M|                    ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
  339|  1.42M|                }
  340|       |
  341|  1.44M|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  342|  1.44M|            } break;
  343|       |
  344|   587k|            case 'c': {
  ------------------
  |  Branch (344:13): [True: 587k, False: 305M]
  ------------------
  345|   587k|                auto tokenStart = m_DataIt;
  346|   587k|                auto tokenEnd = getNextDelimiter(m_DataIt, m_DataItEnd);
  347|   587k|                std::string keyword(tokenStart, tokenEnd);
  348|   587k|                m_DataIt = getNextWord(tokenEnd, m_DataItEnd);
  349|       |
  350|   587k|                if (ai_stdStrToLower(keyword) == "clearcoat") {
  ------------------
  |  Branch (350:21): [True: 1.16k, False: 586k]
  ------------------
  351|  1.16k|                    getFloatIfMaterialValid(&ObjFile::Material::clearcoat);
  352|   586k|                } else if (ai_stdStrToLower(keyword) == "clearcoatgloss") {
  ------------------
  |  Branch (352:28): [True: 506, False: 585k]
  ------------------
  353|    506|                    getFloatIfMaterialValid(&ObjFile::Material::clearcoat_gloss);
  354|   585k|                } else {
  355|   585k|                    ASSIMP_LOG_WARN("Unhandled keyword: ", keyword );
  356|   585k|                }
  357|       |
  358|   587k|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  359|   587k|            } break;
  360|       |
  361|   290M|            default: {
  ------------------
  |  Branch (361:13): [True: 290M, False: 15.5M]
  ------------------
  362|   290M|                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
  363|   290M|            } break;
  364|   305M|        }
  365|   305M|    }
  366|  67.6k|}
_ZN6Assimp18ObjFileMtlImporter12getColorRGBAEP9aiColor3D:
  370|   195k|void ObjFileMtlImporter::getColorRGBA(aiColor3D *pColor) {
  371|   195k|    ai_assert(nullptr != pColor);
  ------------------
  |  |   67|   195k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 195k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  372|       |
  373|   195k|    ai_real r(0.0), g(0.0), b(0.0);
  374|   195k|    m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, r);
  375|   195k|    pColor->r = r;
  376|       |
  377|       |    // we have to check if color is default 0 with only one token
  378|   195k|    if (!IsLineEnd(*m_DataIt)) {
  ------------------
  |  Branch (378:9): [True: 164k, False: 31.0k]
  ------------------
  379|   164k|        m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, g);
  380|   164k|        m_DataIt = getFloat<DataArrayIt>(m_DataIt, m_DataItEnd, b);
  381|   164k|    }
  382|   195k|    pColor->g = g;
  383|   195k|    pColor->b = b;
  384|   195k|}
_ZN6Assimp18ObjFileMtlImporter12getColorRGBAERNS_5MaybeI9aiColor3DEE:
  387|  9.71k|void ObjFileMtlImporter::getColorRGBA(Maybe<aiColor3D> &value) {
  388|  9.71k|    aiColor3D v;
  389|  9.71k|    getColorRGBA(&v);
  390|  9.71k|    value = Maybe<aiColor3D>(v);
  391|  9.71k|}
_ZN6Assimp18ObjFileMtlImporter20getIlluminationModelERi:
  395|   345k|void ObjFileMtlImporter::getIlluminationModel(int &illum_model) {
  396|   345k|    m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
  397|   345k|    illum_model = atoi(&m_buffer[0]);
  398|   345k|}
_ZN6Assimp18ObjFileMtlImporter13getFloatValueERf:
  403|   218k|void ObjFileMtlImporter::getFloatValue(ai_real &value) {
  404|   218k|    m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
  405|   218k|    size_t len = std::strlen(&m_buffer[0]);
  406|   218k|    if (0 == len) {
  ------------------
  |  Branch (406:9): [True: 47.6k, False: 171k]
  ------------------
  407|  47.6k|        value = 0.0f;
  408|  47.6k|        return;
  409|  47.6k|    }
  410|       |
  411|   171k|    value = (ai_real)fast_atof(&m_buffer[0]);
  412|   171k|}
_ZN6Assimp18ObjFileMtlImporter13getFloatValueERNS_5MaybeIfEE:
  415|   100k|void ObjFileMtlImporter::getFloatValue(Maybe<ai_real> &value) {
  416|   100k|    m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
  417|   100k|    size_t len = std::strlen(&m_buffer[0]);
  418|   100k|    if (len)
  ------------------
  |  Branch (418:9): [True: 39.6k, False: 61.3k]
  ------------------
  419|  39.6k|        value = Maybe<ai_real>(fast_atof(&m_buffer[0]));
  420|  61.3k|    else
  421|  61.3k|        value = Maybe<ai_real>();
  422|   100k|}
_ZN6Assimp18ObjFileMtlImporter23getFloatIfMaterialValidEMNS_7ObjFile8MaterialEf:
  426|  6.33k|void ObjFileMtlImporter::getFloatIfMaterialValid(ai_real ObjFile::Material::*member) {
  427|  6.33k|    if (m_pModel != nullptr && m_pModel->mCurrentMaterial != nullptr) {
  ------------------
  |  Branch (427:9): [True: 6.33k, False: 0]
  |  Branch (427:32): [True: 6.09k, False: 237]
  ------------------
  428|       |        // This will call getFloatValue(ai_real&)
  429|  6.09k|        getFloatValue(m_pModel->mCurrentMaterial->*member);
  430|  6.09k|    }
  431|  6.33k|}
_ZN6Assimp18ObjFileMtlImporter23getFloatIfMaterialValidEMNS_7ObjFile8MaterialENS_5MaybeIfEE:
  434|  40.9k|void ObjFileMtlImporter::getFloatIfMaterialValid(Maybe<ai_real> ObjFile::Material::*member) {
  435|       |    // It can directly access `m_pModel` because it's part of the class
  436|  40.9k|    if (m_pModel != nullptr && m_pModel->mCurrentMaterial != nullptr) {
  ------------------
  |  Branch (436:9): [True: 40.9k, False: 0]
  |  Branch (436:32): [True: 37.4k, False: 3.57k]
  ------------------
  437|  37.4k|        getFloatValue(m_pModel->mCurrentMaterial->*member);
  438|  37.4k|    }
  439|  40.9k|}
_ZN6Assimp18ObjFileMtlImporter14createMaterialEv:
  443|  1.06M|void ObjFileMtlImporter::createMaterial() {
  444|  1.06M|    std::string line;
  445|  77.8M|    while (!IsLineEnd(*m_DataIt)) {
  ------------------
  |  Branch (445:12): [True: 76.8M, False: 1.06M]
  ------------------
  446|  76.8M|        line += *m_DataIt;
  447|  76.8M|        ++m_DataIt;
  448|  76.8M|    }
  449|       |
  450|  1.06M|    std::vector<std::string> token;
  451|  1.06M|    const unsigned int numToken = tokenize<std::string>(line, token, " \t");
  452|  1.06M|    std::string name;
  453|  1.06M|    if (numToken == 1) {
  ------------------
  |  Branch (453:9): [True: 50.1k, False: 1.01M]
  ------------------
  454|  50.1k|        name = AI_DEFAULT_MATERIAL_NAME;
  455|  1.01M|    } else {
  456|       |        // skip newmtl and all following white spaces
  457|  1.01M|        std::size_t first_ws_pos = line.find_first_of(" \t");
  458|  1.01M|        std::size_t first_non_ws_pos = line.find_first_not_of(" \t", first_ws_pos);
  459|  1.01M|        if (first_non_ws_pos != std::string::npos) {
  ------------------
  |  Branch (459:13): [True: 1.01M, False: 0]
  ------------------
  460|  1.01M|            name = line.substr(first_non_ws_pos);
  461|  1.01M|        }
  462|  1.01M|    }
  463|       |
  464|  1.06M|    name = ai_trim(name);
  465|       |
  466|  1.06M|    std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->mMaterialMap.find(name);
  467|  1.06M|    if (m_pModel->mMaterialMap.end() == it) {
  ------------------
  |  Branch (467:9): [True: 7.48k, False: 1.06M]
  ------------------
  468|       |        // New Material created
  469|  7.48k|        m_pModel->mCurrentMaterial = new ObjFile::Material();
  470|  7.48k|        m_pModel->mCurrentMaterial->MaterialName.Set(name);
  471|  7.48k|        m_pModel->mMaterialLib.push_back(name);
  472|  7.48k|        m_pModel->mMaterialMap[name] = m_pModel->mCurrentMaterial;
  473|       |
  474|  7.48k|        if (m_pModel->mCurrentMesh) {
  ------------------
  |  Branch (474:13): [True: 2.54k, False: 4.94k]
  ------------------
  475|  2.54k|            m_pModel->mCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->mMaterialLib.size() - 1);
  476|  2.54k|        }
  477|  1.06M|    } else {
  478|       |        // Use older material
  479|  1.06M|        m_pModel->mCurrentMaterial = it->second;
  480|  1.06M|    }
  481|  1.06M|}
_ZN6Assimp18ObjFileMtlImporter10getTextureEv:
  485|  1.18M|void ObjFileMtlImporter::getTexture() {
  486|  1.18M|    aiString *out = nullptr;
  487|  1.18M|    int clampIndex = -1;
  488|       |
  489|  1.18M|    if (m_pModel->mCurrentMaterial == nullptr) {
  ------------------
  |  Branch (489:9): [True: 2.85k, False: 1.17M]
  ------------------
  490|  2.85k|        m_pModel->mCurrentMaterial = new ObjFile::Material();
  491|  2.85k|        m_pModel->mCurrentMaterial->MaterialName.Set("Empty_Material");
  492|  2.85k|        m_pModel->mMaterialMap["Empty_Material"] = m_pModel->mCurrentMaterial;
  493|  2.85k|    }
  494|       |
  495|  1.18M|    const char *pPtr(&(*m_DataIt));
  496|  1.18M|    if (!ASSIMP_strincmp(pPtr, DiffuseTexture, static_cast<unsigned int>(strlen(DiffuseTexture)))) {
  ------------------
  |  Branch (496:9): [True: 66.0k, False: 1.11M]
  ------------------
  497|       |        // Diffuse texture
  498|  66.0k|        out = &m_pModel->mCurrentMaterial->texture;
  499|  66.0k|        clampIndex = ObjFile::Material::TextureDiffuseType;
  500|  1.11M|    } else if (!ASSIMP_strincmp(pPtr, AmbientTexture, static_cast<unsigned int>(strlen(AmbientTexture)))) {
  ------------------
  |  Branch (500:16): [True: 2.24k, False: 1.11M]
  ------------------
  501|       |        // Ambient texture
  502|  2.24k|        out = &m_pModel->mCurrentMaterial->textureAmbient;
  503|  2.24k|        clampIndex = ObjFile::Material::TextureAmbientType;
  504|  1.11M|    } else if (!ASSIMP_strincmp(pPtr, SpecularTexture, static_cast<unsigned int>(strlen(SpecularTexture)))) {
  ------------------
  |  Branch (504:16): [True: 21.5k, False: 1.09M]
  ------------------
  505|       |        // Specular texture
  506|  21.5k|        out = &m_pModel->mCurrentMaterial->textureSpecular;
  507|  21.5k|        clampIndex = ObjFile::Material::TextureSpecularType;
  508|  1.09M|    } else if (!ASSIMP_strincmp(pPtr, DisplacementTexture1, static_cast<unsigned int>(strlen(DisplacementTexture1))) ||
  ------------------
  |  Branch (508:16): [True: 7.14k, False: 1.08M]
  ------------------
  509|  1.08M|               !ASSIMP_strincmp(pPtr, DisplacementTexture2, static_cast<unsigned int>(strlen(DisplacementTexture2)))) {
  ------------------
  |  Branch (509:16): [True: 1.36k, False: 1.08M]
  ------------------
  510|       |        // Displacement texture
  511|  8.51k|        out = &m_pModel->mCurrentMaterial->textureDisp;
  512|  8.51k|        clampIndex = ObjFile::Material::TextureDispType;
  513|  1.08M|    } else if (!ASSIMP_strincmp(pPtr, OpacityTexture, static_cast<unsigned int>(strlen(OpacityTexture)))) {
  ------------------
  |  Branch (513:16): [True: 9.24k, False: 1.07M]
  ------------------
  514|       |        // Opacity texture
  515|  9.24k|        out = &m_pModel->mCurrentMaterial->textureOpacity;
  516|  9.24k|        clampIndex = ObjFile::Material::TextureOpacityType;
  517|  1.07M|    } else if (!ASSIMP_strincmp(pPtr, EmissiveTexture1, static_cast<unsigned int>(strlen(EmissiveTexture1))) ||
  ------------------
  |  Branch (517:16): [True: 1.27k, False: 1.07M]
  ------------------
  518|  1.07M|               !ASSIMP_strincmp(pPtr, EmissiveTexture2, static_cast<unsigned int>(strlen(EmissiveTexture2)))) {
  ------------------
  |  Branch (518:16): [True: 368k, False: 702k]
  ------------------
  519|       |        // Emissive texture
  520|   369k|        out = &m_pModel->mCurrentMaterial->textureEmissive;
  521|   369k|        clampIndex = ObjFile::Material::TextureEmissiveType;
  522|   702k|    } else if (!ASSIMP_strincmp(pPtr, BumpTexture1, static_cast<unsigned int>(strlen(BumpTexture1))) ||
  ------------------
  |  Branch (522:16): [True: 891, False: 702k]
  ------------------
  523|   702k|               !ASSIMP_strincmp(pPtr, BumpTexture2, static_cast<unsigned int>(strlen(BumpTexture2)))) {
  ------------------
  |  Branch (523:16): [True: 1.75k, False: 700k]
  ------------------
  524|       |        // Bump texture
  525|  2.65k|        out = &m_pModel->mCurrentMaterial->textureBump;
  526|  2.65k|        clampIndex = ObjFile::Material::TextureBumpType;
  527|   700k|    } else if (!ASSIMP_strincmp(pPtr, NormalTextureV1, static_cast<unsigned int>(strlen(NormalTextureV1))) || !ASSIMP_strincmp(pPtr, NormalTextureV2, static_cast<unsigned int>(strlen(NormalTextureV2)))) {
  ------------------
  |  Branch (527:16): [True: 18.9k, False: 681k]
  |  Branch (527:111): [True: 67.5k, False: 613k]
  ------------------
  528|       |        // Normal map
  529|  86.4k|        out = &m_pModel->mCurrentMaterial->textureNormal;
  530|  86.4k|        clampIndex = ObjFile::Material::TextureNormalType;
  531|   613k|    } else if (!ASSIMP_strincmp(pPtr, ReflectionTexture, static_cast<unsigned int>(strlen(ReflectionTexture)))) {
  ------------------
  |  Branch (531:16): [True: 1.02k, False: 612k]
  ------------------
  532|       |        // Reflection texture(s)
  533|       |        //Do nothing here
  534|  1.02k|        return;
  535|   612k|    } else if (!ASSIMP_strincmp(pPtr, SpecularityTexture, static_cast<unsigned int>(strlen(SpecularityTexture)))) {
  ------------------
  |  Branch (535:16): [True: 7.70k, False: 605k]
  ------------------
  536|       |        // Specularity scaling (glossiness)
  537|  7.70k|        out = &m_pModel->mCurrentMaterial->textureSpecularity;
  538|  7.70k|        clampIndex = ObjFile::Material::TextureSpecularityType;
  539|   605k|    } else if ( !ASSIMP_strincmp( pPtr, RoughnessTexture, static_cast<unsigned int>(strlen(RoughnessTexture)))) {
  ------------------
  |  Branch (539:17): [True: 20.1k, False: 584k]
  ------------------
  540|       |        // PBR Roughness texture
  541|  20.1k|        out = & m_pModel->mCurrentMaterial->textureRoughness;
  542|  20.1k|        clampIndex = ObjFile::Material::TextureRoughnessType;
  543|   584k|    } else if ( !ASSIMP_strincmp( pPtr, MetallicTexture, static_cast<unsigned int>(strlen(MetallicTexture)))) {
  ------------------
  |  Branch (543:17): [True: 31.7k, False: 553k]
  ------------------
  544|       |        // PBR Metallic texture
  545|  31.7k|        out = & m_pModel->mCurrentMaterial->textureMetallic;
  546|  31.7k|        clampIndex = ObjFile::Material::TextureMetallicType;
  547|   553k|    } else if (!ASSIMP_strincmp( pPtr, SheenTexture, static_cast<unsigned int>(strlen(SheenTexture)))) {
  ------------------
  |  Branch (547:16): [True: 57.1k, False: 496k]
  ------------------
  548|       |        // PBR Sheen (reflectance) texture
  549|  57.1k|        out = & m_pModel->mCurrentMaterial->textureSheen;
  550|  57.1k|        clampIndex = ObjFile::Material::TextureSheenType;
  551|   496k|    } else if (!ASSIMP_strincmp( pPtr, RMATexture, static_cast<unsigned int>(strlen(RMATexture)))) {
  ------------------
  |  Branch (551:16): [True: 0, False: 496k]
  ------------------
  552|       |        // PBR Rough/Metal/AO texture
  553|      0|        out = & m_pModel->mCurrentMaterial->textureRMA;
  554|      0|        clampIndex = ObjFile::Material::TextureRMAType;
  555|   496k|    } else {
  556|   496k|        ASSIMP_LOG_ERROR("OBJ/MTL: Encountered unknown texture type");
  557|   496k|        return;
  558|   496k|    }
  559|       |
  560|   683k|    bool clamp = false;
  561|   683k|    getTextureOption(clamp, clampIndex, out);
  562|   683k|    m_pModel->mCurrentMaterial->clamp[clampIndex] = clamp;
  563|       |
  564|   683k|    std::string texture;
  565|   683k|    m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, texture);
  566|   683k|    if (nullptr != out) {
  ------------------
  |  Branch (566:9): [True: 683k, False: 29]
  ------------------
  567|   683k|        out->Set(m_strAbsPath + texture);
  568|   683k|    }
  569|   683k|}
_ZN6Assimp18ObjFileMtlImporter16getTextureOptionERbRiRP8aiString:
  586|   683k|void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out) {
  587|   683k|    m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  588|       |
  589|       |    // If there is any more texture option
  590|   959k|    while (!isEndOfBuffer(m_DataIt, m_DataItEnd) && *m_DataIt == '-') {
  ------------------
  |  Branch (590:12): [True: 956k, False: 2.73k]
  |  Branch (590:53): [True: 276k, False: 680k]
  ------------------
  591|   276k|        const char *pPtr(&(*m_DataIt));
  592|       |        //skip option key and value
  593|   276k|        int skipToken = 1;
  594|       |
  595|   276k|        if (!ASSIMP_strincmp(pPtr, ClampOption, static_cast<unsigned int>(strlen(ClampOption)))) {
  ------------------
  |  Branch (595:13): [True: 38.6k, False: 237k]
  ------------------
  596|  38.6k|            DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  597|  38.6k|            char value[3];
  598|  38.6k|            CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
  599|  38.6k|            if (!ASSIMP_strincmp(value, "on", 2)) {
  ------------------
  |  Branch (599:17): [True: 4.58k, False: 34.0k]
  ------------------
  600|  4.58k|                clamp = true;
  601|  4.58k|            }
  602|       |
  603|  38.6k|            skipToken = 2;
  604|   237k|        } else if (!ASSIMP_strincmp(pPtr, TypeOption, static_cast<unsigned int>(strlen(TypeOption)))) {
  ------------------
  |  Branch (604:20): [True: 79.2k, False: 158k]
  ------------------
  605|  79.2k|            DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  606|  79.2k|            char value[12];
  607|  79.2k|            CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
  608|  79.2k|            if (!ASSIMP_strincmp(value, "cube_top", 8)) {
  ------------------
  |  Branch (608:17): [True: 705, False: 78.5k]
  ------------------
  609|    705|                clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
  610|    705|                out = &m_pModel->mCurrentMaterial->textureReflection[0];
  611|  78.5k|            } else if (!ASSIMP_strincmp(value, "cube_bottom", 11)) {
  ------------------
  |  Branch (611:24): [True: 3.17k, False: 75.3k]
  ------------------
  612|  3.17k|                clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
  613|  3.17k|                out = &m_pModel->mCurrentMaterial->textureReflection[1];
  614|  75.3k|            } else if (!ASSIMP_strincmp(value, "cube_front", 10)) {
  ------------------
  |  Branch (614:24): [True: 208, False: 75.1k]
  ------------------
  615|    208|                clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
  616|    208|                out = &m_pModel->mCurrentMaterial->textureReflection[2];
  617|  75.1k|            } else if (!ASSIMP_strincmp(value, "cube_back", 9)) {
  ------------------
  |  Branch (617:24): [True: 333, False: 74.8k]
  ------------------
  618|    333|                clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
  619|    333|                out = &m_pModel->mCurrentMaterial->textureReflection[3];
  620|  74.8k|            } else if (!ASSIMP_strincmp(value, "cube_left", 9)) {
  ------------------
  |  Branch (620:24): [True: 394, False: 74.4k]
  ------------------
  621|    394|                clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
  622|    394|                out = &m_pModel->mCurrentMaterial->textureReflection[4];
  623|  74.4k|            } else if (!ASSIMP_strincmp(value, "cube_right", 10)) {
  ------------------
  |  Branch (623:24): [True: 255, False: 74.1k]
  ------------------
  624|    255|                clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
  625|    255|                out = &m_pModel->mCurrentMaterial->textureReflection[5];
  626|  74.1k|            } else if (!ASSIMP_strincmp(value, "sphere", 6)) {
  ------------------
  |  Branch (626:24): [True: 5.80k, False: 68.3k]
  ------------------
  627|  5.80k|                clampIndex = ObjFile::Material::TextureReflectionSphereType;
  628|  5.80k|                out = &m_pModel->mCurrentMaterial->textureReflection[0];
  629|  5.80k|            }
  630|       |
  631|  79.2k|            skipToken = 2;
  632|   158k|        } else if (!ASSIMP_strincmp(pPtr, BumpOption, static_cast<unsigned int>(strlen(BumpOption)))) {
  ------------------
  |  Branch (632:20): [True: 11.9k, False: 146k]
  ------------------
  633|  11.9k|            DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  634|  11.9k|            getFloat(it, m_DataItEnd, m_pModel->mCurrentMaterial->bump_multiplier);
  635|  11.9k|            skipToken = 2;
  636|   146k|        } else if (!ASSIMP_strincmp(pPtr, BlendUOption, static_cast<unsigned int>(strlen(BlendUOption))) ||
  ------------------
  |  Branch (636:20): [True: 2.95k, False: 143k]
  ------------------
  637|   143k|                !ASSIMP_strincmp(pPtr, BlendVOption, static_cast<unsigned int>(strlen(BlendVOption))) ||
  ------------------
  |  Branch (637:17): [True: 220, False: 143k]
  ------------------
  638|   143k|                !ASSIMP_strincmp(pPtr, BoostOption, static_cast<unsigned int>(strlen(BoostOption))) ||
  ------------------
  |  Branch (638:17): [True: 517, False: 142k]
  ------------------
  639|   142k|                !ASSIMP_strincmp(pPtr, ResolutionOption, static_cast<unsigned int>(strlen(ResolutionOption))) ||
  ------------------
  |  Branch (639:17): [True: 381, False: 142k]
  ------------------
  640|   142k|                !ASSIMP_strincmp(pPtr, ChannelOption, static_cast<unsigned int>(strlen(ChannelOption)))) {
  ------------------
  |  Branch (640:17): [True: 21.0k, False: 121k]
  ------------------
  641|  25.0k|            skipToken = 2;
  642|   121k|        } else if (!ASSIMP_strincmp(pPtr, ModifyMapOption, static_cast<unsigned int>(strlen(ModifyMapOption)))) {
  ------------------
  |  Branch (642:20): [True: 382, False: 120k]
  ------------------
  643|    382|            skipToken = 3;
  644|   120k|        } else if (!ASSIMP_strincmp(pPtr, OffsetOption, static_cast<unsigned int>(strlen(OffsetOption))) ||
  ------------------
  |  Branch (644:20): [True: 12.3k, False: 108k]
  ------------------
  645|   108k|                !ASSIMP_strincmp(pPtr, ScaleOption, static_cast<unsigned int>(strlen(ScaleOption))) ||
  ------------------
  |  Branch (645:17): [True: 861, False: 107k]
  ------------------
  646|   107k|                !ASSIMP_strincmp(pPtr, TurbulenceOption, static_cast<unsigned int>(strlen(TurbulenceOption)))) {
  ------------------
  |  Branch (646:17): [True: 14.8k, False: 92.7k]
  ------------------
  647|  28.0k|            skipToken = 4;
  648|  28.0k|        }
  649|       |
  650|   791k|        for (int i = 0; i < skipToken; ++i) {
  ------------------
  |  Branch (650:25): [True: 515k, False: 276k]
  ------------------
  651|   515k|            m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
  652|   515k|        }
  653|   276k|    }
  654|   683k|}

_ZN6Assimp18ObjFileMtlImporterD2Ev:
   74|  67.4k|    ~ObjFileMtlImporter() = default;

_ZN6Assimp13ObjFileParserC2ERNS_14IOStreamBufferIcEERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPNS_8IOSystemEPNS_15ProgressHandlerESC_:
   90|  12.0k|            mIO(io),
   91|  12.0k|            mProgress(progress),
   92|  12.0k|            mOriginalObjFileName(originalObjFileName) { 
   93|  12.0k|    std::fill_n(mBuffer, Buffersize, '\0');
   94|       |
   95|       |    // Create the model instance to store all the data
   96|  12.0k|    mModel.reset(new ObjFile::Model());
   97|  12.0k|    mModel->mModelName = modelName;
   98|       |
   99|       |    // create default material and store it
  100|  12.0k|    mModel->mDefaultMaterial = new ObjFile::Material;
  101|  12.0k|    mModel->mDefaultMaterial->MaterialName.Set(DEFAULT_MATERIAL);
  102|  12.0k|    mModel->mMaterialLib.emplace_back(DEFAULT_MATERIAL);
  103|  12.0k|    mModel->mMaterialMap[DEFAULT_MATERIAL] = mModel->mDefaultMaterial;
  104|       |
  105|       |    // Start parsing the file
  106|  12.0k|    parseFile(streamBuffer);
  107|  12.0k|}
_ZNK6Assimp13ObjFileParser8GetModelEv:
  119|  11.1k|ObjFile::Model *ObjFileParser::GetModel() const {
  120|  11.1k|    return mModel.get();
  121|  11.1k|}
_ZN6Assimp13ObjFileParser9parseFileERNS_14IOStreamBufferIcEE:
  124|  12.0k|void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
  125|       |    // only update every 100KB or it'll be too slow
  126|       |    // const unsigned int updateProgressEveryBytes = 100 * 1024;
  127|  12.0k|    const unsigned int bytesToProcess = static_cast<unsigned int>(streamBuffer.size());
  128|  12.0k|    const unsigned int progressTotal = bytesToProcess;
  129|  12.0k|    unsigned int processed = 0u;
  130|  12.0k|    size_t lastFilePos = 0u;
  131|       |
  132|  12.0k|    bool insideCstype = false;
  133|  12.0k|    std::vector<char> buffer;
  134|  9.78M|    while (streamBuffer.getNextDataLine(buffer, '\\')) {
  ------------------
  |  Branch (134:12): [True: 9.77M, False: 11.1k]
  ------------------
  135|  9.77M|        mDataIt = buffer.begin();
  136|  9.77M|        mDataItEnd = buffer.end();
  137|  9.77M|        mEnd = &buffer[buffer.size() - 1] + 1;
  138|       |
  139|  9.77M|        if (processed == 0 && std::distance(mDataIt, mDataItEnd) >= 3 &&
  ------------------
  |  Branch (139:13): [True: 12.0k, False: 9.76M]
  |  Branch (139:13): [True: 32, False: 9.77M]
  |  Branch (139:31): [True: 12.0k, False: 0]
  ------------------
  140|  12.0k|            	static_cast<unsigned char>(*mDataIt) == 0xEF &&
  ------------------
  |  Branch (140:14): [True: 147, False: 11.8k]
  ------------------
  141|    147|            	static_cast<unsigned char>(*(mDataIt + 1)) == 0xBB &&
  ------------------
  |  Branch (141:14): [True: 74, False: 73]
  ------------------
  142|     74|            	static_cast<unsigned char>(*(mDataIt + 2)) == 0xBF) {
  ------------------
  |  Branch (142:14): [True: 32, False: 42]
  ------------------
  143|     32|            mDataIt += 3; // skip BOM
  144|     32|        }
  145|       |
  146|       |        // Handle progress reporting
  147|  9.77M|        const size_t filePos = streamBuffer.getFilePos();
  148|  9.77M|        if (lastFilePos < filePos) {
  ------------------
  |  Branch (148:13): [True: 12.0k, False: 9.76M]
  ------------------
  149|  12.0k|            processed = static_cast<unsigned int>(filePos);
  150|  12.0k|            lastFilePos = filePos;
  151|  12.0k|			if (mProgress != nullptr) {
  ------------------
  |  Branch (151:8): [True: 12.0k, False: 0]
  ------------------
  152|  12.0k|				mProgress->UpdateFileRead(processed, progressTotal);
  153|  12.0k|			}
  154|  12.0k|        }
  155|       |
  156|       |        // handle c-stype section end (http://paulbourke.net/dataformats/obj/)
  157|  9.77M|        if (insideCstype) {
  ------------------
  |  Branch (157:13): [True: 49.5k, False: 9.72M]
  ------------------
  158|  49.5k|            switch (*mDataIt) {
  159|  1.52k|	            case 'e': {
  ------------------
  |  Branch (159:14): [True: 1.52k, False: 48.0k]
  ------------------
  160|  1.52k|	                std::string name;
  161|  1.52k|	                getNameNoSpace(mDataIt, mDataItEnd, name);
  162|  1.52k|	                insideCstype = name != "end";
  163|  1.52k|	            } break;
  164|  48.0k|				default:
  ------------------
  |  Branch (164:5): [True: 48.0k, False: 1.52k]
  ------------------
  165|  48.0k|					break;
  166|  49.5k|            }
  167|  49.5k|            goto pf_skip_line;
  168|  49.5k|        }
  169|       |
  170|       |        // parse line
  171|  9.72M|        switch (*mDataIt) {
  172|  1.60M|        case 'v': // Parse a vertex texture coordinate
  ------------------
  |  Branch (172:9): [True: 1.60M, False: 8.12M]
  ------------------
  173|  1.60M|        {
  174|  1.60M|            ++mDataIt;
  175|  1.60M|            if (*mDataIt == ' ' || *mDataIt == '\t') {
  ------------------
  |  Branch (175:17): [True: 1.45M, False: 140k]
  |  Branch (175:36): [True: 584, False: 140k]
  ------------------
  176|  1.46M|                size_t numComponents = getNumComponentsInDataDefinition();
  177|  1.46M|                if (numComponents == 3) {
  ------------------
  |  Branch (177:21): [True: 1.28M, False: 170k]
  ------------------
  178|       |                    // read in vertex definition
  179|  1.28M|                    getVector3(mModel->mVertices);
  180|  1.28M|                } else if (numComponents == 4) {
  ------------------
  |  Branch (180:28): [True: 45.8k, False: 124k]
  ------------------
  181|       |                    // read in vertex definition (homogeneous coords)
  182|  45.8k|                    getHomogeneousVector3(mModel->mVertices);
  183|   124k|                } else if (numComponents == 6) {
  ------------------
  |  Branch (183:28): [True: 7.03k, False: 117k]
  ------------------
  184|       |                    // fill previous omitted vertex-colors by default
  185|  7.03k|                    if (mModel->mVertexColors.size() < mModel->mVertices.size()) {
  ------------------
  |  Branch (185:25): [True: 807, False: 6.22k]
  ------------------
  186|    807|                        mModel->mVertexColors.resize(mModel->mVertices.size(), aiVector3D(0, 0, 0));
  187|    807|                    }
  188|       |                    // read vertex and vertex-color
  189|  7.03k|                    getTwoVectors3(mModel->mVertices, mModel->mVertexColors);
  190|  7.03k|                }
  191|       |                // append omitted vertex-colors as default for the end if any vertex-color exists
  192|  1.46M|                if (!mModel->mVertexColors.empty() && mModel->mVertexColors.size() < mModel->mVertices.size()) {
  ------------------
  |  Branch (192:21): [True: 1.00M, False: 458k]
  |  Branch (192:55): [True: 921k, False: 80.6k]
  ------------------
  193|   921k|                    mModel->mVertexColors.resize(mModel->mVertices.size(), aiVector3D(0, 0, 0));
  194|   921k|                }
  195|  1.46M|            } else if (*mDataIt == 't') {
  ------------------
  |  Branch (195:24): [True: 42.5k, False: 97.5k]
  ------------------
  196|       |                // read in texture coordinate ( 2D or 3D )
  197|  42.5k|                ++mDataIt;
  198|  42.5k|                size_t dim = getTexCoordVector(mModel->mTextureCoord);
  199|  42.5k|                mModel->mTextureCoordDim = std::max(mModel->mTextureCoordDim, (unsigned int)dim);
  200|  97.5k|            } else if (*mDataIt == 'n') {
  ------------------
  |  Branch (200:24): [True: 75.0k, False: 22.4k]
  ------------------
  201|       |                // Read in normal vector definition
  202|  75.0k|                ++mDataIt;
  203|  75.0k|                getVector3(mModel->mNormals);
  204|  75.0k|            }
  205|  1.60M|        } break;
  206|       |
  207|  6.10k|        case 'p': // Parse a face, line or point statement
  ------------------
  |  Branch (207:9): [True: 6.10k, False: 9.72M]
  ------------------
  208|  29.9k|        case 'l':
  ------------------
  |  Branch (208:9): [True: 23.8k, False: 9.70M]
  ------------------
  209|   705k|        case 'f': {
  ------------------
  |  Branch (209:9): [True: 675k, False: 9.05M]
  ------------------
  210|   705k|            getFace(*mDataIt == 'f' ? aiPrimitiveType_POLYGON : (*mDataIt == 'l' ? aiPrimitiveType_LINE : aiPrimitiveType_POINT));
  ------------------
  |  Branch (210:21): [True: 675k, False: 29.9k]
  |  Branch (210:66): [True: 23.8k, False: 6.10k]
  ------------------
  211|   705k|        } break;
  212|       |
  213|   124k|        case '#': // Parse a comment
  ------------------
  |  Branch (213:9): [True: 124k, False: 9.60M]
  ------------------
  214|   124k|        {
  215|   124k|            skipComment();
  216|   124k|        } break;
  217|       |
  218|   118k|        case 'u': // Parse a material desc. setter
  ------------------
  |  Branch (218:9): [True: 118k, False: 9.60M]
  ------------------
  219|   118k|        {
  220|   118k|            std::string name;
  221|   118k|            getNameNoSpace(mDataIt, mDataItEnd, name);
  222|       |
  223|   118k|            size_t nextSpace = name.find(' ');
  224|   118k|            if (nextSpace != std::string::npos)
  ------------------
  |  Branch (224:17): [True: 0, False: 118k]
  ------------------
  225|      0|                name = name.substr(0, nextSpace);
  226|       |
  227|   118k|            if (name == "usemtl") {
  ------------------
  |  Branch (227:17): [True: 105k, False: 13.0k]
  ------------------
  228|   105k|                getMaterialDesc();
  229|   105k|            }
  230|   118k|        } break;
  231|       |
  232|   106k|        case 'm': // Parse a material library or merging group ('mg')
  ------------------
  |  Branch (232:9): [True: 106k, False: 9.62M]
  ------------------
  233|   106k|        {
  234|   106k|            std::string name;
  235|       |
  236|   106k|            getNameNoSpace(mDataIt, mDataItEnd, name);
  237|       |
  238|   106k|            size_t nextSpace = name.find(' ');
  239|   106k|            if (nextSpace != std::string::npos)
  ------------------
  |  Branch (239:17): [True: 0, False: 106k]
  ------------------
  240|      0|                name = name.substr(0, nextSpace);
  241|       |
  242|   106k|            if (name == "mg")
  ------------------
  |  Branch (242:17): [True: 766, False: 105k]
  ------------------
  243|    766|                skipGroupNumberAndResolution();
  244|   105k|            else if (name == "mtllib")
  ------------------
  |  Branch (244:22): [True: 69.3k, False: 36.3k]
  ------------------
  245|  69.3k|                getMaterialLib();
  246|  36.3k|            else
  247|  36.3k|                goto pf_skip_line;
  248|   106k|        } break;
  249|       |
  250|   255k|        case 'g': // Parse group name
  ------------------
  |  Branch (250:9): [True: 255k, False: 9.47M]
  ------------------
  251|   255k|        {
  252|   255k|            getGroupName();
  253|   255k|        } break;
  254|       |
  255|  29.3k|        case 's': // Parse group number
  ------------------
  |  Branch (255:9): [True: 29.3k, False: 9.69M]
  ------------------
  256|  29.3k|        {
  257|  29.3k|            skipGroupNumber();
  258|  29.3k|        } break;
  259|       |
  260|  23.1k|        case 'o': // Parse object name
  ------------------
  |  Branch (260:9): [True: 23.1k, False: 9.70M]
  ------------------
  261|  23.1k|        {
  262|  23.1k|            getObjectName();
  263|  23.1k|        } break;
  264|       |
  265|  5.55k|        case 'c': // handle cstype section start
  ------------------
  |  Branch (265:9): [True: 5.55k, False: 9.72M]
  ------------------
  266|  5.55k|        {
  267|  5.55k|            std::string name;
  268|  5.55k|            getNameNoSpace(mDataIt, mDataItEnd, name);
  269|  5.55k|            insideCstype = name == "cstype";
  270|  5.55k|            goto pf_skip_line;
  271|   106k|        }
  272|       |
  273|  6.75M|        default: {
  ------------------
  |  Branch (273:9): [True: 6.75M, False: 2.96M]
  ------------------
  274|  6.84M|        pf_skip_line:
  275|  6.84M|            mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  276|  6.84M|        } break;
  277|  9.72M|        }
  278|  9.72M|    }
  279|  12.0k|}
_ZN6Assimp13ObjFileParser12copyNextWordEPcm:
  282|  4.43M|void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
  283|  4.43M|    size_t index = 0;
  284|  4.43M|    mDataIt = getNextWord<DataArrayIt>(mDataIt, mDataItEnd);
  285|  4.43M|    if (*mDataIt == '\\') {
  ------------------
  |  Branch (285:9): [True: 344, False: 4.43M]
  ------------------
  286|    344|        ++mDataIt;
  287|    344|        ++mDataIt;
  288|    344|        mDataIt = getNextWord<DataArrayIt>(mDataIt, mDataItEnd);
  289|    344|    }
  290|  39.6M|    while (mDataIt != mDataItEnd && !IsSpaceOrNewLine(*mDataIt)) {
  ------------------
  |  Branch (290:12): [True: 39.6M, False: 0]
  |  Branch (290:37): [True: 35.2M, False: 4.43M]
  ------------------
  291|  35.2M|        pBuffer[index] = *mDataIt;
  292|  35.2M|        index++;
  293|  35.2M|        if (index == length - 1) {
  ------------------
  |  Branch (293:13): [True: 73, False: 35.2M]
  ------------------
  294|     73|            break;
  295|     73|        }
  296|  35.2M|        ++mDataIt;
  297|  35.2M|    }
  298|       |
  299|  4.43M|    ai_assert(index < length);
  ------------------
  |  |   67|  4.43M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 4.43M, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  300|  4.43M|    pBuffer[index] = '\0';
  301|  4.43M|}
_ZN6Assimp13ObjFileParser32getNumComponentsInDataDefinitionEv:
  304|  1.50M|size_t ObjFileParser::getNumComponentsInDataDefinition() {
  305|  1.50M|    size_t numComponents(0);
  306|  1.50M|    const char *tmp = &mDataIt[0];
  307|  1.50M|    bool end_of_definition = false;
  308|  4.85M|    while (!end_of_definition) {
  ------------------
  |  Branch (308:12): [True: 4.85M, False: 0]
  ------------------
  309|  4.85M|        if (isDataDefinitionEnd(tmp)) {
  ------------------
  |  Branch (309:13): [True: 770, False: 4.84M]
  ------------------
  310|    770|            tmp += 2;
  311|  4.84M|        } else if (IsLineEnd(*tmp)) {
  ------------------
  |  Branch (311:20): [True: 6, False: 4.84M]
  ------------------
  312|      6|            end_of_definition = true;
  313|      6|        }
  314|  4.85M|        if (!SkipSpaces(&tmp, mEnd) || *tmp == '#') {
  ------------------
  |  Branch (314:13): [True: 2.83k, False: 4.84M]
  |  Branch (314:40): [True: 393, False: 4.84M]
  ------------------
  315|  3.22k|            break;
  316|  3.22k|        }
  317|  4.84M|        const bool isNum(IsNumeric(*tmp) || isNanOrInf(tmp));
  ------------------
  |  Branch (317:26): [True: 4.76M, False: 78.3k]
  |  Branch (317:45): [True: 845, False: 77.5k]
  ------------------
  318|  4.84M|        SkipToken(tmp, mEnd);
  319|  4.84M|        if (isNum) {
  ------------------
  |  Branch (319:13): [True: 4.76M, False: 77.5k]
  ------------------
  320|  4.76M|            ++numComponents;
  321|  4.76M|        }
  322|  4.84M|        if (!SkipSpaces(&tmp, mEnd) || *tmp == '#') {
  ------------------
  |  Branch (322:13): [True: 1.49M, False: 3.34M]
  |  Branch (322:40): [True: 1.55k, False: 3.34M]
  ------------------
  323|  1.49M|            break;
  324|  1.49M|        }
  325|  4.84M|    }
  326|       |
  327|  1.50M|    return numComponents;
  328|  1.50M|}
_ZN6Assimp13ObjFileParser17getTexCoordVectorERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEE:
  331|  42.5k|size_t ObjFileParser::getTexCoordVector(std::vector<aiVector3D> &point3d_array) {
  332|  42.5k|    size_t numComponents = getNumComponentsInDataDefinition();
  333|  42.5k|    ai_real x, y, z;
  334|  42.5k|    if (2 == numComponents) {
  ------------------
  |  Branch (334:9): [True: 13.5k, False: 28.9k]
  ------------------
  335|  13.5k|        copyNextWord(mBuffer, Buffersize);
  336|  13.5k|        x = fast_atof(mBuffer);
  337|       |
  338|  13.5k|        copyNextWord(mBuffer, Buffersize);
  339|  13.5k|        y = fast_atof(mBuffer);
  340|  13.5k|        z = 0.0;
  341|  28.9k|    } else if (3 == numComponents) {
  ------------------
  |  Branch (341:16): [True: 28.8k, False: 54]
  ------------------
  342|  28.8k|        copyNextWord(mBuffer, Buffersize);
  343|  28.8k|        x = fast_atof(mBuffer);
  344|       |
  345|  28.8k|        copyNextWord(mBuffer, Buffersize);
  346|  28.8k|        y = fast_atof(mBuffer);
  347|       |
  348|  28.8k|        copyNextWord(mBuffer, Buffersize);
  349|  28.8k|        z = fast_atof(mBuffer);
  350|  28.8k|    } else {
  351|     54|        throw DeadlyImportError("OBJ: Invalid number of components");
  352|     54|    }
  353|       |
  354|       |    // Coerce nan and inf to 0 as is the OBJ default value
  355|  42.4k|    if (!std::isfinite(x))
  ------------------
  |  Branch (355:9): [True: 103, False: 42.3k]
  ------------------
  356|    103|        x = 0;
  357|       |
  358|  42.4k|    if (!std::isfinite(y))
  ------------------
  |  Branch (358:9): [True: 85, False: 42.3k]
  ------------------
  359|     85|        y = 0;
  360|       |
  361|  42.4k|    if (!std::isfinite(z))
  ------------------
  |  Branch (361:9): [True: 67, False: 42.3k]
  ------------------
  362|     67|        z = 0;
  363|       |
  364|  42.4k|    point3d_array.emplace_back(x, y, z);
  365|  42.4k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  366|  42.4k|    return numComponents;
  367|  42.5k|}
_ZN6Assimp13ObjFileParser10getVector3ERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEE:
  370|  1.36M|void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
  371|  1.36M|    ai_real x, y, z;
  372|  1.36M|    copyNextWord(mBuffer, Buffersize);
  373|  1.36M|    x = fast_atof(mBuffer);
  374|       |
  375|  1.36M|    copyNextWord(mBuffer, Buffersize);
  376|  1.36M|    y = fast_atof(mBuffer);
  377|       |
  378|  1.36M|    copyNextWord(mBuffer, Buffersize);
  379|  1.36M|    z = fast_atof(mBuffer);
  380|       |
  381|  1.36M|    point3d_array.emplace_back(x, y, z);
  382|  1.36M|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  383|  1.36M|}
_ZN6Assimp13ObjFileParser21getHomogeneousVector3ERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEE:
  386|  45.8k|void ObjFileParser::getHomogeneousVector3(std::vector<aiVector3D> &point3d_array) {
  387|  45.8k|    ai_real x, y, z, w;
  388|  45.8k|    copyNextWord(mBuffer, Buffersize);
  389|  45.8k|    x = fast_atof(mBuffer);
  390|       |
  391|  45.8k|    copyNextWord(mBuffer, Buffersize);
  392|  45.8k|    y = fast_atof(mBuffer);
  393|       |
  394|  45.8k|    copyNextWord(mBuffer, Buffersize);
  395|  45.8k|    z = fast_atof(mBuffer);
  396|       |
  397|  45.8k|    copyNextWord(mBuffer, Buffersize);
  398|  45.8k|    w = fast_atof(mBuffer);
  399|       |
  400|  45.8k|    if (w == 0)
  ------------------
  |  Branch (400:9): [True: 8, False: 45.7k]
  ------------------
  401|      8|        throw DeadlyImportError("OBJ: Invalid component in homogeneous vector (Division by zero)");
  402|       |
  403|  45.7k|    point3d_array.emplace_back(x / w, y / w, z / w);
  404|  45.7k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  405|  45.7k|}
_ZN6Assimp13ObjFileParser14getTwoVectors3ERNSt3__16vectorI10aiVector3tIfENS1_9allocatorIS4_EEEES8_:
  408|  7.03k|void ObjFileParser::getTwoVectors3(std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b) {
  409|  7.03k|    ai_real x, y, z;
  410|  7.03k|    copyNextWord(mBuffer, Buffersize);
  411|  7.03k|    x = fast_atof(mBuffer);
  412|       |
  413|  7.03k|    copyNextWord(mBuffer, Buffersize);
  414|  7.03k|    y = fast_atof(mBuffer);
  415|       |
  416|  7.03k|    copyNextWord(mBuffer, Buffersize);
  417|  7.03k|    z = fast_atof(mBuffer);
  418|       |
  419|  7.03k|    point3d_array_a.emplace_back(x, y, z);
  420|       |
  421|  7.03k|    copyNextWord(mBuffer, Buffersize);
  422|  7.03k|    x = fast_atof(mBuffer);
  423|       |
  424|  7.03k|    copyNextWord(mBuffer, Buffersize);
  425|  7.03k|    y = fast_atof(mBuffer);
  426|       |
  427|  7.03k|    copyNextWord(mBuffer, Buffersize);
  428|  7.03k|    z = fast_atof(mBuffer);
  429|       |
  430|  7.03k|    point3d_array_b.emplace_back(x, y, z);
  431|       |
  432|  7.03k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  433|  7.03k|}
_ZN6Assimp13ObjFileParser7getFaceE15aiPrimitiveType:
  452|   705k|void ObjFileParser::getFace(aiPrimitiveType type) {
  453|   705k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  454|   705k|    if (mDataIt == mDataItEnd || *mDataIt == '\0') {
  ------------------
  |  Branch (454:9): [True: 0, False: 705k]
  |  Branch (454:34): [True: 209, False: 704k]
  ------------------
  455|    209|        return;
  456|    209|    }
  457|       |
  458|   704k|    ObjFile::Face *face = new ObjFile::Face(type);
  459|   704k|    bool hasNormal = false;
  460|       |
  461|   704k|    const int vSize = static_cast<unsigned int>(mModel->mVertices.size());
  462|   704k|    const int vtSize = static_cast<unsigned int>(mModel->mTextureCoord.size());
  463|   704k|    const int vnSize = static_cast<unsigned int>(mModel->mNormals.size());
  464|       |
  465|   704k|    const bool vt = (!mModel->mTextureCoord.empty());
  466|   704k|    const bool vn = (!mModel->mNormals.empty());
  467|   704k|    int iPos = 0;
  468|  16.5M|    while (mDataIt < mDataItEnd) {
  ------------------
  |  Branch (468:12): [True: 16.5M, False: 17]
  ------------------
  469|  16.5M|        int iStep = 1;
  470|       |
  471|  16.5M|        if (IsLineEnd(*mDataIt) || *mDataIt == '#') {
  ------------------
  |  Branch (471:13): [True: 696k, False: 15.8M]
  |  Branch (471:36): [True: 7.83k, False: 15.8M]
  ------------------
  472|   704k|            break;
  473|   704k|        }
  474|       |
  475|  15.8M|        if (*mDataIt == '/') {
  ------------------
  |  Branch (475:13): [True: 2.67M, False: 13.1M]
  ------------------
  476|  2.67M|            if (type == aiPrimitiveType_POINT) {
  ------------------
  |  Branch (476:17): [True: 2.85k, False: 2.67M]
  ------------------
  477|  2.85k|                ASSIMP_LOG_ERROR("Obj: Separator unexpected in point statement");
  478|  2.85k|            }
  479|  2.67M|            ++iPos;
  480|  13.1M|        } else if (IsSpaceOrNewLine(*mDataIt) || *mDataIt == '\v') {
  ------------------
  |  Branch (480:20): [True: 5.32M, False: 7.84M]
  |  Branch (480:50): [True: 243, False: 7.84M]
  ------------------
  481|  5.32M|            iPos = 0;
  482|  7.84M|        } else {
  483|       |            //OBJ USES 1 Base ARRAYS!!!!
  484|  7.84M|            const int iVal = ::atoi(&(*mDataIt));
  485|       |
  486|       |            // increment iStep position based off of the sign and # of digits
  487|  7.84M|            int tmp = iVal;
  488|  7.84M|            if (iVal < 0) {
  ------------------
  |  Branch (488:17): [True: 72.2k, False: 7.77M]
  ------------------
  489|  72.2k|                ++iStep;
  490|  72.2k|            }
  491|  12.4M|            while ((tmp = tmp / 10) != 0) {
  ------------------
  |  Branch (491:20): [True: 4.60M, False: 7.84M]
  ------------------
  492|  4.60M|                ++iStep;
  493|  4.60M|            }
  494|       |
  495|  7.84M|            if (iPos == 1 && !vt && vn) {
  ------------------
  |  Branch (495:17): [True: 314k, False: 7.53M]
  |  Branch (495:30): [True: 13.0k, False: 301k]
  |  Branch (495:37): [True: 8.39k, False: 4.63k]
  ------------------
  496|  8.39k|                iPos = 2; // skip texture coords for normals if there are no tex coords
  497|  8.39k|            }
  498|       |
  499|  7.84M|            if (iVal > 0) {
  ------------------
  |  Branch (499:17): [True: 7.77M, False: 72.5k]
  ------------------
  500|       |                // Store parsed index
  501|  7.77M|                if (0 == iPos) {
  ------------------
  |  Branch (501:21): [True: 6.16M, False: 1.60M]
  ------------------
  502|  6.16M|                    face->m_vertices.push_back(iVal - 1);
  503|  6.16M|                } else if (1 == iPos) {
  ------------------
  |  Branch (503:28): [True: 300k, False: 1.30M]
  ------------------
  504|   300k|                    face->m_texturCoords.push_back(iVal - 1);
  505|  1.30M|                } else if (2 == iPos) {
  ------------------
  |  Branch (505:28): [True: 1.28M, False: 21.4k]
  ------------------
  506|  1.28M|                    face->m_normals.push_back(iVal - 1);
  507|  1.28M|                    hasNormal = true;
  508|  1.28M|                } else {
  509|  21.4k|                    reportErrorTokenInFace();
  510|  21.4k|                }
  511|  7.77M|            } else if (iVal < 0) {
  ------------------
  |  Branch (511:24): [True: 72.2k, False: 304]
  ------------------
  512|       |                // Store relatively index
  513|  72.2k|                if (0 == iPos) {
  ------------------
  |  Branch (513:21): [True: 63.5k, False: 8.64k]
  ------------------
  514|  63.5k|                    face->m_vertices.push_back(vSize + iVal);
  515|  63.5k|                } else if (1 == iPos) {
  ------------------
  |  Branch (515:28): [True: 4.78k, False: 3.85k]
  ------------------
  516|  4.78k|                    face->m_texturCoords.push_back(vtSize + iVal);
  517|  4.78k|                } else if (2 == iPos) {
  ------------------
  |  Branch (517:28): [True: 2.22k, False: 1.62k]
  ------------------
  518|  2.22k|                    face->m_normals.push_back(vnSize + iVal);
  519|  2.22k|                    hasNormal = true;
  520|  2.22k|                } else {
  521|  1.62k|                    reportErrorTokenInFace();
  522|  1.62k|                }
  523|  72.2k|            } else {
  524|       |                //On error, std::atoi will return 0 which is not a valid value
  525|    304|                delete face;
  526|    304|                throw DeadlyImportError("OBJ: Invalid face index.");
  527|    304|            }
  528|  7.84M|        }
  529|  15.8M|        mDataIt += iStep;
  530|  15.8M|    }
  531|       |
  532|   704k|    if (face->m_vertices.empty()) {
  ------------------
  |  Branch (532:9): [True: 17.9k, False: 686k]
  ------------------
  533|  17.9k|        ASSIMP_LOG_ERROR("Obj: Ignoring empty face");
  534|       |        // skip line and clean up
  535|  17.9k|        mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  536|  17.9k|        delete face;
  537|  17.9k|        return;
  538|  17.9k|    }
  539|       |
  540|       |    // Set active material, if one set
  541|   686k|    if (nullptr != mModel->mCurrentMaterial) {
  ------------------
  |  Branch (541:9): [True: 650k, False: 35.7k]
  ------------------
  542|   650k|        face->m_pMaterial = mModel->mCurrentMaterial;
  543|   650k|    } else {
  544|  35.7k|        face->m_pMaterial = mModel->mDefaultMaterial;
  545|  35.7k|    }
  546|       |
  547|       |    // Create a default object, if nothing is there
  548|   686k|    if (nullptr == mModel->mCurrentObject) {
  ------------------
  |  Branch (548:9): [True: 2.52k, False: 684k]
  ------------------
  549|  2.52k|        createObject(DefaultObjName);
  550|  2.52k|    }
  551|       |
  552|       |    // Assign face to mesh
  553|   686k|    if (nullptr == mModel->mCurrentMesh) {
  ------------------
  |  Branch (553:9): [True: 0, False: 686k]
  ------------------
  554|      0|        createMesh(DefaultObjName);
  555|      0|    }
  556|       |
  557|       |    // Store the face
  558|   686k|    mModel->mCurrentMesh->m_Faces.emplace_back(face);
  559|   686k|    mModel->mCurrentMesh->m_uiNumIndices += static_cast<unsigned int>(face->m_vertices.size());
  560|   686k|    mModel->mCurrentMesh->m_uiUVCoordinates[0] += static_cast<unsigned int>(face->m_texturCoords.size());
  561|   686k|    if (!mModel->mCurrentMesh->m_hasNormals && hasNormal) {
  ------------------
  |  Branch (561:9): [True: 574k, False: 112k]
  |  Branch (561:48): [True: 24.7k, False: 549k]
  ------------------
  562|  24.7k|        mModel->mCurrentMesh->m_hasNormals = true;
  563|  24.7k|    }
  564|       |    // Skip the rest of the line
  565|   686k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  566|   686k|}
_ZN6Assimp13ObjFileParser15getMaterialDescEv:
  569|   105k|void ObjFileParser::getMaterialDesc() {
  570|       |    // Get next data for material data
  571|   105k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  572|   105k|    if (mDataIt == mDataItEnd) {
  ------------------
  |  Branch (572:9): [True: 0, False: 105k]
  ------------------
  573|      0|        return;
  574|      0|    }
  575|       |
  576|   105k|    char *pStart = &(*mDataIt);
  577|  11.2M|    while (mDataIt != mDataItEnd && !IsLineEnd(*mDataIt)) {
  ------------------
  |  Branch (577:12): [True: 11.2M, False: 0]
  |  Branch (577:37): [True: 11.1M, False: 105k]
  ------------------
  578|  11.1M|        ++mDataIt;
  579|  11.1M|    }
  580|       |
  581|       |    // In some cases we should ignore this 'usemtl' command, this variable helps us to do so
  582|   105k|    bool skip = false;
  583|       |
  584|       |    // Get name
  585|   105k|    std::string strName(pStart, &(*mDataIt));
  586|   105k|    strName = ai_trim(strName);
  587|   105k|    if (strName.empty()) {
  ------------------
  |  Branch (587:9): [True: 1.51k, False: 104k]
  ------------------
  588|  1.51k|        skip = true;
  589|  1.51k|    }
  590|       |
  591|       |    // If the current mesh has the same material, we will ignore that 'usemtl' command
  592|       |    // There is no need to create another object or even mesh here
  593|   105k|    if (!skip) {
  ------------------
  |  Branch (593:9): [True: 104k, False: 1.51k]
  ------------------
  594|   104k|        if (mModel->mCurrentMaterial && mModel->mCurrentMaterial->MaterialName == aiString(strName)) {
  ------------------
  |  Branch (594:13): [True: 102k, False: 2.16k]
  |  Branch (594:13): [True: 38.8k, False: 65.3k]
  |  Branch (594:41): [True: 38.8k, False: 63.1k]
  ------------------
  595|  38.8k|            skip = true;
  596|  38.8k|        }
  597|   104k|    }
  598|       |
  599|   105k|    if (!skip) {
  ------------------
  |  Branch (599:9): [True: 65.3k, False: 40.3k]
  ------------------
  600|       |        // Search for material
  601|  65.3k|        std::map<std::string, ObjFile::Material *>::iterator it = mModel->mMaterialMap.find(strName);
  602|  65.3k|        if (it == mModel->mMaterialMap.end()) {
  ------------------
  |  Branch (602:13): [True: 14.6k, False: 50.7k]
  ------------------
  603|       |            // Not found, so we don't know anything about the material except for its name.
  604|       |            // This may be the case if the material library is missing. We don't want to lose all
  605|       |            // materials if that happens, so create a new named material instead of discarding it
  606|       |            // completely.
  607|  14.6k|            ASSIMP_LOG_ERROR("OBJ: failed to locate material ", strName, ", creating new material");
  608|  14.6k|            mModel->mCurrentMaterial = new ObjFile::Material();
  609|  14.6k|            mModel->mCurrentMaterial->MaterialName.Set(strName);
  610|  14.6k|            mModel->mMaterialLib.push_back(strName);
  611|  14.6k|            mModel->mMaterialMap[strName] = mModel->mCurrentMaterial;
  612|  50.7k|        } else {
  613|       |            // Found, using detected material
  614|  50.7k|            mModel->mCurrentMaterial = it->second;
  615|  50.7k|        }
  616|       |
  617|  65.3k|        if (needsNewMesh(strName)) {
  ------------------
  |  Branch (617:13): [True: 34.4k, False: 30.9k]
  ------------------
  618|  34.4k|            auto newMeshName = mModel->mActiveGroup.empty() ? strName : mModel->mActiveGroup;
  ------------------
  |  Branch (618:32): [True: 13.9k, False: 20.5k]
  ------------------
  619|  34.4k|            createMesh(newMeshName);
  620|  34.4k|        }
  621|       |
  622|  65.3k|        mModel->mCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
  623|  65.3k|    }
  624|       |
  625|       |    // Skip rest of line
  626|   105k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  627|   105k|}
_ZN6Assimp13ObjFileParser11skipCommentEv:
  631|   124k|void ObjFileParser::skipComment() {
  632|   124k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  633|   124k|}
_ZN6Assimp13ObjFileParser14getMaterialLibEv:
  636|  69.3k|void ObjFileParser::getMaterialLib() {
  637|       |    // Translate tuple
  638|  69.3k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  639|  69.3k|    if (mDataIt == mDataItEnd) {
  ------------------
  |  Branch (639:9): [True: 0, False: 69.3k]
  ------------------
  640|      0|        return;
  641|      0|    }
  642|       |
  643|  69.3k|    char *pStart = &(*mDataIt);
  644|  17.2M|    while (mDataIt != mDataItEnd && !IsLineEnd(*mDataIt)) {
  ------------------
  |  Branch (644:12): [True: 17.2M, False: 0]
  |  Branch (644:37): [True: 17.1M, False: 69.3k]
  ------------------
  645|  17.1M|        ++mDataIt;
  646|  17.1M|    }
  647|       |
  648|       |    // Check for existence
  649|  69.3k|    const std::string strMatName(pStart, &(*mDataIt));
  650|  69.3k|    std::string absName;
  651|       |
  652|       |    // Check if directive is valid.
  653|  69.3k|    if (0 == strMatName.length()) {
  ------------------
  |  Branch (653:9): [True: 1.55k, False: 67.7k]
  ------------------
  654|  1.55k|        ASSIMP_LOG_WARN("OBJ: no name for material library specified.");
  655|  1.55k|        return;
  656|  1.55k|    }
  657|       |
  658|  67.7k|    if (mIO->StackSize() > 0) {
  ------------------
  |  Branch (658:9): [True: 0, False: 67.7k]
  ------------------
  659|      0|        std::string path = mIO->CurrentDirectory();
  660|      0|        if ('/' != *path.rbegin()) {
  ------------------
  |  Branch (660:13): [True: 0, False: 0]
  ------------------
  661|      0|            path += '/';
  662|      0|        }
  663|      0|        absName += path;
  664|      0|        absName += strMatName;
  665|  67.7k|    } else {
  666|  67.7k|        absName = strMatName;
  667|  67.7k|    }
  668|       |	
  669|  67.7k|	std::unique_ptr<IOStream> pFile(mIO->Open(absName));
  670|  67.7k|    if (nullptr == pFile) {
  ------------------
  |  Branch (670:9): [True: 67.3k, False: 446]
  ------------------
  671|  67.3k|        ASSIMP_LOG_ERROR("OBJ: Unable to locate material file ", strMatName);
  672|  67.3k|        std::string strMatFallbackName = mOriginalObjFileName.substr(0, mOriginalObjFileName.length() - 3) + "mtl";
  673|  67.3k|        ASSIMP_LOG_INFO("OBJ: Opening fallback material file ", strMatFallbackName);
  674|  67.3k|        pFile.reset(mIO->Open(strMatFallbackName));
  675|  67.3k|        if (!pFile) {
  ------------------
  |  Branch (675:13): [True: 0, False: 67.3k]
  ------------------
  676|      0|            ASSIMP_LOG_ERROR("OBJ: Unable to locate fallback material file ", strMatFallbackName);
  677|      0|            mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  678|      0|            return;
  679|      0|        }
  680|  67.3k|    }
  681|       |
  682|       |    // Import material library data from file.
  683|       |    // Some exporters (e.g. Silo) will happily write out empty
  684|       |    // material files if the model doesn't use any materials, so we
  685|       |    // allow that.
  686|  67.7k|    std::vector<char> buffer;
  687|  67.7k|    BaseImporter::TextFileToBuffer(pFile.get(), buffer, BaseImporter::ALLOW_EMPTY);
  688|       |    //m_pIO->Close(pFile);
  689|       |
  690|       |    // Importing the material library
  691|  67.7k|    ObjFileMtlImporter mtlImporter(buffer, strMatName, mModel.get());
  692|  67.7k|}
_ZN6Assimp13ObjFileParser16getMaterialIndexERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  726|   206k|int ObjFileParser::getMaterialIndex(const std::string &strMaterialName) {
  727|   206k|    int mat_index = InvalidMaterialIndex;
  728|   206k|    if (strMaterialName.empty()) {
  ------------------
  |  Branch (728:9): [True: 693, False: 205k]
  ------------------
  729|    693|        return mat_index;
  730|    693|    }
  731|  2.92M|    for (size_t index = 0; index < mModel->mMaterialLib.size(); ++index) {
  ------------------
  |  Branch (731:28): [True: 2.92M, False: 3.58k]
  ------------------
  732|  2.92M|        if (strMaterialName == mModel->mMaterialLib[index]) {
  ------------------
  |  Branch (732:13): [True: 202k, False: 2.71M]
  ------------------
  733|   202k|            mat_index = (int)index;
  734|   202k|            break;
  735|   202k|        }
  736|  2.92M|    }
  737|   205k|    return mat_index;
  738|   206k|}
_ZN6Assimp13ObjFileParser12getGroupNameEv:
  742|   255k|void ObjFileParser::getGroupName() {
  743|   255k|    std::string groupName;
  744|       |
  745|       |    // here we skip 'g ' from line
  746|   255k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  747|   255k|    mDataIt = getName<DataArrayIt>(mDataIt, mDataItEnd, groupName);
  748|   255k|    if (isEndOfBuffer(mDataIt, mDataItEnd)) {
  ------------------
  |  Branch (748:9): [True: 4, False: 255k]
  ------------------
  749|      4|        return;
  750|      4|    }
  751|       |
  752|       |    // Change active group, if necessary
  753|   255k|    if (mModel->mActiveGroup != groupName) {
  ------------------
  |  Branch (753:9): [True: 183k, False: 71.7k]
  ------------------
  754|       |        // Search for already existing entry
  755|   183k|        ObjFile::Model::ConstGroupMapIt it = mModel->mGroups.find(groupName);
  756|       |
  757|       |        // We are mapping groups into the object structure
  758|   183k|        createObject(groupName);
  759|       |
  760|       |        // New group name, creating a new entry
  761|   183k|        if (it == mModel->mGroups.end()) {
  ------------------
  |  Branch (761:13): [True: 17.6k, False: 166k]
  ------------------
  762|  17.6k|            std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
  763|  17.6k|            mModel->mGroups[groupName] = pFaceIDArray;
  764|  17.6k|            mModel->mGroupFaceIDs = (pFaceIDArray);
  765|   166k|        } else {
  766|   166k|            mModel->mGroupFaceIDs = (*it).second;
  767|   166k|        }
  768|   183k|        mModel->mActiveGroup = groupName;
  769|   183k|    }
  770|   255k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  771|   255k|}
_ZN6Assimp13ObjFileParser15skipGroupNumberEv:
  774|  29.3k|void ObjFileParser::skipGroupNumber() {
  775|       |    // Not used
  776|       |
  777|  29.3k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  778|  29.3k|}
_ZN6Assimp13ObjFileParser28skipGroupNumberAndResolutionEv:
  781|    766|void ObjFileParser::skipGroupNumberAndResolution() {
  782|       |    // Not used
  783|       |
  784|    766|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  785|    766|}
_ZN6Assimp13ObjFileParser13getObjectNameEv:
  790|  23.1k|void ObjFileParser::getObjectName() {
  791|  23.1k|    mDataIt = getNextToken<DataArrayIt>(mDataIt, mDataItEnd);
  792|  23.1k|    if (mDataIt == mDataItEnd) {
  ------------------
  |  Branch (792:9): [True: 0, False: 23.1k]
  ------------------
  793|      0|        return;
  794|      0|    }
  795|  23.1k|    char *pStart = &(*mDataIt);
  796|   858k|    while (mDataIt != mDataItEnd && !IsSpaceOrNewLine(*mDataIt)) {
  ------------------
  |  Branch (796:12): [True: 858k, False: 0]
  |  Branch (796:37): [True: 835k, False: 23.1k]
  ------------------
  797|   835k|        ++mDataIt;
  798|   835k|    }
  799|       |
  800|  23.1k|    std::string strObjectName(pStart, &(*mDataIt));
  801|  23.1k|    if (!strObjectName.empty()) {
  ------------------
  |  Branch (801:9): [True: 18.3k, False: 4.82k]
  ------------------
  802|       |        // Reset current object
  803|  18.3k|        mModel->mCurrentObject = nullptr;
  804|       |
  805|       |        // Search for actual object
  806|   234k|        for (auto it = mModel->mObjects.begin(); it != mModel->mObjects.end(); ++it) {
  ------------------
  |  Branch (806:50): [True: 230k, False: 3.75k]
  ------------------
  807|   230k|            if ((*it)->m_strObjName == strObjectName) {
  ------------------
  |  Branch (807:17): [True: 14.5k, False: 215k]
  ------------------
  808|  14.5k|                mModel->mCurrentObject = *it;
  809|  14.5k|                break;
  810|  14.5k|            }
  811|   230k|        }
  812|       |
  813|       |        // Allocate a new object, if current one was not found before
  814|  18.3k|        if (mModel->mCurrentObject == nullptr) {
  ------------------
  |  Branch (814:13): [True: 3.75k, False: 14.5k]
  ------------------
  815|  3.75k|            createObject(strObjectName);
  816|  3.75k|        }
  817|  18.3k|    }
  818|  23.1k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  819|  23.1k|}
_ZN6Assimp13ObjFileParser12createObjectERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  823|   190k|void ObjFileParser::createObject(const std::string &objName) {
  824|   190k|    ai_assert(nullptr != mModel);
  ------------------
  |  |   67|   190k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 190k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  825|       |
  826|   190k|    mModel->mCurrentObject = new ObjFile::Object;
  827|   190k|    mModel->mCurrentObject->m_strObjName = objName;
  828|   190k|    mModel->mObjects.push_back(mModel->mCurrentObject);
  829|       |
  830|   190k|    createMesh(objName);
  831|       |
  832|   190k|    if (mModel->mCurrentMaterial) {
  ------------------
  |  Branch (832:9): [True: 77.2k, False: 112k]
  ------------------
  833|  77.2k|        mModel->mCurrentMesh->m_uiMaterialIndex =
  834|  77.2k|                getMaterialIndex(mModel->mCurrentMaterial->MaterialName.data);
  835|  77.2k|        mModel->mCurrentMesh->m_pMaterial = mModel->mCurrentMaterial;
  836|  77.2k|    }
  837|   190k|}
_ZN6Assimp13ObjFileParser10createMeshERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  840|   224k|void ObjFileParser::createMesh(const std::string &meshName) {
  841|   224k|    ai_assert(nullptr != mModel);
  ------------------
  |  |   67|   224k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 224k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  842|       |
  843|   224k|    mModel->mCurrentMesh = new ObjFile::Mesh(meshName);
  844|   224k|    mModel->mMeshes.push_back(mModel->mCurrentMesh);
  845|   224k|    auto meshId = static_cast<unsigned int>(mModel->mMeshes.size() - 1);
  846|   224k|    if (mModel->mCurrentObject != nullptr) {
  ------------------
  |  Branch (846:9): [True: 223k, False: 1.39k]
  ------------------
  847|   223k|        mModel->mCurrentObject->m_Meshes.push_back(meshId);
  848|   223k|    } else {
  849|       |        ASSIMP_LOG_ERROR("OBJ: No object detected to attach a new mesh instance.");
  850|  1.39k|    }
  851|   224k|}
_ZN6Assimp13ObjFileParser12needsNewMeshERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  855|  65.3k|bool ObjFileParser::needsNewMesh(const std::string &materialName) {
  856|       |    // If no mesh data yet
  857|  65.3k|    if (mModel->mCurrentMesh == nullptr) {
  ------------------
  |  Branch (857:9): [True: 1.39k, False: 63.9k]
  ------------------
  858|  1.39k|        return true;
  859|  1.39k|    }
  860|  63.9k|    bool newMat = false;
  861|  63.9k|    int matIdx = getMaterialIndex(materialName);
  862|  63.9k|    int curMatIdx = mModel->mCurrentMesh->m_uiMaterialIndex;
  863|  63.9k|    if (curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx
  ------------------
  |  Branch (863:9): [True: 62.4k, False: 1.52k]
  |  Branch (863:56): [True: 61.5k, False: 913]
  ------------------
  864|       |            // no need create a new mesh if no faces in current
  865|       |            // lets say 'usemtl' goes straight after 'g'
  866|  61.5k|            && !mModel->mCurrentMesh->m_Faces.empty()) {
  ------------------
  |  Branch (866:16): [True: 33.0k, False: 28.4k]
  ------------------
  867|       |        // New material -> only one material per mesh, so we need to create a new
  868|       |        // material
  869|  33.0k|        newMat = true;
  870|  33.0k|    }
  871|  63.9k|    return newMat;
  872|  65.3k|}
_ZN6Assimp13ObjFileParser22reportErrorTokenInFaceEv:
  876|  23.1k|void ObjFileParser::reportErrorTokenInFace() {
  877|  23.1k|    mDataIt = skipLine<DataArrayIt>(mDataIt, mDataItEnd, mLine);
  878|       |    ASSIMP_LOG_ERROR("OBJ: Not supported token in face description detected");
  879|  23.1k|}
ObjFileParser.cpp:_ZN6AssimpL19isDataDefinitionEndEPKc:
   61|  4.85M|static bool isDataDefinitionEnd(const char *tmp) {
   62|  4.85M|	ai_assert(tmp != nullptr);
  ------------------
  |  |   67|  4.85M|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 4.85M, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   63|       |	
   64|  4.85M|    if (*tmp == '\\') {
  ------------------
  |  Branch (64:9): [True: 1.19k, False: 4.84M]
  ------------------
   65|  1.19k|        ++tmp;
   66|  1.19k|        if (IsLineEnd(*tmp)) {
  ------------------
  |  Branch (66:13): [True: 770, False: 420]
  ------------------
   67|    770|            return true;
   68|    770|        }
   69|  1.19k|    }
   70|  4.84M|    return false;
   71|  4.85M|}
ObjFileParser.cpp:_ZN6AssimpL10isNanOrInfEPKc:
   74|  78.3k|static bool isNanOrInf(const char *in) {
   75|  78.3k|	ai_assert(in != nullptr);
  ------------------
  |  |   67|  78.3k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 78.3k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   76|       |	
   77|       |    // Look for "nan" or "inf", case insensitive
   78|  78.3k|    return ((in[0] == 'N' || in[0] == 'n') && ASSIMP_strincmp(in, "nan", 3) == 0) ||
  ------------------
  |  Branch (78:14): [True: 266, False: 78.0k]
  |  Branch (78:30): [True: 1.35k, False: 76.7k]
  |  Branch (78:47): [True: 407, False: 1.21k]
  ------------------
   79|  77.9k|           ((in[0] == 'I' || in[0] == 'i') && ASSIMP_strincmp(in, "inf", 3) == 0);
  ------------------
  |  Branch (79:14): [True: 629, False: 77.3k]
  |  Branch (79:30): [True: 7.27k, False: 70.0k]
  |  Branch (79:47): [True: 438, False: 7.46k]
  ------------------
   80|  78.3k|}

_ZN6Assimp13ObjFileParserD2Ev:
   79|  11.1k|    ~ObjFileParser() = default;

_ZN6Assimp14getNameNoSpaceINSt3__111__wrap_iterIPcEEEET_S5_S5_RNS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  192|   232k|inline char_t getNameNoSpace(char_t it, char_t end, std::string &name) {
  193|   232k|    name = "";
  194|   232k|    if (isEndOfBuffer(it, end)) {
  ------------------
  |  Branch (194:9): [True: 0, False: 232k]
  ------------------
  195|      0|        return end;
  196|      0|    }
  197|       |
  198|   232k|    char *pStart = &(*it);
  199|  11.3M|    while (!isEndOfBuffer(it, end) && !IsLineEnd(*it) && !IsSpaceOrNewLine(*it)) {
  ------------------
  |  Branch (199:12): [True: 11.3M, False: 3]
  |  Branch (199:39): [True: 11.3M, False: 27.2k]
  |  Branch (199:58): [True: 11.1M, False: 205k]
  ------------------
  200|  11.1M|        ++it;
  201|  11.1M|    }
  202|       |
  203|   464k|    while (isEndOfBuffer(it, end) || IsLineEnd(*it) || IsSpaceOrNewLine(*it)) {
  ------------------
  |  Branch (203:12): [True: 3, False: 464k]
  |  Branch (203:38): [True: 27.2k, False: 437k]
  |  Branch (203:56): [True: 205k, False: 232k]
  ------------------
  204|   232k|        --it;
  205|   232k|    }
  206|   232k|    ++it;
  207|       |
  208|       |    // Get name
  209|       |    // if there is no name, and the previous char is a separator, come back to start
  210|   232k|    while (&(*it) < pStart) {
  ------------------
  |  Branch (210:12): [True: 0, False: 232k]
  ------------------
  211|      0|        ++it;
  212|      0|    }
  213|   232k|    std::string strName(pStart, &(*it));
  214|   232k|    if (!strName.empty()) {
  ------------------
  |  Branch (214:9): [True: 232k, False: 0]
  ------------------
  215|   232k|        name = strName;
  216|   232k|    }
  217|       |
  218|   232k|    return it;
  219|   232k|}
_ZN6Assimp8skipLineINSt3__111__wrap_iterIPcEEEET_S5_S5_Rj:
  125|   315M|inline char_t skipLine(char_t it, char_t end, unsigned int &uiLine) {
  126|   315M|    if (it >= end) {
  ------------------
  |  Branch (126:9): [True: 2.51k, False: 315M]
  ------------------
  127|  2.51k|        return it;
  128|  2.51k|    }
  129|       |
  130|  4.77G|    while (!isEndOfBuffer(it, end) && !IsLineEnd(*it)) {
  ------------------
  |  Branch (130:12): [True: 4.77G, False: 64.8k]
  |  Branch (130:39): [True: 4.46G, False: 315M]
  ------------------
  131|  4.46G|        ++it;
  132|  4.46G|    }
  133|       |
  134|   315M|    if (it != end) {
  ------------------
  |  Branch (134:9): [True: 315M, False: 0]
  ------------------
  135|   315M|        ++it;
  136|   315M|        ++uiLine;
  137|   315M|    }
  138|       |    // fix .. from time to time there are spaces at the beginning of a material line
  139|   322M|    while (it != end && (*it == '\t' || *it == ' ')) {
  ------------------
  |  Branch (139:12): [True: 322M, False: 64.8k]
  |  Branch (139:26): [True: 1.87M, False: 320M]
  |  Branch (139:41): [True: 5.36M, False: 315M]
  ------------------
  140|  7.23M|        ++it;
  141|  7.23M|    }
  142|       |
  143|   315M|    return it;
  144|   315M|}
_ZN6Assimp11getNextWordINSt3__111__wrap_iterIPcEEEET_S5_S5_:
   77|  21.1M|inline Char_T getNextWord(Char_T pBuffer, Char_T pEnd) {
   78|  39.9M|    while (!isEndOfBuffer(pBuffer, pEnd)) {
  ------------------
  |  Branch (78:12): [True: 39.9M, False: 20.4k]
  ------------------
   79|  39.9M|        if (!IsSpaceOrNewLine(*pBuffer) || IsLineEnd(*pBuffer)) {
  ------------------
  |  Branch (79:13): [True: 17.1M, False: 22.8M]
  |  Branch (79:44): [True: 4.06M, False: 18.7M]
  ------------------
   80|  21.1M|            break;
   81|  21.1M|        }
   82|  18.7M|        ++pBuffer;
   83|  18.7M|    }
   84|       |
   85|  21.1M|    return pBuffer;
   86|  21.1M|}
_ZN6Assimp12getNextTokenINSt3__111__wrap_iterIPcEEEET_S5_S5_:
  112|  2.93M|inline Char_T getNextToken(Char_T pBuffer, Char_T pEnd) {
  113|  2.93M|    pBuffer = getNextDelimiter(pBuffer, pEnd);
  114|  2.93M|    return getNextWord(pBuffer, pEnd);
  115|  2.93M|}
_ZN6Assimp16getNextDelimiterINSt3__111__wrap_iterIPcEEEET_S5_S5_:
   95|  15.4M|inline Char_T getNextDelimiter(Char_T pBuffer, Char_T pEnd) {
   96|   199M|    while (!isEndOfBuffer(pBuffer, pEnd)) {
  ------------------
  |  Branch (96:12): [True: 199M, False: 13.3k]
  ------------------
   97|   199M|        if (IsSpaceOrNewLine(*pBuffer)) {
  ------------------
  |  Branch (97:13): [True: 15.4M, False: 184M]
  ------------------
   98|  15.4M|            break;
   99|  15.4M|        }
  100|   184M|        ++pBuffer;
  101|   184M|    }
  102|  15.4M|    return pBuffer;
  103|  15.4M|}
_ZN6Assimp7getNameINSt3__111__wrap_iterIPcEEEET_S5_S5_RNS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  155|   938k|inline char_t getName(char_t it, char_t end, std::string &name) {
  156|   938k|    name = "";
  157|   938k|    if (isEndOfBuffer(it, end)) {
  ------------------
  |  Branch (157:9): [True: 2.70k, False: 936k]
  ------------------
  158|  2.70k|        return end;
  159|  2.70k|    }
  160|       |
  161|   936k|    char *pStart = &(*it);
  162|  32.7M|    while (!isEndOfBuffer(it, end) && !IsLineEnd(*it)) {
  ------------------
  |  Branch (162:12): [True: 32.7M, False: 807]
  |  Branch (162:39): [True: 31.8M, False: 935k]
  ------------------
  163|  31.8M|        ++it;
  164|  31.8M|    }
  165|       |
  166|   936k|    while (IsSpace(*it)) {
  ------------------
  |  Branch (166:12): [True: 0, False: 936k]
  ------------------
  167|      0|        --it;
  168|      0|    }
  169|       |    // Get name
  170|       |    // if there is no name, and the previous char is a separator, come back to start
  171|   936k|    while (&(*it) < pStart) {
  ------------------
  |  Branch (171:12): [True: 0, False: 936k]
  ------------------
  172|      0|        ++it;
  173|      0|    }
  174|   936k|    std::string strName(pStart, &(*it));
  175|   936k|    if (!strName.empty()) {
  ------------------
  |  Branch (175:9): [True: 661k, False: 274k]
  ------------------
  176|   661k|        name = strName;
  177|   661k|    }
  178|       |
  179|       |
  180|   936k|    return it;
  181|   938k|}
_ZN6Assimp13isEndOfBufferINSt3__111__wrap_iterIPcEEEEbT_S5_:
   61|  5.07G|inline bool isEndOfBuffer(char_t it, char_t end) {
   62|  5.07G|    if (it == end) {
  ------------------
  |  Branch (62:9): [True: 2, False: 5.07G]
  ------------------
   63|      2|        return true;
   64|      2|    }
   65|  5.07G|    --end;
   66|       |
   67|  5.07G|    return (it == end);
   68|  5.07G|}
_ZN6Assimp8getFloatINSt3__111__wrap_iterIPcEEEET_S5_S5_Rf:
  253|   537k|inline char_t getFloat(char_t it, char_t end, ai_real &value) {
  254|   537k|    static const size_t BUFFERSIZE = 1024;
  255|   537k|    char buffer[BUFFERSIZE] = {};
  256|   537k|    it = CopyNextWord<char_t>(it, end, buffer, BUFFERSIZE);
  257|   537k|    value = (ai_real)fast_atof(buffer);
  258|       |
  259|   537k|    return it;
  260|   537k|}
_ZN6Assimp12CopyNextWordINSt3__111__wrap_iterIPcEEEET_S5_S5_S3_m:
  230|  1.32M|inline char_t CopyNextWord(char_t it, char_t end, char *pBuffer, size_t length) {
  231|  1.32M|    size_t index = 0;
  232|  1.32M|    it = getNextWord<char_t>(it, end);
  233|  12.6M|    while (!IsSpaceOrNewLine(*it) && !isEndOfBuffer(it, end)) {
  ------------------
  |  Branch (233:12): [True: 11.3M, False: 1.29M]
  |  Branch (233:38): [True: 11.3M, False: 0]
  ------------------
  234|  11.3M|        pBuffer[index] = *it;
  235|  11.3M|        ++index;
  236|  11.3M|        if (index == length - 1) {
  ------------------
  |  Branch (236:13): [True: 24.0k, False: 11.3M]
  ------------------
  237|  24.0k|            break;
  238|  24.0k|        }
  239|  11.3M|        ++it;
  240|  11.3M|    }
  241|  1.32M|    pBuffer[index] = '\0';
  242|  1.32M|    return it;
  243|  1.32M|}

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

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

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

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

_ZN6Assimp11PLYImporterC2Ev:
   68|  12.0k|    PLYImporter() = default;

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

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

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

_ZN6Assimp11RAWImporterC2Ev:
   60|  12.0k|    RAWImporter() = default;

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

_ZN6Assimp11SIBImporterC2Ev:
   60|  12.0k|    SIBImporter() = default;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp12BaseImporterC2Ev:
   92|   578k|        : m_progress() {
   93|       |    // empty
   94|   578k|}
_ZN6Assimp12BaseImporter19UpdateImporterScaleEPNS_8ImporterE:
   96|  10.5k|void BaseImporter::UpdateImporterScale(Importer *pImp) {
   97|  10.5k|    ai_assert(pImp != nullptr);
   98|  10.5k|    ai_assert(importerScale != 0.0);
   99|  10.5k|    ai_assert(fileScale != 0.0);
  100|       |
  101|  10.5k|    double activeScale = importerScale * fileScale;
  102|       |
  103|       |    // Set active scaling
  104|  10.5k|    pImp->SetPropertyFloat(AI_CONFIG_APP_SCALE_KEY, static_cast<float>(activeScale));
  105|       |
  106|       |    ASSIMP_LOG_DEBUG("UpdateImporterScale scale set: ", activeScale);
  107|  10.5k|}
_ZN6Assimp12BaseImporter8ReadFileEPNS_8ImporterERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEPNS_8IOSystemE:
  111|  12.0k|aiScene *BaseImporter::ReadFile(Importer *pImp, const std::string &pFile, IOSystem *pIOHandler) {
  112|       |
  113|  12.0k|    m_progress = pImp->GetProgressHandler();
  114|  12.0k|    if (nullptr == m_progress) {
  ------------------
  |  Branch (114:9): [True: 0, False: 12.0k]
  ------------------
  115|      0|        return nullptr;
  116|      0|    }
  117|       |
  118|  12.0k|    ai_assert(m_progress);
  119|       |
  120|       |    // Gather configuration properties for this run
  121|  12.0k|    SetupProperties(pImp);
  122|       |
  123|       |    // Construct a file system filter to improve our success ratio at reading external files
  124|  12.0k|    FileSystemFilter filter(pFile, pIOHandler);
  125|       |
  126|       |    // create a scene object to hold the data
  127|  12.0k|    std::unique_ptr<aiScene> sc(new aiScene());
  128|       |
  129|       |    // dispatch importing
  130|  12.0k|    try {
  131|  12.0k|        InternReadFile(pFile, sc.get(), &filter);
  132|       |
  133|       |        // Calculate import scale hook - required because pImp not available anywhere else
  134|       |        // passes scale into ScaleProcess
  135|  12.0k|        UpdateImporterScale(pImp);
  136|       |
  137|  12.0k|    } catch( const std::exception &err ) {
  138|       |        // extract error description
  139|  1.54k|        m_ErrorText = err.what();
  140|  1.54k|        ASSIMP_LOG_ERROR(err.what());
  141|  1.54k|        m_Exception = std::current_exception();
  142|  1.54k|        return nullptr;
  143|  1.54k|    }
  144|       |
  145|       |    // return what we gathered from the import.
  146|  10.5k|    return sc.release();
  147|  12.0k|}
_ZN6Assimp12BaseImporter15SetupPropertiesEPKNS_8ImporterE:
  150|  12.0k|void BaseImporter::SetupProperties(const Importer *) {
  151|       |    // the default implementation does nothing
  152|  12.0k|}
_ZN6Assimp12BaseImporter16GetExtensionListERNSt3__13setINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_4lessIS8_EENS6_IS8_EEEE:
  155|  12.0k|void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
  156|  12.0k|    const aiImporterDesc *desc = GetInfo();
  157|  12.0k|    ai_assert(desc != nullptr);
  158|       |
  159|  12.0k|    const char *ext = desc->mFileExtensions;
  160|  12.0k|    ai_assert(ext != nullptr);
  161|       |
  162|  12.0k|    const char *last = ext;
  163|  48.2k|    do {
  164|  48.2k|        if (!*ext || *ext == ' ') {
  ------------------
  |  Branch (164:13): [True: 12.0k, False: 36.1k]
  |  Branch (164:22): [True: 0, False: 36.1k]
  ------------------
  165|  12.0k|            extensions.insert(std::string(last, ext - last));
  166|  12.0k|            ai_assert(ext - last > 0);
  167|  12.0k|            last = ext;
  168|  12.0k|            while (*last == ' ') {
  ------------------
  |  Branch (168:20): [True: 0, False: 12.0k]
  ------------------
  169|      0|                ++last;
  170|      0|            }
  171|  12.0k|        }
  172|  48.2k|    } while (*ext++);
  ------------------
  |  Branch (172:14): [True: 36.1k, False: 12.0k]
  ------------------
  173|  12.0k|}
_ZN6Assimp12BaseImporter12HasExtensionERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERKNS1_3setIS7_NS1_4lessIS7_EENS5_IS7_EEEE:
  265|  12.0k|/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
  266|  12.0k|    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|  12.0k|    for (const std::string& ext : extensions) {
  ------------------
  |  Branch (271:33): [True: 12.0k, False: 0]
  ------------------
  272|       |        // Yay for C++<20 not having std::string::ends_with()
  273|  12.0k|        const std::string dotExt = "." + ext;
  274|  12.0k|        if (dotExt.length() > file.length()) continue;
  ------------------
  |  Branch (274:13): [True: 0, False: 12.0k]
  ------------------
  275|       |        // Possible optimization: Fetch the lowercase filename!
  276|  12.0k|        if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) {
  ------------------
  |  Branch (276:13): [True: 12.0k, False: 0]
  ------------------
  277|  12.0k|            return true;
  278|  12.0k|        }
  279|  12.0k|    }
  280|      0|    return false;
  281|  12.0k|}
_ZN6Assimp12BaseImporter13ConvertToUTF8ERNSt3__16vectorIcNS1_9allocatorIcEEEE:
  361|  67.7k|void BaseImporter::ConvertToUTF8(std::vector<char> &data) {
  362|       |    //ConversionResult result;
  363|  67.7k|    if (data.size() < 8) {
  ------------------
  |  Branch (363:9): [True: 0, False: 67.7k]
  ------------------
  364|      0|        throw DeadlyImportError("File is too small");
  365|      0|    }
  366|       |
  367|       |    // UTF 8 with BOM
  368|  67.7k|    if ((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
  ------------------
  |  Branch (368:9): [True: 1.67k, False: 66.0k]
  |  Branch (368:37): [True: 1.09k, False: 575]
  |  Branch (368:65): [True: 437, False: 660]
  ------------------
  369|    437|        ASSIMP_LOG_DEBUG("Found UTF-8 BOM ...");
  370|       |
  371|    437|        std::copy(data.begin() + 3, data.end(), data.begin());
  372|    437|        data.resize(data.size() - 3);
  373|    437|        return;
  374|    437|    }
  375|       |
  376|       |    // UTF 32 BE with BOM
  377|  67.2k|    if (*((uint32_t *)&data.front()) == 0xFFFE0000) {
  ------------------
  |  Branch (377:9): [True: 236, False: 67.0k]
  ------------------
  378|    236|        if (data.size() % sizeof(uint32_t) != 0) {
  ------------------
  |  Branch (378:13): [True: 1, False: 235]
  ------------------
  379|      1|            throw DeadlyImportError("Not valid UTF-32 BE");
  380|      1|        }
  381|       |
  382|       |        // swap the endianness ..
  383|  79.5k|        for (uint32_t *p = (uint32_t *)&data.front(), *end = (uint32_t *)&data.back(); p <= end; ++p) {
  ------------------
  |  Branch (383:88): [True: 79.3k, False: 235]
  ------------------
  384|  79.3k|            AI_SWAP4P(p);
  385|  79.3k|        }
  386|    235|    }
  387|       |
  388|       |    // UTF 32 LE with BOM
  389|  67.2k|    if (*((uint32_t *)&data.front()) == 0x0000FFFE) {
  ------------------
  |  Branch (389:9): [True: 106, False: 67.1k]
  ------------------
  390|    106|        if (data.size() % sizeof(uint32_t) != 0) {
  ------------------
  |  Branch (390:13): [True: 1, False: 105]
  ------------------
  391|      1|            throw DeadlyImportError("Not valid UTF-32 LE");
  392|      1|        }
  393|    106|        ASSIMP_LOG_DEBUG("Found UTF-32 BOM ...");
  394|       |
  395|    105|        std::vector<char> output;
  396|    105|        auto *ptr = (uint32_t *)&data[0];
  397|    105|        uint32_t *end = ptr + (data.size() / sizeof(uint32_t)) + 1;
  398|    105|        utf8::utf32to8(ptr, end, back_inserter(output));
  399|    105|        return;
  400|    106|    }
  401|       |
  402|       |    // UTF 16 BE with BOM
  403|  67.1k|    if (*((uint16_t *)&data.front()) == 0xFFFE) {
  ------------------
  |  Branch (403:9): [True: 2.09k, False: 65.0k]
  ------------------
  404|       |        // Check to ensure no overflow can happen
  405|  2.09k|        if (data.size() % sizeof(uint16_t) != 0) {
  ------------------
  |  Branch (405:13): [True: 3, False: 2.09k]
  ------------------
  406|      3|            throw DeadlyImportError("Not valid UTF-16 BE");
  407|      3|        }
  408|       |        // swap the endianness ..
  409|  7.12M|        for (uint16_t *p = (uint16_t *)&data.front(), *end = (uint16_t *)&data.back(); p <= end; ++p) {
  ------------------
  |  Branch (409:88): [True: 7.11M, False: 2.09k]
  ------------------
  410|  7.11M|            ByteSwap::Swap2(p);
  411|  7.11M|        }
  412|  2.09k|    }
  413|       |
  414|       |    // UTF 16 LE with BOM
  415|  67.1k|    if (*((uint16_t *)&data.front()) == 0xFEFF) {
  ------------------
  |  Branch (415:9): [True: 2.09k, False: 65.0k]
  ------------------
  416|  2.09k|        if (data.size() % sizeof(uint16_t) != 0) {
  ------------------
  |  Branch (416:13): [True: 1, False: 2.09k]
  ------------------
  417|      1|            throw DeadlyImportError("Not valid UTF-16 LE");
  418|      1|        }
  419|  2.09k|        ASSIMP_LOG_DEBUG("Found UTF-16 BOM ...");
  420|       |
  421|  2.09k|        std::vector<unsigned char> output;
  422|  2.09k|        utf8::utf16to8(data.begin(), data.end(), back_inserter(output));
  423|  2.09k|        return;
  424|  2.09k|    }
  425|  67.1k|}
_ZN6Assimp12BaseImporter16TextFileToBufferEPNS_8IOStreamERNSt3__16vectorIcNS3_9allocatorIcEEEENS0_12TextFileModeE:
  465|  67.7k|        TextFileMode mode) {
  466|  67.7k|    ai_assert(nullptr != stream);
  467|       |
  468|  67.7k|    const size_t fileSize = stream->FileSize();
  469|  67.7k|    if (mode == FORBID_EMPTY) {
  ------------------
  |  Branch (469:9): [True: 0, False: 67.7k]
  ------------------
  470|      0|        if (!fileSize) {
  ------------------
  |  Branch (470:13): [True: 0, False: 0]
  ------------------
  471|      0|            throw DeadlyImportError("File is empty");
  472|      0|        }
  473|      0|    }
  474|       |
  475|  67.7k|    data.reserve(fileSize + 1);
  476|  67.7k|    data.resize(fileSize);
  477|  67.7k|    if (fileSize > 0) {
  ------------------
  |  Branch (477:9): [True: 67.7k, False: 0]
  ------------------
  478|  67.7k|        if (fileSize != stream->Read(&data[0], 1, fileSize)) {
  ------------------
  |  Branch (478:13): [True: 19, False: 67.7k]
  ------------------
  479|     19|            throw DeadlyImportError("File read error");
  480|     19|        }
  481|       |
  482|  67.7k|        ConvertToUTF8(data);
  483|  67.7k|    }
  484|       |
  485|       |    // append a binary zero to simplify string parsing
  486|  67.7k|    data.push_back(0);
  487|  67.7k|}
BaseImporter.cpp:_ZN12_GLOBAL__N_116StripVersionHashERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
   75|  12.0k|std::string StripVersionHash(const std::string &filename) {
   76|  12.0k|    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|  12.0k|    if (pos != std::string::npos && pos > filename.find_last_of('.') &&
  ------------------
  |  Branch (79:9): [True: 0, False: 12.0k]
  |  Branch (79:9): [True: 0, False: 12.0k]
  |  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|  12.0k|    return filename;
   84|  12.0k|}

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

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

_ZN6Assimp15DefaultIOStreamD2Ev:
   82|     38|DefaultIOStream::~DefaultIOStream() {
   83|     38|    if (mFile) {
  ------------------
  |  Branch (83:9): [True: 38, False: 0]
  ------------------
   84|     38|        ::fclose(mFile);
   85|     38|    }
   86|     38|}
_ZN6Assimp15DefaultIOStream4ReadEPvmm:
   91|     38|        size_t pCount) {
   92|     38|    if (0 == pCount) {
  ------------------
  |  Branch (92:9): [True: 0, False: 38]
  ------------------
   93|      0|        return 0;
   94|      0|    }
   95|     38|    ai_assert(nullptr != pvBuffer);
  ------------------
  |  |   67|     38|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 38, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   96|     38|    ai_assert(0 != pSize);
  ------------------
  |  |   67|     38|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 38, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   97|       |
   98|     38|    return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0);
  ------------------
  |  Branch (98:13): [True: 38, False: 0]
  ------------------
   99|     38|}
_ZNK6Assimp15DefaultIOStream8FileSizeEv:
  137|     38|size_t DefaultIOStream::FileSize() const {
  138|     38|    if (!mFile || mFilename.empty()) {
  ------------------
  |  Branch (138:9): [True: 0, False: 38]
  |  Branch (138:19): [True: 0, False: 38]
  ------------------
  139|      0|        return 0;
  140|      0|    }
  141|       |
  142|     38|    if (SIZE_MAX == mCachedSize) {
  ------------------
  |  Branch (142:9): [True: 38, False: 0]
  ------------------
  143|       |
  144|       |        // Although fseek/ftell would allow us to reuse the existing file handle here,
  145|       |        // it is generally unsafe because:
  146|       |        //  - For binary streams, it is not technically well-defined
  147|       |        //  - For text files the results are meaningless
  148|       |        // That's why we use the safer variant fstat here.
  149|       |        //
  150|       |        // See here for details:
  151|       |        // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
  152|       |#if defined _WIN32 && (!defined __GNUC__ || !defined __CLANG__ && __MSVCRT_VERSION__ >= 0x0601)
  153|       |        struct __stat64 fileStat;
  154|       |        //using fileno + fstat avoids having to handle the filename
  155|       |        int err = _fstat64(_fileno(mFile), &fileStat);
  156|       |        if (0 != err)
  157|       |            return 0;
  158|       |        mCachedSize = (size_t)(fileStat.st_size);
  159|       |#elif defined _WIN32
  160|       |        struct _stat fileStat;
  161|       |        //using fileno + fstat avoids having to handle the filename
  162|       |        int err = _fstat(_fileno(mFile), &fileStat);
  163|       |        if (0 != err)
  164|       |            return 0;
  165|       |        mCachedSize = (size_t)(fileStat.st_size);
  166|       |#elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__
  167|       |        struct stat fileStat;
  168|     38|        int err = stat(mFilename.c_str(), &fileStat);
  169|     38|        if (0 != err)
  ------------------
  |  Branch (169:13): [True: 0, False: 38]
  ------------------
  170|      0|            return 0;
  171|     38|        const unsigned long long cachedSize = fileStat.st_size;
  172|     38|        mCachedSize = static_cast<size_t>(cachedSize);
  173|       |#else
  174|       |#error "Unknown platform"
  175|       |#endif
  176|     38|    }
  177|     38|    return mCachedSize;
  178|     38|}

_ZNK6Assimp15DefaultIOSystem6ExistsEPKc:
   95|   330k|bool DefaultIOSystem::Exists(const char *pFile) const {
   96|   330k|    if (pFile == nullptr) {
  ------------------
  |  Branch (96:9): [True: 0, False: 330k]
  ------------------
   97|      0|        return false;
   98|      0|    }
   99|       |
  100|       |#ifdef _WIN32
  101|       |    struct __stat64 filestat;
  102|       |    if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) {
  103|       |        return false;
  104|       |    }
  105|       |#else
  106|   330k|	struct stat statbuf;
  107|   330k|    if (stat(pFile, &statbuf) != 0) {
  ------------------
  |  Branch (107:9): [True: 321k, False: 9.14k]
  ------------------
  108|   321k|        return false;
  109|   321k|    }
  110|       |    // test for a regular file
  111|  9.14k|    if (!S_ISREG(statbuf.st_mode)) {
  ------------------
  |  Branch (111:9): [True: 9.13k, False: 19]
  ------------------
  112|  9.13k|        return false;
  113|  9.13k|    }
  114|     19|#endif
  115|       |
  116|     19|    return true;
  117|  9.14k|}
_ZN6Assimp15DefaultIOSystem4OpenEPKcS2_:
  121|   201k|IOStream *DefaultIOSystem::Open(const char *strFile, const char *strMode) {
  122|   201k|    ai_assert(strFile != nullptr);
  123|   201k|    ai_assert(strMode != nullptr);
  124|   201k|    FILE *file;
  125|       |
  126|       |#ifdef _WIN32
  127|       |    std::wstring name = Utf8ToWide(strFile);
  128|       |    if (name.empty()) {
  129|       |        return nullptr;
  130|       |    }
  131|       |
  132|       |    file = ::_wfopen(name.c_str(), Utf8ToWide(strMode).c_str());
  133|       |#else
  134|   201k|    file = ::fopen(strFile, strMode);
  135|   201k|#endif
  136|       |
  137|   201k|    if (!file) {
  ------------------
  |  Branch (137:9): [True: 201k, False: 38]
  ------------------
  138|   201k|        return nullptr;
  139|   201k|    }
  140|       |
  141|     38|    return new DefaultIOStream(file, strFile);
  142|   201k|}
_ZNK6Assimp15DefaultIOSystem14getOsSeparatorEv:
  152|   103k|char DefaultIOSystem::getOsSeparator() const {
  153|   103k|#ifndef _WIN32
  154|   103k|    return '/';
  155|       |#else
  156|       |    return '\\';
  157|       |#endif
  158|   103k|}

_ZN6Assimp6Logger5debugEPKc:
  166|   104k|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|   104k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (171:9): [True: 0, False: 104k]
  ------------------
  172|      0|        return OnDebug("<fixme: long message discarded>");
  173|      0|    }
  174|   104k|    return OnDebug(message);
  175|   104k|}
_ZN6Assimp6Logger4infoEPKc:
  188|   763k|void Logger::info(const char *message) {
  189|       |
  190|       |    // SECURITY FIX: see above
  191|   763k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (191:9): [True: 0, False: 763k]
  ------------------
  192|      0|        return OnInfo("<fixme: long message discarded>");
  193|      0|    }
  194|   763k|    return OnInfo(message);
  195|   763k|}
_ZN6Assimp6Logger4warnEPKc:
  198|  3.11M|void Logger::warn(const char *message) {
  199|       |
  200|       |    // SECURITY FIX: see above
  201|  3.11M|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (201:9): [True: 6.38k, False: 3.10M]
  ------------------
  202|  6.38k|        return OnWarn("<fixme: long message discarded>");
  203|  6.38k|    }
  204|  3.10M|    return OnWarn(message);
  205|  3.11M|}
_ZN6Assimp6Logger5errorEPKc:
  208|   740k|void Logger::error(const char *message) {
  209|       |    // SECURITY FIX: see above
  210|   740k|    if (strlen(message) > MAX_LOG_MESSAGE_LENGTH) {
  ------------------
  |  Branch (210:9): [True: 465, False: 739k]
  ------------------
  211|    465|        return OnError("<fixme: long message discarded>");
  212|    465|    }
  213|   739k|    return OnError(message);
  214|   740k|}
_ZN6Assimp13DefaultLogger12isNullLoggerEv:
  232|   163k|bool DefaultLogger::isNullLogger() {
  233|   163k|    return m_pLogger == &s_pNullLogger;
  234|   163k|}
_ZN6Assimp13DefaultLogger3getEv:
  237|  4.72M|Logger *DefaultLogger::get() {
  238|  4.72M|    return m_pLogger;
  239|  4.72M|}

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

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

_ZN6Assimp16FileSystemFilterC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS_8IOSystemE:
   68|  12.0k|    : mWrapped  (old)
   69|  12.0k|    , mSrc_file(file)
   70|  12.0k|    , mSep(mWrapped->getOsSeparator()) {
   71|  12.0k|        ai_assert(nullptr != mWrapped);
   72|       |
   73|       |        // Determine base directory
   74|  12.0k|        mBase = mSrc_file;
   75|  12.0k|        std::string::size_type ss2;
   76|  12.0k|        if (std::string::npos != (ss2 = mBase.find_last_of("\\/")))  {
  ------------------
  |  Branch (76:13): [True: 0, False: 12.0k]
  ------------------
   77|      0|            mBase.erase(ss2,mBase.length()-ss2);
   78|  12.0k|        } else {
   79|  12.0k|            mBase = std::string();
   80|  12.0k|        }
   81|       |
   82|       |        // make sure the directory is terminated properly
   83|  12.0k|        char s;
   84|       |
   85|  12.0k|        if ( mBase.empty() ) {
  ------------------
  |  Branch (85:14): [True: 12.0k, False: 0]
  ------------------
   86|  12.0k|            mBase = ".";
   87|  12.0k|            mBase += getOsSeparator();
   88|  12.0k|        } 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|  12.0k|        DefaultLogger::get()->info("Import root directory is \'", mBase, "\'");
   93|  12.0k|    }
_ZNK6Assimp16FileSystemFilter9BuildPathERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  222|   134k|    void BuildPath (std::string& in) const {
  223|   134k|        ai_assert( nullptr != mWrapped );
  224|       |        // if we can already access the file, great.
  225|   134k|        if (in.length() < 3 || mWrapped->Exists(in)) {
  ------------------
  |  Branch (225:13): [True: 51.3k, False: 83.2k]
  |  Branch (225:32): [True: 5, False: 83.2k]
  ------------------
  226|  51.3k|            return;
  227|  51.3k|        }
  228|       |
  229|       |        // Determine whether this is a relative path (Windows-specific - most assets are packaged on Windows).
  230|  83.2k|        if (in[1] != ':') {
  ------------------
  |  Branch (230:13): [True: 82.6k, False: 633]
  ------------------
  231|       |
  232|       |            // append base path and try
  233|  82.6k|            const std::string tmp = mBase + in;
  234|  82.6k|            if (mWrapped->Exists(tmp)) {
  ------------------
  |  Branch (234:17): [True: 0, False: 82.6k]
  ------------------
  235|      0|                in = tmp;
  236|      0|                return;
  237|      0|            }
  238|  82.6k|        }
  239|       |
  240|       |        // Chop of the file name and look in the model directory, if
  241|       |        // this fails try all sub paths of the given path, i.e.
  242|       |        // if the given path is foo/bar/something.lwo, try
  243|       |        // <base>/something.lwo
  244|       |        // <base>/bar/something.lwo
  245|       |        // <base>/foo/bar/something.lwo
  246|  83.2k|        std::string::size_type pos = in.rfind('/');
  247|  83.2k|        if (std::string::npos == pos) {
  ------------------
  |  Branch (247:13): [True: 69.2k, False: 14.0k]
  ------------------
  248|  69.2k|            pos = in.rfind('\\');
  249|  69.2k|        }
  250|       |
  251|  83.2k|        if (std::string::npos != pos)   {
  ------------------
  |  Branch (251:13): [True: 16.2k, False: 66.9k]
  ------------------
  252|  16.2k|            std::string tmp;
  253|  16.2k|            std::string::size_type last_dirsep = std::string::npos;
  254|       |
  255|   181k|            while(true) {
  ------------------
  |  Branch (255:19): [True: 181k, Folded]
  ------------------
  256|   181k|                tmp = mBase;
  257|   181k|                tmp += mSep;
  258|       |
  259|   181k|                std::string::size_type dirsep = in.rfind('/', last_dirsep);
  260|   181k|                if (std::string::npos == dirsep) {
  ------------------
  |  Branch (260:21): [True: 41.0k, False: 140k]
  ------------------
  261|  41.0k|                    dirsep = in.rfind('\\', last_dirsep);
  262|  41.0k|                }
  263|       |
  264|   181k|                if (std::string::npos == dirsep || dirsep == 0) {
  ------------------
  |  Branch (264:21): [True: 13.2k, False: 167k]
  |  Branch (264:52): [True: 3.01k, False: 164k]
  ------------------
  265|       |                    // we did try this already.
  266|  16.2k|                    break;
  267|  16.2k|                }
  268|       |
  269|   164k|                last_dirsep = dirsep-1;
  270|       |
  271|   164k|                tmp += in.substr(dirsep+1, in.length()-pos);
  272|   164k|                if (mWrapped->Exists(tmp)) {
  ------------------
  |  Branch (272:21): [True: 14, False: 164k]
  ------------------
  273|     14|                    in = tmp;
  274|     14|                    return;
  275|     14|                }
  276|   164k|            }
  277|  16.2k|        }
  278|       |
  279|       |        // hopefully the underlying file system has another few tricks to access this file ...
  280|  83.2k|    }
_ZNK6Assimp16FileSystemFilter7CleanupERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
  285|  67.3k|    void Cleanup (std::string& in) const {
  286|  67.3k|        if(in.empty()) {
  ------------------
  |  Branch (286:12): [True: 0, False: 67.3k]
  ------------------
  287|      0|            return;
  288|      0|        }
  289|       |
  290|       |        // Remove a very common issue when we're parsing file names: spaces at the
  291|       |        // beginning of the path.
  292|  67.3k|        char last = 0;
  293|  67.3k|        std::string::iterator it = in.begin();
  294|  67.3k|        while (IsSpaceOrNewLine( *it ))++it;
  ------------------
  |  Branch (294:16): [True: 0, False: 67.3k]
  ------------------
  295|  67.3k|        if (it != in.begin()) {
  ------------------
  |  Branch (295:13): [True: 0, False: 67.3k]
  ------------------
  296|      0|            in.erase(in.begin(),it+1);
  297|      0|        }
  298|       |
  299|  67.3k|        const char separator = getOsSeparator();
  300|  16.9M|        for (it = in.begin(); it < in.end(); ++it) {
  ------------------
  |  Branch (300:31): [True: 16.9M, False: 67.3k]
  ------------------
  301|  16.9M|            const size_t remaining = std::distance(in.end(), it);
  302|       |            // Exclude :// and \\, which remain untouched.
  303|       |            // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
  304|  16.9M|            if (remaining >= 3u && !strncmp(&*it, "://", 3 )) {
  ------------------
  |  Branch (304:17): [True: 16.9M, False: 0]
  |  Branch (304:36): [True: 617, False: 16.9M]
  ------------------
  305|    617|                it += 3;
  306|    617|                continue;
  307|    617|            }
  308|  16.9M|            if (it == in.begin() && remaining >= 2 && !strncmp(&*it, "\\\\", 2)) {
  ------------------
  |  Branch (308:17): [True: 67.3k, False: 16.8M]
  |  Branch (308:17): [True: 778, False: 16.9M]
  |  Branch (308:37): [True: 67.3k, False: 0]
  |  Branch (308:55): [True: 778, False: 66.5k]
  ------------------
  309|    778|                it += 2;
  310|    778|                continue;
  311|    778|            }
  312|       |
  313|       |            // Cleanup path delimiters
  314|  16.9M|            if (*it == '/' || (*it) == '\\') {
  ------------------
  |  Branch (314:17): [True: 70.8k, False: 16.8M]
  |  Branch (314:31): [True: 24.8k, False: 16.8M]
  ------------------
  315|  95.7k|                *it = separator;
  316|       |
  317|       |                // And we're removing double delimiters, frequent issue with
  318|       |                // incorrectly composited paths ...
  319|  95.7k|                if (last == *it) {
  ------------------
  |  Branch (319:21): [True: 30.7k, False: 65.0k]
  ------------------
  320|  30.7k|                    it = in.erase(it);
  321|  30.7k|                    --it;
  322|  30.7k|                }
  323|  16.8M|            } else if (*it == '%' && in.end() - it > 2) {
  ------------------
  |  Branch (323:24): [True: 12.5k, False: 16.7M]
  |  Branch (323:24): [True: 12.0k, False: 16.7M]
  |  Branch (323:38): [True: 12.0k, False: 468]
  ------------------
  324|       |                // Hex sequence in URIs
  325|  12.0k|                if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
  ------------------
  |  Branch (325:21): [True: 0, False: 12.0k]
  |  Branch (325:41): [True: 0, False: 0]
  ------------------
  326|      0|                    *it = HexOctetToDecimal(&*it);
  327|      0|                    it = in.erase(it+1,it+2);
  328|      0|                    --it;
  329|      0|                }
  330|  12.0k|            }
  331|       |
  332|  16.9M|            last = *it;
  333|  16.9M|        }
  334|  67.3k|    }
_ZN6Assimp5IsHexEc:
   56|  12.0k|inline bool IsHex(char s) {
   57|  12.0k|    return (s>='0' && s<='9') || (s>='a' && s<='f') || (s>='A' && s<='F');
  ------------------
  |  Branch (57:13): [True: 0, False: 12.0k]
  |  Branch (57:23): [True: 0, False: 0]
  |  Branch (57:35): [True: 0, False: 12.0k]
  |  Branch (57:45): [True: 0, False: 0]
  |  Branch (57:57): [True: 0, False: 12.0k]
  |  Branch (57:67): [True: 0, False: 0]
  ------------------
   58|  12.0k|}
_ZNK6Assimp16FileSystemFilter14getOsSeparatorEv:
  116|  79.3k|    char getOsSeparator() const {
  117|  79.3k|        return mSep;
  118|  79.3k|    }
_ZN6Assimp16FileSystemFilter4OpenEPKcS2_:
  122|   147k|    IOStream* Open( const char* pFile, const char* pMode = "rb") {
  123|   147k|        ai_assert( nullptr != mWrapped );
  124|   147k|        if ( nullptr == pFile || nullptr == pMode ) {
  ------------------
  |  Branch (124:14): [True: 0, False: 147k]
  |  Branch (124:34): [True: 0, False: 147k]
  ------------------
  125|      0|            return nullptr;
  126|      0|        }
  127|       |
  128|   147k|        ai_assert( nullptr != pFile );
  129|   147k|        ai_assert( nullptr != pMode );
  130|       |
  131|       |        // First try the unchanged path
  132|   147k|        IOStream* s = mWrapped->Open(pFile,pMode);
  133|       |
  134|   147k|        if (nullptr == s) {
  ------------------
  |  Branch (134:13): [True: 67.3k, False: 79.7k]
  ------------------
  135|  67.3k|            std::string tmp = pFile;
  136|       |
  137|       |            // Try to convert between absolute and relative paths
  138|  67.3k|            BuildPath(tmp);
  139|  67.3k|            s = mWrapped->Open(tmp,pMode);
  140|       |
  141|  67.3k|            if (nullptr == s) {
  ------------------
  |  Branch (141:17): [True: 67.3k, False: 14]
  ------------------
  142|       |                // Finally, look for typical issues with paths
  143|       |                // and try to correct them. This is our last
  144|       |                // resort.
  145|  67.3k|                tmp = pFile;
  146|  67.3k|                Cleanup(tmp);
  147|  67.3k|                BuildPath(tmp);
  148|  67.3k|                s = mWrapped->Open(tmp,pMode);
  149|  67.3k|            }
  150|  67.3k|        }
  151|       |
  152|   147k|        return s;
  153|   147k|    }
_ZN6Assimp16FileSystemFilter5CloseEPNS_8IOStreamE:
  157|  12.0k|    void Close( IOStream* pFile) {
  158|       |        ai_assert( nullptr != mWrapped );
  159|  12.0k|        return mWrapped->Close(pFile);
  160|  12.0k|    }
_ZNK6Assimp16FileSystemFilter9StackSizeEv:
  185|  78.2k|    size_t StackSize() const {
  186|       |        ai_assert( nullptr != mWrapped );
  187|  78.2k|        return mWrapped->StackSize();
  188|  78.2k|    }
_ZN6Assimp16FileSystemFilterD2Ev:
   96|  12.0k|    ~FileSystemFilter() = default;

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

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

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

_ZNK6Assimp5MaybeIfEcvbEv:
   63|  86.8k|    operator bool() const {
   64|  86.8k|        return _valid;
   65|  86.8k|    }
_ZNK6Assimp5MaybeIfE3GetEv:
   79|    408|    const T &Get() const {
   80|    408|        ai_assert(_valid);
  ------------------
  |  |   67|    408|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 408, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   81|    408|        return _val;
   82|    408|    }
_ZNK6Assimp5MaybeI9aiColor3DEcvbEv:
   63|  21.7k|    operator bool() const {
   64|  21.7k|        return _valid;
   65|  21.7k|    }
_ZNK6Assimp5MaybeI9aiColor3DE3GetEv:
   79|    415|    const T &Get() const {
   80|    415|        ai_assert(_valid);
  ------------------
  |  |   67|    415|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 415, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   81|    415|        return _val;
   82|    415|    }
_ZN6Assimp5MaybeIfEC2Ev:
   53|   505k|    Maybe() = default;
_ZN6Assimp5MaybeI9aiColor3DEC2Ev:
   53|  37.0k|    Maybe() = default;
_ZN6Assimp5MaybeI9aiColor3DEaSERKS2_:
   86|  9.70k|    Maybe &operator=(const Maybe &) = default;
_ZN6Assimp5MaybeI9aiColor3DEC2IRS1_EEOT_:
   59|  9.70k|            _val(std::forward<U>(val)), _valid(true) {}
_ZN6Assimp5MaybeIfEC2IfEEOT_:
   59|  39.5k|            _val(std::forward<U>(val)), _valid(true) {}

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

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

_ZN6Assimp17ScenePreprocessor12ProcessSceneEv:
   50|  3.36k|void ScenePreprocessor::ProcessScene() {
   51|  3.36k|    ai_assert(scene != nullptr);
  ------------------
  |  |   67|  3.36k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 3.36k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   52|       |
   53|       |    // Process all meshes
   54|  79.1k|    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (54:30): [True: 75.8k, False: 3.36k]
  ------------------
   55|  75.8k|        if (nullptr == scene->mMeshes[i]) {
  ------------------
  |  Branch (55:13): [True: 0, False: 75.8k]
  ------------------
   56|      0|            continue;
   57|      0|        }
   58|  75.8k|        ProcessMesh(scene->mMeshes[i]);
   59|  75.8k|    }
   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|  3.36k|    for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
  ------------------
  |  Branch (67:30): [True: 0, False: 3.36k]
  ------------------
   68|      0|        if (nullptr == scene->mAnimations[i]) {
  ------------------
  |  Branch (68:13): [True: 0, False: 0]
  ------------------
   69|      0|            continue;
   70|      0|        }
   71|      0|        ProcessAnimation(scene->mAnimations[i]);
   72|      0|    }
   73|       |
   74|       |    // Generate a default material if none was specified
   75|  3.36k|    if (!scene->mNumMaterials && scene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 0, False: 3.36k]
  |  Branch (75:34): [True: 0, False: 0]
  ------------------
   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|  3.36k|}
_ZN6Assimp17ScenePreprocessor11ProcessMeshEP6aiMesh:
  103|  75.8k|void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
  104|       |    // If aiMesh::mNumUVComponents is *not* set assign the default value of 2
  105|   682k|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (105:30): [True: 606k, False: 75.8k]
  ------------------
  106|   606k|        if (!mesh->mTextureCoords[i]) {
  ------------------
  |  Branch (106:13): [True: 598k, False: 7.46k]
  ------------------
  107|   598k|            mesh->mNumUVComponents[i] = 0;
  108|   598k|            continue;
  109|   598k|        }
  110|       |
  111|  7.46k|        if (!mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (111:13): [True: 0, False: 7.46k]
  ------------------
  112|      0|            mesh->mNumUVComponents[i] = 2;
  113|      0|        }
  114|       |
  115|  7.46k|        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|  7.46k|        if (2 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (120:13): [True: 411, False: 7.05k]
  ------------------
  121|   148k|            for (; p != end; ++p) {
  ------------------
  |  Branch (121:20): [True: 148k, False: 411]
  ------------------
  122|   148k|                p->z = 0.f;
  123|   148k|            }
  124|  7.05k|        } else if (1 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (124:20): [True: 0, False: 7.05k]
  ------------------
  125|      0|            for (; p != end; ++p) {
  ------------------
  |  Branch (125:20): [True: 0, False: 0]
  ------------------
  126|      0|                p->z = p->y = 0.f;
  127|      0|            }
  128|  7.05k|        } else if (3 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (128:20): [True: 7.05k, False: 0]
  ------------------
  129|       |            // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
  130|   108k|            for (; p != end; ++p) {
  ------------------
  |  Branch (130:20): [True: 107k, False: 1.21k]
  ------------------
  131|   107k|                if (p->z != 0) {
  ------------------
  |  Branch (131:21): [True: 5.83k, False: 101k]
  ------------------
  132|  5.83k|                    break;
  133|  5.83k|                }
  134|   107k|            }
  135|  7.05k|            if (p == end) {
  ------------------
  |  Branch (135:17): [True: 1.21k, False: 5.83k]
  ------------------
  136|  1.21k|                ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
  137|  1.21k|                mesh->mNumUVComponents[i] = 2;
  138|  1.21k|            }
  139|  7.05k|        }
  140|  7.46k|    }
  141|       |
  142|       |    // If the information which primitive types are there in the
  143|       |    // mesh is currently not available, compute it.
  144|  75.8k|    if (!mesh->mPrimitiveTypes) {
  ------------------
  |  Branch (144:9): [True: 0, False: 75.8k]
  ------------------
  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|  75.8k|    if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
  ------------------
  |  Branch (169:9): [True: 0, False: 75.8k]
  |  Branch (169:28): [True: 0, False: 0]
  |  Branch (169:46): [True: 0, False: 0]
  ------------------
  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|  75.8k|}

_ZN6Assimp17ScenePreprocessorC2EP7aiScene:
   79|  3.36k|            scene(_scene) {}

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

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

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

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

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

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

_ZN7aiSceneC2Ev:
   46|  12.0k|        mFlags(0),
   47|  12.0k|        mRootNode(nullptr),
   48|  12.0k|        mNumMeshes(0),
   49|  12.0k|        mMeshes(nullptr),
   50|  12.0k|        mNumMaterials(0),
   51|  12.0k|        mMaterials(nullptr),
   52|  12.0k|        mNumAnimations(0),
   53|  12.0k|        mAnimations(nullptr),
   54|  12.0k|        mNumTextures(0),
   55|  12.0k|        mTextures(nullptr),
   56|  12.0k|        mNumLights(0),
   57|  12.0k|        mLights(nullptr),
   58|  12.0k|        mNumCameras(0),
   59|  12.0k|        mCameras(nullptr),
   60|  12.0k|        mMetaData(nullptr),
   61|  12.0k|        mName(),
   62|  12.0k|        mNumSkeletons(0),
   63|  12.0k|        mSkeletons(nullptr),
   64|  12.0k|        mPrivate(new Assimp::ScenePrivateData()) {
   65|       |    // empty
   66|  12.0k|}
_ZN7aiSceneD2Ev:
   68|  12.0k|aiScene::~aiScene() {
   69|       |    // delete all sub-objects recursively
   70|  12.0k|    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|  12.0k|    if (mNumMeshes && mMeshes) {
  ------------------
  |  Branch (75:9): [True: 3.84k, False: 8.20k]
  |  Branch (75:23): [True: 3.82k, False: 20]
  ------------------
   76|   107k|        for (unsigned int a = 0; a < mNumMeshes; ++a) {
  ------------------
  |  Branch (76:34): [True: 104k, False: 3.82k]
  ------------------
   77|   104k|            delete mMeshes[a];
   78|   104k|        }
   79|  3.82k|    }
   80|  12.0k|    delete[] mMeshes;
   81|       |
   82|  12.0k|    if (mNumMaterials && mMaterials) {
  ------------------
  |  Branch (82:9): [True: 4.87k, False: 7.17k]
  |  Branch (82:26): [True: 4.87k, False: 0]
  ------------------
   83|  15.1k|        for (unsigned int a = 0; a < mNumMaterials; ++a) {
  ------------------
  |  Branch (83:34): [True: 10.3k, False: 4.87k]
  ------------------
   84|  10.3k|            delete mMaterials[a];
   85|  10.3k|        }
   86|  4.87k|    }
   87|  12.0k|    delete[] mMaterials;
   88|       |
   89|  12.0k|    if (mNumAnimations && mAnimations) {
  ------------------
  |  Branch (89:9): [True: 0, False: 12.0k]
  |  Branch (89:27): [True: 0, False: 0]
  ------------------
   90|      0|        for (unsigned int a = 0; a < mNumAnimations; ++a) {
  ------------------
  |  Branch (90:34): [True: 0, False: 0]
  ------------------
   91|      0|            delete mAnimations[a];
   92|      0|        }
   93|      0|    }
   94|  12.0k|    delete[] mAnimations;
   95|       |
   96|  12.0k|    if (mNumTextures && mTextures) {
  ------------------
  |  Branch (96:9): [True: 0, False: 12.0k]
  |  Branch (96:25): [True: 0, False: 0]
  ------------------
   97|      0|        for (unsigned int a = 0; a < mNumTextures; ++a) {
  ------------------
  |  Branch (97:34): [True: 0, False: 0]
  ------------------
   98|      0|            delete mTextures[a];
   99|      0|        }
  100|      0|    }
  101|  12.0k|    delete[] mTextures;
  102|       |
  103|  12.0k|    if (mNumLights && mLights) {
  ------------------
  |  Branch (103:9): [True: 0, False: 12.0k]
  |  Branch (103:23): [True: 0, False: 0]
  ------------------
  104|      0|        for (unsigned int a = 0; a < mNumLights; ++a) {
  ------------------
  |  Branch (104:34): [True: 0, False: 0]
  ------------------
  105|      0|            delete mLights[a];
  106|      0|        }
  107|      0|    }
  108|  12.0k|    delete[] mLights;
  109|       |
  110|  12.0k|    if (mNumCameras && mCameras) {
  ------------------
  |  Branch (110:9): [True: 0, False: 12.0k]
  |  Branch (110:24): [True: 0, False: 0]
  ------------------
  111|      0|        for (unsigned int a = 0; a < mNumCameras; ++a) {
  ------------------
  |  Branch (111:34): [True: 0, False: 0]
  ------------------
  112|      0|            delete mCameras[a];
  113|      0|        }
  114|      0|    }
  115|  12.0k|    delete[] mCameras;
  116|       |
  117|  12.0k|    aiMetadata::Dealloc(mMetaData);
  118|       |
  119|  12.0k|    delete[] mSkeletons;
  120|       |
  121|  12.0k|    delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
  122|  12.0k|}
_ZN6aiNodeC2Ev:
  125|   187k|        mName(""),
  126|   187k|        mParent(nullptr),
  127|   187k|        mNumChildren(0),
  128|   187k|        mChildren(nullptr),
  129|   187k|        mNumMeshes(0),
  130|   187k|        mMeshes(nullptr),
  131|   187k|        mMetaData(nullptr) {
  132|       |    // empty
  133|   187k|}
_ZN6aiNodeD2Ev:
  147|   187k|aiNode::~aiNode() {
  148|       |    // delete all children recursively
  149|       |    // to make sure we won't crash if the data is invalid ...
  150|   187k|    if (mNumChildren && mChildren) {
  ------------------
  |  Branch (150:9): [True: 5.47k, False: 181k]
  |  Branch (150:25): [True: 5.47k, False: 0]
  ------------------
  151|   181k|        for (unsigned int a = 0; a < mNumChildren; a++)
  ------------------
  |  Branch (151:34): [True: 175k, False: 5.47k]
  ------------------
  152|   175k|            delete mChildren[a];
  153|  5.47k|    }
  154|   187k|    delete[] mChildren;
  155|   187k|    delete[] mMeshes;
  156|   187k|    delete mMetaData;
  157|   187k|}

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

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

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

_ZN6Assimp16ArmaturePopulateC2Ev:
   71|  12.0k|    ArmaturePopulate() = default;

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

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

_ZN6Assimp23ComputeUVMappingProcessC2Ev:
   63|  12.0k|    ComputeUVMappingProcess() = default;

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

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

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

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

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

_ZN6Assimp22DropFaceNormalsProcessC2Ev:
   57|  12.0k|    DropFaceNormalsProcess() = default;

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

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

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

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

_ZN6Assimp22FindInvalidDataProcessC2Ev:
   59|  12.0k|        configEpsilon(0.0), mIgnoreTexCoods(false) {
   60|       |    // nothing to do here
   61|  12.0k|}
_ZNK6Assimp22FindInvalidDataProcess8IsActiveEj:
   65|  3.21k|bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {
   66|  3.21k|    return 0 != (pFlags & aiProcess_FindInvalidData);
   67|  3.21k|}
_ZN6Assimp22FindInvalidDataProcess15SetupPropertiesEPKNS_8ImporterE:
   71|  3.21k|void FindInvalidDataProcess::SetupProperties(const Importer *pImp) {
   72|       |    // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
   73|  3.21k|    configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY, 0.f));
   74|       |    mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false);
   75|  3.21k|}
_Z20UpdateMeshReferencesP6aiNodeRKNSt3__16vectorIjNS1_9allocatorIjEEEE:
   79|  11.1k|void UpdateMeshReferences(aiNode *node, const std::vector<unsigned int> &meshMapping) {
   80|  11.1k|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 8.63k, False: 2.51k]
  ------------------
   81|  8.63k|        unsigned int out = 0;
   82|  41.2k|        for (unsigned int a = 0; a < node->mNumMeshes; ++a) {
  ------------------
  |  Branch (82:34): [True: 32.5k, False: 8.63k]
  ------------------
   83|       |
   84|  32.5k|            unsigned int ref = node->mMeshes[a];
   85|  32.5k|            if (ref >= meshMapping.size())
  ------------------
  |  Branch (85:17): [True: 0, False: 32.5k]
  ------------------
   86|      0|                throw DeadlyImportError("Invalid mesh ref");
   87|       |
   88|  32.5k|            if (UINT_MAX != (ref = meshMapping[ref])) {
  ------------------
  |  Branch (88:17): [True: 26.6k, False: 5.97k]
  ------------------
   89|  26.6k|                node->mMeshes[out++] = ref;
   90|  26.6k|            }
   91|  32.5k|        }
   92|       |        // just let the members that are unused, that's much cheaper
   93|       |        // than a full array realloc'n'copy party ...
   94|  8.63k|        node->mNumMeshes = out;
   95|  8.63k|        if (0 == out) {
  ------------------
  |  Branch (95:13): [True: 823, False: 7.81k]
  ------------------
   96|    823|            delete[] node->mMeshes;
   97|    823|            node->mMeshes = nullptr;
   98|    823|        }
   99|  8.63k|    }
  100|       |    // recursively update all children
  101|  22.1k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 10.9k, False: 11.1k]
  ------------------
  102|  10.9k|        UpdateMeshReferences(node->mChildren[i], meshMapping);
  103|  10.9k|    }
  104|  11.1k|}
_ZN6Assimp22FindInvalidDataProcess7ExecuteEP7aiScene:
  108|  3.21k|void FindInvalidDataProcess::Execute(aiScene *pScene) {
  109|  3.21k|    ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin");
  110|       |
  111|  3.21k|    bool out = false;
  112|  3.21k|    std::vector<unsigned int> meshMapping(pScene->mNumMeshes);
  113|  3.21k|    unsigned int real = 0;
  114|       |
  115|       |    // Process meshes
  116|  98.6k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (116:30): [True: 95.4k, False: 3.21k]
  ------------------
  117|  95.4k|        int result = ProcessMesh(pScene->mMeshes[a]);
  118|  95.4k|        if (0 == result) {
  ------------------
  |  Branch (118:13): [True: 78.4k, False: 17.0k]
  ------------------
  119|  78.4k|            out = true;
  120|  78.4k|        }
  121|  95.4k|        if (2 == result) {
  ------------------
  |  Branch (121:13): [True: 6.70k, False: 88.7k]
  ------------------
  122|       |            // remove this mesh
  123|  6.70k|            delete pScene->mMeshes[a];
  124|  6.70k|            pScene->mMeshes[a] = nullptr;
  125|       |
  126|  6.70k|            meshMapping[a] = UINT_MAX;
  127|  6.70k|            out = true;
  128|  6.70k|            continue;
  129|  6.70k|        }
  130|       |
  131|  88.7k|        pScene->mMeshes[real] = pScene->mMeshes[a];
  132|  88.7k|        meshMapping[a] = real++;
  133|  88.7k|    }
  134|       |
  135|       |    // Process animations
  136|  3.21k|    for (unsigned int animIdx = 0; animIdx < pScene->mNumAnimations; ++animIdx) {
  ------------------
  |  Branch (136:36): [True: 0, False: 3.21k]
  ------------------
  137|      0|        ProcessAnimation(pScene->mAnimations[animIdx]);
  138|      0|    }
  139|       |
  140|  3.21k|    if (out) {
  ------------------
  |  Branch (140:9): [True: 3.13k, False: 80]
  ------------------
  141|  3.13k|        if (real != pScene->mNumMeshes) {
  ------------------
  |  Branch (141:13): [True: 265, False: 2.86k]
  ------------------
  142|    265|            if (!real) {
  ------------------
  |  Branch (142:17): [True: 87, False: 178]
  ------------------
  143|     87|                throw DeadlyImportError("No meshes remaining");
  144|     87|            }
  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|    178|            try {
  150|    178|                UpdateMeshReferences(pScene->mRootNode, meshMapping);
  151|    178|            } 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|    178|            pScene->mNumMeshes = real;
  157|    178|        }
  158|       |
  159|  3.13k|        ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ...");
  160|  3.04k|    } else {
  161|       |        ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK.");
  162|     80|    }
  163|  3.21k|}
_ZN6Assimp22FindInvalidDataProcess11ProcessMeshEP6aiMesh:
  323|  95.4k|int FindInvalidDataProcess::ProcessMesh(aiMesh *pMesh) {
  324|  95.4k|    bool ret = false;
  325|  95.4k|    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|  1.95M|    for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
  ------------------
  |  Branch (329:30): [True: 1.85M, False: 95.4k]
  ------------------
  330|  1.85M|        const aiFace &f = pMesh->mFaces[m];
  331|       |
  332|  7.06M|        for (unsigned int i = 0; i < f.mNumIndices; ++i) {
  ------------------
  |  Branch (332:34): [True: 5.21M, False: 1.85M]
  ------------------
  333|  5.21M|            dirtyMask[f.mIndices[i]] = false;
  334|  5.21M|        }
  335|  1.85M|    }
  336|       |
  337|       |    // Process vertex positions
  338|  95.4k|    if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) {
  ------------------
  |  Branch (338:9): [True: 95.4k, False: 0]
  |  Branch (338:29): [True: 6.70k, False: 88.7k]
  ------------------
  339|  6.70k|        ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions");
  340|       |
  341|  6.70k|        return 2;
  342|  6.70k|    }
  343|       |
  344|       |    // process texture coordinates
  345|  88.7k|    if (!mIgnoreTexCoods) {
  ------------------
  |  Branch (345:9): [True: 88.7k, False: 0]
  ------------------
  346|   100k|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) {
  ------------------
  |  Branch (346:34): [True: 100k, False: 0]
  |  Branch (346:72): [True: 11.2k, False: 88.7k]
  ------------------
  347|  11.2k|            if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) {
  ------------------
  |  Branch (347:17): [True: 5.44k, False: 5.83k]
  ------------------
  348|  5.44k|                pMesh->mNumUVComponents[i] = 0;
  349|       |
  350|       |                // delete all subsequent texture coordinate sets.
  351|  43.5k|                for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
  ------------------
  |  Branch (351:46): [True: 38.1k, False: 5.44k]
  ------------------
  352|  38.1k|                    delete[] pMesh->mTextureCoords[a];
  353|  38.1k|                    pMesh->mTextureCoords[a] = nullptr;
  354|  38.1k|                    pMesh->mNumUVComponents[a] = 0;
  355|  38.1k|                }
  356|       |
  357|  5.44k|                ret = true;
  358|  5.44k|            }
  359|  11.2k|        }
  360|  88.7k|    }
  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|  88.7k|    if (pMesh->mNormals || pMesh->mTangents) {
  ------------------
  |  Branch (366:9): [True: 13.7k, False: 74.9k]
  |  Branch (366:28): [True: 0, False: 74.9k]
  ------------------
  367|       |
  368|  13.7k|        if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (368:13): [True: 546, False: 13.2k]
  ------------------
  369|  13.2k|                aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (369:17): [True: 2.41k, False: 10.8k]
  ------------------
  370|  2.95k|            if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (370:17): [True: 0, False: 2.95k]
  ------------------
  371|  2.95k|                    aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (371:21): [True: 0, False: 2.95k]
  ------------------
  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|  2.95k|            else {
  387|  2.95k|                return ret;
  388|  2.95k|            }
  389|  2.95k|        }
  390|       |
  391|       |        // Process mesh normals
  392|  10.8k|        if (pMesh->mNormals && ProcessArray(pMesh->mNormals, pMesh->mNumVertices,
  ------------------
  |  Branch (392:13): [True: 10.8k, False: 0]
  |  Branch (392:32): [True: 4.94k, False: 5.90k]
  ------------------
  393|  10.8k|                                       "normals", dirtyMask, true, false))
  394|  4.94k|            ret = true;
  395|       |
  396|       |        // Process mesh tangents
  397|  10.8k|        if (pMesh->mTangents && ProcessArray(pMesh->mTangents, pMesh->mNumVertices, "tangents", dirtyMask)) {
  ------------------
  |  Branch (397:13): [True: 0, False: 10.8k]
  |  Branch (397:33): [True: 0, False: 0]
  ------------------
  398|      0|            delete[] pMesh->mBitangents;
  399|      0|            pMesh->mBitangents = nullptr;
  400|      0|            ret = true;
  401|      0|        }
  402|       |
  403|       |        // Process mesh bitangents
  404|  10.8k|        if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents, pMesh->mNumVertices, "bitangents", dirtyMask)) {
  ------------------
  |  Branch (404:13): [True: 0, False: 10.8k]
  |  Branch (404:35): [True: 0, False: 0]
  ------------------
  405|      0|            delete[] pMesh->mTangents;
  406|      0|            pMesh->mTangents = nullptr;
  407|      0|            ret = true;
  408|      0|        }
  409|  10.8k|    }
  410|  85.7k|    return ret ? 1 : 0;
  ------------------
  |  Branch (410:12): [True: 9.82k, False: 75.9k]
  ------------------
  411|  88.7k|}
_Z12ProcessArrayI10aiVector3tIfEEbRPT_jPKcRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  203|   117k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) {
  204|   117k|    const char *err = ValidateArrayContents(in, num, dirtyMask, mayBeIdentical, mayBeZero);
  205|   117k|    if (err) {
  ------------------
  |  Branch (205:9): [True: 17.0k, False: 100k]
  ------------------
  206|  17.0k|        ASSIMP_LOG_ERROR("FindInvalidDataProcess fails on mesh ", name, ": ", err);
  207|  17.0k|        delete[] in;
  208|  17.0k|        in = nullptr;
  209|  17.0k|        return true;
  210|  17.0k|    }
  211|   100k|    return false;
  212|   117k|}
_Z21ValidateArrayContentsI10aiVector3tIfEEPKcPKT_jRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  175|   117k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical, bool mayBeZero) {
  176|   117k|    bool b = false;
  177|   117k|    unsigned int cnt = 0;
  178|  6.40M|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (178:30): [True: 6.29M, False: 109k]
  ------------------
  179|       |
  180|  6.29M|        if (dirtyMask.size() && dirtyMask[i]) {
  ------------------
  |  Branch (180:13): [True: 6.29M, False: 0]
  |  Branch (180:13): [True: 853k, False: 5.43M]
  |  Branch (180:33): [True: 853k, False: 5.43M]
  ------------------
  181|   853k|            continue;
  182|   853k|        }
  183|  5.43M|        ++cnt;
  184|       |
  185|  5.43M|        const aiVector3D &v = arr[i];
  186|  5.43M|        if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
  ------------------
  |  Branch (186:13): [True: 1.91k, False: 5.43M]
  |  Branch (186:38): [True: 486, False: 5.43M]
  |  Branch (186:63): [True: 587, False: 5.43M]
  ------------------
  187|  2.98k|            return "INF/NAN was found in a vector component";
  188|  2.98k|        }
  189|  5.43M|        if (!mayBeZero && !v.x && !v.y && !v.z) {
  ------------------
  |  Branch (189:13): [True: 325k, False: 5.11M]
  |  Branch (189:27): [True: 41.5k, False: 283k]
  |  Branch (189:35): [True: 36.5k, False: 5.06k]
  |  Branch (189:43): [True: 4.94k, False: 31.5k]
  ------------------
  190|  4.94k|            return "Found zero-length vector";
  191|  4.94k|        }
  192|  5.43M|        if (i && v != arr[i - 1]) b = true;
  ------------------
  |  Branch (192:13): [True: 5.32M, False: 109k]
  |  Branch (192:18): [True: 4.06M, False: 1.25M]
  ------------------
  193|  5.43M|    }
  194|   109k|    if (cnt > 1 && !b && !mayBeIdentical) {
  ------------------
  |  Branch (194:9): [True: 101k, False: 7.91k]
  |  Branch (194:20): [True: 14.0k, False: 87.6k]
  |  Branch (194:26): [True: 9.16k, False: 4.85k]
  ------------------
  195|  9.16k|        return "All vectors are identical";
  196|  9.16k|    }
  197|   100k|    return nullptr;
  198|   109k|}

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

_ZN6Assimp25FixInfacingNormalsProcessC2Ev:
   62|  12.0k|    FixInfacingNormalsProcess() = default;

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

_ZN6Assimp23GenBoundingBoxesProcessC2Ev:
   65|  12.0k|    GenBoundingBoxesProcess() = default;

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

_ZN6Assimp21GenFaceNormalsProcessC2Ev:
   59|  12.0k|    GenFaceNormalsProcess() = default;

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

_ZN6Assimp27ImproveCacheLocalityProcessC2Ev:
   65|  12.0k|        mConfigCacheDepth(PP_ICL_PTCACHE_SIZE) {
   66|       |    // empty
   67|  12.0k|}
_ZNK6Assimp27ImproveCacheLocalityProcess8IsActiveEj:
   71|  3.12k|bool ImproveCacheLocalityProcess::IsActive(unsigned int pFlags) const {
   72|  3.12k|    return (pFlags & aiProcess_ImproveCacheLocality) != 0;
   73|  3.12k|}
_ZN6Assimp27ImproveCacheLocalityProcess15SetupPropertiesEPKNS_8ImporterE:
   77|  3.12k|void ImproveCacheLocalityProcess::SetupProperties(const Importer *pImp) {
   78|       |    // AI_CONFIG_PP_ICL_PTCACHE_SIZE controls the target cache size for the optimizer
   79|  3.12k|    mConfigCacheDepth = pImp->GetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE, PP_ICL_PTCACHE_SIZE);
   80|  3.12k|}
_ZN6Assimp27ImproveCacheLocalityProcess7ExecuteEP7aiScene:
   84|  3.12k|void ImproveCacheLocalityProcess::Execute(aiScene *pScene) {
   85|  3.12k|    if (!pScene->mNumMeshes) {
  ------------------
  |  Branch (85:9): [True: 0, False: 3.12k]
  ------------------
   86|      0|        ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess skipped; there are no meshes");
   87|      0|        return;
   88|      0|    }
   89|       |
   90|  3.12k|    ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess begin");
   91|       |
   92|  3.12k|    float out = 0.f;
   93|  3.12k|    unsigned int numf = 0, numm = 0;
   94|  91.8k|    for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (94:30): [True: 88.7k, False: 3.12k]
  ------------------
   95|  88.7k|        const float res = ProcessMesh(pScene->mMeshes[a], a);
   96|  88.7k|        if (res) {
  ------------------
  |  Branch (96:13): [True: 0, False: 88.7k]
  ------------------
   97|      0|            numf += pScene->mMeshes[a]->mNumFaces;
   98|      0|            out += res;
   99|      0|            ++numm;
  100|      0|        }
  101|  88.7k|    }
  102|  3.12k|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (102:9): [True: 0, False: 3.12k]
  ------------------
  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|  3.12k|}
_ZN6Assimp27ImproveCacheLocalityProcess11ProcessMeshEP6aiMeshj:
  157|  88.7k|ai_real ImproveCacheLocalityProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshNum) {
  158|       |    // TODO: rewrite this to use std::vector or boost::shared_array
  159|  88.7k|    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|  88.7k|    if (!pMesh->HasFaces() || !pMesh->HasPositions())
  ------------------
  |  Branch (164:9): [True: 0, False: 88.7k]
  |  Branch (164:31): [True: 0, False: 88.7k]
  ------------------
  165|      0|        return static_cast<ai_real>(0.f);
  166|       |
  167|  88.7k|    if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) {
  ------------------
  |  Branch (167:9): [True: 37.8k, False: 50.8k]
  ------------------
  168|  37.8k|        ASSIMP_LOG_ERROR("This algorithm works on triangle meshes only");
  169|  37.8k|        return static_cast<ai_real>(0.f);
  170|  37.8k|    }
  171|       |
  172|  50.8k|    if (pMesh->mNumVertices <= mConfigCacheDepth) {
  ------------------
  |  Branch (172:9): [True: 37.9k, False: 12.9k]
  ------------------
  173|  37.9k|        return static_cast<ai_real>(0.f);
  174|  37.9k|    }
  175|       |
  176|  12.9k|    ai_real fACMR = 3.f;
  177|  12.9k|    const aiFace *const pcEnd = pMesh->mFaces + pMesh->mNumFaces;
  178|       |
  179|       |    // Input ACMR is for logging purposes only
  180|  12.9k|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (180:9): [True: 0, False: 12.9k]
  ------------------
  181|      0|        fACMR = calculateInputACMR(pMesh, pcEnd, mConfigCacheDepth, meshNum);
  182|      0|    }
  183|       |
  184|       |    // first we need to build a vertex-triangle adjacency list
  185|  12.9k|    VertexTriangleAdjacency adj(pMesh->mFaces, pMesh->mNumFaces, pMesh->mNumVertices, true);
  186|       |
  187|       |    // build a list to store per-vertex caching time stamps
  188|  12.9k|    std::vector<unsigned int> piCachingStamps;
  189|  12.9k|    piCachingStamps.resize(pMesh->mNumVertices);
  190|  12.9k|    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|  12.9k|    const unsigned int iIdxCnt = pMesh->mNumFaces * 3;
  196|  12.9k|    std::vector<unsigned int> piIBOutput;
  197|  12.9k|    piIBOutput.resize(iIdxCnt);
  198|  12.9k|    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|  12.9k|    std::vector<bool> abEmitted(pMesh->mNumFaces, false);
  203|       |
  204|       |    // dead-end vertex index stack
  205|  12.9k|    std::stack<unsigned int, std::vector<unsigned int>> sDeadEndVStack;
  206|       |
  207|       |    // create a copy of the piNumTriPtr buffer
  208|  12.9k|    unsigned int *const piNumTriPtr = adj.mLiveTriangles;
  209|  12.9k|    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|  12.9k|    unsigned int iMaxRefTris = 0;
  213|  12.9k|    {
  214|  12.9k|        const unsigned int *piCur = adj.mLiveTriangles;
  215|  12.9k|        const unsigned int *const piCurEnd = adj.mLiveTriangles + pMesh->mNumVertices;
  216|   553k|        for (; piCur != piCurEnd; ++piCur) {
  ------------------
  |  Branch (216:16): [True: 540k, False: 12.9k]
  ------------------
  217|   540k|            iMaxRefTris = std::max(iMaxRefTris, *piCur);
  218|   540k|        }
  219|  12.9k|    }
  220|  12.9k|    ai_assert(iMaxRefTris > 0);
  221|  12.9k|    std::vector<unsigned int> piCandidates;
  222|  12.9k|    piCandidates.resize(iMaxRefTris * 3);
  223|  12.9k|    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|  12.9k|    int ivdx = 0;
  256|  12.9k|    int ics = 1;
  257|  12.9k|    int iStampCnt = mConfigCacheDepth + 1;
  258|   282k|    while (ivdx >= 0) {
  ------------------
  |  Branch (258:12): [True: 269k, False: 12.9k]
  ------------------
  259|       |
  260|   269k|        unsigned int icnt = piNumTriPtrNoModify[ivdx];
  261|   269k|        unsigned int *piList = adj.GetAdjacentTriangles(ivdx);
  262|   269k|        std::vector<unsigned int>::iterator piCurCandidate = piCandidates.begin();
  263|       |
  264|       |        // get all triangles in the neighborhood
  265|  2.62M|        for (unsigned int tri = 0; tri < icnt; ++tri) {
  ------------------
  |  Branch (265:36): [True: 2.35M, False: 269k]
  ------------------
  266|       |
  267|       |            // if they have not yet been emitted, add them to the output IB
  268|  2.35M|            const unsigned int fidx = *piList++;
  269|  2.35M|            if (!abEmitted[fidx]) {
  ------------------
  |  Branch (269:17): [True: 1.28M, False: 1.06M]
  ------------------
  270|       |
  271|       |                // so iterate through all vertices of the current triangle
  272|  1.28M|                const aiFace *pcFace = &pMesh->mFaces[fidx];
  273|  1.28M|                const unsigned nind = pcFace->mNumIndices;
  274|  5.13M|                for (unsigned ind = 0; ind < nind; ind++) {
  ------------------
  |  Branch (274:40): [True: 3.85M, False: 1.28M]
  ------------------
  275|  3.85M|                    unsigned dp = pcFace->mIndices[ind];
  276|       |
  277|       |                    // the current vertex won't have any free triangles after this step
  278|  3.85M|                    if (ivdx != (int)dp) {
  ------------------
  |  Branch (278:25): [True: 2.56M, False: 1.28M]
  ------------------
  279|       |                        // append the vertex to the dead-end stack
  280|  2.56M|                        sDeadEndVStack.push(dp);
  281|       |
  282|       |                        // register as candidate for the next step
  283|  2.56M|                        *piCurCandidate++ = dp;
  284|       |
  285|       |                        // decrease the per-vertex triangle counts
  286|  2.56M|                        piNumTriPtr[dp]--;
  287|  2.56M|                    }
  288|       |
  289|       |                    // append the vertex to the output index buffer
  290|  3.85M|                    *piCSIter++ = dp;
  291|       |
  292|       |                    // if the vertex is not yet in cache, set its cache count
  293|  3.85M|                    if (iStampCnt - piCachingStamps[dp] > mConfigCacheDepth) {
  ------------------
  |  Branch (293:25): [True: 629k, False: 3.22M]
  ------------------
  294|   629k|                        piCachingStamps[dp] = iStampCnt++;
  295|   629k|                        ++iCacheMisses;
  296|   629k|                    }
  297|  3.85M|                }
  298|       |                // flag triangle as emitted
  299|  1.28M|                abEmitted[fidx] = true;
  300|  1.28M|            }
  301|  2.35M|        }
  302|       |
  303|       |        // the vertex has now no living adjacent triangles anymore
  304|   269k|        piNumTriPtr[ivdx] = 0;
  305|       |
  306|       |        // get next fanning vertex
  307|   269k|        ivdx = -1;
  308|   269k|        int max_priority = -1;
  309|  2.83M|        for (std::vector<unsigned int>::iterator piCur = piCandidates.begin(); piCur != piCurCandidate; ++piCur) {
  ------------------
  |  Branch (309:80): [True: 2.56M, False: 269k]
  ------------------
  310|  2.56M|            const unsigned int dp = *piCur;
  311|       |
  312|       |            // must have live triangles
  313|  2.56M|            if (piNumTriPtr[dp] > 0) {
  ------------------
  |  Branch (313:17): [True: 1.38M, False: 1.18M]
  ------------------
  314|  1.38M|                int priority = 0;
  315|       |
  316|       |                // will the vertex be in cache, even after fanning occurs?
  317|  1.38M|                unsigned int tmp;
  318|  1.38M|                if ((tmp = iStampCnt - piCachingStamps[dp]) + 2 * piNumTriPtr[dp] <= mConfigCacheDepth) {
  ------------------
  |  Branch (318:21): [True: 588k, False: 798k]
  ------------------
  319|   588k|                    priority = tmp;
  320|   588k|                }
  321|       |
  322|       |                // keep best candidate
  323|  1.38M|                if (priority > max_priority) {
  ------------------
  |  Branch (323:21): [True: 282k, False: 1.10M]
  ------------------
  324|   282k|                    max_priority = priority;
  325|   282k|                    ivdx = dp;
  326|   282k|                }
  327|  1.38M|            }
  328|  2.56M|        }
  329|       |        // did we reach a dead end?
  330|   269k|        if (-1 == ivdx) {
  ------------------
  |  Branch (330:13): [True: 80.6k, False: 188k]
  ------------------
  331|       |            // need to get a non-local vertex for which we have a good chance that it is still
  332|       |            // in the cache ...
  333|  2.63M|            while (!sDeadEndVStack.empty()) {
  ------------------
  |  Branch (333:20): [True: 2.56M, False: 68.8k]
  ------------------
  334|  2.56M|                unsigned int iCachedIdx = sDeadEndVStack.top();
  335|  2.56M|                sDeadEndVStack.pop();
  336|  2.56M|                if (piNumTriPtr[iCachedIdx] > 0) {
  ------------------
  |  Branch (336:21): [True: 11.7k, False: 2.55M]
  ------------------
  337|  11.7k|                    ivdx = iCachedIdx;
  338|  11.7k|                    break;
  339|  11.7k|                }
  340|  2.56M|            }
  341|       |
  342|  80.6k|            if (-1 == ivdx) {
  ------------------
  |  Branch (342:17): [True: 68.8k, False: 11.7k]
  ------------------
  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|   540k|                while (ics < (int)pMesh->mNumVertices) {
  ------------------
  |  Branch (345:24): [True: 527k, False: 12.9k]
  ------------------
  346|   527k|                    ++ics;
  347|   527k|                    if (piNumTriPtr[ics] > 0) {
  ------------------
  |  Branch (347:25): [True: 55.9k, False: 471k]
  ------------------
  348|  55.9k|                        ivdx = ics;
  349|  55.9k|                        break;
  350|  55.9k|                    }
  351|   527k|                }
  352|  68.8k|            }
  353|  80.6k|        }
  354|   269k|    }
  355|  12.9k|    ai_real fACMR2 = 0.0f;
  356|  12.9k|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (356:9): [True: 0, False: 12.9k]
  ------------------
  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|  12.9k|    piCSIter = piIBOutput.begin();
  368|  1.29M|    for (aiFace *pcFace = pMesh->mFaces; pcFace != pcEnd; ++pcFace) {
  ------------------
  |  Branch (368:42): [True: 1.28M, False: 12.9k]
  ------------------
  369|  1.28M|        unsigned nind = pcFace->mNumIndices;
  370|  1.28M|        unsigned *ind = pcFace->mIndices;
  371|  1.28M|        if (nind > 0)
  ------------------
  |  Branch (371:13): [True: 1.28M, False: 0]
  ------------------
  372|  1.28M|            ind[0] = *piCSIter++;
  373|  1.28M|        if (nind > 1)
  ------------------
  |  Branch (373:13): [True: 1.28M, False: 0]
  ------------------
  374|  1.28M|            ind[1] = *piCSIter++;
  375|  1.28M|        if (nind > 2)
  ------------------
  |  Branch (375:13): [True: 1.28M, False: 0]
  ------------------
  376|  1.28M|            ind[2] = *piCSIter++;
  377|  1.28M|    }
  378|       |
  379|  12.9k|    return fACMR2;
  380|  50.8k|}

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

_ZN6Assimp19JoinVerticesProcessC2Ev:
   67|  12.0k|    JoinVerticesProcess() = default;

_ZN6Assimp23LimitBoneWeightsProcessC2Ev:
   57|  12.0k|        mMaxWeights(AI_LMW_MAX_WEIGHTS), mRemoveEmptyBones(true) {
   58|       |    // empty
   59|  12.0k|}
_ZNK6Assimp23LimitBoneWeightsProcess8IsActiveEj:
   63|  3.12k|bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const {
   64|  3.12k|    return (pFlags & aiProcess_LimitBoneWeights) != 0;
   65|  3.12k|}
_ZN6Assimp23LimitBoneWeightsProcess7ExecuteEP7aiScene:
   69|  3.12k|void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
   70|  3.12k|    ai_assert(pScene != nullptr);
   71|       |
   72|  3.12k|    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin");
   73|       |
   74|  91.8k|    for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
  ------------------
  |  Branch (74:30): [True: 88.7k, False: 3.12k]
  ------------------
   75|  88.7k|        ProcessMesh(pScene->mMeshes[m]);
   76|  88.7k|    }
   77|       |
   78|       |    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end");
   79|  3.12k|}
_ZN6Assimp23LimitBoneWeightsProcess15SetupPropertiesEPKNS_8ImporterE:
   83|  3.12k|void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) {
   84|  3.12k|    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|  3.12k|}
_ZN6Assimp23LimitBoneWeightsProcess11ProcessMeshEP6aiMesh:
  107|  88.7k|void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) {
  108|  88.7k|    if (!pMesh->HasBones())
  ------------------
  |  Branch (108:9): [True: 88.7k, False: 0]
  ------------------
  109|  88.7k|        return;
  110|       |
  111|       |    // collect all bone weights per vertex
  112|      0|    typedef SmallVector<Weight,8> VertexWeightArray;
  113|      0|    typedef std::vector<VertexWeightArray> WeightsPerVertex;
  114|      0|    WeightsPerVertex vertexWeights(pMesh->mNumVertices);
  115|      0|    size_t maxVertexWeights = 0;
  116|       |
  117|      0|    for (unsigned int b = 0; b < pMesh->mNumBones; ++b) {
  ------------------
  |  Branch (117:30): [True: 0, False: 0]
  ------------------
  118|      0|        const aiBone* bone = pMesh->mBones[b];
  119|      0|        for (unsigned int w = 0; w < bone->mNumWeights; ++w) {
  ------------------
  |  Branch (119:34): [True: 0, False: 0]
  ------------------
  120|      0|            const aiVertexWeight& vw = bone->mWeights[w];
  121|       |
  122|      0|            if (vertexWeights.size() <= vw.mVertexId)
  ------------------
  |  Branch (122:17): [True: 0, False: 0]
  ------------------
  123|      0|                continue;
  124|       |
  125|      0|            vertexWeights[vw.mVertexId].push_back(Weight(b, vw.mWeight));
  126|      0|            maxVertexWeights = std::max(maxVertexWeights, vertexWeights[vw.mVertexId].size());
  127|      0|        }
  128|      0|    }
  129|       |
  130|      0|    if (maxVertexWeights <= mMaxWeights)
  ------------------
  |  Branch (130:9): [True: 0, False: 0]
  ------------------
  131|      0|        return;
  132|       |
  133|      0|    unsigned int removed = 0, old_bones = pMesh->mNumBones;
  134|       |
  135|       |    // now cut the weight count if it exceeds the maximum
  136|      0|    for (WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) {
  ------------------
  |  Branch (136:66): [True: 0, False: 0]
  ------------------
  137|      0|        if (vit->size() <= mMaxWeights)
  ------------------
  |  Branch (137:13): [True: 0, False: 0]
  ------------------
  138|      0|            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|      0|        std::sort(vit->begin(), vit->end());
  143|       |
  144|       |        // now kill everything beyond the maximum count
  145|      0|        unsigned int m = static_cast<unsigned int>(vit->size());
  146|      0|        vit->resize(mMaxWeights);
  147|      0|        removed += static_cast<unsigned int>(m - vit->size());
  148|       |
  149|       |        // and renormalize the weights
  150|      0|        float sum = 0.0f;
  151|      0|        for(const Weight* it = vit->begin(); it != vit->end(); ++it) {
  ------------------
  |  Branch (151:46): [True: 0, False: 0]
  ------------------
  152|      0|            sum += it->mWeight;
  153|      0|        }
  154|      0|        if (0.0f != sum) {
  ------------------
  |  Branch (154:13): [True: 0, False: 0]
  ------------------
  155|      0|            const float invSum = 1.0f / sum;
  156|      0|            for(Weight* it = vit->begin(); it != vit->end(); ++it) {
  ------------------
  |  Branch (156:44): [True: 0, False: 0]
  ------------------
  157|      0|                it->mWeight *= invSum;
  158|      0|            }
  159|      0|        }
  160|      0|    }
  161|       |
  162|       |    // clear weight count for all bone
  163|      0|    for (unsigned int a = 0; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (163:30): [True: 0, False: 0]
  ------------------
  164|      0|        pMesh->mBones[a]->mNumWeights = 0;
  165|      0|    }
  166|       |
  167|       |    // rebuild the vertex weight array for all bones
  168|      0|    for (unsigned int a = 0; a < vertexWeights.size(); ++a) {
  ------------------
  |  Branch (168:30): [True: 0, False: 0]
  ------------------
  169|      0|        const VertexWeightArray& vw = vertexWeights[a];
  170|      0|        for (const Weight* it = vw.begin(); it != vw.end(); ++it) {
  ------------------
  |  Branch (170:45): [True: 0, False: 0]
  ------------------
  171|      0|            aiBone* bone = pMesh->mBones[it->mBone];
  172|      0|            bone->mWeights[bone->mNumWeights++] = aiVertexWeight(a, it->mWeight);
  173|      0|        }
  174|      0|    }
  175|       |
  176|       |    // remove empty bones
  177|      0|    if (mRemoveEmptyBones) {
  ------------------
  |  Branch (177:9): [True: 0, False: 0]
  ------------------
  178|      0|        pMesh->mNumBones = removeEmptyBones(pMesh);
  179|      0|    }
  180|       |
  181|      0|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (181:9): [True: 0, False: 0]
  ------------------
  182|       |        ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones);
  183|      0|    }
  184|      0|}

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

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

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

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

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

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

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

_ZN6Assimp26RemoveRedundantMatsProcessC2Ev:
   57|  12.0k|RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() : mConfigFixedMaterials() {}
_ZNK6Assimp26RemoveRedundantMatsProcess8IsActiveEj:
   61|  3.36k|bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const {
   62|  3.36k|    return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
   63|  3.36k|}
_ZN6Assimp26RemoveRedundantMatsProcess15SetupPropertiesEPKNS_8ImporterE:
   67|  3.36k|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|  3.36k|}
_ZN6Assimp26RemoveRedundantMatsProcess7ExecuteEP7aiScene:
   74|  3.36k|void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
   75|  3.36k|    ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
   76|       |
   77|  3.36k|    unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
   78|  3.36k|    if (pScene->mNumMaterials == 0) {
  ------------------
  |  Branch (78:9): [True: 0, False: 3.36k]
  ------------------
   79|      0|        return;
   80|      0|    }
   81|       |
   82|       |    // Find out which materials are referenced by meshes
   83|  3.36k|    std::vector<bool> abReferenced(pScene->mNumMaterials,false);
   84|  79.1k|    for (unsigned int i = 0;i < pScene->mNumMeshes;++i) {
  ------------------
  |  Branch (84:29): [True: 75.8k, False: 3.36k]
  ------------------
   85|  75.8k|        abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true;
   86|  75.8k|    }
   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|  3.36k|    if (mConfigFixedMaterials.length()) {
  ------------------
  |  Branch (91:9): [True: 0, False: 3.36k]
  ------------------
   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|  3.36k|    unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials];
  119|  18.7k|    for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) {
  ------------------
  |  Branch (119:29): [True: 15.3k, False: 3.36k]
  ------------------
  120|  15.3k|        aiMappingTable[ i ] = 0;
  121|  15.3k|    }
  122|  3.36k|    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|  3.36k|    uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];
  129|  18.7k|    for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
  ------------------
  |  Branch (129:30): [True: 15.3k, False: 3.36k]
  ------------------
  130|       |        // No mesh is referencing this material, remove it.
  131|  15.3k|        if (!abReferenced[i]) {
  ------------------
  |  Branch (131:13): [True: 8.36k, False: 7.00k]
  ------------------
  132|  8.36k|            ++unreferencedRemoved;
  133|  8.36k|            delete pScene->mMaterials[i];
  134|  8.36k|            pScene->mMaterials[i] = nullptr;
  135|  8.36k|            continue;
  136|  8.36k|        }
  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|  7.00k|        uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
  141|  37.7k|        for (unsigned int a = 0; a < i;++a) {
  ------------------
  |  Branch (141:34): [True: 33.7k, False: 3.96k]
  ------------------
  142|  33.7k|            if (abReferenced[a] && me == aiHashes[a]) {
  ------------------
  |  Branch (142:17): [True: 6.06k, False: 27.6k]
  |  Branch (142:17): [True: 3.04k, False: 30.7k]
  |  Branch (142:36): [True: 3.04k, False: 3.02k]
  ------------------
  143|  3.04k|                ++redundantRemoved;
  144|  3.04k|                me = 0;
  145|  3.04k|                aiMappingTable[i] = aiMappingTable[a];
  146|  3.04k|                delete pScene->mMaterials[i];
  147|  3.04k|                pScene->mMaterials[i] = nullptr;
  148|  3.04k|                break;
  149|  3.04k|            }
  150|  33.7k|        }
  151|       |        // This is a new material that is referenced, add to the map.
  152|  7.00k|        if (me) {
  ------------------
  |  Branch (152:13): [True: 3.96k, False: 3.04k]
  ------------------
  153|  3.96k|            aiMappingTable[i] = iNewNum++;
  154|  3.96k|        }
  155|  7.00k|    }
  156|       |    // If the new material count differs from the original,
  157|       |    // we need to rebuild the material list and remap mesh material indexes.
  158|  3.36k|    if (iNewNum < 1) {
  ------------------
  |  Branch (158:9): [True: 0, False: 3.36k]
  ------------------
  159|      0|        delete [] aiMappingTable;
  160|      0|        delete [] aiHashes;
  161|      0|        pScene->mNumMaterials = 0;
  162|      0|        return;
  163|      0|    }
  164|  3.36k|    if (iNewNum != pScene->mNumMaterials) {
  ------------------
  |  Branch (164:9): [True: 1.91k, False: 1.44k]
  ------------------
  165|  1.91k|        ai_assert(iNewNum > 0);
  166|  1.91k|        aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
  167|  1.91k|        ::memset(ppcMaterials,0,sizeof(void*)*iNewNum);
  168|  15.8k|        for (unsigned int p = 0; p < pScene->mNumMaterials;++p) {
  ------------------
  |  Branch (168:34): [True: 13.9k, False: 1.91k]
  ------------------
  169|       |            // if the material is not referenced ... remove it
  170|  13.9k|            if (!abReferenced[p]) {
  ------------------
  |  Branch (170:17): [True: 8.36k, False: 5.54k]
  ------------------
  171|  8.36k|                continue;
  172|  8.36k|            }
  173|       |
  174|       |            // generate new names for modified materials that had no names
  175|  5.54k|            const unsigned int idx = aiMappingTable[p];
  176|  5.54k|            if (ppcMaterials[idx]) {
  ------------------
  |  Branch (176:17): [True: 3.04k, False: 2.50k]
  ------------------
  177|  3.04k|                aiString sz;
  178|  3.04k|                if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
  ------------------
  |  Branch (178:21): [True: 0, False: 3.04k]
  ------------------
  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|  3.04k|            } else {
  183|  2.50k|                ppcMaterials[idx] = pScene->mMaterials[p];
  184|  2.50k|            }
  185|  5.54k|        }
  186|       |        // update all material indices
  187|  72.2k|        for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
  ------------------
  |  Branch (187:34): [True: 70.3k, False: 1.91k]
  ------------------
  188|  70.3k|            aiMesh* mesh = pScene->mMeshes[p];
  189|  70.3k|            ai_assert(nullptr != mesh);
  190|  70.3k|            mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
  191|  70.3k|        }
  192|       |        // delete the old material list
  193|  1.91k|        delete[] pScene->mMaterials;
  194|  1.91k|        pScene->mMaterials = ppcMaterials;
  195|  1.91k|        pScene->mNumMaterials = iNewNum;
  196|  1.91k|    }
  197|       |    // delete temporary storage
  198|  3.36k|    delete[] aiHashes;
  199|  3.36k|    delete[] aiMappingTable;
  200|       |
  201|  3.36k|    if (redundantRemoved == 0 && unreferencedRemoved == 0) {
  ------------------
  |  Branch (201:9): [True: 2.32k, False: 1.04k]
  |  Branch (201:34): [True: 1.44k, False: 877]
  ------------------
  202|  1.44k|        ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
  203|  1.91k|    } else {
  204|       |        ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
  205|  1.91k|            unreferencedRemoved, " unused materials.");
  206|  1.91k|    }
  207|  3.36k|}

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

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

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

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

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

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

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

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

_ZN6Assimp20TextureTransformStepC2Ev:
  172|  12.0k|    TextureTransformStep() = default;

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

_ZN6Assimp18TriangulateProcessC2Ev:
   65|  12.0k|    TriangulateProcess() = default;

_ZN6Assimp17ValidateDSProcessC2Ev:
   61|  10.5k|ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {}
_ZN6Assimp17ValidateDSProcess11ReportErrorEPKcz:
   69|  7.13k|AI_WONT_RETURN void ValidateDSProcess::ReportError(const char *msg, ...) {
   70|  7.13k|    ai_assert(nullptr != msg);
   71|       |
   72|  7.13k|    va_list args;
   73|  7.13k|    va_start(args, msg);
   74|       |
   75|  7.13k|    char szBuffer[3000];
   76|  7.13k|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   77|  7.13k|    ai_assert(iLen > 0);
   78|       |
   79|  7.13k|    va_end(args);
   80|       |
   81|  7.13k|    throw DeadlyImportError("Validation failed: ", std::string(szBuffer, iLen));
   82|  7.13k|}
_ZN6Assimp17ValidateDSProcess13ReportWarningEPKcz:
   84|  2.78k|void ValidateDSProcess::ReportWarning(const char *msg, ...) {
   85|  2.78k|    ai_assert(nullptr != msg);
   86|       |
   87|  2.78k|    va_list args;
   88|  2.78k|    va_start(args, msg);
   89|       |
   90|  2.78k|    char szBuffer[3000];
   91|  2.78k|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   92|  2.78k|    ai_assert(iLen > 0);
   93|       |
   94|  2.78k|    va_end(args);
   95|       |    ASSIMP_LOG_WARN("Validation warning: ", std::string(szBuffer, iLen));
   96|  2.78k|}
_ZN6Assimp17ValidateDSProcess7ExecuteEP7aiScene:
  183|  10.5k|void ValidateDSProcess::Execute(aiScene *pScene) {
  184|  10.5k|    mScene = pScene;
  185|  10.5k|    ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin");
  186|       |
  187|       |    // validate the node graph of the scene
  188|  10.5k|    Validate(pScene->mRootNode);
  189|       |
  190|       |    // validate all meshes
  191|  10.5k|    if (pScene->mNumMeshes) {
  ------------------
  |  Branch (191:9): [True: 3.82k, False: 6.68k]
  ------------------
  192|  3.82k|        DoValidation(pScene->mMeshes, pScene->mNumMeshes, "mMeshes", "mNumMeshes");
  193|  6.68k|    } else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
  ------------------
  |  Branch (193:16): [True: 6.68k, False: 0]
  ------------------
  194|  6.68k|        ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
  195|  6.68k|    } else if (pScene->mMeshes) {
  ------------------
  |  Branch (195:16): [True: 0, False: 0]
  ------------------
  196|      0|        ReportError("aiScene::mMeshes is non-null although there are no meshes");
  197|      0|    }
  198|       |
  199|       |    // validate all animations
  200|  10.5k|    if (pScene->mNumAnimations) {
  ------------------
  |  Branch (200:9): [True: 0, False: 10.5k]
  ------------------
  201|      0|        DoValidation(pScene->mAnimations, pScene->mNumAnimations,
  202|      0|                "mAnimations", "mNumAnimations");
  203|  10.5k|    } else if (pScene->mAnimations) {
  ------------------
  |  Branch (203:16): [True: 0, False: 10.5k]
  ------------------
  204|      0|        ReportError("aiScene::mAnimations is non-null although there are no animations");
  205|      0|    }
  206|       |
  207|       |    // validate all cameras
  208|  10.5k|    if (pScene->mNumCameras) {
  ------------------
  |  Branch (208:9): [True: 0, False: 10.5k]
  ------------------
  209|      0|        DoValidationWithNameCheck(pScene->mCameras, pScene->mNumCameras,
  210|      0|                "mCameras", "mNumCameras");
  211|  10.5k|    } else if (pScene->mCameras) {
  ------------------
  |  Branch (211:16): [True: 0, False: 10.5k]
  ------------------
  212|      0|        ReportError("aiScene::mCameras is non-null although there are no cameras");
  213|      0|    }
  214|       |
  215|       |    // validate all lights
  216|  10.5k|    if (pScene->mNumLights) {
  ------------------
  |  Branch (216:9): [True: 0, False: 10.5k]
  ------------------
  217|      0|        DoValidationWithNameCheck(pScene->mLights, pScene->mNumLights,
  218|      0|                "mLights", "mNumLights");
  219|  10.5k|    } else if (pScene->mLights) {
  ------------------
  |  Branch (219:16): [True: 0, False: 10.5k]
  ------------------
  220|      0|        ReportError("aiScene::mLights is non-null although there are no lights");
  221|      0|    }
  222|       |
  223|       |    // validate all textures
  224|  10.5k|    if (pScene->mNumTextures) {
  ------------------
  |  Branch (224:9): [True: 0, False: 10.5k]
  ------------------
  225|      0|        DoValidation(pScene->mTextures, pScene->mNumTextures,
  226|      0|                "mTextures", "mNumTextures");
  227|  10.5k|    } else if (pScene->mTextures) {
  ------------------
  |  Branch (227:16): [True: 0, False: 10.5k]
  ------------------
  228|      0|        ReportError("aiScene::mTextures is non-null although there are no textures");
  229|      0|    }
  230|       |
  231|       |    // validate all materials
  232|  10.5k|    if (pScene->mNumMaterials) {
  ------------------
  |  Branch (232:9): [True: 3.36k, False: 7.13k]
  ------------------
  233|  3.36k|        DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials");
  234|  3.36k|    }
  235|  7.13k|    else if (pScene->mMaterials) {
  ------------------
  |  Branch (235:14): [True: 0, False: 7.13k]
  ------------------
  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|  10.5k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMesh:
  273|  78.8k|void ValidateDSProcess::Validate(const aiMesh *pMesh) {
  274|       |    // validate the material index of the mesh
  275|  78.8k|    if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) {
  ------------------
  |  Branch (275:9): [True: 78.4k, False: 388]
  |  Branch (275:34): [True: 0, False: 78.4k]
  ------------------
  276|      0|        ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)",
  277|      0|                pMesh->mMaterialIndex, mScene->mNumMaterials - 1);
  278|      0|    }
  279|       |
  280|  78.8k|    Validate(&pMesh->mName);
  281|       |
  282|   780k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (282:30): [True: 701k, False: 78.7k]
  ------------------
  283|   701k|        aiFace &face = pMesh->mFaces[i];
  284|       |
  285|   701k|        if (pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (285:13): [True: 701k, False: 0]
  ------------------
  286|   701k|            switch (face.mNumIndices) {
  287|      0|            case 0:
  ------------------
  |  Branch (287:13): [True: 0, False: 701k]
  ------------------
  288|      0|                ReportError("aiMesh::mFaces[%i].mNumIndices is 0", i);
  289|  27.4k|            case 1:
  ------------------
  |  Branch (289:13): [True: 27.4k, False: 674k]
  ------------------
  290|  27.4k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT)) {
  ------------------
  |  Branch (290:21): [True: 40, False: 27.4k]
  ------------------
  291|     40|                    ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimitiveTypes "
  292|     40|                                "does not report the POINT flag",
  293|     40|                            i);
  294|     40|                }
  295|  27.4k|                break;
  296|  58.5k|            case 2:
  ------------------
  |  Branch (296:13): [True: 58.5k, False: 643k]
  ------------------
  297|  58.5k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE)) {
  ------------------
  |  Branch (297:21): [True: 24, False: 58.5k]
  ------------------
  298|     24|                    ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimitiveTypes "
  299|     24|                                "does not report the LINE flag",
  300|     24|                            i);
  301|     24|                }
  302|  58.5k|                break;
  303|   520k|            case 3:
  ------------------
  |  Branch (303:13): [True: 520k, False: 181k]
  ------------------
  304|   520k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) {
  ------------------
  |  Branch (304:21): [True: 0, False: 520k]
  ------------------
  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|   520k|                break;
  310|  95.4k|            default:
  ------------------
  |  Branch (310:13): [True: 95.4k, False: 606k]
  ------------------
  311|  95.4k|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (311:21): [True: 0, False: 95.4k]
  ------------------
  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|  95.4k|                break;
  317|   701k|            };
  318|   701k|        }
  319|       |
  320|   701k|        if (!face.mIndices)
  ------------------
  |  Branch (320:13): [True: 0, False: 701k]
  ------------------
  321|      0|            ReportError("aiMesh::mFaces[%i].mIndices is nullptr", i);
  322|   701k|    }
  323|       |
  324|       |    // positions must always be there ...
  325|  78.7k|    if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) {
  ------------------
  |  Branch (325:9): [True: 0, False: 78.7k]
  |  Branch (325:34): [True: 0, False: 78.7k]
  |  Branch (325:55): [True: 0, False: 0]
  ------------------
  326|      0|        ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str());
  327|      0|    }
  328|       |
  329|  78.7k|    if (pMesh->mNumVertices > AI_MAX_VERTICES) {
  ------------------
  |  Branch (329:9): [True: 0, False: 78.7k]
  ------------------
  330|      0|        ReportError("Mesh has too many vertices: %u, but the limit is %u", pMesh->mNumVertices, AI_MAX_VERTICES);
  331|      0|    }
  332|  78.7k|    if (pMesh->mNumFaces > AI_MAX_FACES) {
  ------------------
  |  Branch (332:9): [True: 0, False: 78.7k]
  ------------------
  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|  78.7k|    if ((pMesh->mTangents != nullptr) != (pMesh->mBitangents != nullptr)) {
  ------------------
  |  Branch (337:9): [True: 0, False: 78.7k]
  ------------------
  338|      0|        ReportError("If there are tangents, bitangent vectors must be present as well");
  339|      0|    }
  340|       |
  341|       |    // faces, too
  342|  78.7k|    if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) {
  ------------------
  |  Branch (342:9): [True: 388, False: 78.3k]
  |  Branch (342:31): [True: 0, False: 78.3k]
  |  Branch (342:49): [True: 0, False: 0]
  ------------------
  343|    388|        ReportError("Mesh %s contains no faces", pMesh->mName.C_Str());
  344|    388|    }
  345|       |
  346|       |    // now check whether the face indexing layout is correct:
  347|       |    // unique vertices, pseudo-indexed.
  348|  78.7k|    std::vector<bool> abRefList;
  349|  78.7k|    abRefList.resize(pMesh->mNumVertices, false);
  350|   773k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (350:30): [True: 695k, False: 78.7k]
  ------------------
  351|   695k|        aiFace &face = pMesh->mFaces[i];
  352|   695k|        if (face.mNumIndices > AI_MAX_FACE_INDICES) {
  ------------------
  |  Branch (352:13): [True: 5, False: 695k]
  ------------------
  353|      5|            ReportError("Face %u has too many faces: %u, but the limit is %u", i, face.mNumIndices, AI_MAX_FACE_INDICES);
  354|      5|        }
  355|       |
  356|  5.88M|        for (unsigned int a = 0; a < face.mNumIndices; ++a) {
  ------------------
  |  Branch (356:34): [True: 5.18M, False: 695k]
  ------------------
  357|  5.18M|            if (face.mIndices[a] >= pMesh->mNumVertices) {
  ------------------
  |  Branch (357:17): [True: 0, False: 5.18M]
  ------------------
  358|      0|                ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a);
  359|      0|            }
  360|  5.18M|            abRefList[face.mIndices[a]] = true;
  361|  5.18M|        }
  362|   695k|    }
  363|       |
  364|       |    // check whether there are vertices that aren't referenced by a face
  365|  78.7k|    bool b = false;
  366|  5.26M|    for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (366:30): [True: 5.18M, False: 78.7k]
  ------------------
  367|  5.18M|        if (!abRefList[i]) b = true;
  ------------------
  |  Branch (367:13): [True: 0, False: 5.18M]
  ------------------
  368|  5.18M|    }
  369|  78.7k|    abRefList.clear();
  370|  78.7k|    if (b) {
  ------------------
  |  Branch (370:9): [True: 0, False: 78.7k]
  ------------------
  371|      0|        ReportWarning("There are unreferenced vertices");
  372|      0|    }
  373|       |
  374|       |    // vertex color channel 2 may not be set if channel 1 is zero ...
  375|  78.7k|    {
  376|  78.7k|        unsigned int i = 0;
  377|   106k|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
  ------------------
  |  Branch (377:16): [True: 106k, False: 393]
  ------------------
  378|   106k|            if (!pMesh->HasVertexColors(i)) break;
  ------------------
  |  Branch (378:17): [True: 78.3k, False: 28.1k]
  ------------------
  379|   106k|        }
  380|   677k|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i)
  ------------------
  |  Branch (380:16): [True: 598k, False: 78.7k]
  ------------------
  381|   598k|            if (pMesh->HasVertexColors(i)) {
  ------------------
  |  Branch (381:17): [True: 0, False: 598k]
  ------------------
  382|      0|                ReportError("Vertex color channel %i is exists "
  383|      0|                            "although the previous channel was nullptr.",
  384|      0|                        i);
  385|      0|            }
  386|  78.7k|    }
  387|       |
  388|       |    // now validate all bones
  389|  78.7k|    if (pMesh->mNumBones) {
  ------------------
  |  Branch (389:9): [True: 0, False: 78.7k]
  ------------------
  390|      0|        if (!pMesh->mBones) {
  ------------------
  |  Branch (390:13): [True: 0, False: 0]
  ------------------
  391|      0|            ReportError("aiMesh::mBones is nullptr (aiMesh::mNumBones is %i)",
  392|      0|                    pMesh->mNumBones);
  393|      0|        }
  394|      0|        std::unique_ptr<float[]> afSum(nullptr);
  395|      0|        if (pMesh->mNumVertices) {
  ------------------
  |  Branch (395:13): [True: 0, False: 0]
  ------------------
  396|      0|            afSum.reset(new float[pMesh->mNumVertices]);
  397|      0|            for (unsigned int i = 0; i < pMesh->mNumVertices; ++i)
  ------------------
  |  Branch (397:38): [True: 0, False: 0]
  ------------------
  398|      0|                afSum[i] = 0.0f;
  399|      0|        }
  400|       |
  401|       |        // check whether there are duplicate bone names
  402|      0|        for (unsigned int i = 0; i < pMesh->mNumBones; ++i) {
  ------------------
  |  Branch (402:34): [True: 0, False: 0]
  ------------------
  403|      0|            const aiBone *bone = pMesh->mBones[i];
  404|      0|            if (bone->mNumWeights > AI_MAX_BONE_WEIGHTS) {
  ------------------
  |  Branch (404:17): [True: 0, False: 0]
  ------------------
  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|      0|            if (!pMesh->mBones[i]) {
  ------------------
  |  Branch (408:17): [True: 0, False: 0]
  ------------------
  409|      0|                ReportError("aiMesh::mBones[%i] is nullptr (aiMesh::mNumBones is %i)",
  410|      0|                        i, pMesh->mNumBones);
  411|      0|            }
  412|      0|            Validate(pMesh, pMesh->mBones[i], afSum.get());
  413|       |
  414|      0|            for (unsigned int a = i + 1; a < pMesh->mNumBones; ++a) {
  ------------------
  |  Branch (414:42): [True: 0, False: 0]
  ------------------
  415|      0|                if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName) {
  ------------------
  |  Branch (415:21): [True: 0, False: 0]
  ------------------
  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|      0|            }
  425|      0|        }
  426|       |        // check whether all bone weights for a vertex sum to 1.0 ...
  427|      0|        for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (427:34): [True: 0, False: 0]
  ------------------
  428|      0|            if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) {
  ------------------
  |  Branch (428:17): [True: 0, False: 0]
  |  Branch (428:30): [True: 0, False: 0]
  |  Branch (428:50): [True: 0, False: 0]
  ------------------
  429|      0|                ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)", i, afSum[i]);
  430|      0|            }
  431|      0|        }
  432|  78.7k|    } else if (pMesh->mBones) {
  ------------------
  |  Branch (432:16): [True: 0, False: 78.7k]
  ------------------
  433|      0|        ReportError("aiMesh::mBones is non-null although there are no bones");
  434|      0|    }
  435|  78.7k|}
_ZN6Assimp17ValidateDSProcess24SearchForInvalidTexturesEPK10aiMaterial13aiTextureType:
  491|   261k|        aiTextureType type) {
  492|   261k|    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|   261k|    int iNumIndices = 0;
  501|   261k|    int iIndex = -1;
  502|  3.58M|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (502:30): [True: 3.32M, False: 261k]
  ------------------
  503|  3.32M|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  504|  3.32M|        ai_assert(nullptr != prop);
  505|  3.32M|        if (!::strcmp(prop->mKey.data, "$tex.file") && prop->mSemantic == static_cast<unsigned int>(type)) {
  ------------------
  |  Branch (505:13): [True: 85.2k, False: 3.23M]
  |  Branch (505:56): [True: 4.79k, False: 80.4k]
  ------------------
  506|  4.79k|            iIndex = std::max(iIndex, (int)prop->mIndex);
  507|  4.79k|            ++iNumIndices;
  508|       |
  509|  4.79k|            if (aiPTI_String != prop->mType) {
  ------------------
  |  Branch (509:17): [True: 0, False: 4.79k]
  ------------------
  510|      0|                ReportError("Material property %s is expected to be a string", prop->mKey.data);
  511|      0|            }
  512|  4.79k|        }
  513|  3.32M|    }
  514|   261k|    if (iIndex + 1 != iNumIndices) {
  ------------------
  |  Branch (514:9): [True: 0, False: 261k]
  ------------------
  515|      0|        ReportError("%s #%i is set, but there are only %i %s textures",
  516|      0|                szType, iIndex, iNumIndices, szType);
  517|      0|    }
  518|   261k|    if (!iNumIndices) {
  ------------------
  |  Branch (518:9): [True: 257k, False: 3.64k]
  ------------------
  519|   257k|        return;
  520|   257k|    }
  521|  3.64k|    std::vector<aiTextureMapping> mappings(iNumIndices);
  522|       |
  523|       |    // Now check whether all UV indices are valid ...
  524|  3.64k|    bool bNoSpecified = true;
  525|  75.1k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (525:30): [True: 71.4k, False: 3.64k]
  ------------------
  526|  71.4k|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  527|  71.4k|        if (static_cast<aiTextureType>(prop->mSemantic) != type) {
  ------------------
  |  Branch (527:13): [True: 61.5k, False: 9.90k]
  ------------------
  528|  61.5k|            continue;
  529|  61.5k|        }
  530|       |
  531|  9.90k|        if ((int)prop->mIndex >= iNumIndices) {
  ------------------
  |  Branch (531:13): [True: 0, False: 9.90k]
  ------------------
  532|      0|            ReportError("Found texture property with index %i, although there "
  533|      0|                        "are only %i textures of type %s",
  534|      0|                    prop->mIndex, iNumIndices, szType);
  535|      0|        }
  536|       |
  537|  9.90k|        if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
  ------------------
  |  Branch (537:13): [True: 0, False: 9.90k]
  ------------------
  538|      0|            if (aiPTI_Integer != prop->mType || prop->mDataLength < sizeof(aiTextureMapping)) {
  ------------------
  |  Branch (538:17): [True: 0, False: 0]
  |  Branch (538:49): [True: 0, False: 0]
  ------------------
  539|      0|                ReportError("Material property %s%i is expected to be an integer (size is %i)",
  540|      0|                        prop->mKey.data, prop->mIndex, prop->mDataLength);
  541|      0|            }
  542|      0|            mappings[prop->mIndex] = *((aiTextureMapping *)prop->mData);
  543|  9.90k|        } else if (!::strcmp(prop->mKey.data, "$tex.uvtrafo")) {
  ------------------
  |  Branch (543:20): [True: 0, False: 9.90k]
  ------------------
  544|      0|            if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform)) {
  ------------------
  |  Branch (544:17): [True: 0, False: 0]
  |  Branch (544:47): [True: 0, False: 0]
  ------------------
  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|  9.90k|        } else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
  ------------------
  |  Branch (549:20): [True: 4.79k, False: 5.11k]
  ------------------
  550|  4.79k|            if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) {
  ------------------
  |  Branch (550:17): [True: 0, False: 4.79k]
  |  Branch (550:49): [True: 0, False: 4.79k]
  ------------------
  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|  4.79k|            bNoSpecified = false;
  555|       |
  556|       |            // Ignore UV indices for texture channels that are not there ...
  557|       |
  558|       |            // Get the value
  559|  4.79k|            iIndex = *((unsigned int *)prop->mData);
  560|       |
  561|       |            // Check whether there is a mesh using this material
  562|       |            // which has not enough UV channels ...
  563|   218k|            for (unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (563:38): [True: 213k, False: 4.79k]
  ------------------
  564|   213k|                aiMesh *mesh = this->mScene->mMeshes[a];
  565|   213k|                if (mesh->mMaterialIndex == (unsigned int)i) {
  ------------------
  |  Branch (565:21): [True: 2.66k, False: 211k]
  ------------------
  566|  2.66k|                    int iChannels = 0;
  567|  2.99k|                    while (mesh->HasTextureCoords(iChannels))
  ------------------
  |  Branch (567:28): [True: 328, False: 2.66k]
  ------------------
  568|    328|                        ++iChannels;
  569|  2.66k|                    if (iIndex >= iChannels) {
  ------------------
  |  Branch (569:25): [True: 2.33k, False: 328]
  ------------------
  570|  2.33k|                        ReportWarning("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
  571|  2.33k|                                iIndex, prop->mKey.data, a, iChannels);
  572|  2.33k|                    }
  573|  2.66k|                }
  574|   213k|            }
  575|  4.79k|        }
  576|  9.90k|    }
  577|  3.64k|    if (bNoSpecified) {
  ------------------
  |  Branch (577:9): [True: 0, False: 3.64k]
  ------------------
  578|       |        // Assume that all textures are using the first UV channel
  579|      0|        for (unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (579:34): [True: 0, False: 0]
  ------------------
  580|      0|            aiMesh *mesh = mScene->mMeshes[a];
  581|      0|            if (mesh->mMaterialIndex == (unsigned int)iIndex && mappings[0] == aiTextureMapping_UV) {
  ------------------
  |  Branch (581:17): [True: 0, False: 0]
  |  Branch (581:65): [True: 0, False: 0]
  ------------------
  582|      0|                if (!mesh->mTextureCoords[0]) {
  ------------------
  |  Branch (582:21): [True: 0, False: 0]
  ------------------
  583|       |                    // This is a special case ... it could be that the
  584|       |                    // original mesh format intended the use of a special
  585|       |                    // mapping here.
  586|      0|                    ReportWarning("UV-mapped texture, but there are no UV coords");
  587|      0|                }
  588|      0|            }
  589|      0|        }
  590|      0|    }
  591|  3.64k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK10aiMaterial:
  593|  15.3k|void ValidateDSProcess::Validate(const aiMaterial *pMaterial) {
  594|       |    // check whether there are material keys that are obviously not legal
  595|   210k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (595:30): [True: 195k, False: 15.3k]
  ------------------
  596|   195k|        const aiMaterialProperty *prop = pMaterial->mProperties[i];
  597|   195k|        if (!prop) {
  ------------------
  |  Branch (597:13): [True: 0, False: 195k]
  ------------------
  598|      0|            ReportError("aiMaterial::mProperties[%i] is nullptr (aiMaterial::mNumProperties is %i)",
  599|      0|                    i, pMaterial->mNumProperties);
  600|      0|        }
  601|   195k|        if (!prop->mDataLength || !prop->mData) {
  ------------------
  |  Branch (601:13): [True: 0, False: 195k]
  |  Branch (601:35): [True: 0, False: 195k]
  ------------------
  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|   195k|        if (aiPTI_String == prop->mType) {
  ------------------
  |  Branch (607:13): [True: 20.3k, False: 175k]
  ------------------
  608|       |            // FIX: strings are now stored in a less expensive way, but we can't use the
  609|       |            // validation routine for 'normal' aiStrings
  610|  20.3k|            if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast<uint32_t *>(prop->mData)) + 1) {
  ------------------
  |  Branch (610:17): [True: 0, False: 20.3k]
  |  Branch (610:42): [True: 0, False: 20.3k]
  ------------------
  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|  20.3k|            if (prop->mData[prop->mDataLength - 1]) {
  ------------------
  |  Branch (615:17): [True: 0, False: 20.3k]
  ------------------
  616|      0|                ReportError("Missing null-terminator in string material property");
  617|      0|            }
  618|       |            //  Validate((const aiString*)prop->mData);
  619|   175k|        } else if (aiPTI_Float == prop->mType) {
  ------------------
  |  Branch (619:20): [True: 139k, False: 35.9k]
  ------------------
  620|   139k|            if (prop->mDataLength < sizeof(float)) {
  ------------------
  |  Branch (620:17): [True: 0, False: 139k]
  ------------------
  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|   139k|        } else if (aiPTI_Integer == prop->mType) {
  ------------------
  |  Branch (625:20): [True: 35.9k, False: 0]
  ------------------
  626|  35.9k|            if (prop->mDataLength < sizeof(int)) {
  ------------------
  |  Branch (626:17): [True: 0, False: 35.9k]
  ------------------
  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|  35.9k|        }
  632|       |        // TODO: check whether there is a key with an unknown name ...
  633|   195k|    }
  634|       |
  635|       |    // make some more specific tests
  636|  15.3k|    ai_real fTemp;
  637|  15.3k|    int iShading;
  638|  15.3k|    if (AI_SUCCESS == aiGetMaterialInteger(pMaterial, AI_MATKEY_SHADING_MODEL, &iShading)) {
  ------------------
  |  Branch (638:9): [True: 15.3k, False: 0]
  ------------------
  639|  15.3k|        switch ((aiShadingMode)iShading) {
  640|      0|        case aiShadingMode_Blinn:
  ------------------
  |  Branch (640:9): [True: 0, False: 15.3k]
  ------------------
  641|      0|        case aiShadingMode_CookTorrance:
  ------------------
  |  Branch (641:9): [True: 0, False: 15.3k]
  ------------------
  642|    124|        case aiShadingMode_Phong:
  ------------------
  |  Branch (642:9): [True: 124, False: 15.2k]
  ------------------
  643|       |
  644|    124|            if (AI_SUCCESS != aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS, &fTemp)) {
  ------------------
  |  Branch (644:17): [True: 0, False: 124]
  ------------------
  645|      0|                ReportWarning("A specular shading model is specified but there is no "
  646|      0|                              "AI_MATKEY_SHININESS key");
  647|      0|            }
  648|    124|            if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS_STRENGTH, &fTemp) && !fTemp) {
  ------------------
  |  Branch (648:17): [True: 0, False: 124]
  |  Branch (648:102): [True: 0, False: 0]
  ------------------
  649|      0|                ReportWarning("A specular shading model is specified but the value of the "
  650|      0|                              "AI_MATKEY_SHININESS_STRENGTH key is 0.0");
  651|      0|            }
  652|    124|            break;
  653|  15.2k|        default:
  ------------------
  |  Branch (653:9): [True: 15.2k, False: 124]
  ------------------
  654|  15.2k|            break;
  655|  15.3k|        }
  656|  15.3k|    }
  657|       |
  658|  15.3k|    if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_OPACITY, &fTemp) && (!fTemp || fTemp > 1.01)) {
  ------------------
  |  Branch (658:9): [True: 15.3k, False: 0]
  |  Branch (658:84): [True: 188, False: 15.1k]
  |  Branch (658:94): [True: 253, False: 14.9k]
  ------------------
  659|    441|        ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)");
  660|    441|    }
  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|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE);
  666|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_SPECULAR);
  667|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT);
  668|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSIVE);
  669|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_OPACITY);
  670|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_SHININESS);
  671|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_HEIGHT);
  672|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMALS);
  673|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_DISPLACEMENT);
  674|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_LIGHTMAP);
  675|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_REFLECTION);
  676|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_BASE_COLOR);
  677|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMAL_CAMERA);
  678|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSION_COLOR);
  679|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_METALNESS);
  680|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE_ROUGHNESS);
  681|  15.3k|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT_OCCLUSION);
  682|  15.3k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiNode:
  850|   184k|void ValidateDSProcess::Validate(const aiNode *pNode) {
  851|   184k|    if (!pNode) {
  ------------------
  |  Branch (851:9): [True: 0, False: 184k]
  ------------------
  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|   184k|    this->Validate(&pNode->mName);
  856|   184k|    const char *nodeName = (&pNode->mName)->C_Str();
  857|   184k|    if (pNode != mScene->mRootNode && !pNode->mParent) {
  ------------------
  |  Branch (857:9): [True: 174k, False: 10.5k]
  |  Branch (857:39): [True: 0, False: 174k]
  ------------------
  858|      0|        ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is nullptr) ", nodeName);
  859|      0|    }
  860|       |
  861|       |    // validate all meshes
  862|   184k|    if (pNode->mNumMeshes) {
  ------------------
  |  Branch (862:9): [True: 54.9k, False: 129k]
  ------------------
  863|  54.9k|        if (!pNode->mMeshes) {
  ------------------
  |  Branch (863:13): [True: 0, False: 54.9k]
  ------------------
  864|      0|            ReportError("aiNode::mMeshes is nullptr for node %s (aiNode::mNumMeshes is %i)",
  865|      0|                    nodeName, pNode->mNumMeshes);
  866|      0|        }
  867|  54.9k|        std::vector<bool> abHadMesh;
  868|  54.9k|        abHadMesh.resize(mScene->mNumMeshes, false);
  869|   137k|        for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) {
  ------------------
  |  Branch (869:34): [True: 83.0k, False: 54.9k]
  ------------------
  870|  83.0k|            if (pNode->mMeshes[i] >= mScene->mNumMeshes) {
  ------------------
  |  Branch (870:17): [True: 0, False: 83.0k]
  ------------------
  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|  83.0k|            if (abHadMesh[pNode->mMeshes[i]]) {
  ------------------
  |  Branch (874:17): [True: 0, False: 83.0k]
  ------------------
  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|  83.0k|            abHadMesh[pNode->mMeshes[i]] = true;
  879|  83.0k|        }
  880|  54.9k|    }
  881|   184k|    if (pNode->mNumChildren) {
  ------------------
  |  Branch (881:9): [True: 4.87k, False: 179k]
  ------------------
  882|  4.87k|        if (!pNode->mChildren) {
  ------------------
  |  Branch (882:13): [True: 0, False: 4.87k]
  ------------------
  883|      0|            ReportError("aiNode::mChildren is nullptr for node %s (aiNode::mNumChildren is %i)",
  884|      0|                    nodeName, pNode->mNumChildren);
  885|      0|        }
  886|   179k|        for (unsigned int i = 0; i < pNode->mNumChildren; ++i) {
  ------------------
  |  Branch (886:34): [True: 174k, False: 4.87k]
  ------------------
  887|   174k|            const aiNode *pChild = pNode->mChildren[i];
  888|   174k|            Validate(pChild);
  889|   174k|            if (pChild->mParent != pNode) {
  ------------------
  |  Branch (889:17): [True: 0, False: 174k]
  ------------------
  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|   174k|        }
  894|   179k|    } else if (pNode->mChildren) {
  ------------------
  |  Branch (894:16): [True: 0, False: 179k]
  ------------------
  895|      0|        ReportError("aiNode::mChildren is not nullptr for empty node %s (aiNode::mNumChildren is %i)",
  896|      0|                nodeName, pNode->mNumChildren);
  897|      0|    }
  898|   184k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiString:
  901|   263k|void ValidateDSProcess::Validate(const aiString *pString) {
  902|   263k|    if (pString->length > AI_MAXLEN) {
  ------------------
  |  Branch (902:9): [True: 0, False: 263k]
  ------------------
  903|      0|        ReportError("aiString::length is too large (%u, maximum is %lu)",
  904|      0|                pString->length, AI_MAXLEN);
  905|      0|    }
  906|   263k|    const char *sz = pString->data;
  907|  2.80M|    while (true) {
  ------------------
  |  Branch (907:12): [True: 2.80M, Folded]
  ------------------
  908|  2.80M|        if ('\0' == *sz) {
  ------------------
  |  Branch (908:13): [True: 263k, False: 2.54M]
  ------------------
  909|   263k|            if (pString->length != (unsigned int)(sz - pString->data)) {
  ------------------
  |  Branch (909:17): [True: 0, False: 263k]
  ------------------
  910|      0|                ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
  911|      0|            }
  912|   263k|            break;
  913|  2.54M|        } else if (sz >= &pString->data[AI_MAXLEN]) {
  ------------------
  |  Branch (913:20): [True: 0, False: 2.54M]
  ------------------
  914|      0|            ReportError("aiString::data is invalid. There is no terminal character");
  915|      0|        }
  916|  2.54M|        ++sz;
  917|  2.54M|    }
  918|   263k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI6aiMeshEEvPPT_jPKcS7_:
  109|  3.82k|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|  3.82k|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 3.82k]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|  3.82k|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 3.82k]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|  82.6k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 78.8k, False: 3.82k]
  ------------------
  121|  78.8k|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 78.8k]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|  78.8k|        Validate(parray[i]);
  126|  78.8k|    }
  127|  3.82k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI10aiMaterialEEvPPT_jPKcS7_:
  109|  3.36k|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|  3.36k|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 3.36k]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|  3.36k|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 3.36k]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|  18.7k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 15.3k, False: 3.36k]
  ------------------
  121|  15.3k|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 15.3k]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|  15.3k|        Validate(parray[i]);
  126|  15.3k|    }
  127|  3.36k|}

_ZN6mapbox6earcutIjNSt3__16vectorINS2_I10aiVector2tIfENS1_9allocatorIS4_EEEENS5_IS7_EEEEEENS2_IT_NS5_ISA_EEEERKT0_:
  809|  35.5k|std::vector<N> earcut(const Polygon& poly) {
  810|  35.5k|    mapbox::detail::Earcut<N> earcut;
  811|  35.5k|    earcut(poly);
  812|  35.5k|    return std::move(earcut.indices);
  813|  35.5k|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEEC2Ev:
   99|  35.5k|        ObjectPool() { }
_ZN6mapbox6detail6EarcutIjEclINSt3__16vectorINS5_I10aiVector2tIfENS4_9allocatorIS7_EEEENS8_ISA_EEEEEEvRKT_:
  139|  35.5k|void Earcut<N>::operator()(const Polygon& points) {
  140|       |    // reset
  141|  35.5k|    indices.clear();
  142|  35.5k|    vertices = 0;
  143|       |
  144|  35.5k|    if (points.empty()) return;
  ------------------
  |  Branch (144:9): [True: 0, False: 35.5k]
  ------------------
  145|       |
  146|  35.5k|    double x;
  147|  35.5k|    double y;
  148|  35.5k|    int threshold = 80;
  149|  35.5k|    std::size_t len = 0;
  150|       |
  151|  71.1k|    for (size_t i = 0; threshold >= 0 && i < points.size(); i++) {
  ------------------
  |  Branch (151:24): [True: 66.1k, False: 4.91k]
  |  Branch (151:42): [True: 35.5k, False: 30.6k]
  ------------------
  152|  35.5k|        threshold -= static_cast<int>(points[i].size());
  153|  35.5k|        len += points[i].size();
  154|  35.5k|    }
  155|       |
  156|       |    //estimate size of nodes and indices
  157|  35.5k|    nodes.reset(len * 3 / 2);
  158|  35.5k|    indices.reserve(len + points[0].size());
  159|       |
  160|  35.5k|    Node* outerNode = linkedList(points[0], true);
  161|  35.5k|    if (!outerNode || outerNode->prev == outerNode->next) return;
  ------------------
  |  Branch (161:9): [True: 0, False: 35.5k]
  |  Branch (161:23): [True: 0, False: 35.5k]
  ------------------
  162|       |
  163|  35.5k|    if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
  ------------------
  |  Branch (163:9): [True: 0, False: 35.5k]
  ------------------
  164|       |
  165|       |    // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
  166|  35.5k|    hashing = threshold < 0;
  167|  35.5k|    if (hashing) {
  ------------------
  |  Branch (167:9): [True: 4.91k, False: 30.6k]
  ------------------
  168|  4.91k|        Node* p = outerNode->next;
  169|  4.91k|        minX = maxX = outerNode->x;
  170|  4.91k|        minY = maxY = outerNode->y;
  171|  2.21M|        do {
  172|  2.21M|            x = p->x;
  173|  2.21M|            y = p->y;
  174|  2.21M|            minX = std::min<double>(minX, x);
  175|  2.21M|            minY = std::min<double>(minY, y);
  176|  2.21M|            maxX = std::max<double>(maxX, x);
  177|  2.21M|            maxY = std::max<double>(maxY, y);
  178|  2.21M|            p = p->next;
  179|  2.21M|        } while (p != outerNode);
  ------------------
  |  Branch (179:18): [True: 2.21M, False: 4.91k]
  ------------------
  180|       |
  181|       |        // minX, minY and inv_size are later used to transform coords into integers for z-order calculation
  182|  4.91k|        inv_size = std::max<double>(maxX - minX, maxY - minY);
  183|  4.91k|        inv_size = inv_size != .0 ? (32767. / inv_size) : .0;
  ------------------
  |  Branch (183:20): [True: 4.84k, False: 69]
  ------------------
  184|  4.91k|    }
  185|       |
  186|  35.5k|    earcutLinked(outerNode);
  187|       |
  188|  35.5k|    nodes.clear();
  189|  35.5k|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE5resetEm:
  117|   106k|        void reset(std::size_t newBlockSize) {
  118|   106k|            for (auto allocation : allocations) {
  ------------------
  |  Branch (118:34): [True: 35.5k, False: 106k]
  ------------------
  119|  35.5k|                alloc_traits::deallocate(alloc, allocation, blockSize);
  120|  35.5k|            }
  121|   106k|            allocations.clear();
  122|   106k|            blockSize = std::max<std::size_t>(1, newBlockSize);
  123|   106k|            currentBlock = nullptr;
  124|   106k|            currentIndex = blockSize;
  125|   106k|        }
_ZN6mapbox6detail6EarcutIjE10linkedListINSt3__16vectorI10aiVector2tIfENS4_9allocatorIS7_EEEEEEPNS2_4NodeERKT_b:
  194|  35.5k|Earcut<N>::linkedList(const Ring& points, const bool clockwise) {
  195|  35.5k|    using Point = typename Ring::value_type;
  196|  35.5k|    double sum = 0;
  197|  35.5k|    const std::size_t len = points.size();
  198|  35.5k|    std::size_t i, j;
  199|  35.5k|    Node* last = nullptr;
  200|       |
  201|       |    // calculate original winding order of a polygon ring
  202|  3.29M|    for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) {
  ------------------
  |  Branch (202:21): [True: 35.5k, False: 0]
  |  Branch (202:44): [True: 3.25M, False: 35.5k]
  ------------------
  203|  3.25M|        const auto& p1 = points[i];
  204|  3.25M|        const auto& p2 = points[j];
  205|  3.25M|        const double p20 = util::nth<0, Point>::get(p2);
  206|  3.25M|        const double p10 = util::nth<0, Point>::get(p1);
  207|  3.25M|        const double p11 = util::nth<1, Point>::get(p1);
  208|  3.25M|        const double p21 = util::nth<1, Point>::get(p2);
  209|  3.25M|        sum += (p20 - p10) * (p11 + p21);
  210|  3.25M|    }
  211|       |
  212|       |    // link points into circular doubly-linked list in the specified winding order
  213|  35.5k|    if (clockwise == (sum > 0)) {
  ------------------
  |  Branch (213:9): [True: 31.2k, False: 4.33k]
  ------------------
  214|  2.73M|        for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
  ------------------
  |  Branch (214:21): [True: 2.70M, False: 31.2k]
  ------------------
  215|  31.2k|    } else {
  216|   562k|        for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
  ------------------
  |  Branch (216:23): [True: 557k, False: 4.33k]
  ------------------
  217|  4.33k|    }
  218|       |
  219|  35.5k|    if (last && equals(last, last->next)) {
  ------------------
  |  Branch (219:9): [True: 35.5k, False: 0]
  |  Branch (219:17): [True: 4.44k, False: 31.1k]
  ------------------
  220|  4.44k|        removeNode(last);
  221|  4.44k|        last = last->next;
  222|  4.44k|    }
  223|       |
  224|  35.5k|    vertices += len;
  225|       |
  226|  35.5k|    return last;
  227|  35.5k|}
_ZN6mapbox6detail6EarcutIjE10insertNodeI10aiVector2tIfEEEPNS2_4NodeEmRKT_S7_:
  781|  3.25M|Earcut<N>::insertNode(std::size_t i, const Point& pt, Node* last) {
  782|  3.25M|    Node* p = nodes.construct(static_cast<N>(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt));
  783|       |
  784|  3.25M|    if (!last) {
  ------------------
  |  Branch (784:9): [True: 35.5k, False: 3.22M]
  ------------------
  785|  35.5k|        p->prev = p;
  786|  35.5k|        p->next = p;
  787|       |
  788|  3.22M|    } else {
  789|  3.22M|        assert(last);
  ------------------
  |  Branch (789:9): [True: 3.22M, False: 0]
  ------------------
  790|  3.22M|        p->next = last->next;
  791|  3.22M|        p->prev = last;
  792|  3.22M|        last->next->prev = p;
  793|  3.22M|        last->next = p;
  794|  3.22M|    }
  795|  3.25M|    return p;
  796|  3.25M|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE9constructIJjffEEEPS4_DpOT_:
  107|  3.25M|        T* construct(Args&&... args) {
  108|  3.25M|            if (currentIndex >= blockSize) {
  ------------------
  |  Branch (108:17): [True: 35.5k, False: 3.22M]
  ------------------
  109|  35.5k|                currentBlock = alloc_traits::allocate(alloc, blockSize);
  110|  35.5k|                allocations.emplace_back(currentBlock);
  111|  35.5k|                currentIndex = 0;
  112|  35.5k|            }
  113|  3.25M|            T* object = &currentBlock[currentIndex++];
  114|  3.25M|            alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
  115|  3.25M|            return object;
  116|  3.25M|        }
_ZN6mapbox6detail6EarcutIjE4NodeC2Ejdd:
   37|  3.31M|        Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {}
_ZN6mapbox6detail6EarcutIjE6equalsEPKNS2_4NodeES5_:
  678|   133M|bool Earcut<N>::equals(const Node* p1, const Node* p2) {
  679|   133M|    return p1->x == p2->x && p1->y == p2->y;
  ------------------
  |  Branch (679:12): [True: 3.63M, False: 129M]
  |  Branch (679:30): [True: 2.18M, False: 1.45M]
  ------------------
  680|   133M|}
_ZN6mapbox6detail6EarcutIjE10removeNodeEPNS2_4NodeE:
  799|  2.77M|void Earcut<N>::removeNode(Node* p) {
  800|  2.77M|    p->next->prev = p->prev;
  801|  2.77M|    p->prev->next = p->next;
  802|       |
  803|  2.77M|    if (p->prevZ) p->prevZ->nextZ = p->nextZ;
  ------------------
  |  Branch (803:9): [True: 1.90M, False: 872k]
  ------------------
  804|  2.77M|    if (p->nextZ) p->nextZ->prevZ = p->prevZ;
  ------------------
  |  Branch (804:9): [True: 1.78M, False: 991k]
  ------------------
  805|  2.77M|}
_ZNK6mapbox6detail6EarcutIjE15pointInTriangleEdddddddd:
  655|  2.82G|bool Earcut<N>::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const {
  656|  2.82G|    return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
  ------------------
  |  Branch (656:12): [True: 2.02G, False: 803M]
  ------------------
  657|  2.02G|           (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
  ------------------
  |  Branch (657:12): [True: 1.29G, False: 725M]
  ------------------
  658|  1.29G|           (bx - px) * (cy - py) >= (cx - px) * (by - py);
  ------------------
  |  Branch (658:12): [True: 1.11G, False: 185M]
  ------------------
  659|  2.82G|}
_ZN6mapbox6detail6EarcutIjE13locallyInsideEPKNS2_4NodeES5_:
  729|   118M|bool Earcut<N>::locallyInside(const Node* a, const Node* b) {
  730|   118M|    return area(a->prev, a, a->next) < 0 ?
  ------------------
  |  Branch (730:12): [True: 1.77M, False: 116M]
  ------------------
  731|  1.77M|        area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 :
  ------------------
  |  Branch (731:9): [True: 1.40M, False: 363k]
  |  Branch (731:37): [True: 1.27M, False: 129k]
  ------------------
  732|   118M|        area(a, b, a->prev) < 0 || area(a, a->next, b) < 0;
  ------------------
  |  Branch (732:9): [True: 366k, False: 116M]
  |  Branch (732:36): [True: 244k, False: 116M]
  ------------------
  733|   118M|}
_ZNK6mapbox6detail6EarcutIjE4areaEPKNS2_4NodeES5_S5_:
  672|  2.60G|double Earcut<N>::area(const Node* p, const Node* q, const Node* r) const {
  673|  2.60G|    return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y);
  674|  2.60G|}
_ZN6mapbox6detail6EarcutIjE12splitPolygonEPNS2_4NodeES4_:
  757|  28.1k|Earcut<N>::splitPolygon(Node* a, Node* b) {
  758|  28.1k|    Node* a2 = nodes.construct(a->i, a->x, a->y);
  759|  28.1k|    Node* b2 = nodes.construct(b->i, b->x, b->y);
  760|  28.1k|    Node* an = a->next;
  761|  28.1k|    Node* bp = b->prev;
  762|       |
  763|  28.1k|    a->next = b;
  764|  28.1k|    b->prev = a;
  765|       |
  766|  28.1k|    a2->next = an;
  767|  28.1k|    an->prev = a2;
  768|       |
  769|  28.1k|    b2->next = a2;
  770|  28.1k|    a2->prev = b2;
  771|       |
  772|  28.1k|    bp->next = b2;
  773|  28.1k|    b2->prev = bp;
  774|       |
  775|  28.1k|    return b2;
  776|  28.1k|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE9constructIJRKjRKdSD_EEEPS4_DpOT_:
  107|  56.2k|        T* construct(Args&&... args) {
  108|  56.2k|            if (currentIndex >= blockSize) {
  ------------------
  |  Branch (108:17): [True: 0, False: 56.2k]
  ------------------
  109|      0|                currentBlock = alloc_traits::allocate(alloc, blockSize);
  110|      0|                allocations.emplace_back(currentBlock);
  111|      0|                currentIndex = 0;
  112|      0|            }
  113|  56.2k|            T* object = &currentBlock[currentIndex++];
  114|  56.2k|            alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
  115|  56.2k|            return object;
  116|  56.2k|        }
_ZN6mapbox6detail6EarcutIjE12filterPointsEPNS2_4NodeES4_:
  232|   293k|Earcut<N>::filterPoints(Node* start, Node* end) {
  233|   293k|    if (!end) end = start;
  ------------------
  |  Branch (233:9): [True: 237k, False: 56.2k]
  ------------------
  234|       |
  235|   293k|    Node* p = start;
  236|   293k|    bool again;
  237|  10.8M|    do {
  238|  10.8M|        again = false;
  239|       |
  240|  10.8M|        if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
  ------------------
  |  Branch (240:13): [True: 10.8M, False: 0]
  |  Branch (240:29): [True: 595k, False: 10.3M]
  |  Branch (240:51): [True: 433k, False: 9.87M]
  ------------------
  241|  1.02M|            removeNode(p);
  242|  1.02M|            p = end = p->prev;
  243|       |
  244|  1.02M|            if (p == p->next) break;
  ------------------
  |  Branch (244:17): [True: 6.74k, False: 1.02M]
  ------------------
  245|  1.02M|            again = true;
  246|       |
  247|  9.87M|        } else {
  248|  9.87M|            p = p->next;
  249|  9.87M|        }
  250|  10.8M|    } while (again || p != end);
  ------------------
  |  Branch (250:14): [True: 1.02M, False: 9.87M]
  |  Branch (250:23): [True: 9.58M, False: 287k]
  ------------------
  251|       |
  252|   293k|    return end;
  253|   293k|}
_ZN6mapbox6detail6EarcutIjE12earcutLinkedEPNS2_4NodeEi:
  257|   252k|void Earcut<N>::earcutLinked(Node* ear, int pass) {
  258|   252k|    if (!ear) return;
  ------------------
  |  Branch (258:9): [True: 0, False: 252k]
  ------------------
  259|       |
  260|       |    // interlink polygon nodes in z-order
  261|   252k|    if (!pass && hashing) indexCurve(ear);
  ------------------
  |  Branch (261:9): [True: 91.7k, False: 161k]
  |  Branch (261:18): [True: 20.5k, False: 71.2k]
  ------------------
  262|       |
  263|   252k|    Node* stop = ear;
  264|   252k|    Node* prev;
  265|   252k|    Node* next;
  266|       |
  267|       |    // iterate through ears, slicing them one by one
  268|   125M|    while (ear->prev != ear->next) {
  ------------------
  |  Branch (268:12): [True: 125M, False: 16.9k]
  ------------------
  269|   125M|        prev = ear->prev;
  270|   125M|        next = ear->next;
  271|       |
  272|   125M|        if (hashing ? isEarHashed(ear) : isEar(ear)) {
  ------------------
  |  Branch (272:13): [True: 120M, False: 5.40M]
  |  Branch (272:13): [True: 596k, False: 125M]
  ------------------
  273|       |            // cut off the triangle
  274|   596k|            indices.emplace_back(prev->i);
  275|   596k|            indices.emplace_back(ear->i);
  276|   596k|            indices.emplace_back(next->i);
  277|       |
  278|   596k|            removeNode(ear);
  279|       |
  280|       |            // skipping the next vertice leads to less sliver triangles
  281|   596k|            ear = next->next;
  282|   596k|            stop = next->next;
  283|       |
  284|   596k|            continue;
  285|   596k|        }
  286|       |
  287|   125M|        ear = next;
  288|       |
  289|       |        // if we looped through the whole remaining polygon and can't find any more ears
  290|   125M|        if (ear == stop) {
  ------------------
  |  Branch (290:13): [True: 235k, False: 125M]
  ------------------
  291|       |            // try filtering points and slicing again
  292|   235k|            if (!pass) earcutLinked(filterPoints(ear), 1);
  ------------------
  |  Branch (292:17): [True: 84.4k, False: 151k]
  ------------------
  293|       |
  294|       |            // if this didn't work, try curing all small self-intersections locally
  295|   151k|            else if (pass == 1) {
  ------------------
  |  Branch (295:22): [True: 76.6k, False: 74.8k]
  ------------------
  296|  76.6k|                ear = cureLocalIntersections(filterPoints(ear));
  297|  76.6k|                earcutLinked(ear, 2);
  298|       |
  299|       |            // as a last resort, try splitting the remaining polygon into two
  300|  76.6k|            } else if (pass == 2) splitEarcut(ear);
  ------------------
  |  Branch (300:24): [True: 74.8k, False: 0]
  ------------------
  301|       |
  302|   235k|            break;
  303|   235k|        }
  304|   125M|    }
  305|   252k|}
_ZN6mapbox6detail6EarcutIjE10indexCurveEPNS2_4NodeE:
  532|  20.5k|void Earcut<N>::indexCurve(Node* start) {
  533|  20.5k|    assert(start);
  ------------------
  |  Branch (533:5): [True: 20.5k, False: 0]
  ------------------
  534|  20.5k|    Node* p = start;
  535|       |
  536|  2.50M|    do {
  537|  2.50M|        p->z = p->z ? p->z : zOrder(p->x, p->y);
  ------------------
  |  Branch (537:16): [True: 155k, False: 2.34M]
  ------------------
  538|  2.50M|        p->prevZ = p->prev;
  539|  2.50M|        p->nextZ = p->next;
  540|  2.50M|        p = p->next;
  541|  2.50M|    } while (p != start);
  ------------------
  |  Branch (541:14): [True: 2.47M, False: 20.5k]
  ------------------
  542|       |
  543|  20.5k|    p->prevZ->nextZ = nullptr;
  544|  20.5k|    p->prevZ = nullptr;
  545|       |
  546|  20.5k|    sortLinked(p);
  547|  20.5k|}
_ZN6mapbox6detail6EarcutIjE6zOrderEdd:
  620|  7.83M|int32_t Earcut<N>::zOrder(const double x_, const double y_) {
  621|       |    // coords are transformed into non-negative 15-bit integer range
  622|  7.83M|    int32_t x = static_cast<int32_t>((x_ - minX) * inv_size);
  623|  7.83M|    int32_t y = static_cast<int32_t>((y_ - minY) * inv_size);
  624|       |
  625|  7.83M|    x = (x | (x << 8)) & 0x00FF00FF;
  626|  7.83M|    x = (x | (x << 4)) & 0x0F0F0F0F;
  627|  7.83M|    x = (x | (x << 2)) & 0x33333333;
  628|  7.83M|    x = (x | (x << 1)) & 0x55555555;
  629|       |
  630|  7.83M|    y = (y | (y << 8)) & 0x00FF00FF;
  631|  7.83M|    y = (y | (y << 4)) & 0x0F0F0F0F;
  632|  7.83M|    y = (y | (y << 2)) & 0x33333333;
  633|  7.83M|    y = (y | (y << 1)) & 0x55555555;
  634|       |
  635|  7.83M|    return x | (y << 1);
  636|  7.83M|}
_ZN6mapbox6detail6EarcutIjE10sortLinkedEPNS2_4NodeE:
  553|  20.5k|Earcut<N>::sortLinked(Node* list) {
  554|  20.5k|    assert(list);
  ------------------
  |  Branch (554:5): [True: 20.5k, False: 0]
  ------------------
  555|  20.5k|    Node* p;
  556|  20.5k|    Node* q;
  557|  20.5k|    Node* e;
  558|  20.5k|    Node* tail;
  559|  20.5k|    int i, numMerges, pSize, qSize;
  560|  20.5k|    int inSize = 1;
  561|       |
  562|   103k|    for (;;) {
  563|   103k|        p = list;
  564|   103k|        list = nullptr;
  565|   103k|        tail = nullptr;
  566|   103k|        numMerges = 0;
  567|       |
  568|  2.63M|        while (p) {
  ------------------
  |  Branch (568:16): [True: 2.52M, False: 103k]
  ------------------
  569|  2.52M|            numMerges++;
  570|  2.52M|            q = p;
  571|  2.52M|            pSize = 0;
  572|  17.2M|            for (i = 0; i < inSize; i++) {
  ------------------
  |  Branch (572:25): [True: 14.7M, False: 2.47M]
  ------------------
  573|  14.7M|                pSize++;
  574|  14.7M|                q = q->nextZ;
  575|  14.7M|                if (!q) break;
  ------------------
  |  Branch (575:21): [True: 48.1k, False: 14.7M]
  ------------------
  576|  14.7M|            }
  577|       |
  578|  2.52M|            qSize = inSize;
  579|       |
  580|  30.1M|            while (pSize > 0 || (qSize > 0 && q)) {
  ------------------
  |  Branch (580:20): [True: 21.5M, False: 8.69M]
  |  Branch (580:34): [True: 6.25M, False: 2.44M]
  |  Branch (580:47): [True: 6.16M, False: 85.6k]
  ------------------
  581|       |
  582|  27.6M|                if (pSize == 0) {
  ------------------
  |  Branch (582:21): [True: 6.16M, False: 21.5M]
  ------------------
  583|  6.16M|                    e = q;
  584|  6.16M|                    q = q->nextZ;
  585|  6.16M|                    qSize--;
  586|  21.5M|                } else if (qSize == 0 || !q) {
  ------------------
  |  Branch (586:28): [True: 674k, False: 20.8M]
  |  Branch (586:42): [True: 570k, False: 20.2M]
  ------------------
  587|  1.24M|                    e = p;
  588|  1.24M|                    p = p->nextZ;
  589|  1.24M|                    pSize--;
  590|  20.2M|                } else if (p->z <= q->z) {
  ------------------
  |  Branch (590:28): [True: 13.5M, False: 6.74M]
  ------------------
  591|  13.5M|                    e = p;
  592|  13.5M|                    p = p->nextZ;
  593|  13.5M|                    pSize--;
  594|  13.5M|                } else {
  595|  6.74M|                    e = q;
  596|  6.74M|                    q = q->nextZ;
  597|  6.74M|                    qSize--;
  598|  6.74M|                }
  599|       |
  600|  27.6M|                if (tail) tail->nextZ = e;
  ------------------
  |  Branch (600:21): [True: 27.5M, False: 103k]
  ------------------
  601|   103k|                else list = e;
  602|       |
  603|  27.6M|                e->prevZ = tail;
  604|  27.6M|                tail = e;
  605|  27.6M|            }
  606|       |
  607|  2.52M|            p = q;
  608|  2.52M|        }
  609|       |
  610|   103k|        tail->nextZ = nullptr;
  611|       |
  612|   103k|        if (numMerges <= 1) return list;
  ------------------
  |  Branch (612:13): [True: 20.5k, False: 82.5k]
  ------------------
  613|       |
  614|  82.5k|        inSize *= 2;
  615|  82.5k|    }
  616|  20.5k|}
_ZN6mapbox6detail6EarcutIjE11isEarHashedEPNS2_4NodeE:
  329|   120M|bool Earcut<N>::isEarHashed(Node* ear) {
  330|   120M|    const Node* a = ear->prev;
  331|   120M|    const Node* b = ear;
  332|   120M|    const Node* c = ear->next;
  333|       |
  334|   120M|    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  ------------------
  |  Branch (334:9): [True: 117M, False: 2.74M]
  ------------------
  335|       |
  336|       |    // triangle bbox; min & max are calculated like this for speed
  337|  2.74M|    const double minTX = std::min<double>(a->x, std::min<double>(b->x, c->x));
  338|  2.74M|    const double minTY = std::min<double>(a->y, std::min<double>(b->y, c->y));
  339|  2.74M|    const double maxTX = std::max<double>(a->x, std::max<double>(b->x, c->x));
  340|  2.74M|    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|  2.74M|    const int32_t minZ = zOrder(minTX, minTY);
  344|  2.74M|    const int32_t maxZ = zOrder(maxTX, maxTY);
  345|       |
  346|       |    // first look for points inside the triangle in increasing z-order
  347|  2.74M|    Node* p = ear->nextZ;
  348|       |
  349|  1.57G|    while (p && p->z <= maxZ) {
  ------------------
  |  Branch (349:12): [True: 1.57G, False: 372k]
  |  Branch (349:17): [True: 1.57G, False: 613k]
  ------------------
  350|  1.57G|        if (p != ear->prev && p != ear->next &&
  ------------------
  |  Branch (350:13): [True: 1.57G, False: 201k]
  |  Branch (350:31): [True: 1.57G, False: 980k]
  ------------------
  351|  1.57G|            pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (351:13): [True: 718M, False: 852M]
  ------------------
  352|   718M|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (352:13): [True: 1.76M, False: 716M]
  ------------------
  353|  1.56G|        p = p->nextZ;
  354|  1.56G|    }
  355|       |
  356|       |    // then look for points in decreasing z-order
  357|   986k|    p = ear->prevZ;
  358|       |
  359|  1.21G|    while (p && p->z >= minZ) {
  ------------------
  |  Branch (359:12): [True: 1.21G, False: 203k]
  |  Branch (359:17): [True: 1.21G, False: 33.5k]
  ------------------
  360|  1.21G|        if (p != ear->prev && p != ear->next &&
  ------------------
  |  Branch (360:13): [True: 1.21G, False: 320k]
  |  Branch (360:31): [True: 1.21G, False: 155k]
  ------------------
  361|  1.21G|            pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (361:13): [True: 390M, False: 826M]
  ------------------
  362|   390M|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (362:13): [True: 749k, False: 389M]
  ------------------
  363|  1.21G|        p = p->prevZ;
  364|  1.21G|    }
  365|       |
  366|   236k|    return true;
  367|   986k|}
_ZN6mapbox6detail6EarcutIjE5isEarEPNS2_4NodeE:
  309|  5.40M|bool Earcut<N>::isEar(Node* ear) {
  310|  5.40M|    const Node* a = ear->prev;
  311|  5.40M|    const Node* b = ear;
  312|  5.40M|    const Node* c = ear->next;
  313|       |
  314|  5.40M|    if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
  ------------------
  |  Branch (314:9): [True: 2.70M, False: 2.69M]
  ------------------
  315|       |
  316|       |    // now make sure we don't have other points inside the potential ear
  317|  2.69M|    Node* p = ear->next->next;
  318|       |
  319|  42.7M|    while (p != ear->prev) {
  ------------------
  |  Branch (319:12): [True: 42.3M, False: 359k]
  ------------------
  320|  42.3M|        if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
  ------------------
  |  Branch (320:13): [True: 5.60M, False: 36.7M]
  ------------------
  321|  5.60M|            area(p->prev, p, p->next) >= 0) return false;
  ------------------
  |  Branch (321:13): [True: 2.34M, False: 3.26M]
  ------------------
  322|  40.0M|        p = p->next;
  323|  40.0M|    }
  324|       |
  325|   359k|    return true;
  326|  2.69M|}
_ZN6mapbox6detail6EarcutIjE22cureLocalIntersectionsEPNS2_4NodeE:
  372|  76.6k|Earcut<N>::cureLocalIntersections(Node* start) {
  373|  76.6k|    Node* p = start;
  374|   121M|    do {
  375|   121M|        Node* a = p->prev;
  376|   121M|        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|   121M|        if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) {
  ------------------
  |  Branch (379:13): [True: 120M, False: 1.45M]
  |  Branch (379:30): [True: 116M, False: 3.60M]
  |  Branch (379:62): [True: 974k, False: 115M]
  |  Branch (379:85): [True: 571k, False: 402k]
  ------------------
  380|   571k|            indices.emplace_back(a->i);
  381|   571k|            indices.emplace_back(p->i);
  382|   571k|            indices.emplace_back(b->i);
  383|       |
  384|       |            // remove two nodes involved
  385|   571k|            removeNode(p);
  386|   571k|            removeNode(p->next);
  387|       |
  388|   571k|            p = start = b;
  389|   571k|        }
  390|   121M|        p = p->next;
  391|   121M|    } while (p != start);
  ------------------
  |  Branch (391:14): [True: 121M, False: 76.6k]
  ------------------
  392|       |
  393|  76.6k|    return filterPoints(p);
  394|  76.6k|}
_ZN6mapbox6detail6EarcutIjE10intersectsEPKNS2_4NodeES5_S5_S5_:
  684|   250M|bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) {
  685|   250M|    int o1 = sign(area(p1, q1, p2));
  686|   250M|    int o2 = sign(area(p1, q1, q2));
  687|   250M|    int o3 = sign(area(p2, q2, p1));
  688|   250M|    int o4 = sign(area(p2, q2, q1));
  689|       |
  690|   250M|    if (o1 != o2 && o3 != o4) return true; // general case
  ------------------
  |  Branch (690:9): [True: 51.4M, False: 199M]
  |  Branch (690:21): [True: 42.9M, False: 8.53M]
  ------------------
  691|       |
  692|   207M|    if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
  ------------------
  |  Branch (692:9): [True: 129M, False: 78.5M]
  |  Branch (692:20): [True: 129M, False: 306k]
  ------------------
  693|  78.8M|    if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
  ------------------
  |  Branch (693:9): [True: 278k, False: 78.5M]
  |  Branch (693:20): [True: 93.1k, False: 185k]
  ------------------
  694|  78.7M|    if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
  ------------------
  |  Branch (694:9): [True: 25.8M, False: 52.8M]
  |  Branch (694:20): [True: 6.84k, False: 25.8M]
  ------------------
  695|  78.7M|    if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
  ------------------
  |  Branch (695:9): [True: 25.8M, False: 52.8M]
  |  Branch (695:20): [True: 246, False: 25.8M]
  ------------------
  696|       |
  697|  78.7M|    return false;
  698|  78.7M|}
_ZN6mapbox6detail6EarcutIjE4signEd:
  710|  1.00G|int Earcut<N>::sign(double val) {
  711|  1.00G|    return (0.0 < val) - (val < 0.0);
  712|  1.00G|}
_ZN6mapbox6detail6EarcutIjE9onSegmentEPKNS2_4NodeES5_S5_:
  702|   181M|bool Earcut<N>::onSegment(const Node* p, const Node* q, const Node* r) {
  703|   181M|    return q->x <= std::max<double>(p->x, r->x) &&
  ------------------
  |  Branch (703:12): [True: 159M, False: 21.6M]
  ------------------
  704|   159M|        q->x >= std::min<double>(p->x, r->x) &&
  ------------------
  |  Branch (704:9): [True: 136M, False: 23.2M]
  ------------------
  705|   136M|        q->y <= std::max<double>(p->y, r->y) &&
  ------------------
  |  Branch (705:9): [True: 132M, False: 3.67M]
  ------------------
  706|   132M|        q->y >= std::min<double>(p->y, r->y);
  ------------------
  |  Branch (706:9): [True: 129M, False: 3.62M]
  ------------------
  707|   181M|}
_ZN6mapbox6detail6EarcutIjE11splitEarcutEPNS2_4NodeE:
  398|  74.8k|void Earcut<N>::splitEarcut(Node* start) {
  399|       |    // look for a valid diagonal that divides the polygon into two
  400|  74.8k|    Node* a = start;
  401|   729k|    do {
  402|   729k|        Node* b = a->next->next;
  403|  56.7M|        while (b != a->prev) {
  ------------------
  |  Branch (403:16): [True: 56.0M, False: 700k]
  ------------------
  404|  56.0M|            if (a->i != b->i && isValidDiagonal(a, b)) {
  ------------------
  |  Branch (404:17): [True: 56.0M, False: 0]
  |  Branch (404:33): [True: 28.1k, False: 56.0M]
  ------------------
  405|       |                // split the polygon in two by the diagonal
  406|  28.1k|                Node* c = splitPolygon(a, b);
  407|       |
  408|       |                // filter colinear points around the cuts
  409|  28.1k|                a = filterPoints(a, a->next);
  410|  28.1k|                c = filterPoints(c, c->next);
  411|       |
  412|       |                // run earcut on each half
  413|  28.1k|                earcutLinked(a);
  414|  28.1k|                earcutLinked(c);
  415|  28.1k|                return;
  416|  28.1k|            }
  417|  56.0M|            b = b->next;
  418|  56.0M|        }
  419|   700k|        a = a->next;
  420|   700k|    } while (a != start);
  ------------------
  |  Branch (420:14): [True: 654k, False: 46.7k]
  ------------------
  421|  74.8k|}
_ZN6mapbox6detail6EarcutIjE15isValidDiagonalEPNS2_4NodeES4_:
  663|  56.0M|bool Earcut<N>::isValidDiagonal(Node* a, Node* b) {
  664|  56.0M|    return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges
  ------------------
  |  Branch (664:12): [True: 56.0M, False: 0]
  |  Branch (664:34): [True: 56.0M, False: 0]
  |  Branch (664:56): [True: 629k, False: 55.3M]
  ------------------
  665|   629k|           ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
  ------------------
  |  Branch (665:14): [True: 216k, False: 412k]
  |  Branch (665:37): [True: 127k, False: 89.1k]
  |  Branch (665:60): [True: 25.1k, False: 102k]
  ------------------
  666|  25.1k|            (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors
  ------------------
  |  Branch (666:14): [True: 19.3k, False: 5.76k]
  |  Branch (666:50): [True: 256, False: 5.51k]
  ------------------
  667|   609k|            (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case
  ------------------
  |  Branch (667:14): [True: 126k, False: 483k]
  |  Branch (667:30): [True: 42.1k, False: 84.1k]
  |  Branch (667:63): [True: 8.48k, False: 33.6k]
  ------------------
  668|  56.0M|}
_ZN6mapbox6detail6EarcutIjE17intersectsPolygonEPKNS2_4NodeES5_:
  716|  56.0M|bool Earcut<N>::intersectsPolygon(const Node* a, const Node* b) {
  717|  56.0M|    const Node* p = a;
  718|   192M|    do {
  719|   192M|        if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i &&
  ------------------
  |  Branch (719:13): [True: 136M, False: 56.0M]
  |  Branch (719:29): [True: 136M, False: 629k]
  |  Branch (719:51): [True: 133M, False: 2.87M]
  |  Branch (719:67): [True: 130M, False: 2.87M]
  ------------------
  720|   130M|                intersects(p, p->next, a, b)) return true;
  ------------------
  |  Branch (720:17): [True: 55.3M, False: 75.1M]
  ------------------
  721|   137M|        p = p->next;
  722|   137M|    } while (p != a);
  ------------------
  |  Branch (722:14): [True: 136M, False: 629k]
  ------------------
  723|       |
  724|   629k|    return false;
  725|  56.0M|}
_ZN6mapbox6detail6EarcutIjE12middleInsideEPKNS2_4NodeES5_:
  737|   127k|bool Earcut<N>::middleInside(const Node* a, const Node* b) {
  738|   127k|    const Node* p = a;
  739|   127k|    bool inside = false;
  740|   127k|    double px = (a->x + b->x) / 2;
  741|   127k|    double py = (a->y + b->y) / 2;
  742|  3.09M|    do {
  743|  3.09M|        if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y &&
  ------------------
  |  Branch (743:13): [True: 718k, False: 2.37M]
  |  Branch (743:51): [True: 718k, False: 0]
  ------------------
  744|   718k|                (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x))
  ------------------
  |  Branch (744:17): [True: 336k, False: 382k]
  ------------------
  745|   336k|            inside = !inside;
  746|  3.09M|        p = p->next;
  747|  3.09M|    } while (p != a);
  ------------------
  |  Branch (747:14): [True: 2.96M, False: 127k]
  ------------------
  748|       |
  749|   127k|    return inside;
  750|   127k|}
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEE5clearEv:
  126|  71.1k|        void clear() { reset(blockSize); }
_ZN6mapbox6detail6EarcutIjE10ObjectPoolINS2_4NodeENSt3__19allocatorIS4_EEED2Ev:
  103|  35.5k|        ~ObjectPool() {
  104|  35.5k|            clear();
  105|  35.5k|        }

_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|  24.1k|	PUGI_IMPL_FN xml_node::xml_node(): _root(nullptr)
 5594|  24.1k|	{
 5595|  24.1k|	}
_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|	}

_ZN4utf88utf32to8INSt3__120back_insert_iteratorINS1_6vectorIcNS1_9allocatorIcEEEEEEPjEET_T0_SA_S9_:
  232|    105|    {
  233|  3.73k|        while (start != end)
  ------------------
  |  Branch (233:16): [True: 3.62k, False: 105]
  ------------------
  234|  3.62k|            result = utf8::append(*(start++), result);
  235|       |
  236|    105|        return result;
  237|    105|    }
_ZN4utf86appendINSt3__120back_insert_iteratorINS1_6vectorIcNS1_9allocatorIcEEEEEEEET_jS8_:
   75|  3.62k|    {
   76|  3.62k|        if (!utf8::internal::is_code_point_valid(cp))
  ------------------
  |  Branch (76:13): [True: 105, False: 3.52k]
  ------------------
   77|    105|            throw invalid_code_point(cp);
   78|       |
   79|  3.52k|        return internal::append(cp, result);
   80|  3.62k|    }
_ZN4utf818invalid_code_pointC2Ej:
   44|    105|        invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
_ZNK4utf818invalid_code_point4whatEv:
   45|    210|        virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
_ZN4utf88utf16to8INSt3__111__wrap_iterIPcEENS1_20back_insert_iteratorINS1_6vectorIhNS1_9allocatorIhEEEEEEEET0_T_SC_SB_:
  190|  2.09k|    {
  191|  14.2M|        while (start != end) {
  ------------------
  |  Branch (191:16): [True: 14.2M, False: 2.09k]
  ------------------
  192|  14.2M|            uint32_t cp = utf8::internal::mask16(*start++);
  193|       |            // Take care of surrogate pairs first
  194|  14.2M|            if (utf8::internal::is_lead_surrogate(cp)) {
  ------------------
  |  Branch (194:17): [True: 0, False: 14.2M]
  ------------------
  195|      0|                if (start != end) {
  ------------------
  |  Branch (195:21): [True: 0, False: 0]
  ------------------
  196|      0|                    uint32_t trail_surrogate = utf8::internal::mask16(*start++);
  197|      0|                    if (utf8::internal::is_trail_surrogate(trail_surrogate))
  ------------------
  |  Branch (197:25): [True: 0, False: 0]
  ------------------
  198|      0|                        cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
  199|      0|                    else
  200|      0|                        throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
  201|      0|                }
  202|      0|                else
  203|      0|                    throw invalid_utf16(static_cast<uint16_t>(cp));
  204|       |
  205|      0|            }
  206|       |            // Lone trail surrogate
  207|  14.2M|            else if (utf8::internal::is_trail_surrogate(cp))
  ------------------
  |  Branch (207:22): [True: 0, False: 14.2M]
  ------------------
  208|      0|                throw invalid_utf16(static_cast<uint16_t>(cp));
  209|       |
  210|  14.2M|            result = utf8::append(cp, result);
  211|  14.2M|        }
  212|  2.09k|        return result;
  213|  2.09k|    }
_ZN4utf86appendINSt3__120back_insert_iteratorINS1_6vectorIhNS1_9allocatorIhEEEEEEEET_jS8_:
   75|  14.2M|    {
   76|  14.2M|        if (!utf8::internal::is_code_point_valid(cp))
  ------------------
  |  Branch (76:13): [True: 0, False: 14.2M]
  ------------------
   77|      0|            throw invalid_code_point(cp);
   78|       |
   79|  14.2M|        return internal::append(cp, result);
   80|  14.2M|    }

_ZN4utf88internal19is_code_point_validIjEEbT_:
  111|  14.2M|    {
  112|  14.2M|        return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
  ------------------
  |  Branch (112:17): [True: 14.2M, False: 101]
  |  Branch (112:41): [True: 14.2M, False: 4]
  ------------------
  113|  14.2M|    }
_ZN4utf88internal12is_surrogateIjEEbT_:
  105|  14.2M|    {
  106|  14.2M|        return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
  ------------------
  |  Branch (106:17): [True: 10.0M, False: 4.23M]
  |  Branch (106:45): [True: 4, False: 10.0M]
  ------------------
  107|  14.2M|    }
_ZN4utf88internal6appendINSt3__16vectorIcNS2_9allocatorIcEEEEEENS2_20back_insert_iteratorIT_EEjS9_:
  336|  3.52k|            (uint32_t cp, std::back_insert_iterator<container_type> result) {
  337|  3.52k|        return append<std::back_insert_iterator<container_type>,
  338|  3.52k|            typename container_type::value_type>(cp, result);
  339|  3.52k|    }
_ZN4utf88internal6appendINSt3__120back_insert_iteratorINS2_6vectorIcNS2_9allocatorIcEEEEEEcEET_jS9_:
  304|  3.52k|    octet_iterator append(uint32_t cp, octet_iterator result) {
  305|  3.52k|        if (cp < 0x80)                        // one octet
  ------------------
  |  Branch (305:13): [True: 2.27k, False: 1.24k]
  ------------------
  306|  2.27k|            *(result++) = static_cast<octet_type>(cp);
  307|  1.24k|        else if (cp < 0x800) {                // two octets
  ------------------
  |  Branch (307:18): [True: 343, False: 902]
  ------------------
  308|    343|            *(result++) = static_cast<octet_type>((cp >> 6)          | 0xc0);
  309|    343|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  310|    343|        }
  311|    902|        else if (cp < 0x10000) {              // three octets
  ------------------
  |  Branch (311:18): [True: 549, False: 353]
  ------------------
  312|    549|            *(result++) = static_cast<octet_type>((cp >> 12)         | 0xe0);
  313|    549|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  314|    549|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  315|    549|        }
  316|    353|        else {                                // four octets
  317|    353|            *(result++) = static_cast<octet_type>((cp >> 18)         | 0xf0);
  318|    353|            *(result++) = static_cast<octet_type>(((cp >> 12) & 0x3f)| 0x80);
  319|    353|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  320|    353|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  321|    353|        }
  322|  3.52k|        return result;
  323|  3.52k|    }
_ZN4utf88internal6mask16IcEEtT_:
   82|  14.2M|    {
   83|  14.2M|        return static_cast<uint16_t>(0xffff & oc);
   84|  14.2M|    }
_ZN4utf88internal17is_lead_surrogateIjEEbT_:
   93|  14.2M|    {
   94|  14.2M|        return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
  ------------------
  |  Branch (94:17): [True: 10.0M, False: 4.22M]
  |  Branch (94:45): [True: 0, False: 10.0M]
  ------------------
   95|  14.2M|    }
_ZN4utf88internal18is_trail_surrogateIjEEbT_:
   99|  14.2M|    {
  100|  14.2M|        return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
  ------------------
  |  Branch (100:17): [True: 10.0M, False: 4.22M]
  |  Branch (100:46): [True: 0, False: 10.0M]
  ------------------
  101|  14.2M|    }
_ZN4utf88internal6appendINSt3__16vectorIhNS2_9allocatorIhEEEEEENS2_20back_insert_iteratorIT_EEjS9_:
  336|  14.2M|            (uint32_t cp, std::back_insert_iterator<container_type> result) {
  337|  14.2M|        return append<std::back_insert_iterator<container_type>,
  338|  14.2M|            typename container_type::value_type>(cp, result);
  339|  14.2M|    }
_ZN4utf88internal6appendINSt3__120back_insert_iteratorINS2_6vectorIhNS2_9allocatorIhEEEEEEhEET_jS9_:
  304|  14.2M|    octet_iterator append(uint32_t cp, octet_iterator result) {
  305|  14.2M|        if (cp < 0x80)                        // one octet
  ------------------
  |  Branch (305:13): [True: 4.22M, False: 10.0M]
  ------------------
  306|  4.22M|            *(result++) = static_cast<octet_type>(cp);
  307|  10.0M|        else if (cp < 0x800) {                // two octets
  ------------------
  |  Branch (307:18): [True: 0, False: 10.0M]
  ------------------
  308|      0|            *(result++) = static_cast<octet_type>((cp >> 6)          | 0xc0);
  309|      0|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  310|      0|        }
  311|  10.0M|        else if (cp < 0x10000) {              // three octets
  ------------------
  |  Branch (311:18): [True: 10.0M, False: 0]
  ------------------
  312|  10.0M|            *(result++) = static_cast<octet_type>((cp >> 12)         | 0xe0);
  313|  10.0M|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  314|  10.0M|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  315|  10.0M|        }
  316|      0|        else {                                // four octets
  317|      0|            *(result++) = static_cast<octet_type>((cp >> 18)         | 0xf0);
  318|      0|            *(result++) = static_cast<octet_type>(((cp >> 12) & 0x3f)| 0x80);
  319|      0|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  320|      0|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  321|      0|        }
  322|  14.2M|        return result;
  323|  14.2M|    }

LLVMFuzzerTestOneInput:
   48|  12.0k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t dataSize) {
   49|       |    // Limit input size to 1MB
   50|  12.0k|    if (dataSize > 1024 * 1024) {
  ------------------
  |  Branch (50:9): [True: 0, False: 12.0k]
  ------------------
   51|      0|        return 0;
   52|      0|    }
   53|       |
   54|  12.0k|    Importer importer;
   55|       |    // Force OBJ format
   56|  12.0k|    if (!AssimpFuzz::ForceFormat(importer, "obj")) {
  ------------------
  |  Branch (56:9): [True: 0, False: 12.0k]
  ------------------
   57|      0|        return 0;
   58|      0|    }
   59|       |
   60|  12.0k|    unsigned int flags = aiProcessPreset_TargetRealtime_Quality | aiProcess_ValidateDataStructure;
   61|       |    // We pass "obj" hint as well, though only OBJ loader is registered now.
   62|  12.0k|    const aiScene *sc = importer.ReadFileFromMemory(data, dataSize, flags, "obj");
   63|       |
   64|  12.0k|    return 0;
   65|  12.0k|}

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

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

