// Load model textures bool VSResModelLib::loadTextures(const aiScene* scene, std::string prefix) { VSLOG(mLogInfo, "Loading Textures from %s", prefix.c_str()); /* scan scene's materials for textures */ for (unsigned int m=0; m<scene->mNumMaterials; ++m) { int texIndex = 0; aiString path; // filename aiReturn texFound = scene->mMaterials[m]-> GetTexture(aiTextureType_DIFFUSE, texIndex, &path); while (texFound == AI_SUCCESS) { //fill map with textures, OpenGL image ids set to 0 pTextureIdMap[path.data] = 0; // more textures? texIndex++; texFound = scene->mMaterials[m]-> GetTexture(aiTextureType_DIFFUSE, texIndex, &path); } } int numTextures = pTextureIdMap.size(); /* get iterator */ std::map<std::string, GLuint>::iterator itr = pTextureIdMap.begin(); for (int i= 0; itr != pTextureIdMap.end(); ++i, ++itr) { // get filename std::string filename = (*itr).first; filename = prefix + filename; // save texture id for filename in map (*itr).second = loadRGBATexture(filename, true,true); VSLOG(mLogInfo, "Texture %s loaded with name %d", filename.c_str(), (int)(*itr).second); } return true; }
// helper function for derived classes // loads an image and defines an 8-bit RGBA texture unsigned int VSResourceLib::loadCubeMapTexture( std::string posX, std::string negX, std::string posY, std::string negY, std::string posZ, std::string negZ) { ILboolean success; unsigned int imageID; GLuint textureID = 0; std::string files[6]; files[0] = posX; files[1] = negX; files[2] = posY; files[3] = negY; files[4] = posZ; files[5] = negZ; glGenTextures(1, &textureID); /* Texture name generation */ glBindTexture(GL_TEXTURE_CUBE_MAP, textureID); // Load Textures for Cube Map glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); ilGenImages(1, &imageID); ilBindImage(imageID); /* Binding of DevIL image name */ for (int i = 0; i < 6; ++i) { ilEnable(IL_ORIGIN_SET); ilOriginFunc(IL_ORIGIN_LOWER_LEFT); success = ilLoadImage((ILstring)files[i].c_str()); if (!success) { VSLOG(sLogError, "Couldn't load texture: %s", files[i].c_str()); // The operation was not sucessfull // hence free image and texture ilDeleteImages(1, &imageID); return 0; } /* Convert image to RGBA */ ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); /* Create and load textures to OpenGL */ glTexImage2D(faceTarget[i], 0, GL_RGBA, ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT), 0, GL_RGBA, GL_UNSIGNED_BYTE, ilGetData()); VSLOG(sLogInfo, "Texture Loaded: %s", files[i].c_str()); } VSLOG(sLogInfo, "Cube Map Loaded Successfully"); glBindTexture(GL_TEXTURE_CUBE_MAP,0); /* Because we have already copied image data into texture data we can release memory used by image. */ ilDeleteImages(1, &imageID); // add information to the log return textureID; }
// helper function for derived classes // loads an image and defines an 8-bit RGBA texture unsigned int VSResourceLib::loadRGBATexture(std::string filename, bool mipmap, bool compress, GLenum aFilter, GLenum aRepMode) { ILboolean success; unsigned int imageID; GLuint textureID = 0; // Load Texture Map ilGenImages(1, &imageID); ilBindImage(imageID); /* Binding of DevIL image name */ ilEnable(IL_ORIGIN_SET); ilOriginFunc(IL_ORIGIN_LOWER_LEFT); success = ilLoadImage((ILstring)filename.c_str()); if (!success) { VSLOG(sLogError, "Couldn't load texture: %s", filename.c_str()); // The operation was not sucessfull // hence free image and texture ilDeleteImages(1, &imageID); return 0; } // add information to the log VSLOG(sLogInfo, "Texture Loaded: %s", filename.c_str()); printf("Width: %d, Height %d, Bytes per Pixel %d", ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT), ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL)); std::string s; switch(ilGetInteger(IL_IMAGE_FORMAT)) { case IL_COLOR_INDEX : s = "IL_COLOR_INDEX"; break; case IL_ALPHA : s = "IL_ALPHA"; break; case IL_RGB : s = "IL_RGB"; break; case IL_RGBA : s = "IL_RGBA"; break; case IL_BGR : s = "IL_BGR"; break; case IL_BGRA : s = "IL_BGRA"; break; case IL_LUMINANCE : s = "IL_LUMINANCE"; break; case IL_LUMINANCE_ALPHA : s = "IL_LUMINANCE_ALPHA"; break; } printf(" Format %s", s.c_str()); switch(ilGetInteger(IL_IMAGE_TYPE)) { case IL_BYTE : s = "IL_BYTE"; break; case IL_UNSIGNED_BYTE : s = "IL_UNSIGNED_BYTE"; break; case IL_SHORT : s = "IL_SHORT"; break; case IL_UNSIGNED_SHORT : s = "IL_UNSIGNED_SHORT"; break; case IL_INT : s = "IL_INT"; break; case IL_UNSIGNED_INT : s = "IL_UNSIGNED_INT"; break; case IL_FLOAT : s = "IL_FLOAT"; break; case IL_DOUBLE : s = "IL_DOUBLE"; break; case IL_HALF : s = "IL_HALF"; break; } printf(" Data type: %s\n", s.c_str()); /* Convert image to RGBA */ ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); // Set filters GLenum minFilter = aFilter; if (aFilter == GL_LINEAR && mipmap) { minFilter = GL_LINEAR_MIPMAP_LINEAR; } else if (aFilter == GL_NEAREST && mipmap){ minFilter = GL_NEAREST_MIPMAP_LINEAR; } GLenum type; if (compress) type = GL_RGBA; else type = GL_COMPRESSED_RGBA; /* Create and load textures to OpenGL */ glGenTextures(1, &textureID); /* Texture name generation */ glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, aRepMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, aRepMode); glTexImage2D(GL_TEXTURE_2D, 0, type, ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT), 0, GL_RGBA, GL_UNSIGNED_BYTE, ilGetData()); // Mipmapping? if (mipmap) glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,0); /* Because we have already copied image data into texture data we can release memory used by image. */ ilDeleteImages(1, &imageID); return textureID; }
// helper function for derived classes // loads an image and defines an 8-bit RGBA texture unsigned int VSResourceLib::loadRGBATexture(std::string filename, bool mipmap, bool compress, GLenum aFilter, GLenum aRepMode) { ILboolean success; unsigned int imageID; GLuint textureID = 0; // Load Texture Map ilGenImages(1, &imageID); ilBindImage(imageID); /* Binding of DevIL image name */ ilEnable(IL_ORIGIN_SET); ilOriginFunc(IL_ORIGIN_LOWER_LEFT); success = ilLoadImage((ILstring)filename.c_str()); if (!success) { VSLOG(mLogError, "Couldn't load texture: %s", filename.c_str()); // The operation was not sucessfull // hence free image and texture ilDeleteImages(1, &imageID); return 0; } /* Convert image to RGBA */ ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); // Set filters GLenum minFilter = aFilter; if (aFilter == GL_LINEAR && mipmap) { minFilter = GL_LINEAR_MIPMAP_LINEAR; } else if (aFilter == GL_NEAREST && mipmap){ minFilter = GL_NEAREST_MIPMAP_LINEAR; } GLenum type; if (compress) type = GL_RGBA; else type = GL_COMPRESSED_RGBA; /* Create and load textures to OpenGL */ glGenTextures(1, &textureID); /* Texture name generation */ glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, aRepMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, aRepMode); glTexImage2D(GL_TEXTURE_2D, 0, type, ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT), 0, GL_RGBA, GL_UNSIGNED_BYTE, ilGetData()); // Mipmapping? if (mipmap) glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,0); /* Because we have already copied image data into texture data we can release memory used by image. */ ilDeleteImages(1, &imageID); // add information to the log VSLOG(mLogInfo, "Texture Loaded: %s", filename.c_str()); return textureID; }
bool VSResModelLib::load(std::string filename) { Assimp::Importer importer; //check if file exists std::ifstream fin(filename.c_str()); if(!fin.fail()) fin.close(); else { VSLOG(mLogError, "Unable to open file %s", filename.c_str()); return false; } pScene = importer.ReadFile( filename, aiProcessPreset_TargetRealtime_Quality); // If the import failed, report it if( !pScene) { VSLOG(mLogError, "Failed to import %s", filename.c_str()); return false; } // Get prefix for texture loading size_t index = filename.find_last_of("/\\"); std::string prefix = filename.substr(0, index+1); pTextureIdMap.clear(); bool result = loadTextures(pScene, prefix); genVAOsAndUniformBuffer(pScene); // determine bounding box struct aiVector3D min, max; min.x = min.y = min.z = 1e10f; max.x = max.y = max.z = -1e10f; mVSML->loadIdentity(VSMathLib::AUX0); get_bounding_box_for_node(pScene->mRootNode,&min,&max); float tmp; tmp = max.x - min.x; tmp = max.y - min.y > tmp? max.y - min.y:tmp; tmp = max.z - min.z > tmp? max.z - min.z:tmp; mScaleToUnitCube = 2.0f / tmp; mCenter[0] = min.x + (max.x - min.x) * 0.5f; mCenter[1] = min.y + (max.y - min.y) * 0.5f; mCenter[2] = min.z + (max.z - min.z) * 0.5f; mVSML->loadIdentity(VSMathLib::AUX0); mVSML->scale(VSMathLib::AUX0, mScaleToUnitCube, mScaleToUnitCube, mScaleToUnitCube); mVSML->translate(VSMathLib::AUX0, -mCenter[0], -mCenter[1], -mCenter[2]); for (unsigned int i = 0; i < mMyMeshes.size(); ++i) { mVSML->pushMatrix(mVSML->AUX0); mVSML->multMatrix(mVSML->AUX0, mMyMeshes[i].transform); memcpy(mMyMeshes[i].transform, mVSML->get(mVSML->AUX0), sizeof(float)*16); mVSML->popMatrix(mVSML->AUX0); } // clear texture map pTextureIdMap.clear(); return result; }
void VSResModelLib::genVAOsAndUniformBuffer(const struct aiScene *sc) { struct MyMesh aMesh; struct Material aMat; GLuint buffer; int totalTris = 0; unsigned int *adjFaceArray; VSLOG(mLogInfo, "Number of Meshes: %d",sc->mNumMeshes); // For each mesh for (unsigned int n = 0; n < sc->mNumMeshes; ++n) { const struct aiMesh* mesh = sc->mMeshes[n]; if (mesh->mPrimitiveTypes != 4) { aMesh.numIndices = 0; pMyMeshesAux.push_back(aMesh); continue; } VSLOG(mLogInfo, "Mesh[%d] Triangles %d",n, mesh->mNumFaces); totalTris += mesh->mNumFaces; // create array with faces // have to convert from Assimp format to array unsigned int *faceArray; faceArray = (unsigned int *)malloc( sizeof(unsigned int) * mesh->mNumFaces * 3); unsigned int faceIndex = 0; for (unsigned int t = 0; t < mesh->mNumFaces; ++t) { const struct aiFace* face = &mesh->mFaces[t]; memcpy(&faceArray[faceIndex], face->mIndices, 3 * sizeof(unsigned int)); faceIndex += 3; } if (pUseAdjacency) { // Create the half edge structure std::map<std::pair<unsigned int,unsigned int>, struct HalfEdge *> myEdges; struct HalfEdge *edge; // fill it up with edges. twin info will be added latter edge = (struct HalfEdge *)malloc(sizeof(struct HalfEdge) * mesh->mNumFaces * 3); for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { edge[i*3].vertex = faceArray[i*3+1]; edge[i*3+1].vertex = faceArray[i*3+2]; edge[i*3+2].vertex = faceArray[i*3]; edge[i*3].next = &edge[i*3+1]; edge[i*3+1].next = &edge[i*3+2]; edge[i*3+2].next = &edge[i*3]; myEdges[std::pair<unsigned int,unsigned int>(faceArray[i*3+2],faceArray[i*3])] = &edge[i*3]; myEdges[std::pair<unsigned int,unsigned int>(faceArray[i*3],faceArray[i*3+1])] = &edge[i*3+1]; myEdges[std::pair<unsigned int,unsigned int>(faceArray[i*3+1],faceArray[i*3+2])] = &edge[i*3+2]; } // add twin info std::map<std::pair<unsigned int,unsigned int>, struct HalfEdge *>::iterator iter; std::pair<unsigned int,unsigned int> edgeIndex, twinIndex; iter = myEdges.begin(); for (; iter != myEdges.end(); ++iter) { edgeIndex = iter->first; twinIndex = std::pair<unsigned int, unsigned int>(edgeIndex.second, edgeIndex.first); if (myEdges.count(twinIndex)) iter->second->twin = myEdges[twinIndex]; else iter->second->twin = NULL; } adjFaceArray = (unsigned int *)malloc(sizeof(unsigned int) * mesh->mNumFaces * 6); for (unsigned int i = 0; i < mesh->mNumFaces; i++) { // NOTE: twin may be null adjFaceArray[i*6] = edge[3*i + 0].next->vertex; adjFaceArray[i*6+1] = edge[3*i + 0].twin?edge[3*i + 0].twin->vertex:edge[3*i + 0].next->vertex; adjFaceArray[i*6+2] = edge[3*i + 1].next->vertex; adjFaceArray[i*6+3] = edge[3*i + 1].twin?edge[3*i + 1].twin->vertex:edge[3*i + 1].next->vertex; adjFaceArray[i*6+4] = edge[3*i + 2].next->vertex; adjFaceArray[i*6+5] = edge[3*i + 2].twin?edge[3*i + 2].twin->vertex:edge[3*i + 2].next->vertex; } } //printf("\n"); //for (int i = 0; i < mesh->mNumFaces * 3; ++i) // printf("%d ", faceArray[i]); //printf("\n"); //for (int i = 0; i < mesh->mNumFaces * 6; ++i) // printf("%d ", adjFaceArray[i]); //printf("\n"); aMesh.numIndices = sc->mMeshes[n]->mNumFaces * 3; // generate Vertex Array for mesh glGenVertexArrays(1,&(aMesh.vao)); glBindVertexArray(aMesh.vao); // buffer for faces glGenBuffers(1, &buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); if (pUseAdjacency) { glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * mesh->mNumFaces * 6, adjFaceArray, GL_STATIC_DRAW); free(adjFaceArray); } else glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * mesh->mNumFaces * 3, faceArray, GL_STATIC_DRAW); free(faceArray); // buffer for vertex positions if (mesh->HasPositions()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mVertices, GL_STATIC_DRAW); glEnableVertexAttribArray( VSShaderLib::VERTEX_COORD_ATTRIB); glVertexAttribPointer(VSShaderLib::VERTEX_COORD_ATTRIB, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex normals if (mesh->HasNormals()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mNormals, GL_STATIC_DRAW); glEnableVertexAttribArray(VSShaderLib::NORMAL_ATTRIB); glVertexAttribPointer(VSShaderLib::NORMAL_ATTRIB, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex normals if (mesh->HasTangentsAndBitangents()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mTangents, GL_STATIC_DRAW); glEnableVertexAttribArray(VSShaderLib::TANGENT_ATTRIB); glVertexAttribPointer(VSShaderLib::TANGENT_ATTRIB, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex normals if (mesh->HasTangentsAndBitangents()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mBitangents, GL_STATIC_DRAW); glEnableVertexAttribArray(VSShaderLib::BITANGENT_ATTRIB); glVertexAttribPointer(VSShaderLib::BITANGENT_ATTRIB, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex texture coordinates if (mesh->HasTextureCoords(0)) { float *texCoords = (float *)malloc( sizeof(float)*2*mesh->mNumVertices); for (unsigned int k = 0; k < mesh->mNumVertices; ++k) { texCoords[k*2] = mesh->mTextureCoords[0][k].x; texCoords[k*2+1] = mesh->mTextureCoords[0][k].y; } glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->mNumVertices, texCoords, GL_STATIC_DRAW); glEnableVertexAttribArray( VSShaderLib::TEXTURE_COORD_ATTRIB); glVertexAttribPointer( VSShaderLib::TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, 0, 0, 0); free(texCoords); } // unbind buffers glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER,0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); // create material uniform buffer struct aiMaterial *mtl = sc->mMaterials[mesh->mMaterialIndex]; aiString texPath; //contains filename of texture for (int j = 0; j < VSResourceLib::MAX_TEXTURES; ++j) aMesh.texUnits[j] = 0; if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, 0, &texPath)) { //bind texture aMesh.texUnits[0] = pTextureIdMap[texPath.data]; aMesh.texTypes[0] = GL_TEXTURE_2D; aMat.texCount = 1; } else { aMesh.texUnits[0] = 0; aMat.texCount = 0; } float c[4]; set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f); aiColor4D diffuse; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) color4_to_float4(&diffuse, c); memcpy(aMat.diffuse, c, sizeof(c)); set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f); aiColor4D ambient; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient)) color4_to_float4(&ambient, c); memcpy(aMat.ambient, c, sizeof(c)); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); aiColor4D specular; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular)) color4_to_float4(&specular, c); memcpy(aMat.specular, c, sizeof(c)); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); aiColor4D emission; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) color4_to_float4(&emission, c); memcpy(aMat.emissive, c, sizeof(c)); float shininess = 0.0; unsigned int max; aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max); aMat.shininess = shininess; aMesh.mat = aMat; pMyMeshesAux.push_back(aMesh); } mVSML->loadIdentity(VSMathLib::AUX0); recursive_walk_for_matrices(sc, sc->mRootNode); pMyMeshesAux.clear(); VSLOG(mLogInfo, "Total Meshes: %d | Faces: %d", sc->mNumMeshes, totalTris); }