473 lines
13 KiB
C++
473 lines
13 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;
|
|
shininessStrength = 0;
|
|
|
|
vbo[VERTEX_BUFFER] = NULL;
|
|
vbo[NORMAL_BUFFER] = NULL;
|
|
vbo[TEXCOORD_BUFFER] = NULL;
|
|
vbo[COLOR_BUFFER] = NULL;
|
|
vbo[INDEX_BUFFER] = NULL;
|
|
vbo[TANGENTS_BUFFER] = NULL;
|
|
vbo[BITTANGENTS_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
|
|
if (set.tex_mapping.size() > 0)
|
|
{
|
|
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
|
|
if (set.colors.size() > 0)
|
|
{
|
|
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);
|
|
}
|
|
|
|
//Copy indexes to VBO
|
|
if (set.indexes.size() > 0)
|
|
{
|
|
renderType = OBJ;
|
|
|
|
glGenBuffers(1, &vbo[INDEX_BUFFER]);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[INDEX_BUFFER]);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, set.indexes.size() * sizeof(GLuint), set.indexes.data(), GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(INDEX_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glEnableVertexAttribArray(INDEX_BUFFER);
|
|
}
|
|
|
|
|
|
dset_size = set.vertices.size();
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(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;
|
|
vbo[TANGENTS_BUFFER] = NULL;
|
|
vbo[BITTANGENTS_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(VERTEX_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glEnableVertexAttribArray(VERTEX_BUFFER);
|
|
|
|
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(NORMAL_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glEnableVertexAttribArray(NORMAL_BUFFER);
|
|
|
|
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(TEXCOORD_BUFFER, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glEnableVertexAttribArray(TEXCOORD_BUFFER);
|
|
|
|
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(INDEX_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glEnableVertexAttribArray(INDEX_BUFFER);
|
|
|
|
delete[] indices;
|
|
}
|
|
|
|
if (mesh->HasTangentsAndBitangents()) {
|
|
float *tangents = new float[mesh->mNumVertices * 3];
|
|
float *bittangents = new float[mesh->mNumVertices * 3];
|
|
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
|
|
|
tangents[i * 3] = mesh->mTangents[i].x;
|
|
tangents[i * 3 + 1] = mesh->mTangents[i].y;
|
|
tangents[i * 3 + 2] = mesh->mTangents[i].z;
|
|
|
|
bittangents[i * 3] = mesh->mBitangents[i].x;
|
|
bittangents[i * 3 + 1] = mesh->mBitangents[i].y;
|
|
bittangents[i * 3 + 2] = mesh->mBitangents[i].z;
|
|
|
|
}
|
|
|
|
glGenBuffers(1, &vbo[TANGENTS_BUFFER]);
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo[TANGENTS_BUFFER]);
|
|
glBufferData(GL_ARRAY_BUFFER, 3 * mesh->mNumVertices * sizeof(GLfloat), tangents, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(TANGENTS_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glEnableVertexAttribArray(TANGENTS_BUFFER);
|
|
|
|
glGenBuffers(1, &vbo[BITTANGENTS_BUFFER]);
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo[BITTANGENTS_BUFFER]);
|
|
glBufferData(GL_ARRAY_BUFFER, 3 * mesh->mNumVertices * sizeof(GLfloat), bittangents, GL_STATIC_DRAW);
|
|
|
|
glVertexAttribPointer(BITTANGENTS_BUFFER, 3, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glEnableVertexAttribArray(BITTANGENTS_BUFFER);
|
|
|
|
|
|
delete[] tangents;
|
|
delete[] bittangents;
|
|
}
|
|
|
|
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);
|
|
|
|
if (material->GetTextureCount(aiTextureType_DIFFUSE) > 0) { //we only care diffuse texture
|
|
aiString Path;
|
|
if (material->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL,
|
|
NULL, NULL) == AI_SUCCESS) {
|
|
std::string FullPath = parent->directory + Path.data; //texture file
|
|
textures.push_back(parent->textures[FullPath]);
|
|
}
|
|
}
|
|
}
|
|
|
|
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]);
|
|
}
|
|
|
|
if (vbo[BITTANGENTS_BUFFER]) {
|
|
glDeleteBuffers(1, &vbo[BITTANGENTS_BUFFER]);
|
|
}
|
|
|
|
if (vbo[TANGENTS_BUFFER]) {
|
|
glDeleteBuffers(1, &vbo[TANGENTS_BUFFER]);
|
|
}
|
|
|
|
glDeleteVertexArrays(1, &vao);
|
|
}
|
|
|
|
/**
|
|
* Renders this MeshEntry
|
|
**/
|
|
void Mesh::MeshEntry::render(SceneContext &ctx, Shader &shd) {
|
|
|
|
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, std::string vert_shd, std::string frag_shd)
|
|
{
|
|
shader = std::make_shared<Shader>(vert_shd, frag_shd);
|
|
std::string fullname;
|
|
fullname = std::string("./Models/")+ std::string(filename);
|
|
directory = fullname;
|
|
directory.resize(fullname.find_last_of('/') + 1);
|
|
|
|
Assimp::Importer importer; //aiProcessPreset_TargetRealtime_Fast
|
|
const aiScene* scene = importer.ReadFile(fullname.c_str(),
|
|
aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_OptimizeMeshes
|
|
| aiProcess_CalcTangentSpace);
|
|
|
|
// 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;
|
|
throw new std::exception(("Error loading mesh at the following location : " + fullname).c_str());
|
|
}
|
|
|
|
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
|
|
meshEntries.push_back(new Mesh::MeshEntry(scene->mMeshes[i], scene, this));
|
|
|
|
for (unsigned int i = 0; i < scene->mNumMaterials; i++)
|
|
{
|
|
aiMaterial* material = scene->mMaterials[i];
|
|
if (material->GetTextureCount(aiTextureType_DIFFUSE) > 0)
|
|
{
|
|
aiString Path;
|
|
if (material->GetTexture(aiTextureType_DIFFUSE, 0, &Path, NULL, NULL, NULL,
|
|
NULL, NULL) == AI_SUCCESS)
|
|
{
|
|
std::string FullPath = directory + Path.data; //texture file
|
|
textures.emplace("0", Texture(FullPath));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Mesh::Mesh(Dataset &set, std::string vert_shd, std::string frag_shd)
|
|
{
|
|
shader = std::make_shared<Shader>(vert_shd, frag_shd);
|
|
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::draw(SceneContext &ctx) {
|
|
|
|
shader->enable();
|
|
for (unsigned int i = 0; i < meshEntries.size(); ++i) {
|
|
|
|
MeshEntry * m = meshEntries[i];
|
|
|
|
// Moving the object to his set position
|
|
|
|
model.glPushMatrix();
|
|
effectTransformations();
|
|
|
|
// Setting the space matrixes uniques to the object
|
|
ctx.modelMatrix = model.getMatrix();
|
|
ctx.mvpMatrix = ctx.projectionMatrix * ctx.viewMatrix * ctx.modelMatrix;
|
|
//ctx.modelViewMatrix = ctx.viewMatrix * ctx.modelMatrix;
|
|
ctx.normalMatrix = glm::transpose(glm::inverse(glm::mat3(ctx.modelMatrix)));
|
|
|
|
shader->addUniform("mvp", ctx.mvpMatrix);
|
|
shader->addUniform("NormalMatrix", ctx.normalMatrix);
|
|
shader->addUniform("ModelMatrix", ctx.modelMatrix);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, textures["0"].tex_ref);
|
|
|
|
meshEntries.at(i)->render(ctx, *shader);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
|
model.glPopMatrix();
|
|
}
|
|
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::addStartRotation(glm::vec4 vec)
|
|
{
|
|
model.glRotate(vec.w, vec.x, vec.y, vec.z);
|
|
}
|
|
|
|
void Mesh::addStartTranslation(glm::vec4 vec)
|
|
{
|
|
model.glTranslate(vec.x, vec.y, vec.z);
|
|
}
|
|
|
|
void Mesh::addStartScaling(glm::vec4 vec)
|
|
{
|
|
model.glScale(vec.x, vec.y, vec.z);
|
|
}
|
|
|
|
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;
|
|
} |