From c4a51a4d5b4bcacc05a39cd7dfbe49b15aa34b8e Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 27 Apr 2024 12:55:22 -0700 Subject: [PATCH 01/18] add zlib to nix shell --- shell.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/shell.nix b/shell.nix index 01be7ef5..f398b3e7 100644 --- a/shell.nix +++ b/shell.nix @@ -9,6 +9,7 @@ mkShell { gnumake gcc13 gdb + zlib wayland wayland-scanner From a9bc44cbd85883a19f5db217b673b283779ea075 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 27 Apr 2024 17:07:32 -0700 Subject: [PATCH 02/18] add assimp and stb --- CMakeLists.txt | 6 ++++ dependencies/assimp/CMakeLists.txt | 15 ++++++++++ dependencies/glew/CMakeLists.txt | 6 ++-- dependencies/stb/CMakeLists.txt | 11 +++++++ src/client/CMakeLists.txt | 48 ++++++++++++++++++++++-------- src/client/tests/CMakeLists.txt | 16 ++++++++-- 6 files changed, 85 insertions(+), 17 deletions(-) create mode 100644 dependencies/assimp/CMakeLists.txt create mode 100644 dependencies/stb/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ec3ce19..15a4e224 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,12 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS True) # Tell CMake to ignore warnings from stuff in our dependencies. Surely GLM # knows what it is doing... https://7tv.app/emotes/61e8fae862858c6406126ced +IF (NOT WIN32) + set_property( + DIRECTORY build + PROPERTY COMPILE_OPTIONS "-w" + ) +ENDIF() # Add google test to CMake add_subdirectory(dependencies/google-test) diff --git a/dependencies/assimp/CMakeLists.txt b/dependencies/assimp/CMakeLists.txt new file mode 100644 index 00000000..13eb3a9c --- /dev/null +++ b/dependencies/assimp/CMakeLists.txt @@ -0,0 +1,15 @@ +include(FetchContent) + +FetchContent_Declare(assimp + GIT_REPOSITORY https://github.com/assimp/assimp + GIT_TAG v5.3.1 + GIT_PROGRESS TRUE +) + +FetchContent_MakeAvailable(assimp) + +set(ASSIMP_INCLUDE_DIRS + ${CMAKE_BINARY_DIR}/_deps/assimp-src/include/ + ${CMAKE_BINARY_DIR}/_deps/assimp-build/include/ + PARENT_SCOPE +) diff --git a/dependencies/glew/CMakeLists.txt b/dependencies/glew/CMakeLists.txt index 8a750c9b..3cf51284 100644 --- a/dependencies/glew/CMakeLists.txt +++ b/dependencies/glew/CMakeLists.txt @@ -8,6 +8,6 @@ FetchContent_Declare(glew FetchContent_MakeAvailable(glew) -# find_package(GLEW 2.0 REQUIRED) -# target_link_libraries(Starting GLEW::GLEW) - +set(GLEW_INCLUDE_DIRS + ${CMAKE_BINARY_DIR}/_deps/glew-src/include + PARENT_SCOPE) diff --git a/dependencies/stb/CMakeLists.txt b/dependencies/stb/CMakeLists.txt new file mode 100644 index 00000000..84bd7aba --- /dev/null +++ b/dependencies/stb/CMakeLists.txt @@ -0,0 +1,11 @@ +include(FetchContent) + +FetchContent_Declare(stb + GIT_REPOSITORY https://github.com/nothings/stb + GIT_PROGRESS TRUE +) +FetchContent_MakeAvailable(stb) + +set(STB_INCLUDE_DIRS + ${CMAKE_BINARY_DIR}/_deps/stb-src/ + PARENT_SCOPE) diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 225e7b3a..e2f27751 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -7,7 +7,8 @@ set(FILES cube.cpp util.cpp lobbyfinder.cpp - shaders.cpp + shader.cpp + model.cpp ${imgui-source} ) @@ -21,10 +22,22 @@ add_subdirectory(../../dependencies/glfw ${CMAKE_BINARY_DIR}/glfw) add_subdirectory(../../dependencies/glm ${CMAKE_BINARY_DIR}/glm) add_subdirectory(../../dependencies/imgui ${CMAKE_BINARY_DIR}/imgui) add_subdirectory(../../dependencies/glew ${CMAKE_BINARY_DIR}/glew) +add_subdirectory(../../dependencies/assimp ${CMAKE_BINARY_DIR}/assimp) +add_subdirectory(../../dependencies/stb ${CMAKE_BINARY_DIR}/stb) add_library(${LIB_NAME} STATIC ${FILES}) target_include_directories(${LIB_NAME} PRIVATE ${INCLUDE_DIRECTORY}) -target_include_directories(${LIB_NAME} PRIVATE ${BOOST_LIBRARY_INCLUDES}) +target_include_directories(${LIB_NAME} + PRIVATE + ${BOOST_LIBRARY_INCLUDES} + ${OPENGL_INCLUDE_DIRS} + glfw + glm + ${imgui-directory} + ${GLEW_INCLUDE_DIRS} + ${ASSIMP_INCLUDE_DIRS} + ${STB_INCLUDE_DIRS} +) target_link_libraries(${LIB_NAME} PRIVATE game_shared_lib @@ -34,27 +47,38 @@ target_link_libraries(${LIB_NAME} Boost::program_options Boost::serialization nlohmann_json::nlohmann_json + glm + glfw + libglew_static + assimp ) -target_include_directories(${LIB_NAME} PRIVATE ${OPENGL_INCLUDE_DIRS} glfw glm ${imgui-directory} "${CMAKE_BINARY_DIR}/_deps/glew-src/include") -target_link_libraries(${LIB_NAME} PRIVATE glm glfw libglew_static) add_executable(${TARGET_NAME} main.cpp) - target_include_directories(${TARGET_NAME} PRIVATE ${INCLUDE_DIRECTORY}) -target_include_directories(${TARGET_NAME} PRIVATE ${OPENGL_INCLUDE_DIRS} glfw glm ${imgui-directory} "${CMAKE_BINARY_DIR}/_deps/glew-src/include") +target_include_directories(${TARGET_NAME} + PRIVATE + ${BOOST_LIBRARY_INCLUDES} + ${OPENGL_INCLUDE_DIRS} + glfw + glm + ${imgui-directory} + ${GLEW_INCLUDE_DIRS} + ${ASSIMP_INCLUDE_DIRS} + ${STB_INCLUDE_DIRS} +) target_link_libraries(${TARGET_NAME} PRIVATE game_shared_lib ${LIB_NAME}) -target_link_libraries(${TARGET_NAME} PRIVATE glm glfw libglew_static) - -target_include_directories(${TARGET_NAME} PRIVATE ${BOOST_LIBRARY_INCLUDES}) -target_link_libraries(${TARGET_NAME} - PRIVATE +target_link_libraries(${TARGET_NAME} + PRIVATE Boost::asio Boost::filesystem Boost::thread Boost::program_options Boost::serialization nlohmann_json::nlohmann_json + glm + glfw + libglew_static + assimp ) - add_subdirectory(tests) # define client unit tests diff --git a/src/client/tests/CMakeLists.txt b/src/client/tests/CMakeLists.txt index fbe4eb69..88ba2017 100644 --- a/src/client/tests/CMakeLists.txt +++ b/src/client/tests/CMakeLists.txt @@ -12,6 +12,17 @@ target_include_directories(${TARGET_NAME} PRIVATE ${INCLUDE_DIRECTORY}) target_link_libraries(${TARGET_NAME} PUBLIC gtest_main) add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME}) target_include_directories(${TARGET_NAME} PRIVATE ${BOOST_LIBRARY_INCLUDES}) +target_include_directories(${TARGET_NAME} + PRIVATE + ${OPENGL_INCLUDE_DIRS} + glfw + glm + ${imgui-directory} + ${GLEW_INCLUDE_DIRS} + ${ASSIMP_INCLUDE_DIRS} + ${STB_INCLUDE_DIRS} +) + target_link_libraries(${TARGET_NAME} PRIVATE Boost::asio @@ -20,9 +31,10 @@ target_link_libraries(${TARGET_NAME} Boost::program_options Boost::serialization nlohmann_json::nlohmann_json + glm + glfw + libglew_static ) -target_include_directories(${TARGET_NAME} PRIVATE ${OPENGL_INCLUDE_DIRS} glfw glm ${imgui-directory} "${CMAKE_BINARY_DIR}/_deps/glew-src/include") -target_link_libraries(${TARGET_NAME} PRIVATE glm glfw libglew_static) # setup make target set(RUN_TESTS_TARGET "run_${TARGET_NAME}") From 470f26f6b1b79570abceefedd1a8b7acb64fccdc Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 27 Apr 2024 17:37:04 -0700 Subject: [PATCH 03/18] model loading using assimp library to load 3d models --- include/client/client.hpp | 11 +- include/client/model.hpp | 614 +++++++++++++++++++++++++++++++++++++ include/client/shader.hpp | 27 ++ include/client/shaders.hpp | 5 - include/client/util.hpp | 17 - src/client/client.cpp | 54 ++-- src/client/model.cpp | 273 +++++++++++++++++ src/client/shader.cpp | 110 +++++++ src/client/shaders.cpp | 19 -- src/client/util.cpp | 77 ----- 10 files changed, 1066 insertions(+), 141 deletions(-) create mode 100644 include/client/model.hpp create mode 100644 include/client/shader.hpp delete mode 100644 include/client/shaders.hpp create mode 100644 src/client/model.cpp create mode 100644 src/client/shader.cpp delete mode 100644 src/client/shaders.cpp diff --git a/include/client/client.hpp b/include/client/client.hpp index 8582c57b..12e67537 100644 --- a/include/client/client.hpp +++ b/include/client/client.hpp @@ -9,8 +9,11 @@ #include #include +#include #include "client/cube.hpp" +#include "client/shader.hpp" +#include "client/model.hpp" #include "client/util.hpp" #include "client/lobbyfinder.hpp" @@ -51,8 +54,10 @@ class Client { SharedGameState gameState; - GLuint cubeShaderProgram; - float cubeMovementDelta = 0.05f; + std::shared_ptr cubeShader; + + std::unique_ptr playerModel; + float playerMovementDelta = 0.05f; GLFWwindow *window; @@ -69,5 +74,7 @@ class Client { /// @brief Generate endpoints the client can connect to basic_resolver_results endpoints; std::shared_ptr session; + + boost::filesystem::path root_path; }; diff --git a/include/client/model.hpp b/include/client/model.hpp new file mode 100644 index 00000000..d178abad --- /dev/null +++ b/include/client/model.hpp @@ -0,0 +1,614 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "assimp/material.h" +#include "client/shader.hpp" + +struct Vertex { + glm::vec3 position; + glm::vec3 normal; + glm::vec2 textureCoords; +}; + +class Texture { + public: + Texture(const std::string& filepath, const aiTextureType& type); + unsigned int getID() const; + std::string getType() const; + private: + unsigned int ID; + std::string type; +}; + +class Mesh { + public: + std::vector vertices; + // std::vector indices; + // std::vector textures; + + std::vector positions; + std::vector normals; + std::vector indices; + std::vector textures; + + Mesh(std::vector vertices, std::vector indices, std::vector textures); + void Draw(std::shared_ptr shader, glm::mat4 modelView) const; + private: + // render data opengl needs + GLuint VAO, VBO, EBO; + // GLuint VAO, VBO_positions, VBO_normals, EBO; +}; + + +class Model { + public: + /** + * Loads Model from a given filename. Can be of format + * .obj, .blend or any of the formats that assimp supports + * @see https://assimp-docs.readthedocs.io/en/latest/about/introduction.html?highlight=obj#introduction + * + * @param Filepath to model file. + */ + Model(const std::string& filepath); + + /** + * Draws all the meshes of a given model + * + * @param Shader to use while drawing all the + * meshes of the model + */ + void Draw(std::shared_ptr shader); + + void Update(const glm::vec3& new_pos); + void Scale(const float& new_factor); + private: + // model data + std::vector meshes; + + void processNode(aiNode *node, const aiScene *scene); + Mesh processMesh(aiMesh *mesh, const aiScene *scene); + std::vector loadMaterialTextures(aiMaterial *mat, const aiTextureType& type); + + glm::mat4 modelView; +}; + +// #ifndef MODEL_H +// #define MODEL_H +// +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// +// +// #include +// #include +// #include +// #include +// #include +// #include +// using namespace std; +// +// +// #include +// +// #include +// #include +// #include +// #include +// +// class Shader +// { +// public: +// unsigned int ID; +// // constructor generates the shader on the fly +// // ------------------------------------------------------------------------ +// Shader() = default; +// Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr) +// { +// // 1. retrieve the vertex/fragment source code from filePath +// std::string vertexCode; +// std::string fragmentCode; +// std::string geometryCode; +// std::ifstream vShaderFile; +// std::ifstream fShaderFile; +// std::ifstream gShaderFile; +// // ensure ifstream objects can throw exceptions: +// vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); +// fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); +// gShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); +// try +// { +// // open files +// vShaderFile.open(vertexPath); +// fShaderFile.open(fragmentPath); +// std::stringstream vShaderStream, fShaderStream; +// // read file's buffer contents into streams +// vShaderStream << vShaderFile.rdbuf(); +// fShaderStream << fShaderFile.rdbuf(); +// // close file handlers +// vShaderFile.close(); +// fShaderFile.close(); +// // convert stream into string +// vertexCode = vShaderStream.str(); +// fragmentCode = fShaderStream.str(); +// // if geometry shader path is present, also load a geometry shader +// if(geometryPath != nullptr) +// { +// gShaderFile.open(geometryPath); +// std::stringstream gShaderStream; +// gShaderStream << gShaderFile.rdbuf(); +// gShaderFile.close(); +// geometryCode = gShaderStream.str(); +// } +// } +// catch (std::ifstream::failure& e) +// { +// std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl; +// } +// const char* vShaderCode = vertexCode.c_str(); +// const char * fShaderCode = fragmentCode.c_str(); +// // 2. compile shaders +// unsigned int vertex, fragment; +// // vertex shader +// vertex = glCreateShader(GL_VERTEX_SHADER); +// glShaderSource(vertex, 1, &vShaderCode, NULL); +// glCompileShader(vertex); +// checkCompileErrors(vertex, "VERTEX"); +// // fragment Shader +// fragment = glCreateShader(GL_FRAGMENT_SHADER); +// glShaderSource(fragment, 1, &fShaderCode, NULL); +// glCompileShader(fragment); +// checkCompileErrors(fragment, "FRAGMENT"); +// // if geometry shader is given, compile geometry shader +// unsigned int geometry; +// if(geometryPath != nullptr) +// { +// const char * gShaderCode = geometryCode.c_str(); +// geometry = glCreateShader(GL_GEOMETRY_SHADER); +// glShaderSource(geometry, 1, &gShaderCode, NULL); +// glCompileShader(geometry); +// checkCompileErrors(geometry, "GEOMETRY"); +// } +// // shader Program +// ID = glCreateProgram(); +// glAttachShader(ID, vertex); +// glAttachShader(ID, fragment); +// if(geometryPath != nullptr) +// glAttachShader(ID, geometry); +// glLinkProgram(ID); +// checkCompileErrors(ID, "PROGRAM"); +// // delete the shaders as they're linked into our program now and no longer necessary +// glDeleteShader(vertex); +// glDeleteShader(fragment); +// if(geometryPath != nullptr) +// glDeleteShader(geometry); +// +// } +// // activate the shader +// // ------------------------------------------------------------------------ +// void use() +// { +// glUseProgram(ID); +// } +// // utility uniform functions +// // ------------------------------------------------------------------------ +// void setBool(const std::string &name, bool value) const +// { +// glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); +// } +// // ------------------------------------------------------------------------ +// void setInt(const std::string &name, int value) const +// { +// glUniform1i(glGetUniformLocation(ID, name.c_str()), value); +// } +// // ------------------------------------------------------------------------ +// void setFloat(const std::string &name, float value) const +// { +// glUniform1f(glGetUniformLocation(ID, name.c_str()), value); +// } +// // ------------------------------------------------------------------------ +// void setVec2(const std::string &name, const glm::vec2 &value) const +// { +// glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); +// } +// void setVec2(const std::string &name, float x, float y) const +// { +// glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); +// } +// // ------------------------------------------------------------------------ +// void setVec3(const std::string &name, const glm::vec3 &value) const +// { +// glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); +// } +// void setVec3(const std::string &name, float x, float y, float z) const +// { +// glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); +// } +// // ------------------------------------------------------------------------ +// void setVec4(const std::string &name, const glm::vec4 &value) const +// { +// glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); +// } +// void setVec4(const std::string &name, float x, float y, float z, float w) +// { +// glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); +// } +// // ------------------------------------------------------------------------ +// void setMat2(const std::string &name, const glm::mat2 &mat) const +// { +// glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); +// } +// // ------------------------------------------------------------------------ +// void setMat3(const std::string &name, const glm::mat3 &mat) const +// { +// glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); +// } +// // ------------------------------------------------------------------------ +// void setMat4(const std::string &name, const glm::mat4 &mat) const +// { +// glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); +// } +// +// private: +// // utility function for checking shader compilation/linking errors. +// // ------------------------------------------------------------------------ +// void checkCompileErrors(GLuint shader, std::string type) +// { +// GLint success; +// GLchar infoLog[1024]; +// if(type != "PROGRAM") +// { +// glGetShaderiv(shader, GL_COMPILE_STATUS, &success); +// if(!success) +// { +// glGetShaderInfoLog(shader, 1024, NULL, infoLog); +// std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; +// } +// } +// else +// { +// glGetProgramiv(shader, GL_LINK_STATUS, &success); +// if(!success) +// { +// glGetProgramInfoLog(shader, 1024, NULL, infoLog); +// std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; +// } +// } +// } +// }; +// +// #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); +// } +// }; +// +// 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; +// } +// }; +// +// +// #endif diff --git a/include/client/shader.hpp b/include/client/shader.hpp new file mode 100644 index 00000000..e5a44e6c --- /dev/null +++ b/include/client/shader.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include +#include +#include +#include + + +class Shader { + public: + // constructor reads and builds the shader + Shader(const std::string& vertexPath, const std::string& fragmentPath); + ~Shader(); + + unsigned int getID(); + // use/activate the shader + void use(); + // utility uniform functions + void setBool(const std::string &name, bool value) const; + void setInt(const std::string &name, int value) const; + void setFloat(const std::string &name, float value) const; + private: + // the shader program ID + unsigned int ID; +}; diff --git a/include/client/shaders.hpp b/include/client/shaders.hpp deleted file mode 100644 index 2c5d1d46..00000000 --- a/include/client/shaders.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - - - -GLuint loadCubeShaders(); diff --git a/include/client/util.hpp b/include/client/util.hpp index e9c4ffaa..3f59c932 100644 --- a/include/client/util.hpp +++ b/include/client/util.hpp @@ -1,19 +1,2 @@ #pragma once -#include - -#include -#include -#include -#include -#include - -// #include - -// #include -// #include - -#include "client/core.hpp" - - -GLuint LoadShaders(const std::string& vertex_file_path, const std::string& fragment_file_path); diff --git a/src/client/client.cpp b/src/client/client.cpp index 4362cdc7..7e00b4ec 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1,12 +1,16 @@ #include "client/client.hpp" + +#include +#include + #include #include #include #include -#include -#include +#include -#include "client/shaders.hpp" +#include "client/shader.hpp" +#include "client/model.hpp" #include "shared/game/event.hpp" #include "shared/network/constants.hpp" #include "shared/network/packet.hpp" @@ -25,8 +29,8 @@ Client::Client(boost::asio::io_context& io_context, GameConfig config): resolver(io_context), socket(io_context), config(config), - gameState(GamePhase::TITLE_SCREEN, config) -{ + gameState(GamePhase::TITLE_SCREEN, config) { + this->root_path = boost::dll::program_location().parent_path().parent_path().parent_path(); } void Client::connectAndListen(std::string ip_addr) { @@ -57,7 +61,7 @@ bool Client::init() { /* Create a windowed mode window and its OpenGL context */ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL); + window = glfwCreateWindow(640, 480, "Arcana", NULL, NULL); if (!window) { glfwTerminate(); return false; @@ -75,17 +79,27 @@ bool Client::init() { std::cout << "shader version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; std::cout << "shader version: " << glGetString(GL_VERSION) << std::endl; - this->cubeShaderProgram = loadCubeShaders(); - if (!this->cubeShaderProgram) { - std::cout << "Failed to load cube shader files" << std::endl; + + boost::filesystem::path vertFilepath = this->root_path / "src/client/shaders/shader.vert"; + boost::filesystem::path fragFilepath = this->root_path / "src/client/shaders/shader.frag"; + this->cubeShader = std::make_shared(vertFilepath.c_str(), fragFilepath.c_str()); + if (!this->cubeShader) { + std::cout << "Could not load cube shader" << std::endl; return false; } + boost::filesystem::path playerModelFilepath = this->root_path / "src/client/models/bear-sp22.obj"; + this->playerModel = std::make_unique(playerModelFilepath.string()); + if (!this->playerModel) { + std::cout << "Could not load player model" << std::endl; + return false; + } + this->playerModel->Scale(0.25); + return true; } bool Client::cleanup() { - glDeleteProgram(this->cubeShaderProgram); return true; } @@ -108,13 +122,13 @@ void Client::idleCallback(boost::asio::io_context& context) { std::optional movement = glm::vec3(0.0f); if(is_held_right) - movement.value() += glm::vec3(cubeMovementDelta, 0.0f, 0.0f); + movement.value() += glm::vec3(playerMovementDelta, 0.0f, 0.0f); if(is_held_left) - movement.value() += glm::vec3(-cubeMovementDelta, 0.0f, 0.0f); + movement.value() += glm::vec3(-playerMovementDelta, 0.0f, 0.0f); if(is_held_up) - movement.value() += glm::vec3(0.0f, cubeMovementDelta, 0.0f); + movement.value() += glm::vec3(0.0f, playerMovementDelta, 0.0f); if(is_held_down) - movement.value() += glm::vec3(0.0f, -cubeMovementDelta, 0.0f); + movement.value() += glm::vec3(0.0f, -playerMovementDelta, 0.0f); if (movement.has_value()) { auto eid = 0; @@ -143,14 +157,12 @@ void Client::draw() { for (int i = 0; i < this->gameState.objects.size(); i++) { std::shared_ptr sharedObject = this->gameState.objects.at(i); - if (sharedObject == nullptr) + if (sharedObject == nullptr) { continue; - - std::cout << "got an object" << std::endl; - // tmp: all objects are cubes - Cube* cube = new Cube(); - cube->update(sharedObject->physics.position); - cube->draw(this->cubeShaderProgram); + } + // all objects are players for now + this->playerModel->Update(sharedObject->physics.position); + this->playerModel->Draw(this->cubeShader); } } diff --git a/src/client/model.cpp b/src/client/model.cpp new file mode 100644 index 00000000..dcee5092 --- /dev/null +++ b/src/client/model.cpp @@ -0,0 +1,273 @@ +#include "client/model.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "assimp/material.h" +#include "glm/ext/matrix_transform.hpp" +#include +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#include + +#define GLM_ENABLE_EXPERIMENTAL +#include "glm/ext/matrix_clip_space.hpp" +#include "glm/fwd.hpp" +#include +#include +#include +#include + + +Mesh::Mesh(std::vector vertices, std::vector indices, std::vector textures) : + vertices(vertices), indices(indices), textures(textures) { + + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + glGenBuffers(1, &EBO); + + glBindVertexArray(VAO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + 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); + + // 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, textureCoords)); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + std::cout << "Loaded mesh with " << vertices.size() << " vertices, and " << textures.size() << " textures" << std::endl; +} + +void Mesh::Draw(std::shared_ptr shader, glm::mat4 modelView) const { + // actiavte the shader program + shader->use(); + + // Currently 'hardcoding' camera logic in + float FOV = 45.0f; + float Aspect = 1.33f; + float NearClip = 0.1f; + float FarClip = 100.0f; + + float Distance = 10.0f; + float Azimuth = 0.0f; + float Incline = 20.0f; + + glm::mat4 world(1); + world[3][2] = Distance; + world = glm::eulerAngleY(glm::radians(-Azimuth)) * glm::eulerAngleX(glm::radians(-Incline)) * world; + + // Compute view matrix (inverse of world matrix) + glm::mat4 view = glm::inverse(world); + + // Compute perspective projection matrix + glm::mat4 project = glm::perspective(glm::radians(FOV), Aspect, NearClip, FarClip); + + // Compute final view-projection matrix + glm::mat4 viewProjMtx = project * view; + + auto color = glm::vec3(0.0f, 1.0f, 1.0f); + + // get the locations and send the uniforms to the shader + glUniformMatrix4fv(glGetUniformLocation(shader->getID(), "viewProj"), 1, false, reinterpret_cast(&viewProjMtx)); + glUniformMatrix4fv(glGetUniformLocation(shader->getID(), "model"), 1, GL_FALSE, reinterpret_cast(&modelView)); + glUniform3fv(glGetUniformLocation(shader->getID(), "DiffuseColor"), 1, &color[0]); + + unsigned int diffuseNr = 1; + unsigned int specularNr = 1; + for(unsigned int i = 0; i < textures.size(); i++) { + glActiveTexture(GL_TEXTURE0 + i); // activate proper texture unit before binding + // retrieve texture number (the N in diffuse_textureN) + std::string number; + std::string name = textures[i].getType(); + if(name == "texture_diffuse") + number = std::to_string(diffuseNr++); + else if(name == "texture_specular") + number = std::to_string(specularNr++); + + shader->setInt(("material." + name + number).c_str(), i); + glBindTexture(GL_TEXTURE_2D, textures[i].getID()); + } + glActiveTexture(GL_TEXTURE0); + + // draw mesh + glBindVertexArray(VAO); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + glUseProgram(0); +} + +Model::Model(const std::string& filepath) : + modelView(1.0f) { + + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(filepath, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_SplitLargeMeshes | aiProcess_OptimizeMeshes); + if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { + throw std::invalid_argument(std::string("ERROR::ASSIMP::") + importer.GetErrorString()); + } + + processNode(scene->mRootNode, scene); +} + +void Model::Draw(std::shared_ptr shader) { + for(const Mesh& mesh : this->meshes) + mesh.Draw(shader, this->modelView); +} + +void Model::Update(const glm::vec3 &new_pos) { + modelView[3] = glm::vec4(new_pos, 1.0f); +} + +void Model::Scale(const float& new_factor) { + glm::vec3 scaleVector(new_factor, new_factor, new_factor); + this->modelView = glm::scale(this->modelView, scaleVector); +} + +void Model::processNode(aiNode *node, const aiScene *scene) { + // process all the node's meshes (if any) + for(unsigned int i = 0; i < node->mNumMeshes; i++) { + aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; + meshes.push_back(processMesh(mesh, scene)); + } + // then do the same for each of its children + for(unsigned int i = 0; i < node->mNumChildren; i++) { + processNode(node->mChildren[i], scene); + } +} + +Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) { + std::vector vertices; + std::vector indices; + std::vector textures; + + // process vertex positions, normals and texture coordinates + for(unsigned int i = 0; i < mesh->mNumVertices; i++) { + glm::vec3 position( + mesh->mVertices[i].x, + mesh->mVertices[i].y, + mesh->mVertices[i].z); + glm::vec3 normal( + mesh->mNormals[i].x, + mesh->mNormals[i].y, + mesh->mNormals[i].z); + + // check if the mesh contain texture coordinates + glm::vec2 texture(0.0f, 0.0f); + if(mesh->mTextureCoords[0]) { + texture.x = mesh->mTextureCoords[0][i].x; + texture.y = mesh->mTextureCoords[0][i].y; + } + + vertices.push_back(Vertex{ + position, + normal, + texture + }); + } + // process indices + for(unsigned int i = 0; i < mesh->mNumFaces; i++) { + aiFace face = mesh->mFaces[i]; + for(unsigned int j = 0; j < face.mNumIndices; j++) + indices.push_back(face.mIndices[j]); + } + + // process material + if(mesh->mMaterialIndex >= 0) { + aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; + std::vector diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE); + textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); + std::vector specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR); + textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); + } + + return Mesh(vertices, indices, textures); +} + + +std::vector Model::loadMaterialTextures(aiMaterial* mat, const aiTextureType& type) { + std::vector textures; + for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) { + aiString str; + mat->GetTexture(type, i, &str); + Texture texture(std::string(str.C_Str()), type); + textures.push_back(texture); + } + return textures; +} + + +Texture::Texture(const std::string& filepath, const aiTextureType& type) { + switch (type) { + case aiTextureType_DIFFUSE: + this->type = "texture_diffuse"; + case aiTextureType_SPECULAR: + this->type = "texture_specular"; + default: + throw std::invalid_argument(std::string("Unimplemented texture type ") + aiTextureTypeToString(type)); + } + + unsigned int textureID; + glGenTextures(1, &textureID); + + int width, height, nrComponents; + std::cout << "attempting to load texture at " << filepath << std::endl; + unsigned char *data = stbi_load(filepath.c_str(), &width, &height, &nrComponents, 0); + if (!data) { + std::cout << "Texture failed to load at path: " << filepath << std::endl; + stbi_image_free(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); + + this->ID = textureID; +} + +unsigned int Texture::getID() const { + return ID; +} + +std::string Texture::getType() const { + return type; +} + + diff --git a/src/client/shader.cpp b/src/client/shader.cpp new file mode 100644 index 00000000..2cca847e --- /dev/null +++ b/src/client/shader.cpp @@ -0,0 +1,110 @@ +#include +#include + +#include +#include +#include + +#include "client/shader.hpp" + +Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { + std::string vertexCode; + std::string fragmentCode; + std::ifstream vShaderFile; + std::ifstream fShaderFile; + // ensure ifstream objects can throw exceptions: + vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); + fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); + try { + // open files + vShaderFile.open(vertexPath); + fShaderFile.open(fragmentPath); + std::stringstream vShaderStream, fShaderStream; + // read file's buffer contents into streams + vShaderStream << vShaderFile.rdbuf(); + fShaderStream << fShaderFile.rdbuf(); + // close file handlers + vShaderFile.close(); + fShaderFile.close(); + // convert stream into string + vertexCode = vShaderStream.str(); + fragmentCode = fShaderStream.str(); + } catch(std::ifstream::failure e) { + std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; + } + const char* vShaderCode = vertexCode.c_str(); + const char* fShaderCode = fragmentCode.c_str(); + + // 2. compile shaders + unsigned int vertex, fragment; + int success; + char infoLog[512]; + + // vertex Shader + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vShaderCode, NULL); + glCompileShader(vertex); + // print compile errors if any + glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); + if(!success) { + glGetShaderInfoLog(vertex, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + }; + + // fragment shader + fragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment, 1, &fShaderCode, NULL); + glCompileShader(fragment); + // print compile errors if any + glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); + if(!success) { + glGetShaderInfoLog(vertex, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + }; + + if (vertex == 0 && fragment == 0) { + throw new std::invalid_argument("both shaders failed to init"); + } + + // shader Program + ID = glCreateProgram(); + glAttachShader(ID, vertex); + glAttachShader(ID, fragment); + glLinkProgram(ID); + // print linking errors if any + glGetProgramiv(ID, GL_LINK_STATUS, &success); + if(!success) { + glGetProgramInfoLog(ID, 512, NULL, infoLog); + std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; + } + + // delete the shaders as they're linked into our program now and no longer necessary + glDetachShader(ID, vertex); + glDetachShader(ID, fragment); + glDeleteShader(vertex); + glDeleteShader(fragment); +} + +Shader::~Shader() { + glDeleteProgram(this->ID); +} + +void Shader::use() { + glUseProgram(ID); +} + +void Shader::setBool(const std::string &name, bool value) const { + glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); +} + +void Shader::setInt(const std::string &name, int value) const { + glUniform1i(glGetUniformLocation(ID, name.c_str()), value); +} + +void Shader::setFloat(const std::string &name, float value) const { + glUniform1f(glGetUniformLocation(ID, name.c_str()), value); +} + +unsigned int Shader::getID() { + return ID; +} diff --git a/src/client/shaders.cpp b/src/client/shaders.cpp deleted file mode 100644 index 2a7ea5f0..00000000 --- a/src/client/shaders.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -#include - -#include "client/util.hpp" - -GLuint loadCubeShaders() { - boost::filesystem::path root_path = boost::dll::program_location().parent_path().parent_path().parent_path(); - boost::filesystem::path vertFilepath = root_path / "src/client/shaders/shader.vert"; - boost::filesystem::path fragFilepath = root_path / "src/client/shaders/shader.frag"; - - GLuint shaderProgram = LoadShaders(vertFilepath.string(), fragFilepath.string()); - // Check the shader program exists and is non-zero - if (!shaderProgram) { - return 0; - } - return shaderProgram; -} diff --git a/src/client/util.cpp b/src/client/util.cpp index b5357dd3..4abfa034 100644 --- a/src/client/util.cpp +++ b/src/client/util.cpp @@ -1,79 +1,2 @@ #include "client/util.hpp" -enum ShaderType { - vertex, - fragment -}; - -GLuint LoadSingleShader(const std::string& shaderFilePath, ShaderType type) { - // Create a shader id. - GLuint shaderID = 0; - - if (type == vertex) - shaderID = glCreateShader(GL_VERTEX_SHADER); - else if (type == fragment) - shaderID = glCreateShader(GL_FRAGMENT_SHADER); - - // Try to read shader codes from the shader file. - std::string shaderCode; - std::ifstream shaderStream(shaderFilePath, std::ios::in); - if (shaderStream.is_open()) { - std::string Line = ""; - while (getline(shaderStream, Line)) - shaderCode += "\n" + Line; - shaderStream.close(); - } else { - std::cerr << "Impossible to open " << shaderFilePath << ". " - << "Check to make sure the file exists and you passed in the " - << "right filepath!" - << std::endl; - return 0; - } - - GLint Result = GL_FALSE; - - // Compile Shader. - std::cerr << "Compiling shader: " << shaderFilePath << std::endl; - char const* sourcePointer = shaderCode.c_str(); - glShaderSource(shaderID, 1, &sourcePointer, NULL); - glCompileShader(shaderID); - - // Check Shader. - glGetShaderiv(shaderID, GL_COMPILE_STATUS, &Result); - if (type == vertex) - printf("Successfully compiled vertex shader!\n"); - else if (type == fragment) - printf("Successfully compiled fragment shader!\n"); - - return shaderID; -} - -GLuint LoadShaders(const std::string& vertexFilePath, const std::string& fragmentFilePath) { - // Create the vertex shader and fragment shader. - GLuint vertexShaderID = LoadSingleShader(vertexFilePath, vertex); - GLuint fragmentShaderID = LoadSingleShader(fragmentFilePath, fragment); - - // Check both shaders. - if (vertexShaderID == 0 || fragmentShaderID == 0) return 0; - - GLint Result = GL_FALSE; - - // Link the program. - printf("Linking program\n"); - GLuint programID = glCreateProgram(); - glAttachShader(programID, vertexShaderID); - glAttachShader(programID, fragmentShaderID); - glLinkProgram(programID); - - // Check the program. - glGetProgramiv(programID, GL_LINK_STATUS, &Result); - printf("Successfully linked program!\n"); - - // Detach and delete the shaders as they are no longer needed. - glDetachShader(programID, vertexShaderID); - glDetachShader(programID, fragmentShaderID); - glDeleteShader(vertexShaderID); - glDeleteShader(fragmentShaderID); - - return programID; -} From 744c7aa9f7cecf6901d2a4a23499b06bfe9cfbfe Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 27 Apr 2024 18:05:12 -0700 Subject: [PATCH 04/18] make target to automate model downloads --- CMakeLists.txt | 9 +++++++++ README.md | 4 ++++ shell.nix | 2 ++ src/client/models/.gitignore | 2 ++ 4 files changed, 17 insertions(+) create mode 100644 src/client/models/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index 15a4e224..f31e259a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,3 +73,12 @@ add_custom_target(lint -i${CMAKE_SOURCE_DIR}/src/server/tests -i${CMAKE_SOURCE_DIR}/src/shared/tests ) + +add_custom_target(pull_models + COMMAND + gdown 133bVNM4_27hg_VoZGo9EUfCn7n6VXzOU -O ${CMAKE_SOURCE_DIR}/src/client/models/Player1-fire.obj && + gdown 1v3XO_E1ularO5Ku2WaA8O9GqE402a8cx -O ${CMAKE_SOURCE_DIR}/src/client/models/bear-sp22.obj && + gdown 1hHK-0iKMT6uboFUl3DXC9JcbnfsNCNF4 -O ${CMAKE_SOURCE_DIR}/src/client/models/cube.obj && + gdown 1mEWRgBP7G-s3XOr6NO9yichD4_eKc3JH -O ${CMAKE_SOURCE_DIR}/src/client/models/teapot.obj +) + diff --git a/README.md b/README.md index 6ceff0e2..f918e256 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,10 @@ Depending on where you need to link the library (client, server, shared), you wi - [C++ Intellisense](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) - [General Productivity](https://marketplace.visualstudio.com/items?itemName=jirkavrba.subway-surfers) +## Models + +You can download models from our Google Drive folder [here](https://drive.google.com/drive/folders/1N7a5cDgMcXbPO0RtgznnEo-1XUfdMScM?usp=sharing) and place them in `src/client/models`. Alternatively, you can install [gdown](https://github.com/wkentaro/gdown) and run `make pull_models` to automatically pull them. + ## Documentation View deployed documentation [here](https://cse125.ucsd.edu/2024/cse125g3/site/docs/html/) diff --git a/shell.nix b/shell.nix index f398b3e7..56922eb6 100644 --- a/shell.nix +++ b/shell.nix @@ -30,6 +30,8 @@ mkShell { doxygen clang-tools_14 cppcheck + + python310Packages.gdown ]; nativeBuildInputs = with pkgs; [ pkg-config diff --git a/src/client/models/.gitignore b/src/client/models/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/src/client/models/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From 675bcefd641b1e90a8a0f1a0c720f69dd4b528ab Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sun, 28 Apr 2024 23:28:16 -0700 Subject: [PATCH 05/18] docs and cleanup --- include/client/model.hpp | 612 ++++---------------------------------- include/client/shader.hpp | 41 ++- src/client/client.cpp | 10 +- src/client/model.cpp | 10 +- src/client/shader.cpp | 21 +- 5 files changed, 118 insertions(+), 576 deletions(-) diff --git a/include/client/model.hpp b/include/client/model.hpp index d178abad..7505631f 100644 --- a/include/client/model.hpp +++ b/include/client/model.hpp @@ -14,6 +14,10 @@ #include "assimp/material.h" #include "client/shader.hpp" +/** + * Stores position, normal vector, and coordinates + * in texture map for every vertex in a mesh. + */ struct Vertex { glm::vec3 position; glm::vec3 normal; @@ -22,31 +26,60 @@ struct Vertex { class Texture { public: + /** + * Load a texture from a filepath. + * + * @param filepath is the file path to the texture + * @param type specifies the type of texture to load. + * Currently only aiTextureType_SPECULAR and aiTextureType_DIFFUSE + * are implemented. + */ Texture(const std::string& filepath, const aiTextureType& type); - unsigned int getID() const; + + /** + * @return the texture's ID to be passed into OpenGL functions + */ + GLuint getID() const; + + /* + * Get the type of texture. Either "texture_diffuse" or "texture_specular". + */ std::string getType() const; private: - unsigned int ID; + GLuint ID; std::string type; }; +/** + * Mesh holds the data needed to render a mesh (collection of triangles). + * + * A Mesh differs from a Model since a Model is typically made up of multiple, + * smaller meshes. This is useful for animating parts of model individual (ex: legs, + * arms, head) + */ class Mesh { public: - std::vector vertices; - // std::vector indices; - // std::vector textures; + /** + * Creates a new mesh from a collection of vertices, indices and textures + */ + Mesh(const std::vector& vertices, const std::vector& indices, const std::vector& textures); - std::vector positions; - std::vector normals; + /** + * Render the Mesh to the viewport using the provided shader program. + * + * @param shader to use when rendering the program. Determines position of + * vertices and their color/texture. + * @param modelView determines the scaling/rotation/translation of the + * mesh + */ + void Draw(std::shared_ptr shader, glm::mat4 modelView) const; + private: + std::vector vertices; std::vector indices; std::vector textures; - Mesh(std::vector vertices, std::vector indices, std::vector textures); - void Draw(std::shared_ptr shader, glm::mat4 modelView) const; - private: // render data opengl needs GLuint VAO, VBO, EBO; - // GLuint VAO, VBO_positions, VBO_normals, EBO; }; @@ -59,7 +92,7 @@ class Model { * * @param Filepath to model file. */ - Model(const std::string& filepath); + explicit Model(const std::string& filepath); /** * Draws all the meshes of a given model @@ -69,546 +102,29 @@ class Model { */ void Draw(std::shared_ptr shader); - void Update(const glm::vec3& new_pos); + /** + * Sets the position of the Model to the given x,y,z + * values + * + * @param vector of x, y, z of the model's new position + */ + void TranslateTo(const glm::vec3& new_pos); + + /** + * Scale the Model across all axes (x,y,z) + * by a factor + * + * @param new_factor describes how much to scale the model by. + * Ex: setting it to 0.5 will cut the model's rendered size + * in half. + */ void Scale(const float& new_factor); private: - // model data std::vector meshes; - void processNode(aiNode *node, const aiScene *scene); - Mesh processMesh(aiMesh *mesh, const aiScene *scene); - std::vector loadMaterialTextures(aiMaterial *mat, const aiTextureType& type); + void processNode(aiNode* node, const aiScene* scene); + Mesh processMesh(aiMesh* mesh, const aiScene* scene); + std::vector loadMaterialTextures(aiMaterial* mat, const aiTextureType& type); glm::mat4 modelView; }; - -// #ifndef MODEL_H -// #define MODEL_H -// -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// -// -// #include -// #include -// #include -// #include -// #include -// #include -// using namespace std; -// -// -// #include -// -// #include -// #include -// #include -// #include -// -// class Shader -// { -// public: -// unsigned int ID; -// // constructor generates the shader on the fly -// // ------------------------------------------------------------------------ -// Shader() = default; -// Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr) -// { -// // 1. retrieve the vertex/fragment source code from filePath -// std::string vertexCode; -// std::string fragmentCode; -// std::string geometryCode; -// std::ifstream vShaderFile; -// std::ifstream fShaderFile; -// std::ifstream gShaderFile; -// // ensure ifstream objects can throw exceptions: -// vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); -// fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); -// gShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); -// try -// { -// // open files -// vShaderFile.open(vertexPath); -// fShaderFile.open(fragmentPath); -// std::stringstream vShaderStream, fShaderStream; -// // read file's buffer contents into streams -// vShaderStream << vShaderFile.rdbuf(); -// fShaderStream << fShaderFile.rdbuf(); -// // close file handlers -// vShaderFile.close(); -// fShaderFile.close(); -// // convert stream into string -// vertexCode = vShaderStream.str(); -// fragmentCode = fShaderStream.str(); -// // if geometry shader path is present, also load a geometry shader -// if(geometryPath != nullptr) -// { -// gShaderFile.open(geometryPath); -// std::stringstream gShaderStream; -// gShaderStream << gShaderFile.rdbuf(); -// gShaderFile.close(); -// geometryCode = gShaderStream.str(); -// } -// } -// catch (std::ifstream::failure& e) -// { -// std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl; -// } -// const char* vShaderCode = vertexCode.c_str(); -// const char * fShaderCode = fragmentCode.c_str(); -// // 2. compile shaders -// unsigned int vertex, fragment; -// // vertex shader -// vertex = glCreateShader(GL_VERTEX_SHADER); -// glShaderSource(vertex, 1, &vShaderCode, NULL); -// glCompileShader(vertex); -// checkCompileErrors(vertex, "VERTEX"); -// // fragment Shader -// fragment = glCreateShader(GL_FRAGMENT_SHADER); -// glShaderSource(fragment, 1, &fShaderCode, NULL); -// glCompileShader(fragment); -// checkCompileErrors(fragment, "FRAGMENT"); -// // if geometry shader is given, compile geometry shader -// unsigned int geometry; -// if(geometryPath != nullptr) -// { -// const char * gShaderCode = geometryCode.c_str(); -// geometry = glCreateShader(GL_GEOMETRY_SHADER); -// glShaderSource(geometry, 1, &gShaderCode, NULL); -// glCompileShader(geometry); -// checkCompileErrors(geometry, "GEOMETRY"); -// } -// // shader Program -// ID = glCreateProgram(); -// glAttachShader(ID, vertex); -// glAttachShader(ID, fragment); -// if(geometryPath != nullptr) -// glAttachShader(ID, geometry); -// glLinkProgram(ID); -// checkCompileErrors(ID, "PROGRAM"); -// // delete the shaders as they're linked into our program now and no longer necessary -// glDeleteShader(vertex); -// glDeleteShader(fragment); -// if(geometryPath != nullptr) -// glDeleteShader(geometry); -// -// } -// // activate the shader -// // ------------------------------------------------------------------------ -// void use() -// { -// glUseProgram(ID); -// } -// // utility uniform functions -// // ------------------------------------------------------------------------ -// void setBool(const std::string &name, bool value) const -// { -// glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); -// } -// // ------------------------------------------------------------------------ -// void setInt(const std::string &name, int value) const -// { -// glUniform1i(glGetUniformLocation(ID, name.c_str()), value); -// } -// // ------------------------------------------------------------------------ -// void setFloat(const std::string &name, float value) const -// { -// glUniform1f(glGetUniformLocation(ID, name.c_str()), value); -// } -// // ------------------------------------------------------------------------ -// void setVec2(const std::string &name, const glm::vec2 &value) const -// { -// glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); -// } -// void setVec2(const std::string &name, float x, float y) const -// { -// glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); -// } -// // ------------------------------------------------------------------------ -// void setVec3(const std::string &name, const glm::vec3 &value) const -// { -// glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); -// } -// void setVec3(const std::string &name, float x, float y, float z) const -// { -// glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); -// } -// // ------------------------------------------------------------------------ -// void setVec4(const std::string &name, const glm::vec4 &value) const -// { -// glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); -// } -// void setVec4(const std::string &name, float x, float y, float z, float w) -// { -// glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); -// } -// // ------------------------------------------------------------------------ -// void setMat2(const std::string &name, const glm::mat2 &mat) const -// { -// glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); -// } -// // ------------------------------------------------------------------------ -// void setMat3(const std::string &name, const glm::mat3 &mat) const -// { -// glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); -// } -// // ------------------------------------------------------------------------ -// void setMat4(const std::string &name, const glm::mat4 &mat) const -// { -// glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); -// } -// -// private: -// // utility function for checking shader compilation/linking errors. -// // ------------------------------------------------------------------------ -// void checkCompileErrors(GLuint shader, std::string type) -// { -// GLint success; -// GLchar infoLog[1024]; -// if(type != "PROGRAM") -// { -// glGetShaderiv(shader, GL_COMPILE_STATUS, &success); -// if(!success) -// { -// glGetShaderInfoLog(shader, 1024, NULL, infoLog); -// std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; -// } -// } -// else -// { -// glGetProgramiv(shader, GL_LINK_STATUS, &success); -// if(!success) -// { -// glGetProgramInfoLog(shader, 1024, NULL, infoLog); -// std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; -// } -// } -// } -// }; -// -// #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); -// } -// }; -// -// 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; -// } -// }; -// -// -// #endif diff --git a/include/client/shader.hpp b/include/client/shader.hpp index e5a44e6c..89c48b4a 100644 --- a/include/client/shader.hpp +++ b/include/client/shader.hpp @@ -10,16 +10,49 @@ class Shader { public: - // constructor reads and builds the shader + /** + * Create a shader program from filepaths to a vertex and fragment shader. + * Use getID() to access the shader program's ID. + */ Shader(const std::string& vertexPath, const std::string& fragmentPath); ~Shader(); - unsigned int getID(); - // use/activate the shader + /* + * @return the shader program's ID which can be passed into OpenGL functions + */ + GLuint getID(); + + /* + * Activate the shader program. Must be called before drawing. + * Calls glUseProgram under the hood. + */ void use(); - // utility uniform functions + + /* + * Sets a boolean unform variable of the shader program + * with the specified value + * @param name is the name of the uniform variable as written + * in the shader program + * @param value is the boolean value to write to that variable + */ void setBool(const std::string &name, bool value) const; + + /* + * Sets an integer unform variable of the shader program + * with the specified value + * @param name is the name of the uniform variable as written + * in the shader program + * @param value is the integer value to write to that variable + */ void setInt(const std::string &name, int value) const; + + /* + * Sets a float unform variable of the shader program + * with the specified value + * @param name is the name of the uniform variable as written + * in the shader program + * @param value is the float value to write to that variable + */ void setFloat(const std::string &name, float value) const; private: // the shader program ID diff --git a/src/client/client.cpp b/src/client/client.cpp index 7e00b4ec..b8e834e6 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -83,17 +83,9 @@ bool Client::init() { boost::filesystem::path vertFilepath = this->root_path / "src/client/shaders/shader.vert"; boost::filesystem::path fragFilepath = this->root_path / "src/client/shaders/shader.frag"; this->cubeShader = std::make_shared(vertFilepath.c_str(), fragFilepath.c_str()); - if (!this->cubeShader) { - std::cout << "Could not load cube shader" << std::endl; - return false; - } boost::filesystem::path playerModelFilepath = this->root_path / "src/client/models/bear-sp22.obj"; this->playerModel = std::make_unique(playerModelFilepath.string()); - if (!this->playerModel) { - std::cout << "Could not load player model" << std::endl; - return false; - } this->playerModel->Scale(0.25); return true; @@ -161,7 +153,7 @@ void Client::draw() { continue; } // all objects are players for now - this->playerModel->Update(sharedObject->physics.position); + this->playerModel->TranslateTo(sharedObject->physics.position); this->playerModel->Draw(this->cubeShader); } } diff --git a/src/client/model.cpp b/src/client/model.cpp index dcee5092..1d06a09a 100644 --- a/src/client/model.cpp +++ b/src/client/model.cpp @@ -30,7 +30,7 @@ #include -Mesh::Mesh(std::vector vertices, std::vector indices, std::vector textures) : +Mesh::Mesh(const std::vector& vertices, const std::vector& indices, const std::vector& textures) : vertices(vertices), indices(indices), textures(textures) { glGenVertexArrays(1, &VAO); @@ -46,15 +46,15 @@ Mesh::Mesh(std::vector vertices, std::vector indices, std: // vertex positions glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(0)); // vertex normals glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, normal))); // vertex texture coords glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, textureCoords)); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, textureCoords))); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); @@ -138,7 +138,7 @@ void Model::Draw(std::shared_ptr shader) { mesh.Draw(shader, this->modelView); } -void Model::Update(const glm::vec3 &new_pos) { +void Model::TranslateTo(const glm::vec3 &new_pos) { modelView[3] = glm::vec4(new_pos, 1.0f); } diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 2cca847e..5433a8aa 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -12,31 +12,32 @@ Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { std::string fragmentCode; std::ifstream vShaderFile; std::ifstream fShaderFile; - // ensure ifstream objects can throw exceptions: + + // ensure ifstream objects can throw exceptions vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit); try { - // open files vShaderFile.open(vertexPath); fShaderFile.open(fragmentPath); + std::stringstream vShaderStream, fShaderStream; - // read file's buffer contents into streams + vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); - // close file handlers + vShaderFile.close(); fShaderFile.close(); - // convert stream into string + vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); - } catch(std::ifstream::failure e) { - std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; + } catch(std::ifstream::failure& e) { + throw std::invalid_argument("Error: could not read shader file"); } + const char* vShaderCode = vertexCode.c_str(); const char* fShaderCode = fragmentCode.c_str(); - // 2. compile shaders - unsigned int vertex, fragment; + GLuint vertex, fragment; int success; char infoLog[512]; @@ -105,6 +106,6 @@ void Shader::setFloat(const std::string &name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); } -unsigned int Shader::getID() { +GLuint Shader::getID() { return ID; } From 758ef8e2d3941afa8ee676e60bc90d20911c3f74 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Mon, 29 Apr 2024 17:27:20 -0700 Subject: [PATCH 06/18] pass std::string to shader constructor might be causing Windows client not to build. for some reason I was converting it to c_str before --- src/client/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index b8e834e6..2b0cf4a0 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -82,7 +82,7 @@ bool Client::init() { boost::filesystem::path vertFilepath = this->root_path / "src/client/shaders/shader.vert"; boost::filesystem::path fragFilepath = this->root_path / "src/client/shaders/shader.frag"; - this->cubeShader = std::make_shared(vertFilepath.c_str(), fragFilepath.c_str()); + this->cubeShader = std::make_shared(vertFilepath.string(), fragFilepath.string()); boost::filesystem::path playerModelFilepath = this->root_path / "src/client/models/bear-sp22.obj"; this->playerModel = std::make_unique(playerModelFilepath.string()); From d287fc63e4ad8d8186255dce7a3f99c7e7dcee44 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Fri, 3 May 2024 15:37:25 -0700 Subject: [PATCH 07/18] load and render model materials --- include/client/client.hpp | 4 ++ include/client/lightsource.hpp | 33 +++++++++++ include/client/model.hpp | 21 ++++++- include/client/shader.hpp | 7 ++- include/client/util.hpp | 5 ++ src/client/CMakeLists.txt | 1 + src/client/client.cpp | 14 ++++- src/client/lightsource.cpp | 59 ++++++++++++++++++++ src/client/model.cpp | 85 ++++++++++++++++++++++++----- src/client/shader.cpp | 12 +++- src/client/shaders/lightsource.frag | 7 +++ src/client/shaders/lightsource.vert | 14 +++++ src/client/shaders/material.frag | 44 +++++++++++++++ src/client/shaders/shader.frag | 1 + src/client/shaders/shader.vert | 4 +- src/client/util.cpp | 4 ++ 16 files changed, 292 insertions(+), 23 deletions(-) create mode 100644 include/client/lightsource.hpp create mode 100644 src/client/lightsource.cpp create mode 100644 src/client/shaders/lightsource.frag create mode 100644 src/client/shaders/lightsource.vert create mode 100644 src/client/shaders/material.frag diff --git a/include/client/client.hpp b/include/client/client.hpp index 12e67537..b88dcac2 100644 --- a/include/client/client.hpp +++ b/include/client/client.hpp @@ -12,6 +12,7 @@ #include #include "client/cube.hpp" +#include "client/lightsource.hpp" #include "client/shader.hpp" #include "client/model.hpp" #include "client/util.hpp" @@ -55,6 +56,9 @@ class Client { SharedGameState gameState; std::shared_ptr cubeShader; + std::shared_ptr lightSourceShader; + + std::unique_ptr lightSource; std::unique_ptr playerModel; float playerMovementDelta = 0.05f; diff --git a/include/client/lightsource.hpp b/include/client/lightsource.hpp new file mode 100644 index 00000000..af9405bd --- /dev/null +++ b/include/client/lightsource.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "client/core.hpp" +#include "client/shader.hpp" + +#define GLM_ENABLE_EXPERIMENTAL +#include +#include +#include + +#include +#include +#include +#include + +class LightSource { +public: + LightSource(); + void draw(std::shared_ptr shader); + + glm::vec3 lightPos; +private: + GLuint VAO, VBO; + + glm::mat4 model; + glm::vec3 color; + + // Cube Information + std::vector positions; + std::vector normals; + std::vector indices; + +}; diff --git a/include/client/model.hpp b/include/client/model.hpp index 7505631f..97ec9476 100644 --- a/include/client/model.hpp +++ b/include/client/model.hpp @@ -50,6 +50,13 @@ class Texture { std::string type; }; +struct Material { + glm::vec3 ambient; + glm::vec3 diffuse; + glm::vec3 specular; + float shininess; +}; + /** * Mesh holds the data needed to render a mesh (collection of triangles). * @@ -62,7 +69,12 @@ class Mesh { /** * Creates a new mesh from a collection of vertices, indices and textures */ - Mesh(const std::vector& vertices, const std::vector& indices, const std::vector& textures); + Mesh( + const std::vector& vertices, + const std::vector& indices, + const std::vector& textures, + const Material& material + ); /** * Render the Mesh to the viewport using the provided shader program. @@ -72,11 +84,12 @@ class Mesh { * @param modelView determines the scaling/rotation/translation of the * mesh */ - void Draw(std::shared_ptr shader, glm::mat4 modelView) const; + void Draw(std::shared_ptr shader, glm::mat4 modelView) ; private: std::vector vertices; std::vector indices; std::vector textures; + Material material; // render data opengl needs GLuint VAO, VBO, EBO; @@ -127,4 +140,8 @@ class Model { std::vector loadMaterialTextures(aiMaterial* mat, const aiTextureType& type); glm::mat4 modelView; + + // store the directory of the model file so that textures can be + // loaded relative to the model file + std::string directory; }; diff --git a/include/client/shader.hpp b/include/client/shader.hpp index 89c48b4a..ca6dcd37 100644 --- a/include/client/shader.hpp +++ b/include/client/shader.hpp @@ -1,11 +1,12 @@ #pragma once -#include - #include #include #include #include + +#include +#include class Shader { @@ -54,6 +55,8 @@ class Shader { * @param value is the float value to write to that variable */ void setFloat(const std::string &name, float value) const; + void setMat4(const std::string &name, glm::mat4& value); + void setVec3(const std::string &name, glm::vec3& value); private: // the shader program ID unsigned int ID; diff --git a/include/client/util.hpp b/include/client/util.hpp index 3f59c932..1206e4fc 100644 --- a/include/client/util.hpp +++ b/include/client/util.hpp @@ -1,2 +1,7 @@ #pragma once +#include "assimp/types.h" +#include + +glm::vec3 aiColorToGLM(const aiColor3D& color); + diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index e2f27751..6f4d762a 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -9,6 +9,7 @@ set(FILES lobbyfinder.cpp shader.cpp model.cpp + lightsource.cpp ${imgui-source} ) diff --git a/src/client/client.cpp b/src/client/client.cpp index 2b0cf4a0..b442ddc9 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1,5 +1,4 @@ #include "client/client.hpp" - #include #include @@ -9,6 +8,7 @@ #include #include +#include "client/lightsource.hpp" #include "client/shader.hpp" #include "client/model.hpp" #include "shared/game/event.hpp" @@ -81,13 +81,20 @@ bool Client::init() { boost::filesystem::path vertFilepath = this->root_path / "src/client/shaders/shader.vert"; - boost::filesystem::path fragFilepath = this->root_path / "src/client/shaders/shader.frag"; + boost::filesystem::path fragFilepath = this->root_path / "src/client/shaders/material.frag"; this->cubeShader = std::make_shared(vertFilepath.string(), fragFilepath.string()); - boost::filesystem::path playerModelFilepath = this->root_path / "src/client/models/bear-sp22.obj"; + boost::filesystem::path playerModelFilepath = this->root_path / "src/client/models/bear_full.obj"; this->playerModel = std::make_unique(playerModelFilepath.string()); this->playerModel->Scale(0.25); + this->lightSource = std::make_unique(); + boost::filesystem::path lightVertFilepath = this->root_path / "src/client/shaders/lightsource.vert"; + boost::filesystem::path lightFragFilepath = this->root_path / "src/client/shaders/lightsource.frag"; + this->lightSourceShader = std::make_shared(lightVertFilepath.string(), lightFragFilepath.string()); + + this->cubeShader->setVec3("lightPos", lightSource->lightPos); + return true; } @@ -146,6 +153,7 @@ void Client::processServerInput(boost::asio::io_context& context) { } void Client::draw() { + this->lightSource->draw(this->lightSourceShader); for (int i = 0; i < this->gameState.objects.size(); i++) { std::shared_ptr sharedObject = this->gameState.objects.at(i); diff --git a/src/client/lightsource.cpp b/src/client/lightsource.cpp new file mode 100644 index 00000000..5c4d3337 --- /dev/null +++ b/src/client/lightsource.cpp @@ -0,0 +1,59 @@ +#include "client/lightsource.hpp" + +#include + +#include + +#include "client/shader.hpp" + +LightSource::LightSource() { + this->lightPos = glm::vec3(1.0f, 10.0f, 0.0f); + model = glm::mat4(1.0f); + model = glm::translate(model, lightPos); + model = glm::scale(model, glm::vec3(0.2f)); + + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); + // we only need to bind to the VBO, the container's VBO's data already contains the data. + glBindBuffer(GL_ARRAY_BUFFER, VBO); + // set the vertex attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); +} + +void LightSource::draw(std::shared_ptr shader) { + shader->use(); + // Currently 'hardcoding' camera logic in + float FOV = 45.0f; + float Aspect = 1.33f; + float NearClip = 0.1f; + float FarClip = 100.0f; + + float Distance = 10.0f; + float Azimuth = 0.0f; + float Incline = 20.0f; + + glm::mat4 world(1); + world[3][2] = Distance; + world = glm::eulerAngleY(glm::radians(-Azimuth)) * glm::eulerAngleX(glm::radians(-Incline)) * world; + + // Compute view matrix (inverse of world matrix) + glm::mat4 view = glm::inverse(world); + + // Compute perspective projection matrix + glm::mat4 project = glm::perspective(glm::radians(FOV), Aspect, NearClip, FarClip); + + // Compute final view-projection matrix + glm::mat4 viewProjMtx = project * view; + + // get the locations and send the uniforms to the shader + shader->setMat4("viewProj", viewProjMtx); + shader->setMat4("model", model); + + // draw the light cube object + glBindVertexArray(VAO); + glDrawArrays(GL_TRIANGLES, 0, 36); + + glBindVertexArray(0); + glUseProgram(0); +} diff --git a/src/client/model.cpp b/src/client/model.cpp index 1d06a09a..6260c532 100644 --- a/src/client/model.cpp +++ b/src/client/model.cpp @@ -13,6 +13,8 @@ #include #include "assimp/material.h" +#include "assimp/types.h" +#include "client/util.hpp" #include "glm/ext/matrix_transform.hpp" #include #include @@ -30,8 +32,12 @@ #include -Mesh::Mesh(const std::vector& vertices, const std::vector& indices, const std::vector& textures) : - vertices(vertices), indices(indices), textures(textures) { +Mesh::Mesh( + const std::vector& vertices, + const std::vector& indices, + const std::vector& textures, + const Material& material) : + vertices(vertices), indices(indices), textures(textures), material(material) { glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); @@ -60,9 +66,13 @@ Mesh::Mesh(const std::vector& vertices, const std::vector& glBindVertexArray(0); std::cout << "Loaded mesh with " << vertices.size() << " vertices, and " << textures.size() << " textures" << std::endl; + std::cout << "\t diffuse " << glm::to_string(this->material.diffuse) << std::endl; + std::cout << "\t ambient " << glm::to_string(this->material.diffuse) << std::endl; + std::cout << "\t specular " << glm::to_string(this->material.specular) << std::endl; + std::cout << "\t shininess" << this->material.shininess << std::endl; } -void Mesh::Draw(std::shared_ptr shader, glm::mat4 modelView) const { +void Mesh::Draw(std::shared_ptr shader, glm::mat4 modelView) { // actiavte the shader program shader->use(); @@ -89,12 +99,19 @@ void Mesh::Draw(std::shared_ptr shader, glm::mat4 modelView) const { // Compute final view-projection matrix glm::mat4 viewProjMtx = project * view; - auto color = glm::vec3(0.0f, 1.0f, 1.0f); + auto lightColor = glm::vec3(1.0f, 1.0f, 1.0f); + shader->setVec3("lightColor", lightColor); - // get the locations and send the uniforms to the shader - glUniformMatrix4fv(glGetUniformLocation(shader->getID(), "viewProj"), 1, false, reinterpret_cast(&viewProjMtx)); - glUniformMatrix4fv(glGetUniformLocation(shader->getID(), "model"), 1, GL_FALSE, reinterpret_cast(&modelView)); - glUniform3fv(glGetUniformLocation(shader->getID(), "DiffuseColor"), 1, &color[0]); + glm::vec3 viewPos = glm::vec3(world[3].x, world[3].y, world[3].z); + shader->setVec3("viewPos", viewPos); + + shader->setMat4("viewProj", viewProjMtx); + shader->setMat4("model", modelView); + + shader->setVec3("material.diffuse", this->material.diffuse); + shader->setVec3("material.ambient", this->material.ambient); + shader->setVec3("material.specular", this->material.specular); + shader->setFloat("materia.shininess", this->material.shininess); unsigned int diffuseNr = 1; unsigned int specularNr = 1; @@ -108,7 +125,8 @@ void Mesh::Draw(std::shared_ptr shader, glm::mat4 modelView) const { else if(name == "texture_specular") number = std::to_string(specularNr++); - shader->setInt(("material." + name + number).c_str(), i); + std::string shaderTextureName = "material." + name + number; + shader->setInt(shaderTextureName, i); glBindTexture(GL_TEXTURE_2D, textures[i].getID()); } glActiveTexture(GL_TEXTURE0); @@ -122,7 +140,7 @@ void Mesh::Draw(std::shared_ptr shader, glm::mat4 modelView) const { } Model::Model(const std::string& filepath) : - modelView(1.0f) { + modelView(1.0f), directory(filepath.substr(0, filepath.find_last_of('/'))) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(filepath, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_SplitLargeMeshes | aiProcess_OptimizeMeshes); @@ -134,7 +152,7 @@ Model::Model(const std::string& filepath) : } void Model::Draw(std::shared_ptr shader) { - for(const Mesh& mesh : this->meshes) + for(Mesh& mesh : this->meshes) mesh.Draw(shader, this->modelView); } @@ -196,24 +214,60 @@ Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) { } // process material + aiColor3D diffuse_color; + aiColor3D ambient_color; + aiColor3D specular_color; + float shininess; + if(mesh->mMaterialIndex >= 0) { + std::cout << "processing material of id: " << mesh->mMaterialIndex << std::endl; aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; + std::vector diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE); textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); + std::vector specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR); textures.insert(textures.end(), specularMaps.begin(), specularMaps.end()); + + if(AI_SUCCESS != material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse_color)) { + std::cout << "couldn't get diffuse color" << std::endl; + } + + if(AI_SUCCESS != material->Get(AI_MATKEY_COLOR_AMBIENT, ambient_color)) { + std::cout << "couldn't get ambient color" << std::endl; + } + + if(AI_SUCCESS != material->Get(AI_MATKEY_COLOR_SPECULAR, specular_color)) { + std::cout << "couldn't get specular color" << std::endl; + } + + if(AI_SUCCESS != material->Get(AI_MATKEY_SHININESS, shininess)) { + std::cout << "couldn't get shininess factor" << std::endl; + } } - return Mesh(vertices, indices, textures); + return Mesh( + vertices, + indices, + textures, + Material { + aiColorToGLM(diffuse_color), + aiColorToGLM(ambient_color), + aiColorToGLM(specular_color), + shininess + } + ); } std::vector Model::loadMaterialTextures(aiMaterial* mat, const aiTextureType& type) { std::vector textures; + std::cout << "material has " << mat->GetTextureCount(type) << " textures of type " << aiTextureTypeToString(type) << std::endl; for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); - Texture texture(std::string(str.C_Str()), type); + std::string textureFilepath = this->directory + "/" + std::string(str.C_Str()); + Texture texture(textureFilepath, type); textures.push_back(texture); } return textures; @@ -224,8 +278,10 @@ Texture::Texture(const std::string& filepath, const aiTextureType& type) { switch (type) { case aiTextureType_DIFFUSE: this->type = "texture_diffuse"; + break; case aiTextureType_SPECULAR: this->type = "texture_specular"; + break; default: throw std::invalid_argument(std::string("Unimplemented texture type ") + aiTextureTypeToString(type)); } @@ -234,12 +290,13 @@ Texture::Texture(const std::string& filepath, const aiTextureType& type) { glGenTextures(1, &textureID); int width, height, nrComponents; - std::cout << "attempting to load texture at " << filepath << std::endl; + std::cout << "Attempting to load texture at " << filepath << std::endl; unsigned char *data = stbi_load(filepath.c_str(), &width, &height, &nrComponents, 0); if (!data) { std::cout << "Texture failed to load at path: " << filepath << std::endl; stbi_image_free(data); } + std::cout << "Succesfully loaded texture at " << filepath << std::endl; GLenum format; if (nrComponents == 1) format = GL_RED; diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 5433a8aa..4209a53f 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -1,10 +1,12 @@ #include -#include #include #include #include +#include +#include + #include "client/shader.hpp" Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { @@ -106,6 +108,14 @@ void Shader::setFloat(const std::string &name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); } +void Shader::setMat4(const std::string &name, glm::mat4& value) { + glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, reinterpret_cast(&value)); +} + +void Shader::setVec3(const std::string &name, glm::vec3& value) { + glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, reinterpret_cast(&value)); +} + GLuint Shader::getID() { return ID; } diff --git a/src/client/shaders/lightsource.frag b/src/client/shaders/lightsource.frag new file mode 100644 index 00000000..6b1b3513 --- /dev/null +++ b/src/client/shaders/lightsource.frag @@ -0,0 +1,7 @@ +#version 330 core +out vec4 FragColor; + +void main() +{ + FragColor = vec4(1.0); // set all 4 vector values to 1.0 +} diff --git a/src/client/shaders/lightsource.vert b/src/client/shaders/lightsource.vert new file mode 100644 index 00000000..820e2b27 --- /dev/null +++ b/src/client/shaders/lightsource.vert @@ -0,0 +1,14 @@ +#version 330 core +// NOTE: Do NOT use any version older than 330! Bad things will happen! + +layout (location = 0) in vec3 position; + +// Uniform variables +uniform mat4 viewProj; +uniform mat4 model; + +void main() +{ + // OpenGL maintains the D matrix so you only need to multiply by P, V (aka C inverse), and M + gl_Position = viewProj * model * vec4(position, 1.0); +} diff --git a/src/client/shaders/material.frag b/src/client/shaders/material.frag new file mode 100644 index 00000000..b0086ef5 --- /dev/null +++ b/src/client/shaders/material.frag @@ -0,0 +1,44 @@ +#version 330 core + +// Inputs to the fragment shader are the outputs of the same name from the vertex shader. +// Note that you do not have access to the vertex shader's default output, gl_Position. + +in vec3 fragNormal; +in vec3 fragPos; + +struct Material { + vec3 ambient; + vec3 diffuse; + vec3 specular; + float shininess; +}; + +uniform Material material; +uniform vec3 viewPos; + +uniform vec3 lightPos; +uniform vec3 lightColor; + +// You can output many things. The first vec4 type output determines the color of the fragment +out vec4 fragColor; + +void main() +{ + // ambient + vec3 ambient = lightColor * material.ambient; + + // diffuse + vec3 norm = normalize(fragNormal); + vec3 lightDir = normalize(lightPos - fragPos); + float diff = max(dot(norm, lightDir), 0.0); + vec3 diffuse = lightColor * (diff * material.diffuse); + + // specular + vec3 viewDir = normalize(viewPos - fragPos); + vec3 reflectDir = reflect(-lightDir, norm); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); + vec3 specular = lightColor * (spec * material.specular); + + vec3 result = ambient + diffuse + specular; + fragColor = vec4(result, 1.0); +} diff --git a/src/client/shaders/shader.frag b/src/client/shaders/shader.frag index 9b84c61c..3bc9cbee 100644 --- a/src/client/shaders/shader.frag +++ b/src/client/shaders/shader.frag @@ -4,6 +4,7 @@ // Note that you do not have access to the vertex shader's default output, gl_Position. in vec3 fragNormal; +in vec3 fragPos; // uniforms used for lighting uniform vec3 AmbientColor = vec3(0.2); diff --git a/src/client/shaders/shader.vert b/src/client/shaders/shader.vert index 56567efe..a3f529c8 100644 --- a/src/client/shaders/shader.vert +++ b/src/client/shaders/shader.vert @@ -11,7 +11,7 @@ uniform mat4 model; // Outputs of the vertex shader are the inputs of the same name of the fragment shader. // The default output, gl_Position, should be assigned something. out vec3 fragNormal; - +out vec3 fragPos; void main() { @@ -20,4 +20,6 @@ void main() // for shading fragNormal = vec3(model * vec4(normal, 0)); + //fragNormal = normal; + fragPos = vec3(model * vec4(position, 1.0)); } \ No newline at end of file diff --git a/src/client/util.cpp b/src/client/util.cpp index 4abfa034..39a0ffac 100644 --- a/src/client/util.cpp +++ b/src/client/util.cpp @@ -1,2 +1,6 @@ #include "client/util.hpp" +glm::vec3 aiColorToGLM(const aiColor3D& color) { + return glm::vec3(color.r, color.g, color.b); +} + From f263d923cf96b754f4d110ee9ee19239580c2d5c Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 4 May 2024 15:48:23 -0700 Subject: [PATCH 08/18] move graphics models/materials/textures to assets/graphics --- .../models => assets/graphics}/.gitignore | 0 include/client/client.hpp | 10 ++--- src/client/client.cpp | 37 ++++++++++--------- src/client/model.cpp | 35 ++++++++++-------- 4 files changed, 43 insertions(+), 39 deletions(-) rename {src/client/models => assets/graphics}/.gitignore (100%) diff --git a/src/client/models/.gitignore b/assets/graphics/.gitignore similarity index 100% rename from src/client/models/.gitignore rename to assets/graphics/.gitignore diff --git a/include/client/client.hpp b/include/client/client.hpp index 9f530492..462bc5ea 100644 --- a/include/client/client.hpp +++ b/include/client/client.hpp @@ -58,13 +58,13 @@ class Client { SharedGameState gameState; - std::shared_ptr cubeShader; - std::shared_ptr bearShader; - std::shared_ptr lightSourceShader; + std::shared_ptr cube_shader; + std::shared_ptr model_shader; + std::shared_ptr light_source_shader; - std::unique_ptr lightSource; + std::unique_ptr bear_model; + std::unique_ptr light_source; - std::unique_ptr bearModel; float playerMovementDelta = 0.05f; GLFWwindow *window; diff --git a/src/client/client.cpp b/src/client/client.cpp index abcf1151..dd1aa1ec 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -108,24 +108,25 @@ bool Client::init() { std::cout << "shader version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; std::cout << "shader version: " << glGetString(GL_VERSION) << std::endl; + boost::filesystem::path shaders_dir = this->root_path / "src/client/shaders"; + boost::filesystem::path graphics_assets_dir = this->root_path / "assets/graphics"; - boost::filesystem::path cubeVertFilepath = this->root_path / "src/client/shaders/shader.vert"; - boost::filesystem::path cubeFragFilepath = this->root_path / "src/client/shaders/shader.frag"; - this->cubeShader = std::make_shared(cubeVertFilepath.string(), cubeFragFilepath.string()); + boost::filesystem::path cube_vert_path = shaders_dir / "shader.vert"; + boost::filesystem::path cube_frag_path = shaders_dir / "shader.frag"; + this->cube_shader = std::make_shared(cube_vert_path.string(), cube_frag_path.string()); - boost::filesystem::path playerVertFilepath = this->root_path / "src/client/shaders/model.vert"; - boost::filesystem::path playerFragFilepath = this->root_path / "src/client/shaders/model.frag"; - this->bearShader = std::make_shared(playerVertFilepath.string(), playerFragFilepath.string()); + boost::filesystem::path model_vert_path = shaders_dir / "model.vert"; + boost::filesystem::path model_frag_path = shaders_dir / "model.frag"; + this->model_shader = std::make_shared(model_vert_path.string(), model_frag_path.string()); - boost::filesystem::path playerModelFilepath = this->root_path / "src/client/models/bear-sp22.obj"; - this->bearModel = std::make_unique(playerModelFilepath.string()); - this->bearModel->Scale(0.25); + boost::filesystem::path bear_model_path = graphics_assets_dir / "bear-sp22.obj"; + this->bear_model = std::make_unique(bear_model_path.string()); + this->bear_model->Scale(0.25); - this->lightSource = std::make_unique(); + this->light_source = std::make_unique(); boost::filesystem::path lightVertFilepath = this->root_path / "src/client/shaders/lightsource.vert"; boost::filesystem::path lightFragFilepath = this->root_path / "src/client/shaders/lightsource.frag"; - this->lightSourceShader = std::make_shared(lightVertFilepath.string(), lightFragFilepath.string()); - + this->light_source_shader = std::make_shared(lightVertFilepath.string(), lightFragFilepath.string()); return true; } @@ -241,15 +242,15 @@ void Client::draw() { continue; } if (sharedObject->type == ObjectType::Enemy) { - this->bearModel->TranslateTo(sharedObject->physics.position); - this->bearModel->Draw(this->cam->getViewProj(), this->cam->getPos(), this->bearShader, this->cam->getPos()); + this->bear_model->TranslateTo(sharedObject->physics.position); + this->bear_model->Draw(this->cam->getViewProj(), this->cam->getPos(), this->model_shader, this->cam->getPos()); } // Get camera position from server, update position and don't render player object (or special handling) if (this->session->getInfo().client_eid.has_value() && sharedObject->globalID == this->session->getInfo().client_eid.value()) { cam->updatePos(sharedObject->physics.position); - this->lightSource->TranslateTo(cam->getPos()); - this->lightSource->draw(this->lightSourceShader); + this->light_source->TranslateTo(cam->getPos()); + this->light_source->draw(this->light_source_shader); continue; } @@ -257,14 +258,14 @@ void Client::draw() { if(sharedObject->solidSurface.has_value()){ Cube* cube = new Cube(glm::vec3(0.4f,0.5f,0.7f), sharedObject->solidSurface->dimensions); cube->update(sharedObject->physics.position); - cube->draw(this->cam->getViewProj(), this->cubeShader->getID(), true); + cube->draw(this->cam->getViewProj(), this->cube_shader->getID(), true); continue; } // tmp: all objects are cubes Cube* cube = new Cube(glm::vec3(0.0f,1.0f,1.0f), glm::vec3(1.0f)); cube->update(sharedObject->physics.position); - cube->draw(this->cam->getViewProj(), this->cubeShader->getID(), false); + cube->draw(this->cam->getViewProj(), this->cube_shader->getID(), false); } } diff --git a/src/client/model.cpp b/src/client/model.cpp index e2ff7298..c9e43181 100644 --- a/src/client/model.cpp +++ b/src/client/model.cpp @@ -90,23 +90,26 @@ void Mesh::Draw(std::shared_ptr shader, glm::mat4 model, glm::mat4 viewP shader->setVec3("material.specular", this->material.specular); shader->setFloat("material.shininess", this->material.shininess); - unsigned int diffuseNr = 1; - unsigned int specularNr = 1; - for(unsigned int i = 0; i < textures.size(); i++) { - glActiveTexture(GL_TEXTURE0 + i); // activate proper texture unit before binding - // retrieve texture number (the N in diffuse_textureN) - std::string number; - std::string name = textures[i].getType(); - if(name == "texture_diffuse") - number = std::to_string(diffuseNr++); - else if(name == "texture_specular") - number = std::to_string(specularNr++); - - std::string shaderTextureName = "material." + name + number; - shader->setInt(shaderTextureName, i); - glBindTexture(GL_TEXTURE_2D, textures[i].getID()); + if (textures.size() == 0) { + } else { + unsigned int diffuseNr = 1; + unsigned int specularNr = 1; + for(unsigned int i = 0; i < textures.size(); i++) { + glActiveTexture(GL_TEXTURE0 + i); // activate proper texture unit before binding + // retrieve texture number (the N in diffuse_textureN) + std::string number; + std::string name = textures[i].getType(); + if(name == "texture_diffuse") + number = std::to_string(diffuseNr++); + else if(name == "texture_specular") + number = std::to_string(specularNr++); + + std::string shaderTextureName = "material." + name + number; + shader->setInt(shaderTextureName, i); + glBindTexture(GL_TEXTURE_2D, textures[i].getID()); + } + glActiveTexture(GL_TEXTURE0); } - glActiveTexture(GL_TEXTURE0); // draw mesh glBindVertexArray(VAO); From f8b35f2307100a2ebda3c36ed8e7d0173f3bd77d Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 4 May 2024 15:48:47 -0700 Subject: [PATCH 09/18] update make pull_models to pull entire drive folder --- CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 508e864b..6d5400af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,8 +76,5 @@ add_custom_target(lint add_custom_target(pull_models COMMAND - gdown 133bVNM4_27hg_VoZGo9EUfCn7n6VXzOU -O ${CMAKE_SOURCE_DIR}/src/client/models/Player1-fire.obj && - gdown 1v3XO_E1ularO5Ku2WaA8O9GqE402a8cx -O ${CMAKE_SOURCE_DIR}/src/client/models/bear-sp22.obj && - gdown 1hHK-0iKMT6uboFUl3DXC9JcbnfsNCNF4 -O ${CMAKE_SOURCE_DIR}/src/client/models/cube.obj && - gdown 1mEWRgBP7G-s3XOr6NO9yichD4_eKc3JH -O ${CMAKE_SOURCE_DIR}/src/client/models/teapot.obj + gdown 1N7a5cDgMcXbPO0RtgznnEo-1XUfdMScM -O ${CMAKE_SOURCE_DIR}/assets/graphics --folder ) From 070d07d7b0b5da108afd75047739e32ef7e76513 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 4 May 2024 23:19:55 -0700 Subject: [PATCH 10/18] add renderable class all renderable items inherit from the renderable class to avoid redefining functionality they all share (translation, scaling) --- include/client/cube.hpp | 16 ++++---- include/client/model.hpp | 41 +++++++++++++++----- include/client/renderable.hpp | 70 +++++++++++++++++++++++++++++++++++ src/client/CMakeLists.txt | 1 + src/client/client.cpp | 29 ++++++++++----- src/client/cube.cpp | 51 ++++++------------------- src/client/model.cpp | 65 ++++++++++++++++++++++---------- src/client/renderable.cpp | 28 ++++++++++++++ src/client/shader.cpp | 6 +-- 9 files changed, 219 insertions(+), 88 deletions(-) create mode 100644 include/client/renderable.hpp create mode 100644 src/client/renderable.cpp diff --git a/include/client/cube.hpp b/include/client/cube.hpp index 20ea8d55..6a191736 100644 --- a/include/client/cube.hpp +++ b/include/client/cube.hpp @@ -1,6 +1,7 @@ #pragma once #include "client/core.hpp" +#include "client/renderable.hpp" #define GLM_ENABLE_EXPERIMENTAL #include @@ -11,23 +12,22 @@ #include #include -class Cube { +class Cube : public Renderable { public: - Cube(glm::vec3 newColor, glm::vec3 scale); + Cube(glm::vec3 newColor); ~Cube(); - void draw(glm::mat4 viewProjMat, GLuint shader, bool fill); - void update(glm::vec3 new_pos); - void update_delta(glm::vec3 delta); - + void draw(std::shared_ptr shader, + glm::mat4 viewProj, + glm::vec3 camPos, + glm::vec3 lightPos, + bool fill) override; private: GLuint VAO; GLuint VBO_positions, VBO_normals, EBO; - glm::mat4 model; glm::vec3 color; - // Cube Information std::vector positions; std::vector normals; diff --git a/include/client/model.hpp b/include/client/model.hpp index 6797ab99..74be2229 100644 --- a/include/client/model.hpp +++ b/include/client/model.hpp @@ -12,6 +12,7 @@ #include #include "assimp/material.h" +#include "client/renderable.hpp" #include "client/shader.hpp" /** @@ -64,7 +65,7 @@ struct Material { * smaller meshes. This is useful for animating parts of model individual (ex: legs, * arms, head) */ -class Mesh { +class Mesh : public Renderable { public: /** * Creates a new mesh from a collection of vertices, indices and textures @@ -84,7 +85,11 @@ class Mesh { * @param modelView determines the scaling/rotation/translation of the * mesh */ - void Draw(std::shared_ptr shader, glm::mat4 model, glm::mat4 viewProj, glm::vec3 camPos, glm::vec3 lightPos); + void draw(std::shared_ptr shader, + glm::mat4 viewProj, + glm::vec3 camPos, + glm::vec3 lightPos, + bool fill) override; private: std::vector vertices; std::vector indices; @@ -96,7 +101,7 @@ class Mesh { }; -class Model { +class Model : public Renderable { public: /** * Loads Model from a given filename. Can be of format @@ -113,7 +118,11 @@ class Model { * @param Shader to use while drawing all the * meshes of the model */ - void Draw(glm::mat4 viewProj, glm::vec3 camPos, std::shared_ptr shader, glm::vec3 lightPos); + void draw(std::shared_ptr shader, + glm::mat4 viewProj, + glm::vec3 camPos, + glm::vec3 lightPos, + bool fill) override; /** * Sets the position of the Model to the given x,y,z @@ -121,7 +130,16 @@ class Model { * * @param vector of x, y, z of the model's new position */ - void TranslateTo(const glm::vec3& new_pos); + void translateAbsolute(const glm::vec3& new_pos); + + /** + * Updates the position of the Model relative to it's + * previous position + * + * @param vector of x, y, z of the change in the Model's + * position + */ + void translateRelative(const glm::vec3& delta); /** * Scale the Model across all axes (x,y,z) @@ -131,9 +149,16 @@ class Model { * Ex: setting it to 0.5 will cut the model's rendered size * in half. */ - void Scale(const float& new_factor); + void scale(const float& new_factor); - void setModelView(const glm::mat4& modelView); + /** + * Scale the model across all axes (x,y,z) + * by the scale factor in each axis. + * + * @param the scale vector describes how much to independently scale + * the model in each axis (x, y, z) + */ + void scale(const glm::vec3& scale); private: std::vector meshes; @@ -141,8 +166,6 @@ class Model { Mesh processMesh(aiMesh* mesh, const aiScene* scene); std::vector loadMaterialTextures(aiMaterial* mat, const aiTextureType& type); - glm::mat4 model; - // store the directory of the model file so that textures can be // loaded relative to the model file std::string directory; diff --git a/include/client/renderable.hpp b/include/client/renderable.hpp new file mode 100644 index 00000000..b0b5f9a6 --- /dev/null +++ b/include/client/renderable.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include + +#include + +#include "client/shader.hpp" + +class Renderable { + public: + Renderable(); + /** + * Draws the renderable item + * + * @param Shader to use while drawing all the + * meshes of the model + * @param + */ + virtual void draw(std::shared_ptr shader, + glm::mat4 viewProj, + glm::vec3 camPos, + glm::vec3 lightPos, + bool fill) = 0; + + /** + * Sets the position of the item to the given x,y,z + * values + * + * @param vector of x, y, z of the 's new position + */ + void translateAbsolute(const glm::vec3& new_pos); + + /** + * Updates the position of the item relative to it's + * previous position + * + * @param vector of x, y, z of the change in the item's + * position + */ + void translateRelative(const glm::vec3& delta); + + /** + * Scale the Model across all axes (x,y,z) + * by a factor + * + * @param new_factor describes how much to scale the model by. + * Ex: setting it to 0.5 will cut the model's rendered size + * in half. + */ + void scale(const float& new_factor); + + /** + * Scale the item across all axes (x,y,z) + * by the scale factor in each axis. + * + * @param the scale vector describes how much to independently scale + * the item in each axis (x, y, z) + */ + void scale(const glm::vec3& scale); + + /** + * Gets the model matrix given all the transformations + * applied to it + * + * @return updated model matrix + */ + glm::mat4 getModelMat(); + private: + glm::mat4 model; +}; diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 199ec06c..6fe0794a 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -11,6 +11,7 @@ set(FILES shader.cpp model.cpp lightsource.cpp + renderable.cpp ${imgui-source} ) diff --git a/src/client/client.cpp b/src/client/client.cpp index dd1aa1ec..fda63733 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -11,7 +11,9 @@ #include "client/lightsource.hpp" #include "client/shader.hpp" #include "client/model.hpp" +#include "glm/fwd.hpp" #include "shared/game/event.hpp" +#include "shared/game/sharedobject.hpp" #include "shared/network/constants.hpp" #include "shared/network/packet.hpp" #include "shared/utilities/config.hpp" @@ -121,7 +123,7 @@ bool Client::init() { boost::filesystem::path bear_model_path = graphics_assets_dir / "bear-sp22.obj"; this->bear_model = std::make_unique(bear_model_path.string()); - this->bear_model->Scale(0.25); + this->bear_model->scale(0.25); this->light_source = std::make_unique(); boost::filesystem::path lightVertFilepath = this->root_path / "src/client/shaders/lightsource.vert"; @@ -242,8 +244,13 @@ void Client::draw() { continue; } if (sharedObject->type == ObjectType::Enemy) { - this->bear_model->TranslateTo(sharedObject->physics.position); - this->bear_model->Draw(this->cam->getViewProj(), this->cam->getPos(), this->model_shader, this->cam->getPos()); + this->bear_model->translateAbsolute(sharedObject->physics.position); + this->bear_model->draw( + this->model_shader, + this->cam->getViewProj(), + this->cam->getPos(), + this->cam->getPos(), + true); } // Get camera position from server, update position and don't render player object (or special handling) @@ -256,16 +263,18 @@ void Client::draw() { // If solidsurface, scale cube to given dimensions if(sharedObject->solidSurface.has_value()){ - Cube* cube = new Cube(glm::vec3(0.4f,0.5f,0.7f), sharedObject->solidSurface->dimensions); - cube->update(sharedObject->physics.position); - cube->draw(this->cam->getViewProj(), this->cube_shader->getID(), true); + std::cout << "solid surface has type " << objectTypeString(sharedObject->type) << std::endl; + Cube* cube = new Cube(glm::vec3(0.4f,0.5f,0.7f)); + cube->scale( sharedObject->solidSurface->dimensions); + cube->translateAbsolute(sharedObject->physics.position); + cube->draw(this->cube_shader, this->cam->getViewProj(), this->cam->getPos(), glm::vec3(), true); continue; } - // tmp: all objects are cubes - Cube* cube = new Cube(glm::vec3(0.0f,1.0f,1.0f), glm::vec3(1.0f)); - cube->update(sharedObject->physics.position); - cube->draw(this->cam->getViewProj(), this->cube_shader->getID(), false); + // original center cube because why not + Cube* cube = new Cube(glm::vec3(0.0f,1.0f,1.0f)); + cube->translateAbsolute(sharedObject->physics.position); + cube->draw(this->cube_shader, this->cam->getViewProj(), this->cam->getPos(), glm::vec3(), false); } } diff --git a/src/client/cube.cpp b/src/client/cube.cpp index 5b01e8ef..163ef89e 100644 --- a/src/client/cube.cpp +++ b/src/client/cube.cpp @@ -1,16 +1,11 @@ #include "client/cube.hpp" -Cube::Cube(glm::vec3 newColor, glm::vec3 scale) { +Cube::Cube(glm::vec3 newColor) { // create a vertex buffer for positions and normals // insert the data into these buffers // initialize model matrix - // Model matrix. glm::vec3 cubeMin = glm::vec3(-1.0f, -1.0f, -1.0f); glm::vec3 cubeMax = glm::vec3(1.0f, 1.0f, 1.0f); - model = glm::mat4(1.0f); - - //scale the cube to with given vector - model = glm::scale(model, scale); // The color of the cube. Try setting it to something else! color = newColor; @@ -139,34 +134,20 @@ Cube::~Cube() { glDeleteVertexArrays(1, &VAO); } -void Cube::draw(glm::mat4 viewProjMat, GLuint shader, bool fill) { - // actiavte the shader program - glUseProgram(shader); - - // Currently 'hardcoding' camera logic in - float FOV = 45.0f; - float Aspect = 1.33f; - float NearClip = 0.1f; - float FarClip = 100.0f; - - float Distance = 10.0f; - float Azimuth = 0.0f; - float Incline = 20.0f; - - glm::mat4 world(1); - world[3][2] = Distance; - world = glm::eulerAngleY(glm::radians(-Azimuth)) * glm::eulerAngleX(glm::radians(-Incline)) * world; +void Cube::draw(std::shared_ptr shader, + glm::mat4 viewProj, + glm::vec3 camPos, + glm::vec3 lightPos, + bool fill) { - // Compute view matrix (inverse of world matrix) - glm::mat4 view = glm::inverse(world); - - // Compute perspective projection matrix - glm::mat4 project = glm::perspective(glm::radians(FOV), Aspect, NearClip, FarClip); + // actiavte the shader program + shader->use(); // get the locations and send the uniforms to the shader - glUniformMatrix4fv(glGetUniformLocation(shader, "viewProj"), 1, false, reinterpret_cast(&viewProjMat)); - glUniformMatrix4fv(glGetUniformLocation(shader, "model"), 1, GL_FALSE, reinterpret_cast(&model)); - glUniform3fv(glGetUniformLocation(shader, "DiffuseColor"), 1, &color[0]); + shader->setMat4("viewProj", viewProj); + auto model = this->getModelMat(); + shader->setMat4("model", model); + shader->setVec3("DiffuseColor", color); // Bind the VAO glBindVertexArray(VAO); @@ -185,11 +166,3 @@ void Cube::draw(glm::mat4 viewProjMat, GLuint shader, bool fill) { glBindVertexArray(0); glUseProgram(0); } - -void Cube::update(glm::vec3 new_pos) { - model[3] = glm::vec4(new_pos, 1.0f); -} - -void Cube::update_delta(glm::vec3 delta) { - model = glm::translate(model, delta); -} \ No newline at end of file diff --git a/src/client/model.cpp b/src/client/model.cpp index c9e43181..d8da0915 100644 --- a/src/client/model.cpp +++ b/src/client/model.cpp @@ -72,23 +72,29 @@ Mesh::Mesh( std::cout << "\t shininess" << this->material.shininess << std::endl; } -void Mesh::Draw(std::shared_ptr shader, glm::mat4 model, glm::mat4 viewProj, glm::vec3 camPos, glm::vec3 lightPos) { +void Mesh::draw( + std::shared_ptr shader, + glm::mat4 viewProj, + glm::vec3 camPos, + glm::vec3 lightPos, + bool fill) { // actiavte the shader program shader->use(); - auto lightColor = glm::vec3(1.0f, 1.0f, 1.0f); - shader->setVec3("lightColor", lightColor); - shader->setVec3("lightPos", lightPos); - - shader->setVec3("viewPos", camPos); - + // vertex shader uniforms shader->setMat4("viewProj", viewProj); + auto model = this->getModelMat(); shader->setMat4("model", model); + // fragment shader uniforms shader->setVec3("material.diffuse", this->material.diffuse); shader->setVec3("material.ambient", this->material.ambient); shader->setVec3("material.specular", this->material.specular); shader->setFloat("material.shininess", this->material.shininess); + shader->setVec3("viewPos", camPos); + auto lightColor = glm::vec3(1.0f, 1.0f, 1.0f); + shader->setVec3("lightColor", lightColor); + shader->setVec3("lightPos", lightPos); if (textures.size() == 0) { } else { @@ -113,14 +119,18 @@ void Mesh::Draw(std::shared_ptr shader, glm::mat4 model, glm::mat4 viewP // draw mesh glBindVertexArray(VAO); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + if(fill){ + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } else { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); glUseProgram(0); } Model::Model(const std::string& filepath) : - model(1.0f), directory(filepath.substr(0, filepath.find_last_of('/'))) { + directory(filepath.substr(0, filepath.find_last_of('/'))) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(filepath, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_SplitLargeMeshes | aiProcess_OptimizeMeshes); @@ -131,22 +141,39 @@ Model::Model(const std::string& filepath) : processNode(scene->mRootNode, scene); } -void Model::Draw(glm::mat4 viewProj, glm::vec3 camPos, std::shared_ptr shader, glm::vec3 lightPos) { - for(Mesh& mesh : this->meshes) - mesh.Draw(shader, this->model, viewProj, camPos, lightPos); +void Model::draw(std::shared_ptr shader, + glm::mat4 viewProj, + glm::vec3 camPos, + glm::vec3 lightPos, + bool fill) { + + for(Mesh& mesh : this->meshes) { + mesh.draw(shader, viewProj, camPos, lightPos, fill); + } +} + +void Model::translateAbsolute(const glm::vec3& new_pos) { + for(Mesh& mesh : this->meshes) { + mesh.translateAbsolute(new_pos); + } } -void Model::TranslateTo(const glm::vec3 &new_pos) { - model[3] = glm::vec4(new_pos, 1.0f); +void Model::translateRelative(const glm::vec3& delta) { + for(Mesh& mesh : this->meshes) { + mesh.translateAbsolute(delta); + } } -void Model::Scale(const float& new_factor) { - glm::vec3 scaleVector(new_factor, new_factor, new_factor); - this->model = glm::scale(this->model, scaleVector); +void Model::scale(const float& new_factor) { + for(Mesh& mesh : this->meshes) { + mesh.scale(new_factor); + } } -void Model::setModelView(const glm::mat4& modelView) { - this->model = modelView; +void Model::scale(const glm::vec3& scale) { + for(Mesh& mesh : this->meshes) { + mesh.scale(scale); + } } void Model::processNode(aiNode *node, const aiScene *scene) { diff --git a/src/client/renderable.cpp b/src/client/renderable.cpp new file mode 100644 index 00000000..5094337c --- /dev/null +++ b/src/client/renderable.cpp @@ -0,0 +1,28 @@ +#include "client/renderable.hpp" + +#include +#define GLM_ENABLE_EXPERIMENTAL +#include + +Renderable::Renderable() : model(1.0f) { } + +void Renderable::translateAbsolute(const glm::vec3 &new_pos) { + this->model[3] = glm::vec4(new_pos, 1.0f); +} + +void Renderable::translateRelative(const glm::vec3& delta) { + this->model = glm::translate(this->model, delta); +} + +void Renderable::scale(const float& new_factor) { + glm::vec3 scaleVector(new_factor, new_factor, new_factor); + this->model = glm::scale(this->model, scaleVector); +} + +void Renderable::scale(const glm::vec3& scale) { + this->model = glm::scale(this->model, scale); +} + +glm::mat4 Renderable::getModelMat() { + return this->model; +} diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 48c1f2b3..0d984189 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -33,7 +33,7 @@ Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); } catch(std::ifstream::failure& e) { - throw std::invalid_argument("Error: could not read shader file"); + throw std::invalid_argument("Error: could not read shader file " + vertexPath + " and " + fragmentPath); } const char* vShaderCode = vertexCode.c_str(); @@ -51,7 +51,7 @@ Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(vertex, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + std::cout << "ERROR: Vertex shader compilation failed\n" << infoLog << std::endl; }; // fragment shader @@ -62,7 +62,7 @@ Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath) { glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(vertex, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; + std::cout << "ERROR: Fragment shader compilation failed\n" << infoLog << std::endl; }; if (vertex == 0 && fragment == 0) { From 914415c38628d1ad1b439376aefc6d87f6c83db1 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 4 May 2024 23:20:46 -0700 Subject: [PATCH 11/18] populated objectTypeToString --- src/shared/game/sharedobject.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/shared/game/sharedobject.cpp b/src/shared/game/sharedobject.cpp index fd112aff..d1521876 100644 --- a/src/shared/game/sharedobject.cpp +++ b/src/shared/game/sharedobject.cpp @@ -4,6 +4,14 @@ std::string objectTypeString(ObjectType type) { switch (type) { case ObjectType::Object: return "Object"; + case ObjectType::Item: + return "Item"; + case ObjectType::SolidSurface: + return "SolidSurface"; + case ObjectType::Player: + return "Player"; + case ObjectType::Enemy: + return "Enemy"; default: return "Unknown"; } From 4bd91e2717bdde03c431799bd7562ee9dac325e7 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 4 May 2024 23:27:44 -0700 Subject: [PATCH 12/18] clean up client draw function --- src/client/client.cpp | 48 +++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index fda63733..4d282174 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -12,6 +12,7 @@ #include "client/shader.hpp" #include "client/model.hpp" #include "glm/fwd.hpp" +#include "server/game/solidsurface.hpp" #include "shared/game/event.hpp" #include "shared/game/sharedobject.hpp" #include "shared/network/constants.hpp" @@ -243,15 +244,6 @@ void Client::draw() { if (sharedObject == nullptr) { continue; } - if (sharedObject->type == ObjectType::Enemy) { - this->bear_model->translateAbsolute(sharedObject->physics.position); - this->bear_model->draw( - this->model_shader, - this->cam->getViewProj(), - this->cam->getPos(), - this->cam->getPos(), - true); - } // Get camera position from server, update position and don't render player object (or special handling) if (this->session->getInfo().client_eid.has_value() && sharedObject->globalID == this->session->getInfo().client_eid.value()) { @@ -261,20 +253,32 @@ void Client::draw() { continue; } - // If solidsurface, scale cube to given dimensions - if(sharedObject->solidSurface.has_value()){ - std::cout << "solid surface has type " << objectTypeString(sharedObject->type) << std::endl; - Cube* cube = new Cube(glm::vec3(0.4f,0.5f,0.7f)); - cube->scale( sharedObject->solidSurface->dimensions); - cube->translateAbsolute(sharedObject->physics.position); - cube->draw(this->cube_shader, this->cam->getViewProj(), this->cam->getPos(), glm::vec3(), true); - continue; + switch (sharedObject->type) { + case ObjectType::Enemy: { + // warren bear is an enemy because why not + this->bear_model->translateAbsolute(sharedObject->physics.position); + this->bear_model->draw( + this->model_shader, + this->cam->getViewProj(), + this->cam->getPos(), + this->cam->getPos(), + true); + break; + } + case ObjectType::SolidSurface: { + Cube* cube = new Cube(glm::vec3(0.4f,0.5f,0.7f)); + cube->scale( sharedObject->solidSurface->dimensions); + cube->translateAbsolute(sharedObject->physics.position); + cube->draw(this->cube_shader, + this->cam->getViewProj(), + this->cam->getPos(), + glm::vec3(), + true); + break; + } + default: + break; } - - // original center cube because why not - Cube* cube = new Cube(glm::vec3(0.0f,1.0f,1.0f)); - cube->translateAbsolute(sharedObject->physics.position); - cube->draw(this->cube_shader, this->cam->getViewProj(), this->cam->getPos(), glm::vec3(), false); } } From 29d68260611d22f4f39baa895b28d800baf5fa00 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 4 May 2024 23:31:39 -0700 Subject: [PATCH 13/18] renamed solid color shaders to cube shader also added some comments to clarify what each shader can and can't do --- src/client/client.cpp | 4 ++-- src/client/shaders/{shader.frag => cube.frag} | 9 ++------- src/client/shaders/{shader.vert => cube.vert} | 3 ++- src/client/shaders/model.frag | 9 ++++----- src/client/shaders/model.vert | 7 ++++--- 5 files changed, 14 insertions(+), 18 deletions(-) rename src/client/shaders/{shader.frag => cube.frag} (63%) rename src/client/shaders/{shader.vert => cube.vert} (90%) diff --git a/src/client/client.cpp b/src/client/client.cpp index 4d282174..0ec27f92 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -114,8 +114,8 @@ bool Client::init() { boost::filesystem::path shaders_dir = this->root_path / "src/client/shaders"; boost::filesystem::path graphics_assets_dir = this->root_path / "assets/graphics"; - boost::filesystem::path cube_vert_path = shaders_dir / "shader.vert"; - boost::filesystem::path cube_frag_path = shaders_dir / "shader.frag"; + boost::filesystem::path cube_vert_path = shaders_dir / "cube.vert"; + boost::filesystem::path cube_frag_path = shaders_dir / "cube.frag"; this->cube_shader = std::make_shared(cube_vert_path.string(), cube_frag_path.string()); boost::filesystem::path model_vert_path = shaders_dir / "model.vert"; diff --git a/src/client/shaders/shader.frag b/src/client/shaders/cube.frag similarity index 63% rename from src/client/shaders/shader.frag rename to src/client/shaders/cube.frag index 3bc9cbee..9c30ceae 100644 --- a/src/client/shaders/shader.frag +++ b/src/client/shaders/cube.frag @@ -1,23 +1,18 @@ #version 330 core -// Inputs to the fragment shader are the outputs of the same name from the vertex shader. -// Note that you do not have access to the vertex shader's default output, gl_Position. +// Fragment shader of solid color, untextured cubes in vec3 fragNormal; in vec3 fragPos; -// uniforms used for lighting uniform vec3 AmbientColor = vec3(0.2); uniform vec3 LightDirection = normalize(vec3(2, 4, 3)); uniform vec3 LightColor = vec3(1.0, 1.0, 1.0); uniform vec3 DiffuseColor = vec3(1.0, 1.0, 1.0); -// You can output many things. The first vec4 type output determines the color of the fragment out vec4 fragColor; -void main() -{ - +void main() { // Compute irradiance (sum of ambient & direct lighting) vec3 irradiance = AmbientColor + LightColor * max(0, dot(LightDirection, fragNormal)); diff --git a/src/client/shaders/shader.vert b/src/client/shaders/cube.vert similarity index 90% rename from src/client/shaders/shader.vert rename to src/client/shaders/cube.vert index a3f529c8..2ae4fdda 100644 --- a/src/client/shaders/shader.vert +++ b/src/client/shaders/cube.vert @@ -1,5 +1,6 @@ #version 330 core -// NOTE: Do NOT use any version older than 330! Bad things will happen! +# +// Fragment shader of solid color, untextured cubes layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal; diff --git a/src/client/shaders/model.frag b/src/client/shaders/model.frag index b737a5bc..18572321 100644 --- a/src/client/shaders/model.frag +++ b/src/client/shaders/model.frag @@ -1,7 +1,8 @@ #version 330 core -// Inputs to the fragment shader are the outputs of the same name from the vertex shader. -// Note that you do not have access to the vertex shader's default output, gl_Position. +// Fragment shader for loaded models. +// This shader currently expects textured models. Untextured +// models will show up as black. in vec3 fragNormal; in vec3 fragPos; @@ -21,11 +22,9 @@ uniform vec3 viewPos; uniform vec3 lightPos; uniform vec3 lightColor; -// You can output many things. The first vec4 type output determines the color of the fragment out vec4 fragColor; -void main() -{ +void main() { // ambient vec3 ambient = lightColor * material.ambient; diff --git a/src/client/shaders/model.vert b/src/client/shaders/model.vert index cca0b196..7d681852 100644 --- a/src/client/shaders/model.vert +++ b/src/client/shaders/model.vert @@ -1,5 +1,7 @@ #version 330 core -// NOTE: Do NOT use any version older than 330! Bad things will happen! +# +// Vertex shader for loaded models. +// Also forwards texture coordinates to fragment shader. layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal; @@ -15,8 +17,7 @@ out vec3 fragNormal; out vec3 fragPos; out vec2 TexCoords; -void main() -{ +void main() { // OpenGL maintains the D matrix so you only need to multiply by P, V (aka C inverse), and M gl_Position = viewProj * model * vec4(position, 1.0); From 07dfe93c8ef477e83bc2f462cf226437fb9b1d97 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Sat, 4 May 2024 23:51:05 -0700 Subject: [PATCH 14/18] lint --- include/client/cube.hpp | 2 +- include/client/model.hpp | 8 ++++---- include/client/renderable.hpp | 8 ++++---- include/debugger/debugger.hpp | 2 +- include/server/game/creature.hpp | 2 +- include/server/game/servergamestate.hpp | 2 +- include/shared/game/sharedgamestate.hpp | 2 +- src/client/lightsource.cpp | 5 +---- src/client/model.cpp | 2 +- src/client/shader.cpp | 2 +- src/server/game/enemy.cpp | 4 +++- src/server/game/item.cpp | 2 +- src/server/game/player.cpp | 2 +- src/server/game/servergamestate.cpp | 4 ++-- src/server/game/solidsurface.cpp | 6 +++--- src/server/server.cpp | 12 ++++++------ 16 files changed, 32 insertions(+), 33 deletions(-) diff --git a/include/client/cube.hpp b/include/client/cube.hpp index 6a191736..58cf1574 100644 --- a/include/client/cube.hpp +++ b/include/client/cube.hpp @@ -14,7 +14,7 @@ class Cube : public Renderable { public: - Cube(glm::vec3 newColor); + explicit Cube(glm::vec3 newColor); ~Cube(); void draw(std::shared_ptr shader, diff --git a/include/client/model.hpp b/include/client/model.hpp index 74be2229..27dcb9a5 100644 --- a/include/client/model.hpp +++ b/include/client/model.hpp @@ -130,7 +130,7 @@ class Model : public Renderable { * * @param vector of x, y, z of the model's new position */ - void translateAbsolute(const glm::vec3& new_pos); + void translateAbsolute(const glm::vec3& new_pos) override; /** * Updates the position of the Model relative to it's @@ -139,7 +139,7 @@ class Model : public Renderable { * @param vector of x, y, z of the change in the Model's * position */ - void translateRelative(const glm::vec3& delta); + void translateRelative(const glm::vec3& delta) override; /** * Scale the Model across all axes (x,y,z) @@ -149,7 +149,7 @@ class Model : public Renderable { * Ex: setting it to 0.5 will cut the model's rendered size * in half. */ - void scale(const float& new_factor); + void scale(const float& new_factor) override; /** * Scale the model across all axes (x,y,z) @@ -158,7 +158,7 @@ class Model : public Renderable { * @param the scale vector describes how much to independently scale * the model in each axis (x, y, z) */ - void scale(const glm::vec3& scale); + void scale(const glm::vec3& scale) override; private: std::vector meshes; diff --git a/include/client/renderable.hpp b/include/client/renderable.hpp index b0b5f9a6..a06efa05 100644 --- a/include/client/renderable.hpp +++ b/include/client/renderable.hpp @@ -28,7 +28,7 @@ class Renderable { * * @param vector of x, y, z of the 's new position */ - void translateAbsolute(const glm::vec3& new_pos); + virtual void translateAbsolute(const glm::vec3& new_pos); /** * Updates the position of the item relative to it's @@ -37,7 +37,7 @@ class Renderable { * @param vector of x, y, z of the change in the item's * position */ - void translateRelative(const glm::vec3& delta); + virtual void translateRelative(const glm::vec3& delta); /** * Scale the Model across all axes (x,y,z) @@ -47,7 +47,7 @@ class Renderable { * Ex: setting it to 0.5 will cut the model's rendered size * in half. */ - void scale(const float& new_factor); + virtual void scale(const float& new_factor); /** * Scale the item across all axes (x,y,z) @@ -56,7 +56,7 @@ class Renderable { * @param the scale vector describes how much to independently scale * the item in each axis (x, y, z) */ - void scale(const glm::vec3& scale); + virtual void scale(const glm::vec3& scale); /** * Gets the model matrix given all the transformations diff --git a/include/debugger/debugger.hpp b/include/debugger/debugger.hpp index 6b7e3188..89306510 100644 --- a/include/debugger/debugger.hpp +++ b/include/debugger/debugger.hpp @@ -258,7 +258,7 @@ class CreateCommand : public Command { // Create a new base object in the game state unsigned int globalID = state.objects.createObject(ObjectType::Object); - Object* obj = state.objects.getObject(globalID); + const Object* obj = state.objects.getObject(globalID); // cppcheck-suppress unreadVariable std::cout << "Created new object (global id " << globalID << ")" << std::endl; } diff --git a/include/server/game/creature.hpp b/include/server/game/creature.hpp index dcdd36cf..aee3bbab 100644 --- a/include/server/game/creature.hpp +++ b/include/server/game/creature.hpp @@ -6,7 +6,7 @@ class Creature : public Object { public: - Creature(ObjectType type); + explicit Creature(ObjectType type); ~Creature(); virtual SharedObject toShared() override; diff --git a/include/server/game/servergamestate.hpp b/include/server/game/servergamestate.hpp index b49a030c..9c3a7e3d 100644 --- a/include/server/game/servergamestate.hpp +++ b/include/server/game/servergamestate.hpp @@ -47,7 +47,7 @@ class ServerGameState { */ explicit ServerGameState(GamePhase start_phase); - ServerGameState(GamePhase start_phase, GameConfig config); + ServerGameState(GamePhase start_phase, const GameConfig& config); ~ServerGameState(); diff --git a/include/shared/game/sharedgamestate.hpp b/include/shared/game/sharedgamestate.hpp index f4f9a868..c1a47cc8 100644 --- a/include/shared/game/sharedgamestate.hpp +++ b/include/shared/game/sharedgamestate.hpp @@ -65,7 +65,7 @@ struct SharedGameState { this->lobby.max_players = MAX_PLAYERS; } - SharedGameState(GamePhase start_phase, GameConfig config): + SharedGameState(GamePhase start_phase, const GameConfig& config): objects(std::vector>()) { this->objects.reserve(MAX_NUM_OBJECTS); diff --git a/src/client/lightsource.cpp b/src/client/lightsource.cpp index c53b42e8..7129aaf5 100644 --- a/src/client/lightsource.cpp +++ b/src/client/lightsource.cpp @@ -6,10 +6,7 @@ #include "client/shader.hpp" -LightSource::LightSource() { - model = glm::mat4(1.0f); - // model = glm::scale(model, glm::vec3(0.2f)); - +LightSource::LightSource() : model(1.0f) { glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // we only need to bind to the VBO, the container's VBO's data already contains the data. diff --git a/src/client/model.cpp b/src/client/model.cpp index d8da0915..a20c44d4 100644 --- a/src/client/model.cpp +++ b/src/client/model.cpp @@ -228,7 +228,7 @@ Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene) { aiColor3D diffuse_color; aiColor3D ambient_color; aiColor3D specular_color; - float shininess; + float shininess = 0.0f; if(mesh->mMaterialIndex >= 0) { std::cout << "processing material of id: " << mesh->mMaterialIndex << std::endl; diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 0d984189..437c115c 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -118,7 +118,7 @@ void Shader::setVec3(const std::string &name, glm::vec3& value) { glm::vec3 Shader::getVec3(const std::string &name) { glm::vec3 vec; - glGetUniformfv(ID, glGetUniformLocation(ID, name.c_str()), (float*)&vec); + glGetUniformfv(ID, glGetUniformLocation(ID, name.c_str()), reinterpret_cast(&vec)); return vec; } diff --git a/src/server/game/enemy.cpp b/src/server/game/enemy.cpp index d1c331a6..61119d71 100644 --- a/src/server/game/enemy.cpp +++ b/src/server/game/enemy.cpp @@ -6,6 +6,8 @@ SharedObject Enemy::toShared() { return so; } -Enemy::Enemy() : Creature(ObjectType::Enemy) {} +Enemy::Enemy() : Creature(ObjectType::Enemy) { + this->stats = EnemyStats { 100 }; +} Enemy::~Enemy() {} \ No newline at end of file diff --git a/src/server/game/item.cpp b/src/server/game/item.cpp index dbb256bf..e655869d 100644 --- a/src/server/game/item.cpp +++ b/src/server/game/item.cpp @@ -2,7 +2,7 @@ #include "shared/game/sharedobject.hpp" /* Constructors and Destructors */ -Item::Item() : Object(ObjectType::Item) { +Item::Item() : Object(ObjectType::Item) { // cppcheck-suppress uninitMemberVar } diff --git a/src/server/game/player.cpp b/src/server/game/player.cpp index 95473d44..7082da9a 100644 --- a/src/server/game/player.cpp +++ b/src/server/game/player.cpp @@ -8,7 +8,7 @@ SharedObject Player::toShared() { } Player::Player() : Creature(ObjectType::Player) { - + this->stats = PlayerStats{ 100 }; } Player::~Player() { diff --git a/src/server/game/servergamestate.cpp b/src/server/game/servergamestate.cpp index e34e06a8..5d316637 100644 --- a/src/server/game/servergamestate.cpp +++ b/src/server/game/servergamestate.cpp @@ -3,7 +3,7 @@ /* Constructors and Destructors */ -ServerGameState::ServerGameState(GamePhase start_phase, GameConfig config) { +ServerGameState::ServerGameState(GamePhase start_phase, const GameConfig& config) { this->phase = start_phase; this->timestep = FIRST_TIMESTEP; this->timestep_length = config.game.timestep_length_ms; @@ -159,7 +159,7 @@ void ServerGameState::useItem() { SmartVector items = this->objects.getItems(); for (int i = 0; i < items.size(); i++) { - Item* item = items.get(i); + const Item* item = items.get(i); if (item == nullptr) continue; diff --git a/src/server/game/solidsurface.cpp b/src/server/game/solidsurface.cpp index 04d2c6db..8f3171e4 100644 --- a/src/server/game/solidsurface.cpp +++ b/src/server/game/solidsurface.cpp @@ -9,9 +9,9 @@ SolidSurface::~SolidSurface() {} /* SharedGameState generation */ SharedObject SolidSurface::toShared() { - SharedObject shared = Object::toShared(); + SharedObject sharedSolidSurface = Object::toShared(); - shared.solidSurface = this->shared; + sharedSolidSurface.solidSurface = this->shared; - return shared; + return sharedSolidSurface; } \ No newline at end of file diff --git a/src/server/server.cpp b/src/server/server.cpp index 34fd5714..5e3a9df2 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -38,7 +38,7 @@ Server::Server(boost::asio::io_context& io_context, GameConfig config) state.objects.createObject(ObjectType::Object); EntityID bearID = state.objects.createObject(ObjectType::Enemy); - Enemy* bear = (Enemy*)state.objects.getObject(bearID); + Enemy* bear = reinterpret_cast(state.objects.getObject(bearID)); bear->physics.shared.position = glm::vec3(0.0f, -1.3f, 0.0f); // Create a room @@ -57,11 +57,11 @@ Server::Server(boost::asio::io_context& io_context, GameConfig config) // # # // ##4## - SolidSurface* wall1 = (SolidSurface*)state.objects.getObject(wall1ID); - SolidSurface* wall2 = (SolidSurface*)state.objects.getObject(wall2ID); - SolidSurface* wall3 = (SolidSurface*)state.objects.getObject(wall3ID); - SolidSurface* wall4 = (SolidSurface*)state.objects.getObject(wall4ID); - SolidSurface* floor = (SolidSurface*)state.objects.getObject(floorID); + SolidSurface* wall1 = reinterpret_cast(state.objects.getObject(wall1ID)); + SolidSurface* wall2 = reinterpret_cast(state.objects.getObject(wall2ID)); + SolidSurface* wall3 = reinterpret_cast(state.objects.getObject(wall3ID)); + SolidSurface* wall4 = reinterpret_cast(state.objects.getObject(wall4ID)); + SolidSurface* floor = reinterpret_cast(state.objects.getObject(floorID)); // Wall1 has dimensions (20, 4, 1); and position (0, 0, -19.5) wall1->shared.dimensions = glm::vec3(20, 4, 1); From 70a9903314b61d5fe9a22f8e1dcbfe0252c8a2c6 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Tue, 7 May 2024 11:11:57 -0700 Subject: [PATCH 15/18] add player to camera pos also mess with model shading a bit more --- include/client/client.hpp | 1 + include/client/lightsource.hpp | 2 +- src/client/client.cpp | 33 ++++++++++++++++++++++++++++++--- src/client/lightsource.cpp | 27 +++------------------------ src/client/shaders/model.frag | 8 +++++--- src/server/server.cpp | 2 +- 6 files changed, 41 insertions(+), 32 deletions(-) diff --git a/include/client/client.hpp b/include/client/client.hpp index 462bc5ea..306329d4 100644 --- a/include/client/client.hpp +++ b/include/client/client.hpp @@ -62,6 +62,7 @@ class Client { std::shared_ptr model_shader; std::shared_ptr light_source_shader; + std::unique_ptr player_model; std::unique_ptr bear_model; std::unique_ptr light_source; diff --git a/include/client/lightsource.hpp b/include/client/lightsource.hpp index bdacab5e..a7256107 100644 --- a/include/client/lightsource.hpp +++ b/include/client/lightsource.hpp @@ -16,7 +16,7 @@ class LightSource { public: LightSource(); - void draw(std::shared_ptr shader); + void draw(std::shared_ptr shader, glm::mat4 viewProj); void TranslateTo(const glm::vec3& new_pos); glm::vec3 lightPos; diff --git a/src/client/client.cpp b/src/client/client.cpp index 0ec27f92..50870424 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -126,7 +126,12 @@ bool Client::init() { this->bear_model = std::make_unique(bear_model_path.string()); this->bear_model->scale(0.25); + boost::filesystem::path player_model_path = graphics_assets_dir / "Fire-testing.obj"; + this->player_model = std::make_unique(player_model_path.string()); + this->player_model->scale(0.25); + this->light_source = std::make_unique(); + boost::filesystem::path lightVertFilepath = this->root_path / "src/client/shaders/lightsource.vert"; boost::filesystem::path lightFragFilepath = this->root_path / "src/client/shaders/lightsource.frag"; this->light_source_shader = std::make_shared(lightVertFilepath.string(), lightFragFilepath.string()); @@ -248,21 +253,43 @@ void Client::draw() { // Get camera position from server, update position and don't render player object (or special handling) if (this->session->getInfo().client_eid.has_value() && sharedObject->globalID == this->session->getInfo().client_eid.value()) { cam->updatePos(sharedObject->physics.position); - this->light_source->TranslateTo(cam->getPos()); - this->light_source->draw(this->light_source_shader); + auto lightPos = glm::vec3(-5.0f, 0.0f, 0.0f); + auto player_pos = glm::vec3(this->cam->getPos().x, this->cam->getPos().y - 20.0f, this->cam->getPos().z); + this->player_model->translateAbsolute(sharedObject->physics.position); + this->player_model->draw( + this->model_shader, + this->cam->getViewProj(), + player_pos, + lightPos, + true); continue; } switch (sharedObject->type) { case ObjectType::Enemy: { // warren bear is an enemy because why not + // auto pos = glm::vec3(0.0f, 0.0f, 0.0f); + auto lightPos = glm::vec3(-5.0f, 0.0f, 0.0f); this->bear_model->translateAbsolute(sharedObject->physics.position); this->bear_model->draw( this->model_shader, this->cam->getViewProj(), this->cam->getPos(), - this->cam->getPos(), + lightPos, true); + + this->light_source->TranslateTo(lightPos); + this->light_source->draw( + this->light_source_shader, + this->cam->getViewProj()); + + // Cube* cube = new Cube(glm::vec3(0.4f,0.5f,0.7f)); + // cube->translateAbsolute(lightPos); + // cube->draw(this->cube_shader, + // this->cam->getViewProj(), + // this->cam->getPos(), + // glm::vec3(), + // false); break; } case ObjectType::SolidSurface: { diff --git a/src/client/lightsource.cpp b/src/client/lightsource.cpp index 7129aaf5..363959d8 100644 --- a/src/client/lightsource.cpp +++ b/src/client/lightsource.cpp @@ -16,33 +16,12 @@ LightSource::LightSource() : model(1.0f) { glEnableVertexAttribArray(0); } -void LightSource::draw(std::shared_ptr shader) { +void LightSource::draw(std::shared_ptr shader, + glm::mat4 viewProj) { shader->use(); - // Currently 'hardcoding' camera logic in - float FOV = 45.0f; - float Aspect = 1.33f; - float NearClip = 0.1f; - float FarClip = 100.0f; - - float Distance = 10.0f; - float Azimuth = 0.0f; - float Incline = 20.0f; - - glm::mat4 world(1); - world[3][2] = Distance; - world = glm::eulerAngleY(glm::radians(-Azimuth)) * glm::eulerAngleX(glm::radians(-Incline)) * world; - - // Compute view matrix (inverse of world matrix) - glm::mat4 view = glm::inverse(world); - - // Compute perspective projection matrix - glm::mat4 project = glm::perspective(glm::radians(FOV), Aspect, NearClip, FarClip); - - // Compute final view-projection matrix - glm::mat4 viewProjMtx = project * view; // get the locations and send the uniforms to the shader - shader->setMat4("viewProj", viewProjMtx); + shader->setMat4("viewProj", viewProj); shader->setMat4("model", model); // draw the light cube object diff --git a/src/client/shaders/model.frag b/src/client/shaders/model.frag index 18572321..e08d85d3 100644 --- a/src/client/shaders/model.frag +++ b/src/client/shaders/model.frag @@ -26,13 +26,13 @@ out vec4 fragColor; void main() { // ambient - vec3 ambient = lightColor * material.ambient; + vec3 ambient = lightColor * vec3(texture(material.texture_diffuse1, TexCoords)); // diffuse vec3 norm = normalize(fragNormal); vec3 lightDir = normalize(lightPos - fragPos); float diff = max(dot(norm, lightDir), 0.0); - vec3 diffuse = lightColor * (diff * material.diffuse); + vec3 diffuse = lightColor * (diff * vec3(texture(material.texture_diffuse1, TexCoords))); // specular vec3 viewDir = normalize(viewPos - fragPos); @@ -41,5 +41,7 @@ void main() { vec3 specular = lightColor * (spec * material.specular); vec3 result = ambient + diffuse + specular; - fragColor = vec4(result, 1.0) * vec4(texture(material.texture_diffuse1, TexCoords)); + fragColor = vec4(result, 1.0); + // * vec4(texture(material.texture_diffuse1, TexCoords)); + // fragColor = vec4(0.0, 1.0, 1.0, 1.0); } diff --git a/src/server/server.cpp b/src/server/server.cpp index 5e3a9df2..204faa10 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -39,7 +39,7 @@ Server::Server(boost::asio::io_context& io_context, GameConfig config) EntityID bearID = state.objects.createObject(ObjectType::Enemy); Enemy* bear = reinterpret_cast(state.objects.getObject(bearID)); - bear->physics.shared.position = glm::vec3(0.0f, -1.3f, 0.0f); + bear->physics.shared.position = glm::vec3(0.0f, 50.0f, 0.0f); // Create a room EntityID wall1ID = state.objects.createObject(ObjectType::SolidSurface); From ca99983c39cb4ddda8920051ee42f18931bbe716 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Tue, 7 May 2024 11:32:17 -0700 Subject: [PATCH 16/18] windows fixes --- src/client/client.cpp | 4 ++-- src/client/model.cpp | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index 50870424..45835ee9 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -278,10 +278,10 @@ void Client::draw() { lightPos, true); - this->light_source->TranslateTo(lightPos); + /* this->light_source->TranslateTo(lightPos); this->light_source->draw( this->light_source_shader, - this->cam->getViewProj()); + this->cam->getViewProj());*/ // Cube* cube = new Cube(glm::vec3(0.4f,0.5f,0.7f)); // cube->translateAbsolute(lightPos); diff --git a/src/client/model.cpp b/src/client/model.cpp index a20c44d4..38f7200c 100644 --- a/src/client/model.cpp +++ b/src/client/model.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "assimp/material.h" #include "assimp/types.h" @@ -129,8 +130,8 @@ void Mesh::draw( glUseProgram(0); } -Model::Model(const std::string& filepath) : - directory(filepath.substr(0, filepath.find_last_of('/'))) { +Model::Model(const std::string& filepath) { + this->directory = std::filesystem::path(filepath).parent_path().string(); Assimp::Importer importer; const aiScene *scene = importer.ReadFile(filepath, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_SplitLargeMeshes | aiProcess_OptimizeMeshes); @@ -277,8 +278,8 @@ std::vector Model::loadMaterialTextures(aiMaterial* mat, const aiTextur for(unsigned int i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); - std::string textureFilepath = this->directory + "/" + std::string(str.C_Str()); - Texture texture(textureFilepath, type); + std::filesystem::path textureFilepath = std::filesystem::path(this->directory) / std::string(str.C_Str()); + Texture texture(textureFilepath.string(), type); textures.push_back(texture); } return textures; @@ -306,9 +307,10 @@ Texture::Texture(const std::string& filepath, const aiTextureType& type) { if (!data) { std::cout << "Texture failed to load at path: " << filepath << std::endl; stbi_image_free(data); + throw std::exception(); } std::cout << "Succesfully loaded texture at " << filepath << std::endl; - GLenum format; + GLenum format = GL_RED; if (nrComponents == 1) format = GL_RED; else if (nrComponents == 3) From 5cc73458c4204e25a76ee69e3136c68114f41954 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Tue, 7 May 2024 11:53:17 -0700 Subject: [PATCH 17/18] see other players and don't render yourself --- src/client/client.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index 45835ee9..4953b278 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -253,19 +253,26 @@ void Client::draw() { // Get camera position from server, update position and don't render player object (or special handling) if (this->session->getInfo().client_eid.has_value() && sharedObject->globalID == this->session->getInfo().client_eid.value()) { cam->updatePos(sharedObject->physics.position); - auto lightPos = glm::vec3(-5.0f, 0.0f, 0.0f); - auto player_pos = glm::vec3(this->cam->getPos().x, this->cam->getPos().y - 20.0f, this->cam->getPos().z); - this->player_model->translateAbsolute(sharedObject->physics.position); - this->player_model->draw( - this->model_shader, - this->cam->getViewProj(), - player_pos, - lightPos, - true); - continue; + //continue; } switch (sharedObject->type) { + case ObjectType::Player: { + // don't render yourself + if (this->session->getInfo().client_eid.has_value() && sharedObject->globalID == this->session->getInfo().client_eid.value()) { + break; + } + auto lightPos = glm::vec3(-5.0f, 0.0f, 0.0f); + auto player_pos = glm::vec3(this->cam->getPos().x, this->cam->getPos().y - 20.0f, this->cam->getPos().z); + this->player_model->translateAbsolute(sharedObject->physics.position); + this->player_model->draw( + this->model_shader, + this->cam->getViewProj(), + player_pos, + lightPos, + true); + break; + } case ObjectType::Enemy: { // warren bear is an enemy because why not // auto pos = glm::vec3(0.0f, 0.0f, 0.0f); From 8ef42f9d51076778ff8e320fcf43d672433eebc2 Mon Sep 17 00:00:00 2001 From: Anthony Tarbinian Date: Tue, 7 May 2024 12:24:05 -0700 Subject: [PATCH 18/18] rendering other players works?! --- src/client/client.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index 4953b278..250ef693 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -19,6 +19,7 @@ #include "shared/network/packet.hpp" #include "shared/utilities/config.hpp" + using namespace boost::asio::ip; using namespace std::chrono_literals; @@ -252,23 +253,25 @@ void Client::draw() { // Get camera position from server, update position and don't render player object (or special handling) if (this->session->getInfo().client_eid.has_value() && sharedObject->globalID == this->session->getInfo().client_eid.value()) { - cam->updatePos(sharedObject->physics.position); - //continue; } switch (sharedObject->type) { case ObjectType::Player: { // don't render yourself if (this->session->getInfo().client_eid.has_value() && sharedObject->globalID == this->session->getInfo().client_eid.value()) { + cam->updatePos(sharedObject->physics.position); break; } auto lightPos = glm::vec3(-5.0f, 0.0f, 0.0f); - auto player_pos = glm::vec3(this->cam->getPos().x, this->cam->getPos().y - 20.0f, this->cam->getPos().z); - this->player_model->translateAbsolute(sharedObject->physics.position); + // subtracting 1 from y position to render players "standing" on ground + auto player_pos = glm::vec3(sharedObject->physics.position.x, sharedObject->physics.position.y - 1.0f, sharedObject->physics.position.z); + + + this->player_model->translateAbsolute(player_pos); this->player_model->draw( this->model_shader, this->cam->getViewProj(), - player_pos, + this->cam->getPos(), lightPos, true); break;