2019-03-18 15:20:28 +09:00

408 lines
10 KiB
C++

#define GLM_ENABLE_EXPERIMENTAL
#include <vector>
#include <iostream>
#include "Mesh.h"
#include <glm/vec3.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <SOIL/SOIL.h>
/**
* Constructor, loading the specified aiMesh
**/
Mesh::MeshEntry::MeshEntry(Dataset &set, Mesh *m)
{
renderType = NO_INDEX;
parent = m;
vbo[VERTEX_BUFFER] = NULL;
vbo[NORMAL_BUFFER] = NULL;
vbo[TEXCOORD_BUFFER] = NULL;
vbo[COLOR_BUFFER] = NULL;
vbo[INDEX_BUFFER] = NULL;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//Copy Mesh vertices to VBO
glGenBuffers(1, &vbo[VERTEX_BUFFER]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[VERTEX_BUFFER]);
glBufferData(GL_ARRAY_BUFFER, set.vertices.size() * 3 * sizeof(GLfloat), set.vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(VERTEX_BUFFER, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, NULL);
glEnableVertexAttribArray(VERTEX_BUFFER);
//Copy Normals to VBO
glGenBuffers(1, &vbo[NORMAL_BUFFER]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[NORMAL_BUFFER]);
glBufferData(GL_ARRAY_BUFFER, set.normals.size() * 3 * sizeof(GLfloat), set.normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(NORMAL_BUFFER, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, NULL);
glEnableVertexAttribArray(NORMAL_BUFFER);
//Copy texture mapping to VBO
glGenBuffers(1, &vbo[TEXCOORD_BUFFER]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[TEXCOORD_BUFFER]);
glBufferData(GL_ARRAY_BUFFER, 2 * set.tex_mapping.size() * sizeof(GLfloat), set.tex_mapping.data(), GL_STATIC_DRAW);
glVertexAttribPointer(TEXCOORD_BUFFER, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, NULL);
glEnableVertexAttribArray(TEXCOORD_BUFFER);
//Copy vertice color to VBO
glGenBuffers(1, &vbo[COLOR_BUFFER]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[COLOR_BUFFER]);
glBufferData(GL_ARRAY_BUFFER, set.colors.size() * 3 * sizeof(GLfloat), set.colors.data(), GL_STATIC_DRAW);
glVertexAttribPointer(COLOR_BUFFER, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, NULL);
glEnableVertexAttribArray(COLOR_BUFFER);
dset_size = set.vertices.size();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
shininessStrength = 0;
}
Mesh::MeshEntry::MeshEntry(aiMesh *mesh, const aiScene* scene, Mesh * m)
{
renderType = OBJ;
parent = m;
vbo[VERTEX_BUFFER] = NULL;
vbo[TEXCOORD_BUFFER] = NULL;
vbo[NORMAL_BUFFER] = NULL;
vbo[COLOR_BUFFER] = NULL;
vbo[INDEX_BUFFER] = NULL;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
elementCount = mesh->mNumFaces * 3;
if (mesh->HasPositions()) {
float *vertices = new float[mesh->mNumVertices * 3];
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
vertices[i * 3] = mesh->mVertices[i].x;
vertices[i * 3 + 1] = mesh->mVertices[i].y;
vertices[i * 3 + 2] = mesh->mVertices[i].z;
}
glGenBuffers(1, &vbo[VERTEX_BUFFER]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[VERTEX_BUFFER]);
glBufferData(GL_ARRAY_BUFFER, 3 * mesh->mNumVertices * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
delete[] vertices;
}
if (mesh->HasNormals()) {
float *normals = new float[mesh->mNumVertices * 3];
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
normals[i * 3] = mesh->mNormals[i].x;
normals[i * 3 + 1] = mesh->mNormals[i].y;
normals[i * 3 + 2] = mesh->mNormals[i].z;
}
glGenBuffers(1, &vbo[NORMAL_BUFFER]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[NORMAL_BUFFER]);
glBufferData(GL_ARRAY_BUFFER, 3 * mesh->mNumVertices * sizeof(GLfloat), normals, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(1);
delete[] normals;
}
if (mesh->HasTextureCoords(0)) {
float *texCoords = new float[mesh->mNumVertices * 2];
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
texCoords[i * 2] = mesh->mTextureCoords[0][i].x;
texCoords[i * 2 + 1] = mesh->mTextureCoords[0][i].y;
}
glGenBuffers(1, &vbo[TEXCOORD_BUFFER]);
glBindBuffer(GL_ARRAY_BUFFER, vbo[TEXCOORD_BUFFER]);
glBufferData(GL_ARRAY_BUFFER, 2 * mesh->mNumVertices * sizeof(GLfloat), texCoords, GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(2);
delete[] texCoords;
}
if (mesh->HasFaces()) {
unsigned int *indices = new unsigned int[mesh->mNumFaces * 3];
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
indices[i * 3] = mesh->mFaces[i].mIndices[0];
indices[i * 3 + 1] = mesh->mFaces[i].mIndices[1];
indices[i * 3 + 2] = mesh->mFaces[i].mIndices[2];
}
glGenBuffers(1, &vbo[INDEX_BUFFER]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[INDEX_BUFFER]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * mesh->mNumFaces * sizeof(GLuint), indices, GL_STATIC_DRAW);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(3);
delete[] indices;
}
if (mesh->mMaterialIndex >= 0) {
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
material->Get(AI_MATKEY_SHININESS, shininessStrength);
material->Get(AI_MATKEY_COLOR_DIFFUSE, dcolor);
material->Get(AI_MATKEY_COLOR_AMBIENT, acolor);
material->Get(AI_MATKEY_COLOR_SPECULAR, scolor);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
/**
* Deletes the allocated OpenGL buffers
**/
Mesh::MeshEntry::~MeshEntry() {
if (vbo[VERTEX_BUFFER]) {
glDeleteBuffers(1, &vbo[VERTEX_BUFFER]);
}
if (vbo[TEXCOORD_BUFFER]) {
glDeleteBuffers(1, &vbo[TEXCOORD_BUFFER]);
}
if (vbo[NORMAL_BUFFER]) {
glDeleteBuffers(1, &vbo[NORMAL_BUFFER]);
}
if (vbo[INDEX_BUFFER]) {
glDeleteBuffers(1, &vbo[INDEX_BUFFER]);
}
if (vbo[COLOR_BUFFER]) {
glDeleteBuffers(1, &vbo[COLOR_BUFFER]);
}
glDeleteVertexArrays(1, &vao);
}
/**
* Renders this MeshEntry
**/
void Mesh::MeshEntry::render() {
glBindVertexArray(vao);
if (renderType == NO_INDEX)
{
glDrawArrays(GL_TRIANGLES, 0, dset_size);
}
else
{
int size;
glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size / sizeof(unsigned int), GL_UNSIGNED_INT, NULL);
}
glBindVertexArray(0);
}
/**
* Mesh constructor, loads the specified filename if supported by Assimp
**/
Mesh::Mesh(const char *filename, Shader *sh)
{
shader = sh;
std::string fullname;
fullname = std::string("./Models/")+ std::string(filename);
Assimp::Importer importer; //aiProcessPreset_TargetRealtime_Fast
const aiScene* scene = importer.ReadFile(fullname.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_OptimizeMeshes);
// Check for errors
if (!scene || scene->mFlags == AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero
{
std::cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << std::endl;
return;
}
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
meshEntries.push_back(new Mesh::MeshEntry(scene->mMeshes[i], scene, this));
}
}
Mesh::Mesh(Dataset &set, Shader *sh)
{
shader = sh;
meshEntries.push_back(new Mesh::MeshEntry(set, this));
}
/**
* Clears all loaded MeshEntries
**/
Mesh::~Mesh(void)
{
for (unsigned int i = 0; i < meshEntries.size(); ++i) {
delete meshEntries.at(i);
}
meshEntries.clear();
}
void Mesh::enableCulling()
{
if (cullMode == NONE)
return;
glEnable(GL_CULL_FACE);
glCullFace(cullMode);
}
void Mesh::disableCulling()
{
if (cullMode == NONE)
return;
glDisable(GL_CULL_FACE);
}
void Mesh::draw(SceneContext ctx) {
shader->enable();
enableCulling();
for (unsigned int i = 0; i < meshEntries.size(); ++i) {
MeshEntry * m = meshEntries[i];
// Moving the object to his set position
model.glPushMatrix();
effectTransformations();
//Retrieving material data from the vertex
float shininess = meshEntries.at(i)->shininessStrength;
glm::vec3 diffuse = glm::vec3(meshEntries.at(i)->dcolor.r, meshEntries.at(i)->dcolor.g, meshEntries.at(i)->dcolor.b);
glm::vec3 specular = glm::vec3(meshEntries.at(i)->scolor.r, meshEntries.at(i)->scolor.g, meshEntries.at(i)->scolor.b);
glm::vec3 ambient = glm::vec3(meshEntries.at(i)->acolor.r, meshEntries.at(i)->acolor.g, meshEntries.at(i)->acolor.b);
if (glm::length(ambient) == 0) {
ambient = glm::vec3(0.1, 0.1, 0.1);
}
if (glm::length(diffuse) == 0) {
diffuse = glm::vec3(0.9, 0.9, 0.9);
}
if (glm::length(specular) == 0) {
specular = glm::vec3(0.4, 0.4, 0.4);
}
if (shininess == 0)
shininess = 150.0f;
shader->mat.ka = ambient;
shader->mat.kd = diffuse;
shader->mat.ks = specular;
shader->mat.shininess = shininess;
// Setting the space matrixes uniques to the object
ctx.mvpMatrix = ctx.projectionMatrix * ctx.viewMatrix * model.getMatrix();
ctx.modelViewMatrix = ctx.viewMatrix * model.getMatrix();
ctx.normalMatrix = glm::mat3(glm::transpose(glm::inverse(ctx.modelViewMatrix)));
//Sending the uniform data to the shader
shader->setUniforms(ctx);
meshEntries.at(i)->render();
model.glPopMatrix();
}
disableCulling();
shader->disable();
}
void Mesh::effectTransformations()
{
for (auto pair : _transformations)
{
switch (pair.second)
{
case(Rotation):
model.glRotate(pair.first.w, pair.first.x, pair.first.y, pair.first.z);
break;
case(Translation):
model.glTranslate(pair.first.x, pair.first.y, pair.first.z);
break;
case(Scaling):
model.glScale(pair.first.x, pair.first.y, pair.first.z);
break;
}
}
}
void Mesh::addRotation(glm::vec4 vec)
{
_transformations.emplace_back(vec, Rotation);
}
void Mesh::addTranslation(glm::vec4 vec)
{
_transformations.emplace_back(vec, Translation);
}
void Mesh::addScaling(glm::vec4 vec)
{
_transformations.emplace_back(vec, Scaling);
}
glm::vec4 Mesh::translateToPivot(glm::vec3 pivot)
{
glm::vec4 curr_pos = { 0, 0, 0, 0 };
glm::vec4 h_pivot = { pivot.x, pivot.y, pivot.z, 0 };
for (auto pair : _transformations)
{
if (pair.second == Translation)
curr_pos += pair.first;
}
addTranslation(h_pivot - curr_pos);
return curr_pos - h_pivot;
}
void Mesh::removeLastTransformations(int n = 1)
{
for (int i = 0; i < n; i++)
_transformations.pop_back();
}
glm::vec3 Mesh::getPosition()
{
glm::vec4 curr_pos = { 0, 0, 0, 0 };
for (auto pair : _transformations)
{
if (pair.second == Translation)
curr_pos += pair.first;
}
return curr_pos;
}