Bind texture units using GpuMaterial

This commit is contained in:
2022-10-21 15:33:46 +02:00
parent 0c18186f63
commit e9dec68cb1
35 changed files with 101 additions and 1171 deletions

View File

@@ -69,7 +69,6 @@ void main()
fragmentColor += pointLightContribution(u_pointLight[i], normal, v_fragmentPosition, viewDir);
}
fragmentColor = vec3(1.,1.,1.);
f_color = vec4(fragmentColor, 1.0f);
}

View File

@@ -3,20 +3,16 @@ add_library(fever_engine
Controller.cpp
Window.cpp
ShaderProgram.cpp
VertexArray.cpp
Camera.cpp
Mesh.cpp
Entity.cpp
Light.cpp
Scene.cpp
FrameBuffer.cpp
Helper.cpp
resources/Texture.cpp
resources/Model.cpp
util/Log.cpp
image.cpp
mesh.cpp
gltf_loader.cpp
material.cpp
)
target_compile_features(fever_engine PUBLIC cxx_std_20)

View File

@@ -3,12 +3,9 @@
#include "FrameBuffer.h"
#include "Helper.h"
#include "Light.h"
#include "Mesh.h"
#include "ShaderProgram.h"
#include "Window.h"
#include "definitions/attribute_locations.h"
#include "gltf_loader.h"
#include "resources/Model.h"
#include "util/Log.h"
#include <GLFW/glfw3.h>
@@ -31,30 +28,6 @@ Controller::Controller()
m_gameWindow->dimensions().second,
postProcessingProgram)
{
// fx::gltf::ReadQuotas read_quotas{.MaxFileSize = 512 * 1024 * 1024,
// .MaxBufferByteLength = 512 * 1024 * 1024};
// // auto gltf_path = std::filesystem::path("Lantern/glTF/Lantern.gltf");
// // auto gltf_path = std::filesystem::path("WaterBottle/glTF/WaterBottle.gltf");
// auto gltf_path = std::filesystem::path("ABeautifulGame.glb");
// auto gltf = [&]() {
// if (gltf_path.extension() == ".gltf") {
// return fx::gltf::LoadFromText(gltf_path, read_quotas);
// }
// return fx::gltf::LoadFromBinary(gltf_path, read_quotas);
// }();
// 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");
// locations.tangent = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_tangent");
// ShaderProgram::unbind();
// if (!gltf.cameras.empty()) {
// auto const &gltf_camera = gltf.cameras.at(0);
@@ -65,90 +38,6 @@ Controller::Controller()
// } else {
m_camera = std::make_shared<Camera>(90., m_gameWindow->aspectRatio());
// }
// std::vector<Model> models;
// for (auto const &mesh : gltf.meshes) {
// std::vector<Mesh_> meshes;
// for (auto const &primitive : mesh.primitives) {
// auto const &material = gltf.materials.at(primitive.material);
// auto baseColorTexture = material.pbrMetallicRoughness.baseColorTexture.index;
// auto normalTexture = material.normalTexture.index;
// std::vector<std::reference_wrapper<const Texture>> primitive_textures;
// // Check if texture already exists, if not load it.
// if (baseColorTexture != -1 && !m_textures.contains(baseColorTexture)) {
// auto const &gltf_texture = gltf.textures.at(baseColorTexture);
// m_textures.emplace(baseColorTexture,
// Texture(gltf_texture,
// gltf_path.parent_path(),
// gltf.images,
// gltf.bufferViews,
// gltf.buffers,
// gltf.samplers,
// TextureType::Diffuse));
// primitive_textures.emplace_back(m_textures.at(baseColorTexture));
// }
// if (normalTexture != -1 && !m_textures.contains(normalTexture)) {
// auto const &gltf_texture = gltf.textures.at(normalTexture);
// m_textures.emplace(normalTexture,
// Texture(gltf_texture,
// gltf_path.parent_path(),
// gltf.images,
// gltf.bufferViews,
// gltf.buffers,
// gltf.samplers,
// TextureType::Normal));
// primitive_textures.emplace_back(m_textures.at(normalTexture));
// }
// meshes.emplace_back(Mesh_({primitive, gltf, locations}, primitive_textures));
// }
// models.emplace_back(Model(mesh.name, std::move(meshes)));
// }
// m_models = std::move(models);
// std::vector<ModelEntity> entities;
// for (auto const &node : gltf.nodes) {
// if (node.mesh == -1) {
// continue;
// }
// 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 &node : gltf.nodes) {
// for (auto const &child : node.children) {
// if (!node.translation.empty()) {
// entities[child].translate(
// glm::vec3(node.translation[0], node.translation[1], node.translation[2]));
// }
// }
// }
// m_entities = std::move(entities);
}
void Controller::run()
@@ -191,13 +80,6 @@ void Controller::run()
m_camera->getViewProj(),
m_camera->getPosition());
// 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();

View File

