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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp11STLImporterC2Ev:
  130|  4.62k|        mFileSize(0),
  131|  4.62k|        mScene() {
  132|       |    // empty
  133|  4.62k|}
_ZN6Assimp11STLImporterD2Ev:
  137|  4.62k|STLImporter::~STLImporter() = default;
_ZNK6Assimp11STLImporter7GetInfoEv:
  147|  13.8k|const aiImporterDesc *STLImporter::GetInfo() const {
  148|  13.8k|    return &desc;
  149|  13.8k|}
_ZN6Assimp14addFacesToMeshEP6aiMesh:
  151|   314k|void addFacesToMesh(aiMesh *pMesh) {
  152|   314k|    pMesh->mFaces = new aiFace[pMesh->mNumFaces];
  153|  1.04M|    for (unsigned int i = 0, p = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (153:37): [True: 725k, False: 314k]
  ------------------
  154|       |
  155|   725k|        aiFace &face = pMesh->mFaces[i];
  156|   725k|        face.mIndices = new unsigned int[face.mNumIndices = 3];
  157|  2.90M|        for (unsigned int o = 0; o < 3; ++o, ++p) {
  ------------------
  |  Branch (157:34): [True: 2.17M, False: 725k]
  ------------------
  158|  2.17M|            face.mIndices[o] = p;
  159|  2.17M|        }
  160|   725k|    }
  161|   314k|}
_ZN6Assimp11STLImporter14InternReadFileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEP7aiScenePNS_8IOSystemE:
  165|  4.62k|void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  166|  4.62k|    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  167|       |
  168|       |    // Check whether we can read from the file
  169|  4.62k|    if (file == nullptr) {
  ------------------
  |  Branch (169:9): [True: 0, False: 4.62k]
  ------------------
  170|      0|        throw DeadlyImportError("Failed to open STL file ", pFile, ".");
  171|      0|    }
  172|       |
  173|  4.62k|    mFileSize = file->FileSize();
  174|       |
  175|       |    // allocate storage and copy the contents of the file to a memory buffer
  176|       |    // (terminate it with zero)
  177|  4.62k|    std::vector<char> buffer2;
  178|  4.62k|    TextFileToBuffer(file.get(), buffer2);
  179|       |
  180|  4.62k|    mScene = pScene;
  181|  4.62k|    mBuffer = &buffer2[0];
  182|       |
  183|       |    // the default vertex color is light gray.
  184|  4.62k|    mClrColorDefault.r = mClrColorDefault.g = mClrColorDefault.b = mClrColorDefault.a = 0.6f;
  185|       |
  186|       |    // allocate a single node
  187|  4.62k|    mScene->mRootNode = new aiNode();
  188|       |
  189|  4.62k|    bool bMatClr = false;
  190|       |
  191|  4.62k|    if (IsBinarySTL(mBuffer, mFileSize)) {
  ------------------
  |  Branch (191:9): [True: 923, False: 3.70k]
  ------------------
  192|    923|        bMatClr = LoadBinaryFile();
  193|  3.70k|    } else if (IsAsciiSTL(mBuffer, mFileSize)) {
  ------------------
  |  Branch (193:16): [True: 3.18k, False: 521]
  ------------------
  194|  3.18k|        LoadASCIIFile(mScene->mRootNode);
  195|  3.18k|    } else {
  196|    521|        throw DeadlyImportError("Failed to determine STL storage representation for ", pFile, ".");
  197|    521|    }
  198|       |
  199|       |    // create a single default material, using a white diffuse color for consistency with
  200|       |    // other geometric types (e.g., PLY).
  201|  4.10k|    aiMaterial *pcMat = new aiMaterial();
  202|  4.10k|    aiString s;
  203|  4.10k|    s.Set(AI_DEFAULT_MATERIAL_NAME);
  204|  4.10k|    pcMat->AddProperty(&s, AI_MATKEY_NAME);
  205|       |
  206|  4.10k|    aiColor4D clrDiffuse(ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0));
  207|  4.10k|    if (bMatClr) {
  ------------------
  |  Branch (207:9): [True: 39, False: 4.06k]
  ------------------
  208|     39|        clrDiffuse = mClrColorDefault;
  209|     39|    }
  210|  4.10k|    pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
  211|  4.10k|    pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_SPECULAR);
  212|  4.10k|    clrDiffuse = aiColor4D(0.05f, 0.05f, 0.05f, 1.0f);
  213|  4.10k|    pcMat->AddProperty(&clrDiffuse, 1, AI_MATKEY_COLOR_AMBIENT);
  214|       |
  215|  4.10k|    mScene->mNumMaterials = 1;
  216|  4.10k|    mScene->mMaterials = new aiMaterial *[1];
  217|  4.10k|    mScene->mMaterials[0] = pcMat;
  218|       |
  219|  4.10k|    mBuffer = nullptr;
  220|  4.10k|}
_ZN6Assimp11STLImporter13LoadASCIIFileEP6aiNode:
  224|  3.18k|void STLImporter::LoadASCIIFile(aiNode *root) {
  225|  3.18k|    std::vector<aiMesh *> meshes;
  226|  3.18k|    std::vector<aiNode *> nodes;
  227|  3.18k|    const char *sz = mBuffer;
  228|  3.18k|    const char *bufferEnd = mBuffer + mFileSize;
  229|  3.18k|    std::vector<aiVector3D> positionBuffer;
  230|  3.18k|    std::vector<aiVector3D> normalBuffer;
  231|       |
  232|       |    // try to guess how many vertices we could have
  233|       |    // assume we'll need 160 bytes for each face
  234|  3.18k|    size_t sizeEstimate = std::max(1ull, mFileSize / 160ull) * 3ull;
  235|  3.18k|    positionBuffer.reserve(sizeEstimate);
  236|  3.18k|    normalBuffer.reserve(sizeEstimate);
  237|       |
  238|   317k|    while (IsAsciiSTL(sz, static_cast<unsigned int>(bufferEnd - sz))) {
  ------------------
  |  Branch (238:12): [True: 314k, False: 2.96k]
  ------------------
  239|   314k|        std::vector<unsigned int> meshIndices;
  240|   314k|        aiMesh *pMesh = new aiMesh();
  241|   314k|        pMesh->mMaterialIndex = 0;
  242|   314k|        meshIndices.push_back((unsigned int)meshes.size());
  243|   314k|        meshes.push_back(pMesh);
  244|   314k|        aiNode *node = new aiNode;
  245|   314k|        node->mParent = root;
  246|   314k|        nodes.push_back(node);
  247|   314k|        SkipSpaces(&sz, bufferEnd);
  248|   314k|        ai_assert(!IsLineEnd(sz));
  249|       |
  250|   314k|        sz += 5; // skip the "solid"
  251|   314k|        SkipSpaces(&sz, bufferEnd);
  252|   314k|        const char *szMe = sz;
  253|  1.19M|        while (!IsSpaceOrNewLine(*sz)) {
  ------------------
  |  Branch (253:16): [True: 885k, False: 314k]
  ------------------
  254|   885k|            sz++;
  255|   885k|        }
  256|       |
  257|   314k|        size_t temp = (size_t)(sz - szMe);
  258|       |        // setup the name of the node
  259|   314k|        if (temp) {
  ------------------
  |  Branch (259:13): [True: 180k, False: 134k]
  ------------------
  260|   180k|            if (temp >= AI_MAXLEN) {
  ------------------
  |  Branch (260:17): [True: 8, False: 180k]
  ------------------
  261|      8|                throw DeadlyImportError("STL: Node name too long");
  262|      8|            }
  263|   180k|            std::string name(szMe, temp);
  264|   180k|            node->mName.Set(name.c_str());
  265|   180k|            pMesh->mName.Set(name.c_str());
  266|   180k|        } else {
  267|   134k|            mScene->mRootNode->mName.Set("<STL_ASCII>");
  268|   134k|        }
  269|       |
  270|   314k|        unsigned int faceVertexCounter = 3;
  271|  8.42M|        for (;;) {
  272|       |            // go to the next token
  273|  8.42M|            if (!SkipSpacesAndLineEnd(&sz, bufferEnd)) {
  ------------------
  |  Branch (273:17): [True: 2.09k, False: 8.42M]
  ------------------
  274|       |                // seems we're finished although there was no end marker
  275|  2.09k|                ASSIMP_LOG_WARN("STL: unexpected EOF. \'endsolid\' keyword was expected");
  276|  2.09k|                break;
  277|  2.09k|            }
  278|       |            // facet normal -0.13 -0.13 -0.98
  279|  8.42M|            if (!strncmp(sz, "facet", 5) && IsSpaceOrNewLine(*(sz + 5)) && *(sz + 5) != '\0') {
  ------------------
  |  Branch (279:17): [True: 779k, False: 7.64M]
  |  Branch (279:45): [True: 775k, False: 4.60k]
  |  Branch (279:76): [True: 774k, False: 5]
  ------------------
  280|       |
  281|   774k|                if (faceVertexCounter != 3) {
  ------------------
  |  Branch (281:21): [True: 293k, False: 481k]
  ------------------
  282|   293k|                    ASSIMP_LOG_WARN("STL: A new facet begins but the old is not yet complete");
  283|   293k|                }
  284|   774k|                faceVertexCounter = 0;
  285|       |
  286|   774k|                sz += 6;
  287|   774k|                SkipSpaces(&sz, bufferEnd);
  288|   774k|                if (strncmp(sz, "normal", 6)) {
  ------------------
  |  Branch (288:21): [True: 46.7k, False: 728k]
  ------------------
  289|  46.7k|                    ASSIMP_LOG_WARN("STL: a facet normal vector was expected but not found");
  290|   728k|                } else {
  291|   728k|                    if (sz[6] == '\0') {
  ------------------
  |  Branch (291:25): [True: 2, False: 728k]
  ------------------
  292|      2|                        throw DeadlyImportError("STL: unexpected EOF while parsing facet");
  293|      2|                    }
  294|   728k|                    aiVector3D vn;
  295|   728k|                    sz += 7;
  296|   728k|                    SkipSpaces(&sz, bufferEnd);
  297|   728k|                    sz = fast_atoreal_move(sz, vn.x);
  298|   728k|                    SkipSpaces(&sz, bufferEnd);
  299|   728k|                    sz = fast_atoreal_move(sz, vn.y);
  300|   728k|                    SkipSpaces(&sz, bufferEnd);
  301|   728k|                    sz = fast_atoreal_move(sz, vn.z);
  302|   728k|                    normalBuffer.emplace_back(vn);
  303|   728k|                    normalBuffer.emplace_back(vn);
  304|   728k|                    normalBuffer.emplace_back(vn);
  305|   728k|                }
  306|  7.64M|            } else if (!strncmp(sz, "vertex", 6) && IsSpaceOrNewLine(*(sz + 6))) { // vertex 1.50000 1.50000 0.00000
  ------------------
  |  Branch (306:24): [True: 1.75M, False: 5.89M]
  |  Branch (306:53): [True: 1.73M, False: 20.9k]
  ------------------
  307|  1.73M|                if (faceVertexCounter >= 3) {
  ------------------
  |  Branch (307:21): [True: 285k, False: 1.45M]
  ------------------
  308|   285k|                    ASSIMP_LOG_ERROR("STL: a facet with more than 3 vertices has been found");
  309|   285k|                    ++sz;
  310|  1.45M|                } else {
  311|  1.45M|                    if (sz[6] == '\0') {
  ------------------
  |  Branch (311:25): [True: 2, False: 1.45M]
  ------------------
  312|      2|                        throw DeadlyImportError("STL: unexpected EOF while parsing facet");
  313|      2|                    }
  314|  1.45M|                    sz += 7;
  315|  1.45M|                    SkipSpaces(&sz, bufferEnd);
  316|  1.45M|                    positionBuffer.emplace_back();
  317|  1.45M|                    aiVector3D *vn = &positionBuffer.back();
  318|  1.45M|                    sz = fast_atoreal_move(sz, vn->x);
  319|  1.45M|                    SkipSpaces(&sz, bufferEnd);
  320|  1.45M|                    sz = fast_atoreal_move(sz, vn->y);
  321|  1.45M|                    SkipSpaces(&sz, bufferEnd);
  322|  1.45M|                    sz = fast_atoreal_move(sz, vn->z);
  323|  1.45M|                    faceVertexCounter++;
  324|  1.45M|                }
  325|  5.91M|            } else if (!::strncmp(sz, "endsolid", 8)) {
  ------------------
  |  Branch (325:24): [True: 311k, False: 5.60M]
  ------------------
  326|  2.62M|                do {
  327|  2.62M|                    ++sz;
  328|  2.62M|                } while (!IsLineEnd(*sz));
  ------------------
  |  Branch (328:26): [True: 2.31M, False: 311k]
  ------------------
  329|   311k|                SkipSpacesAndLineEnd(&sz, bufferEnd);
  330|       |                // finished!
  331|   311k|                break;
  332|  5.60M|            } else { // else skip the whole identifier
  333|  25.1M|                do {
  334|  25.1M|                    ++sz;
  335|  25.1M|                } while (!IsSpaceOrNewLine(*sz));
  ------------------
  |  Branch (335:26): [True: 19.5M, False: 5.60M]
  ------------------
  336|  5.60M|            }
  337|  8.42M|        }
  338|       |
  339|   314k|        if (positionBuffer.empty()) {
  ------------------
  |  Branch (339:13): [True: 219k, False: 95.1k]
  ------------------
  340|   219k|            pMesh->mNumFaces = 0;
  341|   219k|            ASSIMP_LOG_WARN("STL: mesh is empty or invalid; no data loaded");
  342|   219k|        }
  343|   314k|        if (positionBuffer.size() % 3 != 0) {
  ------------------
  |  Branch (343:13): [True: 67, False: 314k]
  ------------------
  344|     67|            pMesh->mNumFaces = 0;
  345|     67|            throw DeadlyImportError("STL: Invalid number of vertices");
  346|     67|        }
  347|   314k|        if (normalBuffer.size() != positionBuffer.size()) {
  ------------------
  |  Branch (347:13): [True: 143, False: 314k]
  ------------------
  348|    143|            pMesh->mNumFaces = 0;
  349|    143|            throw DeadlyImportError("Normal buffer size does not match position buffer size");
  350|    143|        }
  351|       |
  352|       |        // only process position buffer when filled, else exception when accessing with index operator
  353|       |        // see line 353: only warning is triggered
  354|       |        // see line 373(now): access to empty position buffer with index operator forced exception
  355|   314k|        if (!positionBuffer.empty()) {
  ------------------
  |  Branch (355:13): [True: 94.2k, False: 220k]
  ------------------
  356|  94.2k|            pMesh->mNumFaces = static_cast<unsigned int>(positionBuffer.size() / 3);
  357|  94.2k|            pMesh->mNumVertices = static_cast<unsigned int>(positionBuffer.size());
  358|  94.2k|            pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  359|  1.37M|            for (size_t i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (359:32): [True: 1.28M, False: 94.2k]
  ------------------
  360|  1.28M|                pMesh->mVertices[i].x = positionBuffer[i].x;
  361|  1.28M|                pMesh->mVertices[i].y = positionBuffer[i].y;
  362|  1.28M|                pMesh->mVertices[i].z = positionBuffer[i].z;
  363|  1.28M|            }
  364|  94.2k|            positionBuffer.clear();
  365|  94.2k|        }
  366|       |        // also only process normalBuffer when filled, else exception when accessing with index operator
  367|   314k|        if (!normalBuffer.empty()) {
  ------------------
  |  Branch (367:13): [True: 94.2k, False: 220k]
  ------------------
  368|  94.2k|            pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  369|  1.37M|            for (size_t i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (369:32): [True: 1.28M, False: 94.2k]
  ------------------
  370|  1.28M|                pMesh->mNormals[i].x = normalBuffer[i].x;
  371|  1.28M|                pMesh->mNormals[i].y = normalBuffer[i].y;
  372|  1.28M|                pMesh->mNormals[i].z = normalBuffer[i].z;
  373|  1.28M|            }
  374|  94.2k|            normalBuffer.clear();
  375|  94.2k|        }
  376|       |
  377|       |        // now copy faces
  378|   314k|        addFacesToMesh(pMesh);
  379|       |
  380|       |        // assign the meshes to the current node
  381|   314k|        pushMeshesToNode(meshIndices, node);
  382|   314k|    }
  383|       |
  384|       |    // now add the loaded meshes
  385|  2.96k|    mScene->mNumMeshes = (unsigned int)meshes.size();
  386|  2.96k|    mScene->mMeshes = new aiMesh *[mScene->mNumMeshes];
  387|   315k|    for (size_t i = 0; i < meshes.size(); i++) {
  ------------------
  |  Branch (387:24): [True: 312k, False: 2.96k]
  ------------------
  388|   312k|        mScene->mMeshes[i] = meshes[i];
  389|   312k|    }
  390|       |
  391|  2.96k|    root->mNumChildren = (unsigned int)nodes.size();
  392|  2.96k|    root->mChildren = new aiNode *[root->mNumChildren];
  393|   315k|    for (size_t i = 0; i < nodes.size(); ++i) {
  ------------------
  |  Branch (393:24): [True: 312k, False: 2.96k]
  ------------------
  394|   312k|        root->mChildren[i] = nodes[i];
  395|   312k|    }
  396|  2.96k|}
