Skip to content

Commit

Permalink
Model loading helper lib with Assimp
Browse files Browse the repository at this point in the history
  • Loading branch information
SeriousSamV committed Feb 24, 2017
1 parent 29bf06d commit 97d5e82
Show file tree
Hide file tree
Showing 2 changed files with 330 additions and 0 deletions.
151 changes: 151 additions & 0 deletions lib/mesh.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#ifndef __MYLIB_MESH_HPP__
#define __MYLIB_MESH_HPP__

#ifdef _DEBUG
#undef _NDEBUG
#undef NDEBUG
#else
#define _NDEBUG
#define NDEBUG
#endif

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

#include <epoxy/gl.h>
#ifdef _WIN32
#include <epoxy/wgl.h>
#else
#include <epoxy/glx.h>
#endif

#include <glm/glm.hpp>

#include "mylib.hpp"

namespace mylib
{

struct Vertex
{
glm::vec3 position;
glm::vec3 normal;
glm::vec2 texCoords;
};

struct Texture
{
GLuint id;
std::string type;
aiString path;
};

class Mesh
{
public:
//! mesh data
std::vector<Vertex> vertices;
std::vector<GLuint> indices;
std::vector<Texture> textures;

Mesh(
std::vector<Vertex> vertices,
std::vector<GLuint> indices,
std::vector<Texture> textures) :
vertices(vertices),
indices(indices),
textures(textures)
{
this->setupMesh();
}

//! draw() renders the mesh onto app window
///
/// assumes sampler2D naming conventions as follows:
/// diffuse textures: texture_diffuseN
/// speculat textures: texture_specularN
/// where N: [0, MAX_TEXTURE_UNITS]
///
void draw(mylib::Shader& shader)
{
GLuint diffuseNr{ 1 }, specularNr{ 1 };
for (GLuint i = 0; i < textures.size(); ++i) {
glActiveTexture(GL_TEXTURE0 + i); // activate *_textureN
std::string number; // *_texture<"N">
std::string name = textures[i].type; // <"*_texture">N
if (name == "texture_diffuse") {
number = std::to_string(diffuseNr++);
}
else if (name == "texture_specular") {
number = std::to_string(specularNr++);
}

glUniform1f(
glGetUniformLocation(
shader.program,
// material.<"*_textureN">
("material." + name + number).c_str()),
i);
#ifdef _DEBUG
//std::clog << "texture: " << ("material." + name + number).c_str()
//<< std::endl;
#endif // _DEBUG

glBindTexture(GL_TEXTURE_2D, textures[i].id);
}
glActiveTexture(GL_TEXTURE0);

// draw
shader.use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES,
indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}

private:
//! render data
GLuint VAO{ 0 }, VBO{ 0 }, EBO{ 0 };

void setupMesh()
{
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);

glBindVertexArray(VAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER,
vertices.size() * sizeof(*(vertices.data())),
vertices.data(),
GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(*(indices.data())),
indices.data(),
GL_STATIC_DRAW);

// Vertex positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3,
GL_FLOAT, GL_FALSE, sizeof(Vertex), ML_BUFFER_OFFSET(0));
// Vertex normals
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3,
GL_FLOAT, GL_FALSE, sizeof(Vertex),
ML_BUFFER_OFFSET(offsetof(Vertex, normal)));
// Vertex texture coordinates
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2,
GL_FLOAT, GL_FALSE, sizeof(Vertex),
ML_BUFFER_OFFSET(offsetof(Vertex, texCoords)));
glBindVertexArray(0);
}
};

}; // namespace mylib

#endif
179 changes: 179 additions & 0 deletions lib/model.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#ifndef __MYLIB_MODEL_HPP__
#define __MYLIB_MODEL_HPP__

#include "c:\Users\samuel vishesh paul\documents\visual studio 2015\Projects\OpenGL Playground\OpenGL Playground\stdafx.h"

namespace mylib
{
static GLint TextureFromFile(const char* path, std::string directory)
{
std::string filename = std::string(path);
filename = directory + '/' + filename;
GLuint textureID;
glGenTextures(1, &textureID);
int width, height;
unsigned char* image = SOIL_load_image(filename.c_str(),
&width, &height, 0, SOIL_LOAD_RGB);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
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);
glBindTexture(GL_TEXTURE_2D, 0);
SOIL_free_image_data(image);

return textureID;
}

