187 lines
5.1 KiB
C++
187 lines
5.1 KiB
C++
#include <glad/glad.h>
|
|
#include <assimp/Importer.hpp>
|
|
#include <assimp/postprocess.h>
|
|
#include <iostream>
|
|
#include <stb_image.h>
|
|
#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<Vertex> vertices;
|
|
std::vector<unsigned int> indices;
|
|
std::vector<Texture> 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<Texture> diffuseMaps = loadMaterialTextures(mat, aiTextureType_DIFFUSE, TextureType::diffuse);
|
|
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
|
|
|
|
std::vector<Texture> specularMaps = loadMaterialTextures(mat, aiTextureType_SPECULAR, TextureType::specular);
|
|
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
|
|
|
|
std::vector<Texture> normalMaps = loadMaterialTextures(mat, aiTextureType_NORMALS, TextureType::normal);
|
|
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
|
|
|
|
std::vector<Texture> heightMaps = loadMaterialTextures(mat, aiTextureType_HEIGHT, TextureType::height);
|
|
textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());
|
|
}
|
|
return Mesh(vertices, indices, textures);
|
|
}
|
|
std::vector<Texture> Model::loadMaterialTextures(aiMaterial* mat, aiTextureType type, TextureType glmlType)
|
|
{
|
|
std::vector<Texture> 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;
|
|
} |