_ZN6Assimp11STLImporter14LoadBinaryFileEv:
  400|    923|bool STLImporter::LoadBinaryFile() {
  401|       |    // allocate one mesh
  402|    923|    mScene->mNumMeshes = 1;
  403|    923|    mScene->mMeshes = new aiMesh *[1];
  404|    923|    aiMesh *pMesh = mScene->mMeshes[0] = new aiMesh();
  405|    923|    pMesh->mMaterialIndex = 0;
  406|       |
  407|       |    // skip the first 80 bytes
  408|    923|    if (mFileSize < 84) {
  ------------------
  |  Branch (408:9): [True: 0, False: 923]
  ------------------
  409|      0|        throw DeadlyImportError("STL: file is too small for the header");
  410|      0|    }
  411|    923|    bool bIsMaterialise = false;
  412|       |
  413|       |    // search for an occurrence of "COLOR=" in the header
  414|    923|    const unsigned char *sz2 = (const unsigned char *)mBuffer;
  415|    923|    const unsigned char *const szEnd = sz2 + 80;
  416|  70.7k|    while (sz2 < szEnd) {
  ------------------
  |  Branch (416:12): [True: 69.8k, False: 857]
  ------------------
  417|       |
  418|  69.8k|        if ('C' == *sz2++ && 'O' == *sz2++ && 'L' == *sz2++ &&
  ------------------
  |  Branch (418:13): [True: 772, False: 69.1k]
  |  Branch (418:30): [True: 374, False: 398]
  |  Branch (418:47): [True: 254, False: 120]
  ------------------
  419|    254|                'O' == *sz2++ && 'R' == *sz2++ && '=' == *sz2++) {
  ------------------
  |  Branch (419:17): [True: 135, False: 119]
  |  Branch (419:34): [True: 96, False: 39]
  |  Branch (419:51): [True: 66, False: 30]
  ------------------
  420|       |
  421|       |            // read the default vertex color for facets
  422|     66|            bIsMaterialise = true;
  423|     66|            ASSIMP_LOG_INFO("STL: Taking code path for Materialise files");
  424|     66|            const ai_real invByte = (ai_real)1.0 / (ai_real)255.0;
  425|     66|            mClrColorDefault.r = (*sz2++) * invByte;
  426|     66|            mClrColorDefault.g = (*sz2++) * invByte;
  427|     66|            mClrColorDefault.b = (*sz2++) * invByte;
  428|     66|            mClrColorDefault.a = (*sz2++) * invByte;
  429|     66|            break;
  430|     66|        }
  431|  69.8k|    }
  432|    923|    const unsigned char *sz = (const unsigned char *)mBuffer + 80;
  433|       |
  434|       |    // now read the number of facets
  435|    923|    mScene->mRootNode->mName.Set("<STL_BINARY>");
  436|       |
  437|    923|    pMesh->mNumFaces = *((uint32_t *)sz);
  438|    923|    sz += 4;
  439|       |
  440|    923|    if (mFileSize < 84ull + pMesh->mNumFaces * 50ull) {
  ------------------
  |  Branch (440:9): [True: 6, False: 917]
  ------------------
  441|      6|        throw DeadlyImportError("STL: file is too small to hold all facets");
  442|      6|    }
  443|       |
  444|    917|    if (!pMesh->mNumFaces) {
  ------------------
  |  Branch (444:9): [True: 30, False: 887]
  ------------------
  445|     30|        throw DeadlyImportError("STL: file is empty. There are no facets defined");
  446|     30|    }
  447|       |
  448|    887|    pMesh->mNumVertices = pMesh->mNumFaces * 3;
  449|       |
  450|    887|    aiVector3D *vp = pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  451|    887|    aiVector3D *vn = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  452|       |
  453|    887|    aiVector3f *theVec;
  454|    887|    aiVector3f theVec3F;
  455|       |
  456|   298k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (456:30): [True: 297k, False: 887]
  ------------------
  457|       |        // NOTE: Blender sometimes writes empty normals ... this is not
  458|       |        // our fault ... the RemoveInvalidData helper step should fix that
  459|       |
  460|       |        // There's one normal for the face in the STL; use it three times
  461|       |        // for vertex normals
  462|   297k|        theVec = (aiVector3f *)sz;
  463|   297k|        ::memcpy(&theVec3F, theVec, sizeof(aiVector3f));
  464|   297k|        vn->x = theVec3F.x;
  465|   297k|        vn->y = theVec3F.y;
  466|   297k|        vn->z = theVec3F.z;
  467|   297k|        *(vn + 1) = *vn;
  468|   297k|        *(vn + 2) = *vn;
  469|   297k|        ++theVec;
  470|   297k|        vn += 3;
  471|       |
  472|       |        // vertex 1
  473|   297k|        ::memcpy(&theVec3F, theVec, sizeof(aiVector3f));
  474|   297k|        vp->x = theVec3F.x;
  475|   297k|        vp->y = theVec3F.y;
  476|   297k|        vp->z = theVec3F.z;
  477|   297k|        ++theVec;
  478|   297k|        ++vp;
  479|       |
  480|       |        // vertex 2
  481|   297k|        ::memcpy(&theVec3F, theVec, sizeof(aiVector3f));
  482|   297k|        vp->x = theVec3F.x;
  483|   297k|        vp->y = theVec3F.y;
  484|   297k|        vp->z = theVec3F.z;
  485|   297k|        ++theVec;
  486|   297k|        ++vp;
  487|       |
  488|       |        // vertex 3
  489|   297k|        ::memcpy(&theVec3F, theVec, sizeof(aiVector3f));
  490|   297k|        vp->x = theVec3F.x;
  491|   297k|        vp->y = theVec3F.y;
  492|   297k|        vp->z = theVec3F.z;
  493|   297k|        ++theVec;
  494|   297k|        ++vp;
  495|       |
  496|   297k|        sz = (const unsigned char *)theVec;
  497|       |
  498|   297k|        uint16_t color = *((uint16_t *)sz);
  499|   297k|        sz += 2;
  500|       |
  501|   297k|        if (color & (1 << 15)) {
  ------------------
  |  Branch (501:13): [True: 66.9k, False: 230k]
  ------------------
  502|       |            // seems we need to take the color
  503|  66.9k|            if (!pMesh->mColors[0]) {
  ------------------
  |  Branch (503:17): [True: 521, False: 66.3k]
  ------------------
  504|    521|                pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
  505|   794k|                for (unsigned int j = 0; j < pMesh->mNumVertices; ++j) {
  ------------------
  |  Branch (505:42): [True: 794k, False: 521]
  ------------------
  506|   794k|                    *pMesh->mColors[0]++ = mClrColorDefault;
  507|   794k|                }
  508|    521|                pMesh->mColors[0] -= pMesh->mNumVertices;
  509|       |
  510|    521|                ASSIMP_LOG_INFO("STL: Mesh has vertex colors");
  511|    521|            }
  512|  66.9k|            aiColor4D *clr = &pMesh->mColors[0][i * 3];
  513|  66.9k|            clr->a = 1.0;
  514|  66.9k|            const ai_real invVal((ai_real)1.0 / (ai_real)31.0);
  515|  66.9k|            if (bIsMaterialise) // this is reversed
  ------------------
  |  Branch (515:17): [True: 101, False: 66.8k]
  ------------------
  516|    101|            {
  517|    101|                clr->r = (color & 0x1fu) * invVal;
  518|    101|                clr->g = ((color & (0x1fu << 5)) >> 5u) * invVal;
  519|    101|                clr->b = ((color & (0x1fu << 10)) >> 10u) * invVal;
  520|  66.8k|            } else {
  521|  66.8k|                clr->b = (color & 0x1fu) * invVal;
  522|  66.8k|                clr->g = ((color & (0x1fu << 5)) >> 5u) * invVal;
  523|  66.8k|                clr->r = ((color & (0x1fu << 10)) >> 10u) * invVal;
  524|  66.8k|            }
  525|       |            // assign the color to all vertices of the face
  526|  66.9k|            *(clr + 1) = *clr;
  527|  66.9k|            *(clr + 2) = *clr;
  528|  66.9k|        }
  529|   297k|    }
  530|       |
  531|       |    // now copy faces
  532|    887|    addFacesToMesh(pMesh);
  533|       |
  534|    887|    aiNode *root = mScene->mRootNode;
  535|       |
  536|       |    // allocate one node
  537|    887|    aiNode *node = new aiNode();
  538|    887|    node->mParent = root;
  539|       |
  540|    887|    root->mNumChildren = 1u;
  541|    887|    root->mChildren = new aiNode *[root->mNumChildren];
  542|    887|    root->mChildren[0] = node;
  543|       |
  544|       |    // add all created meshes to the single node
  545|    887|    node->mNumMeshes = mScene->mNumMeshes;
  546|    887|    node->mMeshes = new unsigned int[mScene->mNumMeshes];
  547|  1.77k|    for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (547:30): [True: 887, False: 887]
  ------------------
  548|    887|        node->mMeshes[i] = i;
  549|    887|    }
  550|       |
  551|    887|    if (bIsMaterialise && !pMesh->mColors[0]) {
  ------------------
  |  Branch (551:9): [True: 60, False: 827]
  |  Branch (551:27): [True: 39, False: 21]
  ------------------
  552|       |        // use the color as diffuse material color
  553|     39|        return true;
  554|     39|    }
  555|    848|    return false;
  556|    887|}
_ZN6Assimp11STLImporter16pushMeshesToNodeERNSt3__16vectorIjNS1_9allocatorIjEEEEP6aiNode:
  558|   313k|void STLImporter::pushMeshesToNode(std::vector<unsigned int> &meshIndices, aiNode *node) {
  559|   313k|    ai_assert(nullptr != node);
  560|   313k|    if (meshIndices.empty()) {
  ------------------
  |  Branch (560:9): [True: 0, False: 313k]
  ------------------
  561|      0|        return;
  562|      0|    }
  563|       |
  564|   313k|    node->mNumMeshes = static_cast<unsigned int>(meshIndices.size());
  565|   313k|    node->mMeshes = new unsigned int[meshIndices.size()];
  566|   626k|    for (size_t i = 0; i < meshIndices.size(); ++i) {
  ------------------
  |  Branch (566:24): [True: 313k, False: 313k]
  ------------------
  567|   313k|        node->mMeshes[i] = meshIndices[i];
  568|   313k|    }
  569|   313k|    meshIndices.clear();
  570|   313k|}
STLLoader.cpp:_ZN6Assimp12_GLOBAL__N_111IsBinarySTLEPKcm:
   76|   324k|static bool IsBinarySTL(const char *buffer, size_t fileSize) {
   77|   324k|    if (fileSize < 84) {
  ------------------
  |  Branch (77:9): [True: 6.89k, False: 317k]
  ------------------
   78|  6.89k|        return false;
   79|  6.89k|    }
   80|       |
   81|   317k|    const char *facecount_pos = buffer + 80;
   82|   317k|    uint32_t faceCount(0);
   83|   317k|    ::memcpy(&faceCount, facecount_pos, sizeof(uint32_t));
   84|   317k|    const uint32_t expectedBinaryFileSize = faceCount * 50 + 84;
   85|       |
   86|   317k|    return expectedBinaryFileSize == fileSize;
   87|   324k|}
STLLoader.cpp:_ZN6Assimp12_GLOBAL__N_110IsAsciiSTLEPKcm:
   95|   320k|static bool IsAsciiSTL(const char *buffer, size_t fileSize) {
   96|   320k|    if (IsBinarySTL(buffer, fileSize))
  ------------------
  |  Branch (96:9): [True: 2, False: 320k]
  ------------------
   97|      2|        return false;
   98|       |
   99|   320k|    const char *bufferEnd = buffer + fileSize;
  100|       |
  101|   320k|    if (!SkipSpaces(&buffer, bufferEnd)) {
  ------------------
  |  Branch (101:9): [True: 2.01k, False: 318k]
  ------------------
  102|  2.01k|        return false;
  103|  2.01k|    }
  104|       |
  105|   318k|    if (buffer + 5 >= bufferEnd) {
  ------------------
  |  Branch (105:9): [True: 42, False: 318k]
  ------------------
  106|     42|        return false;
  107|     42|    }
  108|       |
  109|   318k|    bool isASCII(strncmp(buffer, "solid", 5) == 0);
  110|   318k|    if (isASCII) {
  ------------------
  |  Branch (110:9): [True: 317k, False: 376]
  ------------------
  111|       |        // A lot of importers are write solid even if the file is binary. So we have to check for ASCII-characters.
  112|   317k|        if (fileSize >= BufferSize) {
  ------------------
  |  Branch (112:13): [True: 310k, False: 7.10k]
  ------------------
  113|   310k|            isASCII = true;
  114|   155M|            for (unsigned int i = 0; i < BufferSize; i++) {
  ------------------
  |  Branch (114:38): [True: 155M, False: 310k]
  ------------------
  115|   155M|                if (buffer[i] > UnicodeBoundary) {
  ------------------
  |  Branch (115:21): [True: 0, False: 155M]
  ------------------
  116|      0|                    isASCII = false;
  117|      0|                    break;
  118|      0|                }
  119|   155M|            }
  120|   310k|        }
  121|   317k|    }
  122|   318k|    return isASCII;
  123|   318k|}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp17ScenePreprocessor12ProcessSceneEv:
   50|  2.16k|void ScenePreprocessor::ProcessScene() {
   51|  2.16k|    ai_assert(scene != nullptr);
  ------------------
  |  |   67|  2.16k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 2.16k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   52|       |
   53|       |    // Process all meshes
   54|  96.3k|    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (54:30): [True: 94.1k, False: 2.16k]
  ------------------
   55|  94.1k|        if (nullptr == scene->mMeshes[i]) {
  ------------------
  |  Branch (55:13): [True: 0, False: 94.1k]
  ------------------
   56|      0|            continue;
   57|      0|        }
   58|  94.1k|        ProcessMesh(scene->mMeshes[i]);
   59|  94.1k|    }
   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|  2.16k|    for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
  ------------------
  |  Branch (67:30): [True: 0, False: 2.16k]
  ------------------
   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|  2.16k|    if (!scene->mNumMaterials && scene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 0, False: 2.16k]
  |  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|  2.16k|}
_ZN6Assimp17ScenePreprocessor11ProcessMeshEP6aiMesh:
  103|  94.1k|void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
  104|       |    // If aiMesh::mNumUVComponents is *not* set assign the default value of 2
  105|   847k|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (105:30): [True: 753k, False: 94.1k]
  ------------------
  106|   753k|        if (!mesh->mTextureCoords[i]) {
  ------------------
  |  Branch (106:13): [True: 753k, False: 0]
  ------------------
  107|   753k|            mesh->mNumUVComponents[i] = 0;
  108|   753k|            continue;
  109|   753k|        }
  110|       |
  111|      0|        if (!mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (111:13): [True: 0, False: 0]
  ------------------
  112|      0|            mesh->mNumUVComponents[i] = 2;
  113|      0|        }
  114|       |
  115|      0|        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|      0|        if (2 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (120:13): [True: 0, False: 0]
  ------------------
  121|      0|            for (; p != end; ++p) {
  ------------------
  |  Branch (121:20): [True: 0, False: 0]
  ------------------
  122|      0|                p->z = 0.f;
  123|      0|            }
  124|      0|        } else if (1 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (124:20): [True: 0, False: 0]
  ------------------
  125|      0|            for (; p != end; ++p) {
  ------------------
  |  Branch (125:20): [True: 0, False: 0]
  ------------------
  126|      0|                p->z = p->y = 0.f;
  127|      0|            }
  128|      0|        } else if (3 == mesh->mNumUVComponents[i]) {
  ------------------
  |  Branch (128:20): [True: 0, False: 0]
  ------------------
  129|       |            // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
  130|      0|            for (; p != end; ++p) {
  ------------------
  |  Branch (130:20): [True: 0, False: 0]
  ------------------
  131|      0|                if (p->z != 0) {
  ------------------
  |  Branch (131:21): [True: 0, False: 0]
  ------------------
  132|      0|                    break;
  133|      0|                }
  134|      0|            }
  135|      0|            if (p == end) {
  ------------------
  |  Branch (135:17): [True: 0, False: 0]
  ------------------
  136|      0|                ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
  137|      0|                mesh->mNumUVComponents[i] = 2;
  138|      0|            }
  139|      0|        }
  140|      0|    }
  141|       |
  142|       |    // If the information which primitive types are there in the
  143|       |    // mesh is currently not available, compute it.
  144|  94.1k|    if (!mesh->mPrimitiveTypes) {
  ------------------
  |  Branch (144:9): [True: 94.1k, False: 0]
  ------------------
  145|  94.1k|        ai_assert(mesh->mFaces != nullptr);
  ------------------
  |  |   67|  94.1k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 94.1k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  146|   817k|        for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (146:34): [True: 723k, False: 94.1k]
  ------------------
  147|   723k|            aiFace &face = mesh->mFaces[a];
  148|   723k|            switch (face.mNumIndices) {
  149|   723k|            case 3u:
  ------------------
  |  Branch (149:13): [True: 723k, False: 0]
  ------------------
  150|   723k|                mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  151|   723k|                break;
  152|       |
  153|      0|            case 2u:
  ------------------
  |  Branch (153:13): [True: 0, False: 723k]
  ------------------
  154|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  155|      0|                break;
  156|       |
  157|      0|            case 1u:
  ------------------
  |  Branch (157:13): [True: 0, False: 723k]
  ------------------
  158|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  159|      0|                break;
  160|       |
  161|      0|            default:
  ------------------
  |  Branch (161:13): [True: 0, False: 723k]
  ------------------
  162|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  163|      0|                break;
  164|   723k|            }
  165|   723k|        }
  166|  94.1k|    }
  167|       |
  168|       |    // If tangents and normals are given but no bitangents compute them
  169|  94.1k|    if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
  ------------------
  |  Branch (169:9): [True: 0, False: 94.1k]
  |  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|  94.1k|}

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

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

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

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

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

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

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

_ZN7aiSceneC2Ev:
   46|  4.62k|        mFlags(0),
   47|  4.62k|        mRootNode(nullptr),
   48|  4.62k|        mNumMeshes(0),
   49|  4.62k|        mMeshes(nullptr),
   50|  4.62k|        mNumMaterials(0),
   51|  4.62k|        mMaterials(nullptr),
   52|  4.62k|        mNumAnimations(0),
   53|  4.62k|        mAnimations(nullptr),
   54|  4.62k|        mNumTextures(0),
   55|  4.62k|        mTextures(nullptr),
   56|  4.62k|        mNumLights(0),
   57|  4.62k|        mLights(nullptr),
   58|  4.62k|        mNumCameras(0),
   59|  4.62k|        mCameras(nullptr),
   60|  4.62k|        mMetaData(nullptr),
   61|  4.62k|        mName(),
   62|  4.62k|        mNumSkeletons(0),
   63|  4.62k|        mSkeletons(nullptr),
   64|  4.62k|        mPrivate(new Assimp::ScenePrivateData()) {
   65|       |    // empty
   66|  4.62k|}
_ZN7aiSceneD2Ev:
   68|  4.62k|aiScene::~aiScene() {
   69|       |    // delete all sub-objects recursively
   70|  4.62k|    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|  4.62k|    if (mNumMeshes && mMeshes) {
  ------------------
  |  Branch (75:9): [True: 3.07k, False: 1.55k]
  |  Branch (75:23): [True: 3.07k, False: 0]
  ------------------
   76|   346k|        for (unsigned int a = 0; a < mNumMeshes; ++a) {
  ------------------
  |  Branch (76:34): [True: 343k, False: 3.07k]
  ------------------
   77|   343k|            delete mMeshes[a];
   78|   343k|        }
   79|  3.07k|    }
   80|  4.62k|    delete[] mMeshes;
   81|       |
   82|  4.62k|    if (mNumMaterials && mMaterials) {
  ------------------
  |  Branch (82:9): [True: 3.03k, False: 1.59k]
  |  Branch (82:26): [True: 3.03k, False: 0]
  ------------------
   83|  6.07k|        for (unsigned int a = 0; a < mNumMaterials; ++a) {
  ------------------
  |  Branch (83:34): [True: 3.03k, False: 3.03k]
  ------------------
   84|  3.03k|            delete mMaterials[a];
   85|  3.03k|        }
   86|  3.03k|    }
   87|  4.62k|    delete[] mMaterials;
   88|       |
   89|  4.62k|    if (mNumAnimations && mAnimations) {
  ------------------
  |  Branch (89:9): [True: 0, False: 4.62k]
  |  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|  4.62k|    delete[] mAnimations;
   95|       |
   96|  4.62k|    if (mNumTextures && mTextures) {
  ------------------
  |  Branch (96:9): [True: 0, False: 4.62k]
  |  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|  4.62k|    delete[] mTextures;
  102|       |
  103|  4.62k|    if (mNumLights && mLights) {
  ------------------
  |  Branch (103:9): [True: 0, False: 4.62k]
  |  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|  4.62k|    delete[] mLights;
  109|       |
  110|  4.62k|    if (mNumCameras && mCameras) {
  ------------------
  |  Branch (110:9): [True: 0, False: 4.62k]
  |  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|  4.62k|    delete[] mCameras;
  116|       |
  117|  4.62k|    aiMetadata::Dealloc(mMetaData);
  118|       |
  119|  4.62k|    delete[] mSkeletons;
  120|       |
  121|  4.62k|    delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
  122|  4.62k|}
_ZN6aiNodeC2Ev:
  125|   319k|        mName(""),
  126|   319k|        mParent(nullptr),
  127|   319k|        mNumChildren(0),
  128|   319k|        mChildren(nullptr),
  129|   319k|        mNumMeshes(0),
  130|   319k|        mMeshes(nullptr),
  131|   319k|        mMetaData(nullptr) {
  132|       |    // empty
  133|   319k|}
_ZN6aiNodeD2Ev:
  147|   317k|aiNode::~aiNode() {
  148|       |    // delete all children recursively
  149|       |    // to make sure we won't crash if the data is invalid ...
  150|   317k|    if (mNumChildren && mChildren) {
  ------------------
  |  Branch (150:9): [True: 3.03k, False: 314k]
  |  Branch (150:25): [True: 3.03k, False: 0]
  ------------------
  151|   316k|        for (unsigned int a = 0; a < mNumChildren; a++)
  ------------------
  |  Branch (151:34): [True: 313k, False: 3.03k]
  ------------------
  152|   313k|            delete mChildren[a];
  153|  3.03k|    }
  154|   317k|    delete[] mChildren;
  155|   317k|    delete[] mMeshes;
  156|   317k|    delete mMetaData;
  157|   317k|}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp22FindDegeneratesProcessC2Ev:
   62|  4.62k|        mConfigRemoveDegenerates(false),
   63|  4.62k|        mConfigCheckAreaOfTriangle(false) {
   64|       |    // empty
   65|  4.62k|}
_ZNK6Assimp22FindDegeneratesProcess8IsActiveEj:
   69|  2.16k|bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const {
   70|  2.16k|    return 0 != (pFlags & aiProcess_FindDegenerates);
   71|  2.16k|}
_ZN6Assimp22FindDegeneratesProcess15SetupPropertiesEPKNS_8ImporterE:
   75|  2.16k|void FindDegeneratesProcess::SetupProperties(const Importer *pImp) {
   76|       |    // Get the current value of AI_CONFIG_PP_FD_REMOVE
   77|  2.16k|    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0));
   78|       |    mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA));
   79|  2.16k|}
_ZN6Assimp22FindDegeneratesProcess7ExecuteEP7aiScene:
   83|  2.16k|void FindDegeneratesProcess::Execute(aiScene *pScene) {
   84|  2.16k|    ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
   85|  2.16k|    if (nullptr == pScene) {
  ------------------
  |  Branch (85:9): [True: 0, False: 2.16k]
  ------------------
   86|      0|        return;
   87|      0|    }
   88|       |
   89|  2.16k|    std::unordered_map<unsigned int, unsigned int> meshMap;
   90|  2.16k|    meshMap.reserve(pScene->mNumMeshes);
   91|       |
   92|  2.16k|    const unsigned int originalNumMeshes = pScene->mNumMeshes;
   93|  2.16k|    unsigned int targetIndex = 0;
   94|  96.3k|    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
  ------------------
  |  Branch (94:30): [True: 94.1k, False: 2.16k]
  ------------------
   95|       |        // Do not process point cloud, ExecuteOnMesh works only with faces data
   96|  94.1k|        if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
  ------------------
  |  Branch (96:13): [True: 94.1k, False: 0]
  |  Branch (96:96): [True: 0, False: 94.1k]
  ------------------
   97|      0|            delete pScene->mMeshes[i];
   98|       |            // Not strictly required, but clean:
   99|      0|            pScene->mMeshes[i] = nullptr;
  100|  94.1k|        } else {
  101|  94.1k|            meshMap[i] = targetIndex;
  102|  94.1k|            pScene->mMeshes[targetIndex] = pScene->mMeshes[i];
  103|  94.1k|            ++targetIndex;
  104|  94.1k|        }
  105|  94.1k|    }
  106|  2.16k|    pScene->mNumMeshes = targetIndex;
  107|       |
  108|  2.16k|    if (meshMap.size() < originalNumMeshes) {
  ------------------
  |  Branch (108:9): [True: 0, False: 2.16k]
  ------------------
  109|      0|        updateSceneGraph(pScene->mRootNode, meshMap);
  110|      0|    }
  111|       |
  112|       |    ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
  113|  2.16k|}
