diff --git a/data/shaders/basic.frag b/data/shaders/basic.frag index e8b0e88..4805a70 100644 --- a/data/shaders/basic.frag +++ b/data/shaders/basic.frag @@ -111,7 +111,7 @@ void main() { //fragmentColor += spotLightContribution(u_spotLight, normal, v_fragmentPositionTangent, viewDir); f_color = vec4(fragmentColor, 1.0f); - + f_color = vec4(0.95f, 0.16f, 0.33f, 1.0f); } vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 viewDir) { diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index b574f61..ef50766 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -2,6 +2,7 @@ option(SPDLOG_NO_EXCEPTIONS "" ON) set(TINYGLTF_HEADER_ONLY OFF CACHE INTERNAL "" FORCE) set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE) +set(TINYGLTF_NOEXCEPTION OFF CACHE INTERNAL "" FORCE) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/glad) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/entt) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 931ad7f..c9d1dad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ target_link_libraries( fmt pthread spdlog + tinygltf ) add_executable(Fall-Fever diff --git a/src/Controller.cpp b/src/Controller.cpp index b98ca64..b6ce73d 100644 --- a/src/Controller.cpp +++ b/src/Controller.cpp @@ -1,12 +1,12 @@ #include "Controller.h" #include "Camera.h" -#include "Entity.h" #include "FrameBuffer.h" #include "Helper.h" -#include "Light.h" -#include "Scene.h" +#include "Mesh.h" #include "ShaderProgram.h" #include "Window.h" +#include "definitions/attribute_locations.h" +#include "resources/Model.h" #include "util/Log.h" #include @@ -21,6 +21,73 @@ Controller::Controller() m_postProcessFrameBuffer(m_gameWindow->dimensions().first, m_gameWindow->dimensions().second, postProcessingProgram) { + tinygltf::TinyGLTF loader; + + std::string err; + std::string warn; + bool ret = loader.LoadASCIIFromFile(&m_model, &err, &warn, "glTF/ABeautifulGame.gltf"); + // bool ret = loader.LoadASCIIFromFile(&m_model, &err, &warn, "minimal.gltf"); + + if (!warn.empty()) { + Log::logger().warn("{}", warn); + } + + if (!err.empty()) { + Log::logger().error("{}", err); + } + + if (!ret) { + Log::logger().error("Failed to parse glTF"); + } + + defaultProgram.bind(); + AttributeLocations locations{}; + + locations.position = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_position"); + locations.normal = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_normal"); + locations.uv = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_texCoord"); + + ShaderProgram::unbind(); + + std::vector models; + for (auto const &mesh : m_model.meshes) { + std::vector meshes; + for (auto const &primitive : mesh.primitives) { + meshes.emplace_back(Mesh({primitive, m_model, locations}, {})); + } + models.emplace_back(Model(mesh.name, std::move(meshes))); + } + m_models = std::move(models); + + std::vector entities; + for (auto const &node : m_model.nodes) { + ModelEntity entity(Entity::Prototype(node.name, {}, {}, 1.0F), m_models[static_cast(node.mesh)], + defaultProgram); + + if (!node.translation.empty()) { + entity.setPosition(glm::vec3(node.translation[0], node.translation[1], node.translation[2])); + } + + if (!node.rotation.empty()) { + entity.setRotation( + glm::eulerAngles(glm::quat(node.rotation[3], node.rotation[0], node.rotation[1], node.rotation[2]))); + } + + if (!node.scale.empty()) { + entity.setScale(node.scale[0]); + } + + entities.push_back(std::move(entity)); + + for (auto const &child : node.children) { + if (!node.translation.empty()) { + entities[child].translate(glm::vec3(node.translation[0], node.translation[1], node.translation[2])); + } + } + + Log::logger().info("Load node {}.", node.name); + } + m_entities = std::move(entities); } void Controller::run() @@ -29,7 +96,7 @@ void Controller::run() m_camera->translate(glm::vec3(0., 1.5, 5.)); - Log::logger().info("Startup complete."); + Log::logger().info("Startup complete. Enter game loop."); // This is the game loop while (glfwWindowShouldClose(&m_gameWindow->glfw_window()) == GLFW_FALSE) { @@ -40,7 +107,7 @@ void Controller::run() // --- Update game --- lightProgram.bind(); lightProgram.setUniform("v_lightColor", glm::vec3{1., 1., 1.} * 100.0F); - lightProgram.unbind(); + ShaderProgram::unbind(); // --- Render and buffer swap --- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -51,6 +118,13 @@ void Controller::run() m_camera->lookForward(); m_camera->updateVPM(); + // Draw scene + defaultProgram.bind(); + for (auto const &entity : m_entities) { + entity.draw(m_camera->getViewProj(), m_camera->getPosition()); + } + ShaderProgram::unbind(); + m_postProcessFrameBuffer.unbind(); m_postProcessFrameBuffer.drawOnEntireScreen(); @@ -68,7 +142,6 @@ void Controller::run() auto const &key_input = m_gameWindow->key_input(); auto const &mouse_cursor_input = m_gameWindow->mouse_cursor_input(); - // auto const &mouse_button_input = m_gameWindow->mouse_button_input(); m_camera->updatePositionFromKeyboardInput(key_input, (float)m_deltaTime); diff --git a/src/Controller.h b/src/Controller.h index 546ae09..a1b07c9 100644 --- a/src/Controller.h +++ b/src/Controller.h @@ -2,9 +2,13 @@ #include "FrameBuffer.h" #include "ShaderProgram.h" +#include "VertexArray.h" +#include "resources/Model.h" +#include "Entity.h" #include #include +#include #include class Window; @@ -39,6 +43,11 @@ private: static constexpr unsigned MAX_FPS = 60; + tinygltf::Model m_model; + + std::vector m_entities; + std::vector m_models; + double m_deltaTime{}; float m_exposure = 1.0; }; diff --git a/src/Entity.cpp b/src/Entity.cpp index 2bb0bfc..7567e05 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -12,10 +12,8 @@ uint32_t Entity::s_idCounter = 0; Entity::Entity(const std::string &name) : m_id(s_idCounter++), m_uniqueName(name) -{} - -Entity::~Entity() -{} +{ +} uint32_t Entity::getId() const { @@ -93,7 +91,7 @@ glm::mat4 Entity::getModelMatrix() const return m_modelMatrix; } -ModelEntity::ModelEntity(Prototype prototype, const Model *model, ShaderProgram *shaderProgram) +ModelEntity::ModelEntity(Entity::Prototype prototype, Model const &model, ShaderProgram const &shaderProgram) : Entity(prototype.name), m_model(model), m_shaderProgram(shaderProgram) { setPosition(prototype.position); @@ -101,27 +99,27 @@ ModelEntity::ModelEntity(Prototype prototype, const Model *model, ShaderProgram setScale(prototype.scale); } -void ModelEntity::draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) +void ModelEntity::draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) const { - m_shaderProgram->bind(); + m_shaderProgram.bind(); glm::mat4 modelViewProj = viewProjMatrix * m_modelMatrix; - m_shaderProgram->setUniform("u_modelViewProjMatrix", modelViewProj); - m_shaderProgram->setUniform("u_modelMatrix", m_modelMatrix); + m_shaderProgram.setUniform("u_modelViewProjMatrix", modelViewProj); + m_shaderProgram.setUniform("u_modelMatrix", m_modelMatrix); glm::mat3 normalMatrix = glm::mat3(m_modelMatrix); normalMatrix = glm::transpose(glm::inverse(normalMatrix)); - m_shaderProgram->setUniform("u_normalMatrix", normalMatrix); + m_shaderProgram.setUniform("u_normalMatrix", normalMatrix); - m_shaderProgram->setUniform("u_viewPosition", viewPosition); + m_shaderProgram.setUniform("u_viewPosition", viewPosition); // Draw the model - m_model->draw(m_shaderProgram); + m_model.draw(m_shaderProgram); - m_shaderProgram->unbind(); + m_shaderProgram.unbind(); } -void ModelEntity::drawDirectionalShadows(glm::mat4 viewProjMatrix, ShaderProgram *shaderProgram) +void ModelEntity::drawDirectionalShadows(glm::mat4 viewProjMatrix, ShaderProgram *shaderProgram) const { shaderProgram->bind(); @@ -129,19 +127,19 @@ void ModelEntity::drawDirectionalShadows(glm::mat4 viewProjMatrix, ShaderProgram shaderProgram->setUniform("u_modelViewProjMatrix", modelViewProj); // Draw the model - m_model->drawWithoutTextures(); + m_model.drawWithoutTextures(); shaderProgram->unbind(); } -void ModelEntity::drawPointShadows(ShaderProgram *shaderProgram) +void ModelEntity::drawPointShadows(ShaderProgram *shaderProgram) const { shaderProgram->bind(); shaderProgram->setUniform("u_modelMatrix", m_modelMatrix); // Draw the model - m_model->drawWithoutTextures(); + m_model.drawWithoutTextures(); shaderProgram->unbind(); } diff --git a/src/Entity.h b/src/Entity.h index 89cc269..2d94c35 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -20,7 +20,8 @@ public: { Prototype(const std::string &_name, glm::vec3 _position, glm::vec3 _rotation, float _scale) : name(_name), position(_position), rotation(_rotation), scale(_scale) - {} + { + } virtual ~Prototype() = default; std::string name; @@ -30,7 +31,7 @@ public: }; Entity(const std::string &name); - virtual ~Entity() = 0; + virtual ~Entity() = default; uint32_t getId() const; const std::string &getUniqueName() const; @@ -64,26 +65,15 @@ protected: class ModelEntity : public Entity { public: - struct Prototype : public Entity::Prototype - { - Prototype(const std::string &_name, glm::vec3 _position, glm::vec3 _rotation, float _scale, - std::string _modelName, std::string _shaderProgramName) - : Entity::Prototype(_name, _position, _rotation, _scale), modelName(std::move(_modelName)), - shaderProgramName(std::move(_shaderProgramName)) - {} - std::string modelName; - std::string shaderProgramName; - }; + ModelEntity(Entity::Prototype prototype, Model const &model, ShaderProgram const &shaderProgram); - ModelEntity(Prototype prototype, const Model *model, ShaderProgram *shaderProgram); - - void draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition); - void drawDirectionalShadows(glm::mat4 viewProjMatrix, ShaderProgram *p_shaderProgram); - void drawPointShadows(ShaderProgram *p_shaderProgram); + void draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) const; + void drawDirectionalShadows(glm::mat4 viewProjMatrix, ShaderProgram *p_shaderProgram) const; + void drawPointShadows(ShaderProgram *p_shaderProgram) const; private: - const Model *m_model; - ShaderProgram *m_shaderProgram; + Model const &m_model; + ShaderProgram const &m_shaderProgram; }; class Skybox diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 395b49e..546252c 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -1,65 +1,57 @@ #include "Mesh.h" + #include "ShaderProgram.h" #include "VertexArray.h" #include "resources/ResourceHandler.h" #include "resources/Texture.h" +#include -Mesh::Mesh(std::vector vertices, std::vector indices, std::vector textures) - : m_preInitializationVertexData{vertices, indices}, m_numElements(static_cast(indices.size())), - m_textures(textures) +Mesh::Mesh(VertexArray vertexArray, std::vector textures) + : m_vertexArray(std::move(vertexArray)), m_textures(std::move(textures)) { } -void Mesh::initializeOnGPU() +void Mesh::draw(ShaderProgram const &shaderProgram) const { - m_vertexArray = new VertexArray(static_cast(m_preInitializationVertexData.vertices.data()), - static_cast(m_preInitializationVertexData.indices.data()), - static_cast(m_preInitializationVertexData.vertices.size()), - static_cast(m_preInitializationVertexData.indices.size())); -} + std::array(TextureType::TEXTURE_TYPE_NUM_ITEMS)> typeNumberCount{}; -Mesh::~Mesh() -{ - delete m_vertexArray; -} - -void Mesh::draw(ShaderProgram *shaderProgram) -{ - uint8_t typeNumberCount[static_cast(TextureType::TEXTURE_TYPE_NUM_ITEMS)]{0}; glBindTexture(GL_TEXTURE_2D, 0); // Bind all textures in order to its texture unit - std::size_t i = 0; - for (auto it : m_textures) { - auto texture = std::static_pointer_cast(ResourceHandler::instance().resource(it)); + std::size_t textureNum = 0; + for (auto textureIt : m_textures) { + auto texture = std::static_pointer_cast(ResourceHandler::instance().resource(textureIt)); TextureType currentTextureType = texture->textureType(); - texture->bind(static_cast(i), shaderProgram, typeNumberCount[static_cast(currentTextureType)]); + texture->bind(static_cast(textureNum), shaderProgram, + typeNumberCount.at(static_cast(currentTextureType))); - typeNumberCount[static_cast(currentTextureType)] += 1; + typeNumberCount.at(static_cast(currentTextureType)) += 1; - i++; + textureNum++; } // Draw elements - m_vertexArray->bind(); - glDrawElements(GL_TRIANGLES, static_cast(m_numElements), GL_UNSIGNED_INT, 0); - m_vertexArray->unbind(); + m_vertexArray.bind(); + glDrawElements(GL_TRIANGLES, static_cast(m_vertexArray.indicesCount()), + static_cast(m_vertexArray.indicesType()), nullptr); + VertexArray::unbind(); // Unbind all textures - for (auto it : m_textures) { - auto texture = std::static_pointer_cast(ResourceHandler::instance().resource(it)); + for (auto textureIt : m_textures) { + auto texture = std::static_pointer_cast(ResourceHandler::instance().resource(textureIt)); texture->unbind(); } } -void Mesh::drawWithoutTextures() +void Mesh::drawWithoutTextures() const { - m_vertexArray->bind(); - glDrawElements(GL_TRIANGLES, static_cast(m_numElements), GL_UNSIGNED_INT, 0); - m_vertexArray->unbind(); + m_vertexArray.bind(); + glDrawElements(GL_TRIANGLES, static_cast(m_vertexArray.indicesCount()), + static_cast(m_vertexArray.indicesType()), nullptr); + VertexArray::unbind(); } -VertexArray *Mesh::getVertexArray() +auto Mesh::getVertexArray() -> VertexArray * { - return m_vertexArray; + return &m_vertexArray; } diff --git a/src/Mesh.h b/src/Mesh.h index b166cb2..e365395 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -1,7 +1,6 @@ #pragma once #include "VertexArray.h" -#include "definitions/models.h" #include "resources/Resource.h" #include @@ -11,27 +10,14 @@ class ShaderProgram; class Mesh { public: - Mesh(std::vector vertices, std::vector indices, std::vector textures); - ~Mesh(); + Mesh(VertexArray vertexArray, std::vector textures); - void initializeOnGPU(); - - void draw(ShaderProgram *shaderProgram); - void drawWithoutTextures(); + void draw(ShaderProgram const &shaderProgram) const; + void drawWithoutTextures() const; auto getVertexArray() -> VertexArray *; private: - struct PreInitializationVertexData - { - std::vector vertices; - std::vector indices; - } m_preInitializationVertexData; - - bool m_isInitialized = false; - - uint32_t m_numElements; + VertexArray m_vertexArray; std::vector m_textures; - - VertexArray *m_vertexArray; }; diff --git a/src/ShaderProgram.cpp b/src/ShaderProgram.cpp index f79ad82..9054aeb 100644 --- a/src/ShaderProgram.cpp +++ b/src/ShaderProgram.cpp @@ -1,28 +1,28 @@ #include "ShaderProgram.h" #include "util/Log.h" +#include #include #include -ShaderProgram::ShaderProgram(Prototype prototype) : m_uniqueName(prototype.name) +ShaderProgram::ShaderProgram(Prototype prototype) : m_shaderProgramId(glCreateProgram()) { - std::string vertexShaderSource = parse(prototype.vertexPath.c_str()); - std::string fragmentShaderSource = parse(prototype.fragmentPath.c_str()); + std::string vertexShaderSource = parse(prototype.vertexPath).value(); + std::string fragmentShaderSource = parse(prototype.fragmentPath).value(); - m_shaderProgramId = glCreateProgram(); - GLuint vs = compile(vertexShaderSource, GL_VERTEX_SHADER); - GLuint fs = compile(fragmentShaderSource, GL_FRAGMENT_SHADER); + GLuint vertexShader = compile(vertexShaderSource, GL_VERTEX_SHADER); + GLuint fragmentShader = compile(fragmentShaderSource, GL_FRAGMENT_SHADER); - glAttachShader(m_shaderProgramId, vs); - glAttachShader(m_shaderProgramId, fs); + glAttachShader(m_shaderProgramId, vertexShader); + glAttachShader(m_shaderProgramId, fragmentShader); glLinkProgram(m_shaderProgramId); GLint isLinked = 0; glGetProgramiv(m_shaderProgramId, GL_LINK_STATUS, &isLinked); - if (!isLinked) - Log::logger().critical("Failed to link shaderProgram \"{}\", \"{}\"", prototype.vertexPath, - prototype.fragmentPath); + if (isLinked == 0) { + Log::logger().warn(R"(Failed to link shaderProgram "{}", "{}")", prototype.vertexPath, prototype.fragmentPath); + } #ifdef _RELEASE glDetachShader(program, vs); @@ -32,7 +32,7 @@ ShaderProgram::ShaderProgram(Prototype prototype) : m_uniqueName(prototype.name) glDeleteShader(fs); #endif - Log::logger().info("Loaded shaderprogram \"{}\"", prototype.name); + Log::logger().info(R"(Loaded shaderprogram "{}")", prototype.name); } ShaderProgram::~ShaderProgram() @@ -40,7 +40,7 @@ ShaderProgram::~ShaderProgram() glDeleteProgram(m_shaderProgramId); } -void ShaderProgram::bind() +void ShaderProgram::bind() const { glUseProgram(m_shaderProgramId); } @@ -50,14 +50,14 @@ void ShaderProgram::unbind() glUseProgram(0); } -std::string ShaderProgram::parse(const std::string &filename) +auto ShaderProgram::parse(const std::filesystem::path &path) -> std::optional { std::fstream shaderfile; - shaderfile.open(filename, std::ios::in); + shaderfile.open(path, std::ios::in); if (!shaderfile.is_open()) { - Log::logger().critical("Shader \"{}\" not found", filename); - exit(-1); + Log::logger().warn("Shader \"{}\" not found", path.c_str()); + return {}; } std::string contents((std::istreambuf_iterator(shaderfile)), (std::istreambuf_iterator())); @@ -65,34 +65,40 @@ std::string ShaderProgram::parse(const std::string &filename) return contents; } -GLuint ShaderProgram::compile(const std::string &shaderSource, GLenum type) +auto ShaderProgram::compile(const std::string &shaderSource, GLenum type) -> GLuint { GLuint shaderId = glCreateShader(type); const char *src = shaderSource.c_str(); - glShaderSource(shaderId, 1, &src, 0); + glShaderSource(shaderId, 1, &src, nullptr); glCompileShader(shaderId); - int result; + int result{}; glGetShaderiv(shaderId, GL_COMPILE_STATUS, &result); + if (result != GL_TRUE) { - int length; + int length{}; glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &length); - char *message = new char[static_cast(length)]; - glGetShaderInfoLog(shaderId, length, &length, message); + + std::string message; + message.reserve(static_cast(length)); + + glGetShaderInfoLog(shaderId, length, &length, message.data()); Log::logger().error("Shader compilation failed: {}", message); - delete[] message; + return 0; } + return shaderId; } -GLint ShaderProgram::retrieveUniformLocation(const std::string &name) const +auto ShaderProgram::retrieveUniformLocation(std::string_view uniform_name) const -> GLint { - if (m_uniformLocationCache.find(name) != m_uniformLocationCache.end()) - return m_uniformLocationCache[name]; + if (m_uniformLocationCache.find(uniform_name.data()) != m_uniformLocationCache.end()) { + return m_uniformLocationCache[uniform_name.data()]; + } - GLint location = glGetUniformLocation(m_shaderProgramId, name.c_str()); - m_uniformLocationCache[name] = location; + GLint location = glGetUniformLocation(m_shaderProgramId, uniform_name.data()); + m_uniformLocationCache[uniform_name.data()] = location; return location; } @@ -139,12 +145,7 @@ void ShaderProgram::setUniform(const std::string &name, glm::mat4 matrix) const glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix)); } -GLuint ShaderProgram::getShaderProgramId() +auto ShaderProgram::getShaderProgramId() const -> GLuint { return m_shaderProgramId; } - -const std::string &ShaderProgram::getUniqueName() -{ - return m_uniqueName; -} diff --git a/src/ShaderProgram.h b/src/ShaderProgram.h index ece2a07..e1c49e3 100644 --- a/src/ShaderProgram.h +++ b/src/ShaderProgram.h @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include #include #include @@ -16,13 +18,13 @@ public: }; ShaderProgram(Prototype prototype); - ~ShaderProgram(); - void bind(); - void unbind(); + void bind() const; + static void unbind(); + + auto retrieveUniformLocation(std::string_view uniform_name) const -> GLint; - GLint retrieveUniformLocation(const std::string &name) const; // May be rewritten... void setUniform(const std::string &name, bool value) const; void setUniform(const std::string &name, int value) const; @@ -32,14 +34,12 @@ public: void setUniform(const std::string &name, glm::mat3 matrix) const; void setUniform(const std::string &name, glm::mat4 matrix) const; - GLuint getShaderProgramId(); - const std::string &getUniqueName(); + auto getShaderProgramId() const -> GLuint; private: - std::string parse(const std::string &filename); - GLuint compile(const std::string &shaderSource, GLenum type); + static auto parse(const std::filesystem::path &path) -> std::optional; + static auto compile(const std::string &shaderSource, GLenum type) -> GLuint; GLuint m_shaderProgramId; - std::string m_uniqueName; mutable std::unordered_map m_uniformLocationCache; }; diff --git a/src/VertexArray.cpp b/src/VertexArray.cpp index 393ca2a..8833974 100644 --- a/src/VertexArray.cpp +++ b/src/VertexArray.cpp @@ -4,51 +4,80 @@ #include #include -VertexArray::VertexArray(void *vertexData, void *indexData, uint32_t numVertices, uint32_t numIndices) +VertexArray::VertexArray(tinygltf::Primitive const &primitive, tinygltf::Model const &model, AttributeLocations &locations) { - glGenVertexArrays(1, &m_VAO); - glBindVertexArray(m_VAO); + GLuint vao{}; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); - glGenBuffers(1, &m_VBO); - glBindBuffer(GL_ARRAY_BUFFER, m_VBO); - glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), vertexData, GL_STATIC_DRAW); + int position_accessor_id = primitive.attributes.at("POSITION"); + // int normal_accessor = primitive.attributes.at("NORMAL"); + // int uv_accessor = primitive.attributes.at("TEXCOORD_0"); + int indices_accessor_id = primitive.indices; - glGenBuffers(1, &m_EBO); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices * sizeof(uint32_t), indexData, GL_STATIC_DRAW); + auto const &position_accessor = model.accessors.at(position_accessor_id); + auto const &indices_accessor = model.accessors.at(indices_accessor_id); - // Position - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, position)); + int position_buffer_view_id = model.accessors[position_accessor_id].bufferView; + int indices_buffer_view_id = model.accessors[indices_accessor_id].bufferView; - // UV Texture Mapping - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, textureCoords)); + auto const &position_buffer_view = model.bufferViews.at(position_buffer_view_id); + auto const &indices_buffer_view = model.bufferViews.at(indices_buffer_view_id); - // Normal vectors - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, normalVec)); + auto const &position_buffer = model.buffers.at(position_buffer_view.buffer); + auto const &indices_buffer = model.buffers.at(indices_buffer_view.buffer); - // Tangent vectors - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, tangentVec)); + GLuint positionVbo{}; + glGenBuffers(1, &positionVbo); + glBindBuffer(GL_ARRAY_BUFFER, positionVbo); + glBufferData(GL_ARRAY_BUFFER, position_buffer_view.byteLength, + position_buffer.data.data() + position_buffer_view.byteOffset, GL_STATIC_DRAW); - // Bitangent vectors - glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, bitangentVec)); + int size = 1; + if (position_accessor.type == TINYGLTF_TYPE_SCALAR) { + size = 1; + } else if (position_accessor.type == TINYGLTF_TYPE_VEC2) { + size = 2; + } else if (position_accessor.type == TINYGLTF_TYPE_VEC3) { + size = 3; + } else if (position_accessor.type == TINYGLTF_TYPE_VEC4) { + size = 4; + } else { + assert(0); + } + + int position_byte_stride = position_accessor.ByteStride(position_buffer_view); + glEnableVertexAttribArray(locations.position); + glVertexAttribPointer(locations.position, size, position_accessor.componentType, + position_accessor.normalized ? GL_TRUE : GL_FALSE, position_byte_stride, + (void *)position_accessor.byteOffset); + + GLuint ebo{}; + glGenBuffers(1, &ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_buffer_view.byteLength, + indices_buffer.data.data() + indices_buffer_view.byteOffset, GL_STATIC_DRAW); - // This will also unbind the vertex buffer and index buffer glBindVertexArray(0); + + m_vao = vao; + m_ebo = ebo; + m_positionVbo = positionVbo; + m_indicesCount = indices_accessor.count; + m_indicesType = indices_accessor.componentType; } VertexArray::~VertexArray() { - glDeleteBuffers(1, &m_VBO); + glDeleteVertexArrays(1, &m_vao); + + glDeleteBuffers(1, &m_positionVbo); + glDeleteBuffers(1, &m_ebo); } -void VertexArray::bind() +void VertexArray::bind() const { - glBindVertexArray(m_VAO); + glBindVertexArray(m_vao); } void VertexArray::unbind() diff --git a/src/VertexArray.h b/src/VertexArray.h index b9dde17..1b6addf 100644 --- a/src/VertexArray.h +++ b/src/VertexArray.h @@ -1,19 +1,59 @@ #pragma once +#include "definitions/attribute_locations.h" + #include +#include #include -class VertexArray +class VertexArray final { public: - VertexArray(void *vertexData, void *indexData, uint32_t numVertices, uint32_t numIndices); + VertexArray(tinygltf::Primitive const &primitive, tinygltf::Model const &model, AttributeLocations &locations); + VertexArray(VertexArray &&other) noexcept + : m_indicesCount(other.m_indicesCount), + m_indicesType(other.m_indicesType), + m_vao(other.m_vao), + m_positionVbo(other.m_positionVbo), + m_ebo(other.m_ebo) + { + other.m_ebo = 0; + other.m_vao = 0; + other.m_positionVbo = 0; + } + + auto operator=(VertexArray &&other) noexcept -> VertexArray & + { + m_indicesCount = other.m_indicesCount; + m_indicesType = other.m_indicesType; + m_vao = other.m_vao; + m_positionVbo = other.m_positionVbo; + m_ebo = other.m_ebo; + + other.m_ebo = 0; + other.m_vao = 0; + other.m_positionVbo = 0; + + return *this; + } + + VertexArray(VertexArray const &) = delete; + auto operator=(VertexArray const &) -> VertexArray & = delete; + ~VertexArray(); - void bind(); - void unbind(); + void bind() const; + static void unbind(); + + [[nodiscard]] auto indicesCount() const -> uint64_t { return m_indicesCount; } + [[nodiscard]] auto indicesType() const -> int { return m_indicesType; } private: - GLuint m_VAO; - GLuint m_VBO; - GLuint m_EBO; + uint64_t m_indicesCount; + int m_indicesType; + + GLuint m_vao; + + GLuint m_positionVbo; + GLuint m_ebo; }; diff --git a/src/definitions/attribute_locations.h b/src/definitions/attribute_locations.h new file mode 100644 index 0000000..337fbfb --- /dev/null +++ b/src/definitions/attribute_locations.h @@ -0,0 +1,9 @@ +#pragma once + +struct AttributeLocations +{ + int position; + int normal; + int uv; + int tangent; +}; diff --git a/src/definitions/models.h b/src/definitions/models.h index d3d0af9..80855c1 100644 --- a/src/definitions/models.h +++ b/src/definitions/models.h @@ -18,4 +18,4 @@ struct Vertex // Bittangent vector glm::vec3 bitangentVec; -}; \ No newline at end of file +}; diff --git a/src/resources/AbstractTexture.h b/src/resources/AbstractTexture.h index 69963b5..a2c820a 100644 --- a/src/resources/AbstractTexture.h +++ b/src/resources/AbstractTexture.h @@ -5,8 +5,8 @@ class AbstractTexture : public Resource, public GlResource { public: - AbstractTexture(const std::string &path) : Resource(path) - {} + AbstractTexture(const std::string &path) : Resource(path) {} + virtual ~AbstractTexture() = default; protected: uint32_t m_textureWidth; diff --git a/src/resources/Model.cpp b/src/resources/Model.cpp index a4c670d..ea38e01 100644 --- a/src/resources/Model.cpp +++ b/src/resources/Model.cpp @@ -1,31 +1,15 @@ #include "Model.h" -#include "../util/Log.h" -#include "ResourceHandler.h" #include "Texture.h" -#include -#include - -Model::Model(const ModelDescriptor &descriptor) : Resource(descriptor.path), NamedResource(descriptor.name) +Model::Model(std::string_view name, std::vector meshes) : m_meshes(std::move(meshes)), m_name(name) { - m_workingPath = descriptor.path.substr(0, descriptor.path.find_last_of('/')); - - loadModel(descriptor.path); } -void Model::initialize() -{ - m_initialized = true; - - for (auto mesh : m_meshes) - mesh->initializeOnGPU(); -} - -void Model::draw(ShaderProgram *shaderProgram) const +void Model::draw(ShaderProgram const &shaderProgram) const { // Iterate through every mesh and call the draw function for (const auto &mesh : m_meshes) { - mesh->draw(shaderProgram); + mesh.draw(shaderProgram); } } @@ -33,126 +17,11 @@ void Model::drawWithoutTextures() const { // Iterate through every mesh and call the draw function for (const auto &mesh : m_meshes) { - mesh->drawWithoutTextures(); + mesh.drawWithoutTextures(); } } -Mesh *Model::getMesh(unsigned int index) const +auto Model::getMesh(unsigned int index) -> Mesh * { - return m_meshes[index]; -} - -void Model::loadModel(const std::string &pathToModel) -{ - std::ifstream input(pathToModel, std::ios::in | std::ios::binary); - - if (!input.is_open()) { - Log::logger().warn("Could not find model file {}", pathToModel); - return; - } - - uint32_t numTextures; - input.read((char *)&numTextures, sizeof(uint32_t)); - - std::vector textureTypes; - for (unsigned int i = 0; i < numTextures; i++) { - TextureType currentTextureType; - input.read((char *)¤tTextureType, sizeof(uint32_t)); - textureTypes.push_back(currentTextureType); - } - - std::vector textureSources; - for (unsigned int i = 0; i < numTextures; i++) { - std::string currentTextureSource; - for (unsigned int k = 0; k < 128; k++) { - uint8_t currentChar; - input.read((char *)¤tChar, sizeof(uint8_t)); - - if (currentChar) { - currentTextureSource.push_back(static_cast(currentChar)); - } - } - textureSources.push_back(currentTextureSource); - } - - // Maybe write a texture loader class in future, that handles all this. - { - std::vector> futures; - std::mutex mutex; - - for (unsigned int i = 0; i < numTextures; i++) { - std::string texturePath = m_workingPath + '/' + textureSources[i].c_str(); - - auto loadModel = [=, this, &mutex]() { - ResourceId texture = ResourceHandler::instance().registerResource( - TextureDescriptor{texturePath, textureTypes[i]}); - - std::lock_guard lock(mutex); - m_textures.push_back(texture); - }; - - futures.push_back(std::async(std::launch::async, loadModel)); - } - } - - // When there is no normal map bound, please use fallback texture - bool hasNormalMap = false; - for (auto it = textureTypes.begin(); it != textureTypes.end(); it++) { - if (*it == TextureType::Normal) - hasNormalMap = true; - } - - if (!hasNormalMap) { - ResourceId texture = ResourceHandler::instance().registerResource( - TextureDescriptor{"data/res/models/tex/fallback_normal.png", TextureType::Normal}); - - m_textures.push_back(texture); - } - - // Here starts the first mesh - uint32_t numMeshes; - input.read((char *)&numMeshes, sizeof(uint32_t)); - - for (unsigned int j = 0; j < numMeshes; j++) { - uint32_t numMeshVertices, numMeshIndices, numMeshTextureIds; - - input.read((char *)&numMeshVertices, sizeof(uint32_t)); - input.read((char *)&numMeshIndices, sizeof(uint32_t)); - input.read((char *)&numMeshTextureIds, sizeof(uint32_t)); - - uint32_t vertexBlockSize = numMeshVertices * sizeof(Vertex); - uint32_t indexBlockSize = numMeshIndices * sizeof(uint32_t); - - // Here starts the first Vertex data - - std::vector meshVertices; - meshVertices.resize(numMeshVertices); - input.read((char *)meshVertices.data(), vertexBlockSize); - - std::vector meshIndices; - meshIndices.resize(numMeshIndices); - input.read((char *)meshIndices.data(), indexBlockSize); - - std::vector meshTextureIds; - std::vector meshTextures; - - for (unsigned int i = 0; i < numMeshTextureIds; i++) { - uint32_t currentTextureId; - input.read((char *)¤tTextureId, sizeof(uint32_t)); - meshTextureIds.push_back(currentTextureId); - } - - if (!hasNormalMap) { - // This will be the last texture - meshTextureIds.push_back(numTextures); - } - - for (auto textureId : meshTextureIds) { - meshTextures.push_back(m_textures[textureId]); - } - - m_meshes.push_back(new Mesh(std::move(meshVertices), std::move(meshIndices), std::move(meshTextures))); - } - - input.close(); + return &m_meshes[index]; } diff --git a/src/resources/Model.h b/src/resources/Model.h index 0ad9b80..ed3ab1a 100644 --- a/src/resources/Model.h +++ b/src/resources/Model.h @@ -6,30 +6,19 @@ #include #include -struct ModelDescriptor -{ - std::string name; - std::string path; -}; - -class Model : public Resource, public NamedResource +class Model { public: - Model(const ModelDescriptor &descriptor); + Model(std::string_view name, std::vector meshes); - void draw(ShaderProgram *shaderProgram) const; + void draw(ShaderProgram const &shaderProgram) const; void drawWithoutTextures() const; - Mesh *getMesh(unsigned int index) const; // TODO... - -protected: - void initialize() override; + auto getMesh(unsigned int index) -> Mesh *; // TODO... private: - void loadModel(const std::string &pathToModel); - - std::vector m_meshes; + std::vector m_meshes; std::vector m_textures; - std::string m_workingPath; + std::string m_name; }; diff --git a/src/resources/ResourceHandler.cpp b/src/resources/ResourceHandler.cpp index 2d7ff5d..aca9622 100644 --- a/src/resources/ResourceHandler.cpp +++ b/src/resources/ResourceHandler.cpp @@ -1,7 +1,6 @@ #include "ResourceHandler.h" #include "../util/Log.h" #include "CubeMap.h" -#include "Model.h" #include "Texture.h" #include @@ -24,7 +23,6 @@ auto ResourceHandler::registerResource(Param const &...param) -> ResourceId template ResourceId ResourceHandler::registerResource(TextureDescriptor const &); template ResourceId ResourceHandler::registerResource(TextureCubeMapDescriptor const &); template ResourceId ResourceHandler::registerResource(int const &); -template ResourceId ResourceHandler::registerResource(ModelDescriptor const &); auto ResourceHandler::resource(const ResourceId resourceId) const -> std::shared_ptr { diff --git a/src/resources/Texture.cpp b/src/resources/Texture.cpp index ae873c8..505b884 100644 --- a/src/resources/Texture.cpp +++ b/src/resources/Texture.cpp @@ -2,7 +2,6 @@ #include "../ShaderProgram.h" #include "../util/Log.h" -#define STB_IMAGE_IMPLEMENTATION #include Texture::Texture(const TextureDescriptor &descriptor) @@ -20,16 +19,17 @@ Texture::Texture(const TextureDescriptor &descriptor) m_textureHeight = static_cast(textureHeight); m_numComponents = static_cast(numComponents); - if (!m_textureBuffer) + if (m_textureBuffer == nullptr) { Log::logger().warn("Texture {} could not be loaded", resourcePath().string()); + } } void Texture::initialize() { m_initialized = true; - GLenum internalFormat; - GLenum dataFormat; + GLenum internalFormat{}; + GLenum dataFormat{}; switch (m_numComponents) { case 1: @@ -52,7 +52,7 @@ void Texture::initialize() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -2.0f); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -2.0F); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -66,12 +66,12 @@ void Texture::initialize() stbi_image_free(m_textureBuffer); } -TextureType Texture::textureType() const +auto Texture::textureType() const -> TextureType { return m_textureType; } -void Texture::bind(uint8_t textureUnit, ShaderProgram *shaderProgram, uint8_t textureTypeNum) const +void Texture::bind(uint8_t textureUnit, ShaderProgram const &shaderProgram, uint8_t textureTypeNum) const { std::string uniformName = "texture_"; @@ -99,7 +99,7 @@ void Texture::bind(uint8_t textureUnit, ShaderProgram *shaderProgram, uint8_t te // Add u_material as we store textures in a struct uniformName = "u_material." + uniformName; - shaderProgram->setUniform(uniformName.c_str(), textureUnit); + shaderProgram.setUniform(uniformName, textureUnit); glActiveTexture(GL_TEXTURE0 + textureUnit); glBindTexture(GL_TEXTURE_2D, m_glId); } diff --git a/src/resources/Texture.h b/src/resources/Texture.h index 0e315fb..88c4ea9 100644 --- a/src/resources/Texture.h +++ b/src/resources/Texture.h @@ -3,8 +3,8 @@ #include "AbstractTexture.h" #include "TextureType.h" -#include #include +#include class ShaderProgram; @@ -19,9 +19,9 @@ class Texture : public AbstractTexture public: Texture(const TextureDescriptor &descriptor); - TextureType textureType() const; + [[nodiscard]] auto textureType() const -> TextureType; - void bind(uint8_t textureUnit, ShaderProgram *shaderProgram, uint8_t textureTypeNum) const; + void bind(uint8_t textureUnit, ShaderProgram const &shaderProgram, uint8_t textureTypeNum) const; void unbind() const override; protected: