From 127839585161197fd1469c577a6d697b9443c0da Mon Sep 17 00:00:00 2001 From: Lukian Date: Tue, 4 Feb 2025 11:39:09 +0100 Subject: [PATCH] added a model class --- .gitmodules | 3 + CMakeLists.txt | 3 +- include/myEngine/mesh.hpp | 146 +++++++++++ include/myEngine/model.hpp | 246 ++++++++++++++++++ include/myEngine/texture.hpp | 51 ---- lib/assimp | 1 + resources/shaders/shader.fs | 11 + {shaders => resources/shaders}/shader.vs | 9 +- .../textures}/oh_my_gah.png | Bin .../textures}/saataa_andagii.png | Bin shaders/shader.fs | 11 - src/main.cpp | 143 +++------- 12 files changed, 444 insertions(+), 180 deletions(-) create mode 100644 include/myEngine/mesh.hpp create mode 100644 include/myEngine/model.hpp delete mode 100644 include/myEngine/texture.hpp create mode 160000 lib/assimp create mode 100644 resources/shaders/shader.fs rename {shaders => resources/shaders}/shader.vs (59%) rename {textures => resources/textures}/oh_my_gah.png (100%) rename {textures => resources/textures}/saataa_andagii.png (100%) delete mode 100644 shaders/shader.fs diff --git a/.gitmodules b/.gitmodules index 879dbe7..67647c8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "lib/glm"] path = lib/glm url = https://github.com/g-truc/glm +[submodule "lib/assimp"] + path = lib/assimp + url = https://github.com/assimp/assimp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c970c6..414bdb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,9 @@ file(GLOB_RECURSE MY_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/ add_subdirectory("lib/glfw") add_subdirectory("lib/glm") +add_subdirectory("lib/assimp") project("game_engine") add_executable("game_engine" "src/main.cpp" "${MY_SOURCES}") target_include_directories("game_engine" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries("game_engine" "glfw" "glm") +target_link_libraries("game_engine" "glfw" "glm" "assimp") diff --git a/include/myEngine/mesh.hpp b/include/myEngine/mesh.hpp new file mode 100644 index 0000000..7a847e3 --- /dev/null +++ b/include/myEngine/mesh.hpp @@ -0,0 +1,146 @@ +#ifndef MESH_H +#define MESH_H + +#include // holds all OpenGL type declarations + +#include +#include + +#include + +#include +#include +using namespace std; + +#define MAX_BONE_INFLUENCE 4 + +struct Vertex { + // position + glm::vec3 Position; + // normal + glm::vec3 Normal; + // texCoords + glm::vec2 TexCoords; + // tangent + glm::vec3 Tangent; + // bitangent + glm::vec3 Bitangent; + //bone indexes which will influence this vertex + int m_BoneIDs[MAX_BONE_INFLUENCE]; + //weights from each bone + float m_Weights[MAX_BONE_INFLUENCE]; +}; + +struct Texture { + unsigned int id; + string type; + string path; +}; + +class Mesh { +public: + // mesh Data + vector vertices; + vector indices; + vector textures; + unsigned int VAO; + + // constructor + Mesh(vector vertices, vector indices, vector textures) + { + this->vertices = vertices; + this->indices = indices; + this->textures = textures; + + // now that we have all the required data, set the vertex buffers and its attribute pointers. + setupMesh(); + } + + // render the mesh + void Draw(Shader &shader) + { + // bind appropriate textures + unsigned int diffuseNr = 1; + unsigned int specularNr = 1; + unsigned int normalNr = 1; + unsigned int heightNr = 1; + for(unsigned int i = 0; i < textures.size(); i++) + { + glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding + // retrieve texture number (the N in diffuse_textureN) + string number; + string name = textures[i].type; + if(name == "texture_diffuse") + number = std::to_string(diffuseNr++); + else if(name == "texture_specular") + number = std::to_string(specularNr++); // transfer unsigned int to string + else if(name == "texture_normal") + number = std::to_string(normalNr++); // transfer unsigned int to string + else if(name == "texture_height") + number = std::to_string(heightNr++); // transfer unsigned int to string + + // now set the sampler to the correct texture unit + glUniform1i(glGetUniformLocation(shader.ID, (name + number).c_str()), i); + // and finally bind the texture + glBindTexture(GL_TEXTURE_2D, textures[i].id); + } + + // draw mesh + glBindVertexArray(VAO); + glDrawElements(GL_TRIANGLES, static_cast(indices.size()), GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + + // always good practice to set everything back to defaults once configured. + glActiveTexture(GL_TEXTURE0); + } + +private: + // render data + unsigned int VBO, EBO; + + // initializes all the buffer objects/arrays + void setupMesh() + { + // create buffers/arrays + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); + + glBindVertexArray(VAO); + // load data into vertex buffers + glBindBuffer(GL_ARRAY_BUFFER, VBO); + // A great thing about structs is that their memory layout is sequential for all its items. + // The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which + // again translates to 3/2 floats which translates to a byte array. + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(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); + + // set the vertex attribute pointers + // vertex Positions + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); + // vertex normals + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal)); + // vertex texture coords + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords)); + // vertex tangent + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent)); + // vertex bitangent + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent)); + // ids + glEnableVertexAttribArray(5); + glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (void*)offsetof(Vertex, m_BoneIDs)); + + // weights + glEnableVertexAttribArray(6); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, m_Weights)); + glBindVertexArray(0); + } +}; +#endif diff --git a/include/myEngine/model.hpp b/include/myEngine/model.hpp new file mode 100644 index 0000000..105e1ec --- /dev/null +++ b/include/myEngine/model.hpp @@ -0,0 +1,246 @@ +#ifndef MODEL_H +#define MODEL_H + +#include + +#include +#include +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +using namespace std; + +unsigned int TextureFromFile(const char *path, const string &directory, bool gamma = false); + +class Model +{ +public: + // model data + vector textures_loaded; // stores all the textures loaded so far, optimization to make sure textures aren't loaded more than once. + vector meshes; + string directory; + bool gammaCorrection; + + // constructor, expects a filepath to a 3D model. + Model(string const &path, bool gamma = false) : gammaCorrection(gamma) + { + loadModel(path); + } + + // draws the model, and thus all its meshes + void Draw(Shader &shader) + { + for(unsigned int i = 0; i < meshes.size(); i++) + meshes[i].Draw(shader); + } + +private: + // loads a model with supported ASSIMP extensions from file and stores the resulting meshes in the meshes vector. + void loadModel(string const &path) + { + // read file via ASSIMP + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace); + // check for errors + if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // if is Not Zero + { + cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl; + return; + } + // retrieve the directory path of the filepath + directory = path.substr(0, path.find_last_of('/')); + + // process ASSIMP's root node recursively + processNode(scene->mRootNode, scene); + } + + // processes a node in a recursive fashion. Processes each individual mesh located at the node and repeats this process on its children nodes (if any). + void processNode(aiNode *node, const aiScene *scene) + { + // process each mesh located at the current node + for(unsigned int i = 0; i < node->mNumMeshes; i++) + { + // the node object only contains indices to index the actual objects in the scene. + // the scene contains all the data, node is just to keep stuff organized (like relations between nodes). + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + meshes.push_back(processMesh(mesh, scene)); + } + // after we've processed all of the meshes (if any) we then recursively process each of the children nodes + for(unsigned int i = 0; i < node->mNumChildren; i++) + { + processNode(node->mChildren[i], scene); + } + + } + + Mesh processMesh(aiMesh *mesh, const aiScene *scene) + { + // data to fill + vector vertices; + vector indices; + vector textures; + + // walk through each of the mesh's vertices + for(unsigned int i = 0; i < mesh->mNumVertices; i++) + { + Vertex vertex; + glm::vec3 vector; // we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first. + // positions + vector.x = mesh->mVertices[i].x; + vector.y = mesh->mVertices[i].y; + vector.z = mesh->mVertices[i].z; + vertex.Position = vector; + // normals + if (mesh->HasNormals()) + { + vector.x = mesh->mNormals[i].x; + vector.y = mesh->mNormals[i].y; + vector.z = mesh->mNormals[i].z; + vertex.Normal = vector; + } + // texture coordinates + if(mesh->mTextureCoords[0]) // does the mesh contain texture coordinates? + { + glm::vec2 vec; + // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't + // use models where a vertex can have multiple texture coordinates so we always take the first set (0). + vec.x = mesh->mTextureCoords[0][i].x; + vec.y = mesh->mTextureCoords[0][i].y; + vertex.TexCoords = vec; + // tangent + vector.x = mesh->mTangents[i].x; + vector.y = mesh->mTangents[i].y; + vector.z = mesh->mTangents[i].z; + vertex.Tangent = vector; + // bitangent + vector.x = mesh->mBitangents[i].x; + vector.y = mesh->mBitangents[i].y; + vector.z = mesh->mBitangents[i].z; + vertex.Bitangent = vector; + } + else + vertex.TexCoords = glm::vec2(0.0f, 0.0f); + + vertices.push_back(vertex); + } + // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices. + for(unsigned int i = 0; i < mesh->mNumFaces; i++) + { + aiFace face = mesh->mFaces[i]; + // retrieve all indices of the face and store them in the indices vector + for(unsigned int j = 0; j < face.mNumIndices; j++) + indices.push_back(face.mIndices[j]); + } + // process materials + aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; + // 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 + + // 1. diffuse maps + vector diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse"); + textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); + // 2. specular maps + vector specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular"); + textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); + // 3. normal maps + std::vector normalMaps = loadMaterialTextures(material, aiTextureType_HEIGHT, "texture_normal"); + textures.insert(textures.end(), normalMaps.begin(), normalMaps.end()); + // 4. height maps + std::vector heightMaps = loadMaterialTextures(material, aiTextureType_AMBIENT, "texture_height"); + textures.insert(textures.end(), heightMaps.begin(), heightMaps.end()); + + // return a mesh object created from the extracted mesh data + return Mesh(vertices, indices, textures); + } + + // checks all material textures of a given type and loads the textures if they're not loaded yet. + // the required info is returned as a Texture struct. + vector loadMaterialTextures(aiMaterial *mat, aiTextureType type, string typeName) + { + vector textures; + for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) + { + aiString str; + mat->GetTexture(type, i, &str); + // check if texture was loaded before and if so, continue to next iteration: skip loading a new texture + bool skip = false; + for(unsigned 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]); + skip = true; // a texture with the same filepath has already been loaded, continue to next one. (optimization) + break; + } + } + if(!skip) + { // if texture hasn't been loaded already, load it + Texture texture; + texture.id = TextureFromFile(str.C_Str(), this->directory); + texture.type = typeName; + texture.path = str.C_Str(); + textures.push_back(texture); + textures_loaded.push_back(texture); // store it as texture loaded for entire model, to ensure we won't unnecessary load duplicate textures. + } + } + return textures; + } +}; + + +unsigned int TextureFromFile(const char *path, const string &directory, bool gamma) +{ + string filename = string(path); + filename = directory + '/' + filename; + + unsigned int textureID; + glGenTextures(1, &textureID); + + int width, height, nrComponents; + unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0); + if (data) + { + GLenum format; + if (nrComponents == 1) + format = GL_RED; + else if (nrComponents == 3) + format = GL_RGB; + else if (nrComponents == 4) + format = GL_RGBA; + + glBindTexture(GL_TEXTURE_2D, textureID); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); + 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); + + stbi_image_free(data); + } + else + { + std::cout << "Texture failed to load at path: " << path << std::endl; + stbi_image_free(data); + } + + return textureID; +} +#endif diff --git a/include/myEngine/texture.hpp b/include/myEngine/texture.hpp deleted file mode 100644 index 2c920aa..0000000 --- a/include/myEngine/texture.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef TEXTURE_H -#define TEXTURE_H - -#include -#include -#include - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -class Texture -{ -public: - unsigned int ID; - - Texture(const char* texturePath) - { - glGenTextures(1, &ID); - glBindTexture(GL_TEXTURE_2D, ID); - // set the texture wrapping/filtering options (on the currently bound texture object) - 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); - // load and generate the texture - int width, height, nrChannels; - stbi_set_flip_vertically_on_load(true); - unsigned char *data = stbi_load(texturePath, &width, &height, &nrChannels, 0); - if (data) - { - GLenum format = GL_RGB; - if (nrChannels == 1) format = GL_RED; - else if (nrChannels == 3) format = GL_RGB; - else if (nrChannels == 4) format = GL_RGBA; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, format, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); - } - else - { - std::cout << "Failed to load texture" << std::endl; - } - stbi_image_free(data); - } - - void use() - { - glBindTexture(GL_TEXTURE_2D, ID); - } -}; - -#endif \ No newline at end of file diff --git a/lib/assimp b/lib/assimp new file mode 160000 index 0000000..d41511b --- /dev/null +++ b/lib/assimp @@ -0,0 +1 @@ +Subproject commit d41511bf8a7c3e84584788306da6a5c812ca9a6a diff --git a/resources/shaders/shader.fs b/resources/shaders/shader.fs new file mode 100644 index 0000000..9da78b1 --- /dev/null +++ b/resources/shaders/shader.fs @@ -0,0 +1,11 @@ +#version 330 core +out vec4 FragColor; + +in vec2 TexCoords; + +uniform sampler2D texture_diffuse1; + +void main() +{ + FragColor = texture(texture_diffuse1, TexCoords); +} \ No newline at end of file diff --git a/shaders/shader.vs b/resources/shaders/shader.vs similarity index 59% rename from shaders/shader.vs rename to resources/shaders/shader.vs index 5c3dc19..253b79e 100644 --- a/shaders/shader.vs +++ b/resources/shaders/shader.vs @@ -1,8 +1,9 @@ #version 330 core layout (location = 0) in vec3 aPos; -layout (location = 1) in vec2 aTexCoord; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec2 aTexCoords; -out vec2 TexCoord; +out vec2 TexCoords; uniform mat4 model; uniform mat4 view; @@ -10,6 +11,6 @@ uniform mat4 projection; void main() { + TexCoords = aTexCoords; gl_Position = projection * view * model * vec4(aPos, 1.0); - TexCoord = aTexCoord; -} \ No newline at end of file +} \ No newline at end of file diff --git a/textures/oh_my_gah.png b/resources/textures/oh_my_gah.png similarity index 100% rename from textures/oh_my_gah.png rename to resources/textures/oh_my_gah.png diff --git a/textures/saataa_andagii.png b/resources/textures/saataa_andagii.png similarity index 100% rename from textures/saataa_andagii.png rename to resources/textures/saataa_andagii.png diff --git a/shaders/shader.fs b/shaders/shader.fs deleted file mode 100644 index 796e31b..0000000 --- a/shaders/shader.fs +++ /dev/null @@ -1,11 +0,0 @@ -#version 330 core -out vec4 FragColor; - -in vec2 TexCoord; - -uniform sampler2D ourTexture; - -void main() -{ - FragColor = texture(ourTexture, TexCoord); -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index aa43b74..6d72c07 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,23 +1,27 @@ #include +#include + #include #include -#include -#include -#include + #include #include #include +#include +#include +#include + void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window); void mouse_callback(GLFWwindow* window, double xpos, double ypos); -const unsigned int SCR_WIDTH = 800; -const unsigned int SCR_HEIGHT = 600; +unsigned int width = 800; +unsigned int height = 600; Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); -float lastX = SCR_WIDTH / 2.0f; -float lastY = SCR_HEIGHT / 2.0f; +float lastX = width / 2.0f; +float lastY = height / 2.0f; bool firstMouse = true; float deltaTime = 0.0f; @@ -29,7 +33,8 @@ int main() glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL); if (window == NULL) @@ -48,102 +53,20 @@ int main() return -1; } - glViewport(0, 0, 800, 600); + glViewport(0, 0, width, height); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); - float vertices[] = { - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, + glEnable(GL_DEPTH_TEST); - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, + stbi_set_flip_vertically_on_load(true); - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, - - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, - 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, - -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, - -0.5f, 0.5f, -0.5f, 0.0f, 1.0f - }; - - unsigned int VAO; - glGenVertexArrays(1, &VAO); - glBindVertexArray(VAO); - - unsigned int VBO; - glGenBuffers(1, &VBO); - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - /*unsigned int EBO; - glGenBuffers(1, &EBO); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);*/ - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); - - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3* sizeof(float))); - glEnableVertexAttribArray(1); - - Shader ourShader("shaders/shader.vs", "shaders/shader.fs"); - Texture sataaAndagii("textures/saataa_andagii.png"); - Texture ohMyGah("textures/oh_my_gah.png"); + Shader ourShader("resources/shaders/shader.vs", "resources/shaders/shader.fs"); + Model ourModel("resources/models/backpack/backpack.obj"); glm::mat4 model = glm::mat4(1.0f); model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f)); - glm::mat4 view = glm::mat4(1.0f); - view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); - - glm::mat4 projection; - projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); - - glEnable(GL_DEPTH_TEST); - - glm::vec3 cubePositions[] = { - glm::vec3( 0.0f, 0.0f, 0.0f), - glm::vec3( 2.0f, 5.0f, -15.0f), - glm::vec3(-1.5f, -2.2f, -2.5f), - glm::vec3(-3.8f, -2.0f, -12.3f), - glm::vec3( 2.4f, -0.4f, -3.5f), - glm::vec3(-1.7f, 3.0f, -7.5f), - glm::vec3( 1.3f, -2.0f, -2.5f), - glm::vec3( 1.5f, 2.0f, -2.5f), - glm::vec3( 1.5f, 0.2f, -1.5f), - glm::vec3(-1.3f, 1.0f, -1.5f) - }; - while(!glfwWindowShouldClose(window)) { float currentFrame = glfwGetTime(); @@ -155,26 +78,18 @@ int main() glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glm::mat4 view = camera.GetViewMatrix(); - ourShader.use(); - ourShader.setMat4("model", model); + + glm::mat4 view = camera.GetViewMatrix(); + glm::mat4 projection = glm::perspective(glm::radians(45.0f), float(width) / float(height), 0.1f, 100.0f); ourShader.setMat4("view", view); ourShader.setMat4("projection", projection); - ohMyGah.use(); - glBindVertexArray(VAO); - for(unsigned int i = 0; i < 10; i++) - { - glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model, cubePositions[i]); - float angle = 20.0f * i; - model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); - ourShader.setMat4("model", model); - - glDrawArrays(GL_TRIANGLES, 0, 36); - } - glBindVertexArray(0); + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); + model = glm::scale(model, glm::vec3(1.0f, 1.0f, 1.0f)); + ourShader.setMat4("model", model); + ourModel.Draw(ourShader); glfwSwapBuffers(window); glfwPollEvents(); @@ -185,9 +100,11 @@ int main() return 0; } -void framebuffer_size_callback(GLFWwindow* window, int width, int height) +void framebuffer_size_callback(GLFWwindow* window, int new_width, int new_height) { - glViewport(0, 0, width, height); + width = new_width; + height = new_height; + glViewport(0, 0, new_width, new_height); } void processInput(GLFWwindow *window)