diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f9be77..b9858d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,8 +42,11 @@ include_directories( SYSTEM ${SDL2_INCLUDE_DIRS}) set(SRCS + "src/AssetManager.cpp" "src/Logger.cpp" "src/Main.cpp" + "src/Model.cpp" + "src/Shader.cpp" "src/System.cpp") # Define C++ compiler flags diff --git a/assets/shaders/fragment_shader.glsl b/assets/shaders/fragment_shader.glsl new file mode 100644 index 0000000..20f803f --- /dev/null +++ b/assets/shaders/fragment_shader.glsl @@ -0,0 +1,7 @@ +#version 330 core +in vec3 frag_col; +out vec3 col; + +void main() { + col = frag_col; +} diff --git a/assets/shaders/vertex_shader.glsl b/assets/shaders/vertex_shader.glsl new file mode 100644 index 0000000..744420a --- /dev/null +++ b/assets/shaders/vertex_shader.glsl @@ -0,0 +1,9 @@ +#version 330 core +layout(location = 0) in vec3 vert_pos; +uniform vec3 col; +/*uniform mat4 mvp;*/ +out vec3 frag_col; +void main() { + gl_Position = /*mvp * */vec4(vert_pos, 1); + frag_col = col; +} diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 5121868..57ab2f8 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -18,7 +18,132 @@ #include "AssetManager.hpp" -void AssetManager::loadOBJ(const std::string &path, +#include "System.hpp" + +#include +#include + +//#define TINYOBJLOADER_IMPLEMENTATION +//#include +#include +#include +#include +#include + +/*void AssetManager::loadOBJ(const std::string &path, const std::string &name) { + std::vector vertexIndices, + uvIndices, normalIndices; + std::vector temp_vertices; + std::vector temp_uvs; + std::vector temp_normals; + + FILE *file = fopen(path.c_str(), "r"); + if(not file) + { + System::logger->writeError("Failed to open file."); + return; + } + + while(true) + { + char lineHeader[128]; + int res = fscanf(file, "%s", lineHeader); + if(res == EOF) + break; + + if(strcmp(lineHeader, "v") == 0) + { + glm::vec3 vertex; + fscanf(file, "%f %f %f\n", + &vertex.x, &vertex.y, &vertex.z); + temp_vertices.push_back(vertex); + } + else if(strcmp(lineHeader, "vt") == 0) + { + glm::vec2 uv; + fscanf(file, "%f %f\n", &uv.x, &uv.y); + temp_uvs.push_back(uv); + } + else if(strcmp(lineHeader, "vn") == 0) + { + glm::vec3 normal; + fscanf(file, "%f %f %f\n", + &normal.x, &normal.y, &normal.z); + temp_normals.push_back(normal); + } + else if(strcmp(lineHeader, "f") == 0) + { + std::string v1, v2, v3; + unsigned int vIndex[3], uvIndex[3], normIndex[3]; + int matches = fscanf(file, + "%d/%d/%d %d/%d/%d %d/%d/%d\n", + &vIndex[0], &uvIndex[0], &normIndex[0], + &vIndex[1], &uvIndex[1], &normIndex[1], + &vIndex[2], &uvIndex[2], &normIndex[2]); + if(matches not_eq 9) + { + System::logger->writeError( + "OBJ file is too complicated."); + return; + } + + for(auto &i : vIndex) + vertexIndices.push_back(i); + for(auto &i : uvIndex) + uvIndices.push_back(i); + for(auto &i : normIndex) + normalIndices.push_back(i); + } + } +}*/ + +void AssetManager::loadModel(const std::string &path, + const std::string &name) +{ + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(path, + aiProcess_Triangulate); + if(not scene) + { + System::logger->writeError(importer.GetErrorString()); + return; + } + const aiMesh *mesh = scene->mMeshes[0]; + + std::vector vertices; + std::vector indices; + + vertices.reserve(mesh->mNumVertices); + for(unsigned int i = 0; i < mesh->mNumVertices; ++i) + { + aiVector3D pos = mesh->mVertices[i]; + aiVector3D norm = mesh->mNormals[i]; + + vertices.push_back({ + glm::vec3(pos.x, pos.y, pos.z), + glm::vec3(norm.x, norm.y, norm.z)}); + } + + indices.reserve(3 * mesh->mNumFaces); + for(unsigned int i = 0; i < mesh->mNumFaces; ++i) + { + for(unsigned int j = 0; j < 3; ++j) + indices.push_back(mesh->mFaces[i].mIndices[j]); + } + + models.insert({ name, + std::make_shared( + vertices, indices)}); +} + +std::shared_ptr AssetManager::getModel( + const std::string &name) +{ + return models.at(name); +} + +void AssetManager::unloadModel(const std::string &name) { + models.erase(name); } diff --git a/src/AssetManager.hpp b/src/AssetManager.hpp index f5f1c6b..1c80fde 100644 --- a/src/AssetManager.hpp +++ b/src/AssetManager.hpp @@ -18,17 +18,22 @@ #pragma once +#include "Model.hpp" +#include +#include #include class AssetManager { public: AssetManager(); - void loadOBJ(const std::string &path, + /*void loadOBJ(const std::string &path, + const std::string &name);*/ + void loadModel(const std::string &path, const std::string &name); - void loadSound(const std::string &path, - const std::string &name); - void unloadOBJ(const std::string &name); - void unloadSound(const std::string &name); + std::shared_ptr getModel(const std::string &name); + void unloadModel(const std::string &name); + //void unloadOBJ(const std::string &name); private: + std::map> models; }; diff --git a/src/Model.cpp b/src/Model.cpp new file mode 100644 index 0000000..b06a9a9 --- /dev/null +++ b/src/Model.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 Ortega Froysa, Nicolás + * Author: Ortega Froysa, Nicolás + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "Model.hpp" + +#include +#include + +Model::Model(const std::vector &vertices, + const std::vector &indices) : + vertices(vertices), indices(indices) +{ + glGenVertexArrays(1, &vao); + glGenBuffers(1, &vbo); + glGenBuffers(1, &ebo); + + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, + vertices.size() * sizeof(struct Vertex), + &vertices[0], GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + indices.size() * sizeof(unsigned int), + &indices[0], GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, + sizeof(struct Vertex), nullptr); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, + sizeof(struct Vertex), + (void*)offsetof(struct Vertex, normal)); + glBindVertexArray(0); +} + +void Model::draw(const Shader &shader) { + glUniform3f( + glGetUniformLocation(shader.getId(), "col"), + color.r, color.g, color.b); + glBindVertexArray(vao); + glDrawElements(GL_TRIANGLES, indices.size(), + GL_UNSIGNED_INT, 0); + glBindVertexArray(0); +} diff --git a/src/Model.hpp b/src/Model.hpp new file mode 100644 index 0000000..d7b340c --- /dev/null +++ b/src/Model.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 Ortega Froysa, Nicolás + * Author: Ortega Froysa, Nicolás + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "Shader.hpp" + +#include +#include + +struct Color { + float r; + float g; + float b; +}; + +struct Vertex { + glm::vec3 position; + glm::vec3 normal; +}; + +class Model { +public: + Model(const std::vector &vertices, + const std::vector &indices); + void draw(const Shader &shader); + + inline void setColor(float r, float g, float b) { + color = { r, g, b }; + } + +private: + struct Color color; + std::vector vertices; + std::vector indices; + unsigned int vao, vbo, ebo; +}; diff --git a/src/Shader.cpp b/src/Shader.cpp new file mode 100644 index 0000000..6edea68 --- /dev/null +++ b/src/Shader.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2018 Ortega Froysa, Nicolás + * Author: Ortega Froysa, Nicolás + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "Shader.hpp" +#include "System.hpp" + +#include +#include + +Shader::Shader(const std::string &vShaderPath, + const std::string &fShaderPath) +{ + // Load the code from the files. + std::string vShaderCode, fShaderCode; + std::ifstream vShaderFile, fShaderFile; + vShaderFile.exceptions(std::ifstream::failbit bitor + std::ifstream::badbit); + fShaderFile.exceptions(std::ifstream::failbit bitor + std::ifstream::badbit); + try + { + vShaderFile.open(vShaderPath); + fShaderFile.open(fShaderPath); + std::stringstream vShaderStream, fShaderStream; + vShaderStream << vShaderFile.rdbuf(); + fShaderStream << fShaderFile.rdbuf(); + vShaderFile.close(); + fShaderFile.close(); + vShaderCode = vShaderStream.str(); + fShaderCode = fShaderStream.str(); + } + catch(const std::exception &e) + { + System::logger->writeError( + std::string("Failed to read from file: ") + + e.what()); + } + + // Compile the shaders + unsigned int vertexId, fragmentId; + int res; + char infoLog[512]; + + vertexId = glCreateShader(GL_VERTEX_SHADER); + { + const char *vShaderCodeChar = vShaderCode.c_str(); + glShaderSource(vertexId, 1, + &vShaderCodeChar, nullptr); + } + glCompileShader(vertexId); + glGetShaderiv(vertexId, GL_COMPILE_STATUS, &res); + if(not res) + { + glGetShaderInfoLog(vertexId, 512, nullptr, infoLog); + System::logger->writeError( + std::string( + "Vertex shader compilation failed: ") + + infoLog); + } + fragmentId = glCreateShader(GL_FRAGMENT_SHADER); + { + const char *fShaderCodeChar = fShaderCode.c_str(); + glShaderSource(fragmentId, 1, + &fShaderCodeChar, nullptr); + } + glCompileShader(fragmentId); + glGetShaderiv(fragmentId, GL_COMPILE_STATUS, &res); + if(not res) + { + glGetShaderInfoLog(fragmentId, 512, nullptr, infoLog); + System::logger->writeError( + std::string( + "Fragment shader compilation failed: ") + + infoLog); + } + + // Link the program + id = glCreateProgram(); + glAttachShader(id, vertexId); + glAttachShader(id, fragmentId); + glLinkProgram(id); + + glGetProgramiv(id, GL_LINK_STATUS, &res); + if(not res) + { + glGetProgramInfoLog(id, 512, nullptr, infoLog); + System::logger->writeError( + std::string("Failed to link program: ") + + infoLog); + } + + // Delete the shaders + glDeleteShader(vertexId); + glDeleteShader(fragmentId); +} diff --git a/src/Shader.hpp b/src/Shader.hpp new file mode 100644 index 0000000..99b4aaa --- /dev/null +++ b/src/Shader.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 Ortega Froysa, Nicolás + * Author: Ortega Froysa, Nicolás + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include + +class Shader { +public: + Shader(const std::string &vShaderPath, + const std::string &fShaderPath); + + inline void use() { + glUseProgram(id); + } + inline void setBool(const std::string &name, + bool value) const + { + glUniform1i(glGetUniformLocation(id, name.c_str()), + static_cast(value)); + } + inline void setInt(const std::string &name, + bool value) const + { + glUniform1i(glGetUniformLocation(id, name.c_str()), + value); + } + inline void setFloat(const std::string &name, + bool value) const + { + glUniform1f(glGetUniformLocation(id, name.c_str()), + value); + } + inline unsigned int getId() const { + return id; + } + +private: + unsigned int id; +}; diff --git a/src/System.cpp b/src/System.cpp index a8a9b2e..cbd5855 100644 --- a/src/System.cpp +++ b/src/System.cpp @@ -48,8 +48,6 @@ System::System() : running(true) { exit(1); } - //SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); - glcontext = SDL_GL_CreateContext(window); SDL_GL_SetSwapInterval(0); @@ -61,104 +59,19 @@ System::System() : running(true) { exit(1); } - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - try { - loadShaders(); - } catch(std::exception &e) { - logger->writeError(e.what()); - exit(1); - } - matrixId = glGetUniformLocation(programId, "MVP"); -} - -void System::loadShaders() { - logger->writeDebug("Compiling shaders..."); - GLuint vshader_id = glCreateShader(GL_VERTEX_SHADER); - GLuint fshader_id = glCreateShader(GL_FRAGMENT_SHADER); - GLint res; - int info_log_length = 0; - - // Load/Compile vertex shader - glShaderSource(vshader_id, 1, &vertShader, - nullptr); - glCompileShader(vshader_id); - glGetShaderiv(vshader_id, GL_COMPILE_STATUS, &res); - glGetShaderiv(vshader_id, GL_INFO_LOG_LENGTH, - &info_log_length); - if(info_log_length > 0) - { - char *vshader_error = new char[info_log_length+1]; - glGetShaderInfoLog(vshader_id, info_log_length, - nullptr, vshader_error); - std::string error = - "Vector shader compilation failed: "; - error.append(vshader_error); - delete vshader_error; - - throw std::runtime_error(error); - } - - // Load/Compile fragment shader - glShaderSource(fshader_id, 1, &fragShader, nullptr); - glCompileShader(fshader_id); - glGetShaderiv(fshader_id, GL_COMPILE_STATUS, &res); - glGetShaderiv(fshader_id, GL_INFO_LOG_LENGTH, - &info_log_length); - if(info_log_length > 0) - { - char *fshader_error = new char[info_log_length+1]; - glGetShaderInfoLog(fshader_id, info_log_length, - nullptr, fshader_error); - std::string error = - "Fragment shader compilation failed: "; - error.append(fshader_error); - delete fshader_error; - - throw std::runtime_error(error); - } - - logger->writeDebug("Linking program..."); - - programId = glCreateProgram(); - glAttachShader(programId, vshader_id); - glAttachShader(programId, fshader_id); - glLinkProgram(programId); - - // check linkage - glGetProgramiv(programId, GL_LINK_STATUS, &res); - glGetProgramiv(programId, GL_INFO_LOG_LENGTH, - &info_log_length); - if(info_log_length > 0) - { - char *link_error = new char[info_log_length+1]; - glGetProgramInfoLog(programId, info_log_length, - nullptr, link_error); - std::string error = "Program linking failed: "; - error.append(link_error); - delete link_error; - - throw std::runtime_error(error); - } - - // detach - glDetachShader(programId, vshader_id); - glDetachShader(programId, fshader_id); - - glDeleteShader(vshader_id); - glDeleteShader(fshader_id); + shader = std::make_unique( + "../assets/shaders/vertex_shader.glsl", + "../assets/shaders/fragment_shader.glsl"); } System::~System() { logger->write("Shutting down systems."); - glDeleteProgram(programId); SDL_GL_DeleteContext(glcontext); SDL_DestroyWindow(window); SDL_Quit(); @@ -171,7 +84,7 @@ void System::run() { syncInputs(); glClear(GL_COLOR_BUFFER_BIT bitor GL_DEPTH_BUFFER_BIT); - glUseProgram(programId); + shader->use(); SDL_GL_SwapWindow(window); diff --git a/src/System.hpp b/src/System.hpp index 9890f08..b8cf672 100644 --- a/src/System.hpp +++ b/src/System.hpp @@ -19,6 +19,7 @@ #pragma once #include "Logger.hpp" +#include "Shader.hpp" #include #include @@ -34,28 +35,11 @@ public: static std::unique_ptr logger; private: - void loadShaders(); void syncInputs(); - const GLchar *vertShader = - "#version 330 core\n" - "layout(location = 0) in vec3 vert_pos;\n" - "layout(location = 1) in vec3 vert_col;\n" - "uniform mat4 MVP;\n" - "out vec3 frag_col;\n" - "void main() {\n" - "gl_Position = MVP * vec4(vert_pos, 1);\n" - "frag_col = vert_col;}\n"; - const GLchar *fragShader = - "#version 330 core\n" - "in vec3 frag_col;\n" - "out vec3 color;\n" - "void main() { color = frag_col; }\n"; - GLuint programId; - GLuint matrixId; SDL_Window *window; SDL_GLContext glcontext; - GLuint vao; + std::unique_ptr shader; bool running; };