//-------------------------------------------
ofMesh ofxAssimpModelLoader::getMesh(int num){
	ofMesh ofm;
	if((int)scene->mNumMeshes<=num){
		ofLog(OF_LOG_ERROR,"couldn't find mesh " + ofToString(num) + " there's only " + ofToString(scene->mNumMeshes));
		return ofm;
	}

	aiMeshToOfMesh(scene->mMeshes[num],ofm);
	return ofm;
}
//-------------------------------------------
ofMesh ofxAssimpModelLoader::getMesh(int num){
	ofMesh ofm;
	if((int)scene->mNumMeshes<=num){
		ofLogError("ofxAssimpModelLoader") << "getMesh(): mesh id " << num
		<< " out of range for total num meshes: " << scene->mNumMeshes;
		return ofm;
	}

	aiMeshToOfMesh(scene->mMeshes[num],ofm);
	return ofm;
}
//-------------------------------------------
ofMesh ofxAssimpModelLoader::getMesh(string name){
	ofMesh ofm;
	// default to triangle mode
	ofm.setMode(OF_PRIMITIVE_TRIANGLES);
	aiMesh * aim = NULL;
	for(int i=0; i<(int)scene->mNumMeshes; i++){
		if(string(scene->mMeshes[i]->mName.data)==name){
			aim = scene->mMeshes[i];
			break;
		}
	}

	if(!aim){
		ofLogError("ofxAssimpModelLoader") <<"getMesh(): couldn't find mesh: \"" << name << "\"";
		return ofm;
	}

	aiMeshToOfMesh(aim,ofm);
	return ofm;
}
//-------------------------------------------
void ofxAssimpModelLoader::loadGLResources(){

	ofLogVerbose("ofxAssimpModelLoader") << "loadGLResources(): starting";

    // create new mesh helpers for each mesh, will populate their data later.
    modelMeshes.resize(scene->mNumMeshes,ofxAssimpMeshHelper());

    // create OpenGL buffers and populate them based on each meshes pertinant info.
    for (unsigned int i = 0; i < scene->mNumMeshes; ++i){
        ofLogVerbose("ofxAssimpModelLoader") << "loadGLResources(): loading mesh " << i;
        // current mesh we are introspecting
        aiMesh* mesh = scene->mMeshes[i];

        // the current meshHelper we will be populating data into.
        ofxAssimpMeshHelper & meshHelper = modelMeshes[i];
        //ofxAssimpMeshHelper meshHelper;
		
        //meshHelper.texture = NULL;

        // Handle material info
        aiMaterial* mtl = scene->mMaterials[mesh->mMaterialIndex];
        aiColor4D dcolor, scolor, acolor, ecolor;

        if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &dcolor)){
            meshHelper.material.setDiffuseColor(aiColorToOfColor(dcolor));
        }

        if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &scolor)){
        	meshHelper.material.setSpecularColor(aiColorToOfColor(scolor));
        }

        if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &acolor)){
        	meshHelper.material.setAmbientColor(aiColorToOfColor(acolor));
        }

        if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &ecolor)){
        	meshHelper.material.setEmissiveColor(aiColorToOfColor(ecolor));
        }

        float shininess;
        if(AI_SUCCESS == aiGetMaterialFloat(mtl, AI_MATKEY_SHININESS, &shininess)){
			meshHelper.material.setShininess(shininess);
		}

        int blendMode;
		if(AI_SUCCESS == aiGetMaterialInteger(mtl, AI_MATKEY_BLEND_FUNC, &blendMode)){
			if(blendMode==aiBlendMode_Default){
				meshHelper.blendMode=OF_BLENDMODE_ALPHA;
			}else{
				meshHelper.blendMode=OF_BLENDMODE_ADD;
			}
		}

        // Culling
        unsigned int max = 1;
        int two_sided;
        if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)
            meshHelper.twoSided = true;
        else
            meshHelper.twoSided = false;

        // Load Textures
        int texIndex = 0;
        aiString texPath;

        // TODO: handle other aiTextureTypes
        if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)){
            ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): loading image from \"" << texPath.data << "\"";
            string modelFolder = file.getEnclosingDirectory();
            string relTexPath = ofFilePath::getEnclosingDirectory(texPath.data,false);
            string texFile = ofFilePath::getFileName(texPath.data);
            string realPath = ofFilePath::join(ofFilePath::join(modelFolder, relTexPath), texFile);
            
            if(ofFile::doesFileExist(realPath) == false) {
                ofLogError("ofxAssimpModelLoader") << "loadGLResource(): texture doesn't exist: \""
					<< file.getFileName() + "\" in \"" << realPath << "\"";
            }
            
            ofxAssimpTexture assimpTexture;
            bool bTextureAlreadyExists = false;
            for(int j=0; j<textures.size(); j++) {
                assimpTexture = textures[j];
                if(assimpTexture.getTexturePath() == realPath) {
                    bTextureAlreadyExists = true;
                    break;
                }
            }
            if(bTextureAlreadyExists) {
                meshHelper.assimpTexture = assimpTexture;
                ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): texture already loaded: \""
					<< file.getFileName() + "\" from \"" << realPath << "\"";
            } else {
                ofTexture texture;
                bool bTextureLoadedOk = ofLoadImage(texture, realPath);
                if(bTextureLoadedOk) {
                    textures.push_back(ofxAssimpTexture(texture, realPath));
                    assimpTexture = textures.back();
                    meshHelper.assimpTexture = assimpTexture;
                    ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): texture loaded, dimensions: "
						<< texture.getWidth() << "x" << texture.getHeight();
                } else {
                    ofLogError("ofxAssimpModelLoader") << "loadGLResource(): couldn't load texture: \""
						<< file.getFileName() + "\" from \"" << realPath << "\"";
                }
            }
        }

        meshHelper.mesh = mesh;
        aiMeshToOfMesh(mesh, meshHelper.cachedMesh, &meshHelper);
        meshHelper.cachedMesh.setMode(OF_PRIMITIVE_TRIANGLES);
        meshHelper.validCache = true;
        meshHelper.hasChanged = false;

        meshHelper.animatedPos.resize(mesh->mNumVertices);
        if(mesh->HasNormals()){
        	meshHelper.animatedNorm.resize(mesh->mNumVertices);
        }


        int usage;
        if(getAnimationCount()){
#ifndef TARGET_OPENGLES
        	if(!ofIsGLProgrammableRenderer()){
        		usage = GL_STATIC_DRAW;
        	}else{
        		usage = GL_STREAM_DRAW;
        	}
#else
        	usage = GL_DYNAMIC_DRAW;
#endif
        }else{
        	usage = GL_STATIC_DRAW;

        }

        meshHelper.vbo.setVertexData(&mesh->mVertices[0].x,3,mesh->mNumVertices,usage,sizeof(aiVector3D));
        if(mesh->HasVertexColors(0)){
        	meshHelper.vbo.setColorData(&mesh->mColors[0][0].r,mesh->mNumVertices,GL_STATIC_DRAW,sizeof(aiColor4D));
        }
        if(mesh->HasNormals()){
        	meshHelper.vbo.setNormalData(&mesh->mNormals[0].x,mesh->mNumVertices,usage,sizeof(aiVector3D));
        }
        if (meshHelper.cachedMesh.hasTexCoords()){			
        	meshHelper.vbo.setTexCoordData(meshHelper.cachedMesh.getTexCoordsPointer()[0].getPtr(),mesh->mNumVertices,GL_STATIC_DRAW,sizeof(ofVec2f));
        }

        meshHelper.indices.resize(mesh->mNumFaces * 3);
        int j=0;
        for (unsigned int x = 0; x < mesh->mNumFaces; ++x){
			for (unsigned int a = 0; a < mesh->mFaces[x].mNumIndices; ++a){
				meshHelper.indices[j++]=mesh->mFaces[x].mIndices[a];
			}
		}

        meshHelper.vbo.setIndexData(&meshHelper.indices[0],meshHelper.indices.size(),GL_STATIC_DRAW);

        //modelMeshes.push_back(meshHelper);
    }
    
    int numOfAnimations = scene->mNumAnimations;
    for(int i=0; i<numOfAnimations; i++) {
        aiAnimation * animation = scene->mAnimations[i];
        animations.push_back(ofxAssimpAnimation(scene, animation));
    }

    ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): finished";
}
//-------------------------------------------
void ofxAssimpModelLoader::loadGLResources(){

    ofLog(OF_LOG_VERBOSE, "loading gl resources");

    // create new mesh helpers for each mesh, will populate their data later.
   // modelMeshes.resize(scene->mNumMeshes,ofxAssimpMeshHelper());

    // create OpenGL buffers and populate them based on each meshes pertinant info.
    for (unsigned int i = 0; i < scene->mNumMeshes; ++i){
        ofLog(OF_LOG_VERBOSE, "loading mesh %u", i);
        // current mesh we are introspecting
        aiMesh* mesh = scene->mMeshes[i];

        // the current meshHelper we will be populating data into.
        //ofxAssimpMeshHelper & meshHelper = modelMeshes[i];
        ofxAssimpMeshHelper meshHelper;
		
        //meshHelper.texture = NULL;

        // Handle material info
        aiMaterial* mtl = scene->mMaterials[mesh->mMaterialIndex];
        aiColor4D dcolor, scolor, acolor, ecolor;

        if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &dcolor)){
            meshHelper.material.setDiffuseColor(aiColorToOfColor(dcolor));
        }

        if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &scolor)){
        	meshHelper.material.setSpecularColor(aiColorToOfColor(scolor));
        }

        if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &acolor)){
        	meshHelper.material.setAmbientColor(aiColorToOfColor(acolor));
        }

        if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &ecolor)){
        	meshHelper.material.setEmissiveColor(aiColorToOfColor(ecolor));
        }

        float shininess;
        if(AI_SUCCESS == aiGetMaterialFloat(mtl, AI_MATKEY_SHININESS, &shininess)){
			meshHelper.material.setShininess(shininess);
		}

        int blendMode;
		if(AI_SUCCESS == aiGetMaterialInteger(mtl, AI_MATKEY_BLEND_FUNC, &blendMode)){
			if(blendMode==aiBlendMode_Default){
				meshHelper.blendMode=OF_BLENDMODE_ALPHA;
			}else{
				meshHelper.blendMode=OF_BLENDMODE_ADD;
			}
		}

        // Culling
        unsigned int max = 1;
        int two_sided;
        if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)
            meshHelper.twoSided = true;
        else
            meshHelper.twoSided = false;

        // Load Textures
        int texIndex = 0;
        aiString texPath;

        // TODO: handle other aiTextureTypes
        if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)){
            ofLog(OF_LOG_VERBOSE, "loading image from %s", texPath.data);
            string modelFolder = ofFilePath::getEnclosingDirectory(filepath,false);
            string relTexPath = ofFilePath::getEnclosingDirectory(texPath.data,false);
            string texFile = ofFilePath::getFileName(texPath.data);
            string realPath = modelFolder + relTexPath  + texFile;
			if(!ofFile::doesFileExist(realPath) || !ofLoadImage(meshHelper.texture,realPath)) {
                ofLog(OF_LOG_ERROR,string("error loading image ") + filepath + " " +realPath);
			}else{
                ofLog(OF_LOG_VERBOSE, "texture width: %f height %f", meshHelper.texture.getWidth(), meshHelper.texture.getHeight());
			}
        }

        meshHelper.mesh = mesh;
        aiMeshToOfMesh(mesh, meshHelper.cachedMesh, &meshHelper);
        meshHelper.cachedMesh.setMode(OF_PRIMITIVE_TRIANGLES);
        meshHelper.validCache = true;
        meshHelper.hasChanged = false;

        meshHelper.animatedPos.resize(mesh->mNumVertices);
        if(mesh->HasNormals()){
        	meshHelper.animatedNorm.resize(mesh->mNumVertices);
        }


        int usage;
        if(getAnimationCount()){
#ifndef TARGET_OPENGLES
        	usage = GL_STREAM_DRAW;
#else
        	usage = GL_DYNAMIC_DRAW;
#endif
        }else{
        	usage = GL_STATIC_DRAW;

        }

        meshHelper.vbo.setVertexData(&mesh->mVertices[0].x,3,mesh->mNumVertices,usage,sizeof(aiVector3D));
        if(mesh->HasVertexColors(0)){
        	meshHelper.vbo.setColorData(&mesh->mColors[0][0].r,mesh->mNumVertices,GL_STATIC_DRAW,sizeof(aiColor4D));
        }
        if(mesh->HasNormals()){
        	meshHelper.vbo.setNormalData(&mesh->mNormals[0].x,mesh->mNumVertices,usage,sizeof(aiVector3D));
        }
        if (meshHelper.cachedMesh.hasTexCoords()){			
        	meshHelper.vbo.setTexCoordData(meshHelper.cachedMesh.getTexCoordsPointer()[0].getPtr(),mesh->mNumVertices,GL_STATIC_DRAW,sizeof(ofVec2f));
        }

        meshHelper.indices.resize(mesh->mNumFaces * 3);
        int j=0;
        for (unsigned int x = 0; x < mesh->mNumFaces; ++x){
			for (unsigned int a = 0; a < mesh->mFaces[x].mNumIndices; ++a){
				meshHelper.indices[j++]=mesh->mFaces[x].mIndices[a];
			}
		}

        meshHelper.vbo.setIndexData(&meshHelper.indices[0],meshHelper.indices.size(),GL_STATIC_DRAW);
        modelMeshes.push_back(meshHelper);
    }

    animationTime = -1;
    setNormalizedTime(0);

    ofLog(OF_LOG_VERBOSE, "finished loading gl resources");

}