post processing
parent
622b706618
commit
ecae5287cc
|
@ -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})
|
||||
|
|
|
@ -123,6 +123,8 @@ namespace blt::gfx
|
|||
|
||||
static void unbind();
|
||||
|
||||
static void bindScreen(draw_t type);
|
||||
|
||||
void destroy();
|
||||
|
||||
[[nodiscard]] i32 getHeight() const
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue