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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp17ScenePreprocessor12ProcessSceneEv:
   50|  1.95k|void ScenePreprocessor::ProcessScene() {
   51|  1.95k|    ai_assert(scene != nullptr);
  ------------------
  |  |   67|  1.95k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 1.95k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
   52|       |
   53|       |    // Process all meshes
   54|   118k|    for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
  ------------------
  |  Branch (54:30): [True: 116k, False: 1.95k]
  ------------------
   55|   116k|        if (nullptr == scene->mMeshes[i]) {
  ------------------
  |  Branch (55:13): [True: 0, False: 116k]
  ------------------
   56|      0|            continue;
   57|      0|        }
   58|   116k|        ProcessMesh(scene->mMeshes[i]);
   59|   116k|    }
   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|  1.95k|    for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
  ------------------
  |  Branch (67:30): [True: 0, False: 1.95k]
  ------------------
   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|  1.95k|    if (!scene->mNumMaterials && scene->mNumMeshes) {
  ------------------
  |  Branch (75:9): [True: 0, False: 1.95k]
  |  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|  1.95k|}
_ZN6Assimp17ScenePreprocessor11ProcessMeshEP6aiMesh:
  103|   116k|void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
  104|       |    // If aiMesh::mNumUVComponents is *not* set assign the default value of 2
  105|  1.04M|    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
  ------------------
  |  Branch (105:30): [True: 932k, False: 116k]
  ------------------
  106|   932k|        if (!mesh->mTextureCoords[i]) {
  ------------------
  |  Branch (106:13): [True: 932k, False: 0]
  ------------------
  107|   932k|            mesh->mNumUVComponents[i] = 0;
  108|   932k|            continue;
  109|   932k|        }
  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|   116k|    if (!mesh->mPrimitiveTypes) {
  ------------------
  |  Branch (144:9): [True: 116k, False: 0]
  ------------------
  145|   116k|        ai_assert(mesh->mFaces != nullptr);
  ------------------
  |  |   67|   116k|#   define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0))
  |  |  ------------------
  |  |  |  Branch (67:41): [True: 116k, False: 0]
  |  |  |  Branch (67:61): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  146|   986k|        for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
  ------------------
  |  Branch (146:34): [True: 869k, False: 116k]
  ------------------
  147|   869k|            aiFace &face = mesh->mFaces[a];
  148|   869k|            switch (face.mNumIndices) {
  149|   869k|            case 3u:
  ------------------
  |  Branch (149:13): [True: 869k, False: 0]
  ------------------
  150|   869k|                mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
  151|   869k|                break;
  152|       |
  153|      0|            case 2u:
  ------------------
  |  Branch (153:13): [True: 0, False: 869k]
  ------------------
  154|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
  155|      0|                break;
  156|       |
  157|      0|            case 1u:
  ------------------
  |  Branch (157:13): [True: 0, False: 869k]
  ------------------
  158|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
  159|      0|                break;
  160|       |
  161|      0|            default:
  ------------------
  |  Branch (161:13): [True: 0, False: 869k]
  ------------------
  162|      0|                mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
  163|      0|                break;
  164|   869k|            }
  165|   869k|        }
  166|   116k|    }
  167|       |
  168|       |    // If tangents and normals are given but no bitangents compute them
  169|   116k|    if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) {
  ------------------
  |  Branch (169:9): [True: 0, False: 116k]
  |  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|   116k|}

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

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

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

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

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

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

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

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

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

aiGetMaterialProperty:
   63|  3.91k|        const aiMaterialProperty **pPropOut) {
   64|  3.91k|    ai_assert(pMat != nullptr);
   65|  3.91k|    ai_assert(pKey != nullptr);
   66|  3.91k|    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|  19.5k|    for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
  ------------------
  |  Branch (72:30): [True: 15.6k, False: 3.91k]
  ------------------
   73|  15.6k|        aiMaterialProperty *prop = pMat->mProperties[i];
   74|       |
   75|  15.6k|        if (prop /* just for safety ... */
  ------------------
  |  Branch (75:13): [True: 15.6k, False: 0]
  ------------------
   76|  15.6k|                && 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: 15.6k]
  |  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|  15.6k|    }
   82|  3.91k|    *pPropOut = nullptr;
   83|       |
   84|       |    return AI_FAILURE;
   85|  3.91k|}
aiGetMaterialFloatArray:
  194|  1.95k|        unsigned int *pMax) {
  195|  1.95k|    return GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
  196|  1.95k|}
