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);
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) {

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_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)

View File

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

View File

@@ -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 <GLFW/glfw3.h>
@@ -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<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()
@@ -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);

View File

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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -1,65 +1,57 @@
#include "Mesh.h"
#include "ShaderProgram.h"
#include "VertexArray.h"
#include "resources/ResourceHandler.h"
#include "resources/Texture.h"
#include <utility>
Mesh::Mesh(std::vector<Vertex> vertices, std::vector<uint32_t> indices, std::vector<ResourceId> textures)
: m_preInitializationVertexData{vertices, indices}, m_numElements(static_cast<unsigned>(indices.size())),
m_textures(textures)
Mesh::Mesh(VertexArray vertexArray, std::vector<ResourceId> 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<void *>(m_preInitializationVertexData.vertices.data()),
static_cast<void *>(m_preInitializationVertexData.indices.data()),
static_cast<unsigned>(m_preInitializationVertexData.vertices.size()),
static_cast<unsigned>(m_preInitializationVertexData.indices.size()));
}
std::array<uint8_t, static_cast<std::size_t>(TextureType::TEXTURE_TYPE_NUM_ITEMS)> typeNumberCount{};
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);
// 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<Texture>(ResourceHandler::instance().resource(it));
std::size_t textureNum = 0;
for (auto textureIt : m_textures) {
auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(textureIt));
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
m_vertexArray->bind();
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_numElements), GL_UNSIGNED_INT, 0);
m_vertexArray->unbind();
m_vertexArray.bind();
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_vertexArray.indicesCount()),
static_cast<GLenum>(m_vertexArray.indicesType()), nullptr);
VertexArray::unbind();
// Unbind all textures
for (auto it : m_textures) {
auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(it));
for (auto textureIt : m_textures) {
auto texture = std::static_pointer_cast<Texture>(ResourceHandler::instance().resource(textureIt));
texture->unbind();
}
}
void Mesh::drawWithoutTextures()
void Mesh::drawWithoutTextures() const
{
m_vertexArray->bind();
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_numElements), GL_UNSIGNED_INT, 0);
m_vertexArray->unbind();
m_vertexArray.bind();
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_vertexArray.indicesCount()),
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
#include "VertexArray.h"
#include "definitions/models.h"
#include "resources/Resource.h"
#include <vector>
@@ -11,27 +10,14 @@ class ShaderProgram;
class Mesh
{
public:
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices, std::vector<ResourceId> textures);
~Mesh();
Mesh(VertexArray vertexArray, std::vector<ResourceId> 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<Vertex> vertices;
std::vector<unsigned int> indices;
} m_preInitializationVertexData;
bool m_isInitialized = false;
uint32_t m_numElements;
VertexArray m_vertexArray;
std::vector<ResourceId> m_textures;
VertexArray *m_vertexArray;
};

View File

@@ -1,28 +1,28 @@
#include "ShaderProgram.h"
#include "util/Log.h"
#include <fmt/format.h>
#include <fstream>
#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 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::string>
{
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<char>(shaderfile)), (std::istreambuf_iterator<char>()));
@@ -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<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);
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;
}

View File

@@ -1,7 +1,9 @@
#pragma once
#include <filesystem>
#include <glad/gl.h>
#include <glm/glm.hpp>
#include <optional>
#include <string>
#include <unordered_map>
@@ -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<std::string>;
static auto compile(const std::string &shaderSource, GLenum type) -> GLuint;
GLuint m_shaderProgramId;
std::string m_uniqueName;
mutable std::unordered_map<std::string, GLint> m_uniformLocationCache;
};

View File

@@ -4,51 +4,80 @@
#include <cstddef>
#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);
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()

View File

@@ -1,19 +1,59 @@
#pragma once
#include "definitions/attribute_locations.h"
#include <glad/gl.h>
#include <tiny_gltf.h>
#include <vector>
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;
};

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
{
public:
AbstractTexture(const std::string &path) : Resource(path)
{}
AbstractTexture(const std::string &path) : Resource(path) {}
virtual ~AbstractTexture() = default;
protected:
uint32_t m_textureWidth;

View File

@@ -1,31 +1,15 @@
#include "Model.h"
#include "../util/Log.h"
#include "ResourceHandler.h"
#include "Texture.h"
#include <fstream>
#include <future>
Model::Model(const ModelDescriptor &descriptor) : Resource(descriptor.path), NamedResource(descriptor.name)
Model::Model(std::string_view name, std::vector<Mesh> 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<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();
return &m_meshes[index];
}

View File

@@ -6,30 +6,19 @@
#include <string>
#include <vector>
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<Mesh> 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<Mesh *> m_meshes;
std::vector<Mesh> m_meshes;
std::vector<ResourceId> m_textures;
std::string m_workingPath;
std::string m_name;
};

View File

@@ -1,7 +1,6 @@
#include "ResourceHandler.h"
#include "../util/Log.h"
#include "CubeMap.h"
#include "Model.h"
#include "Texture.h"
#include <algorithm>
@@ -24,7 +23,6 @@ auto ResourceHandler::registerResource(Param const &...param) -> ResourceId
template ResourceId ResourceHandler::registerResource<Texture>(TextureDescriptor const &);
template ResourceId ResourceHandler::registerResource<TextureCubeMap>(TextureCubeMapDescriptor 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>
{

View File

@@ -2,7 +2,6 @@
#include "../ShaderProgram.h"
#include "../util/Log.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
Texture::Texture(const TextureDescriptor &descriptor)
@@ -20,16 +19,17 @@ Texture::Texture(const TextureDescriptor &descriptor)
m_textureHeight = static_cast<unsigned>(textureHeight);
m_numComponents = static_cast<unsigned>(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);
}

View File

@@ -3,8 +3,8 @@
#include "AbstractTexture.h"
#include "TextureType.h"
#include <string>
#include <stb/stb_image.h>
#include <string>
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: