Re-using a static ofxAssimpModelLoader

Hey all,

I am building an iOS app where I need to go in and out of an openFrameworks view. It is an AR app where 3D models are displayed on top of markers, so I am using the ofxQCAR and ofxAssimpModelLoader addons. The openFrameworks view controller is part of the navigation controller hierarchy, so I can push and pop it, instantiating a new testApp each time.

The models are pretty big and take quite some time to load, so I would like to keep them in memory once they are loaded. This is where my problem comes in. The app will load the models and run fine the first time it is instantiated, but will crash any subsequent time when trying to display the models.

It looks like the EXC_BAD_ACCESS comes from ofVbo.drawElements(int, int). You can see that in the attached screenshot.

I have tried just reloading the models each time a new testApp runs, that works OK.
I have tried just keeping the ofBuffer in memory and rebuilding the models each time a new testApp runs, that fails with the same error.

Anyone have any ideas or suggestions?

TIA!

![](http://forum.openframeworks.cc/uploads/default/2984/Screen Shot 2013-08-01 at 5.03.21 PM.png)

Hello,
I’ve faced the exact same problem! And for now the best I’ve found is saving the aiScene within a singleton, and reload the GLResources each time the app is pushed.
It takes half the time to load, but I wish it could be better

Cool, thanks! I was able to put something together quickly.

WMAssimpLoader.h

  
  
#pragma once  
  
#include "ofMain.h"  
#include "ofxAssimpModelLoader.h"  
  
//--------------------------------------------------------------  
//--------------------------------------------------------------  
class WMAssimpLoader : public ofxAssimpModelLoader  
{  
public:  
    WMAssimpLoader();  
      
    void loadModel(string modelName, bool optimize = false);  
    void deinit();  
      
    void init();  
      
    bool bLoaded;  
    bool bInited;  
};  
  

WMAssimpLoader.cpp

  
  
#include "WMAssimpLoader.h"  
  
#include "ofxAssimpUtils.h"  
  
#include "assimp.h"  
#include "aiScene.h"  
#include "aiConfig.h"  
#include "aiPostProcess.h"  
  
//--------------------------------------------------------------  
WMAssimpLoader::WMAssimpLoader()  
{  
    bLoaded = false;  
    bInited = false;  
}  
  
//--------------------------------------------------------------  
void WMAssimpLoader::loadModel(string modelName, bool optimize)  
{  
    bLoaded = false;  
    bInited = false;  
      
    file.open(modelName);  
    if (!file.exists()) {  
        ofLog(OF_LOG_VERBOSE, "%s is not found.", modelName.c_str());  
        return;  
    }  
      
    ofLog(OF_LOG_VERBOSE, "loading model %s", file.getFileName().c_str());  
    ofLog(OF_LOG_VERBOSE, "loading from folder %s", file.getEnclosingDirectory().c_str());  
      
    ofBuffer buffer = file.readToBuffer();  
      
    normalizeFactor = 320.0 / 2.0;  
      
    if (scene != NULL) {  
        clear();  
    }  
      
    // only ever give us triangles.  
	aiSetImportPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT );  
	aiSetImportPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, true);  
      
	// aiProcess_FlipUVs is for VAR code. Not needed otherwise. Not sure why.  
	unsigned int flags = aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_Triangulate | aiProcess_FlipUVs;  
	if (optimize) flags |=  aiProcess_ImproveCacheLocality | aiProcess_OptimizeGraph |  
        aiProcess_OptimizeMeshes | aiProcess_JoinIdenticalVertices |  
        aiProcess_RemoveRedundantMaterials;  
      
	scene = aiImportFileFromMemory(buffer.getBinaryBuffer(), buffer.size(), flags, file.getExtension().c_str());  
      
    if (scene) {  
        bLoaded = true;  
    }  
    else {  
        ofLog(OF_LOG_ERROR,string("ofxAssimpModelLoader: ") + aiGetErrorString());  
    }  
      
    init();  
}  
  
//--------------------------------------------------------------  
void WMAssimpLoader::init()  
{  
    if (bLoaded == false || bInited == true) return;  
      
    ofLog(OF_LOG_NOTICE, "finishing set up in main thread");  
    if (scene) {  
		calculateDimensions();  
		loadGLResources();  
        update();  
          
		if (getAnimationCount())  
			ofLog(OF_LOG_VERBOSE, "scene has animations");  
		else {  
			ofLog(OF_LOG_VERBOSE, "no animations");  
		}  
	}  
    else {  
		ofLog(OF_LOG_ERROR,string("ofxAssimpModelLoader: ") + aiGetErrorString());  
	}  
      
    bInited = true;  
}  
  
//--------------------------------------------------------------  
void WMAssimpLoader::deinit()  
{  
    ofLog(OF_LOG_VERBOSE, "deleting gl resources");  
      
    // clear out GL.  
    modelMeshes.clear();  
    animations.clear();  
    pos.set(0,0,0);  
    scale.set(1,1,1);  
    rotAngle.clear();  
    rotAxis.clear();  
    lights.clear();  
      
    scale = ofPoint(1, 1, 1);  
    //	if(scene){  
    //		aiReleaseImport(scene);  
    //		scene = NULL;  
    //	}  
    normalizeScale = true;  
    bUsingMaterials = true;  
    bUsingNormals = true;  
    bUsingTextures = true;  
    bUsingColors = true;  
      
    currentAnimation = -1;  
      
    bInited = false;  
      
    updateModelMatrix();  
}  
  

Then, in my testApp.cpp

  
  
#include "WMAssimpLoader.h"  
  
static WMAssimpLoader * _loader = NULL;  
  
//--------------------------------------------------------------  
void WMTrackerApp::setup()  
{  
    if (_loader == NULL) {  
        _loader = new WMAssimpLoader();  
        _loader->loadModel("3D/astroboy/astroBoy_walk.dae");  
    }  
    else {  
        _loader->init();  
    }  
    _loader->setPosition(ofGetWidth() * 0.5, (float)ofGetHeight() * 0.75 , 0);  
}  
  
//--------------------------------------------------------------  
void WMTrackerApp::update()  
{            
    _loader->update();  
}  
  
//--------------------------------------------------------------  
void WMTrackerApp::draw()  
{  
    _loader->drawFaces();  
}  
  
//--------------------------------------------------------------  
void WMTrackerApp::exit()  
{  
    _loader->deinit();  
}  
  

But as you say, I wish it could be better :slight_smile: I will try to load the aiScene (the contents of loadModel(…)) in a different thread so that the app starts faster and post my results here.

Now it’s your init() metho which is consuming time.
Maybe you could try to tweak loadGLResources() so it doesn’t re-instantiate meshHelpers each time, and let only the vbo part to execute (all meshHelper.vbo.set… calls)
I don’t know if it could solve the segmentation fault problem you first mentioned up there