breaking change, new VAO/VBO. Updated renderers not tested.

main
Brett 2025-06-12 02:16:37 -04:00
parent c28f8e6109
commit dd3a242b41
10 changed files with 405 additions and 771 deletions

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
include(FetchContent) include(FetchContent)
set(BLT_GRAPHICS_VERSION 2.0.11) set(BLT_GRAPHICS_VERSION 3.0.0)
set(BLT_GRAPHICS_TEST_VERSION 0.0.1) set(BLT_GRAPHICS_TEST_VERSION 0.0.1)
project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION}) project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION})

View File

@ -1,243 +0,0 @@
/*
* <Short Description>
* Copyright (C) 2023 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_WITH_GRAPHICS_MODEL_H
#define BLT_WITH_GRAPHICS_MODEL_H
#include <blt/math/vectors.h>
#include <vector>
#include <blt/gfx/gl_includes.h>
#include <variant>
#include <array>
#include <blt/std/hashmap.h>
namespace blt::gfx
{
struct vbo_t_owner;
class static_dynamic_array;
class vertex_array_t;
// vbo
struct vertex_buffer_t
{
friend vbo_t_owner;
friend vertex_array_t;
friend static_dynamic_array;
private:
GLuint bufferID_ = 0;
GLsizeiptr size_ = 0;
GLint buffer_type = 0;
GLint memory_type = 0;
public:
void create(GLint type = GL_ARRAY_BUFFER);
void bind() const;
void unbind() const;
void allocate(GLsizeiptr size, GLint mem_type = GL_STATIC_DRAW, const void* data = nullptr);
template<typename T>
void allocate(GLsizeiptr size, const T* data, GLint mem_type = GL_STATIC_DRAW)
{
allocate(size, mem_type, static_cast<const void*>(data));
}
void sub_update(GLsizeiptr offset, GLsizeiptr size, const void* data) const;
void update(GLsizeiptr size, const void* data);
void destroy();
};
// ssbo
struct shader_buffer_t : public vertex_buffer_t
{
public:
inline void create()
{
vertex_buffer_t::create(GL_SHADER_STORAGE_BUFFER);
}
};
// ebo
struct element_buffer_t : public vertex_buffer_t
{
public:
inline void create()
{
vertex_buffer_t::create(GL_ELEMENT_ARRAY_BUFFER);
}
};
struct vbo_t_owner
{
vertex_buffer_t vbo;
vbo_t_owner() = default;
explicit vbo_t_owner(vertex_buffer_t vbo): vbo(vbo)
{}
vertex_buffer_t* operator->()
{
return &vbo;
}
~vbo_t_owner()
{
if (!vbo.bufferID_)
return;
vbo.destroy();
vbo.unbind();
}
};
/**
* Since most VAOs will not use more than 8 VBOs it makes no sense to heap allocate memory to store them
* This class is used to make that easier to handle
*/
class static_dynamic_array
{
public:
using vbo_type = std::shared_ptr<vbo_t_owner>;
private:
static constexpr size_t DATA_SIZE = 8;
using array_t = std::array<vbo_type, DATA_SIZE>;
std::variant<array_t, vbo_type*> data_;
size_t size_ = DATA_SIZE;
size_t max = 0;
void swap();
public:
static_dynamic_array();
static_dynamic_array(const static_dynamic_array& copy) = delete;
static_dynamic_array(static_dynamic_array&& move) noexcept = default;
static_dynamic_array& operator=(const static_dynamic_array& copy) = delete;
static_dynamic_array& operator=(static_dynamic_array&& move) noexcept = default;
vbo_type& operator[](size_t index);
[[nodiscard]] inline size_t used() const noexcept
{
return max;
}
~static_dynamic_array()
{
if (std::holds_alternative<vbo_type*>(data_))
delete[] std::get<vbo_type*>(data_);
}
};
/**
* basic VAO class.
*/
class vertex_array_t
{
private:
GLuint vaoID;
static_dynamic_array VBOs;
blt::hashset_t<GLuint> used_attributes;
vertex_buffer_t element;
void handle_vbo(const vertex_buffer_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
public:
vertex_array_t();
vertex_array_t(const vertex_array_t&) = delete;
vertex_array_t(vertex_array_t&&) = delete;
vertex_array_t& operator=(const vertex_array_t&) = delete;
vertex_array_t& operator=(vertex_array_t&&) = delete;
/**
* This function takes ownership of the underlying VBO (GPU side). It will be freed when the basic vertex array is deleted
* @param vbo vbo to bind to this attribute
* @param attribute_number attribute number to bind to
* @param coordinate_size size of the data (number of
* @param type type of data
* @param stride how many bytes this data takes (for the entire per-vertex data structure) 0 will assume packed data
* This is in effect how many bytes until the next block of data
* @param offset offset into the data structure to where the data is stored
* @return a shared pointer to the stored vbo. used for chaining VAOs with multiple shared VBOs
*/
void bindVBO(const vertex_buffer_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
// same as the other bind method except you provide the shared reference.
void bindVBO(const static_dynamic_array::vbo_type& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
inline void bindElement(const vertex_buffer_t& vbo)
{
bind();
element = vbo;
vbo.bind();
unbind();
}
inline vertex_buffer_t& getElement()
{
return element;
}
/**
* Returns a non-owning reference to a vbo allowing for updating the VBO
* The VBO is considered invalid if its ID is 0
*/
inline vertex_buffer_t& operator[](size_t index)
{
return getBuffer(index);
}
inline vertex_buffer_t& getBuffer(size_t index)
{
return VBOs[index]->vbo;
}
inline void bind() const
{
glBindVertexArray(vaoID);
}
static inline void unbind()
{
glBindVertexArray(0);
}
static inline static_dynamic_array::vbo_type make_vbo(const vertex_buffer_t& vbo)
{
return std::make_shared<vbo_t_owner>(vbo);
}
~vertex_array_t();
};
}
#endif //BLT_WITH_GRAPHICS_MODEL_H

View File

@ -19,16 +19,16 @@
#ifndef BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H #ifndef BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H
#define BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H #define BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H
#include "blt/gfx/model.h"
#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>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include <blt/math/vectors.h>
#include <blt/std/hashmap.h>
#include <blt/std/memory_util.h>
#include "blt/gfx/framebuffer.h"
#include "blt/gfx/shader.h"
#include "blt/gfx/vao.h"
#include "blt/gfx/renderer/postprocess.h"
#include "blt/gfx/renderer/resource_manager.h"
namespace blt::gfx namespace blt::gfx
{ {
@ -121,12 +121,12 @@ namespace blt::gfx
struct draw_t struct draw_t
{ {
std::unique_ptr<vertex_array_t> vao; std::optional<unique_vao_t> vao;
i32 count; i32 count;
}; };
[[nodiscard]] draw_t to_vertex_array() const; [[nodiscard]] draw_t to_vertex_array() const;
size_t populate_vertex_array(vertex_array_t& va) const; [[nodiscard]] size_t populate_vertex_array(const unique_vao_t& va) const;
[[nodiscard]] std::vector<line_vertex_t> calculate_vertices() const; [[nodiscard]] std::vector<line_vertex_t> calculate_vertices() const;
@ -254,9 +254,9 @@ namespace blt::gfx
using object_container = hashmap_t<std::string, std::vector<std::pair<render_info_t, T>>>; using object_container = hashmap_t<std::string, std::vector<std::pair<render_info_t, T>>>;
private: private:
std::unique_ptr<vertex_array_t> square_vao; std::optional<unique_vao_t> square_vao;
std::unique_ptr<vertex_array_t> line_vao; std::optional<unique_vao_t> line_vao;
std::unique_ptr<vertex_array_t> curve_vao; std::optional<unique_vao_t> curve_vao;
std::unique_ptr<shader_t> square_shader; std::unique_ptr<shader_t> square_shader;
std::unique_ptr<shader_t> point_shader; std::unique_ptr<shader_t> point_shader;
resource_manager& resources; resource_manager& resources;

View File

@ -22,7 +22,7 @@
#include <blt/gfx/font/font.h> #include <blt/gfx/font/font.h>
#include <blt/gfx/texture.h> #include <blt/gfx/texture.h>
#include <blt/gfx/shader.h> #include <blt/gfx/shader.h>
#include <blt/gfx/model.h> #include <blt/gfx/vao.h>
#include <blt/gfx/framebuffer.h> #include <blt/gfx/framebuffer.h>
#include <blt/std/hashmap.h> #include <blt/std/hashmap.h>
#include <blt/std/binary_tree.h> #include <blt/std/binary_tree.h>
@ -368,7 +368,7 @@ namespace blt::gfx
font_generator_t& generator; font_generator_t& generator;
std::string contents, font; std::string contents, font;
vertex_array_t vao{}; unique_vao_t vao{};
std::vector<text_render_info_t> renders; std::vector<text_render_info_t> renders;
blt::vec2f position, bounds; blt::vec2f position, bounds;
blt::vec2f scale = DEFAULT_SCALE; blt::vec2f scale = DEFAULT_SCALE;

View File

@ -22,7 +22,7 @@
#include <blt/std/types.h> #include <blt/std/types.h>
#include <blt/gfx/framebuffer.h> #include <blt/gfx/framebuffer.h>
#include <blt/gfx/shader.h> #include <blt/gfx/shader.h>
#include <blt/gfx/model.h> #include <blt/gfx/vao.h>
#include <blt/gfx/state.h> #include <blt/gfx/state.h>
#include <vector> #include <vector>
#include <memory> #include <memory>
@ -271,10 +271,10 @@ namespace blt::gfx
private: private:
pp_engine_t() = default; pp_engine_t() = default;
pp_step_t& find_last_frame_buffer(size_t index); pp_step_t& find_last_frame_buffer(size_t index) const;
std::vector<std::unique_ptr<pp_step_t>> steps; std::vector<std::unique_ptr<pp_step_t>> steps;
std::unique_ptr<vertex_array_t> screen_vao; std::optional<unique_vao_t> screen_vao{};
}; };
} }

View File

@ -54,14 +54,6 @@ namespace blt::gfx
*/ */
vbo_context_t& resize(GLsizeiptr size, GLint mem_type); vbo_context_t& resize(GLsizeiptr size, GLint mem_type);
/**
* Reserves a chunk of GPU memory for future use
*/
vbo_context_t& resize(const size_t size, const GLint mem_type)
{
return resize(static_cast<GLsizeiptr>(size), mem_type);
}
/** /**
* Uploads a chunk of memory to the GPU. If the existing VBO has enough space, the memory will be reused. * Uploads a chunk of memory to the GPU. If the existing VBO has enough space, the memory will be reused.
*/ */
@ -71,9 +63,9 @@ namespace blt::gfx
* Uploads a chunk of memory to the GPU. If the existing VBO has enough space, the memory will be reused. * Uploads a chunk of memory to the GPU. If the existing VBO has enough space, the memory will be reused.
*/ */
template <typename T, std::enable_if_t<!std::is_same_v<T, void>, bool> = true> template <typename T, std::enable_if_t<!std::is_same_v<T, void>, bool> = true>
vbo_context_t& upload(const size_t size, T* ptr, const GLint mem_type) vbo_context_t& upload(const size_t size, const T* ptr, const GLint mem_type)
{ {
return upload(size, static_cast<void*>(ptr), mem_type); return upload(size, static_cast<const void*>(ptr), mem_type);
} }
/** /**

View File

@ -1,155 +0,0 @@
/*
* <Short Description>
* Copyright (C) 2023 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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/model.h>
#include <blt/std/memory_util.h>
#include "blt/logging/logging.h"
namespace blt::gfx
{
void static_dynamic_array::swap()
{
size_t next_size = blt::mem::next_byte_allocation(size_);
auto* new_data = new vbo_type[next_size];
if (std::holds_alternative<vbo_type*>(data_))
{
auto* ptr = std::get<vbo_type*>(data_);
for (size_t i = 0; i < size_; i++)
new_data[i] = ptr[i];
delete[] ptr;
} else
{
auto data = std::get<array_t>(data_);
for (size_t i = 0; i < DATA_SIZE; i++)
new_data[i] = data[i];
}
data_ = new_data;
size_ = next_size;
}
static_dynamic_array::static_dynamic_array() = default;
static_dynamic_array::vbo_type& static_dynamic_array::operator[](size_t index)
{
if (index >= size_)
swap();
max = std::max(index, max);
if (std::holds_alternative<vbo_type*>(data_))
return std::get<vbo_type*>(data_)[index];
else
return std::get<array_t>(data_)[index];
}
/*
* -----------------------------------
* vbo_t
* -----------------------------------
*/
void vertex_buffer_t::create(GLint type)
{
glGenBuffers(1, &bufferID_);
buffer_type = type;
}
void vertex_buffer_t::destroy()
{
// prevent multiple destroys of the same object, in cases of multi attribute binds
if (bufferID_ == 0)
return;
glDeleteBuffers(1, &bufferID_);
bufferID_ = 0;
}
void vertex_buffer_t::allocate(GLsizeiptr size, GLint mem_type, const void* data)
{
bind();
size_ = size;
glBufferData(buffer_type, size, data, mem_type);
memory_type = mem_type;
}
void vertex_buffer_t::update(GLsizeiptr size, const void* data)
{
if (size <= size_)
sub_update(0, size, data);
else
allocate(size, memory_type, data);
size_ = size;
}
void vertex_buffer_t::sub_update(GLsizeiptr offset, GLsizeiptr size, const void* data) const
{
bind();
glBufferSubData(buffer_type, offset, size, data);
}
void vertex_buffer_t::bind() const
{
glBindBuffer(buffer_type, bufferID_);
}
void vertex_buffer_t::unbind() const
{
glBindBuffer(buffer_type, 0);
}
/*
* ----------------------------
* basic_vertex_array
* ----------------------------
*/
vertex_array_t::vertex_array_t(): vaoID(0)
{
glGenVertexArrays(1, &vaoID);
}
vertex_array_t::~vertex_array_t()
{
// free all VBOs
for (size_t i = 0; i < VBOs.used(); i++)
VBOs[i] = nullptr;
element.destroy();
// then free the vertex array
glDeleteVertexArrays(1, &vaoID);
}
void vertex_array_t::bindVBO(const vertex_buffer_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset)
{
handle_vbo(vbo, attribute_number, coordinate_size, type, stride, offset);
VBOs[attribute_number] = make_vbo(vbo);
}
void vertex_array_t::bindVBO(const static_dynamic_array::vbo_type& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset)
{
handle_vbo(vbo->vbo, attribute_number, coordinate_size, type, stride, offset);
VBOs[attribute_number] = vbo;
}
void vertex_array_t::handle_vbo(const vertex_buffer_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset)
{
used_attributes.insert(attribute_number);
bind();
vbo.bind();
glEnableVertexAttribArray(attribute_number);
glVertexAttribPointer(attribute_number, coordinate_size, type, GL_FALSE, stride < 0 ? 0 : stride, (void*) offset);
unbind();
}
}

View File

@ -23,22 +23,58 @@
float square_vertices[20] = { float square_vertices[20] = {
// positions // texture coords // positions // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right 0.5f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right 0.5f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left 1.0f,
1.0f, // top right
0.5f,
-0.5f,
0.0f,
1.0f,
0.0f, // bottom right
-0.5f,
-0.5f,
0.0f,
0.0f,
0.0f, // bottom left
-0.5f,
0.5f,
0.0f,
0.0f,
1.0f // top left
}; };
const unsigned int square_indices[6] = { const unsigned int square_indices[6] = {
0, 1, 3, // first triangle 0,
1, 2, 3 // second triangle 1,
3, // first triangle
1,
2,
3 // second triangle
}; };
float line_vertices[20] = { float line_vertices[20] = {
// positions // texture coords // positions // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right 0.5f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right 0.5f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left 1.0f,
1.0f, // top right
0.5f,
-0.5f,
0.0f,
1.0f,
0.0f, // bottom right
-0.5f,
-0.5f,
0.0f,
0.0f,
0.0f, // bottom left
-0.5f,
0.5f,
0.0f,
0.0f,
1.0f // top left
}; };
// 0, 1 (top right) // 0, 1 (top right)
@ -51,23 +87,23 @@ namespace blt::gfx
curve2d_mesh_data_t::draw_t curve2d_mesh_data_t::to_vertex_array() const curve2d_mesh_data_t::draw_t curve2d_mesh_data_t::to_vertex_array() const
{ {
const auto vertices = calculate_vertices(); const auto vertices = calculate_vertices();
auto vao = std::make_unique<vertex_array_t>(); auto vao = unique_vao_t{};
vertex_buffer_t vertex_buffer; unique_vbo_t vertex_buffer{GL_ARRAY_BUFFER};
vertex_buffer.create(); vertex_buffer.bind().upload(static_cast<long>(vertices.size() * sizeof(line_vertex_t)), vertices.data(), GL_STATIC_DRAW);
vertex_buffer.allocate(static_cast<long>(vertices.size() * sizeof(line_vertex_t)), vertices.data());
const auto vb = vertex_array_t::make_vbo(vertex_buffer); const auto ctx = vao.configure();
vao->bindVBO(vb, 0, 3, GL_FLOAT, sizeof(line_vertex_t), 0); auto vbo = ctx.attach_vbo(std::move(vertex_buffer));
vao->bindVBO(vb, 1, 2, GL_FLOAT, sizeof(line_vertex_t), sizeof(vec3)); vbo.attribute_ptr(0, 3, GL_FLOAT, sizeof(line_vertex_t), 0);
vbo.attribute_ptr(1, 2, GL_FLOAT, sizeof(line_vertex_t), sizeof(vec3));
return {std::move(vao), static_cast<i32>(vertices.size())}; return {std::move(vao), static_cast<i32>(vertices.size())};
} }
size_t curve2d_mesh_data_t::populate_vertex_array(vertex_array_t& va) const size_t curve2d_mesh_data_t::populate_vertex_array(const unique_vao_t& va) const
{ {
const auto vertices = calculate_vertices(); const auto vertices = calculate_vertices();
va.getBuffer(0).update(static_cast<long>(vertices.size() * sizeof(line_vertex_t)), vertices.data()); va.get_attribute(0)->get().bind().upload(static_cast<long>(vertices.size() * sizeof(line_vertex_t)), vertices.data(), GL_STATIC_DRAW);
return vertices.size(); return vertices.size();
} }
@ -210,47 +246,43 @@ namespace blt::gfx
void batch_renderer_2d::create() void batch_renderer_2d::create()
{ {
{ {
vertex_buffer_t vertices_vbo; unique_vbo_t vertices_vbo{GL_ARRAY_BUFFER};
element_buffer_t indices_vbo; unique_ebo_t indices_vbo;
vertices_vbo.create(); vertices_vbo.bind().upload(sizeof(square_vertices), square_vertices, GL_STATIC_DRAW);
indices_vbo.create(); indices_vbo.bind().upload(sizeof(square_indices), square_indices, GL_STATIC_DRAW);
vertices_vbo.allocate(sizeof(square_vertices), square_vertices); square_vao = unique_vao_t{};
indices_vbo.allocate(sizeof(square_indices), square_indices); const auto ctx = square_vao->configure();
auto vbo = ctx.attach_vbo(std::move(vertices_vbo));
square_vao = std::make_unique<vertex_array_t>(); vbo.attribute_ptr(0, 3, GL_FLOAT, 5 * sizeof(float), 0);
auto vb = vertex_array_t::make_vbo(vertices_vbo); vbo.attribute_ptr(1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
square_vao->bindVBO(vb, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); ctx.attach_vbo(std::move(indices_vbo));
square_vao->bindVBO(vb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
square_vao->bindElement(indices_vbo);
} }
{ {
vertex_buffer_t vertices_vbo; unique_vbo_t vertices_vbo{GL_ARRAY_BUFFER};
element_buffer_t indices_vbo; unique_ebo_t indices_vbo;
vertices_vbo.create(); vertices_vbo.bind().upload(sizeof(line_vertices), line_vertices, GL_DYNAMIC_DRAW);
indices_vbo.create(); indices_vbo.bind().upload(sizeof(square_indices), square_indices, GL_DYNAMIC_DRAW);
vertices_vbo.allocate(sizeof(line_vertices), line_vertices, GL_DYNAMIC_DRAW); line_vao = unique_vao_t{};
indices_vbo.allocate(sizeof(square_indices), square_indices, GL_DYNAMIC_DRAW); const auto ctx = line_vao->configure();
auto vbo = ctx.attach_vbo(std::move(vertices_vbo));
line_vao = std::make_unique<vertex_array_t>(); vbo.attribute_ptr(0, 3, GL_FLOAT, 5 * sizeof(float), 0);
const auto vb = vertex_array_t::make_vbo(vertices_vbo); vbo.attribute_ptr(1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
line_vao->bindVBO(vb, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); ctx.attach_vbo(std::move(indices_vbo));
line_vao->bindVBO(vb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
line_vao->bindElement(indices_vbo);
} }
{ {
curve_vao = std::make_unique<vertex_array_t>(); curve_vao = unique_vao_t{};
vertex_buffer_t vertex_buffer; unique_vbo_t vertex_buffer{GL_ARRAY_BUFFER};
vertex_buffer.create(); vertex_buffer.bind().resize(0, GL_DYNAMIC_DRAW);
vertex_buffer.allocate(0, GL_DYNAMIC_DRAW);
const auto vb = vertex_array_t::make_vbo(vertex_buffer); const auto ctx = curve_vao->configure();
curve_vao->bindVBO(vb, 0, 3, GL_FLOAT, sizeof(curve2d_mesh_data_t::line_vertex_t), 0); auto vbo = ctx.attach_vbo(std::move(vertex_buffer));
curve_vao->bindVBO(vb, 1, 2, GL_FLOAT, sizeof(curve2d_mesh_data_t::line_vertex_t), sizeof(vec3)); vbo.attribute_ptr(0, 3, GL_FLOAT, sizeof(curve2d_mesh_data_t::line_vertex_t), 0);
vbo.attribute_ptr(1, 2, GL_FLOAT, sizeof(curve2d_mesh_data_t::line_vertex_t), sizeof(vec3));
} }
square_shader = shader_t::make_unique(shader_2d_textured_vert, shader_2d_textured_frag); square_shader = shader_t::make_unique(shader_2d_textured_vert, shader_2d_textured_frag);
@ -340,9 +372,9 @@ namespace blt::gfx
{ {
engine->cleanup(); engine->cleanup();
engine = nullptr; engine = nullptr;
square_vao = nullptr; square_vao.reset();
line_vao = nullptr; line_vao.reset();
curve_vao = nullptr; curve_vao.reset();
square_shader = nullptr; square_shader = nullptr;
point_shader = nullptr; point_shader = nullptr;
} }
@ -435,8 +467,8 @@ namespace blt::gfx
mat4x4 empty_model; mat4x4 empty_model;
square_shader->setMatrix("model", empty_model); square_shader->setMatrix("model", empty_model);
line_vao->bind(); line_vao->bind();
auto& buf = line_vao->getBuffer(0); auto& buf = line_vao->get_attribute(0)->get();
buf.bind(); auto vbo = buf.bind();
for (auto& [texture, objects] : draw.complex_lines) for (auto& [texture, objects] : draw.complex_lines)
{ {
// resource manager handles the check for empty string // resource manager handles the check for empty string
@ -479,7 +511,7 @@ namespace blt::gfx
line_vertices[15] = top_left.x(); line_vertices[15] = top_left.x();
line_vertices[16] = top_left.y(); line_vertices[16] = top_left.y();
buf.update(sizeof(line_vertices), line_vertices); vbo.update(0, sizeof(line_vertices), line_vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
draw.draw_count++; draw.draw_count++;

View File

@ -328,12 +328,9 @@ namespace blt::gfx
font_renderer_t::compiled_text_t::compiled_text_t(font_generator_t& generator): generator(generator) font_renderer_t::compiled_text_t::compiled_text_t(font_generator_t& generator): generator(generator)
{ {
auto vbo = vertex_array_t::make_vbo({}); unique_vbo_t vbo{GL_ARRAY_BUFFER};
vbo->vbo.create(); vbo.bind().resize(sizeof(float) * 6 * 4, GL_DYNAMIC_DRAW);
vbo->vbo.bind(); vao.configure().attach_vbo(std::move(vbo)).attribute_ptr(0, 4, GL_FLOAT, 4 * sizeof(float), 0);
vbo->vbo.allocate(sizeof(float) * 6 * 4, GL_DYNAMIC_DRAW);
vao.bind();
vao.bindVBO(vbo, 0, 4, GL_FLOAT, 4 * sizeof(float), 0);
} }
void font_renderer_t::compiled_text_t::draw() void font_renderer_t::compiled_text_t::draw()
@ -433,7 +430,7 @@ namespace blt::gfx
// BLT_TRACE("size: %ld %ld %ld", draw_count, vertices.size(), vertices.size() / 4); // BLT_TRACE("size: %ld %ld %ld", draw_count, vertices.size(), vertices.size() / 4);
renders.emplace_back(last_texture, draw_start, draw_count); renders.emplace_back(last_texture, draw_start, draw_count);
vao.getBuffer(0).update(static_cast<long>(vertices.size() * sizeof(float)), vertices.data()); vao.get_attribute(0)->get().bind().update(0, static_cast<long>(vertices.size() * sizeof(float)), vertices.data());
return *this; return *this;
} }

View File

@ -27,295 +27,306 @@
#include <blt/std/ranges.h> #include <blt/std/ranges.h>
#include <blt/math/log_util.h> #include <blt/math/log_util.h>
#define __EMSCRIPTEN__ // #define __EMSCRIPTEN__
float full_screen_vertices[20] = { float full_screen_vertices[20] = {
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f 1.0f,
}; 1.0f,
const unsigned int full_screen_indices[6] = { 1.0f,
0, 1, 3, -1.0f,
1, 2, 3 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};
template<typename T> template <typename T>
bool once() bool once()
{ {
static bool ran = true; static bool ran = true;
return std::exchange(ran, false); return std::exchange(ran, false);
} }
namespace blt::gfx namespace blt::gfx
{ {
void pp_engine_t::create() void pp_engine_t::create()
{ {
{ {
vertex_buffer_t vertices_vbo; unique_vbo_t vertices_vbo{GL_ARRAY_BUFFER};
element_buffer_t indices_vbo; unique_ebo_t indices_vbo;
vertices_vbo.create(); vertices_vbo.bind().upload(sizeof(full_screen_vertices), full_screen_vertices, GL_STATIC_DRAW);
indices_vbo.create(); indices_vbo.bind().upload(sizeof(full_screen_indices), full_screen_indices, GL_STATIC_DRAW);
vertices_vbo.allocate(sizeof(full_screen_vertices), full_screen_vertices); screen_vao = unique_vao_t{};
indices_vbo.allocate(sizeof(full_screen_indices), full_screen_indices); const auto ctx = screen_vao->configure();
auto vbo = ctx.attach_vbo(std::move(vertices_vbo));
screen_vao = std::make_unique<vertex_array_t>(); vbo.attribute_ptr(0, 3, GL_FLOAT, 5 * sizeof(float), 0);
auto vb = vertex_array_t::make_vbo(vertices_vbo); vbo.attribute_ptr(1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
screen_vao->bindVBO(vb, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); ctx.attach_vbo(std::move(indices_vbo));
screen_vao->bindVBO(vb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); }
screen_vao->bindElement(indices_vbo); #ifdef __EMSCRIPTEN__
} addStep(std::make_unique<pp_to_screen_step_t>());
#ifdef __EMSCRIPTEN__ #endif
addStep(std::make_unique<pp_to_screen_step_t>()); for (const auto& step : steps)
#endif step->create();
for (auto& step : steps) }
step->create();
} pp_step_t& pp_engine_t::find_last_frame_buffer(const size_t index) const
{
pp_step_t& pp_engine_t::find_last_frame_buffer(size_t index) for (i64 i = static_cast<i64>(index); i >= 0; i--)
{ {
for (i64 i = static_cast<i64>(index); i >= 0; i--) if (steps[i]->requests(pp_request_t::BIND_BUFFER))
{ return *steps[i];
if (steps[i]->requests(pp_request_t::BIND_BUFFER)) }
return *steps[i]; BLT_FATAL("We reached the end trying to find a previous frame buffer, unable to do so! Please ensure this in-place step has a framebuffer!");
} std::exit(1);
BLT_FATAL("We reached the end trying to find a previous frame buffer, unable to do so! Please ensure this in-place step has a framebuffer!"); }
std::exit(1);
} void pp_engine_t::render()
{
void pp_engine_t::render() screen_vao->bind();
{ for (const auto& [index, step] : blt::enumerate(steps))
screen_vao->bind(); {
for (const auto& [index, step] : blt::enumerate(steps)) if (index == 0)
{ continue;
if (index == 0) auto& previous = find_last_frame_buffer(index - 1);
continue; if (step->requests(pp_request_t::BIND_BUFFER))
auto& previous = find_last_frame_buffer(index - 1); step->getBuffer().bind();
if (step->requests(pp_request_t::BIND_BUFFER)) else
step->getBuffer().bind(); previous.getBuffer().bind();
else if (step->requests(pp_request_t::CLEAR_BUFFER))
previous.getBuffer().bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
if (step->requests(pp_request_t::CLEAR_BUFFER)) step->draw(previous.getBuffer());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); if (step->hasShader())
step->draw(previous.getBuffer()); step->getShader().bind();
if (step->hasShader()) render_quad();
step->getShader().bind(); step->post_draw(previous.getBuffer());
render_quad(); }
step->post_draw(previous.getBuffer()); glBindTexture(GL_TEXTURE_2D, 0);
} frame_buffer_t::unbind();
glBindTexture(GL_TEXTURE_2D, 0); #ifndef __EMSCRIPTEN__
frame_buffer_t::unbind();
#ifndef __EMSCRIPTEN__
steps.back()->getBuffer().blitToScreen(getWindowWidth(), getWindowHeight()); steps.back()->getBuffer().blitToScreen(getWindowWidth(), getWindowHeight());
#endif #endif
} }
void pp_engine_t::cleanup() void pp_engine_t::cleanup()
{ {
screen_vao = nullptr; screen_vao.reset();
for (auto& v : steps) for (auto& v : steps)
v = nullptr; v = nullptr;
steps.clear(); steps.clear();
} }
std::unique_ptr<shader_t> pp_engine_t::createShader(std::string_view fragment, std::optional<std::reference_wrapper<template_engine_t>> engine) std::unique_ptr<shader_t> pp_engine_t::createShader(std::string_view fragment, std::optional<std::reference_wrapper<template_engine_t>> engine)
{ {
std::unique_ptr<shader_t> shader; std::unique_ptr<shader_t> shader;
if (engine) if (engine)
{ {
shader = shader_t::make_unique(engine, shader_postprocess_vert, std::string(fragment)); shader = shader_t::make_unique(engine, shader_postprocess_vert, std::string(fragment));
} else } else
{ {
template_engine_t templateEngine; template_engine_t templateEngine;
templateEngine.set("LAYOUT_STRING", ""); templateEngine.set("LAYOUT_STRING", "");
shader = shader_t::make_unique(templateEngine, shader_postprocess_vert, std::string(fragment)); shader = shader_t::make_unique(templateEngine, shader_postprocess_vert, std::string(fragment));
} }
shader->bindAttribute(0, "vertex"); shader->bindAttribute(0, "vertex");
shader->bindAttribute(1, "uv_in"); shader->bindAttribute(1, "uv_in");
return shader; return shader;
} }
void pp_engine_t::bind() void pp_engine_t::bind()
{ {
steps.front()->getBuffer().bind(); steps.front()->getBuffer().bind();
steps.front()->draw(); steps.front()->draw();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
} }
void pp_engine_t::render_quad() void pp_engine_t::render_quad()
{ {
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
} }
void pp_in_place_t::create() void pp_in_place_t::create()
{ {
template_engine_t engine; template_engine_t engine;
engine.set("LAYOUT_STRING", "layout (location = ${IF(LAYOUT_LOCATION) { LAYOUT_LOCATION } ELSE { ~DISCARD }}) "); 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))); 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); shader_pass = pp_engine_t::createShader(shader_pp_screen_frag, engine);
draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight()); draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight());
} }
void pp_in_place_t::post_draw(frame_buffer_t& previous) void pp_in_place_t::post_draw(frame_buffer_t& previous)
{ {
// draw_buffer.blitTexture(previous, 0, 0, 0, 0, GL_NEAREST, from, to); // draw_buffer.blitTexture(previous, 0, 0, 0, 0, GL_NEAREST, from, to);
handle_errors(); handle_errors();
previous.bind(); previous.bind();
GLenum buf[32]; GLenum buf[32];
auto to_val = static_cast<GLenum>(to); auto to_val = static_cast<GLenum>(to);
auto size = to_val - GL_COLOR_ATTACHMENT0; auto size = to_val - GL_COLOR_ATTACHMENT0;
for (GLenum i = 0; i < size; i++) for (GLenum i = 0; i < size; i++)
buf[i] = GL_NONE; buf[i] = GL_NONE;
buf[size] = to_val; buf[size] = to_val;
glDrawBuffers(static_cast<int>(size) + 1, buf); glDrawBuffers(static_cast<int>(size) + 1, buf);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
shader_pass->bind(); shader_pass->bind();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
draw_buffer.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); draw_buffer.getTexture(frame_buffer_t::attachment_t::COLOR0).bind();
pp_engine_t::render_quad(); pp_engine_t::render_quad();
} }
void pp_in_place_t::draw(frame_buffer_t& previous) void pp_in_place_t::draw(frame_buffer_t& previous)
{ {
draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight());
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
previous.getTexture(from).bind(); previous.getTexture(from).bind();
draw_buffer.bind(); draw_buffer.bind();
GLenum buf[]{static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR0)}; GLenum buf[]{static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR0)};
glDrawBuffers(1, buf); glDrawBuffers(1, buf);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
} }
void pp_to_screen_step_t::create() void pp_to_screen_step_t::create()
{ {
shader = pp_engine_t::createShader(shader_pp_screen_frag); shader = pp_engine_t::createShader(shader_pp_screen_frag);
} }
void pp_to_screen_step_t::draw(frame_buffer_t& previous) void pp_to_screen_step_t::draw(frame_buffer_t& previous)
{ {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
previous.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); previous.getTexture(frame_buffer_t::attachment_t::COLOR0).bind();
GLenum buf[]{GL_BACK}; GLenum buf[]{GL_BACK};
glDrawBuffers(1, buf); glDrawBuffers(1, buf);
} }
void pp_render_target_t::create() void pp_render_target_t::create()
{ {
draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight()); draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight());
} }
void pp_render_target_t::draw() void pp_render_target_t::draw()
{ {
draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight());
GLenum buf[]{static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR0)}; GLenum buf[]{static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR0)};
glDrawBuffers(1, buf); glDrawBuffers(1, buf);
} }
void pp_outline_target_t::create() void pp_outline_target_t::create()
{ {
draw_buffer.create(); draw_buffer.create();
draw_buffer.bind(); draw_buffer.bind();
auto* texture = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8); auto* texture = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8);
draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0); draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0);
auto* mask = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8); auto* mask = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8);
draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1); draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1);
render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, getWindowWidth(), getWindowHeight()); render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, getWindowWidth(), getWindowHeight());
draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL); draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL);
if (!frame_buffer_t::validate()) if (!frame_buffer_t::validate())
BLT_ERROR("Failed to create render texture framebuffer!"); BLT_ERROR("Failed to create render texture framebuffer!");
frame_buffer_t::unbind(); frame_buffer_t::unbind();
} }
void pp_outline_target_t::draw() void pp_outline_target_t::draw()
{ {
draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight());
const GLenum buffers[]{static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR0), static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR1)}; const GLenum buffers[]{static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR0), static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR1)};
glDrawBuffers(2, buffers); glDrawBuffers(2, buffers);
} }
void pp_outline_step_t::create() void pp_outline_step_t::create()
{ {
draw_buffer = frame_buffer_t::make_render_texture(getWindowHeight(), getWindowHeight()); draw_buffer = frame_buffer_t::make_render_texture(getWindowHeight(), getWindowHeight());
shader = pp_engine_t::createShader(shader_pp_outline_step_frag); shader = pp_engine_t::createShader(shader_pp_outline_step_frag);
shader->setInt("albedo", 0); shader->setInt("albedo", 0);
shader->setInt("mask", 1); shader->setInt("mask", 1);
} }
void pp_outline_step_t::draw(frame_buffer_t& previous) void pp_outline_step_t::draw(frame_buffer_t& previous)
{ {
draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight());
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
previous.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); previous.getTexture(frame_buffer_t::attachment_t::COLOR0).bind();
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
previous.getTexture(frame_buffer_t::attachment_t::COLOR1).bind(); previous.getTexture(frame_buffer_t::attachment_t::COLOR1).bind();
shader->bind(); shader->bind();
//auto v = vec2(getWindowWidth(), getWindowHeight()) * (1.0 / blt::make_vec2(manager.getScale2D())); //auto v = vec2(getWindowWidth(), getWindowHeight()) * (1.0 / blt::make_vec2(manager.getScale2D()));
//BLT_TRACE_STREAM << v << '\n'; //BLT_TRACE_STREAM << v << '\n';
//shader->setVec2("viewportSize", static_cast<f32>(v.x()), static_cast<f32>(v.y())); //shader->setVec2("viewportSize", static_cast<f32>(v.x()), static_cast<f32>(v.y()));
GLenum buf[]{static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR0)}; GLenum buf[]{static_cast<GLenum>(frame_buffer_t::attachment_t::COLOR0)};
glDrawBuffers(1, buf); glDrawBuffers(1, buf);
} }
void pp_blur_step_inplace_t::create() void pp_blur_step_inplace_t::create()
{ {
pp_in_place_t::create(); pp_in_place_t::create();
shader = pp_engine_t::createShader(shader_gaussian_blur_frag); shader = pp_engine_t::createShader(shader_gaussian_blur_frag);
} }
void pp_blur_step_inplace_t::draw(frame_buffer_t& previous) void pp_blur_step_inplace_t::draw(frame_buffer_t& previous)
{ {
pp_in_place_t::draw(previous); pp_in_place_t::draw(previous);
shader->bind(); shader->bind();
//auto v = vec2(getWindowWidth(), getWindowHeight()) * (1.0 / blt::make_vec2(manager.getScale2D())); //auto v = vec2(getWindowWidth(), getWindowHeight()) * (1.0 / blt::make_vec2(manager.getScale2D()));
auto v = vec2(getWindowWidth(), getWindowHeight()); auto v = vec2(getWindowWidth(), getWindowHeight());
shader->setVec4i("size", {static_cast<i32>(v.x()), static_cast<i32>(v.y()), x_blur, y_blur}); shader->setVec4i("size", {static_cast<i32>(v.x()), static_cast<i32>(v.y()), x_blur, y_blur});
} }
void pp_multiplier_step_inplace_t::create() void pp_multiplier_step_inplace_t::create()
{ {
pp_in_place_t::create(); pp_in_place_t::create();
shader = pp_engine_t::createShader(shader_multiplier_frag); shader = pp_engine_t::createShader(shader_multiplier_frag);
} }
void pp_multiplier_step_inplace_t::draw(frame_buffer_t& previous) void pp_multiplier_step_inplace_t::draw(frame_buffer_t& previous)
{ {
pp_in_place_t::draw(previous); pp_in_place_t::draw(previous);
shader->bind(); shader->bind();
shader->setVec4("multiplier", multiplier); shader->setVec4("multiplier", multiplier);
} }
void pp_overlay_blur_step_t::create() void pp_overlay_blur_step_t::create()
{ {
pp_in_place_t::create(); pp_in_place_t::create();
shader = pp_engine_t::createShader(shader_overlay_blur_frag); shader = pp_engine_t::createShader(shader_overlay_blur_frag);
} }
void pp_overlay_blur_step_t::draw(frame_buffer_t& previous) void pp_overlay_blur_step_t::draw(frame_buffer_t& previous)
{ {
pp_in_place_t::draw(previous); pp_in_place_t::draw(previous);
shader->bind(); shader->bind();
auto v = vec2(getWindowWidth(), getWindowHeight()); auto v = vec2(getWindowWidth(), getWindowHeight());
shader->setVec4i("size", {static_cast<i32>(v.x()), static_cast<i32>(v.y()), x_blur, y_blur}); shader->setVec4i("size", {static_cast<i32>(v.x()), static_cast<i32>(v.y()), x_blur, y_blur});
} }
void pp_mouse_highlight_step_t::create() void pp_mouse_highlight_step_t::create()
{ {
pp_in_place_t::create(); pp_in_place_t::create();
shader = pp_engine_t::createShader(shader_highlight_frag); shader = pp_engine_t::createShader(shader_highlight_frag);
} }
void pp_mouse_highlight_step_t::draw(frame_buffer_t& previous) void pp_mouse_highlight_step_t::draw(frame_buffer_t& previous)
{ {
pp_in_place_t::draw(previous); pp_in_place_t::draw(previous);
shader->bind(); shader->bind();
auto v = vec2(getWindowWidth(), getWindowHeight()); auto v = vec2(getWindowWidth(), getWindowHeight());
shader->setVec4("mousePos", blt::make_vec4(blt::vec2{getMouseX(), v.y() - getMouseY()})); shader->setVec4("mousePos", blt::make_vec4(blt::vec2{getMouseX(), v.y() - getMouseY()}));
shader->setVec4i("size", {static_cast<i32>(v.x()), static_cast<i32>(v.y()), 4, 4}); shader->setVec4i("size", {static_cast<i32>(v.x()), static_cast<i32>(v.y()), 4, 4});
} }
} }