aiGetMaterialIntegerArray:
  205|  1.95k|        unsigned int *pMax) {
  206|  1.95k|    ai_assert(pOut != nullptr);
  207|  1.95k|    ai_assert(pMat != nullptr);
  208|       |
  209|  1.95k|    const aiMaterialProperty *prop;
  210|  1.95k|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  211|  1.95k|    if (!prop) {
  ------------------
  |  Branch (211:9): [True: 1.95k, False: 0]
  ------------------
  212|  1.95k|        return AI_FAILURE;
  213|  1.95k|    }
  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|  2.78k|aiMaterial::aiMaterial() : mProperties(nullptr), mNumProperties(0), mNumAllocated(DefaultNumAllocated) {
  419|       |    // Allocate 5 entries by default
  420|  2.78k|    mProperties = new aiMaterialProperty *[DefaultNumAllocated];
  421|  2.78k|}
_ZN10aiMaterialD2Ev:
  424|  2.78k|aiMaterial::~aiMaterial() {
  425|  2.78k|    Clear();
  426|       |
  427|  2.78k|    delete[] mProperties;
  428|  2.78k|}
_ZN10aiMaterial5ClearEv:
  439|  2.78k|void aiMaterial::Clear() {
  440|  13.9k|    for (unsigned int i = 0; i < mNumProperties; ++i) {
  ------------------
  |  Branch (440:30): [True: 11.1k, False: 2.78k]
  ------------------
  441|       |        // delete this entry
  442|  11.1k|        delete mProperties[i];
  443|  11.1k|        AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
  444|  11.1k|    }
  445|  2.78k|    mNumProperties = 0;
  446|       |
  447|       |    // The array remains allocated, we just invalidated its contents
  448|  2.78k|}
_ZN10aiMaterial17AddBinaryPropertyEPKvjPKcjj18aiPropertyTypeInfo:
  480|  11.1k|        aiPropertyTypeInfo pType) {
  481|  11.1k|    ai_assert(pInput != nullptr);
  482|  11.1k|    ai_assert(pKey != nullptr);
  483|  11.1k|    ai_assert(0 != pSizeInBytes);
  484|       |
  485|  11.1k|    if (0 == pSizeInBytes) {
  ------------------
  |  Branch (485:9): [True: 0, False: 11.1k]
  ------------------
  486|      0|        return AI_FAILURE;
  487|      0|    }
  488|       |
  489|       |    // first search the list whether there is already an entry with this key
  490|  11.1k|    unsigned int iOutIndex(UINT_MAX);
  491|  27.8k|    for (unsigned int i = 0; i < mNumProperties; ++i) {
  ------------------
  |  Branch (491:30): [True: 16.7k, False: 11.1k]
  ------------------
  492|  16.7k|        aiMaterialProperty *prop(mProperties[i]);
  493|       |
  494|  16.7k|        if (prop /* just for safety */ && !strcmp(prop->mKey.data, pKey) &&
  ------------------
  |  Branch (494:13): [True: 16.7k, False: 0]
  |  Branch (494:43): [True: 0, False: 16.7k]
  ------------------
  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|  16.7k|    }
  501|       |
  502|       |    // Allocate a new material property
  503|  11.1k|    auto pcNew = std::make_unique<aiMaterialProperty>();
  504|       |
  505|       |    // .. and fill it
  506|  11.1k|    pcNew->mType = pType;
  507|  11.1k|    pcNew->mSemantic = type;
  508|  11.1k|    pcNew->mIndex = index;
  509|       |
  510|  11.1k|    pcNew->mDataLength = pSizeInBytes;
  511|  11.1k|    pcNew->mData = new char[pSizeInBytes];
  512|  11.1k|    memcpy(pcNew->mData, pInput, pSizeInBytes);
  513|       |
  514|  11.1k|    const size_t keyLen = ::strlen(pKey);
  515|  11.1k|    pcNew->mKey.length = static_cast<ai_uint32>(std::min<size_t>(keyLen, AI_MAXLEN - 1));
  516|  11.1k|    if (keyLen >= AI_MAXLEN) {
  ------------------
  |  Branch (516:9): [True: 0, False: 11.1k]
  ------------------
  517|      0|        ASSIMP_LOG_WARN("aiMaterial: property key '", pKey, "' exceeds AI_MAXLEN and will be truncated.");
  518|      0|    }
  519|  11.1k|	memcpy(pcNew->mKey.data, pKey, pcNew->mKey.length);
  520|  11.1k|    pcNew->mKey.data[pcNew->mKey.length] = '\0';
  521|       |
  522|  11.1k|    if (UINT_MAX != iOutIndex) {
  ------------------
  |  Branch (522:9): [True: 0, False: 11.1k]
  ------------------
  523|      0|        mProperties[iOutIndex] = pcNew.release();
  524|      0|        return AI_SUCCESS;
  525|      0|    }
  526|       |
  527|       |    // resize the array ... double the storage allocated
  528|  11.1k|    if (mNumProperties == mNumAllocated) {
  ------------------
  |  Branch (528:9): [True: 0, False: 11.1k]
  ------------------
  529|      0|        const unsigned int iOld = mNumAllocated;
  530|      0|        mNumAllocated *= 2;
  531|       |
  532|      0|        aiMaterialProperty **ppTemp;
  533|      0|        try {
  534|      0|            ppTemp = new aiMaterialProperty *[mNumAllocated];
  535|      0|        } catch (std::bad_alloc &) {
  536|      0|            return AI_OUTOFMEMORY;
  537|      0|        }
  538|       |
  539|       |        // just copy all items over; then replace the old array
  540|      0|        memcpy(ppTemp, mProperties, iOld * sizeof(void *));
  541|       |
  542|      0|        delete[] mProperties;
  543|      0|        mProperties = ppTemp;
  544|      0|    }
  545|       |    // push back ...
  546|  11.1k|    mProperties[mNumProperties++] = pcNew.release();
  547|       |
  548|       |    return AI_SUCCESS;
  549|  11.1k|}
_ZN10aiMaterial11AddPropertyEPK8aiStringPKcjj:
  555|  2.78k|        unsigned int index) {
  556|       |    ai_assert(sizeof(ai_uint32) == 4);
  557|  2.78k|    return AddBinaryProperty(pInput,
  558|  2.78k|            static_cast<unsigned int>(pInput->length + 1 + 4),
  559|  2.78k|            pKey,
  560|  2.78k|            type,
  561|  2.78k|            index,
  562|  2.78k|            aiPTI_String);
  563|  2.78k|}
_ZN6Assimp19ComputeMaterialHashEPK10aiMaterialb:
  566|  1.95k|uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName /*= false*/) {
  567|  1.95k|    uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
  568|  9.79k|    for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
  ------------------
  |  Branch (568:30): [True: 7.83k, False: 1.95k]
  ------------------
  569|       |        // Exclude all properties whose first character is '?' from the hash
  570|       |        // See doc for aiMaterialProperty.
  571|  7.83k|        const aiMaterialProperty *prop = mat->mProperties[i];
  572|  7.83k|        if (nullptr != prop && (includeMatName || prop->mKey.data[0] != '?')) {
  ------------------
  |  Branch (572:13): [True: 7.83k, False: 0]
  |  Branch (572:33): [True: 0, False: 7.83k]
  |  Branch (572:51): [True: 5.87k, False: 1.95k]
  ------------------
  573|       |
  574|  5.87k|            hash = SuperFastHash(prop->mKey.data, (unsigned int)prop->mKey.length, hash);
  575|  5.87k|            hash = SuperFastHash(prop->mData, prop->mDataLength, hash);
  576|       |
  577|       |            // Combine the semantic and the index with the hash
  578|  5.87k|            hash = SuperFastHash((const char *)&prop->mSemantic, sizeof(unsigned int), hash);
  579|  5.87k|            hash = SuperFastHash((const char *)&prop->mIndex, sizeof(unsigned int), hash);
  580|  5.87k|        }
  581|  7.83k|    }
  582|  1.95k|    return hash;
  583|  1.95k|}
MaterialSystem.cpp:_ZN12_GLOBAL__N_121GetMaterialFloatArrayIfEE8aiReturnPK10aiMaterialPKcjjPT_Pj:
   97|  1.95k|        unsigned int *pMax) {
   98|  1.95k|    ai_assert(pOut != nullptr);
   99|  1.95k|    ai_assert(pMat != nullptr);
  100|       |
  101|  1.95k|    const aiMaterialProperty *prop{nullptr};
  102|  1.95k|    aiGetMaterialProperty(pMat, pKey, type, index, &prop);
  103|  1.95k|    if (nullptr == prop) {
  ------------------
  |  Branch (103:9): [True: 1.95k, False: 0]
  ------------------
  104|  1.95k|        return AI_FAILURE;
  105|  1.95k|    }
  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|  1.95k|bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
   60|  1.95k|    return (pFlags & aiProcess_PopulateArmatureData) != 0;
   61|  1.95k|}

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