@@ -2,10 +2,6 @@
#include "FrameBuffer.h"
#include "ShaderProgram.h"
#include "VertexArray.h"
#include "resources/Model.h"
#include "Entity.h"
#include "resources/Texture.h"
#include "Scene.h"
#include <glm/glm.hpp>
@@ -45,10 +41,6 @@ private:
Scene m_scene;
std::vector<ModelEntity> m_entities;
std::vector<Model> m_models;
std::unordered_map<unsigned, Texture> m_textures;
double m_deltaTime{};
float m_exposure = 1.0;
};

View File

@@ -1,161 +0,0 @@
#include "Entity.h"
#include "Mesh.h"
#include "ShaderProgram.h"
#include "VertexArray.h"
#include "resources/Model.h"
#include <glm/ext/matrix_transform.hpp>
#include <glm/gtc/matrix_transform.hpp>
uint32_t Entity::s_idCounter = 0;
Entity::Entity(const std::string &name) : m_id(s_idCounter++), m_uniqueName(name)
{
}
uint32_t Entity::getId() const
{
return m_id;
}
const std::string &Entity::getUniqueName() const
{
return m_uniqueName;
}
void Entity::translate(glm::vec3 vector)
{
m_position += vector;
updateModelMatrix();
}
void Entity::rotate(glm::vec3 axis, float radians)
{
glm::quat rotation = glm::angleAxis(radians, axis);
m_quaternion = rotation * m_quaternion;
updateModelMatrix();
}
void Entity::setPosition(glm::vec3 position)
{
m_position = position;
updateModelMatrix();
}
void Entity::setRotation(glm::vec3 eulerAngles)
{
m_quaternion = glm::quat(eulerAngles);
updateModelMatrix();
}
void Entity::setRotation(glm::vec3 axis, float radians)
{
m_quaternion = glm::angleAxis(radians, axis);
updateModelMatrix();
}
void Entity::setScale(float scale)
{
m_scale = scale;
updateModelMatrix();
}
void Entity::updateModelMatrix()
{
// Translate * Rotate * Scale * vertex_vec;
// First scaling, then rotation, then translation
// Translate
glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f), m_position);
// Rotate
glm::mat4 rotationMatrix = glm::toMat4(m_quaternion);
// Scale
glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(m_scale, m_scale, m_scale));
m_modelMatrix = translationMatrix * rotationMatrix * scaleMatrix;
}
glm::vec3 Entity::getPosition() const
{
return m_position;
}
glm::mat4 Entity::getModelMatrix() const
{
return m_modelMatrix;
}
ModelEntity::ModelEntity(Entity::Prototype prototype, Model const &model, ShaderProgram const &shaderProgram)
: Entity(prototype.name), m_model(model), m_shaderProgram(shaderProgram)
{
setPosition(prototype.position);
setRotation(prototype.rotation);
setScale(prototype.scale);
}
void ModelEntity::draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) const
{
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_viewPosition", viewPosition);
// Draw the model
m_model.draw(m_shaderProgram);
m_shaderProgram.unbind();
}
Skybox::Skybox(Prototype prototype, Model *cubeModel, ShaderProgram *shaderProgram)
: m_cubeModel(cubeModel), m_shaderProgram(shaderProgram), m_vertexArray(cubeModel->getMesh(0)->getVertexArray())
{
// m_cubeMap =
// ResourceHandler::instance().registerResource<TextureCubeMap>(TextureCubeMapDescriptor{prototype.texturePath});
}
Skybox::~Skybox()
{
// delete m_cubeMap;
}
void Skybox::initializeOnGPU()
{
// m_cubeMap->initializeOnGPU();
}
void Skybox::draw(glm::mat4 viewMatrix, glm::mat4 projectionMatrix)
{
// To disable face culling first get current state
GLboolean active;
glGetBooleanv(GL_CULL_FACE_MODE, &active);
glDisable(GL_CULL_FACE);
glDepthMask(GL_FALSE);
m_shaderProgram->bind();
// Delete any translation from the skybox cube
glm::mat4 viewProjectionMatrix = projectionMatrix * glm::mat4(glm::mat3(viewMatrix));
m_shaderProgram->setUniform("u_viewProjectionMatrix", viewProjectionMatrix);
// auto cubeMap = std::static_pointer_cast<TextureCubeMap>(ResourceHandler::instance().resource(m_cubeMap));
// cubeMap->bind(m_shaderProgram);
// m_cubeModel->getMesh(0)->drawWithoutTextures();
// cubeMap->unbind();
m_shaderProgram->unbind();
glDepthMask(GL_TRUE);
// Restore face culling
if (active) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
}

View File