_ZN6Assimp22FindDegeneratesProcess13ExecuteOnMeshEP6aiMesh:
  134|  94.1k|bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
  135|  94.1k|    mesh->mPrimitiveTypes = 0;
  136|       |
  137|  94.1k|    std::vector<bool> remove_me;
  138|  94.1k|    if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (138:9): [True: 0, False: 94.1k]
  ------------------
  139|      0|        remove_me.resize(mesh->mNumFaces, false);
  140|      0|    }
  141|       |
  142|  94.1k|    unsigned int deg = 0, limit;
  143|   817k|    for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (143:30): [True: 723k, False: 94.1k]
  ------------------
  144|   723k|        aiFace &face = mesh->mFaces[a];
  145|   723k|        bool first = true;
  146|   723k|        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|  2.72M|        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
  ------------------
  |  Branch (149:34): [True: 2.00M, False: 723k]
  ------------------
  150|  2.00M|            if (!std::all_of(face.mIndices, face.mIndices + face.mNumIndices, vertex_in_range))
  ------------------
  |  Branch (150:17): [True: 0, False: 2.00M]
  ------------------
  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|  2.00M|            limit = face.mNumIndices;
  157|  2.00M|            if (face.mNumIndices > 4) {
  ------------------
  |  Branch (157:17): [True: 0, False: 2.00M]
  ------------------
  158|      0|                limit = std::min(limit, i + 2);
  159|      0|            }
  160|       |
  161|  4.07M|            for (unsigned int t = i + 1; t < limit; ++t) {
  ------------------
  |  Branch (161:42): [True: 2.07M, False: 2.00M]
  ------------------
  162|  2.07M|                if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) {
  ------------------
  |  Branch (162:21): [True: 168k, False: 1.90M]
  ------------------
  163|       |                    // we have found a matching vertex position
  164|       |                    // remove the corresponding index from the array
  165|   168k|                    --face.mNumIndices;
  166|   168k|                    --limit;
  167|   241k|                    for (unsigned int m = t; m < face.mNumIndices; ++m) {
  ------------------
  |  Branch (167:46): [True: 73.8k, False: 168k]
  ------------------
  168|  73.8k|                        face.mIndices[m] = face.mIndices[m + 1];
  169|  73.8k|                    }
  170|   168k|                    --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|   168k|                    face.mIndices[face.mNumIndices] = 0xdeadbeef;
  176|       |
  177|   168k|                    if (first) {
  ------------------
  |  Branch (177:25): [True: 117k, False: 50.6k]
  ------------------
  178|   117k|                        ++deg;
  179|   117k|                        first = false;
  180|   117k|                    }
  181|       |
  182|   168k|                    if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (182:25): [True: 0, False: 168k]
  ------------------
  183|      0|                        remove_me[a] = true;
  184|      0|                        goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
  185|      0|                    }
  186|   168k|                }
  187|  2.07M|            }
  188|       |
  189|  2.00M|            if (mConfigCheckAreaOfTriangle) {
  ------------------
  |  Branch (189:17): [True: 2.00M, False: 0]
  ------------------
  190|  2.00M|                if (face.mNumIndices == 3) {
  ------------------
  |  Branch (190:21): [True: 1.83M, False: 162k]
  ------------------
  191|  1.83M|                    ai_real area = GeometryUtils::calculateAreaOfTriangle(face, mesh);
  192|  1.83M|                    if (area < ai_epsilon) {
  ------------------
  |  Branch (192:25): [True: 62.7k, False: 1.77M]
  ------------------
  193|  62.7k|                        if (mConfigRemoveDegenerates) {
  ------------------
  |  Branch (193:29): [True: 0, False: 62.7k]
  ------------------
  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|  62.7k|                    }
  201|  1.83M|                }
  202|  2.00M|            }
  203|  2.00M|        }
  204|       |
  205|       |        // We need to update the primitive flags array of the mesh.
  206|   723k|        switch (face.mNumIndices) {
  207|  50.6k|        case 1u:
  ------------------
  |  Branch (207:9): [True: 50.6k, False: 672k]
  ------------------
  208|  50.6k|            mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  209|  50.6k|            break;
  210|  66.8k|        case 2u:
  ------------------
  |  Branch (210:9): [True: 66.8k, False: 656k]
  ------------------
  211|  66.8k|            mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  212|  66.8k|            break;
  213|   606k|        case 3u:
  ------------------
  |  Branch (213:9): [True: 606k, False: 117k]
  ------------------
  214|   606k|            mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  215|   606k|            break;
  216|      0|        default:
  ------------------
  |  Branch (216:9): [True: 0, False: 723k]
  ------------------
  217|      0|            mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  218|      0|            break;
  219|   723k|        };
  220|   723k|    evil_jump_outside:
  221|   723k|        continue;
  222|   723k|    }
  223|       |
  224|       |    // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
  225|  94.1k|    if (mConfigRemoveDegenerates && deg) {
  ------------------
  |  Branch (225:9): [True: 0, False: 94.1k]
  |  Branch (225:37): [True: 0, False: 0]
  ------------------
  226|      0|        unsigned int n = 0;
  227|      0|        for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (227:34): [True: 0, False: 0]
  ------------------
  228|      0|            aiFace &face_src = mesh->mFaces[a];
  229|      0|            if (!remove_me[a]) {
  ------------------
  |  Branch (229:17): [True: 0, False: 0]
  ------------------
  230|      0|                aiFace &face_dest = mesh->mFaces[n++];
  231|       |
  232|       |                // Do a manual copy, keep the index array
  233|      0|                face_dest.mNumIndices = face_src.mNumIndices;
  234|      0|                face_dest.mIndices = face_src.mIndices;
  235|       |
  236|      0|                if (&face_src != &face_dest) {
  ------------------
  |  Branch (236:21): [True: 0, False: 0]
  ------------------
  237|       |                    // clear source
  238|      0|                    face_src.mNumIndices = 0;
  239|      0|                    face_src.mIndices = nullptr;
  240|      0|                }
  241|      0|            } else {
  242|       |                // Otherwise delete it if we don't need this face
  243|      0|                delete[] face_src.mIndices;
  244|      0|                face_src.mIndices = nullptr;
  245|      0|                face_src.mNumIndices = 0;
  246|      0|            }
  247|      0|        }
  248|       |        // Just leave the rest of the array unreferenced, we don't care for now
  249|      0|        mesh->mNumFaces = n;
  250|      0|        if (!mesh->mNumFaces) {
  ------------------
  |  Branch (250:13): [True: 0, False: 0]
  ------------------
  251|       |            // The whole mesh consists of degenerated faces
  252|       |            // signal upward, that this mesh should be deleted.
  253|      0|            ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
  254|      0|            return true;
  255|      0|        }
  256|      0|    }
  257|       |
  258|  94.1k|    if (deg && !DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (258:9): [True: 77.1k, False: 17.0k]
  |  Branch (258:16): [True: 0, False: 77.1k]
  ------------------
  259|       |        ASSIMP_LOG_WARN("Found ", deg, " degenerated primitives");
  260|      0|    }
  261|  94.1k|    return false;
  262|  94.1k|}
FindDegenerates.cpp:_ZZN6Assimp22FindDegeneratesProcess13ExecuteOnMeshEP6aiMeshENK3$_0clEj:
  146|  5.96M|        auto vertex_in_range = [numVertices = mesh->mNumVertices](unsigned int vertex_idx) { return vertex_idx < numVertices; };

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

_ZN6Assimp22FindInvalidDataProcessC2Ev:
   59|  4.62k|        configEpsilon(0.0), mIgnoreTexCoods(false) {
   60|       |    // nothing to do here
   61|  4.62k|}
_ZNK6Assimp22FindInvalidDataProcess8IsActiveEj:
   65|  2.16k|bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {
   66|  2.16k|    return 0 != (pFlags & aiProcess_FindInvalidData);
   67|  2.16k|}
_ZN6Assimp22FindInvalidDataProcess15SetupPropertiesEPKNS_8ImporterE:
   71|  2.16k|void FindInvalidDataProcess::SetupProperties(const Importer *pImp) {
   72|       |    // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
   73|  2.16k|    configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY, 0.f));
   74|       |    mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false);
   75|  2.16k|}
_Z20UpdateMeshReferencesP6aiNodeRKNSt3__16vectorIjNS1_9allocatorIjEEEE:
   79|  54.7k|void UpdateMeshReferences(aiNode *node, const std::vector<unsigned int> &meshMapping) {
   80|  54.7k|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 54.5k, False: 210]
  ------------------
   81|  54.5k|        unsigned int out = 0;
   82|   134k|        for (unsigned int a = 0; a < node->mNumMeshes; ++a) {
  ------------------
  |  Branch (82:34): [True: 80.3k, False: 54.5k]
  ------------------
   83|       |
   84|  80.3k|            unsigned int ref = node->mMeshes[a];
   85|  80.3k|            if (ref >= meshMapping.size())
  ------------------
  |  Branch (85:17): [True: 0, False: 80.3k]
  ------------------
   86|      0|                throw DeadlyImportError("Invalid mesh ref");
   87|       |
   88|  80.3k|            if (UINT_MAX != (ref = meshMapping[ref])) {
  ------------------
  |  Branch (88:17): [True: 73.8k, False: 6.47k]
  ------------------
   89|  73.8k|                node->mMeshes[out++] = ref;
   90|  73.8k|            }
   91|  80.3k|        }
   92|       |        // just let the members that are unused, that's much cheaper
   93|       |        // than a full array realloc'n'copy party ...
   94|  54.5k|        node->mNumMeshes = out;
   95|  54.5k|        if (0 == out) {
  ------------------
  |  Branch (95:13): [True: 5.48k, False: 49.0k]
  ------------------
   96|  5.48k|            delete[] node->mMeshes;
   97|  5.48k|            node->mMeshes = nullptr;
   98|  5.48k|        }
   99|  54.5k|    }
  100|       |    // recursively update all children
  101|   109k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 54.5k, False: 54.7k]
  ------------------
  102|  54.5k|        UpdateMeshReferences(node->mChildren[i], meshMapping);
  103|  54.5k|    }
  104|  54.7k|}
_ZN6Assimp22FindInvalidDataProcess7ExecuteEP7aiScene:
  108|  2.16k|void FindInvalidDataProcess::Execute(aiScene *pScene) {
  109|  2.16k|    ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin");
  110|       |
  111|  2.16k|    bool out = false;
  112|  2.16k|    std::vector<unsigned int> meshMapping(pScene->mNumMeshes);
  113|  2.16k|    unsigned int real = 0;
  114|       |
  115|       |    // Process meshes
  116|   132k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (116:30): [True: 130k, False: 2.16k]
  ------------------
  117|   130k|        int result = ProcessMesh(pScene->mMeshes[a]);
  118|   130k|        if (0 == result) {
  ------------------
  |  Branch (118:13): [True: 110k, False: 19.8k]
  ------------------
  119|   110k|            out = true;
  120|   110k|        }
  121|   130k|        if (2 == result) {
  ------------------
  |  Branch (121:13): [True: 8.71k, False: 121k]
  ------------------
  122|       |            // remove this mesh
  123|  8.71k|            delete pScene->mMeshes[a];
  124|  8.71k|            pScene->mMeshes[a] = nullptr;
  125|       |
  126|  8.71k|            meshMapping[a] = UINT_MAX;
  127|  8.71k|            out = true;
  128|  8.71k|            continue;
  129|  8.71k|        }
  130|       |
  131|   121k|        pScene->mMeshes[real] = pScene->mMeshes[a];
  132|   121k|        meshMapping[a] = real++;
  133|   121k|    }
  134|       |
  135|       |    // Process animations
  136|  2.16k|    for (unsigned int animIdx = 0; animIdx < pScene->mNumAnimations; ++animIdx) {
  ------------------
  |  Branch (136:36): [True: 0, False: 2.16k]
  ------------------
  137|      0|        ProcessAnimation(pScene->mAnimations[animIdx]);
  138|      0|    }
  139|       |
  140|  2.16k|    if (out) {
  ------------------
  |  Branch (140:9): [True: 1.68k, False: 476]
  ------------------
  141|  1.68k|        if (real != pScene->mNumMeshes) {
  ------------------
  |  Branch (141:13): [True: 274, False: 1.41k]
  ------------------
  142|    274|            if (!real) {
  ------------------
  |  Branch (142:17): [True: 64, False: 210]
  ------------------
  143|     64|                throw DeadlyImportError("No meshes remaining");
  144|     64|            }
  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|    210|            try {
  150|    210|                UpdateMeshReferences(pScene->mRootNode, meshMapping);
  151|    210|            } 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|    210|            pScene->mNumMeshes = real;
  157|    210|        }
  158|       |
  159|  1.68k|        ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ...");
  160|  1.62k|    } else {
  161|       |        ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK.");
  162|    476|    }
  163|  2.16k|}
_ZN6Assimp22FindInvalidDataProcess11ProcessMeshEP6aiMesh:
  323|   130k|int FindInvalidDataProcess::ProcessMesh(aiMesh *pMesh) {
  324|   130k|    bool ret = false;
  325|   130k|    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|   853k|    for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
  ------------------
  |  Branch (329:30): [True: 723k, False: 130k]
  ------------------
  330|   723k|        const aiFace &f = pMesh->mFaces[m];
  331|       |
  332|  2.72M|        for (unsigned int i = 0; i < f.mNumIndices; ++i) {
  ------------------
  |  Branch (332:34): [True: 2.00M, False: 723k]
  ------------------
  333|  2.00M|            dirtyMask[f.mIndices[i]] = false;
  334|  2.00M|        }
  335|   723k|    }
  336|       |
  337|       |    // Process vertex positions
  338|   130k|    if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) {
  ------------------
  |  Branch (338:9): [True: 130k, False: 0]
  |  Branch (338:29): [True: 8.71k, False: 121k]
  ------------------
  339|  8.71k|        ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions");
  340|       |
  341|  8.71k|        return 2;
  342|  8.71k|    }
  343|       |
  344|       |    // process texture coordinates
  345|   121k|    if (!mIgnoreTexCoods) {
  ------------------
  |  Branch (345:9): [True: 121k, False: 0]
  ------------------
  346|   121k|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) {
  ------------------
  |  Branch (346:34): [True: 121k, False: 0]
  |  Branch (346:72): [True: 0, False: 121k]
  ------------------
  347|      0|            if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) {
  ------------------
  |  Branch (347:17): [True: 0, False: 0]
  ------------------
  348|      0|                pMesh->mNumUVComponents[i] = 0;
  349|       |
  350|       |                // delete all subsequent texture coordinate sets.
  351|      0|                for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
  ------------------
  |  Branch (351:46): [True: 0, False: 0]
  ------------------
  352|      0|                    delete[] pMesh->mTextureCoords[a];
  353|      0|                    pMesh->mTextureCoords[a] = nullptr;
  354|      0|                    pMesh->mNumUVComponents[a] = 0;
  355|      0|                }
  356|       |
  357|      0|                ret = true;
  358|      0|            }
  359|      0|        }
  360|   121k|    }
  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|   121k|    if (pMesh->mNormals || pMesh->mTangents) {
  ------------------
  |  Branch (366:9): [True: 121k, False: 0]
  |  Branch (366:28): [True: 0, False: 0]
  ------------------
  367|       |
  368|   121k|        if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (368:13): [True: 37.5k, False: 84.0k]
  ------------------
  369|  84.0k|                aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (369:17): [True: 43.9k, False: 40.1k]
  ------------------
  370|  81.4k|            if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (370:17): [True: 0, False: 81.4k]
  ------------------
  371|  81.4k|                    aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (371:21): [True: 0, False: 81.4k]
  ------------------
  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|  81.4k|            else {
  387|  81.4k|                return ret;
  388|  81.4k|            }
  389|  81.4k|        }
  390|       |
  391|       |        // Process mesh normals
  392|  40.1k|        if (pMesh->mNormals && ProcessArray(pMesh->mNormals, pMesh->mNumVertices,
  ------------------
  |  Branch (392:13): [True: 40.1k, False: 0]
  |  Branch (392:32): [True: 11.1k, False: 28.9k]
  ------------------
  393|  40.1k|                                       "normals", dirtyMask, true, false))
  394|  11.1k|            ret = true;
  395|       |
  396|       |        // Process mesh tangents
  397|  40.1k|        if (pMesh->mTangents && ProcessArray(pMesh->mTangents, pMesh->mNumVertices, "tangents", dirtyMask)) {
  ------------------
  |  Branch (397:13): [True: 0, False: 40.1k]
  |  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|  40.1k|        if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents, pMesh->mNumVertices, "bitangents", dirtyMask)) {
  ------------------
  |  Branch (404:13): [True: 0, False: 40.1k]
  |  Branch (404:35): [True: 0, False: 0]
  ------------------
  405|      0|            delete[] pMesh->mTangents;
  406|      0|            pMesh->mTangents = nullptr;
  407|      0|            ret = true;
  408|      0|        }
  409|  40.1k|    }
  410|  40.1k|    return ret ? 1 : 0;
  ------------------
  |  Branch (410:12): [True: 11.1k, False: 28.9k]
  ------------------
  411|   121k|}
_Z12ProcessArrayI10aiVector3tIfEEbRPT_jPKcRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  203|   170k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) {
  204|   170k|    const char *err = ValidateArrayContents(in, num, dirtyMask, mayBeIdentical, mayBeZero);
  205|   170k|    if (err) {
  ------------------
  |  Branch (205:9): [True: 19.8k, False: 150k]
  ------------------
  206|  19.8k|        ASSIMP_LOG_ERROR("FindInvalidDataProcess fails on mesh ", name, ": ", err);
  207|  19.8k|        delete[] in;
  208|  19.8k|        in = nullptr;
  209|  19.8k|        return true;
  210|  19.8k|    }
  211|   150k|    return false;
  212|   170k|}
_Z21ValidateArrayContentsI10aiVector3tIfEEPKcPKT_jRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  175|   170k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical, bool mayBeZero) {
  176|   170k|    bool b = false;
  177|   170k|    unsigned int cnt = 0;
  178|  2.79M|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (178:30): [True: 2.63M, False: 154k]
  ------------------
  179|       |
  180|  2.63M|        if (dirtyMask.size() && dirtyMask[i]) {
  ------------------
  |  Branch (180:13): [True: 2.63M, False: 0]
  |  Branch (180:13): [True: 79.8k, False: 2.55M]
  |  Branch (180:33): [True: 79.8k, False: 2.55M]
  ------------------
  181|  79.8k|            continue;
  182|  79.8k|        }
  183|  2.55M|        ++cnt;
  184|       |
  185|  2.55M|        const aiVector3D &v = arr[i];
  186|  2.55M|        if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
  ------------------
  |  Branch (186:13): [True: 381, False: 2.55M]
  |  Branch (186:38): [True: 4.98k, False: 2.55M]
  |  Branch (186:63): [True: 344, False: 2.55M]
  ------------------
  187|  5.70k|            return "INF/NAN was found in a vector component";
  188|  5.70k|        }
  189|  2.55M|        if (!mayBeZero && !v.x && !v.y && !v.z) {
  ------------------
  |  Branch (189:13): [True: 570k, False: 1.98M]
  |  Branch (189:27): [True: 198k, False: 371k]
  |  Branch (189:35): [True: 75.4k, False: 123k]
  |  Branch (189:43): [True: 10.4k, False: 64.9k]
  ------------------
  190|  10.4k|            return "Found zero-length vector";
  191|  10.4k|        }
  192|  2.54M|        if (i && v != arr[i - 1]) b = true;
  ------------------
  |  Branch (192:13): [True: 2.37M, False: 164k]
  |  Branch (192:18): [True: 1.94M, False: 429k]
  ------------------
  193|  2.54M|    }
  194|   154k|    if (cnt > 1 && !b && !mayBeIdentical) {
  ------------------
  |  Branch (194:9): [True: 116k, False: 37.5k]
  |  Branch (194:20): [True: 24.6k, False: 92.1k]
  |  Branch (194:26): [True: 3.66k, False: 20.9k]
  ------------------
  195|  3.66k|        return "All vectors are identical";
  196|  3.66k|    }
  197|   150k|    return nullptr;
  198|   154k|}

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

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

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

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

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

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

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

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

_ZNK6Assimp19JoinVerticesProcess8IsActiveEj:
   63|  2.09k|bool JoinVerticesProcess::IsActive( unsigned int pFlags) const {
   64|  2.09k|    return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
   65|  2.09k|}
_ZN6Assimp19JoinVerticesProcess7ExecuteEP7aiScene:
   68|  2.09k|void JoinVerticesProcess::Execute( aiScene* pScene) {
   69|  2.09k|    ASSIMP_LOG_DEBUG("JoinVerticesProcess begin");
   70|       |
   71|       |    // get the total number of vertices BEFORE the step is executed
   72|  2.09k|    int iNumOldVertices = 0;
   73|  2.09k|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (73:9): [True: 0, False: 2.09k]
  ------------------
   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|  2.09k|    int iNumVertices = 0;
   81|   123k|    for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (81:30): [True: 121k, False: 2.09k]
  ------------------
   82|   121k|        iNumVertices += ProcessMesh( pScene->mMeshes[a],a);
   83|   121k|    }
   84|       |
   85|  2.09k|    pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
   86|       |
   87|       |    // if logging is active, print detailed statistics
   88|  2.09k|    if (!DefaultLogger::isNullLogger()) {
  ------------------
  |  Branch (88:9): [True: 0, False: 2.09k]
  ------------------
   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|  2.09k|}
_ZN6Assimp19JoinVerticesProcess11ProcessMeshEP6aiMeshj:
  225|   121k|int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
  226|   121k|    static_assert( AI_MAX_NUMBER_OF_COLOR_SETS    == 8, "AI_MAX_NUMBER_OF_COLOR_SETS    == 8");
  227|   121k|	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|   121k|    if (!pMesh->HasPositions() || !pMesh->HasFaces()) {
  ------------------
  |  Branch (230:9): [True: 0, False: 121k]
  |  Branch (230:35): [True: 0, False: 121k]
  ------------------
  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|   121k|    std::vector<bool> usedVertexIndicesMask;
  238|   121k|    usedVertexIndicesMask.resize(pMesh->mNumVertices, false);
  239|   818k|    for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (239:30): [True: 696k, False: 121k]
  ------------------
  240|   696k|        aiFace& face = pMesh->mFaces[a];
  241|  2.64M|        for (unsigned int b = 0; b < face.mNumIndices; b++) {
  ------------------
  |  Branch (241:34): [True: 1.94M, False: 696k]
  ------------------
  242|  1.94M|            usedVertexIndicesMask[face.mIndices[b]] = true;
  243|  1.94M|        }
  244|   696k|    }
  245|       |
  246|       |    // We'll never have more vertices afterwards.
  247|   121k|    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|   121k|    static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
  255|   121k|    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|   121k|    const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
  260|       |
  261|       |    // We'll never have more vertices afterwards.
  262|   121k|    std::vector<std::vector<int>> uniqueAnimatedVertices;
  263|   121k|    if (hasAnimMeshes) {
  ------------------
  |  Branch (263:9): [True: 0, False: 121k]
  ------------------
  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|   121k|    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|   121k|    int newIndex = 0;
  274|  2.13M|    for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
  ------------------
  |  Branch (274:30): [True: 2.00M, False: 121k]
  ------------------
  275|       |        // if the vertex is unused Do nothing
  276|  2.00M|        if (!usedVertexIndicesMask[a]) {
  ------------------
  |  Branch (276:13): [True: 64.0k, False: 1.94M]
  ------------------
  277|  64.0k|            continue;
  278|  64.0k|        }
  279|       |        // collect the vertex data
  280|  1.94M|        Vertex v(pMesh,a);
  281|       |        // is the vertex already in the map?
  282|  1.94M|        auto it = vertex2Index.find(v);
  283|       |        // if the vertex is not in the map then it is a new vertex add it.
  284|  1.94M|        if (it == vertex2Index.end()) {
  ------------------
  |  Branch (284:13): [True: 938k, False: 1.00M]
  ------------------
  285|       |            // this is a new vertex give it a new index
  286|   938k|            vertex2Index.emplace(v, newIndex);
  287|       |            // keep track of its index and increment 1
  288|   938k|            replaceIndex[a] = newIndex++;
  289|       |            // add the vertex to the unique vertices
  290|   938k|            uniqueVertices.push_back(a);
  291|   938k|            if (hasAnimMeshes) {
  ------------------
  |  Branch (291:17): [True: 0, False: 938k]
  ------------------
  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|  1.00M|        } 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|  1.00M|            replaceIndex[a] = it->second | JOINED_VERTICES_MARK;
  300|  1.00M|        }
  301|  1.94M|    }
  302|       |
  303|   121k|    if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE)    {
  ------------------
  |  Branch (303:9): [True: 0, False: 121k]
  |  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|   121k|    updateXMeshVertices(pMesh, uniqueVertices);
  318|   121k|    if (hasAnimMeshes) {
  ------------------
  |  Branch (318:9): [True: 0, False: 121k]
  ------------------
  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|   818k|    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
  ------------------
  |  Branch (325:30): [True: 696k, False: 121k]
  ------------------
  326|   696k|        aiFace& face = pMesh->mFaces[a];
  327|  2.64M|        for( unsigned int b = 0; b < face.mNumIndices; b++) {
  ------------------
  |  Branch (327:34): [True: 1.94M, False: 696k]
  ------------------
  328|  1.94M|            face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~JOINED_VERTICES_MARK;
  329|  1.94M|        }
  330|   696k|    }
  331|       |
  332|       |    // adjust bone vertex weights.
  333|   121k|    for( int a = 0; a < (int)pMesh->mNumBones; a++) {
  ------------------
  |  Branch (333:21): [True: 0, False: 121k]
  ------------------
  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|   121k|    return pMesh->mNumVertices;
  364|   121k|}
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_110HashVertexclERKN6Assimp6VertexE:
  151|  2.76M|    size_t operator () (const Vertex & v) const {
  152|  2.76M|        size_t hash = 0;
  153|       |
  154|  2.76M|        hash_combine(hash, v.position.x);
  155|  2.76M|        hash_combine(hash, v.position.y);
  156|  2.76M|        hash_combine(hash, v.position.z);
  157|       |
  158|  2.76M|        return hash;
  159|  2.76M|    }
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_110HashVertex12hash_combineERmRKf:
  146|  8.28M|    inline void hash_combine(std::size_t& seed, const ai_real& v) const {
  147|  8.28M|        std::hash<ai_real> hasher;
  148|  8.28M|        seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  149|  8.28M|    }
JoinVerticesProcess.cpp:_ZNK12_GLOBAL__N_126CompareVerticesAlmostEqualclERKN6Assimp6VertexES4_:
  104|  2.69M|    bool operator () (const Vertex & a, const Vertex & b) const {
  105|  2.69M|        static const float epsilon = 1e-5f;
  106|  2.69M|        static const float squareEpsilon = epsilon * epsilon;
  107|       |
  108|  2.69M|        if ((a.position - b.position).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (108:13): [True: 74, False: 2.69M]
  ------------------
  109|     74|            return false;
  110|     74|        }
  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|  2.69M|        if ((a.normal - b.normal).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (116:13): [True: 510k, False: 2.18M]
  ------------------
  117|   510k|            return false;
  118|   510k|        }
  119|       |
  120|  2.18M|        if ((a.tangent - b.tangent).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (120:13): [True: 0, False: 2.18M]
  ------------------
  121|      0|            return false;
  122|      0|        }
  123|       |
  124|  2.18M|        if ((a.bitangent - b.bitangent).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (124:13): [True: 0, False: 2.18M]
  ------------------
  125|      0|            return false;
  126|      0|        }
  127|       |
  128|  19.6M|        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i ++) {
  ------------------
  |  Branch (128:30): [True: 17.4M, False: 2.18M]
  ------------------
  129|  17.4M|            if ((a.texcoords[i] - b.texcoords[i]).SquareLength() > squareEpsilon) {
  ------------------
  |  Branch (129:17): [True: 0, False: 17.4M]
  ------------------
  130|      0|                return false;
  131|      0|            }
  132|  17.4M|        }
  133|       |
  134|  10.2M|        for (uint32_t i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; i ++) {
  ------------------
  |  Branch (134:30): [True: 9.23M, False: 1.00M]
  ------------------
  135|  9.23M|            if (GetColorDifference(a.colors[i], b.colors[i]) > squareEpsilon) {
  ------------------
  |  Branch (135:17): [True: 1.17M, False: 8.05M]
  ------------------
  136|  1.17M|                return false;
  137|  1.17M|            }
  138|  9.23M|        }
  139|       |
  140|       |        // If reached this point, they are ~equal
  141|  1.00M|        return true;
  142|  2.18M|    }
JoinVerticesProcess.cpp:_ZN12_GLOBAL__N_119updateXMeshVerticesI6aiMeshEEvPT_RNSt3__16vectorIiNS4_9allocatorIiEEEE:
  163|   121k|void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
  164|       |    // replace vertex data with the unique data sets
  165|   121k|    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|   121k|    if (pMesh->mVertices) {
  ------------------
  |  Branch (174:9): [True: 121k, False: 0]
  ------------------
  175|   121k|        std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
  176|   121k|        pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
  177|  1.05M|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (177:34): [True: 938k, False: 121k]
  ------------------
  178|   938k|            pMesh->mVertices[a] = oldVertices[uniqueVertices[a]];
  179|   121k|    }
  180|       |
  181|       |    // Normals, if present
  182|   121k|    if (pMesh->mNormals) {
  ------------------
  |  Branch (182:9): [True: 121k, False: 0]
  ------------------
  183|   121k|        std::unique_ptr<aiVector3D[]> oldNormals(pMesh->mNormals);
  184|   121k|        pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
  185|  1.05M|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (185:34): [True: 938k, False: 121k]
  ------------------
  186|   938k|            pMesh->mNormals[a] = oldNormals[uniqueVertices[a]];
  187|   121k|    }
  188|       |    // Tangents, if present
  189|   121k|    if (pMesh->mTangents) {
  ------------------
  |  Branch (189:9): [True: 0, False: 121k]
  ------------------
  190|      0|        std::unique_ptr<aiVector3D[]> oldTangents(pMesh->mTangents);
  191|      0|        pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
  192|      0|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (192:34): [True: 0, False: 0]
  ------------------
  193|      0|            pMesh->mTangents[a] = oldTangents[uniqueVertices[a]];
  194|      0|    }
  195|       |    // Bitangents as well
  196|   121k|    if (pMesh->mBitangents) {
  ------------------
  |  Branch (196:9): [True: 0, False: 121k]
  ------------------
  197|      0|        std::unique_ptr<aiVector3D[]> oldBitangents(pMesh->mBitangents);
  198|      0|        pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
  199|      0|        for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
  ------------------
  |  Branch (199:34): [True: 0, False: 0]
  ------------------
  200|      0|            pMesh->mBitangents[a] = oldBitangents[uniqueVertices[a]];
  201|      0|    }
  202|       |    // Vertex colors
  203|   122k|    for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) {
  ------------------
  |  Branch (203:30): [True: 752, False: 121k]
  ------------------
  204|    752|        std::unique_ptr<aiColor4D[]> oldColors(pMesh->mColors[a]);
  205|    752|        pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
  206|   448k|        for (unsigned int b = 0; b < pMesh->mNumVertices; b++)
  ------------------
  |  Branch (206:34): [True: 447k, False: 752]
  ------------------
  207|   447k|            pMesh->mColors[a][b] = oldColors[uniqueVertices[b]];
  208|    752|    }
  209|       |    // Texture coords
  210|   121k|    for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) {
  ------------------
  |  Branch (210:30): [True: 0, False: 121k]
  ------------------
  211|      0|        std::unique_ptr<aiVector3D[]> oldTextureCoords(pMesh->mTextureCoords[a]);
  212|      0|        pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
  213|      0|        for (unsigned int b = 0; b < pMesh->mNumVertices; b++)
  ------------------
  |  Branch (213:34): [True: 0, False: 0]
  ------------------
  214|      0|            pMesh->mTextureCoords[a][b] = oldTextureCoords[uniqueVertices[b]];
  215|      0|    }
  216|   121k|}

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

_ZN6Assimp23LimitBoneWeightsProcessC2Ev:
   57|  4.62k|        mMaxWeights(AI_LMW_MAX_WEIGHTS), mRemoveEmptyBones(true) {
   58|       |    // empty
   59|  4.62k|}
_ZNK6Assimp23LimitBoneWeightsProcess8IsActiveEj:
   63|  2.09k|bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const {
   64|  2.09k|    return (pFlags & aiProcess_LimitBoneWeights) != 0;
   65|  2.09k|}
_ZN6Assimp23LimitBoneWeightsProcess7ExecuteEP7aiScene:
   69|  2.09k|void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
   70|  2.09k|    ai_assert(pScene != nullptr);
   71|       |
   72|  2.09k|    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin");
   73|       |
   74|   123k|    for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
  ------------------
  |  Branch (74:30): [True: 121k, False: 2.09k]
  ------------------
   75|   121k|        ProcessMesh(pScene->mMeshes[m]);
   76|   121k|    }
   77|       |
   78|       |    ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end");
   79|  2.09k|}
_ZN6Assimp23LimitBoneWeightsProcess15SetupPropertiesEPKNS_8ImporterE:
   83|  2.09k|void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) {
   84|  2.09k|    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|  2.09k|}
_ZN6Assimp23LimitBoneWeightsProcess11ProcessMeshEP6aiMesh:
  107|   121k|void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) {
  108|   121k|    if (!pMesh->HasBones())
  ------------------
  |  Branch (108:9): [True: 121k, False: 0]
  ------------------
  109|   121k|        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|  4.62k|		count_merged() {
   78|       |	// empty
   79|  4.62k|}
_ZNK6Assimp20OptimizeGraphProcess8IsActiveEj:
   83|  2.16k|bool OptimizeGraphProcess::IsActive(unsigned int pFlags) const {
   84|  2.16k|	return (0 != (pFlags & aiProcess_OptimizeGraph));
   85|  2.16k|}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp17ValidateDSProcessC2Ev:
   61|  3.03k|ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {}
_ZN6Assimp17ValidateDSProcess11ReportErrorEPKcz:
   69|    872|AI_WONT_RETURN void ValidateDSProcess::ReportError(const char *msg, ...) {
   70|    872|    ai_assert(nullptr != msg);
   71|       |
   72|    872|    va_list args;
   73|    872|    va_start(args, msg);
   74|       |
   75|    872|    char szBuffer[3000];
   76|    872|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   77|    872|    ai_assert(iLen > 0);
   78|       |
   79|    872|    va_end(args);
   80|       |
   81|    872|    throw DeadlyImportError("Validation failed: ", std::string(szBuffer, iLen));
   82|    872|}
_ZN6Assimp17ValidateDSProcess7ExecuteEP7aiScene:
  183|  3.03k|void ValidateDSProcess::Execute(aiScene *pScene) {
  184|  3.03k|    mScene = pScene;
  185|  3.03k|    ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin");
  186|       |
  187|       |    // validate the node graph of the scene
  188|  3.03k|    Validate(pScene->mRootNode);
  189|       |
  190|       |    // validate all meshes
  191|  3.03k|    if (pScene->mNumMeshes) {
  ------------------
  |  Branch (191:9): [True: 3.03k, False: 0]
  ------------------
  192|  3.03k|        DoValidation(pScene->mMeshes, pScene->mNumMeshes, "mMeshes", "mNumMeshes");
  193|  3.03k|    } else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
  ------------------
  |  Branch (193:16): [True: 0, False: 0]
  ------------------
  194|      0|        ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there");
  195|      0|    } 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|  3.03k|    if (pScene->mNumAnimations) {
  ------------------
  |  Branch (200:9): [True: 0, False: 3.03k]
  ------------------
  201|      0|        DoValidation(pScene->mAnimations, pScene->mNumAnimations,
  202|      0|                "mAnimations", "mNumAnimations");
  203|  3.03k|    } else if (pScene->mAnimations) {
  ------------------
  |  Branch (203:16): [True: 0, False: 3.03k]
  ------------------
  204|      0|        ReportError("aiScene::mAnimations is non-null although there are no animations");
  205|      0|    }
  206|       |
  207|       |    // validate all cameras
  208|  3.03k|    if (pScene->mNumCameras) {
  ------------------
  |  Branch (208:9): [True: 0, False: 3.03k]
  ------------------
  209|      0|        DoValidationWithNameCheck(pScene->mCameras, pScene->mNumCameras,
  210|      0|                "mCameras", "mNumCameras");
  211|  3.03k|    } else if (pScene->mCameras) {
  ------------------
  |  Branch (211:16): [True: 0, False: 3.03k]
  ------------------
  212|      0|        ReportError("aiScene::mCameras is non-null although there are no cameras");
  213|      0|    }
  214|       |
  215|       |    // validate all lights
  216|  3.03k|    if (pScene->mNumLights) {
  ------------------
  |  Branch (216:9): [True: 0, False: 3.03k]
  ------------------
  217|      0|        DoValidationWithNameCheck(pScene->mLights, pScene->mNumLights,
  218|      0|                "mLights", "mNumLights");
  219|  3.03k|    } else if (pScene->mLights) {
  ------------------
  |  Branch (219:16): [True: 0, False: 3.03k]
  ------------------
  220|      0|        ReportError("aiScene::mLights is non-null although there are no lights");
  221|      0|    }
  222|       |
  223|       |    // validate all textures
  224|  3.03k|    if (pScene->mNumTextures) {
  ------------------
  |  Branch (224:9): [True: 0, False: 3.03k]
  ------------------
  225|      0|        DoValidation(pScene->mTextures, pScene->mNumTextures,
  226|      0|                "mTextures", "mNumTextures");
  227|  3.03k|    } else if (pScene->mTextures) {
  ------------------
  |  Branch (227:16): [True: 0, False: 3.03k]
  ------------------
  228|      0|        ReportError("aiScene::mTextures is non-null although there are no textures");
  229|      0|    }
  230|       |
  231|       |    // validate all materials
  232|  3.03k|    if (pScene->mNumMaterials) {
  ------------------
  |  Branch (232:9): [True: 2.16k, False: 872]
  ------------------
  233|  2.16k|        DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials");
  234|  2.16k|    }
  235|    872|    else if (pScene->mMaterials) {
  ------------------
  |  Branch (235:14): [True: 0, False: 872]
  ------------------
  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|  3.03k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMesh:
  273|  95.2k|void ValidateDSProcess::Validate(const aiMesh *pMesh) {
  274|       |    // validate the material index of the mesh
  275|  95.2k|    if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) {
  ------------------
  |  Branch (275:9): [True: 95.2k, False: 0]
  |  Branch (275:34): [True: 0, False: 95.2k]
  ------------------
  276|      0|        ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)",
  277|      0|                pMesh->mMaterialIndex, mScene->mNumMaterials - 1);
  278|      0|    }
  279|       |
  280|  95.2k|    Validate(&pMesh->mName);
  281|       |
  282|   819k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (282:30): [True: 723k, False: 95.2k]
  ------------------
  283|   723k|        aiFace &face = pMesh->mFaces[i];
  284|       |
  285|   723k|        if (pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (285:13): [True: 0, False: 723k]
  ------------------
  286|      0|            switch (face.mNumIndices) {
  287|      0|            case 0:
  ------------------
  |  Branch (287:13): [True: 0, False: 0]
  ------------------
  288|      0|                ReportError("aiMesh::mFaces[%i].mNumIndices is 0", i);
  289|      0|            case 1:
  ------------------
  |  Branch (289:13): [True: 0, False: 0]
  ------------------
  290|      0|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT)) {
  ------------------
  |  Branch (290:21): [True: 0, False: 0]
  ------------------
  291|      0|                    ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimitiveTypes "
  292|      0|                                "does not report the POINT flag",
  293|      0|                            i);
  294|      0|                }
  295|      0|                break;
  296|      0|            case 2:
  ------------------
  |  Branch (296:13): [True: 0, False: 0]
  ------------------
  297|      0|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE)) {
  ------------------
  |  Branch (297:21): [True: 0, False: 0]
  ------------------
  298|      0|                    ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimitiveTypes "
  299|      0|                                "does not report the LINE flag",
  300|      0|                            i);
  301|      0|                }
  302|      0|                break;
  303|      0|            case 3:
  ------------------
  |  Branch (303:13): [True: 0, False: 0]
  ------------------
  304|      0|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) {
  ------------------
  |  Branch (304:21): [True: 0, False: 0]
  ------------------
  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|      0|                break;
  310|      0|            default:
  ------------------
  |  Branch (310:13): [True: 0, False: 0]
  ------------------
  311|      0|                if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (311:21): [True: 0, False: 0]
  ------------------
  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|      0|                break;
  317|      0|            };
  318|      0|        }
  319|       |
  320|   723k|        if (!face.mIndices)
  ------------------
  |  Branch (320:13): [True: 0, False: 723k]
  ------------------
  321|      0|            ReportError("aiMesh::mFaces[%i].mIndices is nullptr", i);
  322|   723k|    }
  323|       |
  324|       |    // positions must always be there ...
  325|  95.2k|    if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) {
  ------------------
  |  Branch (325:9): [True: 872, False: 94.3k]
  |  Branch (325:34): [True: 0, False: 94.3k]
  |  Branch (325:55): [True: 0, False: 0]
  ------------------
  326|    872|        ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str());
  327|    872|    }
  328|       |
  329|  95.2k|    if (pMesh->mNumVertices > AI_MAX_VERTICES) {
  ------------------
  |  Branch (329:9): [True: 0, False: 95.2k]
  ------------------
  330|      0|        ReportError("Mesh has too many vertices: %u, but the limit is %u", pMesh->mNumVertices, AI_MAX_VERTICES);
  331|      0|    }
  332|  95.2k|    if (pMesh->mNumFaces > AI_MAX_FACES) {
  ------------------
  |  Branch (332:9): [True: 0, False: 95.2k]
  ------------------
  333|      0|        ReportError("Mesh has too many faces: %u, but the limit is %u", pMesh->mNumFaces, AI_MAX_FACES);
  334|      0|    }
  335|       |
  336|       |    // if tangents are there there must also be bitangent vectors ...
  337|  95.2k|    if ((pMesh->mTangents != nullptr) != (pMesh->mBitangents != nullptr)) {
  ------------------
  |  Branch (337:9): [True: 0, False: 95.2k]
  ------------------
  338|      0|        ReportError("If there are tangents, bitangent vectors must be present as well");
  339|      0|    }
  340|       |
  341|       |    // faces, too
  342|  95.2k|    if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) {
  ------------------
  |  Branch (342:9): [True: 872, False: 94.3k]
  |  Branch (342:31): [True: 0, False: 94.3k]
  |  Branch (342:49): [True: 0, False: 0]
  ------------------
  343|      0|        ReportError("Mesh %s contains no faces", pMesh->mName.C_Str());
  344|      0|    }
  345|       |
  346|       |    // now check whether the face indexing layout is correct:
  347|       |    // unique vertices, pseudo-indexed.
  348|  95.2k|    std::vector<bool> abRefList;
  349|  95.2k|    abRefList.resize(pMesh->mNumVertices, false);
  350|   819k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (350:30): [True: 723k, False: 95.2k]
  ------------------
  351|   723k|        aiFace &face = pMesh->mFaces[i];
  352|   723k|        if (face.mNumIndices > AI_MAX_FACE_INDICES) {
  ------------------
  |  Branch (352:13): [True: 0, False: 723k]
  ------------------
  353|      0|            ReportError("Face %u has too many faces: %u, but the limit is %u", i, face.mNumIndices, AI_MAX_FACE_INDICES);
  354|      0|        }
  355|       |
  356|  2.89M|        for (unsigned int a = 0; a < face.mNumIndices; ++a) {
  ------------------
  |  Branch (356:34): [True: 2.17M, False: 723k]
  ------------------
  357|  2.17M|            if (face.mIndices[a] >= pMesh->mNumVertices) {
  ------------------
  |  Branch (357:17): [True: 0, False: 2.17M]
  ------------------
  358|      0|                ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a);
  359|      0|            }
  360|  2.17M|            abRefList[face.mIndices[a]] = true;
  361|  2.17M|        }
  362|   723k|    }
  363|       |
  364|       |    // check whether there are vertices that aren't referenced by a face
  365|  95.2k|    bool b = false;
  366|  2.26M|    for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (366:30): [True: 2.17M, False: 95.2k]
  ------------------
  367|  2.17M|        if (!abRefList[i]) b = true;
  ------------------
  |  Branch (367:13): [True: 0, False: 2.17M]
  ------------------
  368|  2.17M|    }
  369|  95.2k|    abRefList.clear();
  370|  95.2k|    if (b) {
  ------------------
  |  Branch (370:9): [True: 0, False: 95.2k]
  ------------------
  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|  95.2k|    {
  376|  95.2k|        unsigned int i = 0;
  377|  95.7k|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
  ------------------
  |  Branch (377:16): [True: 94.8k, False: 872]
  ------------------
  378|  94.8k|            if (!pMesh->HasVertexColors(i)) break;
  ------------------
  |  Branch (378:17): [True: 94.3k, False: 521]
  ------------------
  379|  94.8k|        }
  380|   849k|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i)
  ------------------
  |  Branch (380:16): [True: 754k, False: 95.2k]
  ------------------
  381|   754k|            if (pMesh->HasVertexColors(i)) {
  ------------------
  |  Branch (381:17): [True: 0, False: 754k]
  ------------------
  382|      0|                ReportError("Vertex color channel %i is exists "
  383|      0|                            "although the previous channel was nullptr.",
  384|      0|                        i);
  385|      0|            }
  386|  95.2k|    }
  387|       |
  388|       |    // now validate all bones
  389|  95.2k|    if (pMesh->mNumBones) {
  ------------------
  |  Branch (389:9): [True: 0, False: 95.2k]
  ------------------
  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|  95.2k|    } else if (pMesh->mBones) {
  ------------------
  |  Branch (432:16): [True: 0, False: 95.2k]
  ------------------
  433|      0|        ReportError("aiMesh::mBones is non-null although there are no bones");
  434|      0|    }
  435|  95.2k|}
_ZN6Assimp17ValidateDSProcess24SearchForInvalidTexturesEPK10aiMaterial13aiTextureType:
  491|  36.7k|        aiTextureType type) {
  492|  36.7k|    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|  36.7k|    int iNumIndices = 0;
  501|  36.7k|    int iIndex = -1;
  502|   183k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (502:30): [True: 147k, False: 36.7k]
  ------------------
  503|   147k|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  504|   147k|        ai_assert(nullptr != prop);
  505|   147k|        if (!::strcmp(prop->mKey.data, "$tex.file") && prop->mSemantic == static_cast<unsigned int>(type)) {
  ------------------
  |  Branch (505:13): [True: 0, False: 147k]
  |  Branch (505:56): [True: 0, False: 0]
  ------------------
  506|      0|            iIndex = std::max(iIndex, (int)prop->mIndex);
  507|      0|            ++iNumIndices;
  508|       |
  509|      0|            if (aiPTI_String != prop->mType) {
  ------------------
  |  Branch (509:17): [True: 0, False: 0]
  ------------------
  510|      0|                ReportError("Material property %s is expected to be a string", prop->mKey.data);
  511|      0|            }
  512|      0|        }
  513|   147k|    }
  514|  36.7k|    if (iIndex + 1 != iNumIndices) {
  ------------------
  |  Branch (514:9): [True: 0, False: 36.7k]
  ------------------
  515|      0|        ReportError("%s #%i is set, but there are only %i %s textures",
  516|      0|                szType, iIndex, iNumIndices, szType);
  517|      0|    }
  518|  36.7k|    if (!iNumIndices) {
  ------------------
  |  Branch (518:9): [True: 36.7k, False: 0]
  ------------------
  519|  36.7k|        return;
  520|  36.7k|    }
  521|      0|    std::vector<aiTextureMapping> mappings(iNumIndices);
  522|       |
  523|       |    // Now check whether all UV indices are valid ...
  524|      0|    bool bNoSpecified = true;
  525|      0|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (525:30): [True: 0, False: 0]
  ------------------
  526|      0|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  527|      0|        if (static_cast<aiTextureType>(prop->mSemantic) != type) {
  ------------------
  |  Branch (527:13): [True: 0, False: 0]
  ------------------
  528|      0|            continue;
  529|      0|        }
  530|       |
  531|      0|        if ((int)prop->mIndex >= iNumIndices) {
  ------------------
  |  Branch (531:13): [True: 0, False: 0]
  ------------------
  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|      0|        if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
  ------------------
  |  Branch (537:13): [True: 0, False: 0]
  ------------------
  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|      0|        } else if (!::strcmp(prop->mKey.data, "$tex.uvtrafo")) {
  ------------------
  |  Branch (543:20): [True: 0, False: 0]
  ------------------
  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|      0|        } else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
  ------------------
  |  Branch (549:20): [True: 0, False: 0]
  ------------------
  550|      0|            if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) {
  ------------------
  |  Branch (550:17): [True: 0, False: 0]
  |  Branch (550:49): [True: 0, False: 0]
  ------------------
  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|      0|            bNoSpecified = false;
  555|       |
  556|       |            // Ignore UV indices for texture channels that are not there ...
  557|       |
  558|       |            // Get the value
  559|      0|            iIndex = *((unsigned int *)prop->mData);
  560|       |
  561|       |            // Check whether there is a mesh using this material
  562|       |            // which has not enough UV channels ...
  563|      0|            for (unsigned int a = 0; a < mScene->mNumMeshes; ++a) {
  ------------------
  |  Branch (563:38): [True: 0, False: 0]
  ------------------
  564|      0|                aiMesh *mesh = this->mScene->mMeshes[a];
  565|      0|                if (mesh->mMaterialIndex == (unsigned int)i) {
  ------------------
  |  Branch (565:21): [True: 0, False: 0]
  ------------------
  566|      0|                    int iChannels = 0;
  567|      0|                    while (mesh->HasTextureCoords(iChannels))
  ------------------
  |  Branch (567:28): [True: 0, False: 0]
  ------------------
  568|      0|                        ++iChannels;
  569|      0|                    if (iIndex >= iChannels) {
  ------------------
  |  Branch (569:25): [True: 0, False: 0]
  ------------------
  570|      0|                        ReportWarning("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels",
  571|      0|                                iIndex, prop->mKey.data, a, iChannels);
  572|      0|                    }
  573|      0|                }
  574|      0|            }
  575|      0|        }
  576|      0|    }
  577|      0|    if (bNoSpecified) {
  ------------------
  |  Branch (577:9): [True: 0, False: 0]
  ------------------
  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|      0|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK10aiMaterial:
  593|  2.16k|void ValidateDSProcess::Validate(const aiMaterial *pMaterial) {
  594|       |    // check whether there are material keys that are obviously not legal
  595|  10.8k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (595:30): [True: 8.65k, False: 2.16k]
  ------------------
  596|  8.65k|        const aiMaterialProperty *prop = pMaterial->mProperties[i];
  597|  8.65k|        if (!prop) {
  ------------------
  |  Branch (597:13): [True: 0, False: 8.65k]
  ------------------
  598|      0|            ReportError("aiMaterial::mProperties[%i] is nullptr (aiMaterial::mNumProperties is %i)",
  599|      0|                    i, pMaterial->mNumProperties);
  600|      0|        }
  601|  8.65k|        if (!prop->mDataLength || !prop->mData) {
  ------------------
  |  Branch (601:13): [True: 0, False: 8.65k]
  |  Branch (601:35): [True: 0, False: 8.65k]
  ------------------
  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|  8.65k|        if (aiPTI_String == prop->mType) {
  ------------------
  |  Branch (607:13): [True: 2.16k, False: 6.48k]
  ------------------
  608|       |            // FIX: strings are now stored in a less expensive way, but we can't use the
  609|       |            // validation routine for 'normal' aiStrings
  610|  2.16k|            if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast<uint32_t *>(prop->mData)) + 1) {
  ------------------
  |  Branch (610:17): [True: 0, False: 2.16k]
  |  Branch (610:42): [True: 0, False: 2.16k]
  ------------------
  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|  2.16k|            if (prop->mData[prop->mDataLength - 1]) {
  ------------------
  |  Branch (615:17): [True: 0, False: 2.16k]
  ------------------
  616|      0|                ReportError("Missing null-terminator in string material property");
  617|      0|            }
  618|       |            //  Validate((const aiString*)prop->mData);
  619|  6.48k|        } else if (aiPTI_Float == prop->mType) {
  ------------------
  |  Branch (619:20): [True: 6.48k, False: 0]
  ------------------
  620|  6.48k|            if (prop->mDataLength < sizeof(float)) {
  ------------------
  |  Branch (620:17): [True: 0, False: 6.48k]
  ------------------
  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|  6.48k|        } else if (aiPTI_Integer == prop->mType) {
  ------------------
  |  Branch (625:20): [True: 0, False: 0]
  ------------------
  626|      0|            if (prop->mDataLength < sizeof(int)) {
  ------------------
  |  Branch (626:17): [True: 0, False: 0]
  ------------------
  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|      0|        }
  632|       |        // TODO: check whether there is a key with an unknown name ...
  633|  8.65k|    }
  634|       |
  635|       |    // make some more specific tests
  636|  2.16k|    ai_real fTemp;
  637|  2.16k|    int iShading;
  638|  2.16k|    if (AI_SUCCESS == aiGetMaterialInteger(pMaterial, AI_MATKEY_SHADING_MODEL, &iShading)) {
  ------------------
  |  Branch (638:9): [True: 0, False: 2.16k]
  ------------------
  639|      0|        switch ((aiShadingMode)iShading) {
  640|      0|        case aiShadingMode_Blinn:
  ------------------
  |  Branch (640:9): [True: 0, False: 0]
  ------------------
  641|      0|        case aiShadingMode_CookTorrance:
  ------------------
  |  Branch (641:9): [True: 0, False: 0]
  ------------------
  642|      0|        case aiShadingMode_Phong:
  ------------------
  |  Branch (642:9): [True: 0, False: 0]
  ------------------
  643|       |
  644|      0|            if (AI_SUCCESS != aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS, &fTemp)) {
  ------------------
  |  Branch (644:17): [True: 0, False: 0]
  ------------------
  645|      0|                ReportWarning("A specular shading model is specified but there is no "
  646|      0|                              "AI_MATKEY_SHININESS key");
  647|      0|            }
  648|      0|            if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_SHININESS_STRENGTH, &fTemp) && !fTemp) {
  ------------------
  |  Branch (648:17): [True: 0, False: 0]
  |  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|      0|            break;
  653|      0|        default:
  ------------------
  |  Branch (653:9): [True: 0, False: 0]
  ------------------
  654|      0|            break;
  655|      0|        }
  656|      0|    }
  657|       |
  658|  2.16k|    if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_OPACITY, &fTemp) && (!fTemp || fTemp > 1.01)) {
  ------------------
  |  Branch (658:9): [True: 0, False: 2.16k]
  |  Branch (658:84): [True: 0, False: 0]
  |  Branch (658:94): [True: 0, False: 0]
  ------------------
  659|      0|        ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)");
  660|      0|    }
  661|       |
  662|       |    // Check whether there are invalid texture keys
  663|       |    // TODO: that's a relict of the past, where texture type and index were baked
  664|       |    // into the material string ... we could do that in one single pass.
  665|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE);
  666|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_SPECULAR);
  667|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT);
  668|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSIVE);
  669|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_OPACITY);
  670|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_SHININESS);
  671|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_HEIGHT);
  672|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMALS);
  673|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_DISPLACEMENT);
  674|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_LIGHTMAP);
  675|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_REFLECTION);
  676|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_BASE_COLOR);
  677|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMAL_CAMERA);
  678|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSION_COLOR);
  679|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_METALNESS);
  680|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE_ROUGHNESS);
  681|  2.16k|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT_OCCLUSION);
  682|  2.16k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiNode:
  850|   316k|void ValidateDSProcess::Validate(const aiNode *pNode) {
  851|   316k|    if (!pNode) {
  ------------------
  |  Branch (851:9): [True: 0, False: 316k]
  ------------------
  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|   316k|    this->Validate(&pNode->mName);
  856|   316k|    const char *nodeName = (&pNode->mName)->C_Str();
  857|   316k|    if (pNode != mScene->mRootNode && !pNode->mParent) {
  ------------------
  |  Branch (857:9): [True: 313k, False: 3.03k]
  |  Branch (857:39): [True: 0, False: 313k]
  ------------------
  858|      0|        ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is nullptr) ", nodeName);
  859|      0|    }
  860|       |
  861|       |    // validate all meshes
  862|   316k|    if (pNode->mNumMeshes) {
  ------------------
  |  Branch (862:9): [True: 313k, False: 3.03k]
  ------------------
  863|   313k|        if (!pNode->mMeshes) {
  ------------------
  |  Branch (863:13): [True: 0, False: 313k]
  ------------------
  864|      0|            ReportError("aiNode::mMeshes is nullptr for node %s (aiNode::mNumMeshes is %i)",
  865|      0|                    nodeName, pNode->mNumMeshes);
  866|      0|        }
  867|   313k|        std::vector<bool> abHadMesh;
  868|   313k|        abHadMesh.resize(mScene->mNumMeshes, false);
  869|   627k|        for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) {
  ------------------
  |  Branch (869:34): [True: 313k, False: 313k]
  ------------------
  870|   313k|            if (pNode->mMeshes[i] >= mScene->mNumMeshes) {
  ------------------
  |  Branch (870:17): [True: 0, False: 313k]
  ------------------
  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|   313k|            if (abHadMesh[pNode->mMeshes[i]]) {
  ------------------
  |  Branch (874:17): [True: 0, False: 313k]
  ------------------
  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|   313k|            abHadMesh[pNode->mMeshes[i]] = true;
  879|   313k|        }
  880|   313k|    }
  881|   316k|    if (pNode->mNumChildren) {
  ------------------
  |  Branch (881:9): [True: 3.03k, False: 313k]
  ------------------
  882|  3.03k|        if (!pNode->mChildren) {
  ------------------
  |  Branch (882:13): [True: 0, False: 3.03k]
  ------------------
  883|      0|            ReportError("aiNode::mChildren is nullptr for node %s (aiNode::mNumChildren is %i)",
  884|      0|                    nodeName, pNode->mNumChildren);
  885|      0|        }
  886|   316k|        for (unsigned int i = 0; i < pNode->mNumChildren; ++i) {
  ------------------
  |  Branch (886:34): [True: 313k, False: 3.03k]
  ------------------
  887|   313k|            const aiNode *pChild = pNode->mChildren[i];
  888|   313k|            Validate(pChild);
  889|   313k|            if (pChild->mParent != pNode) {
  ------------------
  |  Branch (889:17): [True: 0, False: 313k]
  ------------------
  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|   313k|        }
  894|   313k|    } else if (pNode->mChildren) {
  ------------------
  |  Branch (894:16): [True: 0, False: 313k]
  ------------------
  895|      0|        ReportError("aiNode::mChildren is not nullptr for empty node %s (aiNode::mNumChildren is %i)",
  896|      0|                nodeName, pNode->mNumChildren);
  897|      0|    }
  898|   316k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiString:
  901|   411k|void ValidateDSProcess::Validate(const aiString *pString) {
  902|   411k|    if (pString->length > AI_MAXLEN) {
  ------------------
  |  Branch (902:9): [True: 0, False: 411k]
  ------------------
  903|      0|        ReportError("aiString::length is too large (%u, maximum is %lu)",
  904|      0|                pString->length, AI_MAXLEN);
  905|      0|    }
  906|   411k|    const char *sz = pString->data;
  907|  1.66M|    while (true) {
  ------------------
  |  Branch (907:12): [True: 1.66M, Folded]
  ------------------
  908|  1.66M|        if ('\0' == *sz) {
  ------------------
  |  Branch (908:13): [True: 411k, False: 1.25M]
  ------------------
  909|   411k|            if (pString->length != (unsigned int)(sz - pString->data)) {
  ------------------
  |  Branch (909:17): [True: 0, False: 411k]
  ------------------
  910|      0|                ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
  911|      0|            }
  912|   411k|            break;
  913|  1.25M|        } else if (sz >= &pString->data[AI_MAXLEN]) {
  ------------------
  |  Branch (913:20): [True: 0, False: 1.25M]
  ------------------
  914|      0|            ReportError("aiString::data is invalid. There is no terminal character");
  915|      0|        }
  916|  1.25M|        ++sz;
  917|  1.25M|    }
  918|   411k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI6aiMeshEEvPPT_jPKcS7_:
  109|  3.03k|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|  3.03k|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 3.03k]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|  3.03k|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 3.03k]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|  98.2k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 95.2k, False: 3.03k]
  ------------------
  121|  95.2k|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 95.2k]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|  95.2k|        Validate(parray[i]);
  126|  95.2k|    }
  127|  3.03k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI10aiMaterialEEvPPT_jPKcS7_:
  109|  2.16k|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|  2.16k|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 2.16k]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|  2.16k|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 2.16k]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|  4.32k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 2.16k, False: 2.16k]
  ------------------
  121|  2.16k|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 2.16k]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|  2.16k|        Validate(parray[i]);
  126|  2.16k|    }
  127|  2.16k|}

