breaking change, new VAO/VBO. Updated renderers not tested.
parent
c28f8e6109
commit
dd3a242b41
|
@ -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})
|
||||||
|
|
|
@ -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
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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++;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
vbo.attribute_ptr(0, 3, GL_FLOAT, 5 * sizeof(float), 0);
|
||||||
|
vbo.attribute_ptr(1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
|
||||||
|
ctx.attach_vbo(std::move(indices_vbo));
|
||||||
|
}
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
addStep(std::make_unique<pp_to_screen_step_t>());
|
||||||
|
#endif
|
||||||
|
for (const auto& step : steps)
|
||||||
|
step->create();
|
||||||
|
}
|
||||||
|
|
||||||
screen_vao = std::make_unique<vertex_array_t>();
|
pp_step_t& pp_engine_t::find_last_frame_buffer(const size_t index) const
|
||||||
auto vb = vertex_array_t::make_vbo(vertices_vbo);
|
{
|
||||||
screen_vao->bindVBO(vb, 0, 3, GL_FLOAT, 5 * sizeof(float), 0);
|
for (i64 i = static_cast<i64>(index); i >= 0; i--)
|
||||||
screen_vao->bindVBO(vb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
|
{
|
||||||
screen_vao->bindElement(indices_vbo);
|
if (steps[i]->requests(pp_request_t::BIND_BUFFER))
|
||||||
}
|
return *steps[i];
|
||||||
#ifdef __EMSCRIPTEN__
|
}
|
||||||
addStep(std::make_unique<pp_to_screen_step_t>());
|
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!");
|
||||||
#endif
|
std::exit(1);
|
||||||
for (auto& step : steps)
|
}
|
||||||
step->create();
|
|
||||||
}
|
|
||||||
|
|
||||||
pp_step_t& pp_engine_t::find_last_frame_buffer(size_t index)
|
void pp_engine_t::render()
|
||||||
{
|
{
|
||||||
for (i64 i = static_cast<i64>(index); i >= 0; i--)
|
screen_vao->bind();
|
||||||
{
|
for (const auto& [index, step] : blt::enumerate(steps))
|
||||||
if (steps[i]->requests(pp_request_t::BIND_BUFFER))
|
{
|
||||||
return *steps[i];
|
if (index == 0)
|
||||||
}
|
continue;
|
||||||
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!");
|
auto& previous = find_last_frame_buffer(index - 1);
|
||||||
std::exit(1);
|
if (step->requests(pp_request_t::BIND_BUFFER))
|
||||||
}
|
step->getBuffer().bind();
|
||||||
|
else
|
||||||
void pp_engine_t::render()
|
previous.getBuffer().bind();
|
||||||
{
|
if (step->requests(pp_request_t::CLEAR_BUFFER))
|
||||||
screen_vao->bind();
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
for (const auto& [index, step] : blt::enumerate(steps))
|
step->draw(previous.getBuffer());
|
||||||
{
|
if (step->hasShader())
|
||||||
if (index == 0)
|
step->getShader().bind();
|
||||||
continue;
|
render_quad();
|
||||||
auto& previous = find_last_frame_buffer(index - 1);
|
step->post_draw(previous.getBuffer());
|
||||||
if (step->requests(pp_request_t::BIND_BUFFER))
|
}
|
||||||
step->getBuffer().bind();
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
else
|
frame_buffer_t::unbind();
|
||||||
previous.getBuffer().bind();
|
#ifndef __EMSCRIPTEN__
|
||||||
if (step->requests(pp_request_t::CLEAR_BUFFER))
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
||||||
step->draw(previous.getBuffer());
|
|
||||||
if (step->hasShader())
|
|
||||||
step->getShader().bind();
|
|
||||||
render_quad();
|
|
||||||
step->post_draw(previous.getBuffer());
|
|
||||||
}
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
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});
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue