post processing

main
Brett 2024-05-03 22:14:48 -04:00
parent 622b706618
commit ecae5287cc
11 changed files with 342 additions and 127 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.25)
set(BLT_GRAPHICS_VERSION 0.13.2)
set(BLT_GRAPHICS_VERSION 0.13.3)
set(BLT_GRAPHICS_TEST_VERSION 0.0.1)
project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION})

View File

@ -123,6 +123,8 @@ namespace blt::gfx
static void unbind();
static void bindScreen(draw_t type);
void destroy();
[[nodiscard]] i32 getHeight() const

View File

@ -23,6 +23,7 @@
#include "blt/gfx/shader.h"
#include "blt/gfx/framebuffer.h"
#include "blt/gfx/renderer/resource_manager.h"
#include "blt/gfx/renderer/postprocess.h"
#include <blt/std/hashmap.h>
#include <blt/std/memory_util.h>
#include <blt/math/vectors.h>
@ -148,7 +149,7 @@ namespace blt::gfx
class batch_renderer_2d
{
private:
frame_buffer_t draw_buffer;
pp_engine_t engine;
template<typename T>
struct render_object_t

View File

@ -28,56 +28,74 @@
namespace blt::gfx
{
namespace detail
{
class pp_link;
class pp_engine_t;
class pp_iterator;
class pp_step_t;
class pp_link
{
public:
private:
};
class pp_iterator
{
public:
private:
};
}
class pp_step
class pp_step_t
{
public:
virtual void create(i32 width, i32 height) = 0;
virtual void create() = 0;
virtual void draw(i32 width, i32 height) = 0;
virtual void draw() = 0;
frame_buffer_t& getBuffer()
{
return draw_buffer;
}
shader_t& getShader()
{
return *shader;
}
virtual ~pp_step_t() = default;
protected:
frame_buffer_t draw_buffer;
std::unique_ptr<shader_t> shader;
};
class pp_engine
class pp_render_target_t : public pp_step_t
{
public:
void create() override;
void draw() override;
};
class pp_to_screen_step_t : public pp_step_t
{
public:
void create() override;
void draw() override;
};
class pp_engine_t
{
public:
void create();
void render(i32 width, i32 height);
void bind();
void render();
void cleanup();
void addStep(std::unique_ptr<pp_step_t> step)
{
steps.emplace_back(std::move(step));
}
static std::unique_ptr<shader_t> createShader(std::string_view fragment);
private:
std::vector<std::unique_ptr<pp_step>> steps;
shader_t screen_shader;
std::vector<std::unique_ptr<pp_step_t>> steps;
std::unique_ptr<vertex_array_t> screen_vao;
#ifdef __EMSCRIPTEN__
std::unique_ptr<pp_to_screen_step_t> to_screen;
#endif
};
}

View File

@ -0,0 +1,32 @@
#ifdef __cplusplus
#include <string>
const std::string shader_postprocess_vert = R"("
#version 300 es
precision mediump float;
layout (location = 0) in vec3 vertex;
layout (location = 1) in vec2 uv_in;
out vec2 pos;
out vec2 uv;
layout (std140) uniform GlobalMatrices
{
mat4 projection;
mat4 ortho;
mat4 view;
mat4 pvm;
mat4 ovm;
};
uniform mat4 model;
uniform float z_index;
void main() {
gl_Position = ovm * model * vec4(vertex.xy, z_index, 1.0);
pos = vertex.xy;
uv = uv_in;
}
")";
#endif

View File

@ -0,0 +1,22 @@
#ifdef __cplusplus
#include <string>
const std::string shader_pp_to_screen_frag = R"("
#version 300 es
precision mediump float;
out vec4 FragColor;
in vec2 uv;
in vec2 pos;
uniform sampler2D tex;
vec4 linear_iter(vec4 i, vec4 p, float factor){
return (i + p) * factor;
}
void main() {
FragColor = texture(tex, uv);
}
")";
#endif

View File

@ -9,6 +9,7 @@
#define BLT_WITH_GRAPHICS_TEMPLATE_WINDOW_H
#include <blt/gfx/gl_includes.h>
#include <blt/std/types.h>
#include <GLFW/glfw3.h>
#include <functional>
#include <cstdint>
@ -19,11 +20,11 @@ namespace blt::gfx
{
struct window_context
{
std::int32_t GL_MAJOR = 4;
std::int32_t GL_MINOR = 6;
std::int32_t DOUBLE_BUFFER = GLFW_TRUE;
std::int32_t GL_PROFILE = GLFW_OPENGL_CORE_PROFILE;
std::int32_t SAMPLES = 8;
i32 GL_MAJOR = 4;
i32 GL_MINOR = 6;
i32 DOUBLE_BUFFER = GLFW_TRUE;
i32 GL_PROFILE = GLFW_OPENGL_CORE_PROFILE;
i32 SAMPLES = 8;
};
struct window_data
@ -39,9 +40,9 @@ namespace blt::gfx
window_context context{};
std::int32_t sync_interval = 0;
window_data(std::string title, std::function<void(const window_data&)> init, std::function<void(const window_data&)> update,
std::int32_t width = 640, std::int32_t height = 480): init(std::move(init)), update(std::move(update)),
title(std::move(title)), width(width), height(height)
window_data(std::string_view title, std::function<void(const window_data&)> init, std::function<void(const window_data&)> update,
i32 width = 640, i32 height = 480): init(std::move(init)), update(std::move(update)),
title(title), width(width), height(height)
{}
inline void call_init() const
@ -128,7 +129,11 @@ namespace blt::gfx
double getFrameDeltaMilliseconds();
std::int64_t getFrameDelta();
i64 getFrameDelta();
i32 getWindowWidth();
i32 getWindowHeight();
void cleanup();

View File

@ -279,9 +279,14 @@ namespace blt::gfx
fbo.attachRenderBuffer(depth_rbo, attachment_t::DEPTH_STENCIL);
if (!frame_buffer_t::validate())
BLT_ERROR("Failed to create multi-sampled render texture framebuffer!");
BLT_ERROR("Failed to create render texture framebuffer!");
frame_buffer_t::unbind();
return fbo;
}
void frame_buffer_t::bindScreen(frame_buffer_t::draw_t type)
{
glBindFramebuffer(static_cast<i32>(type), 0);
}
}

View File

@ -89,20 +89,23 @@ namespace blt::gfx
point_shader->bindAttribute(0, "vertex");
point_shader->bindAttribute(1, "uv_in");
draw_buffer.create();
draw_buffer.bind();
engine.addStep(std::make_unique<pp_render_target_t>());
engine.create();
auto* texture = new texture_gl2D(1440, 720);
draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0);
auto* mask = new texture_gl2D(1440, 720);
draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1);
render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, 1440, 720);
draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL);
if (!frame_buffer_t::validate())
BLT_ERROR("Failed to create render framebuffer!");
frame_buffer_t::unbind();
// draw_buffer.create();
// draw_buffer.bind();
//
// auto* texture = new texture_gl2D(1440, 720);
// draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0);
// auto* mask = new texture_gl2D(1440, 720);
// draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1);
//
// render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, 1440, 720);
// draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL);
//
// if (!frame_buffer_t::validate())
// BLT_ERROR("Failed to create render framebuffer!");
// frame_buffer_t::unbind();
}
void batch_renderer_2d::drawRectangleInternal(const std::string_view texture, const rectangle2d_t& rectangle, const f32 z_index)
@ -161,6 +164,7 @@ namespace blt::gfx
void batch_renderer_2d::cleanup()
{
engine.cleanup();
delete square_vao;
delete square_shader;
delete point_shader;
@ -168,8 +172,8 @@ namespace blt::gfx
void batch_renderer_2d::render(i32 width, i32 height, const bool transparency)
{
draw_buffer.bind();
draw_buffer.updateBuffersStorage(width, height);
//draw_buffer.bind();
//draw_buffer.updateBuffersStorage(width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (transparency)
{
@ -179,6 +183,7 @@ namespace blt::gfx
glEnable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
engine.bind();
draw_objects();
glDisable(GL_DEPTH_TEST);
@ -186,8 +191,9 @@ namespace blt::gfx
glDisable(GL_BLEND);
render_reset();
draw_buffer.blitToScreen(width, height);
frame_buffer_t::unbind();
engine.render();
}
void batch_renderer_2d::draw_objects()

View File

@ -15,17 +15,115 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <blt/gfx/renderer/post_process.h>
#include <blt/gfx/window.h>
#include <blt/gfx/renderer/postprocess.h>
#include <blt/gfx/renderer/shaders/postprocess.vert>
#include <blt/gfx/renderer/shaders/pp_to_screen.frag>
#include <blt/std/ranges.h>
float full_screen_vertices[20] = {
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
const unsigned int full_screen_indices[6] = {
0, 1, 3,
1, 2, 3
};
namespace blt::gfx
{
void pp_engine::create()
void pp_engine_t::create()
{
{
vertex_buffer_t vertices_vbo;
element_buffer_t indices_vbo;
vertices_vbo.create();
indices_vbo.create();
vertices_vbo.allocate(sizeof(full_screen_vertices), full_screen_vertices);
indices_vbo.allocate(sizeof(full_screen_indices), full_screen_indices);
screen_vao = std::make_unique<vertex_array_t>();
const auto tb = screen_vao->bindVBO(vertices_vbo, 0, 3, GL_FLOAT, 5 * sizeof(float), 0);
screen_vao->bindVBO(tb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
screen_vao->bindElement(indices_vbo);
}
#ifdef __EMSCRIPTEN__
to_screen = std::make_unique<pp_to_screen_step_t>();
#endif
for (auto& step : steps)
step->create();
}
void pp_engine::render(i32 width, i32 height)
void pp_engine_t::render()
{
screen_vao->bind();
for (const auto& [index, step] : blt::enumerate(steps))
{
if (index == 0)
{
continue;
} else
steps[index - 1]->getBuffer().bind(frame_buffer_t::draw_t::READ);
step->draw();
step->getBuffer().bind(frame_buffer_t::draw_t::DRAW);
step->getShader().bind();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
frame_buffer_t::unbind();
#ifdef __EMSCRIPTEN__
to_screen->getShader().bind();
steps.back()->getBuffer().bind(frame_buffer_t::draw_t::READ);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
#else
steps.back()->getBuffer().blitToScreen(getWindowWidth(), getWindowHeight());
#endif
}
void pp_engine_t::cleanup()
{
screen_vao = nullptr;
for (auto& v : steps)
v = nullptr;
steps.clear();
}
std::unique_ptr<shader_t> pp_engine_t::createShader(std::string_view fragment)
{
auto shader = std::make_unique<shader_t>(shader_postprocess_vert, std::string(fragment));
shader->bindAttribute(0, "vertex");
shader->bindAttribute(1, "uv_in");
return shader;
}
void pp_engine_t::bind()
{
steps.front()->draw();
steps.front()->getBuffer().bind(frame_buffer_t::draw_t::DRAW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void pp_to_screen_step_t::create()
{
shader = pp_engine_t::createShader(shader_pp_to_screen_frag);
}
void pp_to_screen_step_t::draw()
{}
void pp_render_target_t::create()
{
shader = pp_engine_t::createShader(shader_pp_to_screen_frag);
draw_buffer = frame_buffer_t::make_render_target(getWindowWidth(), getWindowHeight());
}
void pp_render_target_t::draw()
{
draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight());
}
}

View File

@ -247,6 +247,9 @@ namespace blt::gfx
glEnable(GL_MULTISAMPLE);
#endif
window_state.width = data.width;
window_state.height = data.height;
/* -- Call User Provided post-window-init function -- */
data.call_init();
@ -275,19 +278,26 @@ namespace blt::gfx
glfwTerminate();
}
double getMouseX() { return window_state.inputManager.mouseX; }
double getMouseX()
{ return window_state.inputManager.mouseX; }
double getMouseY() { return window_state.inputManager.mouseY; }
double getMouseY()
{ return window_state.inputManager.mouseY; }
double getMouseDX() { return window_state.inputManager.deltaX; }
double getMouseDX()
{ return window_state.inputManager.deltaX; }
double getMouseDY() { return window_state.inputManager.deltaY; }
double getMouseDY()
{ return window_state.inputManager.deltaY; }
void lockCursor() { glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); }
void lockCursor()
{ glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); }
void unlockCursor() { glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); }
void unlockCursor()
{ glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); }
bool isCursorLocked() { return glfwGetInputMode(window_state.window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; }
bool isCursorLocked()
{ return glfwGetInputMode(window_state.window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; }
bool isCursorInWindow()
{
@ -318,25 +328,41 @@ namespace blt::gfx
#endif
}
void setClipboard(const std::string& str) { glfwSetClipboardString(window_state.window, str.c_str()); }
void setClipboard(const std::string& str)
{ glfwSetClipboardString(window_state.window, str.c_str()); }
std::string getClipboard() { return glfwGetClipboardString(window_state.window); }
std::string getClipboard()
{ return glfwGetClipboardString(window_state.window); }
bool isMousePressed(int button) { return window_state.inputManager.isMousePressed(button); }
bool isMousePressed(int button)
{ return window_state.inputManager.isMousePressed(button); }
bool isKeyPressed(int key) { return window_state.inputManager.isKeyPressed(key); }
bool isKeyPressed(int key)
{ return window_state.inputManager.isKeyPressed(key); }
double getFrameDeltaSeconds() { return window_state.nanoDelta; }
double getFrameDeltaSeconds()
{ return window_state.nanoDelta; }
double getFrameDeltaMilliseconds() { return window_state.millisDelta; }
double getFrameDeltaMilliseconds()
{ return window_state.millisDelta; }
std::int64_t getFrameDelta() { return window_state.deltaTime; }
i64 getFrameDelta()
{ return window_state.deltaTime; }
bool mouseMovedLastFrame() { return window_state.inputManager.mouse_moved; }
bool mouseMovedLastFrame()
{ return window_state.inputManager.mouse_moved; }
bool mousePressedLastFrame() { return window_state.inputManager.mouse_pressed; }
bool mousePressedLastFrame()
{ return window_state.inputManager.mouse_pressed; }
bool keyPressedLastFrame() { return window_state.inputManager.key_pressed; }
bool keyPressedLastFrame()
{ return window_state.inputManager.key_pressed; }
i32 getWindowHeight()
{ return window_state.height; }
i32 getWindowWidth()
{ return window_state.width; }
window_data& window_data::setWindowSize(int32_t new_width, int32_t new_height)
{