Refactor shaders
This commit is contained in:
@@ -2,7 +2,6 @@ add_library(fever_engine
|
||||
main.cpp
|
||||
Controller.cpp
|
||||
Window.cpp
|
||||
ShaderProgram.cpp
|
||||
Light.cpp
|
||||
Scene.cpp
|
||||
FrameBuffer.cpp
|
||||
@@ -13,6 +12,7 @@ add_library(fever_engine
|
||||
gltf_loader.cpp
|
||||
material.cpp
|
||||
camera.cpp
|
||||
shader.cpp
|
||||
)
|
||||
|
||||
target_compile_features(fever_engine PUBLIC cxx_std_20)
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
#include "FrameBuffer.h"
|
||||
#include "Helper.h"
|
||||
#include "Light.h"
|
||||
#include "ShaderProgram.h"
|
||||
#include "Window.h"
|
||||
#include "gltf_loader.h"
|
||||
#include "render.h"
|
||||
#include "shader.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
@@ -22,10 +23,11 @@
|
||||
using namespace entt::literals;
|
||||
|
||||
Controller::Controller()
|
||||
: m_gameWindow(std::make_shared<Window>()),
|
||||
: m_scene(m_shader_cache),
|
||||
m_gameWindow(std::make_shared<Window>()),
|
||||
m_postProcessFrameBuffer(m_gameWindow->dimensions().first,
|
||||
m_gameWindow->dimensions().second,
|
||||
postProcessingProgram)
|
||||
post_processing_shader)
|
||||
{
|
||||
// if (!gltf.cameras.empty()) {
|
||||
// auto const &gltf_camera = gltf.cameras.at(0);
|
||||
@@ -41,18 +43,20 @@ Controller::Controller()
|
||||
|
||||
void Controller::run()
|
||||
{
|
||||
updateExposure(postProcessingProgram);
|
||||
updateExposure(post_processing_shader);
|
||||
|
||||
// m_camera->translate(glm::vec3(0., .5, 2.));
|
||||
entt::hashed_string shader_hash (Material::SHADER_NAME.data());
|
||||
auto standard_material_shader =
|
||||
m_shader_cache.load(shader_hash, Material::SHADER_NAME).first->second;
|
||||
|
||||
DirectionalLight directional_light(
|
||||
DirectionalLight::Prototype("", glm::vec3(-0.2, -1.0, -0.3), glm::vec3(1.0f), 5.f),
|
||||
&defaultProgram);
|
||||
standard_material_shader.handle().get());
|
||||
directional_light.setActive(true);
|
||||
|
||||
PointLight point_light(
|
||||
PointLight::Prototype("", "", glm::vec3(4.0, 1.0, 6.0), glm::vec3(1.0F), 3.0F),
|
||||
&defaultProgram);
|
||||
standard_material_shader.handle().get());
|
||||
point_light.setActive(true);
|
||||
|
||||
Log::logger().info("Startup complete. Enter game loop.");
|
||||
@@ -62,8 +66,8 @@ void Controller::run()
|
||||
// --- Timing ---
|
||||
limit_framerate();
|
||||
|
||||
// --- Update game ---
|
||||
m_gameWindow->clear_mouse_cursor_input(); // MOVE DOWN AGAIN!
|
||||
// --- Check events, handle input ---
|
||||
m_gameWindow->clear_mouse_cursor_input();
|
||||
glfwPollEvents();
|
||||
|
||||
auto const &key_input = m_gameWindow->key_input();
|
||||
@@ -72,7 +76,10 @@ void Controller::run()
|
||||
static constexpr auto MICROSECONDS_PER_SECOND = 1'000'000;
|
||||
m_scene.update(
|
||||
std::chrono::microseconds(static_cast<unsigned>(m_deltaTime * MICROSECONDS_PER_SECOND)),
|
||||
key_input,mouse_cursor_input, m_gameWindow->aspectRatio());
|
||||
key_input,
|
||||
mouse_cursor_input,
|
||||
m_gameWindow->aspectRatio(),
|
||||
m_gameWindow->cursor_catched());
|
||||
|
||||
// --- Render and buffer swap ---
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
@@ -80,7 +87,7 @@ void Controller::run()
|
||||
m_postProcessFrameBuffer.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
m_scene.draw(&defaultProgram);
|
||||
Render::render(m_scene.registry());
|
||||
|
||||
Framebuffer::unbind();
|
||||
m_postProcessFrameBuffer.drawOnEntireScreen();
|
||||
@@ -92,19 +99,6 @@ void Controller::run()
|
||||
m_gameWindow->update_dimensions();
|
||||
update_window_dimensions();
|
||||
}
|
||||
|
||||
// --- Check events, handle input ---
|
||||
// m_gameWindow->clear_mouse_cursor_input();
|
||||
// glfwPollEvents();
|
||||
|
||||
// auto const &key_input = m_gameWindow->key_input();
|
||||
// auto const &mouse_cursor_input = m_gameWindow->mouse_cursor_input();
|
||||
|
||||
// m_camera->updatePositionFromKeyboardInput(key_input, (float)m_deltaTime);
|
||||
|
||||
// if (m_gameWindow->cursor_catched()) {
|
||||
// m_camera->updateDirectionFromMouseInput(mouse_cursor_input);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +131,9 @@ void Controller::update_window_dimensions()
|
||||
m_postProcessFrameBuffer.changeDimensions(dimensions.first, dimensions.second);
|
||||
}
|
||||
|
||||
void Controller::updateExposure(ShaderProgram &shaderProgram) const
|
||||
void Controller::updateExposure(Shader &shader) const
|
||||
{
|
||||
shaderProgram.bind();
|
||||
shaderProgram.setUniform("u_exposure", m_exposure);
|
||||
ShaderProgram::unbind();
|
||||
shader.bind();
|
||||
shader.set_uniform("u_exposure", m_exposure);
|
||||
Shader::unbind();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "FrameBuffer.h"
|
||||
#include "ShaderProgram.h"
|
||||
#include "Scene.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
class Window;
|
||||
class Scene;
|
||||
@@ -21,21 +22,21 @@ public:
|
||||
|
||||
void run();
|
||||
|
||||
void updateExposure(ShaderProgram &shaderProgram) const;
|
||||
void updateExposure(Shader &shader) const;
|
||||
|
||||
private:
|
||||
void limit_framerate();
|
||||
void update_window_dimensions();
|
||||
|
||||
std::shared_ptr<Window> m_gameWindow;
|
||||
|
||||
ShaderProgram defaultProgram{{"defaultProgram", "data/shaders/basic.vert", "data/shaders/basic.frag"}};
|
||||
ShaderProgram skyboxProgram{{"skyboxProgram", "data/shaders/skybox.vert", "data/shaders/skybox.frag"}};
|
||||
ShaderProgram postProcessingProgram{
|
||||
{"postProcessingProgram", "data/shaders/postprocessing.vert", "data/shaders/postprocessing.frag"}};
|
||||
|
||||
Shader skybox_shader{"skybox", "data/shaders"};
|
||||
Shader post_processing_shader{"post_processing", "data/shaders"};
|
||||
|
||||
Framebuffer m_postProcessFrameBuffer;
|
||||
|
||||
entt::resource_cache<Shader, ShaderLoader> m_shader_cache;
|
||||
|
||||
static constexpr unsigned MAX_FPS = 60;
|
||||
|
||||
Scene m_scene;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "FrameBuffer.h"
|
||||
#include "ShaderProgram.h"
|
||||
#include "shader.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <cstddef>
|
||||
@@ -19,7 +19,7 @@ GLuint Framebuffer::getFBO() const
|
||||
return m_FBO;
|
||||
}
|
||||
|
||||
Framebuffer::Framebuffer(uint32_t width, uint32_t height, ShaderProgram &shaderProgram) : m_shaderProgram(shaderProgram)
|
||||
Framebuffer::Framebuffer(uint32_t width, uint32_t height, Shader &shader) : m_shader(shader)
|
||||
{
|
||||
glGenFramebuffers(1, &m_FBO);
|
||||
|
||||
@@ -46,12 +46,11 @@ void Framebuffer::drawOnEntireScreen() const
|
||||
glGetIntegerv(GL_POLYGON_MODE, &wireframe);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
m_shaderProgram.bind();
|
||||
m_shader.bind();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, getTextureId());
|
||||
|
||||
GLint location = glGetUniformLocation(m_shaderProgram.getShaderProgramId(), "u_texture");
|
||||
glUniform1i(location, 0);
|
||||
m_shader.set_uniform("u_texture", 0);
|
||||
|
||||
// A VAO is necessary although no data is stored in it
|
||||
GLuint temp_vao;
|
||||
@@ -61,7 +60,7 @@ void Framebuffer::drawOnEntireScreen() const
|
||||
glBindVertexArray(0);
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, static_cast<GLenum>(wireframe));
|
||||
m_shaderProgram.unbind();
|
||||
m_shader.unbind();
|
||||
}
|
||||
|
||||
void Framebuffer::changeDimensions(uint32_t width, uint32_t height)
|
||||
@@ -108,7 +107,7 @@ void Framebuffer::generateTextures(uint32_t width, uint32_t height)
|
||||
|
||||
void Framebuffer::setExposureCorrection(bool exposureCorrection) const
|
||||
{
|
||||
m_shaderProgram.bind();
|
||||
m_shaderProgram.setUniform("u_exposureCorrection", exposureCorrection);
|
||||
m_shaderProgram.unbind();
|
||||
m_shader.bind();
|
||||
m_shader.set_uniform("u_exposureCorrection", exposureCorrection);
|
||||
m_shader.unbind();
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include <glad/gl.h>
|
||||
|
||||
class ShaderProgram;
|
||||
class Shader;
|
||||
|
||||
class Framebuffer
|
||||
{
|
||||
public:
|
||||
Framebuffer(uint32_t width, uint32_t height, ShaderProgram &shaderProgram);
|
||||
Framebuffer(uint32_t width, uint32_t height, Shader &shader);
|
||||
~Framebuffer();
|
||||
|
||||
void bind() const;
|
||||
@@ -29,5 +29,5 @@ private:
|
||||
GLuint m_depthStencilBuffer;
|
||||
GLuint m_FBO;
|
||||
|
||||
ShaderProgram &m_shaderProgram;
|
||||
Shader &m_shader;
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "Light.h"
|
||||
#include "ShaderProgram.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
uint32_t Light::s_idCounter = 0;
|
||||
|
||||
Light::Light(const std::string &name, glm::vec3 color, float intensity, ShaderProgram *shaderProgram)
|
||||
: m_shaderProgram(shaderProgram), m_intensity(intensity), m_lightColor(color * intensity)
|
||||
Light::Light(const std::string &name, glm::vec3 color, float intensity, Shader *shader)
|
||||
: m_shader(shader), m_intensity(intensity), m_lightColor(color * intensity)
|
||||
{
|
||||
m_id = s_idCounter++;
|
||||
}
|
||||
@@ -18,9 +18,9 @@ glm::vec3 Light::getColor()
|
||||
return m_lightColor;
|
||||
}
|
||||
|
||||
void Light::setShaderProgram(ShaderProgram *shaderProgram)
|
||||
void Light::setShader(Shader *shader)
|
||||
{
|
||||
this->m_shaderProgram = shaderProgram;
|
||||
this->m_shader = shader;
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -41,21 +41,21 @@ void Light::setActive(bool active)
|
||||
update();
|
||||
}
|
||||
|
||||
PointLight::PointLight(Prototype prototype, ShaderProgram *shaderProgram)
|
||||
: Light(prototype.name, prototype.color, prototype.intensity, shaderProgram), m_position(prototype.position)
|
||||
PointLight::PointLight(Prototype prototype, Shader *shader)
|
||||
: Light(prototype.name, prototype.color, prototype.intensity, shader), m_position(prototype.position)
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void PointLight::update()
|
||||
{
|
||||
m_shaderProgram->bind();
|
||||
m_shader->bind();
|
||||
|
||||
m_shaderProgram->setUniform((getStructMemberName() + "isActive").c_str(), m_isActive);
|
||||
m_shaderProgram->setUniform((getStructMemberName() + "position").c_str(), m_position);
|
||||
m_shaderProgram->setUniform((getStructMemberName() + "color").c_str(), m_lightColor);
|
||||
m_shader->set_uniform((getStructMemberName() + "isActive").c_str(), m_isActive);
|
||||
m_shader->set_uniform((getStructMemberName() + "position").c_str(), m_position);
|
||||
m_shader->set_uniform((getStructMemberName() + "color").c_str(), m_lightColor);
|
||||
|
||||
m_shaderProgram->unbind();
|
||||
m_shader->unbind();
|
||||
}
|
||||
|
||||
std::string PointLight::getStructMemberName()
|
||||
@@ -76,21 +76,21 @@ void PointLight::setPosition(glm::vec3 position)
|
||||
update();
|
||||
}
|
||||
|
||||
DirectionalLight::DirectionalLight(Prototype prototype, ShaderProgram *shaderProgram)
|
||||
: Light(prototype.name, prototype.color, prototype.intensity, shaderProgram), m_direction(prototype.direction)
|
||||
DirectionalLight::DirectionalLight(Prototype prototype, Shader *shader)
|
||||
: Light(prototype.name, prototype.color, prototype.intensity, shader), m_direction(prototype.direction)
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void DirectionalLight::update()
|
||||
{
|
||||
m_shaderProgram->bind();
|
||||
m_shader->bind();
|
||||
|
||||
m_shaderProgram->setUniform("u_directionalLight.isActive", m_isActive);
|
||||
m_shaderProgram->setUniform("u_directionalLight.direction", m_direction);
|
||||
m_shaderProgram->setUniform("u_directionalLight.color", m_lightColor);
|
||||
m_shader->set_uniform("u_directionalLight.isActive", m_isActive);
|
||||
m_shader->set_uniform("u_directionalLight.direction", m_direction);
|
||||
m_shader->set_uniform("u_directionalLight.color", m_lightColor);
|
||||
|
||||
m_shaderProgram->unbind();
|
||||
m_shader->unbind();
|
||||
}
|
||||
|
||||
void DirectionalLight::setDirection(glm::vec3 direction)
|
||||
|
||||
12
src/Light.h
12
src/Light.h
@@ -3,7 +3,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
|
||||
class ShaderProgram;
|
||||
class Shader;
|
||||
|
||||
class Light
|
||||
{
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
float intensity;
|
||||
};
|
||||
|
||||
Light(const std::string &name, glm::vec3 color, float intensity, ShaderProgram *shaderProgram);
|
||||
Light(const std::string &name, glm::vec3 color, float intensity, Shader *shader);
|
||||
virtual ~Light() = 0;
|
||||
|
||||
virtual void update() = 0;
|
||||
@@ -29,12 +29,12 @@ public:
|
||||
void setActive(bool active);
|
||||
void setColor(glm::vec3 color);
|
||||
void setIntensity(float intensity);
|
||||
void setShaderProgram(ShaderProgram *shaderProgram);
|
||||
void setShader(Shader *shader);
|
||||
|
||||
glm::vec3 getColor();
|
||||
|
||||
protected:
|
||||
ShaderProgram *m_shaderProgram;
|
||||
Shader *m_shader;
|
||||
|
||||
uint32_t m_id;
|
||||
static uint32_t s_idCounter;
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
glm::vec3 position;
|
||||
};
|
||||
|
||||
PointLight(Prototype prototype, ShaderProgram *shaderProgram);
|
||||
PointLight(Prototype prototype, Shader *shader);
|
||||
~PointLight() override = default;
|
||||
|
||||
void setPosition(glm::vec3 position);
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
glm::vec3 direction;
|
||||
};
|
||||
|
||||
DirectionalLight(Prototype prototype, ShaderProgram *shaderProgram);
|
||||
DirectionalLight(Prototype prototype, Shader *shader);
|
||||
~DirectionalLight() override = default;
|
||||
|
||||
void setDirection(glm::vec3 direction);
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
#include "Scene.h"
|
||||
#include "ShaderProgram.h"
|
||||
#include "camera.h"
|
||||
#include "mesh.h"
|
||||
#include "name.h"
|
||||
#include "relationship.h"
|
||||
#include "shader.h"
|
||||
#include "transform.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
using namespace entt::literals;
|
||||
|
||||
// TODO: make scene initialization part of gltf loader as seen in bevy
|
||||
Scene::Scene()
|
||||
Scene::Scene(entt::resource_cache<Shader, ShaderLoader> &shader_cache)
|
||||
{
|
||||
GltfLoader loader{.image_cache = m_image_cache,
|
||||
.material_cache = m_material_cache,
|
||||
.mesh_cache = m_mesh_cache,
|
||||
.shader_cache = shader_cache,
|
||||
.gltf_mesh_cache = m_gltf_mesh_cache,
|
||||
.gltf_node_cache = m_gltf_node_cache,
|
||||
.gltf_scene_cache = m_gltf_scene_cache};
|
||||
@@ -92,16 +93,16 @@ Scene::Scene()
|
||||
// Spawn the camera
|
||||
auto entity = m_registry.create();
|
||||
m_registry.emplace<Name>(entity, "Camera");
|
||||
m_registry.emplace<Transform>(entity, Transform{.translation = glm::vec3(0.0, 0.5, -1.0)});
|
||||
m_registry.emplace<Transform>(entity, Transform{.translation = glm::vec3(0.0, 0.25, -1.0)});
|
||||
m_registry.emplace<GlobalTransform>(entity, GlobalTransform{});
|
||||
m_registry.emplace<Camera>(entity,
|
||||
Camera{.projection = Camera::Perspective{}});
|
||||
m_registry.emplace<Camera>(entity, Camera{.projection = Camera::Perspective{}});
|
||||
}
|
||||
|
||||
void Scene::update(std::chrono::duration<float> delta,
|
||||
KeyInput const &key_input,
|
||||
MouseCursorInput const &mouse_cursor_input,
|
||||
float aspect_ratio)
|
||||
float aspect_ratio,
|
||||
bool cursor_catched)
|
||||
{
|
||||
{
|
||||
// Update GlobalTransform components
|
||||
@@ -138,38 +139,10 @@ void Scene::update(std::chrono::duration<float> delta,
|
||||
}
|
||||
}
|
||||
|
||||
Camera::keyboard_movement(m_registry, key_input, delta);
|
||||
Camera::mouse_orientation(m_registry, mouse_cursor_input);
|
||||
Camera::aspect_ratio_update(m_registry, aspect_ratio);
|
||||
}
|
||||
|
||||
void Scene::draw(ShaderProgram *shaderprogram) const
|
||||
{
|
||||
auto mesh_view = m_registry.view<GpuMesh const, GpuMaterial const, GlobalTransform const>();
|
||||
auto camera_view = m_registry.view<Camera const, GlobalTransform const>();
|
||||
auto camera_entity = camera_view.front();
|
||||
auto [camera, camera_transform] = camera_view.get(camera_entity);
|
||||
glm::mat4 view_projection_matrix =
|
||||
camera.projection_matrix() * Camera::view_matrix(camera_transform);
|
||||
|
||||
for (auto [entity, mesh, material, transform] : mesh_view.each()) {
|
||||
shaderprogram->bind();
|
||||
|
||||
// Bind textures
|
||||
material.bind(*shaderprogram);
|
||||
|
||||
// Bind modelview matrix uniform
|
||||
{
|
||||
glm::mat4 modelViewProj = view_projection_matrix * transform.transform;
|
||||
shaderprogram->setUniform("u_modelViewProjMatrix", modelViewProj);
|
||||
shaderprogram->setUniform("u_modelMatrix", transform.transform);
|
||||
shaderprogram->setUniform("u_viewPosition", camera_transform.position());
|
||||
}
|
||||
|
||||
glBindVertexArray(mesh.vao);
|
||||
glDrawElements(GL_TRIANGLES, mesh.indices_count, mesh.indices_type, nullptr);
|
||||
glBindVertexArray(0);
|
||||
|
||||
ShaderProgram::unbind();
|
||||
Camera::keyboard_movement(m_registry, key_input, delta);
|
||||
if (cursor_catched) {
|
||||
Camera::mouse_orientation(m_registry, mouse_cursor_input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,19 +8,20 @@
|
||||
#include <chrono>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
class ShaderProgram;
|
||||
class Shader;
|
||||
|
||||
class Scene
|
||||
{
|
||||
public:
|
||||
Scene();
|
||||
Scene(entt::resource_cache<Shader, ShaderLoader> &shader_cache);
|
||||
|
||||
void update(std::chrono::duration<float> delta_time,
|
||||
KeyInput const &key_input,
|
||||
MouseCursorInput const &mouse_cursor_input,
|
||||
float aspect_ratio);
|
||||
float aspect_ratio,
|
||||
bool cursor_catched);
|
||||
|
||||
void draw(ShaderProgram *shaderprogram) const;
|
||||
auto registry() -> entt::registry & { return m_registry; }
|
||||
|
||||
private:
|
||||
entt::registry m_registry;
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
ShaderProgram::ShaderProgram(Prototype prototype) : m_shaderProgramId(glCreateProgram())
|
||||
{
|
||||
std::string vertexShaderSource = parse(prototype.vertexPath).value();
|
||||
std::string fragmentShaderSource = parse(prototype.fragmentPath).value();
|
||||
std::string vertexShaderSource = parse(prototype.vertexPath);
|
||||
std::string fragmentShaderSource = parse(prototype.fragmentPath);
|
||||
|
||||
GLuint vertexShader = compile(vertexShaderSource, GL_VERTEX_SHADER);
|
||||
GLuint fragmentShader = compile(fragmentShaderSource, GL_FRAGMENT_SHADER);
|
||||
@@ -21,7 +21,9 @@ ShaderProgram::ShaderProgram(Prototype prototype) : m_shaderProgramId(glCreatePr
|
||||
GLint isLinked = 0;
|
||||
glGetProgramiv(m_shaderProgramId, GL_LINK_STATUS, &isLinked);
|
||||
if (isLinked == 0) {
|
||||
Log::logger().warn(R"(Failed to link shaderProgram "{}", "{}")", prototype.vertexPath, prototype.fragmentPath);
|
||||
Log::logger().warn(R"(Failed to link shaderProgram "{}", "{}")",
|
||||
prototype.vertexPath,
|
||||
prototype.fragmentPath);
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
@@ -50,19 +52,17 @@ void ShaderProgram::unbind()
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
auto ShaderProgram::parse(const std::filesystem::path &path) -> std::optional<std::string>
|
||||
auto ShaderProgram::parse(const std::filesystem::path &path) -> std::string
|
||||
{
|
||||
std::fstream shaderfile;
|
||||
shaderfile.open(path, std::ios::in);
|
||||
std::fstream file;
|
||||
file.open(path, std::ios::in);
|
||||
|
||||
if (!shaderfile.is_open()) {
|
||||
Log::logger().warn("Shader \"{}\" not found", path.c_str());
|
||||
return {};
|
||||
if (!file.is_open()) {
|
||||
Log::logger().critical(R"(Shader "{}" not found!)", path.string());
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
std::string contents((std::istreambuf_iterator<char>(shaderfile)), (std::istreambuf_iterator<char>()));
|
||||
|
||||
return contents;
|
||||
return {(std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())};
|
||||
}
|
||||
|
||||
auto ShaderProgram::compile(const std::string &shaderSource, GLenum type) -> GLuint
|
||||
@@ -108,49 +108,49 @@ auto ShaderProgram::retrieveUniformLocation(std::string_view uniform_name) const
|
||||
return location;
|
||||
}
|
||||
|
||||
void ShaderProgram::setUniform(const std::string &name, bool value) const
|
||||
void ShaderProgram::set_uniform(const std::string &name, bool value) const
|
||||
{
|
||||
GLint location = retrieveUniformLocation(name);
|
||||
glUniform1i(location, (int)value);
|
||||
}
|
||||
|
||||
void ShaderProgram::setUniform(const std::string &name, int value) const
|
||||
void ShaderProgram::set_uniform(const std::string &name, int value) const
|
||||
{
|
||||
GLint location = retrieveUniformLocation(name);
|
||||
glUniform1i(location, value);
|
||||
}
|
||||
|
||||
void ShaderProgram::setUniform(const std::string &name, unsigned int value) const
|
||||
void ShaderProgram::set_uniform(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
|
||||
void ShaderProgram::set_uniform(const std::string &name, float value) const
|
||||
{
|
||||
GLint location = retrieveUniformLocation(name);
|
||||
glUniform1f(location, value);
|
||||
}
|
||||
|
||||
void ShaderProgram::setUniform(const std::string &name, glm::vec2 vector) const
|
||||
void ShaderProgram::set_uniform(const std::string &name, glm::vec2 vector) const
|
||||
{
|
||||
GLint location = retrieveUniformLocation(name);
|
||||
glUniform2f(location, vector.x, vector.y);
|
||||
}
|
||||
|
||||
void ShaderProgram::setUniform(const std::string &name, glm::vec3 vector) const
|
||||
void ShaderProgram::set_uniform(const std::string &name, glm::vec3 vector) const
|
||||
{
|
||||
GLint location = retrieveUniformLocation(name);
|
||||
glUniform3f(location, vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
void ShaderProgram::setUniform(const std::string &name, glm::mat3 matrix) const
|
||||
void ShaderProgram::set_uniform(const std::string &name, glm::mat3 matrix) const
|
||||
{
|
||||
GLint location = retrieveUniformLocation(name);
|
||||
glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
|
||||
}
|
||||
|
||||
void ShaderProgram::setUniform(const std::string &name, glm::mat4 matrix) const
|
||||
void ShaderProgram::set_uniform(const std::string &name, glm::mat4 matrix) const
|
||||
{
|
||||
GLint location = retrieveUniformLocation(name);
|
||||
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
|
||||
@@ -26,19 +26,19 @@ public:
|
||||
auto retrieveUniformLocation(std::string_view uniform_name) const -> GLint;
|
||||
|
||||
// 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;
|
||||
void setUniform(const std::string &name, glm::mat3 matrix) const;
|
||||
void setUniform(const std::string &name, glm::mat4 matrix) const;
|
||||
void set_uniform(const std::string &name, bool value) const;
|
||||
void set_uniform(const std::string &name, int value) const;
|
||||
void set_uniform(const std::string &name, unsigned int value) const;
|
||||
void set_uniform(const std::string &name, float value) const;
|
||||
void set_uniform(const std::string &name, glm::vec2 vector) const;
|
||||
void set_uniform(const std::string &name, glm::vec3 vector) const;
|
||||
void set_uniform(const std::string &name, glm::mat3 matrix) const;
|
||||
void set_uniform(const std::string &name, glm::mat4 matrix) const;
|
||||
|
||||
auto getShaderProgramId() const -> GLuint;
|
||||
|
||||
private:
|
||||
static auto parse(const std::filesystem::path &path) -> std::optional<std::string>;
|
||||
static auto parse(const std::filesystem::path &path) -> std::string;
|
||||
static auto compile(const std::string &shaderSource, GLenum type) -> GLuint;
|
||||
|
||||
GLuint m_shaderProgramId;
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "gltf_loader.h"
|
||||
#include "util/Log.h"
|
||||
#include "definitions/attribute_locations.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
@@ -73,7 +73,8 @@ static auto load_material(fx::gltf::Material const &material,
|
||||
fx::gltf::Document const &gltf,
|
||||
std::filesystem::path const &document_path,
|
||||
entt::resource_cache<Material> &material_cache,
|
||||
entt::resource_cache<Image> &image_cache) -> entt::resource<Material>
|
||||
entt::resource_cache<Image> &image_cache,
|
||||
entt::resource_cache<Shader, ShaderLoader> &shader_cache) -> entt::resource<Material>
|
||||
{
|
||||
auto base_color_texture_id = material.pbrMetallicRoughness.baseColorTexture.index;
|
||||
auto normal_texture_id = material.normalTexture.index;
|
||||
@@ -92,6 +93,10 @@ static auto load_material(fx::gltf::Material const &material,
|
||||
load_texture(normal_texture, gltf, document_path, Image::ColorFormat::RGB, image_cache);
|
||||
}
|
||||
|
||||
entt::hashed_string shader_hash(Material::SHADER_NAME.data());
|
||||
entt::resource<Shader> shader =
|
||||
shader_cache.load(shader_hash, Material::SHADER_NAME).first->second;
|
||||
|
||||
if (material.name.empty()) {
|
||||
Log::logger().warn("glTF material has no name.");
|
||||
}
|
||||
@@ -100,7 +105,8 @@ static auto load_material(fx::gltf::Material const &material,
|
||||
return material_cache
|
||||
.load(material_hash,
|
||||
Material{.base_color_texture = base_color_image,
|
||||
.normal_map_texture = normal_map_image})
|
||||
.normal_map_texture = normal_map_image,
|
||||
.shader = shader})
|
||||
.first->second;
|
||||
}
|
||||
|
||||
@@ -256,8 +262,8 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul
|
||||
// Load materials
|
||||
std::vector<entt::resource<Material>> materials;
|
||||
for (auto const &gltf_material : gltf.materials) {
|
||||
entt::resource<Material> material =
|
||||
load_material(gltf_material, gltf, document_path, material_cache, image_cache);
|
||||
entt::resource<Material> material = load_material(
|
||||
gltf_material, gltf, document_path, material_cache, image_cache, shader_cache);
|
||||
materials.push_back(material);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ struct GltfLoader final
|
||||
entt::resource_cache<Image> &image_cache;
|
||||
entt::resource_cache<Material> &material_cache;
|
||||
entt::resource_cache<Mesh> &mesh_cache;
|
||||
entt::resource_cache<Shader, ShaderLoader> &shader_cache;
|
||||
|
||||
entt::resource_cache<GltfMesh> &gltf_mesh_cache;
|
||||
entt::resource_cache<GltfNode> &gltf_node_cache;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "material.h"
|
||||
#include "ShaderProgram.h"
|
||||
#include "shader.h"
|
||||
|
||||
GpuMaterial::GpuMaterial(Material const &material)
|
||||
GpuMaterial::GpuMaterial(Material const &material) : shader(material.shader)
|
||||
{
|
||||
int texture_unit_counter = 0;
|
||||
|
||||
@@ -17,11 +17,11 @@ GpuMaterial::GpuMaterial(Material const &material)
|
||||
normal_map_texture = std::make_pair(GpuImage(material.normal_map_texture.value()), binding);
|
||||
}
|
||||
}
|
||||
void GpuMaterial::bind(ShaderProgram const &shader_program) const
|
||||
void GpuMaterial::bind() const
|
||||
{
|
||||
auto bind_texture = [&shader_program](auto const &texture) {
|
||||
auto bind_texture = [this](auto const &texture) {
|
||||
if (texture.has_value()) {
|
||||
shader_program.setUniform(texture->second.uniform_name, texture->second.texture_unit);
|
||||
shader->set_uniform(texture->second.uniform_name, texture->second.texture_unit);
|
||||
glActiveTexture(GL_TEXTURE0 + texture->second.texture_unit);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->first.texture);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "image.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
#include <optional>
|
||||
|
||||
class ShaderProgram;
|
||||
class Shader;
|
||||
|
||||
struct Material
|
||||
{
|
||||
std::optional<entt::resource<Image>> base_color_texture;
|
||||
std::optional<entt::resource<Image>> normal_map_texture;
|
||||
|
||||
static constexpr std::string_view SHADER_NAME{"standard_material"};
|
||||
entt::resource<Shader> shader;
|
||||
};
|
||||
|
||||
struct GpuMaterial
|
||||
{
|
||||
GpuMaterial(Material const &material);
|
||||
|
||||
void bind(ShaderProgram const &shader_program) const;
|
||||
void bind() const;
|
||||
|
||||
struct Binding
|
||||
{
|
||||
@@ -27,4 +31,6 @@ struct GpuMaterial
|
||||
|
||||
std::optional<std::pair<GpuImage, Binding>> base_color_texture;
|
||||
std::optional<std::pair<GpuImage, Binding>> normal_map_texture;
|
||||
|
||||
entt::resource<Shader> shader;
|
||||
};
|
||||
|
||||
43
src/render.h
Normal file
43
src/render.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "camera.h"
|
||||
#include "material.h"
|
||||
#include "mesh.h"
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
namespace Render {
|
||||
|
||||
void render(entt::registry ®istry)
|
||||
{
|
||||
auto mesh_view = registry.view<GpuMesh const, GpuMaterial const, GlobalTransform const>();
|
||||
auto camera_view = registry.view<Camera const, GlobalTransform const>();
|
||||
auto camera_entity = camera_view.front();
|
||||
auto [camera, camera_transform] = camera_view.get(camera_entity);
|
||||
glm::mat4 view_projection_matrix =
|
||||
camera.projection_matrix() * Camera::view_matrix(camera_transform);
|
||||
|
||||
for (auto [entity, mesh, material, transform] : mesh_view.each()) {
|
||||
auto shader = material.shader;
|
||||
shader->bind();
|
||||
|
||||
// Bind textures
|
||||
material.bind();
|
||||
|
||||
// Bind modelview matrix uniform
|
||||
{
|
||||
glm::mat4 modelViewProj = view_projection_matrix * transform.transform;
|
||||
shader->set_uniform("u_modelViewProjMatrix", modelViewProj);
|
||||
shader->set_uniform("u_modelMatrix", transform.transform);
|
||||
shader->set_uniform("u_viewPosition", camera_transform.position());
|
||||
}
|
||||
|
||||
glBindVertexArray(mesh.vao);
|
||||
glDrawElements(GL_TRIANGLES, mesh.indices_count, mesh.indices_type, nullptr);
|
||||
glBindVertexArray(0);
|
||||
|
||||
Shader::unbind();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Render
|
||||
@@ -69,7 +69,7 @@ void AbstractCubeMap::bind(ShaderProgram *shaderProgram) const
|
||||
{
|
||||
std::string uniformName = "u_skybox";
|
||||
|
||||
shaderProgram->setUniform(uniformName, 0);
|
||||
shaderProgram->set_uniform(uniformName, 0);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_glId);
|
||||
}
|
||||
|
||||
146
src/shader.cpp
Normal file
146
src/shader.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
#include "shader.h"
|
||||
#include "util/Log.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <fstream>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
Shader::Shader(std::string_view name, std::filesystem::path const &directory)
|
||||
: program(glCreateProgram())
|
||||
{
|
||||
std::filesystem::path vertex_shader_path = directory / name;
|
||||
vertex_shader_path.concat(".vert");
|
||||
|
||||
std::filesystem::path frag_shader_path = directory / name;
|
||||
frag_shader_path.concat(".frag");
|
||||
|
||||
std::string vertex_shader_source = parse(vertex_shader_path);
|
||||
std::string fragment_shader_source = parse(frag_shader_path);
|
||||
|
||||
GLuint vertex_shader = compile(vertex_shader_source, GL_VERTEX_SHADER);
|
||||
GLuint fragment_shader = compile(fragment_shader_source, GL_FRAGMENT_SHADER);
|
||||
|
||||
glAttachShader(program, vertex_shader);
|
||||
glAttachShader(program, fragment_shader);
|
||||
|
||||
glLinkProgram(program);
|
||||
|
||||
GLint linked = 0;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &linked);
|
||||
|
||||
if (linked == 0) {
|
||||
Log::logger().warn(R"(Failed to link Shader "{}")", name);
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
glDetachShader(m_ShaderId, vertexShader);
|
||||
glDetachShader(m_ShaderId, fragmentShader);
|
||||
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
#endif
|
||||
|
||||
Log::logger().trace(R"(Loaded Shader "{}")", name);
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
glDeleteProgram(program);
|
||||
}
|
||||
|
||||
void Shader::bind() const
|
||||
{
|
||||
glUseProgram(program);
|
||||
}
|
||||
|
||||
void Shader::unbind()
|
||||
{
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
auto Shader::parse(const std::filesystem::path &path) -> std::string
|
||||
{
|
||||
std::fstream file;
|
||||
file.open(path, std::ios::in);
|
||||
|
||||
if (!file.is_open()) {
|
||||
Log::logger().critical(R"(Shader "{}" not found!)", path.string());
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
return {(std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())};
|
||||
}
|
||||
|
||||
auto Shader::compile(std::string_view source, GLenum type) -> GLuint
|
||||
{
|
||||
GLuint program = glCreateShader(type);
|
||||
auto const *src = source.data();
|
||||
glShaderSource(program, 1, &src, nullptr);
|
||||
glCompileShader(program);
|
||||
|
||||
int result{};
|
||||
glGetShaderiv(program, GL_COMPILE_STATUS, &result);
|
||||
|
||||
if (result != GL_TRUE) {
|
||||
int length{};
|
||||
glGetShaderiv(program, GL_INFO_LOG_LENGTH, &length);
|
||||
|
||||
std::string message;
|
||||
message.reserve(static_cast<unsigned>(length));
|
||||
|
||||
glGetShaderInfoLog(program, length, &length, message.data());
|
||||
Log::logger().error("Shader compilation failed: {}", message);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
auto Shader::retrieveUniformLocation(std::string_view uniform_name) const -> GLint
|
||||
{
|
||||
if (uniform_location_cache.find(uniform_name.data()) != uniform_location_cache.end()) {
|
||||
return uniform_location_cache[uniform_name.data()];
|
||||
}
|
||||
|
||||
GLint location = glGetUniformLocation(program, uniform_name.data());
|
||||
|
||||
if (location != -1) {
|
||||
uniform_location_cache[uniform_name.data()] = location;
|
||||
} else {
|
||||
Log::logger().warn(R"(Uniform "{}" not found.)", uniform_name);
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Shader::set_uniform(std::string_view name, T value) const
|
||||
{
|
||||
GLint location = retrieveUniformLocation(name);
|
||||
|
||||
if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, int>) {
|
||||
glUniform1i(location, (int)value);
|
||||
} else if constexpr (std::is_same_v<T, unsigned>) {
|
||||
glUniform1ui(location, value);
|
||||
} else if constexpr (std::is_same_v<T, float>) {
|
||||
glUniform1f(location, value);
|
||||
} else if constexpr (std::is_same_v<T, glm::vec2>) {
|
||||
glUniform2f(location, value.x, value.y); //NOLINT(cppcoreguidelines-pro-type-union-access)
|
||||
} else if constexpr (std::is_same_v<T, glm::vec3>) {
|
||||
glUniform3f(location, value.x, value.y, value.z); //NOLINT(cppcoreguidelines-pro-type-union-access)
|
||||
} else if constexpr (std::is_same_v<T, glm::mat3>) {
|
||||
glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(value));
|
||||
} else if constexpr (std::is_same_v<T, glm::mat4>) {
|
||||
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
|
||||
}
|
||||
}
|
||||
|
||||
template void Shader::set_uniform(std::string_view, bool) const;
|
||||
template void Shader::set_uniform(std::string_view, int) const;
|
||||
template void Shader::set_uniform(std::string_view, unsigned) const;
|
||||
template void Shader::set_uniform(std::string_view, float) const;
|
||||
template void Shader::set_uniform(std::string_view, glm::vec2) const;
|
||||
template void Shader::set_uniform(std::string_view, glm::vec3) const;
|
||||
template void Shader::set_uniform(std::string_view, glm::mat3) const;
|
||||
template void Shader::set_uniform(std::string_view, glm::mat4) const;
|
||||
50
src/shader.h
Normal file
50
src/shader.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <glad/gl.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
struct Shader
|
||||
{
|
||||
Shader(std::string_view name, std::filesystem::path const &directory);
|
||||
|
||||
Shader(Shader const &) = delete;
|
||||
auto operator=(Shader const &) -> Shader & = delete;
|
||||
|
||||
Shader(Shader &&other) noexcept : program(other.program) { other.program = 0; }
|
||||
auto operator=(Shader &&other) noexcept -> Shader &
|
||||
{
|
||||
program = other.program;
|
||||
other.program = 0;
|
||||
return *this;
|
||||
};
|
||||
|
||||
~Shader();
|
||||
|
||||
void bind() const;
|
||||
static void unbind();
|
||||
|
||||
template <typename T>
|
||||
void set_uniform(std::string_view name, T value) const;
|
||||
|
||||
private:
|
||||
auto retrieveUniformLocation(std::string_view uniform_name) const -> GLint;
|
||||
static auto parse(const std::filesystem::path &path) -> std::string;
|
||||
static auto compile(std::string_view source, GLenum type) -> GLuint;
|
||||
|
||||
GLuint program;
|
||||
mutable std::unordered_map<std::string, GLint> uniform_location_cache;
|
||||
};
|
||||
|
||||
struct ShaderLoader
|
||||
{
|
||||
using result_type = std::shared_ptr<Shader>;
|
||||
static constexpr std::string_view shader_directory{"data/shaders"};
|
||||
|
||||
auto operator()(std::string_view name) -> result_type
|
||||
{
|
||||
return std::make_shared<Shader>(name, shader_directory);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user