class Model
{
public:

Model() {}
Model(const GLchar* path)
{
loadModel(path);
}

void draw(Shader shader)
{
for (GLuint i = 0; i < meshes.size(); ++i) {
meshes[i].draw(shader);
}
}

private:
//! model data
std::vector<Mesh> meshes;
std::string directory;
std::vector<Texture> textures_loaded;

void loadModel(std::string path)
{
Assimp::Importer import;
const aiScene* scene = import.ReadFile(path,
aiProcess_Triangulate | aiProcess_FlipUVs);

if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
std::cerr << "ERROR: ASSIMP: " << __PRETTY_FUNCTION__
<< "\n" << import.GetErrorString() << std::endl;
throw std::runtime_error(
std::string("ERROR::ASSIMP::") + import.GetErrorString());
}
directory = path.substr(0, path.find_last_of('/'));
processNode(scene->mRootNode, scene);
}

void processNode(aiNode* node, const aiScene* scene)
{
// for all the node's meshes (if any)
for (GLuint j = 0; j < node->mNumMeshes; ++j) {
aiMesh* mesh = scene->mMeshes[node->mMeshes[j]];
this->meshes.push_back(processMesh(mesh, scene));
}
// for all it's children
for (GLuint i = 0; i < node->mNumChildren; ++i) {
processNode(node->mChildren[i], scene);
}
}

Mesh processMesh(aiMesh* mesh, const aiScene* scene)
{
std::vector<Vertex> vertices;
std::vector<GLuint> indices;
std::vector<Texture> textures;

// process and extract Vertices, Normals and texture Coords
for (GLuint i = 0; i < mesh->mNumVertices; i++) {
Vertex vertex;

glm::vec3 vector;
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.position = vector;

if (mesh->HasNormals()) {
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.normal = vector;
}

if (mesh->mTextureCoords[0]) {
glm::vec2 coords;
coords.x = mesh->mTextureCoords[0][i].x;
coords.y = mesh->mTextureCoords[0][i].y;
vertex.texCoords = coords;
}
else {
vertex.texCoords = glm::vec2(0.0f, 0.0f);
}

vertices.push_back(vertex);
}
// process and extract indices
for (GLuint i = 0; i < mesh->mNumFaces; i++) {
aiFace face = mesh->mFaces[i];
for (GLuint j = 0; j < face.mNumIndices; j++) {
indices.push_back(face.mIndices[j]);
}
}

// process and extract materials
if (mesh->mMaterialIndex >= 0) {
// We assume a convention for sampler names in the shaders. Each diffuse texture should be named
// as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER.
// Same applies to other texture as the following list summarizes:
// Diffuse: texture_diffuseN
// Specular: texture_specularN
// Normal: texture_normalN
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];

std::vector<Texture> diffuseMaps = this->loadMaterialTextures(
material, aiTextureType_DIFFUSE, "texture_diffuse");
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());

std::vector<Texture> specularMaps = this->loadMaterialTextures(
material, aiTextureType_SPECULAR, "texture_specular");
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
}

return Mesh(vertices, indices, textures);
}

std::vector<Texture> loadMaterialTextures(aiMaterial* mat,
aiTextureType type, std::string typeName)
{
std::vector<Texture> textures;
for (GLuint i = 0; i < mat->GetTextureCount(type); ++i) {
aiString str;
mat->GetTexture(type, i, &str);
bool skip = false;
for (GLuint j = 0; j < textures_loaded.size(); ++j) {
if (std::strcmp(textures_loaded[j].path.C_Str(), str.C_Str()) == 0) {
textures.push_back(textures_loaded[j]);
skip = true;
break;
}
}
if (!skip) {
Texture texture;
texture.id = TextureFromFile(str.C_Str(), this->directory);
texture.type = typeName;
texture.path = str;
textures.push_back(texture);
this->textures_loaded.push_back(texture);
}
}

return textures;
}
};

}

#endif

0 comments on commit 97d5e82

Please sign in to comment.