post processing works on emscripten now

main
Brett 2024-05-11 20:41:16 -04:00
parent 2c85c0f93c
commit a6853e6ff7
12 changed files with 258 additions and 79 deletions

View File

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

View File

@ -216,7 +216,7 @@ namespace blt::gfx
std::make_unique<pp_blur_step_inplace_t>(state, frame_buffer_t::attachment_t::COLOR1),
std::make_unique<pp_expansion_step_inplace_t>(frame_buffer_t::attachment_t::COLOR1,
vec4{4, 4, 4, 1}),
std::make_unique<pp_blur_step_inplace_t>(state, frame_buffer_t::attachment_t::COLOR1, 2, 2),
std::make_unique<pp_overlay_blur_step_t>(frame_buffer_t::attachment_t::COLOR1, 2, 2),
std::make_unique<pp_outline_step_t>(state)
);
}

View File

@ -27,6 +27,8 @@
#include <vector>
#include <memory>
#include <blt/std/assert.h>
#include <blt/parse/templating.h>
#include <optional>
namespace blt::gfx
{
@ -171,6 +173,27 @@ namespace blt::gfx
i32 y_blur;
};
class pp_overlay_blur_step_t : public pp_in_place_t
{
public:
pp_overlay_blur_step_t(frame_buffer_t::attachment_t from, i32 x_blur = 2, i32 y_blur = 2):
pp_in_place_t(from), x_blur(x_blur), y_blur(y_blur)
{}
pp_overlay_blur_step_t(frame_buffer_t::attachment_t from, frame_buffer_t::attachment_t to, i32 x_blur = 2,
i32 y_blur = 2):
pp_in_place_t(from, to), x_blur(x_blur), y_blur(y_blur)
{}
void create() override;
void draw(frame_buffer_t& previous);
private:
i32 x_blur;
i32 y_blur;
};
class pp_expansion_step_inplace_t : public pp_in_place_t
{
public:
@ -207,7 +230,7 @@ namespace blt::gfx
steps.emplace_back(std::move(step));
}
static std::unique_ptr<shader_t> createShader(std::string_view fragment);
static std::unique_ptr<shader_t> createShader(std::string_view fragment, std::optional<std::reference_wrapper<template_engine_t>> engine = {});
static std::unique_ptr<pp_engine_t> make_basic_pp()
{

View File

@ -0,0 +1,32 @@
#ifdef __cplusplus
#include <string>
const std::string shader_overlay_blur_frag = R"("
#version 300 es
precision mediump float;
out vec4 FragColor;
in vec2 uv;
in vec2 pos;
uniform sampler2D tex;
uniform ivec4 size;
void main() {
vec2 texelSize = 1.0 / vec2(float(size.x), float(size.y));
vec4 result = vec4(0.0, 0.0, 0.0, 0.0);
for (int x = -size.z; x <= size.z; ++x) {
for (int y = -size.w; y <= size.w; ++y) {
vec2 offset = (vec2(float(x), float(y)) * texelSize);
result += texture(tex, uv + offset);
}
}
vec4 blur_val = result / vec4((float(size.z) * 2.0) * (float(size.w) * 2.0));
vec4 tex_val = texture(tex, uv);
if (tex_val != vec4(0.0,0.0,0.0,0.0))
FragColor = tex_val;
else
FragColor = blur_val;
}
")";
#endif

View File

@ -23,6 +23,9 @@
#include <unordered_map>
#include <string>
#include <blt/math/math.h>
#include <blt/parse/templating.h>
#include <optional>
#include <memory>
namespace blt::gfx
{
@ -59,21 +62,24 @@ namespace blt::gfx
~uniform_buffer();
[[nodiscard]] inline size_t size() const { return size_; }
[[nodiscard]] inline size_t size() const
{ return size_; }
[[nodiscard]] inline GLuint location() const { return location_; }
[[nodiscard]] inline GLuint location() const
{ return location_; }
};
class shader_base_t
{
friend uniform_buffer;
friend uniform_buffer;
protected:
struct IntDefaultedToMinusOne
{
GLint i = -1;
inline explicit operator bool() const { return i != -1; }
inline explicit operator bool() const
{ return i != -1; }
};
std::unordered_map<std::string, IntDefaultedToMinusOne> uniformVars;
@ -116,6 +122,7 @@ namespace blt::gfx
shader_base_t& setVec3(const std::string& name, const blt::vec3& vec);
shader_base_t& setVec4(const std::string& name, const blt::vec4& vec);
shader_base_t& setVec4i(const std::string& name, const blt::vec4i& vec);
shader_base_t& setVec2(const std::string& name, float x, float y);
@ -155,18 +162,58 @@ namespace blt::gfx
static std::string loadShader(std::string_view file);
shader_t(std::string_view vertex, std::string_view fragment);
static std::pair<std::string, std::string> process_templates(template_engine_t& engine, std::string_view vertex,
std::string_view fragment);
public:
/**
* Creates a shader
* @param vertex vertex shader source or file
* @param fragment fragment shader source or file
* @param geometry geometry shader source or file (optional)
* @param load_as_string load the shader as a string (true) or use the string to load the shader as a file (false)
* Creates a shader from source file
* @param vertex vertex shader source
* @param fragment fragment shader source
*/
shader_t(const std::string& vertex, const std::string& fragment, bool load_as_string = true);
static shader_t* make(std::optional<std::reference_wrapper<template_engine_t>> engine, std::string_view vertex,
std::string_view fragment);
static shader_t* make(std::string_view vertex, std::string_view fragment)
{
return make({}, vertex, fragment);
}
static std::unique_ptr<shader_t> make_unique(std::optional<std::reference_wrapper<template_engine_t>> engine,
std::string_view vertex, std::string_view fragment);
static std::unique_ptr<shader_t> make_unique(std::string_view vertex, std::string_view fragment)
{
return make_unique({}, vertex, fragment);
}
/**
* Creates a shader by loading lines of source from the file.
* @param vertex vertex shader file path
* @param fragment fragment shader file path
*/
static shader_t* load(std::optional<std::reference_wrapper<template_engine_t>> engine, std::string_view vertex,
std::string_view fragment);
static shader_t* load(std::string_view vertex, std::string_view fragment)
{
return load({}, vertex, fragment);
}
static std::unique_ptr<shader_t> load_unique(std::optional<std::reference_wrapper<template_engine_t>> engine,
std::string_view vertex, std::string_view fragment);
static std::unique_ptr<shader_t> load_unique(std::string_view vertex, std::string_view fragment)
{
return load_unique({}, vertex, fragment);
}
shader_t(shader_t&& move) noexcept;
shader_t(const shader_t& copy) = delete;
// used to set the location of VAOs to the in variables in opengl shaders.
void bindAttribute(int attribute, const std::string& name) const;

@ -1 +1 @@
Subproject commit fa5083b637a96af5b430c9f0015ee11d5638d201
Subproject commit f228cfbbe31538731a2ef1bd990d41c99562c4d3

@ -1 +1 @@
Subproject commit a1b06823fe2d964a62fda99385499b218cf5cea5
Subproject commit 231cbee0fc4f59dbe5b8b853a11b08dc84e57c65

@ -1 +1 @@
Subproject commit 6675317107257c2cc16c947b359d557821d85bf2
Subproject commit 111397c71a5f1c2c88e05da9c84edfdba2e472a4

View File

@ -81,11 +81,11 @@ namespace blt::gfx
line_vao->bindElement(indices_vbo);
}
square_shader = new shader_t(shader_2d_textured_vert, shader_2d_textured_frag);
square_shader = shader_t::make(shader_2d_textured_vert, shader_2d_textured_frag);
square_shader->bindAttribute(0, "vertex");
square_shader->bindAttribute(1, "uv_in");
point_shader = new shader_t(shader_2d_textured_vert, shader_2d_textured_cirlce_frag);
point_shader = shader_t::make(shader_2d_textured_vert, shader_2d_textured_cirlce_frag);
point_shader->bindAttribute(0, "vertex");
point_shader->bindAttribute(1, "uv_in");

View File

@ -21,6 +21,7 @@
#include <blt/gfx/renderer/shaders/pp_screen.frag>
#include <blt/gfx/renderer/shaders/pp_outline_step.frag>
#include <blt/gfx/renderer/shaders/pp_gaussian_blur.frag>
#include <blt/gfx/renderer/shaders/pp_overlay_blur.frag>
#include <blt/gfx/renderer/shaders/pp_multiplier.frag>
#include <blt/std/ranges.h>
#include <blt/math/log_util.h>
@ -117,9 +118,18 @@ namespace blt::gfx
steps.clear();
}
std::unique_ptr<shader_t> pp_engine_t::createShader(std::string_view fragment)
std::unique_ptr<shader_t> pp_engine_t::createShader(std::string_view fragment, std::optional<std::reference_wrapper<template_engine_t>> engine)
{
auto shader = std::make_unique<shader_t>(shader_postprocess_vert, std::string(fragment));
std::unique_ptr<shader_t> shader;
if (engine)
{
shader = shader_t::make_unique(engine, shader_postprocess_vert, std::string(fragment));
} else
{
template_engine_t templateEngine;
templateEngine.set("LAYOUT_STRING", "");
shader = shader_t::make_unique(templateEngine, shader_postprocess_vert, std::string(fragment));
}
shader->bindAttribute(0, "vertex");
shader->bindAttribute(1, "uv_in");
return shader;
@ -139,7 +149,10 @@ namespace blt::gfx
void pp_in_place_t::create()
{
shader_pass = pp_engine_t::createShader(shader_pp_screen_frag);
template_engine_t engine;
engine.set("LAYOUT_STRING", "layout (location = ${IF(LAYOUT_LOCATION) { LAYOUT_LOCATION } ELSE { ~DISCARD }}) ");
engine.set("LAYOUT_LOCATION", std::to_string(static_cast<int>(to) - static_cast<int>(frame_buffer_t::attachment_t::COLOR0)));
shader_pass = pp_engine_t::createShader(shader_pp_screen_frag, engine);
draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight());
}
@ -274,4 +287,18 @@ namespace blt::gfx
shader->bind();
shader->setVec4("multiplier", multiplier);
}
void pp_overlay_blur_step_t::create()
{
pp_in_place_t::create();
shader = pp_engine_t::createShader(shader_overlay_blur_frag);
}
void pp_overlay_blur_step_t::draw(frame_buffer_t& previous)
{
pp_in_place_t::draw(previous);
shader->bind();
auto v = vec2(getWindowWidth(), getWindowHeight());
shader->setVec4i("size", {static_cast<i32>(v.x()), static_cast<i32>(v.y()), x_blur, y_blur});
}
}

View File

@ -70,13 +70,13 @@ namespace blt::gfx
glDeleteBuffers(1, &uboID);
}
static std::string removeEmptyFirstLines(const std::string& string)
static std::string removeEmptyFirstLines(std::string_view string)
{
auto lines = blt::string::split(string, "\n");
auto lines = blt::string::split_sv(string, "\n");
std::string new_source_string;
for (const auto& line : lines)
{
if (!line.empty() && !blt::string::contains(line, "\""))
if (!blt::string::trim(line).empty() && !blt::string::starts_with(line, "\""))
{
new_source_string += line;
new_source_string += "\n";
@ -122,21 +122,11 @@ namespace blt::gfx
return shaderID;
}
shader_t::shader_t(const std::string& vertex, const std::string& fragment, bool load_as_string)
shader_t::shader_t(std::string_view vertex, std::string_view fragment)
{
// load shader sources
std::string vertex_source = vertex;
std::string fragment_source = fragment;
if (!load_as_string)
{
// BLT provides a recursive file loader for glsl shaders. It's pretty much just a recursive function looking for include statements.
vertex_source = loadShader(vertex);
fragment_source = loadShader(fragment);
} else
{
vertex_source = removeEmptyFirstLines(vertex_source);
fragment_source = removeEmptyFirstLines(fragment_source);
}
// load shader sources
std::string vertex_source = removeEmptyFirstLines(vertex);
std::string fragment_source = removeEmptyFirstLines(fragment);
// create the shaders
vertexShaderID = createShader(vertex_source, GL_VERTEX_SHADER);
@ -232,6 +222,64 @@ namespace blt::gfx
return str;
}
shader_t* shader_t::make(std::optional<std::reference_wrapper<template_engine_t>> engine, std::string_view vertex,
std::string_view fragment)
{
std::string vertex_source;
std::string fragment_source;
if (engine)
{
auto s_pair = process_templates(engine->get(), vertex, fragment);
vertex_source = std::move(s_pair.first);
fragment_source = std::move(s_pair.second);
} else
{
vertex_source = vertex;
fragment_source = fragment;
}
return new shader_t(vertex_source, fragment_source);
}
shader_t* shader_t::load(std::optional<std::reference_wrapper<template_engine_t>> engine, std::string_view vertex,
std::string_view fragment)
{
auto vertex_source = loadShader(vertex);
auto fragment_source = loadShader((fragment));
return make(engine, vertex_source, fragment_source);
}
std::pair<std::string, std::string> shader_t::process_templates(template_engine_t& engine, std::string_view vertex, std::string_view fragment)
{
auto vertex_e = engine.evaluate(vertex);
auto fragment_e = engine.evaluate(fragment);
if (!vertex_e)
{
BLT_ERROR("Error vertex function returned: %d", static_cast<int>(vertex_e.error()));
throw std::runtime_error("Unable to substitute vertex source");
}
if (!fragment_e)
{
BLT_ERROR("Error fragment function returned: %d", static_cast<int>(vertex_e.error()));
throw std::runtime_error("Unable to substitute fragment source");
}
return {vertex_e.value(), fragment_e.value()};
}
std::unique_ptr<shader_t> shader_t::make_unique(std::optional<std::reference_wrapper<template_engine_t>> engine, std::string_view vertex,
std::string_view fragment)
{
return std::unique_ptr<shader_t>(shader_t::make(engine, vertex, fragment));
}
std::unique_ptr<shader_t> shader_t::load_unique(std::optional<std::reference_wrapper<template_engine_t>> engine, std::string_view vertex,
std::string_view fragment)
{
auto vertex_source = loadShader(vertex);
auto fragment_source = loadShader((fragment));
return make_unique(engine, vertex_source, fragment_source);
}
shader_base_t& shader_base_t::setBool(const std::string& name, bool value)
{
if (auto i = getUniformLocation(name))

View File

@ -252,8 +252,10 @@ namespace blt::gfx
gladLoadGL(glfwGetProcAddress);
#endif
#ifndef __EMSCRIPTEN__
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(gl_error_callback, nullptr);
#endif
/* -- Set up our local callbacks, ImGUI will then call these -- */
create_callbacks();