@@ -1,100 +0,0 @@
#pragma once
#include "resources/Resource.h"
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <memory>
#include <string>
#include <vector>
class VertexArray;
class ShaderProgram;
class Model;
class TextureCubeMap;
class Entity
{
public:
struct Prototype
{
Prototype(const std::string &_name, glm::vec3 _position, glm::vec3 _rotation, float _scale)
: name(_name), position(_position), rotation(_rotation), scale(_scale)
{
}
std::string name;
glm::vec3 position;
glm::vec3 rotation;
float scale;
};
Entity(const std::string &name);
virtual ~Entity() = default;
uint32_t getId() const;
const std::string &getUniqueName() const;
void translate(glm::vec3 vector);
void rotate(glm::vec3 axis, float radians);
void setPosition(glm::vec3 position);
void setRotation(glm::vec3 eulerAngles);
void setRotation(glm::vec3 axis, float radians);
void setScale(float scale);
glm::vec3 getPosition() const;
glm::mat4 getModelMatrix() const;
protected:
void updateModelMatrix();
const uint32_t m_id;
static uint32_t s_idCounter;
std::string m_uniqueName;
glm::mat4 m_modelMatrix = glm::mat4(1.0f);
glm::vec3 m_position = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 m_velocity = glm::vec3(0.0f, 0.0f, 0.0f);
glm::quat m_quaternion;
float m_scale = 1.0f;
};
class ModelEntity : public Entity
{
public:
ModelEntity(Entity::Prototype prototype, Model const &model, ShaderProgram const &shaderProgram);
void draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) const;
private:
Model const &m_model;
ShaderProgram const &m_shaderProgram;
};
class Skybox
{
public:
struct Prototype
{
std::string texturePath;
};
Skybox(Prototype prototype, Model *cubeModel, ShaderProgram *shaderProgram);
~Skybox();
void initializeOnGPU();
void draw(glm::mat4 viewMatrix, glm::mat4 projectionMatrix);
private:
bool m_isInitialized = false;
Model *m_cubeModel;
ShaderProgram *m_shaderProgram;
ResourceId m_cubeMap;
VertexArray *m_vertexArray;
};

View File

@@ -4,19 +4,17 @@
#include <cstddef>
AbstractFrameBuffer::~AbstractFrameBuffer() = default;
void AbstractFrameBuffer::bind() const
void Framebuffer::bind() const
{
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
}
void AbstractFrameBuffer::unbind() const
void Framebuffer::unbind()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
GLuint AbstractFrameBuffer::getFBO() const
GLuint Framebuffer::getFBO() const
{
return m_FBO;
}

View File

@@ -1,31 +1,19 @@
#pragma once
#include "resources/Resource.h"
#include <glad/gl.h>
class ShaderProgram;
class CubeMap;
class AbstractFrameBuffer
{
public:
virtual ~AbstractFrameBuffer() = 0;
void bind() const;
void unbind() const;
GLuint getFBO() const;
protected:
GLuint m_FBO;
};
class Framebuffer : public AbstractFrameBuffer
class Framebuffer
{
public:
Framebuffer(uint32_t width, uint32_t height, ShaderProgram &shaderProgram);
~Framebuffer();
void bind() const;
static void unbind();
GLuint getFBO() const;
void drawOnEntireScreen() const;
void changeDimensions(uint32_t width, uint32_t height);
@@ -39,6 +27,7 @@ private:
GLuint m_colorBuffer;
GLuint m_depthStencilBuffer;
GLuint m_FBO;
ShaderProgram &m_shaderProgram;
};

View File

@@ -6,7 +6,7 @@
uint32_t Light::s_idCounter = 0;
Light::Light(const std::string &name, glm::vec3 color, float intensity, ShaderProgram *shaderProgram)
: Entity(name), m_shaderProgram(shaderProgram), m_intensity(intensity), m_lightColor(color * intensity)
: m_shaderProgram(shaderProgram), m_intensity(intensity), m_lightColor(color * intensity)
{
m_id = s_idCounter++;
}

View File

@@ -1,15 +1,11 @@
#pragma once
#include "Entity.h"
#include <glm/glm.hpp>
#include <string>
#define NUM_POINT_LIGHTS 1
class ShaderProgram;
class Light : public Entity
class Light
{
public:
struct Prototype

View File

@@ -1,47 +0,0 @@
#include "Mesh.h"
#include "ShaderProgram.h"
#include "VertexArray.h"
#include "resources/Texture.h"
#include <utility>
Mesh_::Mesh_(VertexArray vertexArray, std::vector<std::reference_wrapper<const Texture>> textures)
: m_vertexArray(std::move(vertexArray)), m_textures(std::move(textures))
{
}
void Mesh_::draw(ShaderProgram const &shaderProgram) const
{
// Bind all textures in order to its texture unit
std::size_t textureNum = 0;
for (auto textureIt : m_textures) {
textureIt.get().bind(static_cast<uint8_t>(textureNum), shaderProgram);
textureNum++;
}
// Draw elements
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 textureIt : m_textures) {
textureIt.get().unbind();
}
}
void Mesh_::drawWithoutTextures() const
{
m_vertexArray.bind();
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_vertexArray.indicesCount()),
static_cast<GLenum>(m_vertexArray.indicesType()), nullptr);
VertexArray::unbind();
}
auto Mesh_::getVertexArray() -> VertexArray *
{
return &m_vertexArray;
}