_ZN6Assimp19CalcTangentsProcessC2Ev:
   59|  4.24k|        configMaxAngle(float(AI_DEG_TO_RAD(45.f))), configSourceUV(0) {
   60|       |    // nothing to do here
   61|  4.24k|}
_ZNK6Assimp19CalcTangentsProcess8IsActiveEj:
   65|  1.90k|bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
   66|  1.90k|    return (pFlags & aiProcess_CalcTangentSpace) != 0;
   67|  1.90k|}
_ZN6Assimp19CalcTangentsProcess15SetupPropertiesEPKNS_8ImporterE:
   71|  1.90k|void CalcTangentsProcess::SetupProperties(const Importer *pImp) {
   72|  1.90k|    ai_assert(nullptr != pImp);
   73|       |
   74|       |    // get the current value of the property
   75|  1.90k|    configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 45.f);
   76|  1.90k|    configMaxAngle = std::max(std::min(configMaxAngle, 45.0f), 0.0f);
   77|  1.90k|    configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
   78|       |
   79|       |    configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX, 0);
   80|  1.90k|}
_ZN6Assimp19CalcTangentsProcess7ExecuteEP7aiScene:
   84|  1.90k|void CalcTangentsProcess::Execute(aiScene *pScene) {
   85|  1.90k|    ai_assert(nullptr != pScene);
   86|       |
   87|  1.90k|    ASSIMP_LOG_DEBUG("CalcTangentsProcess begin");
   88|       |
   89|  1.90k|    bool bHas = false;
   90|   157k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (90:30): [True: 156k, False: 1.90k]
  ------------------
   91|   156k|        if (ProcessMesh(pScene->mMeshes[a], a)) bHas = true;
  ------------------
  |  Branch (91:13): [True: 0, False: 156k]
  ------------------
   92|   156k|    }
   93|       |
   94|  1.90k|    if (bHas) {
  ------------------
  |  Branch (94:9): [True: 0, False: 1.90k]
  ------------------
   95|      0|        ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated");
   96|  1.90k|    } else {
   97|       |        ASSIMP_LOG_DEBUG("CalcTangentsProcess finished");
   98|  1.90k|    }
   99|  1.90k|}
_ZN6Assimp19CalcTangentsProcess11ProcessMeshEP6aiMeshj:
  103|   156k|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|   156k|    if (pMesh->mTangents) // this implies that mBitangents is also there
  ------------------
  |  Branch (109:9): [True: 0, False: 156k]
  ------------------
  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|   156k|    if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
  ------------------
  |  Branch (115:9): [True: 120k, False: 35.2k]
  ------------------
  116|   120k|        ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes");
  117|   120k|        return false;
  118|   120k|    }
  119|       |
  120|       |    // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
  121|  35.2k|    if (pMesh->mNormals == nullptr) {
  ------------------
  |  Branch (121:9): [True: 0, False: 35.2k]
  ------------------
  122|      0|        ASSIMP_LOG_ERROR("Failed to compute tangents; need normals");
  123|      0|        return false;
  124|      0|    }
  125|  35.2k|    if (configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV]) {
  ------------------
  |  Branch (125:9): [True: 0, False: 35.2k]
  |  Branch (125:61): [True: 35.2k, False: 0]
  ------------------
  126|  35.2k|        ASSIMP_LOG_ERROR("Failed to compute tangents; need UV data in channel", configSourceUV);
  127|  35.2k|        return false;
  128|  35.2k|    }
  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|  35.2k|}

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

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

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

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

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

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

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

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

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

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

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

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

_ZN6Assimp22FindInvalidDataProcessC2Ev:
   59|  4.24k|        configEpsilon(0.0), mIgnoreTexCoods(false) {
   60|       |    // nothing to do here
   61|  4.24k|}
_ZNK6Assimp22FindInvalidDataProcess8IsActiveEj:
   65|  1.95k|bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {
   66|  1.95k|    return 0 != (pFlags & aiProcess_FindInvalidData);
   67|  1.95k|}
_ZN6Assimp22FindInvalidDataProcess15SetupPropertiesEPKNS_8ImporterE:
   71|  1.95k|void FindInvalidDataProcess::SetupProperties(const Importer *pImp) {
   72|       |    // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
   73|  1.95k|    configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY, 0.f));
   74|       |    mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false);
   75|  1.95k|}
_Z20UpdateMeshReferencesP6aiNodeRKNSt3__16vectorIjNS1_9allocatorIjEEEE:
   79|  71.3k|void UpdateMeshReferences(aiNode *node, const std::vector<unsigned int> &meshMapping) {
   80|  71.3k|    if (node->mNumMeshes) {
  ------------------
  |  Branch (80:9): [True: 71.1k, False: 200]
  ------------------
   81|  71.1k|        unsigned int out = 0;
   82|   181k|        for (unsigned int a = 0; a < node->mNumMeshes; ++a) {
  ------------------
  |  Branch (82:34): [True: 110k, False: 71.1k]
  ------------------
   83|       |
   84|   110k|            unsigned int ref = node->mMeshes[a];
   85|   110k|            if (ref >= meshMapping.size())
  ------------------
  |  Branch (85:17): [True: 0, False: 110k]
  ------------------
   86|      0|                throw DeadlyImportError("Invalid mesh ref");
   87|       |
   88|   110k|            if (UINT_MAX != (ref = meshMapping[ref])) {
  ------------------
  |  Branch (88:17): [True: 102k, False: 7.39k]
  ------------------
   89|   102k|                node->mMeshes[out++] = ref;
   90|   102k|            }
   91|   110k|        }
   92|       |        // just let the members that are unused, that's much cheaper
   93|       |        // than a full array realloc'n'copy party ...
   94|  71.1k|        node->mNumMeshes = out;
   95|  71.1k|        if (0 == out) {
  ------------------
  |  Branch (95:13): [True: 6.43k, False: 64.7k]
  ------------------
   96|  6.43k|            delete[] node->mMeshes;
   97|  6.43k|            node->mMeshes = nullptr;
   98|  6.43k|        }
   99|  71.1k|    }
  100|       |    // recursively update all children
  101|   142k|    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
  ------------------
  |  Branch (101:30): [True: 71.1k, False: 71.3k]
  ------------------
  102|  71.1k|        UpdateMeshReferences(node->mChildren[i], meshMapping);
  103|  71.1k|    }
  104|  71.3k|}
