Initial support for gltf scenes

This commit is contained in:
2022-10-10 23:08:50 +02:00
parent 41d09c2b5f
commit 5c1d2bb0ad
21 changed files with 329 additions and 344 deletions

View File

@@ -111,7 +111,7 @@ void main() {
//fragmentColor += spotLightContribution(u_spotLight, normal, v_fragmentPositionTangent, viewDir); //fragmentColor += spotLightContribution(u_spotLight, normal, v_fragmentPositionTangent, viewDir);
f_color = vec4(fragmentColor, 1.0f); 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) { vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 viewDir) {

1
lib/CMakeLists.txt vendored
View File

@@ -2,6 +2,7 @@ option(SPDLOG_NO_EXCEPTIONS "" ON)
set(TINYGLTF_HEADER_ONLY OFF CACHE INTERNAL "" FORCE) set(TINYGLTF_HEADER_ONLY OFF CACHE INTERNAL "" FORCE)
set(TINYGLTF_INSTALL 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}/glad)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/entt) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/entt)

View File

@@ -31,6 +31,7 @@ target_link_libraries(
fmt fmt
pthread pthread
spdlog spdlog
tinygltf
) )
add_executable(Fall-Fever add_executable(Fall-Fever

View File

@@ -1,12 +1,12 @@
#include "Controller.h" #include "Controller.h"
#include "Camera.h" #include "Camera.h"
#include "Entity.h"
#include "FrameBuffer.h" #include "FrameBuffer.h"
#include "Helper.h" #include "Helper.h"
#include "Light.h" #include "Mesh.h"
#include "Scene.h"
#include "ShaderProgram.h" #include "ShaderProgram.h"
#include "Window.h" #include "Window.h"
#include "definitions/attribute_locations.h"
#include "resources/Model.h"
#include "util/Log.h" #include "util/Log.h"
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
@@ -21,6 +21,73 @@ Controller::Controller()
m_postProcessFrameBuffer(m_gameWindow->dimensions().first, m_gameWindow->dimensions().second, m_postProcessFrameBuffer(m_gameWindow->dimensions().first, m_gameWindow->dimensions().second,
postProcessingProgram) 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<Model> models;
for (auto const &mesh : m_model.meshes) {
std::vector<Mesh> 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<ModelEntity> entities;
for (auto const &node : m_model.nodes) {
ModelEntity entity(Entity::Prototype(node.name, {}, {}, 1.0F), m_models[static_cast<unsigned>(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() void Controller::run()
@@ -29,7 +96,7 @@ void Controller::run()
m_camera->translate(glm::vec3(0., 1.5, 5.)); 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 // This is the game loop
while (glfwWindowShouldClose(&m_gameWindow->glfw_window()) == GLFW_FALSE) { while (glfwWindowShouldClose(&m_gameWindow->glfw_window()) == GLFW_FALSE) {
@@ -40,7 +107,7 @@ void Controller::run()
// --- Update game --- // --- Update game ---
lightProgram.bind(); lightProgram.bind();
lightProgram.setUniform("v_lightColor", glm::vec3{1., 1., 1.} * 100.0F); lightProgram.setUniform("v_lightColor", glm::vec3{1., 1., 1.} * 100.0F);
lightProgram.unbind(); ShaderProgram::unbind();
// --- Render and buffer swap --- // --- Render and buffer swap ---
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -51,6 +118,13 @@ void Controller::run()
m_camera->lookForward(); m_camera->lookForward();
m_camera->updateVPM(); 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.unbind();
m_postProcessFrameBuffer.drawOnEntireScreen(); m_postProcessFrameBuffer.drawOnEntireScreen();
@@ -68,7 +142,6 @@ void Controller::run()
auto const &key_input = m_gameWindow->key_input(); auto const &key_input = m_gameWindow->key_input();
auto const &mouse_cursor_input = m_gameWindow->mouse_cursor_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); m_camera->updatePositionFromKeyboardInput(key_input, (float)m_deltaTime);

View File

@@ -2,9 +2,13 @@
#include "FrameBuffer.h" #include "FrameBuffer.h"
#include "ShaderProgram.h" #include "ShaderProgram.h"
#include "VertexArray.h"
#include "resources/Model.h"
#include "Entity.h"
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <memory> #include <memory>
#include <tiny_gltf.h>
#include <vector> #include <vector>
class Window; class Window;
@@ -39,6 +43,11 @@ private:
static constexpr unsigned MAX_FPS = 60; static constexpr unsigned MAX_FPS = 60;
tinygltf::Model m_model;
std::vector<ModelEntity> m_entities;
std::vector<Model> m_models;
double m_deltaTime{}; double m_deltaTime{};
float m_exposure = 1.0; float m_exposure = 1.0;
}; };

View File

@@ -12,10 +12,8 @@
uint32_t Entity::s_idCounter = 0; uint32_t Entity::s_idCounter = 0;
Entity::Entity(const std::string &name) : m_id(s_idCounter++), m_uniqueName(name) Entity::Entity(const std::string &name) : m_id(s_idCounter++), m_uniqueName(name)
{} {
}
Entity::~Entity()
{}
uint32_t Entity::getId() const uint32_t Entity::getId() const
{ {
@@ -93,7 +91,7 @@ glm::mat4 Entity::getModelMatrix() const
return m_modelMatrix; 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) : Entity(prototype.name), m_model(model), m_shaderProgram(shaderProgram)
{ {
setPosition(prototype.position); setPosition(prototype.position);
@@ -101,27 +99,27 @@ ModelEntity::ModelEntity(Prototype prototype, const Model *model, ShaderProgram
setScale(prototype.scale); 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; glm::mat4 modelViewProj = viewProjMatrix * m_modelMatrix;
m_shaderProgram->setUniform("u_modelViewProjMatrix", modelViewProj); m_shaderProgram.setUniform("u_modelViewProjMatrix", modelViewProj);
m_shaderProgram->setUniform("u_modelMatrix", m_modelMatrix); m_shaderProgram.setUniform("u_modelMatrix", m_modelMatrix);
glm::mat3 normalMatrix = glm::mat3(m_modelMatrix); glm::mat3 normalMatrix = glm::mat3(m_modelMatrix);
normalMatrix = glm::transpose(glm::inverse(normalMatrix)); 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 // 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(); shaderProgram->bind();
@@ -129,19 +127,19 @@ void ModelEntity::drawDirectionalShadows(glm::mat4 viewProjMatrix, ShaderProgram
shaderProgram->setUniform("u_modelViewProjMatrix", modelViewProj); shaderProgram->setUniform("u_modelViewProjMatrix", modelViewProj);
// Draw the model // Draw the model
m_model->drawWithoutTextures(); m_model.drawWithoutTextures();
shaderProgram->unbind(); shaderProgram->unbind();
} }
void ModelEntity::drawPointShadows(ShaderProgram *shaderProgram) void ModelEntity::drawPointShadows(ShaderProgram *shaderProgram) const
{ {
shaderProgram->bind(); shaderProgram->bind();
shaderProgram->setUniform("u_modelMatrix", m_modelMatrix); shaderProgram->setUniform("u_modelMatrix", m_modelMatrix);
// Draw the model // Draw the model
m_model->drawWithoutTextures(); m_model.drawWithoutTextures();
shaderProgram->unbind(); shaderProgram->unbind();
} }

View File

@@ -20,7 +20,8 @@ public:
{ {
Prototype(const std::string &_name, glm::vec3 _position, glm::vec3 _rotation, float _scale) Prototype(const std::string &_name, glm::vec3 _position, glm::vec3 _rotation, float _scale)
: name(_name), position(_position), rotation(_rotation), scale(_scale) : name(_name), position(_position), rotation(_rotation), scale(_scale)
{} {
}
virtual ~Prototype() = default; virtual ~Prototype() = default;
std::string name; std::string name;
@@ -30,7 +31,7 @@ public:
}; };
Entity(const std::string &name); Entity(const std::string &name);
virtual ~Entity() = 0; virtual ~Entity() = default;
uint32_t getId() const; uint32_t getId() const;
const std::string &getUniqueName() const; const std::string &getUniqueName() const;
@@ -64,26 +65,15 @@ protected:
class ModelEntity : public Entity class ModelEntity : public Entity
{ {
public: public:
struct Prototype : public Entity::Prototype ModelEntity(Entity::Prototype prototype, Model const &model, ShaderProgram const &shaderProgram);
{
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(Prototype prototype, const Model *model, ShaderProgram *shaderProgram); void draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) const;
void drawDirectionalShadows(glm::mat4 viewProjMatrix, ShaderProgram *p_shaderProgram) const;
void draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition); void drawPointShadows(ShaderProgram *p_shaderProgram) const;
void drawDirectionalShadows(glm::mat4 viewProjMatrix, ShaderProgram *p_shaderProgram);
void drawPointShadows(ShaderProgram *p_shaderProgram);
private: private:
const Model *m_model; Model const &m_model;
ShaderProgram *m_shaderProgram; ShaderProgram const &m_shaderProgram;
}; };
class Skybox class Skybox

View File

@@ -1,65 +1,57 @@
#include "Mesh.h" #include "Mesh.h"
#include "ShaderProgram.h" #include "ShaderProgram.h"
#include "VertexArray.h" #include "VertexArray.h"
#include "resources/ResourceHandler.h" #include "resources/ResourceHandler.h"
#include "resources/Texture.h" #include "resources/Texture.h"
#include <utility>
Mesh::Mesh(std::vector<Vertex> vertices, std::vector<uint32_t> indices, std::vector<ResourceId> textures) Mesh::Mesh(VertexArray vertexArray, std::vector<ResourceId> textures)
: m_preInitializationVertexData{vertices, indices}, m_numElements(static_cast<unsigned>(indices.size())), : m_vertexArray(std::move(vertexArray)), m_textures(std::move(textures))
m_textures(textures)
{ {
} }
void Mesh::initializeOnGPU() void Mesh::draw(ShaderProgram const &shaderProgram) const
{ {
m_vertexArray = new VertexArray(static_cast<void *>(m_preInitializationVertexData.vertices.data()), std::array<uint8_t, static_cast<std::size_t>(TextureType::TEXTURE_TYPE_NUM_ITEMS)> typeNumberCount{};
static_cast<void *>(m_preInitializationVertexData.indices.data()),
static_cast<unsigned>(m_preInitializationVertexData.vertices.size()),
static_cast<unsigned>(m_preInitializationVertexData.indices.size()));
}
Mesh::~Mesh()
{
delete m_vertexArray;
}
void Mesh::draw(ShaderProgram *shaderProgram)
{
uint8_t typeNumberCount[static_cast<int>(TextureType::TEXTURE_TYPE_NUM_ITEMS)]{0};
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
// Bind all textures in order to its texture unit // Bind all textures in order to its texture unit
std::size_t i = 0; std::size_t textureNum = 0;
for (auto it : m_textures) { for (auto textureIt : m_textures) {
auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(it)); auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(textureIt));
TextureType currentTextureType = texture->textureType(); TextureType currentTextureType = texture->textureType();
texture->bind(static_cast<uint8_t>(i), shaderProgram, typeNumberCount[static_cast<int>(currentTextureType)]); texture->bind(static_cast<uint8_t>(textureNum), shaderProgram,
typeNumberCount.at(static_cast<std::size_t>(currentTextureType)));
typeNumberCount[static_cast<int>(currentTextureType)] += 1; typeNumberCount.at(static_cast<std::size_t>(currentTextureType)) += 1;
i++; textureNum++;
} }
// Draw elements // Draw elements
m_vertexArray->bind(); m_vertexArray.bind();
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_numElements), GL_UNSIGNED_INT, 0); glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_vertexArray.indicesCount()),
m_vertexArray->unbind(); static_cast<GLenum>(m_vertexArray.indicesType()), nullptr);
VertexArray::unbind();
// Unbind all textures // Unbind all textures
for (auto it : m_textures) { for (auto textureIt : m_textures) {
auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(it)); auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(textureIt));
texture->unbind(); texture->unbind();
} }
} }
void Mesh::drawWithoutTextures() void Mesh::drawWithoutTextures() const
{ {
m_vertexArray->bind(); m_vertexArray.bind();
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_numElements), GL_UNSIGNED_INT, 0); glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_vertexArray.indicesCount()),
m_vertexArray->unbind(); static_cast<GLenum>(m_vertexArray.indicesType()), nullptr);
VertexArray::unbind();
} }
VertexArray *Mesh::getVertexArray() auto Mesh::getVertexArray() -> VertexArray *
{ {
return m_vertexArray; return &m_vertexArray;
} }

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "VertexArray.h" #include "VertexArray.h"
#include "definitions/models.h"
#include "resources/Resource.h" #include "resources/Resource.h"
#include <vector> #include <vector>
@@ -11,27 +10,14 @@ class ShaderProgram;
class Mesh class Mesh
{ {
public: public:
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices, std::vector<ResourceId> textures); Mesh(VertexArray vertexArray, std::vector<ResourceId> textures);
~Mesh();
void initializeOnGPU(); void draw(ShaderProgram const &shaderProgram) const;
void drawWithoutTextures() const;
void draw(ShaderProgram *shaderProgram);
void drawWithoutTextures();
auto getVertexArray() -> VertexArray *; auto getVertexArray() -> VertexArray *;
private: private:
struct PreInitializationVertexData VertexArray m_vertexArray;
{
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
} m_preInitializationVertexData;
bool m_isInitialized = false;
uint32_t m_numElements;
std::vector<ResourceId> m_textures; std::vector<ResourceId> m_textures;
VertexArray *m_vertexArray;
}; };