View File

@@ -1,23 +0,0 @@
#pragma once
#include "VertexArray.h"
#include "resources/Texture.h"
#include <vector>
class ShaderProgram;
class Mesh_
{
public:
Mesh_(VertexArray vertexArray, std::vector<std::reference_wrapper<const Texture>> textures);
void draw(ShaderProgram const &shaderProgram) const;
void drawWithoutTextures() const;
auto getVertexArray() -> VertexArray *;
private:
VertexArray m_vertexArray;
std::vector<std::reference_wrapper<const Texture>> m_textures;
};

View File

@@ -72,18 +72,21 @@ Scene::Scene()
spawn_node(node, {});
}
auto name_view = m_registry.view<Name>();
for (auto [entity, name] : name_view.each()) {
Log::logger().info("Hello entity {}!", name);
}
auto mesh_view = m_registry.view<entt::resource<Mesh>>();
for (auto [entity, mesh] : mesh_view.each()) {
m_registry.emplace<GpuMesh>(entity, GpuMesh{mesh});
m_registry.emplace<GpuMesh>(entity, GpuMesh(mesh));
// Remove Mesh resource as it is no longer needed.
m_registry.erase<entt::resource<Mesh>>(entity);
}
auto material_view = m_registry.view<entt::resource<Material>>();
for (auto [entity, material] : material_view.each()) {
m_registry.emplace<GpuMaterial>(entity, GpuMaterial(material));
// Remove Material resource as it is no longer needed.
m_registry.erase<entt::resource<Material>>(entity);
}
}
void Scene::update(std::chrono::duration<float> delta,
@@ -123,16 +126,19 @@ void Scene::update(std::chrono::duration<float> delta,
}
}
auto mesh_view = m_registry.view<GpuMesh, GlobalTransform>();
for (auto [entity, mesh, transform] : mesh_view.each()) {
auto mesh_view = m_registry.view<GpuMesh const, GpuMaterial const, GlobalTransform const>();
for (auto [entity, mesh, material, transform] : mesh_view.each()) {
shaderprogram->bind();
// Bind textures
material.bind(*shaderprogram);
// Bind modelview matrix uniform
{
glm::mat4 modelViewProj = viewProjMatrix * transform.transform;
shaderprogram->setUniform("u_modelViewProjMatrix", modelViewProj);
// shaderprogram->setUniform("u_modelMatrix", modelMatrix);
// shaderprogram->setUniform("u_viewPosition", viewPosition);
shaderprogram->setUniform("u_modelMatrix", transform.transform);
shaderprogram->setUniform("u_viewPosition", viewPosition);
}
glBindVertexArray(mesh.vao);

View File

@@ -120,6 +120,12 @@ void ShaderProgram::setUniform(const std::string &name, int value) const
glUniform1i(location, value);
}
void ShaderProgram::setUniform(const std::string &name, unsigned int value) const
{
GLint location = retrieveUniformLocation(name);
glUniform1ui(location, value);
}
void ShaderProgram::setUniform(const std::string &name, float value) const
{
GLint location = retrieveUniformLocation(name);

View File

@@ -28,6 +28,7 @@ public:
// May be rewritten...
void setUniform(const std::string &name, bool value) const;
void setUniform(const std::string &name, int value) const;
void setUniform(const std::string &name, unsigned int value) const;
void setUniform(const std::string &name, float value) const;
void setUniform(const std::string &name, glm::vec2 vector) const;
void setUniform(const std::string &name, glm::vec3 vector) const;

View File

@@ -1,183 +0,0 @@
#include "VertexArray.h"
#include "definitions/models.h"
#include "util/Log.h"
#include <cstddef>
#include <vector>
static auto accessor_byte_size(fx::gltf::Accessor::Type accessor_type) -> std::size_t
{
switch (accessor_type) {
case fx::gltf::Accessor::Type::Scalar:
return 1;
case fx::gltf::Accessor::Type::Vec2:
return 2;
case fx::gltf::Accessor::Type::Vec3:
return 3;
case fx::gltf::Accessor::Type::Vec4:
return 4;
default:
Log::logger().warn("Unexpected accessor type: {}", static_cast<int>(accessor_type));
return 0;
}
}
VertexArray::VertexArray(fx::gltf::Primitive const &primitive,
fx::gltf::Document const &model,
AttributeLocations &locations)
{
GLuint vao{};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
if (!primitive.attributes.contains("TANGENT") || !primitive.attributes.contains("NORMAL")) {
Log::logger().critical("glTF scene has to include tangent and normal components!");
std::terminate();
}
int position_accessor_id = primitive.attributes.at("POSITION");
int normal_accessor_id = primitive.attributes.at("NORMAL");
int uv_accessor_id = primitive.attributes.at("TEXCOORD_0");
int tangent_accessor_id = primitive.attributes.at("TANGENT");
int indices_accessor_id = primitive.indices;
auto const &position_accessor = model.accessors.at(position_accessor_id);
auto const &normal_accessor = model.accessors.at(normal_accessor_id);
auto const &uv_accessor = model.accessors.at(uv_accessor_id);
auto const &tangent_accessor = model.accessors.at(tangent_accessor_id);
auto const &indices_accessor = model.accessors.at(indices_accessor_id);
int position_buffer_view_id = model.accessors[position_accessor_id].bufferView;
int normal_buffer_view_id = model.accessors[normal_accessor_id].bufferView;
int uv_buffer_view_id = model.accessors[uv_accessor_id].bufferView;
int tangent_buffer_view_id = model.accessors[tangent_accessor_id].bufferView;
int indices_buffer_view_id = model.accessors[indices_accessor_id].bufferView;
auto const &position_buffer_view = model.bufferViews.at(position_buffer_view_id);
auto const &normal_buffer_view = model.bufferViews.at(normal_buffer_view_id);
auto const &uv_buffer_view = model.bufferViews.at(uv_buffer_view_id);
auto const &tangent_buffer_view = model.bufferViews.at(tangent_buffer_view_id);
auto const &indices_buffer_view = model.bufferViews.at(indices_buffer_view_id);
auto const &position_buffer = model.buffers.at(position_buffer_view.buffer);
auto const &normal_buffer = model.buffers.at(normal_buffer_view.buffer);
auto const &uv_buffer = model.buffers.at(uv_buffer_view.buffer);
auto const &tangent_buffer = model.buffers.at(tangent_buffer_view.buffer);
auto const &indices_buffer = model.buffers.at(indices_buffer_view.buffer);
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);
glEnableVertexAttribArray(locations.position);
glVertexAttribPointer(locations.position,
accessor_byte_size(position_accessor.type),
static_cast<GLenum>(position_accessor.componentType),
position_accessor.normalized ? GL_TRUE : GL_FALSE,
position_buffer_view.byteStride,
reinterpret_cast<void *>(position_accessor.byteOffset)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,
// performance-no-int-to-ptr)
}
GLuint normalVbo{};
{
glGenBuffers(1, &normalVbo);
glBindBuffer(GL_ARRAY_BUFFER, normalVbo);
glBufferData(GL_ARRAY_BUFFER,
normal_buffer_view.byteLength,
normal_buffer.data.data() + normal_buffer_view.byteOffset,
GL_STATIC_DRAW);
glEnableVertexAttribArray(locations.normal);
glVertexAttribPointer(locations.normal,
accessor_byte_size(normal_accessor.type),
static_cast<GLenum>(normal_accessor.componentType),
normal_accessor.normalized ? GL_TRUE : GL_FALSE,
normal_buffer_view.byteStride,
reinterpret_cast<void *>(normal_accessor.byteOffset)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,
// performance-no-int-to-ptr)
}
GLuint uvVbo{};
{
glGenBuffers(1, &uvVbo);
glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
glBufferData(GL_ARRAY_BUFFER,
uv_buffer_view.byteLength,
uv_buffer.data.data() + uv_buffer_view.byteOffset,
GL_STATIC_DRAW);
glEnableVertexAttribArray(locations.uv);
glVertexAttribPointer(locations.uv,
accessor_byte_size(uv_accessor.type),
static_cast<GLenum>(uv_accessor.componentType),
uv_accessor.normalized ? GL_TRUE : GL_FALSE,
uv_buffer_view.byteStride,
reinterpret_cast<void *>(uv_accessor.byteOffset)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,
// performance-no-int-to-ptr)
}
GLuint tangentVbo{};
{
glGenBuffers(1, &tangentVbo);
glBindBuffer(GL_ARRAY_BUFFER, tangentVbo);
glBufferData(GL_ARRAY_BUFFER,
tangent_buffer_view.byteLength,
tangent_buffer.data.data() + tangent_buffer_view.byteOffset,
GL_STATIC_DRAW);
glEnableVertexAttribArray(locations.tangent);
glVertexAttribPointer(locations.tangent,
accessor_byte_size(tangent_accessor.type),
static_cast<GLenum>(tangent_accessor.componentType),
tangent_accessor.normalized ? GL_TRUE : GL_FALSE,
tangent_buffer_view.byteStride,
reinterpret_cast<void *>(tangent_accessor.byteOffset)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,
// performance-no-int-to-ptr)
}
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);
glBindVertexArray(0);
m_vao = vao;
m_ebo = ebo;
m_positionVbo = positionVbo;
m_normalVbo = normalVbo;
m_uvVbo = uvVbo;
m_tangentVbo = tangentVbo;
m_indicesCount = indices_accessor.count;
m_indicesType = indices_accessor.componentType;
}
VertexArray::~VertexArray()
{
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_positionVbo);
glDeleteBuffers(1, &m_normalVbo);
glDeleteBuffers(1, &m_uvVbo);
glDeleteBuffers(1, &m_tangentVbo);
glDeleteBuffers(1, &m_ebo);
}
void VertexArray::bind() const
{
glBindVertexArray(m_vao);
}
void VertexArray::unbind()
{
glBindVertexArray(0);
}

View File

@@ -1,74 +0,0 @@
#pragma once
#include "definitions/attribute_locations.h"
#include <glad/gl.h>
#include <fx/gltf.h>
#include <vector>
class VertexArray final
{
public:
VertexArray(fx::gltf::Primitive const &primitive, fx::gltf::Document 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_normalVbo(other.m_normalVbo),
m_uvVbo(other.m_uvVbo),
m_tangentVbo(other.m_tangentVbo),
m_ebo(other.m_ebo)
{
other.m_ebo = 0;
other.m_vao = 0;
other.m_positionVbo = 0;
other.m_normalVbo = 0;
other.m_uvVbo = 0;
other.m_tangentVbo = 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_normalVbo = other.m_normalVbo;
m_uvVbo = other.m_uvVbo;
m_tangentVbo = other.m_tangentVbo;
m_ebo = other.m_ebo;
other.m_ebo = 0;
other.m_vao = 0;
other.m_positionVbo = 0;
other.m_normalVbo = 0;
other.m_uvVbo = 0;
other.m_tangentVbo = 0;
return *this;
}
VertexArray(VertexArray const &) = delete;
auto operator=(VertexArray const &) -> VertexArray & = delete;
~VertexArray();
void bind() const;
static void unbind();
[[nodiscard]] auto indicesCount() const -> uint64_t { return m_indicesCount; }
[[nodiscard]] auto indicesType() const -> fx::gltf::Accessor::ComponentType { return m_indicesType; }
private:
uint64_t m_indicesCount;
fx::gltf::Accessor::ComponentType m_indicesType;
GLuint m_vao;
GLuint m_positionVbo;
GLuint m_normalVbo;
GLuint m_uvVbo;
GLuint m_tangentVbo;
GLuint m_ebo;
};

View File

@@ -2,8 +2,10 @@
struct AttributeLocations
{
int position;
int normal;
int uv;
int tangent;
int position = 0;
int uv = 1;
int normal = 2;
int tangent = 3;
};
static constexpr AttributeLocations ATTRIBUTE_LOCATION;

View File

@@ -1,21 +0,0 @@
#pragma once
#include <glm/glm.hpp>
struct Vertex
{
// Postition
glm::vec3 position;
// UV Texture Mapping
glm::vec2 textureCoords;
// Normal vector
glm::vec3 normalVec;
// Tangent vector
glm::vec3 tangentVec;
// Bittangent vector
glm::vec3 bitangentVec;
};

View File

@@ -1,5 +1,6 @@
#include "gltf_loader.h"
#include "util/Log.h"
#include "definitions/attribute_locations.h"
#include <iterator>
@@ -117,16 +118,16 @@ static auto load_attribute(std::string_view attribute_name,
auto vertex_attribute_id = [attribute_name]() -> std::optional<std::size_t> {
if (attribute_name == "POSITION") {
return 0;
return ATTRIBUTE_LOCATION.position;
}
if (attribute_name == "TEXCOORD_0") {
return 1;
return ATTRIBUTE_LOCATION.uv;
}
if (attribute_name == "NORMAL") {
return 2;
return ATTRIBUTE_LOCATION.normal;
}
if (attribute_name == "TANGENT") {
return 3;
return ATTRIBUTE_LOCATION.tangent;
}
return {};

32
src/material.cpp Normal file
View File

@@ -0,0 +1,32 @@
#include "material.h"
#include "ShaderProgram.h"
GpuMaterial::GpuMaterial(Material const &material)
{
int texture_unit_counter = 0;
if (material.base_color_texture.has_value()) {
Binding binding{.uniform_name = "u_material.texture_diffuse",
.texture_unit = texture_unit_counter++};
base_color_texture = std::make_pair(GpuImage(material.base_color_texture.value()), binding);
}
if (material.normal_map_texture.has_value()) {
Binding binding{.uniform_name = "u_material.texture_normal",
.texture_unit = texture_unit_counter++};
normal_map_texture = std::make_pair(GpuImage(material.normal_map_texture.value()), binding);
}
}
void GpuMaterial::bind(ShaderProgram const &shader_program) const
{
auto bind_texture = [&shader_program](auto const &texture) {
if (texture.has_value()) {
shader_program.setUniform(texture->second.uniform_name, texture->second.texture_unit);
glActiveTexture(GL_TEXTURE0 + texture->second.texture_unit);
glBindTexture(GL_TEXTURE_2D, texture->first.texture);
}
};
bind_texture(base_color_texture);
bind_texture(normal_map_texture);
}

View File

@@ -5,8 +5,26 @@
#include <entt/entt.hpp>
#include <optional>
class ShaderProgram;
struct Material
{
std::optional<entt::resource<Image>> base_color_texture;
std::optional<entt::resource<Image>> normal_map_texture;
};
struct GpuMaterial
{
GpuMaterial(Material const &material);
void bind(ShaderProgram const &shader_program) const;
struct Binding
{
std::string uniform_name;
int texture_unit;
};
std::optional<std::pair<GpuImage, Binding>> base_color_texture;
std::optional<std::pair<GpuImage, Binding>> normal_map_texture;
};

View File

@@ -50,6 +50,7 @@ struct GpuMesh
{
other.vao = 0;
}
auto operator=(GpuMesh &&other) noexcept -> GpuMesh &
{
vao = other.vao;

View File

@@ -2,4 +2,7 @@
#include <string>
using Name = std::string;
struct Name
{
std::string name;
};

View File

@@ -1,29 +0,0 @@
#include "Model.h"
#include "Texture.h"
#include "../util/Log.h"
Model::Model(std::string_view name, std::vector<Mesh_> meshes) : m_meshes(std::move(meshes)), m_name(name)
{
Log::logger().trace(R"(Loaded model "{}".)", name);
}
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);
}
}
void Model::drawWithoutTextures() const
{
// Iterate through every mesh and call the draw function
for (const auto &mesh : m_meshes) {
mesh.drawWithoutTextures();
}
}
auto Model::getMesh(unsigned int index) -> Mesh_ *
{
return &m_meshes[index];
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include "../Mesh.h"
#include "Resource.h"
#include <string>
#include <vector>
class Model
{
public:
Model(std::string_view name, std::vector<Mesh_> meshes);
void draw(ShaderProgram const &shaderProgram) const;
void drawWithoutTextures() const;
auto getMesh(unsigned int index) -> Mesh_ *; // TODO...
private:
std::vector<Mesh_> m_meshes;
std::vector<ResourceId> m_textures;
std::string m_name;
};

View File

@@ -1,35 +0,0 @@
#include "Resource.h"
#include "../util/Log.h"
ResourceId Resource::s_idCounter = 0;
Resource::Resource(std::filesystem::path path) : m_id(s_idCounter++), m_path(std::move(path))
{
Log::logger().info("Resource \"{}\" with id {} created", m_path.string(), m_id);
}
auto Resource::id() const -> ResourceId
{
return m_id;
}
auto Resource::resourcePath() const -> const std::filesystem::path &
{
return m_path;
}
auto GlResource::glId() const -> GLuint
{
return m_glId;
}
NamedResource::NamedResource(std::string name) : m_name(std::move(name))
{
}
auto NamedResource::name() const -> const std::string &
{
return m_name;
}
NamedResource::~NamedResource() = default;

View File

@@ -1,53 +0,0 @@
#pragma once
#include <cstdint>
#include <filesystem>
#include <glad/gl.h>
#include <string>
using ResourceId = uint64_t;
class Resource
{
public:
Resource(std::filesystem::path path);
Resource(const Resource &other) = delete;
Resource(Resource &&other) = delete;
auto operator=(const Resource &other) -> Resource & = delete;
auto operator=(Resource &&other) -> Resource & = delete;
[[nodiscard]] auto id() const -> ResourceId;
[[nodiscard]] auto resourcePath() const -> const std::filesystem::path &;
private:
ResourceId m_id;
static ResourceId s_idCounter;
std::filesystem::path m_path;
friend class ResourceHandler;
};
class GlResource
{
public:
// virtual ~GlResource() = 0; TODO!!
virtual void unbind() const = 0;
auto glId() const -> GLuint;
protected:
GLuint m_glId;
};
class NamedResource
{
public:
NamedResource(std::string name);
virtual ~NamedResource() = 0;
[[nodiscard]] auto name() const -> const std::string &;
private:
const std::string m_name;
};

View File

@@ -1,36 +0,0 @@
#include "ResourceHandler.h"
#include "../util/Log.h"
#include "CubeMap.h"
#include <algorithm>
ResourceHandler ResourceHandler::s_instance;
auto ResourceHandler::instance() -> ResourceHandler &
{
return s_instance;
}
template <typename T, typename... Param>
auto ResourceHandler::registerResource(Param const &...param) -> ResourceId
{
auto resource = std::make_shared<T>(param...);
m_resources.emplace(resource->id(), resource);
return resource->id();
}
template ResourceId ResourceHandler::registerResource<TextureCubeMap>(TextureCubeMapDescriptor const &);
template ResourceId ResourceHandler::registerResource<InternalCubeMap>(int const &);
auto ResourceHandler::resource(const ResourceId resourceId) const -> std::shared_ptr<Resource>
{
auto resourceIt = m_resources.find(resourceId);
if (resourceIt != m_resources.end()) {
auto resource = resourceIt->second;
return resource;
}
Log::logger().warn("Could not find resource with id {}", resourceId);
return {};
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include "Resource.h"
#include <map>
#include <memory>
class ResourceHandler
{
public:
static auto instance() -> ResourceHandler &;
template <typename T, typename... Param>
auto registerResource(Param const &...param) -> ResourceId;
[[nodiscard]] auto resource(ResourceId resourceId) const -> std::shared_ptr<Resource>;
private:
ResourceHandler() = default;
static ResourceHandler s_instance;
std::map<ResourceId, std::shared_ptr<Resource>> m_resources;
};

View File

@@ -1,12 +0,0 @@
#pragma once
#include "Resource.h"
class ShaderProgram : public GlResource, public NamedResource
{
public:
ShaderProgram();
void bind() const;
void unbind() const override;
}

View File

@@ -1,129 +0,0 @@
#include "Texture.h"
#include "../ShaderProgram.h"
#include "../util/Log.h"
// #define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
Texture::Texture(fx::gltf::Texture const &texture,
std::filesystem::path const &working_directory,
std::span<fx::gltf::Image> images,
std::span<fx::gltf::BufferView> bufferViews,
std::span<fx::gltf::Buffer> buffers,
std::span<fx::gltf::Sampler> samplers,
TextureType textureType)
: m_textureType(textureType)
{
auto sampler_id = texture.sampler;
auto sampler = [samplers, sampler_id]() {
if (sampler_id != -1) {
return samplers[static_cast<unsigned>(sampler_id)];
}
return fx::gltf::Sampler{.magFilter = fx::gltf::Sampler::MagFilter::Linear,
.minFilter = fx::gltf::Sampler::MinFilter::LinearMipMapLinear,
.wrapS = fx::gltf::Sampler::WrappingMode::Repeat,
.wrapT = fx::gltf::Sampler::WrappingMode::Repeat};
}();
auto const &image = images[static_cast<unsigned>(texture.source)];
auto const &imageBufferView = bufferViews[static_cast<unsigned>(image.bufferView)];
auto const &imageBuffer = buffers[static_cast<unsigned>(imageBufferView.buffer)];
int width{};
int height{};
int components{};
auto *stbi_image = [&]() {
if (!image.uri.empty()) {
auto image_path = working_directory / image.uri;
return stbi_load(image_path.c_str(), &width, &height, &components, 0);
}
return stbi_load_from_memory(&imageBuffer.data[imageBufferView.byteOffset],
static_cast<int>(imageBufferView.byteOffset),
&width,
&height,
&components,
0);
}();
GLenum internalFormat{};
GLenum dataFormat{};
switch (components) {
case 1:
internalFormat = GL_RED;
dataFormat = GL_RED;
break;
case 3:
internalFormat = (m_textureType == TextureType::Diffuse) ? GL_SRGB8 : GL_RGB8;
dataFormat = GL_RGB;
break;
case 4:
internalFormat = (m_textureType == TextureType::Diffuse) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
dataFormat = GL_RGBA;
break;
}
glGenTextures(1, &m_glId);
glBindTexture(GL_TEXTURE_2D, m_glId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(sampler.magFilter));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(sampler.minFilter));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -2.0F);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, static_cast<GLint>(sampler.wrapS));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, static_cast<GLint>(sampler.wrapT));
glTexImage2D(GL_TEXTURE_2D,
0,
static_cast<GLint>(internalFormat),
static_cast<GLsizei>(width),
static_cast<GLsizei>(height),
0,
dataFormat,
GL_UNSIGNED_BYTE,
stbi_image);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(stbi_image);
Log::logger().trace(R"(Loaded texture "{}")", image.name);
}
auto Texture::textureType() const -> TextureType
{
return m_textureType;
}
void Texture::bind(uint8_t textureUnit, ShaderProgram const &shaderProgram) const
{
std::string uniformName = "texture_";
switch (m_textureType) {
case TextureType::Diffuse:
uniformName += "diffuse";
break;
case TextureType::Normal:
uniformName += "normal";
break;
default:
break;
}
// Add u_material as we store textures in a struct
uniformName = "u_material." + uniformName;
shaderProgram.setUniform(uniformName, textureUnit);
glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(GL_TEXTURE_2D, m_glId);
}
void Texture::unbind()
{
glBindTexture(GL_TEXTURE_2D, 0);
}

View File

@@ -1,32 +0,0 @@
#pragma once
#include "TextureType.h"
#include <filesystem>
#include <fx/gltf.h>
#include <glad/gl.h>
#include <span>
#include <string>
class ShaderProgram;
class Texture
{
public:
Texture(fx::gltf::Texture const &texture,
std::filesystem::path const &working_directory,
std::span<fx::gltf::Image> images,
std::span<fx::gltf::BufferView> bufferViews,
std::span<fx::gltf::Buffer> buffers,
std::span<fx::gltf::Sampler> samplers,
TextureType textureType);
[[nodiscard]] auto textureType() const -> TextureType;
void bind(uint8_t textureUnit, ShaderProgram const &shaderProgram) const;
static void unbind();
private:
TextureType m_textureType;
GLuint m_glId = 0;
};

View File

@@ -1,8 +0,0 @@
#pragma once
enum class TextureType
{
Diffuse,
Normal,
TEXTURE_TYPE_NUM_ITEMS
};

View File

@@ -1 +0,0 @@
#pragma once