bool ofxAssimpModelLoader::processScene() { normalizeFactor = ofGetWidth() / 2.0; if(scene){ loadGLResources(); update(); calculateDimensions(); if(getAnimationCount()) ofLogVerbose("ofxAssimpModelLoader") << "loadModel(): scene has " << getAnimationCount() << "animations"; else { ofLogVerbose("ofxAssimpModelLoader") << "loadMode(): no animations"; } ofAddListener(ofEvents().exit,this,&ofxAssimpModelLoader::onAppExit); return true; }else{ ofLogError("ofxAssimpModelLoader") << "loadModel(): " + (string) aiGetErrorString(); clear(); return false; } return false; }
//------------------------------------------- bool ofxAssimpModelLoader::loadModel(ofBuffer & buffer, bool optimize, const char * extension){ normalizeFactor = ofGetWidth() / 2.0; // 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; if(scene){ clear(); } scene = aiImportFileFromMemory(buffer.getBinaryBuffer(), buffer.size(), flags, extension); if(scene){ calculateDimensions(); loadGLResources(); if(getAnimationCount()) ofLog(OF_LOG_VERBOSE, "scene has animations"); else { ofLog(OF_LOG_VERBOSE, "no animations"); } return true; }else{ ofLog(OF_LOG_ERROR,string("ofxAssimpModelLoader: ") + aiGetErrorString()); return false; } }
// DEPRECATED. float ofxAssimpModelLoader::getDuration(int animationIndex) { if(!hasAnimations()) { return 0; } animationIndex = ofClamp(animationIndex, 0, getAnimationCount() - 1); float duration = animations[animationIndex].getDurationInSeconds(); return duration; }
//------------------------------------------ void ofxAssimpModelLoader::loadModel(string modelName){ // if we have a model loaded, unload the f****r. if(scene != NULL) { aiReleaseImport(scene); scene = NULL; deleteGLResources(); } // Load our new path. string filepath = ofToDataPath(modelName); ofLog(OF_LOG_VERBOSE, "loading model %s", filepath.c_str()); // 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. scene = (aiScene*) aiImportFile(filepath.c_str(), aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_OptimizeGraph | aiProcess_Triangulate | aiProcess_FlipUVs | 0 ); if(scene){ ofLog(OF_LOG_VERBOSE, "initted scene with %i meshes & %i animations", scene->mNumMeshes, scene->mNumAnimations); getBoundingBoxWithMinVector(&scene_min, &scene_max); scene_center.x = (scene_min.x + scene_max.x) / 2.0f; scene_center.y = (scene_min.y + scene_max.y) / 2.0f; scene_center.z = (scene_min.z + scene_max.z) / 2.0f; // optional normalized scaling normalizedScale = scene_max.x-scene_min.x; normalizedScale = aisgl_max(scene_max.y - scene_min.y,normalizedScale); normalizedScale = aisgl_max(scene_max.z - scene_min.z,normalizedScale); normalizedScale = 1.f / normalizedScale; normalizedScale *= ofGetWidth() / 2.0; glPushAttrib(GL_ALL_ATTRIB_BITS); glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); loadGLResources(); glPopClientAttrib(); glPopAttrib(); if(getAnimationCount()) ofLog(OF_LOG_VERBOSE, "scene has animations"); else { ofLog(OF_LOG_VERBOSE, "no animations"); } } }
void ofxAssimpModelLoader::setTime(float t){ // 0 - 1 if(getAnimationCount()){ // only evaluate if we have a delta t. if(animationTime != t){ animationTime = t; updateAnimation(currentAnimation, animationTime); } } }
//------------------------------------------- void ofxAssimpModelLoader::setNormalizedTime(float t){ // 0 - 1 if(getAnimationCount()) { const aiAnimation* anim = scene->mAnimations[currentAnimation]; float realT = ofMap(t, 0.0, 1.0, 0.0, (float)anim->mDuration, false); setTime(realT); } }
//------------------------------------------- bool ofxAssimpModelLoader::loadModel(ofBuffer & buffer, bool optimize, const char * extension){ normalizeFactor = ofGetWidth() / 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, extension); if(scene){ calculateDimensions(); loadGLResources(); update(); if(getAnimationCount()) ofLogVerbose("ofxAssimpModelLoader") << "loadModel(): scene has " << getAnimationCount() << "animations"; else { ofLogVerbose("ofxAssimpModelLoader") << "loadMode(): no animations"; } ofAddListener(ofEvents().exit,this,&ofxAssimpModelLoader::onAppExit); return true; }else{ ofLogError("ofxAssimpModelLoader") << "loadModel(): " + (string) aiGetErrorString(); clear(); return false; } }
//------------------------------------------ bool ofxAssimpModelLoader::loadModel(string modelName, unsigned extraFlags /* = 0 */){ // if we have a model loaded, unload the f****r. if(scene != NULL){ clear(); } // Load our new path. filepath = modelName; string filepath = ofToDataPath(modelName); //theo added - so we can have models and their textures in sub folders modelFolder = ofFilePath::getEnclosingDirectory(filepath); ofLog(OF_LOG_VERBOSE, "loading model %s", filepath.c_str()); ofLog(OF_LOG_VERBOSE, "loading from folder %s", modelFolder.c_str()); // 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; flags |= extraFlags; /* if(optimize) flags |= aiProcess_ImproveCacheLocality | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials; */ scene = aiImportFile(filepath.c_str(), flags); if(scene){ calculateDimensions(); loadGLResources(); if(getAnimationCount()) ofLog(OF_LOG_VERBOSE, "scene has animations"); else { ofLog(OF_LOG_VERBOSE, "no animations"); } collectNodeTransforms(scene, scene->mRootNode); collectBoneTransforms(); return true; }else{ ofLog(OF_LOG_ERROR,string("ofxAssimpModelLoader: ") + aiGetErrorString()); return false; } }
//------------------------------------------- void ofxAssimpModelLoader::loadGLResources(){ ofLog(OF_LOG_VERBOSE, "loading gl resources"); // create new mesh helpers for each mesh, will populate their data later. modelMeshes.reserve(scene->mNumMeshes); // 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; meshHelper.mesh = mesh; // set the mesh's default values. aiColor4D dcolor = aiColor4D(0.8f, 0.8f, 0.8f, 1.0f); meshHelper.diffuseColor = dcolor; aiColor4D scolor = aiColor4D(0.0f, 0.0f, 0.0f, 1.0f); meshHelper.specularColor = scolor; aiColor4D acolor = aiColor4D(0.2f, 0.2f, 0.2f, 1.0f); meshHelper.ambientColor = acolor; aiColor4D ecolor = aiColor4D(0.0f, 0.0f, 0.0f, 1.0f); meshHelper.emissiveColor = ecolor; // Handle material info aiMaterial* mtl = scene->mMaterials[mesh->mMaterialIndex]; // Load Textures int texIndex = 0; aiString texPath; //meshHelper.texture = NULL; // TODO: handle other aiTextureTypes if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)){ // This is magic. Thanks Kyle. textures.push_back(ofImage()); ofImage& image = textures.back(); ofLog(OF_LOG_VERBOSE, "loading image from %s", texPath.data); image.loadImage(texPath.data); image.update(); ofLog(OF_LOG_VERBOSE, "texture width: %f height %f", image.getWidth(), image.getHeight()); //meshHelper.texture = &(image.getTextureReference()); meshHelper.textureIndex = textures.size()-1; } if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &dcolor)) meshHelper.diffuseColor = dcolor; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &scolor)) meshHelper.specularColor = scolor; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &acolor)) meshHelper.ambientColor = acolor; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &ecolor)) meshHelper.emissiveColor = ecolor; // 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; // Create a VBO for our vertices GLuint vhandle; glGenBuffers(1, &vhandle); glBindBuffer(GL_ARRAY_BUFFER, vhandle); if(getAnimationCount()) glBufferData(GL_ARRAY_BUFFER, sizeof(aiVertex) * mesh->mNumVertices, NULL, GL_STREAM_DRAW/*GL_STATIC_DRAW GL_STREAM_DRAW*/); else glBufferData(GL_ARRAY_BUFFER, sizeof(aiVertex) * mesh->mNumVertices, NULL, GL_STATIC_DRAW/*GL_STATIC_DRAW GL_STREAM_DRAW*/); // populate vertices aiVertex* verts = (aiVertex*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); for (unsigned int x = 0; x < mesh->mNumVertices; ++x) { verts->vPosition = mesh->mVertices[x]; if (NULL == mesh->mNormals) verts->vNormal = aiVector3D(0.0f,0.0f,0.0f); else verts->vNormal = mesh->mNormals[x]; if (mesh->HasVertexColors(0)) { verts->dColorDiffuse = mesh->mColors[0][x]; } else verts->dColorDiffuse = aiColor4D(1.0, 1.0, 1.0, 1.0); // This varies slightly form Assimp View, we support the 3rd texture component. if (mesh->HasTextureCoords(0)) verts->vTextureUV = mesh->mTextureCoords[0][x]; else verts->vTextureUV = aiVector3D(0.5f,0.5f, 0.0f); // No longer in aiVertex VBO structure /* if (NULL == mesh->mTangents) { verts->vTangent = aiVector3D(0.0f,0.0f,0.0f); verts->vBitangent = aiVector3D(0.0f,0.0f,0.0f); } else { verts->vTangent = mesh->mTangents[x]; verts->vBitangent = mesh->mBitangents[x]; } if (mesh->HasTextureCoords(1)) verts->vTextureUV2 = mesh->mTextureCoords[1][x]; else verts->vTextureUV2 = aiVector3D(0.5f,0.5f, 0.0f); if( mesh->HasBones()){ unsigned char boneIndices[4] = { 0, 0, 0, 0 }; unsigned char boneWeights[4] = { 0, 0, 0, 0 }; ai_assert( weightsPerVertex[x].size() <= 4); for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++){ boneIndices[a] = weightsPerVertex[x][a].mVertexId; boneWeights[a] = (unsigned char) (weightsPerVertex[x][a].mWeight * 255.0f); } memcpy( verts->mBoneIndices, boneIndices, sizeof( boneIndices)); memcpy( verts->mBoneWeights, boneWeights, sizeof( boneWeights)); } else{ // memset( verts->mBoneIndices, 0, sizeof( verts->mBoneIndices)); // memset( verts->mBoneWeights, 0, sizeof( verts->mBoneWeights)); } */ ++verts; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); //invalidates verts glBindBuffer(GL_ARRAY_BUFFER, 0); // set the mesh vertex buffer handle to our new vertex buffer. meshHelper.vertexBuffer = vhandle; // Create Index Buffer unsigned int nidx; switch (mesh->mPrimitiveTypes){ case aiPrimitiveType_POINT: nidx = 1;break; case aiPrimitiveType_LINE: nidx = 2;break; case aiPrimitiveType_TRIANGLE: nidx = 3;break; default: assert(false); } GLuint ihandle; glGenBuffers(1, &ihandle); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ihandle); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * mesh->mNumFaces * nidx, NULL, GL_STATIC_DRAW/*GL_STATIC_DRAW GL_STREAM_DRAW*/); unsigned int* indices = (unsigned int*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_ARB); // now fill the index buffer for (unsigned int x = 0; x < mesh->mNumFaces; ++x){ for (unsigned int a = 0; a < nidx; ++a){ *indices++ = mesh->mFaces[x].mIndices[a]; } } glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // set the mesh index buffer handle to our new index buffer. meshHelper.indexBuffer = ihandle; meshHelper.numIndices = mesh->mNumFaces * nidx; // create the normal buffer. Assimp View creates a second normal buffer. Unsure why. Using only the interleaved normals for now. // This is here for reference. /* GLuint nhandle; glGenBuffers(1, &nhandle); glBindBuffer(GL_ARRAY_BUFFER, nhandle); glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D)* mesh->mNumVertices, NULL, GL_STATIC_DRAW); // populate normals aiVector3D* normals = (aiVector3D*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); for (unsigned int x = 0; x < mesh->mNumVertices; ++x) { aiVector3D vNormal = mesh->mNormals[x]; *normals = vNormal; ++normals; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); //invalidates verts glBindBuffer(GL_ARRAY_BUFFER, 0); meshHelper.normalBuffer = nhandle; */ // Create VAO and populate it GLuint vaoHandle; glGenVertexArraysAPPLE(1, &vaoHandle); // TODO: equivalent PC call. glBindVertexArrayAPPLE(vaoHandle); glBindBuffer(GL_ARRAY_BUFFER, meshHelper.vertexBuffer); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, sizeof(aiVertex), BUFFER_OFFSET(12)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(3, GL_FLOAT, sizeof(aiVertex), BUFFER_OFFSET(24)); //TODO: handle second texture glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, sizeof(aiVertex), BUFFER_OFFSET(36)); // VertexPointer ought to come last, apparently this is some optimization, since if its set once first, it gets fiddled with every time something else is update. glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(aiVertex), 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshHelper.indexBuffer); glBindVertexArrayAPPLE(0); // save the VAO handle into our mesh helper meshHelper.vao = vaoHandle; modelMeshes.push_back(meshHelper); } ofLog(OF_LOG_VERBOSE, "finished loading gl resources"); }
//------------------------------------------- void ofxAssimpModelLoader::draw(ofPolyRenderMode renderType) { if(scene){ ofPushStyle(); #ifndef TARGET_OPENGLES glPushAttrib(GL_ALL_ATTRIB_BITS); glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glPolygonMode(GL_FRONT_AND_BACK, ofGetGLPolyMode(renderType)); #endif glEnable(GL_NORMALIZE); ofPushMatrix(); ofTranslate(pos); ofRotate(180, 0, 0, 1); ofTranslate(-scene_center.x, -scene_center.y, scene_center.z); if(normalizeScale) { ofScale(normalizedScale , normalizedScale, normalizedScale); } for(int i = 0; i < (int)rotAngle.size(); i++){ ofRotate(rotAngle[i], rotAxis[i].x, rotAxis[i].y, rotAxis[i].z); } ofScale(scale.x, scale.y, scale.z); if(getAnimationCount()) { updateGLResources(); } for(int i = 0; i < (int)modelMeshes.size(); i++){ ofxAssimpMeshHelper & meshHelper = modelMeshes.at(i); // Texture Binding if(bUsingTextures && meshHelper.texture.isAllocated()){ meshHelper.texture.bind(); } if(bUsingMaterials){ meshHelper.material.begin(); } // Culling if(meshHelper.twoSided) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); ofEnableBlendMode(meshHelper.blendMode); #ifndef TARGET_OPENGLES meshHelper.vbo.drawElements(GL_TRIANGLES,meshHelper.indices.size()); #else switch(renderType){ case OF_MESH_FILL: meshHelper.vbo.drawElements(GL_TRIANGLES,meshHelper.indices.size()); break; case OF_MESH_WIREFRAME: meshHelper.vbo.drawElements(GL_LINES,meshHelper.indices.size()); break; case OF_MESH_POINTS: meshHelper.vbo.drawElements(GL_POINTS,meshHelper.indices.size()); break; } #endif // Texture Binding if(bUsingTextures && meshHelper.texture.bAllocated()){ meshHelper.texture.unbind(); } if(bUsingMaterials){ meshHelper.material.end(); } } ofPopMatrix(); #ifndef TARGET_OPENGLES glPopClientAttrib(); glPopAttrib(); #endif ofPopStyle(); } }
//------------------------------------------- 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"; }
// DEPRECATED. void ofxAssimpModelLoader::setAnimation(int animationIndex) { if(!hasAnimations()) { return; } currentAnimation = ofClamp(animationIndex, 0, getAnimationCount() - 1); }
Animation * AnimationMgr::getAnimation(unsigned index) const { assert(index < getAnimationCount()); return _animations[index].get(); }
CCAFCAnimation* CCSPX3Sprite::getAnimationAt(int index, CCAFCClipMapping* mapping) { if(index < 0 || index >= getAnimationCount()) return NULL; else return CCSPX3Manager::getInstance()->getAnimationData(m_spx, index, mapping); }
void AnimationMgr::setAnimationId(unsigned id) { assert(id < getAnimationCount()); _index = id; getAnimation(id)->resetFrames(); }
Animation * AnimationMgr::getCurrentAnimation() const { assert(getAnimationId() < getAnimationCount()); return _animations[getAnimationId()].get(); }
wyAFCAnimation* wyAuroraSprite::getAnimationAt(int index, wyAFCClipMapping* mapping) { if(index < 0 || index >= getAnimationCount()) return NULL; else return wyAuroraManager::getInstance()->getAnimationData(m_aurora, index, mapping); }
void ofxAssimpModelLoader::setTime(float t){ // 0 - 1 if(getAnimationCount()) updateAnimation(currentAnimation, t); }
bool ModelMD2::loadModel(const char *filename, GLboolean is_absPath) { FILE *file; GLubyte buffer[MD2_MAX_FRAMESIZE]; int i; file = fopen(Utils::getFileName(filename, is_absPath), "rb"); if (!file) return false; /* initialize model and read header */ fread (&m_header, sizeof (md2_header_t), 1, file); #if DEBUG printf ("magic:\t\t%d\n", m_header.magic); printf ("version:\t\t%d\n", m_header.version); printf ("skinWidth:\t\t%d\n", m_header.skinWidth); printf ("skinHeight:\t\t%d\n", m_header.skinHeight); printf ("frameSize:\t\t%d\n", m_header.frameSize); printf ("numSkins:\t\t%d\n", m_header.numSkins); printf ("numVertices:\t\t%d\n", m_header.numVertices); printf ("numTexCoords:\t\t%d\n", m_header.numTexCoords); printf ("numTriangles:\t\t%d\n", m_header.numTriangles); printf ("numGlCommands:\t\t%d\n", m_header.numGlCommands); printf ("numFrames:\t\t%d\n", m_header.numFrames); printf ("offsetSkins:\t\t%d\n", m_header.offsetSkins); printf ("offsetTexCoords:\t%d\n", m_header.offsetTexCoords); printf ("offsetTriangles:\t%d\n", m_header.offsetTriangles); printf ("offsetFrames:\t\t%d\n", m_header.offsetFrames); printf ("offsetGlCommands:\t%d\n", m_header.offsetGlCommands); printf ("offsetEnd:\t\t%d\n", m_header.offsetEnd); #endif if (m_header.magic != (int) (('2' << 24) + ('P' << 16) + ('D' << 8) + 'I')) { fclose(file); return false; } /* read skins */ fseek (file, m_header.offsetSkins, SEEK_SET); if (m_header.numSkins > 0) { m_skins = (md2_skin_t *) malloc(sizeof(md2_skin_t) * m_header.numSkins); if (!m_skins) { //md2_freeModel (model); return false; } for (i = 0; i < m_header.numSkins; i++) fread (&m_skins[i], sizeof(md2_skin_t), 1, file); } /* read texture coordinates */ fseek (file, m_header.offsetTexCoords, SEEK_SET); if (m_header.numTexCoords > 0) { m_texCoords = (md2_textureCoordinate_t *) malloc (sizeof (md2_textureCoordinate_t) * m_header.numTexCoords); if (!m_texCoords) { //md2_freeModel (model); return false; } for (i = 0; i < m_header.numTexCoords; i++) fread (&m_texCoords[i], sizeof (md2_textureCoordinate_t), 1, file); } /* read triangles */ fseek (file, m_header.offsetTriangles, SEEK_SET); if (m_header.numTriangles > 0) { m_triangles = (md2_triangle_t *) malloc(sizeof(md2_triangle_t) * m_header.numTriangles); if (!m_triangles) { //md2_freeModel (model); return false; } for (i = 0; i < m_header.numTriangles; i++) fread (&m_triangles[i], sizeof (md2_triangle_t), 1, file); } /* read alias frames */ fseek (file, m_header.offsetFrames, SEEK_SET); if (m_header.numFrames > 0) { m_frames = (md2_frame_t *) malloc (sizeof (md2_frame_t) * m_header.numFrames); if (!m_frames) { //md2_freeModel (model); return false; } for (i = 0; i < m_header.numFrames; i++) { md2_alias_frame_t *frame = (md2_alias_frame_t *) buffer; int j; m_frames[i].vertices = (md2_triangleVertex_t *) malloc (sizeof (md2_triangleVertex_t) * m_header.numVertices); if (!m_frames[i].vertices) { //md2_freeModel (model); return false; } fread (frame, 1, m_header.frameSize, file); strcpy (m_frames[i].name, frame->name); for (j = 0; j < m_header.numVertices; j++) { m_frames[i].vertices[j].vertex[0] = (float) ((int) frame->alias_vertices[j].vertex[0]) * frame->scale[0] + frame->translate[0]; m_frames[i].vertices[j].vertex[2] = -1* ((float) ((int) frame->alias_vertices[j].vertex[1]) * frame->scale[1] + frame->translate[1]); m_frames[i].vertices[j].vertex[1] = (float) ((int) frame->alias_vertices[j].vertex[2]) * frame->scale[2] + frame->translate[2]; m_frames[i].vertices[j].normal[0] = NORMALS_TABLE[frame->alias_vertices[j].lightNormalIndex][0]; m_frames[i].vertices[j].normal[1] = NORMALS_TABLE[frame->alias_vertices[j].lightNormalIndex][1]; m_frames[i].vertices[j].normal[2] = NORMALS_TABLE[frame->alias_vertices[j].lightNormalIndex][2]; //model->frames[i].vertices[j].lightNormalIndex = frame->alias_vertices[j].lightNormalIndex; } } } //ignore gl commands reading fclose (file); setTriangleNums(m_header.numTriangles); m_actionCount = getAnimationCount(); #if DEBUG printf("getAnimationCount:\t%d\n", m_actionCount); #endif m_actions = (md2_action_t *) malloc(m_actionCount * sizeof(md2_action_t)); for (i = 0; i < (int) m_actionCount; i++) { m_actions[i].index = i; strcpy (m_actions[i].name, getAnimationName(i)); getAnimationFrames(i, &(m_actions[i].min_idx), &(m_actions[i].max_idx )); #if DEBUG printf("m_actions[%d]:\t\t%s [%d, %d]\n", i, m_actions[i].name, m_actions[i].min_idx, m_actions[i].max_idx); #endif } return true; }
void ofxAssimpModelLoader::draw() { if(scene){ glPushAttrib(GL_ALL_ATTRIB_BITS); glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); glEnable(GL_NORMALIZE); glPushMatrix(); glTranslatef(pos.x, pos.y, pos.z); glRotatef(180, 0, 0, 1); glTranslated(-scene_center.x, -scene_center.y, scene_center.z); if(normalizeScale) { glScaled(normalizedScale , normalizedScale, normalizedScale); } for(int i = 0; i < numRotations; i++){ glRotatef(rotAngle[i], rotAxis[i].x, rotAxis[i].y, rotAxis[i].z); } glScalef(scale.x, scale.y, scale.z); if(getAnimationCount()) { updateGLResources(); } if(modelMeshes.size()) { for(int i = 0; i < modelMeshes.size(); i++){ ofxAssimpMeshHelper meshHelper = modelMeshes.at(i); // Texture Binding if(meshHelper.textureIndex!=-1){ textures[meshHelper.textureIndex].getTextureReference().bind(); } // Set up meterial state. float dc[4]; float sc[4]; float ac[4]; float emc[4]; // Material colors and properties color4_to_float4(&meshHelper.diffuseColor, dc); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, dc); color4_to_float4(&meshHelper.specularColor, sc); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, sc); color4_to_float4(&meshHelper.ambientColor, ac); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ac); color4_to_float4(&meshHelper.emissiveColor, emc); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emc); // Culling if(meshHelper.twoSided) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); // TODO: equivalent VAO callfor linux and windows. glBindVertexArrayAPPLE(meshHelper.vao); glDrawElements(GL_TRIANGLES, meshHelper.numIndices, GL_UNSIGNED_INT, 0); // Texture Binding if(meshHelper.textureIndex!=-1){ textures[meshHelper.textureIndex].getTextureReference().unbind(); } } } glPopMatrix(); glPopClientAttrib(); glPopAttrib(); } }
//------------------------------------------- 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"); }