View File

@@ -1,28 +1,28 @@
#include "ShaderProgram.h" #include "ShaderProgram.h"
#include "util/Log.h" #include "util/Log.h"
#include <fmt/format.h>
#include <fstream> #include <fstream>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
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 vertexShaderSource = parse(prototype.vertexPath).value();
std::string fragmentShaderSource = parse(prototype.fragmentPath.c_str()); std::string fragmentShaderSource = parse(prototype.fragmentPath).value();
m_shaderProgramId = glCreateProgram(); GLuint vertexShader = compile(vertexShaderSource, GL_VERTEX_SHADER);
GLuint vs = compile(vertexShaderSource, GL_VERTEX_SHADER); GLuint fragmentShader = compile(fragmentShaderSource, GL_FRAGMENT_SHADER);
GLuint fs = compile(fragmentShaderSource, GL_FRAGMENT_SHADER);
glAttachShader(m_shaderProgramId, vs); glAttachShader(m_shaderProgramId, vertexShader);
glAttachShader(m_shaderProgramId, fs); glAttachShader(m_shaderProgramId, fragmentShader);
glLinkProgram(m_shaderProgramId); glLinkProgram(m_shaderProgramId);
GLint isLinked = 0; GLint isLinked = 0;
glGetProgramiv(m_shaderProgramId, GL_LINK_STATUS, &isLinked); glGetProgramiv(m_shaderProgramId, GL_LINK_STATUS, &isLinked);
if (!isLinked) if (isLinked == 0) {
Log::logger().critical("Failed to link shaderProgram \"{}\", \"{}\"", prototype.vertexPath, Log::logger().warn(R"(Failed to link shaderProgram "{}", "{}")", prototype.vertexPath, prototype.fragmentPath);
prototype.fragmentPath); }
#ifdef _RELEASE #ifdef _RELEASE
glDetachShader(program, vs); glDetachShader(program, vs);
@@ -32,7 +32,7 @@ ShaderProgram::ShaderProgram(Prototype prototype) : m_uniqueName(prototype.name)
glDeleteShader(fs); glDeleteShader(fs);
#endif #endif
Log::logger().info("Loaded shaderprogram \"{}\"", prototype.name); Log::logger().info(R"(Loaded shaderprogram "{}")", prototype.name);
} }
ShaderProgram::~ShaderProgram() ShaderProgram::~ShaderProgram()
@@ -40,7 +40,7 @@ ShaderProgram::~ShaderProgram()
glDeleteProgram(m_shaderProgramId); glDeleteProgram(m_shaderProgramId);
} }
void ShaderProgram::bind() void ShaderProgram::bind() const
{ {
glUseProgram(m_shaderProgramId); glUseProgram(m_shaderProgramId);
} }
@@ -50,14 +50,14 @@ void ShaderProgram::unbind()
glUseProgram(0); glUseProgram(0);
} }
std::string ShaderProgram::parse(const std::string &filename) auto ShaderProgram::parse(const std::filesystem::path &path) -> std::optional<std::string>
{ {
std::fstream shaderfile; std::fstream shaderfile;
shaderfile.open(filename, std::ios::in); shaderfile.open(path, std::ios::in);
if (!shaderfile.is_open()) { if (!shaderfile.is_open()) {
Log::logger().critical("Shader \"{}\" not found", filename); Log::logger().warn("Shader \"{}\" not found", path.c_str());
exit(-1); return {};
} }
std::string contents((std::istreambuf_iterator<char>(shaderfile)), (std::istreambuf_iterator<char>())); std::string contents((std::istreambuf_iterator<char>(shaderfile)), (std::istreambuf_iterator<char>()));
@@ -65,34 +65,40 @@ std::string ShaderProgram::parse(const std::string &filename)
return contents; 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); GLuint shaderId = glCreateShader(type);
const char *src = shaderSource.c_str(); const char *src = shaderSource.c_str();
glShaderSource(shaderId, 1, &src, 0); glShaderSource(shaderId, 1, &src, nullptr);
glCompileShader(shaderId); glCompileShader(shaderId);
int result; int result{};
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &result); glGetShaderiv(shaderId, GL_COMPILE_STATUS, &result);
if (result != GL_TRUE) { if (result != GL_TRUE) {
int length; int length{};
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &length); glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &length);
char *message = new char[static_cast<unsigned>(length)];
glGetShaderInfoLog(shaderId, length, &length, message); std::string message;
message.reserve(static_cast<unsigned>(length));
glGetShaderInfoLog(shaderId, length, &length, message.data());
Log::logger().error("Shader compilation failed: {}", message); Log::logger().error("Shader compilation failed: {}", message);
delete[] message;
return 0; return 0;
} }
return shaderId; 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()) if (m_uniformLocationCache.find(uniform_name.data()) != m_uniformLocationCache.end()) {
return m_uniformLocationCache[name]; return m_uniformLocationCache[uniform_name.data()];
}
GLint location = glGetUniformLocation(m_shaderProgramId, name.c_str()); GLint location = glGetUniformLocation(m_shaderProgramId, uniform_name.data());
m_uniformLocationCache[name] = location; m_uniformLocationCache[uniform_name.data()] = location;
return 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)); glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
} }
GLuint ShaderProgram::getShaderProgramId() auto ShaderProgram::getShaderProgramId() const -> GLuint
{ {
return m_shaderProgramId; return m_shaderProgramId;
} }
const std::string &ShaderProgram::getUniqueName()
{
return m_uniqueName;
}