_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|  9.25k|	PUGI_IMPL_FN xml_node::xml_node(): _root(nullptr)
 5594|  9.25k|	{
 5595|  9.25k|	}
_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|    219|    {
  233|   220k|        while (start != end)
  ------------------
  |  Branch (233:16): [True: 219k, False: 219]
  ------------------
  234|   219k|            result = utf8::append(*(start++), result);
  235|       |
  236|    219|        return result;
  237|    219|    }
_ZN4utf86appendINSt3__120back_insert_iteratorINS1_6vectorIcNS1_9allocatorIcEEEEEEEET_jS8_:
   75|   219k|    {
   76|   219k|        if (!utf8::internal::is_code_point_valid(cp))
  ------------------
  |  Branch (76:13): [True: 219, False: 219k]
  ------------------
   77|    219|            throw invalid_code_point(cp);
   78|       |
   79|   219k|        return internal::append(cp, result);
   80|   219k|    }
_ZN4utf818invalid_code_pointC2Ej:
   44|    219|        invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
_ZNK4utf818invalid_code_point4whatEv:
   45|    438|        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|    166|    {
  191|  1.63M|        while (start != end) {
  ------------------
  |  Branch (191:16): [True: 1.63M, False: 166]
  ------------------
  192|  1.63M|            uint32_t cp = utf8::internal::mask16(*start++);
  193|       |            // Take care of surrogate pairs first
  194|  1.63M|            if (utf8::internal::is_lead_surrogate(cp)) {
  ------------------
  |  Branch (194:17): [True: 0, False: 1.63M]
  ------------------
  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|  1.63M|            else if (utf8::internal::is_trail_surrogate(cp))
  ------------------
  |  Branch (207:22): [True: 0, False: 1.63M]
  ------------------
  208|      0|                throw invalid_utf16(static_cast<uint16_t>(cp));
  209|       |
  210|  1.63M|            result = utf8::append(cp, result);
  211|  1.63M|        }
  212|    166|        return result;
  213|    166|    }
_ZN4utf86appendINSt3__120back_insert_iteratorINS1_6vectorIhNS1_9allocatorIhEEEEEEEET_jS8_:
   75|  1.63M|    {
   76|  1.63M|        if (!utf8::internal::is_code_point_valid(cp))
  ------------------
  |  Branch (76:13): [True: 0, False: 1.63M]
  ------------------
   77|      0|            throw invalid_code_point(cp);
   78|       |
   79|  1.63M|        return internal::append(cp, result);
   80|  1.63M|    }

_ZN4utf88internal19is_code_point_validIjEEbT_:
  111|  1.85M|    {
  112|  1.85M|        return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
  ------------------
  |  Branch (112:17): [True: 1.85M, False: 205]
  |  Branch (112:41): [True: 1.85M, False: 14]
  ------------------
  113|  1.85M|    }
_ZN4utf88internal12is_surrogateIjEEbT_:
  105|  1.85M|    {
  106|  1.85M|        return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
  ------------------
  |  Branch (106:17): [True: 1.46M, False: 386k]
  |  Branch (106:45): [True: 14, False: 1.46M]
  ------------------
  107|  1.85M|    }
_ZN4utf88internal6appendINSt3__16vectorIcNS2_9allocatorIcEEEEEENS2_20back_insert_iteratorIT_EEjS9_:
  336|   219k|            (uint32_t cp, std::back_insert_iterator<container_type> result) {
  337|   219k|        return append<std::back_insert_iterator<container_type>,
  338|   219k|            typename container_type::value_type>(cp, result);
  339|   219k|    }
_ZN4utf88internal6appendINSt3__120back_insert_iteratorINS2_6vectorIcNS2_9allocatorIcEEEEEEcEET_jS9_:
  304|   219k|    octet_iterator append(uint32_t cp, octet_iterator result) {
  305|   219k|        if (cp < 0x80)                        // one octet
  ------------------
  |  Branch (305:13): [True: 200k, False: 19.5k]
  ------------------
  306|   200k|            *(result++) = static_cast<octet_type>(cp);
  307|  19.5k|        else if (cp < 0x800) {                // two octets
  ------------------
  |  Branch (307:18): [True: 1.02k, False: 18.4k]
  ------------------
  308|  1.02k|            *(result++) = static_cast<octet_type>((cp >> 6)          | 0xc0);
  309|  1.02k|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  310|  1.02k|        }
  311|  18.4k|        else if (cp < 0x10000) {              // three octets
  ------------------
  |  Branch (311:18): [True: 1.25k, False: 17.2k]
  ------------------
  312|  1.25k|            *(result++) = static_cast<octet_type>((cp >> 12)         | 0xe0);
  313|  1.25k|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  314|  1.25k|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  315|  1.25k|        }
  316|  17.2k|        else {                                // four octets
  317|  17.2k|            *(result++) = static_cast<octet_type>((cp >> 18)         | 0xf0);
  318|  17.2k|            *(result++) = static_cast<octet_type>(((cp >> 12) & 0x3f)| 0x80);
  319|  17.2k|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  320|  17.2k|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  321|  17.2k|        }
  322|   219k|        return result;
  323|   219k|    }
_ZN4utf88internal6mask16IcEEtT_:
   82|  1.63M|    {
   83|  1.63M|        return static_cast<uint16_t>(0xffff & oc);
   84|  1.63M|    }
_ZN4utf88internal17is_lead_surrogateIjEEbT_:
   93|  1.63M|    {
   94|  1.63M|        return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
  ------------------
  |  Branch (94:17): [True: 1.44M, False: 184k]
  |  Branch (94:45): [True: 0, False: 1.44M]
  ------------------
   95|  1.63M|    }
_ZN4utf88internal18is_trail_surrogateIjEEbT_:
   99|  1.63M|    {
  100|  1.63M|        return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
  ------------------
  |  Branch (100:17): [True: 1.44M, False: 184k]
  |  Branch (100:46): [True: 0, False: 1.44M]
  ------------------
  101|  1.63M|    }
_ZN4utf88internal6appendINSt3__16vectorIhNS2_9allocatorIhEEEEEENS2_20back_insert_iteratorIT_EEjS9_:
  336|  1.63M|            (uint32_t cp, std::back_insert_iterator<container_type> result) {
  337|  1.63M|        return append<std::back_insert_iterator<container_type>,
  338|  1.63M|            typename container_type::value_type>(cp, result);
  339|  1.63M|    }
_ZN4utf88internal6appendINSt3__120back_insert_iteratorINS2_6vectorIhNS2_9allocatorIhEEEEEEhEET_jS9_:
  304|  1.63M|    octet_iterator append(uint32_t cp, octet_iterator result) {
  305|  1.63M|        if (cp < 0x80)                        // one octet
  ------------------
  |  Branch (305:13): [True: 184k, False: 1.44M]
  ------------------
  306|   184k|            *(result++) = static_cast<octet_type>(cp);
  307|  1.44M|        else if (cp < 0x800) {                // two octets
  ------------------
  |  Branch (307:18): [True: 0, False: 1.44M]
  ------------------
  308|      0|            *(result++) = static_cast<octet_type>((cp >> 6)          | 0xc0);
  309|      0|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  310|      0|        }
  311|  1.44M|        else if (cp < 0x10000) {              // three octets
  ------------------
  |  Branch (311:18): [True: 1.44M, False: 0]
  ------------------
  312|  1.44M|            *(result++) = static_cast<octet_type>((cp >> 12)         | 0xe0);
  313|  1.44M|            *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
  314|  1.44M|            *(result++) = static_cast<octet_type>((cp & 0x3f)        | 0x80);
  315|  1.44M|        }
  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|  1.63M|        return result;
  323|  1.63M|    }

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

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

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

