Refactor framebuffer
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
#version 330 core
|
||||
|
||||
const float GAMMA = 2.2f;
|
||||
const float EXPOSURE = 1.0f;
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
in vec2 v_tex_coords;
|
||||
|
||||
uniform float u_exposure;
|
||||
uniform bool u_exposureCorrection;
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
void main() {
|
||||
@@ -16,8 +14,7 @@ void main() {
|
||||
vec3 fragmentColor = vec3(texture2D(u_texture, v_tex_coords));
|
||||
|
||||
// Exposure tone mapping
|
||||
if(u_exposureCorrection)
|
||||
fragmentColor = vec3(1.0) - exp(-fragmentColor * u_exposure);
|
||||
fragmentColor = vec3(1.0) - exp(-fragmentColor * EXPOSURE);
|
||||
|
||||
// Gamma correction
|
||||
fragmentColor = pow(fragmentColor, vec3(1.0/GAMMA));
|
||||
|
||||
@@ -3,11 +3,11 @@ add_library(fever_engine
|
||||
Controller.cpp
|
||||
Window.cpp
|
||||
scene.cpp
|
||||
FrameBuffer.cpp
|
||||
Helper.cpp
|
||||
framebuffer.cpp
|
||||
util/Log.cpp
|
||||
image.cpp
|
||||
mesh.cpp
|
||||
glad.cpp
|
||||
gltf_loader.cpp
|
||||
material.cpp
|
||||
camera.cpp
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "Controller.h"
|
||||
#include "FrameBuffer.h"
|
||||
#include "Helper.h"
|
||||
#include "Window.h"
|
||||
#include "gltf_loader.h"
|
||||
#include "input.h"
|
||||
@@ -24,9 +22,11 @@
|
||||
|
||||
using namespace entt::literals;
|
||||
|
||||
static constexpr unsigned MAX_FPS = 60;
|
||||
|
||||
Controller::Controller()
|
||||
: m_gameWindow(std::make_shared<Window>()),
|
||||
m_postProcessFrameBuffer(m_gameWindow->physical_dimensions(), post_processing_shader),
|
||||
post_processing_framebuffer(m_gameWindow->physical_dimensions()),
|
||||
m_gltf_loader{.image_cache = m_image_cache,
|
||||
.material_cache = m_material_cache,
|
||||
.mesh_cache = m_mesh_cache,
|
||||
@@ -47,8 +47,6 @@ Controller::Controller()
|
||||
|
||||
void Controller::run()
|
||||
{
|
||||
updateExposure(post_processing_shader);
|
||||
|
||||
entt::hashed_string shader_hash(Material::SHADER_NAME.data());
|
||||
auto standard_material_shader =
|
||||
m_shader_cache.load(shader_hash, Material::SHADER_NAME).first->second;
|
||||
@@ -77,14 +75,14 @@ void Controller::run()
|
||||
// --- Render and buffer swap ---
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
m_postProcessFrameBuffer.bind();
|
||||
post_processing_framebuffer.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
Light::update_lights(m_scene->registry(), standard_material_shader);
|
||||
Render::render(m_scene->registry());
|
||||
|
||||
Framebuffer::unbind();
|
||||
m_postProcessFrameBuffer.drawOnEntireScreen();
|
||||
post_processing_framebuffer.draw(post_processing_shader);
|
||||
|
||||
glfwSwapBuffers(&m_gameWindow->glfw_window());
|
||||
|
||||
@@ -120,14 +118,7 @@ void Controller::update_window_dimensions()
|
||||
// m_gameEventHandler->setFirstMouseInput(1);
|
||||
|
||||
auto dimensions = m_gameWindow->physical_dimensions();
|
||||
m_postProcessFrameBuffer.updateDimensions(dimensions);
|
||||
}
|
||||
|
||||
void Controller::updateExposure(Shader& shader) const
|
||||
{
|
||||
shader.bind();
|
||||
shader.set_uniform("u_exposure", m_exposure);
|
||||
Shader::unbind();
|
||||
post_processing_framebuffer = Framebuffer(dimensions);
|
||||
}
|
||||
|
||||
void Controller::update_delta_time(entt::registry& registry) const
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "FrameBuffer.h"
|
||||
#include "framebuffer.h"
|
||||
#include "gltf_loader.h"
|
||||
#include "scene.h"
|
||||
#include "shader.h"
|
||||
@@ -23,26 +23,19 @@ public:
|
||||
|
||||
void run();
|
||||
|
||||
void updateExposure(Shader &shader) const;
|
||||
|
||||
private:
|
||||
void limit_framerate();
|
||||
void update_delta_time(entt::registry ®istry) const;
|
||||
void update_delta_time(entt::registry& registry) const;
|
||||
void update_window_dimensions();
|
||||
|
||||
std::shared_ptr<Window> m_gameWindow;
|
||||
|
||||
Shader skybox_shader{"skybox", "data/shaders"};
|
||||
Shader post_processing_shader{"post_processing", "data/shaders"};
|
||||
|
||||
Framebuffer m_postProcessFrameBuffer;
|
||||
|
||||
static constexpr unsigned MAX_FPS = 60;
|
||||
|
||||
std::shared_ptr<Scene> m_scene;
|
||||
Shader skybox_shader{"skybox", "data/shaders"};
|
||||
|
||||
Shader post_processing_shader{"post_processing", "data/shaders"};
|
||||
Framebuffer post_processing_framebuffer;
|
||||
|
||||
double m_deltaTime{};
|
||||
float m_exposure = 1.0;
|
||||
|
||||
// Resource caches
|
||||
entt::resource_cache<Image> m_image_cache;
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
#include "FrameBuffer.h"
|
||||
#include "shader.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <glm/fwd.hpp>
|
||||
|
||||
void Framebuffer::bind() const
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
|
||||
}
|
||||
|
||||
void Framebuffer::unbind()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
GLuint Framebuffer::getFBO() const
|
||||
{
|
||||
return m_FBO;
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(glm::u32vec2 physical_dimensions, Shader &shader) : m_shader(shader)
|
||||
{
|
||||
glGenFramebuffers(1, &m_FBO);
|
||||
|
||||
generateTextures(physical_dimensions.x, physical_dimensions.y);
|
||||
setExposureCorrection(true);
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer()
|
||||
{
|
||||
glDeleteFramebuffers(1, &m_FBO);
|
||||
glDeleteTextures(1, &m_colorBuffer);
|
||||
glDeleteRenderbuffers(1, &m_depthStencilBuffer);
|
||||
}
|
||||
|
||||
GLuint Framebuffer::getTextureId() const
|
||||
{
|
||||
return m_colorBuffer;
|
||||
}
|
||||
|
||||
void Framebuffer::drawOnEntireScreen() const
|
||||
{
|
||||
// Disable wireframe mode
|
||||
GLint wireframe;
|
||||
glGetIntegerv(GL_POLYGON_MODE, &wireframe);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
m_shader.bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, getTextureId());
|
||||
|
||||
m_shader.set_uniform("u_texture", 0);
|
||||
|
||||
// A VAO is necessary although no data is stored in it
|
||||
GLuint temp_vao;
|
||||
glGenVertexArrays(1, &temp_vao);
|
||||
glBindVertexArray(temp_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindVertexArray(0);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, static_cast<GLenum>(wireframe));
|
||||
m_shader.unbind();
|
||||
}
|
||||
|
||||
void Framebuffer::updateDimensions(glm::u32vec2 physical_dimensions)
|
||||
{
|
||||
// Delete old textures
|
||||
glDeleteTextures(1, &m_colorBuffer);
|
||||
glDeleteRenderbuffers(1, &m_depthStencilBuffer);
|
||||
|
||||
generateTextures(physical_dimensions.x, physical_dimensions.y);
|
||||
}
|
||||
|
||||
void Framebuffer::generateTextures(uint32_t width, uint32_t height)
|
||||
{
|
||||
bind();
|
||||
|
||||
// Create new textures
|
||||
glGenTextures(1, &m_colorBuffer);
|
||||
glGenRenderbuffers(1, &m_depthStencilBuffer);
|
||||
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, m_colorBuffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, static_cast<GLsizei>(width), static_cast<GLsizei>(height), 0,
|
||||
GL_RGBA, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
std::array<unsigned, 3> attachments = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
|
||||
glDrawBuffers(3, attachments.data());
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, static_cast<GLsizei>(width),
|
||||
static_cast<GLsizei>(height));
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
Log::logger().error("Framebuffer not complete");
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
unbind();
|
||||
}
|
||||
|
||||
void Framebuffer::setExposureCorrection(bool exposureCorrection) const
|
||||
{
|
||||
m_shader.bind();
|
||||
m_shader.set_uniform("u_exposureCorrection", exposureCorrection);
|
||||
m_shader.unbind();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <glad/gl.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Shader;
|
||||
|
||||
class Framebuffer
|
||||
{
|
||||
public:
|
||||
Framebuffer(glm::u32vec2 physical_dimensions, Shader &shader);
|
||||
~Framebuffer();
|
||||
|
||||
void bind() const;
|
||||
static void unbind();
|
||||
GLuint getFBO() const;
|
||||
|
||||
void drawOnEntireScreen() const;
|
||||
|
||||
void updateDimensions(glm::u32vec2 physical_dimensions);
|
||||
void setExposureCorrection(bool exposureCorrection) const;
|
||||
|
||||
GLuint getTextureId() const;
|
||||
|
||||
private:
|
||||
void generateTextures(uint32_t width, uint32_t height);
|
||||
|
||||
GLuint m_colorBuffer;
|
||||
GLuint m_depthStencilBuffer;
|
||||
GLuint m_FBO;
|
||||
|
||||
Shader &m_shader;
|
||||
};
|
||||
31
src/Helper.h
31
src/Helper.h
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <glad/gl.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
namespace Helper {
|
||||
void gl_debug_callback(GLenum source,
|
||||
GLenum type,
|
||||
GLuint id,
|
||||
GLenum severity,
|
||||
GLsizei length,
|
||||
const GLchar *message,
|
||||
const void *userParam);
|
||||
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
Timer(const std::string &name);
|
||||
~Timer();
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_start;
|
||||
std::chrono::high_resolution_clock::time_point m_end;
|
||||
std::chrono::duration<float> m_duration;
|
||||
};
|
||||
|
||||
} // namespace Helper
|
||||
@@ -1,10 +1,12 @@
|
||||
#include "Window.h"
|
||||
#include "Helper.h"
|
||||
#include "definitions/window.h"
|
||||
#include "util/Log.h"
|
||||
#include "glad.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glad/gl.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
static constexpr unsigned INIT_WINDOW_WIDTH = 1280;
|
||||
static constexpr unsigned INIT_WINDOW_HEIGHT = 720;
|
||||
|
||||
Window::Window()
|
||||
{
|
||||
@@ -31,54 +33,20 @@ Window::Window()
|
||||
// Create OpenGL context
|
||||
glfwMakeContextCurrent(m_glfw_window.get());
|
||||
|
||||
// Initialize GLAD
|
||||
if (gladLoadGL(glfwGetProcAddress) == 0) {
|
||||
Log::logger().critical("Failed to initialize GLAD");
|
||||
std::quick_exit(-1);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
auto const* gl_version = reinterpret_cast<char const*>(glGetString(GL_VERSION));
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
Log::logger().debug("OpenGL version: {}", gl_version);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
glDebugMessageCallback(&Helper::gl_debug_callback, nullptr);
|
||||
#endif
|
||||
|
||||
// Enable z buffer
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
// Enable face culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
glFrontFace(GL_CW);
|
||||
glCullFace(GL_FRONT);
|
||||
|
||||
// Enable multisampling (a bit redundant because most graphics drivers do this automatically)
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Disable mouse cursor
|
||||
m_mouse_catched.catched = false;
|
||||
#endif
|
||||
|
||||
// Disable VSync
|
||||
glfwSwapInterval(0);
|
||||
|
||||
set_catched_cursor(m_mouse_catched.catched);
|
||||
|
||||
{
|
||||
int width{};
|
||||
int height{};
|
||||
glfwGetFramebufferSize(m_glfw_window.get(), &width, &height);
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
// Callbacks
|
||||
glfwSetWindowUserPointer(m_glfw_window.get(), this);
|
||||
glfwSetKeyCallback(m_glfw_window.get(), key_callback);
|
||||
glfwSetCursorPosCallback(m_glfw_window.get(), mouse_cursor_callback);
|
||||
glfwSetFramebufferSizeCallback(m_glfw_window.get(), framebuffer_size_callback);
|
||||
|
||||
init_glad();
|
||||
}
|
||||
|
||||
auto Window::dimensions_changed() -> bool
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
struct AttributeLocations
|
||||
{
|
||||
int position = 0;
|
||||
int uv = 1;
|
||||
int normal = 2;
|
||||
int tangent = 3;
|
||||
};
|
||||
|
||||
static constexpr AttributeLocations ATTRIBUTE_LOCATION;
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
static constexpr unsigned INIT_WINDOW_WIDTH = 1280;
|
||||
static constexpr unsigned INIT_WINDOW_HEIGHT = 720;
|
||||
100
src/framebuffer.cpp
Normal file
100
src/framebuffer.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "framebuffer.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
Framebuffer::Framebuffer(glm::u32vec2 physical_dimensions)
|
||||
{
|
||||
glGenFramebuffers(1, &frame_buffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer);
|
||||
|
||||
auto width = static_cast<GLsizei>(physical_dimensions.x);
|
||||
auto height = static_cast<GLsizei>(physical_dimensions.y);
|
||||
|
||||
// Create new textures
|
||||
glGenTextures(1, &color_buffer);
|
||||
glGenRenderbuffers(1, &depth_stencil_buffer);
|
||||
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, color_buffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_buffer, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
std::array<unsigned, 3> attachments = {
|
||||
GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
|
||||
glDrawBuffers(3, attachments.data());
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_buffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
glFramebufferRenderbuffer(
|
||||
GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depth_stencil_buffer);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
Log::logger().error("Framebuffer not complete");
|
||||
}
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(Framebuffer&& other) noexcept
|
||||
: color_buffer(other.color_buffer),
|
||||
depth_stencil_buffer(other.depth_stencil_buffer),
|
||||
frame_buffer(other.frame_buffer)
|
||||
{
|
||||
other.color_buffer = 0;
|
||||
other.depth_stencil_buffer = 0;
|
||||
other.frame_buffer = 0;
|
||||
}
|
||||
|
||||
auto Framebuffer::operator=(Framebuffer&& other) noexcept -> Framebuffer&
|
||||
{
|
||||
glDeleteFramebuffers(1, &frame_buffer);
|
||||
glDeleteTextures(1, &color_buffer);
|
||||
glDeleteRenderbuffers(1, &depth_stencil_buffer);
|
||||
|
||||
color_buffer = other.color_buffer;
|
||||
depth_stencil_buffer = other.depth_stencil_buffer;
|
||||
frame_buffer = other.frame_buffer;
|
||||
|
||||
other.color_buffer = 0;
|
||||
other.depth_stencil_buffer = 0;
|
||||
other.frame_buffer = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer()
|
||||
{
|
||||
glDeleteFramebuffers(1, &frame_buffer);
|
||||
glDeleteTextures(1, &color_buffer);
|
||||
glDeleteRenderbuffers(1, &depth_stencil_buffer);
|
||||
}
|
||||
|
||||
void Framebuffer::draw(Shader const& shader) const
|
||||
{
|
||||
GLint polygon_mode{};
|
||||
glGetIntegerv(GL_POLYGON_MODE, &polygon_mode);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
shader.bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, color_buffer);
|
||||
|
||||
shader.set_uniform("u_texture", 0);
|
||||
|
||||
// A VAO is necessary although no data is stored in it
|
||||
GLuint vao{};
|
||||
glGenVertexArrays(1, &vao);
|
||||
glBindVertexArray(vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, static_cast<GLenum>(polygon_mode));
|
||||
Shader::unbind();
|
||||
}
|
||||
28
src/framebuffer.h
Normal file
28
src/framebuffer.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "shader.h"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
struct Framebuffer
|
||||
{
|
||||
Framebuffer(glm::u32vec2 physical_dimensions);
|
||||
~Framebuffer();
|
||||
|
||||
Framebuffer(Framebuffer const&) = delete;
|
||||
auto operator=(Framebuffer const&) -> Framebuffer& = delete;
|
||||
|
||||
Framebuffer(Framebuffer&& other) noexcept;
|
||||
auto operator=(Framebuffer&& other) noexcept -> Framebuffer&;
|
||||
|
||||
void bind() const { glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer); }
|
||||
static void unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
|
||||
|
||||
void draw(Shader const& shader) const;
|
||||
|
||||
GLuint color_buffer{};
|
||||
GLuint depth_stencil_buffer{};
|
||||
GLuint frame_buffer{};
|
||||
};
|
||||
@@ -1,22 +1,22 @@
|
||||
#include "Helper.h"
|
||||
#include "glad.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
void Helper::gl_debug_callback(GLenum source,
|
||||
GLenum type,
|
||||
GLuint id,
|
||||
GLenum severity,
|
||||
GLsizei length,
|
||||
const GLchar *message,
|
||||
const void *userParam)
|
||||
static void gl_debug_callback(GLenum source,
|
||||
GLenum type,
|
||||
GLuint id,
|
||||
GLenum severity,
|
||||
GLsizei length,
|
||||
GLchar const* message,
|
||||
void const* userParam)
|
||||
{
|
||||
(void)length;
|
||||
(void)userParam;
|
||||
|
||||
const char *_source;
|
||||
const char *_type;
|
||||
const char *_severity;
|
||||
char const* _source;
|
||||
char const* _type;
|
||||
char const* _severity;
|
||||
|
||||
// Remove unwanted newline characters from message string
|
||||
std::string _message = message;
|
||||
@@ -108,7 +108,7 @@ void Helper::gl_debug_callback(GLenum source,
|
||||
break;
|
||||
}
|
||||
|
||||
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM)
|
||||
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) {
|
||||
Log::logger().debug("[OpenGL Debug Message]\n"
|
||||
"Message: {}\n"
|
||||
"Source: {}\n"
|
||||
@@ -120,19 +120,37 @@ void Helper::gl_debug_callback(GLenum source,
|
||||
_type,
|
||||
id,
|
||||
_severity);
|
||||
}
|
||||
}
|
||||
|
||||
Helper::Timer::Timer(const std::string &name) : m_name(name)
|
||||
void init_glad()
|
||||
{
|
||||
m_start = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
Helper::Timer::~Timer()
|
||||
{
|
||||
m_end = std::chrono::high_resolution_clock::now();
|
||||
|
||||
m_duration = m_end - m_start;
|
||||
float ms = m_duration.count() * 1000.0f;
|
||||
|
||||
Log::logger().info("Timer {} took {}", m_name, ms);
|
||||
// Initialize GLAD
|
||||
if (gladLoadGL(glfwGetProcAddress) == 0) {
|
||||
Log::logger().critical("Failed to initialize GLAD");
|
||||
std::quick_exit(-1);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
auto const* gl_version = reinterpret_cast<char const*>(glGetString(GL_VERSION));
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
Log::logger().debug("OpenGL version: {}", gl_version);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
glDebugMessageCallback(&gl_debug_callback, nullptr);
|
||||
#endif
|
||||
|
||||
// Enable z buffer
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
// Enable face culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
glFrontFace(GL_CW);
|
||||
glCullFace(GL_FRONT);
|
||||
|
||||
// Enable multisampling (a bit redundant because most graphics drivers do this automatically)
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
// Disable VSync
|
||||
glfwSwapInterval(0);
|
||||
}
|
||||
3
src/glad.h
Normal file
3
src/glad.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include <glad/gl.h>
|
||||
|
||||
void init_glad();
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "gltf_loader.h"
|
||||
#include "camera.h"
|
||||
#include "definitions/attribute_locations.h"
|
||||
#include "name.h"
|
||||
#include "relationship.h"
|
||||
#include "scene.h"
|
||||
@@ -8,6 +7,16 @@
|
||||
|
||||
#include <iterator>
|
||||
|
||||
struct AttributeLocations
|
||||
{
|
||||
int position = 0;
|
||||
int uv = 1;
|
||||
int normal = 2;
|
||||
int tangent = 3;
|
||||
};
|
||||
|
||||
static constexpr AttributeLocations ATTRIBUTE_LOCATION;
|
||||
|
||||
template <typename T>
|
||||
static auto create_vertex_attribute_data(std::span<uint8_t const> vertex_attribute_data)
|
||||
-> VertexAttributeData
|
||||
|
||||
@@ -77,6 +77,8 @@ struct GpuImage
|
||||
GpuImage(GpuImage &&other) noexcept : texture(other.texture) { other.texture = 0; }
|
||||
auto operator=(GpuImage &&other) noexcept -> GpuImage &
|
||||
{
|
||||
glDeleteTextures(1, &texture);
|
||||
|
||||
texture = other.texture;
|
||||
other.texture = 0;
|
||||
return *this;
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "EntityWindow.h"
|
||||
#include "../Entity.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
Imgui::EntityWindow::EntityWindow(const std::vector<ModelEntity *> entities) : Window("Entities"), m_entites(entities)
|
||||
{}
|
||||
|
||||
void Imgui::EntityWindow::addWidgets()
|
||||
{
|
||||
ImGui::Text("Treelist");
|
||||
|
||||
for (const auto &entity : m_entites) {
|
||||
addChildWidget(*entity);
|
||||
}
|
||||
}
|
||||
|
||||
void Imgui::EntityWindow::addChildWidget(const ModelEntity &entity)
|
||||
{
|
||||
if (entity.getChildren().empty()) {
|
||||
ImGui::Indent();
|
||||
ImGui::Text(entity.getUniqueName().c_str());
|
||||
ImGui::SameLine();
|
||||
ImGui::SmallButton("Edit");
|
||||
ImGui::Unindent();
|
||||
} else {
|
||||
bool expanded = ImGui::TreeNode(entity.getUniqueName().c_str());
|
||||
ImGui::SameLine();
|
||||
ImGui::SmallButton("Edit");
|
||||
|
||||
if (expanded) {
|
||||
for (const auto &child : entity.getChildren()) {
|
||||
addChildWidget(*(const ModelEntity *)child);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Window.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ModelEntity;
|
||||
|
||||
namespace Imgui {
|
||||
|
||||
class EntityWindow : public Window
|
||||
{
|
||||
public:
|
||||
EntityWindow(const std::vector<ModelEntity *> entities);
|
||||
|
||||
private:
|
||||
void addWidgets() override;
|
||||
|
||||
static void addChildWidget(const ModelEntity &entity);
|
||||
|
||||
const std::vector<ModelEntity *> m_entites;
|
||||
};
|
||||
|
||||
} // namespace Imgui
|
||||
@@ -1,55 +0,0 @@
|
||||
#include "GeneralInfoWindow.h"
|
||||
#include "../Controller.h"
|
||||
#include "../Entity.h"
|
||||
#include "../Scene.h"
|
||||
#include "../ShaderProgram.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <math.h>
|
||||
|
||||
Imgui::GeneralInfoWindow::GeneralInfoWindow(Controller *controller, Scene *world, ShaderProgram *postProcessingProgram,
|
||||
bool *rotateEntity, bool *drawShadows, bool *rotateLightSource,
|
||||
glm::vec3 *lightColor, float *exposure, float *intensity)
|
||||
: Window("Debug Utils"), m_controller(controller), m_scene(world), m_postProcessingProgram(postProcessingProgram),
|
||||
m_rotateEntity(rotateEntity), m_drawShadows(drawShadows), m_rotateLightSource(rotateLightSource),
|
||||
m_lightColor(lightColor), m_exposure(exposure), m_intensity(intensity)
|
||||
{}
|
||||
|
||||
void Imgui::GeneralInfoWindow::addWidgets()
|
||||
{
|
||||
ImGui::Text("Object");
|
||||
|
||||
ImGui::SliderFloat("Rotation", &m_rotation, 0, 2 * M_PI);
|
||||
ImGui::SliderFloat3("Position", m_translation, -4.0, 4.0);
|
||||
ImGui::SliderFloat("Scale", &m_scale, 0.02, 2.0);
|
||||
|
||||
ImGui::Checkbox("Rotate Object", m_rotateEntity);
|
||||
|
||||
ModelEntity *mainObject = m_scene->getEntityById(0);
|
||||
mainObject->setPosition(glm::vec3(m_translation[0], m_translation[1], m_translation[2]));
|
||||
if (!*m_rotateEntity) {
|
||||
mainObject->setRotation(glm::vec3(0.f, 1.0f, 0.f), m_rotation);
|
||||
}
|
||||
mainObject->setScale(m_scale);
|
||||
|
||||
// color picker
|
||||
ImGui::Text("\nLight Source");
|
||||
|
||||
m_controller->updateExposure(m_postProcessingProgram);
|
||||
|
||||
ImGui::SliderFloat("Intensity", m_intensity, 0, 250.f);
|
||||
|
||||
ImGui::ColorEdit3("Color", m_color);
|
||||
m_lightColor->x = m_color[0];
|
||||
m_lightColor->y = m_color[1];
|
||||
m_lightColor->z = m_color[2];
|
||||
|
||||
ImGui::Text("\nMiscellaneous");
|
||||
ImGui::SliderFloat("Exposure", m_exposure, 0, 5.0f);
|
||||
|
||||
ImGui::Checkbox("Draw Shadows", m_drawShadows);
|
||||
ImGui::Checkbox("Rotate Lightsource", m_rotateLightSource);
|
||||
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0 / ImGui::GetIO().Framerate,
|
||||
ImGui::GetIO().Framerate);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Window.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Scene;
|
||||
class ShaderProgram;
|
||||
class Controller;
|
||||
|
||||
namespace Imgui {
|
||||
|
||||
class GeneralInfoWindow : public Window
|
||||
{
|
||||
public:
|
||||
GeneralInfoWindow(Controller *controller, Scene *world, ShaderProgram *postProcessingProgram, bool *rotateEntity,
|
||||
bool *drawShadows, bool *rotateLightSource, glm::vec3 *lightColor, float *exposure,
|
||||
float *intensity);
|
||||
|
||||
private:
|
||||
void addWidgets() override;
|
||||
|
||||
Controller *m_controller;
|
||||
Scene *m_scene;
|
||||
ShaderProgram *m_postProcessingProgram;
|
||||
|
||||
bool *m_rotateEntity;
|
||||
bool *m_drawShadows;
|
||||
bool *m_rotateLightSource;
|
||||
|
||||
float m_rotation = 0.0f;
|
||||
float m_translation[3] = {0.0f, 1.0f, 0.0f};
|
||||
float m_scale = 0.6f;
|
||||
float m_color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
glm::vec3 *m_lightColor;
|
||||
float *m_exposure;
|
||||
float *m_intensity;
|
||||
};
|
||||
|
||||
}; // namespace Imgui
|
||||
@@ -1,50 +0,0 @@
|
||||
#include "Handler.h"
|
||||
#include "Window.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
|
||||
Imgui::Handler::Handler(GLFWwindow *window) : m_GLFWwindow(window)
|
||||
{
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
(void)io;
|
||||
// io.IniFilename = nullptr;
|
||||
|
||||
// Setup Platform/Renderer bindings
|
||||
ImGui_ImplGlfw_InitForOpenGL(m_GLFWwindow, true);
|
||||
ImGui_ImplOpenGL3_Init("#version 150");
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
}
|
||||
|
||||
Imgui::Handler::~Handler()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
void Imgui::Handler::addImguiWindow(std::shared_ptr<Window> window)
|
||||
{
|
||||
m_windows.push_back(window);
|
||||
}
|
||||
|
||||
void Imgui::Handler::renderWindows()
|
||||
{
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
for (auto window : m_windows)
|
||||
window->render();
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class GLFWwindow;
|
||||
|
||||
namespace Imgui {
|
||||
|
||||
class Window;
|
||||
|
||||
class Handler
|
||||
{
|
||||
public:
|
||||
Handler(GLFWwindow *window);
|
||||
~Handler();
|
||||
|
||||
void addImguiWindow(std::shared_ptr<Window> window);
|
||||
void renderWindows();
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Window>> m_windows;
|
||||
GLFWwindow *m_GLFWwindow;
|
||||
};
|
||||
|
||||
} // namespace Imgui
|
||||
@@ -1,15 +0,0 @@
|
||||
#include "Window.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
|
||||
Imgui::Window::Window(const std::string &title) : m_title(title)
|
||||
{}
|
||||
|
||||
void Imgui::Window::render()
|
||||
{
|
||||
ImGui::Begin(m_title.c_str());
|
||||
addWidgets();
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Imgui {
|
||||
|
||||
class Window
|
||||
{
|
||||
public:
|
||||
Window(const std::string &title);
|
||||
void render();
|
||||
|
||||
protected:
|
||||
virtual void addWidgets() = 0;
|
||||
|
||||
std::string m_title;
|
||||
};
|
||||
|
||||
} // namespace Imgui
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "Controller.h"
|
||||
#include "Helper.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
#include "CubeMap.h"
|
||||
#include "../ShaderProgram.h"
|
||||
#include "../util/Log.h"
|
||||
|
||||
#include <glad/gl.h>
|
||||
|
||||
TextureCubeMap::TextureCubeMap(const TextureCubeMapDescriptor &descriptor) : AbstractCubeMap(descriptor.path)
|
||||
{
|
||||
stbi_set_flip_vertically_on_load(0);
|
||||
|
||||
glGenTextures(1, &m_glId);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_glId);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
std::size_t faceCount = 0;
|
||||
for (const auto &faceName : FACE_NAMES) {
|
||||
std::string texturePath = descriptor.path + faceName;
|
||||
|
||||
int textureWidth{};
|
||||
int textureHeight{};
|
||||
int numComponents{};
|
||||
|
||||
auto *textureBuffer = stbi_load(texturePath.c_str(), &textureWidth, &textureHeight, &numComponents, 0);
|
||||
|
||||
m_textureWidth = static_cast<unsigned>(textureWidth);
|
||||
m_textureHeight = static_cast<unsigned>(textureHeight);
|
||||
|
||||
if (textureBuffer == nullptr) {
|
||||
Log::logger().warn("CubeMap texture {} could not be loaded", texturePath);
|
||||
return;
|
||||
}
|
||||
|
||||
GLint internalFormat{};
|
||||
GLenum dataFormat{};
|
||||
|
||||
switch (numComponents) {
|
||||
case 1:
|
||||
internalFormat = GL_RED;
|
||||
dataFormat = GL_RED;
|
||||
break;
|
||||
case 3:
|
||||
internalFormat = GL_SRGB8;
|
||||
dataFormat = GL_RGB;
|
||||
break;
|
||||
case 4:
|
||||
internalFormat = GL_SRGB8_ALPHA8;
|
||||
dataFormat = GL_RGBA;
|
||||
break;
|
||||
}
|
||||
|
||||
glTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceCount), 0, internalFormat,
|
||||
static_cast<GLsizei>(m_textureWidth), static_cast<GLsizei>(m_textureHeight), 0, dataFormat,
|
||||
GL_UNSIGNED_BYTE, textureBuffer);
|
||||
|
||||
stbi_image_free(textureBuffer);
|
||||
|
||||
faceCount++;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
}
|
||||
|
||||
void AbstractCubeMap::bind(ShaderProgram *shaderProgram) const
|
||||
{
|
||||
std::string uniformName = "u_skybox";
|
||||
|
||||
shaderProgram->set_uniform(uniformName, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_glId);
|
||||
}
|
||||
|
||||
void AbstractCubeMap::unbind() const
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
}
|
||||
|
||||
InternalCubeMap::InternalCubeMap(unsigned int resolution) : AbstractCubeMap("internal")
|
||||
{
|
||||
m_textureWidth = resolution;
|
||||
m_textureHeight = resolution;
|
||||
|
||||
glGenTextures(1, &m_glId);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_glId);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
for (unsigned int i = 0; i < static_cast<int>(CubeMapFace::CUBEMAP_FACES_NUM_ITEMS); i++) {
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT24, static_cast<GLsizei>(resolution),
|
||||
static_cast<GLsizei>(resolution), 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "AbstractTexture.h"
|
||||
|
||||
#include <array>
|
||||
#include <stb/stb_image.h>
|
||||
#include <vector>
|
||||
|
||||
// Order is important!
|
||||
enum class CubeMapFace
|
||||
{
|
||||
Right,
|
||||
Left,
|
||||
Top,
|
||||
Bottom,
|
||||
Back,
|
||||
Front,
|
||||
CUBEMAP_FACES_NUM_ITEMS
|
||||
};
|
||||
|
||||
const std::array<std::string, 6> FACE_NAMES{"right.png", "left.png", "top.png", "bottom.png", "back.png", "front.png"};
|
||||
|
||||
class ShaderProgram;
|
||||
|
||||
struct TextureCubeMapDescriptor
|
||||
{
|
||||
std::string path;
|
||||
};
|
||||
|
||||
class AbstractCubeMap : public AbstractTexture
|
||||
{
|
||||
public:
|
||||
AbstractCubeMap(const std::string &path) : AbstractTexture(path)
|
||||
{}
|
||||
|
||||
void bind(ShaderProgram *shaderProgram) const;
|
||||
void unbind() const override;
|
||||
};
|
||||
|
||||
class TextureCubeMap : public AbstractCubeMap
|
||||
{
|
||||
public:
|
||||
TextureCubeMap(const TextureCubeMapDescriptor &descriptor);
|
||||
};
|
||||
|
||||
class InternalCubeMap : public AbstractCubeMap
|
||||
{
|
||||
public:
|
||||
InternalCubeMap(unsigned int resolution);
|
||||
};
|
||||
Reference in New Issue
Block a user