View File

@@ -1,7 +1,9 @@
#pragma once #pragma once
#include <filesystem>
#include <glad/gl.h> #include <glad/gl.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@@ -16,13 +18,13 @@ public:
}; };
ShaderProgram(Prototype prototype); ShaderProgram(Prototype prototype);
~ShaderProgram(); ~ShaderProgram();
void bind(); void bind() const;
void unbind(); static void unbind();
auto retrieveUniformLocation(std::string_view uniform_name) const -> GLint;
GLint retrieveUniformLocation(const std::string &name) const;
// May be rewritten... // May be rewritten...
void setUniform(const std::string &name, bool value) const; void setUniform(const std::string &name, bool value) const;
void setUniform(const std::string &name, int 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::mat3 matrix) const;
void setUniform(const std::string &name, glm::mat4 matrix) const; void setUniform(const std::string &name, glm::mat4 matrix) const;
GLuint getShaderProgramId(); auto getShaderProgramId() const -> GLuint;
const std::string &getUniqueName();
private: private:
std::string parse(const std::string &filename); static auto parse(const std::filesystem::path &path) -> std::optional<std::string>;
GLuint compile(const std::string &shaderSource, GLenum type); static auto compile(const std::string &shaderSource, GLenum type) -> GLuint;
GLuint m_shaderProgramId; GLuint m_shaderProgramId;
std::string m_uniqueName;
mutable std::unordered_map<std::string, GLint> m_uniformLocationCache; mutable std::unordered_map<std::string, GLint> m_uniformLocationCache;
}; };