_ZN6Assimp22FindInvalidDataProcess7ExecuteEP7aiScene:
  108|  1.95k|void FindInvalidDataProcess::Execute(aiScene *pScene) {
  109|  1.95k|    ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin");
  110|       |
  111|  1.95k|    bool out = false;
  112|  1.95k|    std::vector<unsigned int> meshMapping(pScene->mNumMeshes);
  113|  1.95k|    unsigned int real = 0;
  114|       |
  115|       |    // Process meshes
  116|   167k|    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
  ------------------
  |  Branch (116:30): [True: 165k, False: 1.95k]
  ------------------
  117|   165k|        int result = ProcessMesh(pScene->mMeshes[a]);
  118|   165k|        if (0 == result) {
  ------------------
  |  Branch (118:13): [True: 146k, False: 18.3k]
  ------------------
  119|   146k|            out = true;
  120|   146k|        }
  121|   165k|        if (2 == result) {
  ------------------
  |  Branch (121:13): [True: 9.10k, False: 156k]
  ------------------
  122|       |            // remove this mesh
  123|  9.10k|            delete pScene->mMeshes[a];
  124|  9.10k|            pScene->mMeshes[a] = nullptr;
  125|       |
  126|  9.10k|            meshMapping[a] = UINT_MAX;
  127|  9.10k|            out = true;
  128|  9.10k|            continue;
  129|  9.10k|        }
  130|       |
  131|   156k|        pScene->mMeshes[real] = pScene->mMeshes[a];
  132|   156k|        meshMapping[a] = real++;
  133|   156k|    }
  134|       |
  135|       |    // Process animations
  136|  1.95k|    for (unsigned int animIdx = 0; animIdx < pScene->mNumAnimations; ++animIdx) {
  ------------------
  |  Branch (136:36): [True: 0, False: 1.95k]
  ------------------
  137|      0|        ProcessAnimation(pScene->mAnimations[animIdx]);
  138|      0|    }
  139|       |
  140|  1.95k|    if (out) {
  ------------------
  |  Branch (140:9): [True: 1.46k, False: 490]
  ------------------
  141|  1.46k|        if (real != pScene->mNumMeshes) {
  ------------------
  |  Branch (141:13): [True: 254, False: 1.21k]
  ------------------
  142|    254|            if (!real) {
  ------------------
  |  Branch (142:17): [True: 54, False: 200]
  ------------------
  143|     54|                throw DeadlyImportError("No meshes remaining");
  144|     54|            }
  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|    200|            try {
  150|    200|                UpdateMeshReferences(pScene->mRootNode, meshMapping);
  151|    200|            } 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|    200|            pScene->mNumMeshes = real;
  157|    200|        }
  158|       |
  159|  1.46k|        ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ...");
  160|  1.41k|    } else {
  161|       |        ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK.");
  162|    490|    }
  163|  1.95k|}
_ZN6Assimp22FindInvalidDataProcess11ProcessMeshEP6aiMesh:
  323|   165k|int FindInvalidDataProcess::ProcessMesh(aiMesh *pMesh) {
  324|   165k|    bool ret = false;
  325|   165k|    std::vector<bool> dirtyMask(pMesh->mNumVertices, pMesh->mNumFaces != 0);
  326|       |
  327|       |    // Ignore elements that are not referenced by vertices.
  328|       |    // (they are, for example, caused by the FindDegenerates step)
  329|  1.03M|    for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
  ------------------
  |  Branch (329:30): [True: 869k, False: 165k]
  ------------------
  330|   869k|        const aiFace &f = pMesh->mFaces[m];
  331|       |
  332|  3.24M|        for (unsigned int i = 0; i < f.mNumIndices; ++i) {
  ------------------
  |  Branch (332:34): [True: 2.38M, False: 869k]
  ------------------
  333|  2.38M|            dirtyMask[f.mIndices[i]] = false;
  334|  2.38M|        }
  335|   869k|    }
  336|       |
  337|       |    // Process vertex positions
  338|   165k|    if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) {
  ------------------
  |  Branch (338:9): [True: 165k, False: 0]
  |  Branch (338:29): [True: 9.10k, False: 156k]
  ------------------
  339|  9.10k|        ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions");
  340|       |
  341|  9.10k|        return 2;
  342|  9.10k|    }
  343|       |
  344|       |    // process texture coordinates
  345|   156k|    if (!mIgnoreTexCoods) {
  ------------------
  |  Branch (345:9): [True: 156k, False: 0]
  ------------------
  346|   156k|        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) {
  ------------------
  |  Branch (346:34): [True: 156k, False: 0]
  |  Branch (346:72): [True: 0, False: 156k]
  ------------------
  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|   156k|    }
  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|   156k|    if (pMesh->mNormals || pMesh->mTangents) {
  ------------------
  |  Branch (366:9): [True: 156k, False: 0]
  |  Branch (366:28): [True: 0, False: 0]
  ------------------
  367|       |
  368|   156k|        if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (368:13): [True: 59.1k, False: 96.9k]
  ------------------
  369|   120k|                aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (369:17): [True: 61.6k, False: 35.2k]
  ------------------
  370|   120k|            if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
  ------------------
  |  Branch (370:17): [True: 0, False: 120k]
  ------------------
  371|   120k|                    aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (371:21): [True: 0, False: 120k]
  ------------------
  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|   120k|            else {
  387|   120k|                return ret;
  388|   120k|            }
  389|   120k|        }
  390|       |
  391|       |        // Process mesh normals
  392|  35.2k|        if (pMesh->mNormals && ProcessArray(pMesh->mNormals, pMesh->mNumVertices,
  ------------------
  |  Branch (392:13): [True: 35.2k, False: 0]
  |  Branch (392:32): [True: 9.27k, False: 25.9k]
  ------------------
  393|  35.2k|                                       "normals", dirtyMask, true, false))
  394|  9.27k|            ret = true;
  395|       |
  396|       |        // Process mesh tangents
  397|  35.2k|        if (pMesh->mTangents && ProcessArray(pMesh->mTangents, pMesh->mNumVertices, "tangents", dirtyMask)) {
  ------------------
  |  Branch (397:13): [True: 0, False: 35.2k]
  |  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|  35.2k|        if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents, pMesh->mNumVertices, "bitangents", dirtyMask)) {
  ------------------
  |  Branch (404:13): [True: 0, False: 35.2k]
  |  Branch (404:35): [True: 0, False: 0]
  ------------------
  405|      0|            delete[] pMesh->mTangents;
  406|      0|            pMesh->mTangents = nullptr;
  407|      0|            ret = true;
  408|      0|        }
  409|  35.2k|    }
  410|  35.2k|    return ret ? 1 : 0;
  ------------------
  |  Branch (410:12): [True: 9.27k, False: 25.9k]
  ------------------
  411|   156k|}
_Z12ProcessArrayI10aiVector3tIfEEbRPT_jPKcRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  203|   200k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) {
  204|   200k|    const char *err = ValidateArrayContents(in, num, dirtyMask, mayBeIdentical, mayBeZero);
  205|   200k|    if (err) {
  ------------------
  |  Branch (205:9): [True: 18.3k, False: 182k]
  ------------------
  206|  18.3k|        ASSIMP_LOG_ERROR("FindInvalidDataProcess fails on mesh ", name, ": ", err);
  207|  18.3k|        delete[] in;
  208|  18.3k|        in = nullptr;
  209|  18.3k|        return true;
  210|  18.3k|    }
  211|   182k|    return false;
  212|   200k|}
_Z21ValidateArrayContentsI10aiVector3tIfEEPKcPKT_jRKNSt3__16vectorIbNS7_9allocatorIbEEEEbb:
  175|   200k|        const std::vector<bool> &dirtyMask, bool mayBeIdentical, bool mayBeZero) {
  176|   200k|    bool b = false;
  177|   200k|    unsigned int cnt = 0;
  178|  3.22M|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (178:30): [True: 3.03M, False: 186k]
  ------------------
  179|       |
  180|  3.03M|        if (dirtyMask.size() && dirtyMask[i]) {
  ------------------
  |  Branch (180:13): [True: 3.03M, False: 0]
  |  Branch (180:13): [True: 96.4k, False: 2.93M]
  |  Branch (180:33): [True: 96.4k, False: 2.93M]
  ------------------
  181|  96.4k|            continue;
  182|  96.4k|        }
  183|  2.93M|        ++cnt;
  184|       |
  185|  2.93M|        const aiVector3D &v = arr[i];
  186|  2.93M|        if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
  ------------------
  |  Branch (186:13): [True: 345, False: 2.93M]
  |  Branch (186:38): [True: 4.59k, False: 2.93M]
  |  Branch (186:63): [True: 477, False: 2.93M]
  ------------------
  187|  5.42k|            return "INF/NAN was found in a vector component";
  188|  5.42k|        }
  189|  2.93M|        if (!mayBeZero && !v.x && !v.y && !v.z) {
  ------------------
  |  Branch (189:13): [True: 575k, False: 2.35M]
  |  Branch (189:27): [True: 157k, False: 417k]
  |  Branch (189:35): [True: 70.5k, False: 87.1k]
  |  Branch (189:43): [True: 8.51k, False: 62.0k]
  ------------------
  190|  8.51k|            return "Found zero-length vector";
  191|  8.51k|        }
  192|  2.92M|        if (i && v != arr[i - 1]) b = true;
  ------------------
  |  Branch (192:13): [True: 2.72M, False: 195k]
  |  Branch (192:18): [True: 2.27M, False: 453k]
  ------------------
  193|  2.92M|    }
  194|   186k|    if (cnt > 1 && !b && !mayBeIdentical) {
  ------------------
  |  Branch (194:9): [True: 127k, False: 59.0k]
  |  Branch (194:20): [True: 21.4k, False: 106k]
  |  Branch (194:26): [True: 4.44k, False: 16.9k]
  ------------------
  195|  4.44k|        return "All vectors are identical";
  196|  4.44k|    }
  197|   182k|    return nullptr;
  198|   186k|}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

_ZNK6Assimp18TriangulateProcess8IsActiveEj:
  179|  1.95k|bool TriangulateProcess::IsActive( unsigned int pFlags) const {
  180|  1.95k|    return (pFlags & aiProcess_Triangulate) != 0;
  181|  1.95k|}
_ZN6Assimp18TriangulateProcess7ExecuteEP7aiScene:
  185|  1.95k|void TriangulateProcess::Execute( aiScene* pScene) {
  186|  1.95k|    ASSIMP_LOG_DEBUG("TriangulateProcess begin");
  187|       |
  188|  1.95k|    bool bHas = false;
  189|   118k|    for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
  ------------------
  |  Branch (189:30): [True: 116k, False: 1.95k]
  ------------------
  190|   116k|    {
  191|   116k|        if (pScene->mMeshes[ a ]) {
  ------------------
  |  Branch (191:13): [True: 116k, False: 0]
  ------------------
  192|   116k|            if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
  ------------------
  |  Branch (192:18): [True: 0, False: 116k]
  ------------------
  193|      0|                bHas = true;
  194|      0|            }
  195|   116k|        }
  196|   116k|    }
  197|  1.95k|    if ( bHas ) {
  ------------------
  |  Branch (197:10): [True: 0, False: 1.95k]
  ------------------
  198|      0|        ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." );
  199|  1.95k|    } else {
  200|       |        ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." );
  201|  1.95k|    }
  202|  1.95k|}
_ZN6Assimp18TriangulateProcess15TriangulateMeshEP6aiMesh:
  206|   116k|bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) {
  207|       |    // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
  208|   116k|    if (!pMesh->mPrimitiveTypes)    {
  ------------------
  |  Branch (208:9): [True: 0, False: 116k]
  ------------------
  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|   116k|    else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
  ------------------
  |  Branch (221:14): [True: 116k, False: 0]
  ------------------
  222|   116k|        return false;
  223|   116k|    }
  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.24k|    TriangulateProcess() = default;

_ZN6Assimp17ValidateDSProcessC2Ev:
   61|  2.78k|ValidateDSProcess::ValidateDSProcess() : mScene(nullptr) {}
_ZN6Assimp17ValidateDSProcess11ReportErrorEPKcz:
   69|    828|AI_WONT_RETURN void ValidateDSProcess::ReportError(const char *msg, ...) {
   70|    828|    ai_assert(nullptr != msg);
   71|       |
   72|    828|    va_list args;
   73|    828|    va_start(args, msg);
   74|       |
   75|    828|    char szBuffer[3000];
   76|    828|    const int iLen = vsnprintf(szBuffer, sizeof(szBuffer), msg, args);
   77|    828|    ai_assert(iLen > 0);
   78|       |
   79|    828|    va_end(args);
   80|       |
   81|    828|    throw DeadlyImportError("Validation failed: ", std::string(szBuffer, iLen));
   82|    828|}
_ZN6Assimp17ValidateDSProcess7ExecuteEP7aiScene:
  183|  2.78k|void ValidateDSProcess::Execute(aiScene *pScene) {
  184|  2.78k|    mScene = pScene;
  185|  2.78k|    ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin");
  186|       |
  187|       |    // validate the node graph of the scene
  188|  2.78k|    Validate(pScene->mRootNode);
  189|       |
  190|       |    // validate all meshes
  191|  2.78k|    if (pScene->mNumMeshes) {
  ------------------
  |  Branch (191:9): [True: 2.78k, False: 0]
  ------------------
  192|  2.78k|        DoValidation(pScene->mMeshes, pScene->mNumMeshes, "mMeshes", "mNumMeshes");
  193|  2.78k|    } 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|  2.78k|    if (pScene->mNumAnimations) {
  ------------------
  |  Branch (200:9): [True: 0, False: 2.78k]
  ------------------
  201|      0|        DoValidation(pScene->mAnimations, pScene->mNumAnimations,
  202|      0|                "mAnimations", "mNumAnimations");
  203|  2.78k|    } else if (pScene->mAnimations) {
  ------------------
  |  Branch (203:16): [True: 0, False: 2.78k]
  ------------------
  204|      0|        ReportError("aiScene::mAnimations is non-null although there are no animations");
  205|      0|    }
  206|       |
  207|       |    // validate all cameras
  208|  2.78k|    if (pScene->mNumCameras) {
  ------------------
  |  Branch (208:9): [True: 0, False: 2.78k]
  ------------------
  209|      0|        DoValidationWithNameCheck(pScene->mCameras, pScene->mNumCameras,
  210|      0|                "mCameras", "mNumCameras");
  211|  2.78k|    } else if (pScene->mCameras) {
  ------------------
  |  Branch (211:16): [True: 0, False: 2.78k]
  ------------------
  212|      0|        ReportError("aiScene::mCameras is non-null although there are no cameras");
  213|      0|    }
  214|       |
  215|       |    // validate all lights
  216|  2.78k|    if (pScene->mNumLights) {
  ------------------
  |  Branch (216:9): [True: 0, False: 2.78k]
  ------------------
  217|      0|        DoValidationWithNameCheck(pScene->mLights, pScene->mNumLights,
  218|      0|                "mLights", "mNumLights");
  219|  2.78k|    } else if (pScene->mLights) {
  ------------------
  |  Branch (219:16): [True: 0, False: 2.78k]
  ------------------
  220|      0|        ReportError("aiScene::mLights is non-null although there are no lights");
  221|      0|    }
  222|       |
  223|       |    // validate all textures
  224|  2.78k|    if (pScene->mNumTextures) {
  ------------------
  |  Branch (224:9): [True: 0, False: 2.78k]
  ------------------
  225|      0|        DoValidation(pScene->mTextures, pScene->mNumTextures,
  226|      0|                "mTextures", "mNumTextures");
  227|  2.78k|    } else if (pScene->mTextures) {
  ------------------
  |  Branch (227:16): [True: 0, False: 2.78k]
  ------------------
  228|      0|        ReportError("aiScene::mTextures is non-null although there are no textures");
  229|      0|    }
  230|       |
  231|       |    // validate all materials
  232|  2.78k|    if (pScene->mNumMaterials) {
  ------------------
  |  Branch (232:9): [True: 1.95k, False: 828]
  ------------------
  233|  1.95k|        DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials");
  234|  1.95k|    }
  235|    828|    else if (pScene->mMaterials) {
  ------------------
  |  Branch (235:14): [True: 0, False: 828]
  ------------------
  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|  2.78k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiMesh:
  273|   117k|void ValidateDSProcess::Validate(const aiMesh *pMesh) {
  274|       |    // validate the material index of the mesh
  275|   117k|    if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) {
  ------------------
  |  Branch (275:9): [True: 117k, False: 0]
  |  Branch (275:34): [True: 0, False: 117k]
  ------------------
  276|      0|        ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)",
  277|      0|                pMesh->mMaterialIndex, mScene->mNumMaterials - 1);
  278|      0|    }
  279|       |
  280|   117k|    Validate(&pMesh->mName);
  281|       |
  282|   987k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (282:30): [True: 869k, False: 117k]
  ------------------
  283|   869k|        aiFace &face = pMesh->mFaces[i];
  284|       |
  285|   869k|        if (pMesh->mPrimitiveTypes) {
  ------------------
  |  Branch (285:13): [True: 0, False: 869k]
  ------------------
  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|   869k|        if (!face.mIndices)
  ------------------
  |  Branch (320:13): [True: 0, False: 869k]
  ------------------
  321|      0|            ReportError("aiMesh::mFaces[%i].mIndices is nullptr", i);
  322|   869k|    }
  323|       |
  324|       |    // positions must always be there ...
  325|   117k|    if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) {
  ------------------
  |  Branch (325:9): [True: 828, False: 116k]
  |  Branch (325:34): [True: 0, False: 116k]
  |  Branch (325:55): [True: 0, False: 0]
  ------------------
  326|    828|        ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str());
  327|    828|    }
  328|       |
  329|   117k|    if (pMesh->mNumVertices > AI_MAX_VERTICES) {
  ------------------
  |  Branch (329:9): [True: 0, False: 117k]
  ------------------
  330|      0|        ReportError("Mesh has too many vertices: %u, but the limit is %u", pMesh->mNumVertices, AI_MAX_VERTICES);
  331|      0|    }
  332|   117k|    if (pMesh->mNumFaces > AI_MAX_FACES) {
  ------------------
  |  Branch (332:9): [True: 0, False: 117k]
  ------------------
  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|   117k|    if ((pMesh->mTangents != nullptr) != (pMesh->mBitangents != nullptr)) {
  ------------------
  |  Branch (337:9): [True: 0, False: 117k]
  ------------------
  338|      0|        ReportError("If there are tangents, bitangent vectors must be present as well");
  339|      0|    }
  340|       |
  341|       |    // faces, too
  342|   117k|    if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) {
  ------------------
  |  Branch (342:9): [True: 828, False: 116k]
  |  Branch (342:31): [True: 0, False: 116k]
  |  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|   117k|    std::vector<bool> abRefList;
  349|   117k|    abRefList.resize(pMesh->mNumVertices, false);
  350|   987k|    for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) {
  ------------------
  |  Branch (350:30): [True: 869k, False: 117k]
  ------------------
  351|   869k|        aiFace &face = pMesh->mFaces[i];
  352|   869k|        if (face.mNumIndices > AI_MAX_FACE_INDICES) {
  ------------------
  |  Branch (352:13): [True: 0, False: 869k]
  ------------------
  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|  3.47M|        for (unsigned int a = 0; a < face.mNumIndices; ++a) {
  ------------------
  |  Branch (356:34): [True: 2.60M, False: 869k]
  ------------------
  357|  2.60M|            if (face.mIndices[a] >= pMesh->mNumVertices) {
  ------------------
  |  Branch (357:17): [True: 0, False: 2.60M]
  ------------------
  358|      0|                ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a);
  359|      0|            }
  360|  2.60M|            abRefList[face.mIndices[a]] = true;
  361|  2.60M|        }
  362|   869k|    }
  363|       |
  364|       |    // check whether there are vertices that aren't referenced by a face
  365|   117k|    bool b = false;
  366|  2.72M|    for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
  ------------------
  |  Branch (366:30): [True: 2.60M, False: 117k]
  ------------------
  367|  2.60M|        if (!abRefList[i]) b = true;
  ------------------
  |  Branch (367:13): [True: 0, False: 2.60M]
  ------------------
  368|  2.60M|    }
  369|   117k|    abRefList.clear();
  370|   117k|    if (b) {
  ------------------
  |  Branch (370:9): [True: 0, False: 117k]
  ------------------
  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|   117k|    {
  376|   117k|        unsigned int i = 0;
  377|   118k|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
  ------------------
  |  Branch (377:16): [True: 117k, False: 828]
  ------------------
  378|   117k|            if (!pMesh->HasVertexColors(i)) break;
  ------------------
  |  Branch (378:17): [True: 116k, False: 446]
  ------------------
  379|   117k|        }
  380|  1.05M|        for (; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i)
  ------------------
  |  Branch (380:16): [True: 934k, False: 117k]
  ------------------
  381|   934k|            if (pMesh->HasVertexColors(i)) {
  ------------------
  |  Branch (381:17): [True: 0, False: 934k]
  ------------------
  382|      0|                ReportError("Vertex color channel %i is exists "
  383|      0|                            "although the previous channel was nullptr.",
  384|      0|                        i);
  385|      0|            }
  386|   117k|    }
  387|       |
  388|       |    // now validate all bones
  389|   117k|    if (pMesh->mNumBones) {
  ------------------
  |  Branch (389:9): [True: 0, False: 117k]
  ------------------
  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|   117k|    } else if (pMesh->mBones) {
  ------------------
  |  Branch (432:16): [True: 0, False: 117k]
  ------------------
  433|      0|        ReportError("aiMesh::mBones is non-null although there are no bones");
  434|      0|    }
  435|   117k|}
_ZN6Assimp17ValidateDSProcess24SearchForInvalidTexturesEPK10aiMaterial13aiTextureType:
  491|  33.3k|        aiTextureType type) {
  492|  33.3k|    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|  33.3k|    int iNumIndices = 0;
  501|  33.3k|    int iIndex = -1;
  502|   166k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (502:30): [True: 133k, False: 33.3k]
  ------------------
  503|   133k|        aiMaterialProperty *prop = pMaterial->mProperties[i];
  504|   133k|        ai_assert(nullptr != prop);
  505|   133k|        if (!::strcmp(prop->mKey.data, "$tex.file") && prop->mSemantic == static_cast<unsigned int>(type)) {
  ------------------
  |  Branch (505:13): [True: 0, False: 133k]
  |  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|   133k|    }
  514|  33.3k|    if (iIndex + 1 != iNumIndices) {
  ------------------
  |  Branch (514:9): [True: 0, False: 33.3k]
  ------------------
  515|      0|        ReportError("%s #%i is set, but there are only %i %s textures",
  516|      0|                szType, iIndex, iNumIndices, szType);
  517|      0|    }
  518|  33.3k|    if (!iNumIndices) {
  ------------------
  |  Branch (518:9): [True: 33.3k, False: 0]
  ------------------
  519|  33.3k|        return;
  520|  33.3k|    }
  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|  1.95k|void ValidateDSProcess::Validate(const aiMaterial *pMaterial) {
  594|       |    // check whether there are material keys that are obviously not legal
  595|  9.79k|    for (unsigned int i = 0; i < pMaterial->mNumProperties; ++i) {
  ------------------
  |  Branch (595:30): [True: 7.83k, False: 1.95k]
  ------------------
  596|  7.83k|        const aiMaterialProperty *prop = pMaterial->mProperties[i];
  597|  7.83k|        if (!prop) {
  ------------------
  |  Branch (597:13): [True: 0, False: 7.83k]
  ------------------
  598|      0|            ReportError("aiMaterial::mProperties[%i] is nullptr (aiMaterial::mNumProperties is %i)",
  599|      0|                    i, pMaterial->mNumProperties);
  600|      0|        }
  601|  7.83k|        if (!prop->mDataLength || !prop->mData) {
  ------------------
  |  Branch (601:13): [True: 0, False: 7.83k]
  |  Branch (601:35): [True: 0, False: 7.83k]
  ------------------
  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|  7.83k|        if (aiPTI_String == prop->mType) {
  ------------------
  |  Branch (607:13): [True: 1.95k, False: 5.87k]
  ------------------
  608|       |            // FIX: strings are now stored in a less expensive way, but we can't use the
  609|       |            // validation routine for 'normal' aiStrings
  610|  1.95k|            if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast<uint32_t *>(prop->mData)) + 1) {
  ------------------
  |  Branch (610:17): [True: 0, False: 1.95k]
  |  Branch (610:42): [True: 0, False: 1.95k]
  ------------------
  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|  1.95k|            if (prop->mData[prop->mDataLength - 1]) {
  ------------------
  |  Branch (615:17): [True: 0, False: 1.95k]
  ------------------
  616|      0|                ReportError("Missing null-terminator in string material property");
  617|      0|            }
  618|       |            //  Validate((const aiString*)prop->mData);
  619|  5.87k|        } else if (aiPTI_Float == prop->mType) {
  ------------------
  |  Branch (619:20): [True: 5.87k, False: 0]
  ------------------
  620|  5.87k|            if (prop->mDataLength < sizeof(float)) {
  ------------------
  |  Branch (620:17): [True: 0, False: 5.87k]
  ------------------
  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|  5.87k|        } 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|  7.83k|    }
  634|       |
  635|       |    // make some more specific tests
  636|  1.95k|    ai_real fTemp;
  637|  1.95k|    int iShading;
  638|  1.95k|    if (AI_SUCCESS == aiGetMaterialInteger(pMaterial, AI_MATKEY_SHADING_MODEL, &iShading)) {
  ------------------
  |  Branch (638:9): [True: 0, False: 1.95k]
  ------------------
  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|  1.95k|    if (AI_SUCCESS == aiGetMaterialFloat(pMaterial, AI_MATKEY_OPACITY, &fTemp) && (!fTemp || fTemp > 1.01)) {
  ------------------
  |  Branch (658:9): [True: 0, False: 1.95k]
  |  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|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE);
  666|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_SPECULAR);
  667|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT);
  668|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSIVE);
  669|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_OPACITY);
  670|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_SHININESS);
  671|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_HEIGHT);
  672|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMALS);
  673|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_DISPLACEMENT);
  674|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_LIGHTMAP);
  675|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_REFLECTION);
  676|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_BASE_COLOR);
  677|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_NORMAL_CAMERA);
  678|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_EMISSION_COLOR);
  679|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_METALNESS);
  680|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_DIFFUSE_ROUGHNESS);
  681|  1.95k|    SearchForInvalidTextures(pMaterial, aiTextureType_AMBIENT_OCCLUSION);
  682|  1.95k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK6aiNode:
  850|   534k|void ValidateDSProcess::Validate(const aiNode *pNode) {
  851|   534k|    if (!pNode) {
  ------------------
  |  Branch (851:9): [True: 0, False: 534k]
  ------------------
  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|   534k|    this->Validate(&pNode->mName);
  856|   534k|    const char *nodeName = (&pNode->mName)->C_Str();
  857|   534k|    if (pNode != mScene->mRootNode && !pNode->mParent) {
  ------------------
  |  Branch (857:9): [True: 531k, False: 2.78k]
  |  Branch (857:39): [True: 0, False: 531k]
  ------------------
  858|      0|        ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is nullptr) ", nodeName);
  859|      0|    }
  860|       |
  861|       |    // validate all meshes
  862|   534k|    if (pNode->mNumMeshes) {
  ------------------
  |  Branch (862:9): [True: 531k, False: 2.78k]
  ------------------
  863|   531k|        if (!pNode->mMeshes) {
  ------------------
  |  Branch (863:13): [True: 0, False: 531k]
  ------------------
  864|      0|            ReportError("aiNode::mMeshes is nullptr for node %s (aiNode::mNumMeshes is %i)",
  865|      0|                    nodeName, pNode->mNumMeshes);
  866|      0|        }
  867|   531k|        std::vector<bool> abHadMesh;
  868|   531k|        abHadMesh.resize(mScene->mNumMeshes, false);
  869|  1.06M|        for (unsigned int i = 0; i < pNode->mNumMeshes; ++i) {
  ------------------
  |  Branch (869:34): [True: 531k, False: 531k]
  ------------------
  870|   531k|            if (pNode->mMeshes[i] >= mScene->mNumMeshes) {
  ------------------
  |  Branch (870:17): [True: 0, False: 531k]
  ------------------
  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|   531k|            if (abHadMesh[pNode->mMeshes[i]]) {
  ------------------
  |  Branch (874:17): [True: 0, False: 531k]
  ------------------
  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|   531k|            abHadMesh[pNode->mMeshes[i]] = true;
  879|   531k|        }
  880|   531k|    }
  881|   534k|    if (pNode->mNumChildren) {
  ------------------
  |  Branch (881:9): [True: 2.78k, False: 531k]
  ------------------
  882|  2.78k|        if (!pNode->mChildren) {
  ------------------
  |  Branch (882:13): [True: 0, False: 2.78k]
  ------------------
  883|      0|            ReportError("aiNode::mChildren is nullptr for node %s (aiNode::mNumChildren is %i)",
  884|      0|                    nodeName, pNode->mNumChildren);
  885|      0|        }
  886|   534k|        for (unsigned int i = 0; i < pNode->mNumChildren; ++i) {
  ------------------
  |  Branch (886:34): [True: 531k, False: 2.78k]
  ------------------
  887|   531k|            const aiNode *pChild = pNode->mChildren[i];
  888|   531k|            Validate(pChild);
  889|   531k|            if (pChild->mParent != pNode) {
  ------------------
  |  Branch (889:17): [True: 0, False: 531k]
  ------------------
  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|   531k|        }
  894|   531k|    } else if (pNode->mChildren) {
  ------------------
  |  Branch (894:16): [True: 0, False: 531k]
  ------------------
  895|      0|        ReportError("aiNode::mChildren is not nullptr for empty node %s (aiNode::mNumChildren is %i)",
  896|      0|                nodeName, pNode->mNumChildren);
  897|      0|    }
  898|   534k|}
_ZN6Assimp17ValidateDSProcess8ValidateEPK8aiString:
  901|   651k|void ValidateDSProcess::Validate(const aiString *pString) {
  902|   651k|    if (pString->length > AI_MAXLEN) {
  ------------------
  |  Branch (902:9): [True: 0, False: 651k]
  ------------------
  903|      0|        ReportError("aiString::length is too large (%u, maximum is %lu)",
  904|      0|                pString->length, AI_MAXLEN);
  905|      0|    }
  906|   651k|    const char *sz = pString->data;
  907|  1.75M|    while (true) {
  ------------------
  |  Branch (907:12): [True: 1.75M, Folded]
  ------------------
  908|  1.75M|        if ('\0' == *sz) {
  ------------------
  |  Branch (908:13): [True: 651k, False: 1.10M]
  ------------------
  909|   651k|            if (pString->length != (unsigned int)(sz - pString->data)) {
  ------------------
  |  Branch (909:17): [True: 0, False: 651k]
  ------------------
  910|      0|                ReportError("aiString::data is invalid: the terminal zero is at a wrong offset");
  911|      0|            }
  912|   651k|            break;
  913|  1.10M|        } else if (sz >= &pString->data[AI_MAXLEN]) {
  ------------------
  |  Branch (913:20): [True: 0, False: 1.10M]
  ------------------
  914|      0|            ReportError("aiString::data is invalid. There is no terminal character");
  915|      0|        }
  916|  1.10M|        ++sz;
  917|  1.10M|    }
  918|   651k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI6aiMeshEEvPPT_jPKcS7_:
  109|  2.78k|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|  2.78k|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 2.78k]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|  2.78k|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 2.78k]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|   120k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 117k, False: 2.78k]
  ------------------
  121|   117k|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 117k]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|   117k|        Validate(parray[i]);
  126|   117k|    }
  127|  2.78k|}
_ZN6Assimp17ValidateDSProcess12DoValidationI10aiMaterialEEvPPT_jPKcS7_:
  109|  1.95k|inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
  110|       |    // validate all entries
  111|  1.95k|    if (size == 0) {
  ------------------
  |  Branch (111:9): [True: 0, False: 1.95k]
  ------------------
  112|      0|        return;
  113|      0|    }
  114|       |
  115|  1.95k|    if (!parray) {
  ------------------
  |  Branch (115:9): [True: 0, False: 1.95k]
  ------------------
  116|      0|        ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
  117|      0|                firstName, secondName, size);
  118|      0|    }
  119|       |
  120|  3.91k|    for (unsigned int i = 0; i < size; ++i) {
  ------------------
  |  Branch (120:30): [True: 1.95k, False: 1.95k]
  ------------------
  121|  1.95k|        if (!parray[i]) {
  ------------------
  |  Branch (121:13): [True: 0, False: 1.95k]
  ------------------
  122|      0|            ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
  123|      0|                    firstName, i, secondName, size);
  124|      0|        }
  125|  1.95k|        Validate(parray[i]);
  126|  1.95k|    }
  127|  1.95k|}

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

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

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

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

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

