#include #include #include #include #include #include "Model.h" using namespace glml; Model::Model(const std::string path) { loadModel(path); } void Model::Draw(Shader& shader) const { for (int i = 0; i < meshes.size(); i++) meshes[i].Draw(shader); } void Model::loadModel(const std::string path) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { std::cerr << "[ASSIMP ERROR] Model '" << path << "' not loaded.\n" << importer.GetErrorString() << std::endl; return; } directory = path.substr(0, path.find_last_of('/')); processNode(scene->mRootNode, scene); } void Model::processNode(aiNode* node, const aiScene* scene) { unsigned int i; for (i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; meshes.push_back(processMesh(mesh, scene)); } for (i = 0; i < node->mNumChildren; i++) processNode(node->mChildren[i], scene); } Mesh Model::processMesh(aiMesh* mesh, const aiScene* scene) { std::vector vertices; std::vector indices; std::vector textures; unsigned int i; for (i = 0; i < mesh->mNumVertices; i++) { Vertex vertex; glm::vec3 v; v.x = mesh->mVertices[i].x; v.y = mesh->mVertices[i].y; v.z = mesh->mVertices[i].z; vertex.Position = v; if (mesh->mNormals != NULL) { v.x = mesh->mNormals[i].x; v.y = mesh->mNormals[i].y; v.z = mesh->mNormals[i].z; vertex.Normal = v; } if (mesh->mTangents != NULL) { v.x = mesh->mTangents[i].x; v.y = mesh->mTangents[i].y; v.z = mesh->mTangents[i].z; vertex.Tangent = v; } if (mesh->mBitangents != NULL) { v.x = mesh->mBitangents[i].x; v.y = mesh->mBitangents[i].y; v.z = mesh->mBitangents[i].z; vertex.Bitangent = v; } vertex.Color = glm::vec3(0.0f); if (mesh->mTextureCoords[0]) { // does the mesh contains texture coordinates? glm::vec2 vec; vec.x = mesh->mTextureCoords[0][i].x; vec.y = mesh->mTextureCoords[0][i].y; vertex.TexCoord = vec; } else { vertex.TexCoord = glm::vec2(0.0f); } vertices.push_back(vertex); } for (i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; for (unsigned int j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } if (mesh->mMaterialIndex >= 0) { aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex]; std::vector diffuseMaps = loadMaterialTextures(mat, aiTextureType_DIFFUSE, TextureType::diffuse); textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); std::vector specularMaps = loadMaterialTextures(mat, aiTextureType_SPECULAR, TextureType::specular); textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); std::vector normalMaps = loadMaterialTextures(mat, aiTextureType_NORMALS, TextureType::normal); textures.insert(textures.end(), normalMaps.begin(), normalMaps.end()); std::vector heightMaps = loadMaterialTextures(mat, aiTextureType_HEIGHT, TextureType::height); textures.insert(textures.end(), heightMaps.begin(), heightMaps.end()); } return Mesh(vertices, indices, textures); } std::vector Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, TextureType glmlType) { std::vector textures; for (unsigned int i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); bool loaded = false; for (int j = 0; j < textures_loaded.size(); j++) { if (std::strcmp(textures_loaded[j].path.data(), str.C_Str()) == 0) { textures.push_back(textures_loaded[j]); loaded = true; break; } } if (!loaded) { Texture texture; texture.id = load_texture(directory + '/' + str.C_Str()); texture.type = glmlType; texture.path = str.C_Str(); textures.push_back(texture); textures_loaded.push_back(texture); } } return textures; } static unsigned int glml::load_texture(const std::string path) { return glml::load_texture(path.c_str()); } static unsigned int glml::load_texture(const char* path) { unsigned int texture = 0; int width, height, nrChannels, format; unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 0); // load image to the array of bytes (char = 1 byte) switch (nrChannels) { case 4: format = GL_RGBA; break; case 3: format = GL_RGB; break; case 1: format = GL_RED; break; default: format = GL_RGB; break; } if (data) // data != NULL { glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, format, GL_UNSIGNED_BYTE, data); // generates texture glGenerateMipmap(GL_TEXTURE_2D); } else { std::cerr << "Could not load texture '" << path << "'\n"; } stbi_image_free(data); return texture; }