View File

@@ -4,51 +4,80 @@
#include <cstddef> #include <cstddef>
#include <vector> #include <vector>
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); GLuint vao{};
glBindVertexArray(m_VAO); glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &m_VBO); int position_accessor_id = primitive.attributes.at("POSITION");
glBindBuffer(GL_ARRAY_BUFFER, m_VBO); // int normal_accessor = primitive.attributes.at("NORMAL");
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), vertexData, GL_STATIC_DRAW); // int uv_accessor = primitive.attributes.at("TEXCOORD_0");
int indices_accessor_id = primitive.indices;
glGenBuffers(1, &m_EBO); auto const &position_accessor = model.accessors.at(position_accessor_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO); auto const &indices_accessor = model.accessors.at(indices_accessor_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices * sizeof(uint32_t), indexData, GL_STATIC_DRAW);
// Position int position_buffer_view_id = model.accessors[position_accessor_id].bufferView;
glEnableVertexAttribArray(0); int indices_buffer_view_id = model.accessors[indices_accessor_id].bufferView;
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, position));
// UV Texture Mapping auto const &position_buffer_view = model.bufferViews.at(position_buffer_view_id);
glEnableVertexAttribArray(1); auto const &indices_buffer_view = model.bufferViews.at(indices_buffer_view_id);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, textureCoords));
// Normal vectors auto const &position_buffer = model.buffers.at(position_buffer_view.buffer);
glEnableVertexAttribArray(2); auto const &indices_buffer = model.buffers.at(indices_buffer_view.buffer);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, normalVec));
// Tangent vectors GLuint positionVbo{};
glEnableVertexAttribArray(3); glGenBuffers(1, &positionVbo);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, tangentVec)); 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 int size = 1;
glEnableVertexAttribArray(4); if (position_accessor.type == TINYGLTF_TYPE_SCALAR) {
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(struct Vertex, bitangentVec)); 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); glBindVertexArray(0);
m_vao = vao;
m_ebo = ebo;
m_positionVbo = positionVbo;
m_indicesCount = indices_accessor.count;
m_indicesType = indices_accessor.componentType;
} }
VertexArray::~VertexArray() 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() void VertexArray::unbind()

View File

@@ -1,19 +1,59 @@
#pragma once #pragma once
#include "definitions/attribute_locations.h"
#include <glad/gl.h> #include <glad/gl.h>
#include <tiny_gltf.h>
#include <vector> #include <vector>
class VertexArray class VertexArray final
{ {
public: 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(); ~VertexArray();
void bind(); void bind() const;
void unbind(); static void unbind();
[[nodiscard]] auto indicesCount() const -> uint64_t { return m_indicesCount; }
[[nodiscard]] auto indicesType() const -> int { return m_indicesType; }
private: private:
GLuint m_VAO; uint64_t m_indicesCount;
GLuint m_VBO; int m_indicesType;
GLuint m_EBO;
GLuint m_vao;
GLuint m_positionVbo;
GLuint m_ebo;
}; };

View File

@@ -0,0 +1,9 @@
#pragma once
struct AttributeLocations
{
int position;
int normal;
int uv;
int tangent;
};

View File

@@ -5,8 +5,8 @@
class AbstractTexture : public Resource, public GlResource class AbstractTexture : public Resource, public GlResource
{ {
public: public:
AbstractTexture(const std::string &path) : Resource(path) AbstractTexture(const std::string &path) : Resource(path) {}
{} virtual ~AbstractTexture() = default;
protected: protected:
uint32_t m_textureWidth; uint32_t m_textureWidth;

View File

@@ -1,31 +1,15 @@
#include "Model.h" #include "Model.h"
#include "../util/Log.h"
#include "ResourceHandler.h"
#include "Texture.h" #include "Texture.h"
#include <fstream> Model::Model(std::string_view name, std::vector<Mesh> meshes) : m_meshes(std::move(meshes)), m_name(name)
#include <future>
Model::Model(const ModelDescriptor &descriptor) : Resource(descriptor.path), NamedResource(descriptor.name)
{ {
m_workingPath = descriptor.path.substr(0, descriptor.path.find_last_of('/'));
loadModel(descriptor.path);
} }
void Model::initialize() void Model::draw(ShaderProgram const &shaderProgram) const
{
m_initialized = true;
for (auto mesh : m_meshes)
mesh->initializeOnGPU();
}
void Model::draw(ShaderProgram *shaderProgram) const
{ {
// Iterate through every mesh and call the draw function // Iterate through every mesh and call the draw function
for (const auto &mesh : m_meshes) { 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 // Iterate through every mesh and call the draw function
for (const auto &mesh : m_meshes) { 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]; 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<TextureType> textureTypes;
for (unsigned int i = 0; i < numTextures; i++) {
TextureType currentTextureType;
input.read((char *)&currentTextureType, sizeof(uint32_t));
textureTypes.push_back(currentTextureType);
}
std::vector<std::string> 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 *)&currentChar, sizeof(uint8_t));
if (currentChar) {
currentTextureSource.push_back(static_cast<char>(currentChar));
}
}
textureSources.push_back(currentTextureSource);
}
// Maybe write a texture loader class in future, that handles all this.
{
std::vector<std::future<void>> 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<Texture>(
TextureDescriptor{texturePath, textureTypes[i]});
std::lock_guard<std::mutex> 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<Texture>(
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<Vertex> meshVertices;
meshVertices.resize(numMeshVertices);
input.read((char *)meshVertices.data(), vertexBlockSize);
std::vector<uint32_t> meshIndices;
meshIndices.resize(numMeshIndices);
input.read((char *)meshIndices.data(), indexBlockSize);
std::vector<uint32_t> meshTextureIds;
std::vector<ResourceId> meshTextures;
for (unsigned int i = 0; i < numMeshTextureIds; i++) {
uint32_t currentTextureId;
input.read((char *)&currentTextureId, 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();
} }

View File

@@ -6,30 +6,19 @@
#include <string> #include <string>
#include <vector> #include <vector>
struct ModelDescriptor class Model
{
std::string name;
std::string path;
};
class Model : public Resource, public NamedResource
{ {
public: public:
Model(const ModelDescriptor &descriptor); Model(std::string_view name, std::vector<Mesh> meshes);
void draw(ShaderProgram *shaderProgram) const; void draw(ShaderProgram const &shaderProgram) const;
void drawWithoutTextures() const; void drawWithoutTextures() const;
Mesh *getMesh(unsigned int index) const; // TODO... auto getMesh(unsigned int index) -> Mesh *; // TODO...
protected:
void initialize() override;
private: private:
void loadModel(const std::string &pathToModel); std::vector<Mesh> m_meshes;
std::vector<Mesh *> m_meshes;
std::vector<ResourceId> m_textures; std::vector<ResourceId> m_textures;
std::string m_workingPath; std::string m_name;
}; };

View File

@@ -1,7 +1,6 @@
#include "ResourceHandler.h" #include "ResourceHandler.h"
#include "../util/Log.h" #include "../util/Log.h"
#include "CubeMap.h" #include "CubeMap.h"
#include "Model.h"
#include "Texture.h" #include "Texture.h"
#include <algorithm> #include <algorithm>
@@ -24,7 +23,6 @@ auto ResourceHandler::registerResource(Param const &...param) -> ResourceId
template ResourceId ResourceHandler::registerResource<Texture>(TextureDescriptor const &); template ResourceId ResourceHandler::registerResource<Texture>(TextureDescriptor const &);
template ResourceId ResourceHandler::registerResource<TextureCubeMap>(TextureCubeMapDescriptor const &); template ResourceId ResourceHandler::registerResource<TextureCubeMap>(TextureCubeMapDescriptor const &);
template ResourceId ResourceHandler::registerResource<InternalCubeMap>(int const &); template ResourceId ResourceHandler::registerResource<InternalCubeMap>(int const &);
template ResourceId ResourceHandler::registerResource<Model>(ModelDescriptor const &);
auto ResourceHandler::resource(const ResourceId resourceId) const -> std::shared_ptr<Resource> auto ResourceHandler::resource(const ResourceId resourceId) const -> std::shared_ptr<Resource>
{ {

View File

@@ -2,7 +2,6 @@
#include "../ShaderProgram.h" #include "../ShaderProgram.h"
#include "../util/Log.h" #include "../util/Log.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h> #include <stb/stb_image.h>
Texture::Texture(const TextureDescriptor &descriptor) Texture::Texture(const TextureDescriptor &descriptor)
@@ -20,16 +19,17 @@ Texture::Texture(const TextureDescriptor &descriptor)
m_textureHeight = static_cast<unsigned>(textureHeight); m_textureHeight = static_cast<unsigned>(textureHeight);
m_numComponents = static_cast<unsigned>(numComponents); m_numComponents = static_cast<unsigned>(numComponents);
if (!m_textureBuffer) if (m_textureBuffer == nullptr) {
Log::logger().warn("Texture {} could not be loaded", resourcePath().string()); Log::logger().warn("Texture {} could not be loaded", resourcePath().string());
}
} }
void Texture::initialize() void Texture::initialize()
{ {
m_initialized = true; m_initialized = true;
GLenum internalFormat; GLenum internalFormat{};
GLenum dataFormat; GLenum dataFormat{};
switch (m_numComponents) { switch (m_numComponents) {
case 1: 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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_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_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
@@ -66,12 +66,12 @@ void Texture::initialize()
stbi_image_free(m_textureBuffer); stbi_image_free(m_textureBuffer);
} }
TextureType Texture::textureType() const auto Texture::textureType() const -> TextureType
{ {
return m_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_"; 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 // Add u_material as we store textures in a struct
uniformName = "u_material." + uniformName; uniformName = "u_material." + uniformName;
shaderProgram->setUniform(uniformName.c_str(), textureUnit); shaderProgram.setUniform(uniformName, textureUnit);
glActiveTexture(GL_TEXTURE0 + textureUnit); glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(GL_TEXTURE_2D, m_glId); glBindTexture(GL_TEXTURE_2D, m_glId);
} }

View File

@@ -3,8 +3,8 @@
#include "AbstractTexture.h" #include "AbstractTexture.h"
#include "TextureType.h" #include "TextureType.h"
#include <string>
#include <stb/stb_image.h> #include <stb/stb_image.h>
#include <string>
class ShaderProgram; class ShaderProgram;
@@ -19,9 +19,9 @@ class Texture : public AbstractTexture
public: public:
Texture(const TextureDescriptor &descriptor); 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; void unbind() const override;
protected: protected: