2d renderer code cleanup

main
Brett 2024-05-03 16:25:02 -04:00
parent 3588dcbd49
commit e25dad380c
13 changed files with 472 additions and 449 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
set(BLT_GRAPHICS_VERSION 0.12.5) set(BLT_GRAPHICS_VERSION 0.13.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

@ -27,79 +27,121 @@
#include <blt/math/vectors.h> #include <blt/math/vectors.h>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include <memory>
#include <map>
#include <variant>
namespace blt::gfx namespace blt::gfx
{ {
struct rectangle2d_t struct rectangle2d_t
{ {
blt::vec2f pos, size; vec2f pos, size;
blt::f32 rotation = 0; f32 rotation = 0;
rectangle2d_t(blt::f32 x, blt::f32 y, blt::f32 width, blt::f32 height, blt::f32 rotation): pos(x, y), size(width, height), rotation(rotation) rectangle2d_t(const f32 x, const f32 y, const f32 width, const f32 height, const f32 rotation): pos(x, y), size(width, height),
rotation(rotation)
{} {}
rectangle2d_t(blt::f32 x, blt::f32 y, blt::f32 width, blt::f32 height): pos(x, y), size(width, height) rectangle2d_t(const f32 x, const f32 y, const f32 width, const f32 height): pos(x, y), size(width, height)
{} {}
rectangle2d_t(blt::vec2f pos, blt::vec2f size, blt::f32 rotation): pos(pos), size(size), rotation(rotation) rectangle2d_t(const vec2f pos, const vec2f size, const f32 rotation): pos(pos), size(size), rotation(rotation)
{} {}
rectangle2d_t(blt::vec2f pos, blt::vec2f size): pos(pos), size(size) rectangle2d_t(const vec2f pos, const vec2f size): pos(pos), size(size)
{} {}
}; };
struct line2d_t struct line2d_t
{ {
blt::vec2f p1; vec2f p1;
blt::vec2f p2; vec2f p2;
blt::f32 thickness = 1; f32 thickness = 1;
line2d_t(blt::f32 px1, blt::f32 py1, blt::f32 px2, blt::f32 py2): p1(px1, py1), p2(px2, py2) line2d_t(const f32 px1, const f32 py1, const f32 px2, const f32 py2): p1(px1, py1), p2(px2, py2)
{} {}
line2d_t(blt::vec2f p1, blt::vec2f p2): p1(p1), p2(p2) line2d_t(const vec2f p1, const vec2f p2): p1(p1), p2(p2)
{} {}
line2d_t(blt::f32 px1, blt::f32 py1, blt::f32 px2, blt::f32 py2, blt::f32 thickness): p1(px1, py1), p2(px2, py2), thickness(thickness) line2d_t(const f32 px1, const f32 py1, const f32 px2, const f32 py2, const f32 thickness): p1(px1, py1), p2(px2, py2), thickness(thickness)
{} {}
line2d_t(blt::vec2f p1, blt::vec2f p2, blt::f32 thickness): p1(p1), p2(p2), thickness(thickness) line2d_t(const vec2f p1, const vec2f p2, const f32 thickness): p1(p1), p2(p2), thickness(thickness)
{} {}
}; };
struct point2d_t struct point2d_t
{ {
blt::vec2f pos; vec2f pos;
float scale = 1; float scale = 1;
point2d_t(float x, float y, float scale): pos(x, y), scale(scale) point2d_t(const float x, const float y, const float scale): pos(x, y), scale(scale)
{} {}
point2d_t(float x, float y): pos(x, y) point2d_t(const float x, const float y): pos(x, y)
{} {}
point2d_t(vec2f pos, float scale): pos(pos), scale(scale) point2d_t(const vec2f pos, const float scale): pos(pos), scale(scale)
{} {}
explicit point2d_t(vec2f pos): pos(pos) explicit point2d_t(const vec2f pos): pos(pos)
{} {}
}; };
struct draw_state struct render_info_t
{ {
// texture to use private:
std::string texture_name; constexpr static color4 disabled = color4(0, 0, 0, 0);
// color to use constexpr static vec4 empty{0, 0, 0, 1};
blt::color4 color; constexpr static vec4 full{1, 1, 1, 1};
// how much to blend the texture into the color? note blending is always additive!
blt::color4 blend; render_info_t(const std::string_view texture, color4 color, color4 blend): texture_name(texture), color(color), blend(blend)
// should we outline this object? {}
bool outline;
// what color should we outline with? public:
blt::color4 outline_color; // texture to use
std::string texture_name;
// color to use
color4 color;
// how much to blend the texture into the color? note blending is always additive!
color4 blend;
// should we outline this object?
bool outline = false;
// what color should we outline with?
color4 outline_color;
render_info_t() = default;
static render_info_t make_info(const std::string_view texture, const color4 outline = disabled)
{
render_info_t info{texture, empty, full};
if (outline != disabled)
{
info.outline = true;
info.outline_color = outline;
}
return info;
}
static render_info_t make_info(const color4 color, const color4 outline = disabled)
{
render_info_t info{"", color, empty};
if (outline != disabled)
{
info.outline = true;
info.outline_color = outline;
}
return info;
}
static render_info_t make_info(const std::string_view texture, const color4 color, const color4 blend, const color4 outline = disabled)
{
render_info_t info{texture, color, blend};
if (outline != disabled)
{
info.outline = true;
info.outline_color = outline;
}
return info;
}
}; };
class batch_renderer_2d class batch_renderer_2d
@ -107,143 +149,125 @@ namespace blt::gfx
private: private:
struct vec_hash struct vec_hash
{ {
std::size_t operator()(const blt::vec4& key) const std::size_t operator()(const vec4& key) const
{ {
using namespace blt::mem; using namespace blt::mem;
return type_cast<blt::i32>(key.x()) ^ type_cast<blt::i32>(key.y()) ^ type_cast<blt::i32>(key.y()) ^ type_cast<blt::i32>(key.z()); return type_cast<i32>(key.x()) ^ type_cast<i32>(key.y()) ^ type_cast<i32>(key.y()) ^ type_cast<i32>(key.z());
} }
}; };
template<typename T> template<typename T>
struct render_object_t struct render_object_t
{ {
blt::f32 z_index; f32 z_index;
T obj; T obj;
render_object_t(float z_index, T obj): z_index(z_index), obj(obj) render_object_t(const float z_index, const T obj): z_index(z_index), obj(obj)
{} {}
}; };
using rectangle2d_obj_t = render_object_t<rectangle2d_t>; using rectangle2d_obj_t = render_object_t<rectangle2d_t>;
using point2d_obj_t = render_object_t<point2d_t>; using point2d_obj_t = render_object_t<point2d_t>;
using line2d_obj_t = render_object_t<line2d_t>; using line2d_obj_t = render_object_t<line2d_t>;
template<typename T>
using object_container = hashmap_t<std::string, std::vector<std::pair<render_info_t, T>>>;
private: private:
vertex_array* square_vao = nullptr; vertex_array* square_vao = nullptr;
vertex_array* line_vao = nullptr; vertex_array* line_vao = nullptr;
shader_t* square_shader = nullptr; shader_t* square_shader = nullptr;
shader_t* point_shader = nullptr; shader_t* point_shader = nullptr;
resource_manager& resources; resource_manager& resources;
// texture -> color -> blend factor -> list of rectangles // texture name -> draw info
blt::hashmap_t<std::string, blt::hashmap_t<blt::vec4, blt::hashmap_t<blt::vec4, std::vector<rectangle2d_obj_t>, vec_hash>, vec_hash>> complex_rectangles; struct
blt::hashmap_t<std::string, blt::hashmap_t<blt::vec4, blt::hashmap_t<blt::vec4, std::vector<point2d_obj_t>, vec_hash>, vec_hash>> complex_points; {
blt::hashmap_t<std::string, blt::hashmap_t<blt::vec4, blt::hashmap_t<blt::vec4, std::vector<line2d_obj_t>, vec_hash>, vec_hash>> complex_lines; object_container<rectangle2d_obj_t> complex_rectangles;
size_t draw_count_ = 0; object_container<point2d_obj_t> complex_points;
object_container<line2d_obj_t> complex_lines;
size_t draw_count = 0;
f32 z_min = std::numeric_limits<f32>::max();
f32 z_max = std::numeric_limits<f32>::min();
} draw;
template<typename E>
static void insert_obj(object_container<E>& map, const render_info_t& info, const E& obj)
{
map[info.texture_name].emplace_back(info, obj);
}
// called at the end of the render function
void render_reset();
// called before invocation of draw_objects
void pre_reset();
// called after draw_objects()
void post_reset();
void draw_objects();
inline void update_z_index(f32 z_index)
{
draw.z_min = std::min(draw.z_min, -z_index);
draw.z_max = std::max(draw.z_max, -z_index);
}
public: public:
explicit batch_renderer_2d(resource_manager& resources): resources(resources) explicit batch_renderer_2d(resource_manager& resources): resources(resources)
{} {}
void create(); void create();
inline void drawRectangleInternal(std::string_view texture, const rectangle2d_t& rectangle, blt::f32 z_index = 0) void drawRectangleInternal(std::string_view texture, const rectangle2d_t& rectangle, f32 z_index = 0);
{
const static blt::vec4 empty{0, 0, 0, 1};
const static blt::vec4 full{1, 1, 1, 1};
complex_rectangles[texture][empty][full].emplace_back(-z_index, rectangle);
}
inline void drawRectangleInternal(const blt::vec4& color, const rectangle2d_t& rectangle, blt::f32 z_index = 0) void drawRectangleInternal(const vec4& color, const rectangle2d_t& rectangle, f32 z_index = 0);
{
const static blt::vec4 empty{0, 0, 0, 0};
complex_rectangles[""][color][empty].emplace_back(-z_index, rectangle);
}
inline void drawRectangleInternal(const draw_state& draw_info, const rectangle2d_t& rectangle, blt::f32 z_index = 0) void drawRectangleInternal(const render_info_t& draw_info, const rectangle2d_t& rectangle, f32 z_index = 0);
{
complex_rectangles[draw_info.texture_name][draw_info.color][draw_info.blend].emplace_back(-z_index, rectangle);
}
inline void drawLineInternal(std::string_view texture, const line2d_t& line, blt::f32 z_index = 0) void drawLineInternal(std::string_view texture, const line2d_t& line, f32 z_index = 0);
{
const static blt::vec4 empty{0, 0, 0, 1};
const static blt::vec4 full{1, 1, 1, 1};
complex_lines[texture][empty][full].emplace_back(-z_index, line);
}
inline void drawLineInternal(const blt::vec4& color, const line2d_t& line, blt::f32 z_index = 0) void drawLineInternal(const vec4& color, const line2d_t& line, f32 z_index = 0);
{
const static blt::vec4 empty{0, 0, 0, 0};
complex_lines[""][color][empty].emplace_back(-z_index, line);
}
inline void drawLineInternal(const draw_state& draw_info, const line2d_t& line, blt::f32 z_index = 0) void drawLineInternal(const render_info_t& draw_info, const line2d_t& line, f32 z_index = 0);
{
complex_lines[draw_info.texture_name][draw_info.color][draw_info.blend].emplace_back(-z_index, line);
}
inline void drawPointInternal(std::string_view texture, const point2d_t& point, blt::f32 z_index = 0) void drawPointInternal(std::string_view texture, const point2d_t& point, f32 z_index = 0);
{
const static blt::vec4 empty{0, 0, 0, 1};
const static blt::vec4 full{1, 1, 1, 1};
complex_points[texture][empty][full].emplace_back(-z_index, point);
}
inline void drawPointInternal(const blt::vec4& color, const point2d_t& point, blt::f32 z_index = 0) void drawPointInternal(const vec4& color, const point2d_t& point, f32 z_index = 0);
{
const static blt::vec4 empty{0, 0, 0, 0};
complex_points[""][color][empty].emplace_back(-z_index, point);
}
inline void drawPointInternal(const draw_state& draw_info, const point2d_t& point, blt::f32 z_index = 0) void drawPointInternal(const render_info_t& draw_info, const point2d_t& point, f32 z_index = 0);
{
complex_points[draw_info.texture_name][draw_info.color][draw_info.blend].emplace_back(-z_index, point);
}
template<typename T, typename... P> template<typename T, typename... P>
inline void drawRectangle(const T& render_info, P... p) void drawRectangle(const T& render_info, P... p)
{ { drawRectangleInternal(render_info, {p...}); }
drawRectangleInternal(render_info, {p...});
}
template<typename T, typename... P> template<typename T, typename... P>
inline void drawPoint(const T& render_info, P... p) void drawPoint(const T& render_info, P... p)
{ { drawPointInternal(render_info, {p...}); }
drawPointInternal(render_info, {p...});
}
template<typename T, typename... P> template<typename T, typename... P>
inline void drawLine(const T& render_info, P... p) void drawLine(const T& render_info, P... p)
{ { drawLineInternal(render_info, {p...}); }
drawLineInternal(render_info, {p...});
}
template<typename T, typename... P> template<typename T, typename... P>
inline void drawRectangle(const T& render_info, blt::f32 z_index, P... p) void drawRectangle(const T& render_info, f32 z_index, P... p)
{ { drawRectangleInternal(render_info, {p...}, z_index); }
drawRectangleInternal(render_info, {p...}, z_index);
}
template<typename T, typename... P> template<typename T, typename... P>
inline void drawPoint(const T& render_info, blt::f32 z_index, P... p) void drawPoint(const T& render_info, f32 z_index, P... p)
{ { drawPointInternal(render_info, {p...}, z_index); }
drawPointInternal(render_info, {p...}, z_index);
}
template<typename T, typename... P> template<typename T, typename... P>
inline void drawLine(const T& render_info, blt::f32 z_index, P... p) void drawLine(const T& render_info, f32 z_index, P... p)
{ { drawLineInternal(render_info, {p...}, z_index); }
drawLineInternal(render_info, {p...}, z_index);
}
void render(bool transparency = true); void render(bool transparency = true);
void cleanup(); void cleanup();
[[nodiscard]] inline size_t draw_count() const [[nodiscard]] size_t draw_count() const
{ { return draw.draw_count; }
return draw_count_;
}
}; };
} }
#endif //BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H #endif //BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H

View File

@ -20,7 +20,6 @@
#define BLT_WITH_GRAPHICS_SHADER_H #define BLT_WITH_GRAPHICS_SHADER_H
#include <blt/gfx/gl_includes.h> #include <blt/gfx/gl_includes.h>
#include <vector>
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include <blt/math/math.h> #include <blt/math/math.h>
@ -33,6 +32,7 @@ namespace blt::gfx
GLuint uboID = 0; GLuint uboID = 0;
size_t size_; size_t size_;
GLuint location_; GLuint location_;
public: public:
explicit uniform_buffer(size_t size, GLuint location = 0); explicit uniform_buffer(size_t size, GLuint location = 0);
@ -59,29 +59,21 @@ namespace blt::gfx
~uniform_buffer(); ~uniform_buffer();
[[nodiscard]] inline size_t size() const [[nodiscard]] inline size_t size() const { return size_; }
{
return size_;
}
[[nodiscard]] inline GLuint location() const [[nodiscard]] inline GLuint location() const { return location_; }
{
return location_;
}
}; };
class shader_base_t class shader_base_t
{ {
friend uniform_buffer; friend uniform_buffer;
protected: protected:
struct IntDefaultedToMinusOne struct IntDefaultedToMinusOne
{ {
GLint i = -1; GLint i = -1;
inline explicit operator bool() const inline explicit operator bool() const { return i != -1; }
{
return i != -1;
}
}; };
std::unordered_map<std::string, IntDefaultedToMinusOne> uniformVars; std::unordered_map<std::string, IntDefaultedToMinusOne> uniformVars;
@ -90,13 +82,19 @@ namespace blt::gfx
IntDefaultedToMinusOne getUniformLocation(const std::string& name); IntDefaultedToMinusOne getUniformLocation(const std::string& name);
public: public:
inline const shader_base_t& bind() const const shader_base_t& bind() const
{ {
glUseProgram(programID); glUseProgram(programID);
return *this; return *this;
} }
inline shader_base_t& unbind() shader_base_t& bind()
{
glUseProgram(programID);
return *this;
}
shader_base_t& unbind()
{ {
glUseProgram(0); glUseProgram(0);
return *this; return *this;
@ -109,6 +107,7 @@ namespace blt::gfx
shader_base_t& setFloat(const std::string& name, float value); shader_base_t& setFloat(const std::string& name, float value);
shader_base_t& setMatrix(const std::string& name, blt::mat4x4& matrix); shader_base_t& setMatrix(const std::string& name, blt::mat4x4& matrix);
// poor solution: TODO // poor solution: TODO
shader_base_t& setMatrix(const std::string& name, blt::mat4x4&& matrix); shader_base_t& setMatrix(const std::string& name, blt::mat4x4&& matrix);
@ -132,10 +131,11 @@ namespace blt::gfx
{ {
private: private:
GLuint shaderID = 0; GLuint shaderID = 0;
public: public:
explicit compute_shader_t(const std::string& shader_source, bool loadAsString = true); explicit compute_shader_t(const std::string& shader_source, bool loadAsString = true);
inline void execute(int x, int y, int z) const void execute(const int x, const int y, const int z) const
{ {
bind(); bind();
glDispatchCompute(x, y, z); glDispatchCompute(x, y, z);
@ -153,6 +153,7 @@ namespace blt::gfx
static unsigned int createShader(const std::string& source, int type); static unsigned int createShader(const std::string& source, int type);
static std::string loadShader(std::string_view file); static std::string loadShader(std::string_view file);
public: public:
/** /**
* Creates a shader * Creates a shader

@ -1 +1 @@
Subproject commit 3f0ea887cd2923cb2cf390a4929ffce452301670 Subproject commit 9b86278a2982d80fbac6f87045a182088e07afbe

View File

@ -16,31 +16,29 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <blt/gfx/renderer/batch_2d_renderer.h> #include <blt/gfx/renderer/batch_2d_renderer.h>
#include <blt/gfx/renderer/2d_textured.vert> #include <blt/gfx/renderer/shaders/2d_textured.vert>
#include <blt/gfx/renderer/2d_line.vert> #include <blt/gfx/renderer/shaders/2d_textured.frag>
#include <blt/gfx/renderer/2d_textured.frag> #include <blt/gfx/renderer/shaders/2d_textured_circle.frag>
#include <blt/gfx/renderer/2d_textured_circle.frag>
#include <blt/gfx/renderer/2d_line.frag>
// https://stackoverflow.com/questions/60440682/drawing-a-line-in-modern-opengl // https://stackoverflow.com/questions/60440682/drawing-a-line-in-modern-opengl
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.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom 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, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top 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, 3, // first triangle
1, 2, 3 // second 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.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom 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, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left -0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left
}; };
// 0, 1 (top right) // 0, 1 (top right)
@ -50,7 +48,6 @@ float line_vertices[20] = {
namespace blt::gfx namespace blt::gfx
{ {
void batch_renderer_2d::create() void batch_renderer_2d::create()
{ {
{ {
@ -64,7 +61,7 @@ namespace blt::gfx
indices_vbo.allocate(sizeof(square_indices), square_indices); indices_vbo.allocate(sizeof(square_indices), square_indices);
square_vao = new vertex_array(); square_vao = new vertex_array();
auto tb = square_vao->bindVBO(vertices_vbo, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); const auto tb = square_vao->bindVBO(vertices_vbo, 0, 3, GL_FLOAT, 5 * sizeof(float), 0);
square_vao->bindVBO(tb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); square_vao->bindVBO(tb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float));
square_vao->bindElement(indices_vbo); square_vao->bindElement(indices_vbo);
} }
@ -93,6 +90,60 @@ namespace blt::gfx
point_shader->bindAttribute(1, "uv_in"); point_shader->bindAttribute(1, "uv_in");
} }
void batch_renderer_2d::drawRectangleInternal(const std::string_view texture, const rectangle2d_t& rectangle, const f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_rectangles, render_info_t::make_info(texture), {-z_index, rectangle});
}
void batch_renderer_2d::drawRectangleInternal(const vec4& color, const rectangle2d_t& rectangle, const f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_rectangles, render_info_t::make_info(color), {-z_index, rectangle});
}
void batch_renderer_2d::drawRectangleInternal(const render_info_t& draw_info, const rectangle2d_t& rectangle, const f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_rectangles, draw_info, {-z_index, rectangle});
}
void batch_renderer_2d::drawLineInternal(const std::string_view texture, const line2d_t& line, const f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_lines, render_info_t::make_info(texture), {-z_index, line});
}
void batch_renderer_2d::drawLineInternal(const vec4& color, const line2d_t& line, const f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_lines, render_info_t::make_info(color), {-z_index, line});
}
void batch_renderer_2d::drawLineInternal(const render_info_t& draw_info, const line2d_t& line, const f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_lines, draw_info, {-z_index, line});
}
void batch_renderer_2d::drawPointInternal(const std::string_view texture, const point2d_t& point, const f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_points, render_info_t::make_info(texture), {-z_index, point});
}
void batch_renderer_2d::drawPointInternal(const vec4& color, const point2d_t& point, f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_points, render_info_t::make_info(color), {-z_index, point});
}
void batch_renderer_2d::drawPointInternal(const render_info_t& draw_info, const point2d_t& point, f32 z_index)
{
update_z_index(z_index);
insert_obj(draw.complex_points, draw_info, {-z_index, point});
}
void batch_renderer_2d::cleanup() void batch_renderer_2d::cleanup()
{ {
delete square_vao; delete square_vao;
@ -101,7 +152,7 @@ namespace blt::gfx
} }
template<typename T> template<typename T>
void find_min_and_max(T& container, blt::f32& min, blt::f32& max) void find_min_and_max(T& container, f32& min, f32& max)
{ {
for (auto& textures : container) for (auto& textures : container)
{ {
@ -119,7 +170,7 @@ namespace blt::gfx
} }
} }
void batch_renderer_2d::render(bool transparency) void batch_renderer_2d::render(const bool transparency)
{ {
if (transparency) if (transparency)
{ {
@ -127,142 +178,143 @@ namespace blt::gfx
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} }
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
draw_count_ = 0;
square_shader->bind();
square_vao->bind();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
// annoying draw_objects();
blt::f32 min = std::numeric_limits<blt::f32>::max();
blt::f32 max = std::numeric_limits<blt::f32>::min();
find_min_and_max(complex_rectangles, min, max);
find_min_and_max(complex_points, min, max);
find_min_and_max(complex_lines, min, max);
blt::f32 denominator = 1.0f / (max - min);
for (auto& textures : complex_rectangles)
{
// resource manager handles the check for empty string
if (auto val = resources.get(textures.first))
val.value()->bind();
for (auto& colors : textures.second)
{
square_shader->setVec4("color", colors.first);
for (auto& blend_factors : colors.second)
{
square_shader->setVec4("use_texture", blend_factors.first);
for (auto& rect_obj : blend_factors.second)
{
auto& rect = rect_obj.obj;
blt::mat4x4 model;
model.translate(rect.pos.x(), rect.pos.y(), 0.0f);
model.scale(rect.size.x(), rect.size.y(), 1);
if (rect.rotation != 0)
model.rotateZ(blt::toRadians(rect.rotation));
square_shader->setMatrix("model", model);
square_shader->setFloat("z_index", (rect_obj.z_index - min) * denominator);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
draw_count_++;
}
blend_factors.second.clear();
}
colors.second.clear();
}
textures.second.clear();
}
point_shader->bind();
for (auto& textures : complex_points)
{
// resource manager handles the check for empty string
if (auto val = resources.get(textures.first))
val.value()->bind();
for (auto& colors : textures.second)
{
point_shader->setVec4("color", colors.first);
for (auto& blend_factors : colors.second)
{
point_shader->setVec4("use_texture", blend_factors.first);
for (auto& point_obj : blend_factors.second)
{
auto& point = point_obj.obj;
blt::mat4x4 model;
model.translate(point.pos.x(), point.pos.y(), 0.0f);
model.scale(point.scale, point.scale, 1);
point_shader->setMatrix("model", model);
point_shader->setFloat("z_index", (point_obj.z_index - min) * denominator);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
draw_count_++;
}
blend_factors.second.clear();
}
colors.second.clear();
}
textures.second.clear();
}
blt::mat4x4 model;
square_shader->bind();
square_shader->setMatrix("model", model);
line_vao->bind();
auto& buf = line_vao->getBuffer(0);
buf.bind();
for (auto& textures : complex_lines)
{
// resource manager handles the check for empty string
if (auto val = resources.get(textures.first))
val.value()->bind();
for (auto& colors : textures.second)
{
square_shader->setVec4("color", colors.first);
for (auto& blend_factors : colors.second)
{
square_shader->setVec4("use_texture", blend_factors.first);
for (auto& line_obj : blend_factors.second)
{
auto& line = line_obj.obj;
// 0, 1 (top right)
// 5, 6 (bottom right)
// 10, 11 (bottom left)
// 15, 16 (top left)
blt::vec2 dir = (line.p1 - line.p2).normalize();
blt::vec2 right = {dir.y(), -dir.x()};
blt::vec2 left = {-dir.y(), dir.x()};
auto bottom_left = line.p1 + left * line.thickness;
auto bottom_right = line.p1 + right * line.thickness;
auto top_left = line.p2 + left * line.thickness;
auto top_right = line.p2 + right * line.thickness;
line_vertices[0] = top_right.x();
line_vertices[1] = top_right.y();
line_vertices[5] = bottom_right.x();
line_vertices[6] = bottom_right.y();
line_vertices[10] = bottom_left.x();
line_vertices[11] = bottom_left.y();
line_vertices[15] = top_left.x();
line_vertices[16] = top_left.y();
buf.update(sizeof(line_vertices), line_vertices);
square_shader->setFloat("z_index", (line_obj.z_index - min) * denominator);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
draw_count_++;
}
blend_factors.second.clear();
}
colors.second.clear();
}
textures.second.clear();
}
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
if (transparency) if (transparency)
glDisable(GL_BLEND); glDisable(GL_BLEND);
render_reset();
}
void batch_renderer_2d::draw_objects()
{
pre_reset();
const f32 denominator = 1.0f / (draw.z_max - draw.z_min);
square_shader->bind();
square_vao->bind();
for (auto& [texture, objects] : draw.complex_rectangles)
{
// resource manager handles the check for empty string
if (auto val = resources.get(texture))
val.value()->bind();
for (auto& [render_info, object] : objects)
{
auto& [z_index, rect] = object;
mat4x4 model;
model.translate(rect.pos.x(), rect.pos.y(), 0.0f);
model.scale(rect.size.x(), rect.size.y(), 1);
if (rect.rotation != 0)
model.rotateZ(toRadians(rect.rotation));
square_shader->setVec4("color", render_info.color);
square_shader->setVec4("use_texture", render_info.blend);
square_shader->setFloat("z_index", (z_index - draw.z_min) * denominator);
square_shader->setMatrix("model", model);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
draw.draw_count++;
}
objects.clear();
}
mat4x4 empty_model;
square_shader->setMatrix("model", empty_model);
line_vao->bind();
auto& buf = line_vao->getBuffer(0);
buf.bind();
for (auto& [texture, objects] : draw.complex_lines)
{
// resource manager handles the check for empty string
if (auto val = resources.get(texture))
val.value()->bind();
for (auto& [render_info, object] : objects)
{
auto& [z_index, line] = object;
square_shader->setVec4("color", render_info.color);
square_shader->setVec4("use_texture", render_info.blend);
square_shader->setFloat("z_index", (z_index - draw.z_min) * denominator);
// 0, 1 (top right)
// 5, 6 (bottom right)
// 10, 11 (bottom left)
// 15, 16 (top left)
vec2 dir = (line.p1 - line.p2).normalize();
vec2 right = {dir.y(), -dir.x()};
vec2 left = {-dir.y(), dir.x()};
auto bottom_left = line.p1 + left * line.thickness;
auto bottom_right = line.p1 + right * line.thickness;
auto top_left = line.p2 + left * line.thickness;
auto top_right = line.p2 + right * line.thickness;
line_vertices[0] = top_right.x();
line_vertices[1] = top_right.y();
line_vertices[5] = bottom_right.x();
line_vertices[6] = bottom_right.y();
line_vertices[10] = bottom_left.x();
line_vertices[11] = bottom_left.y();
line_vertices[15] = top_left.x();
line_vertices[16] = top_left.y();
buf.update(sizeof(line_vertices), line_vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
draw.draw_count++;
}
objects.clear();
}
point_shader->bind();
square_vao->bind();
for (auto& [texture, objects] : draw.complex_points)
{
// resource manager handles the check for empty string
if (auto val = resources.get(texture))
val.value()->bind();
for (auto& [render_info, object] : objects)
{
auto& [z_index, point] = object;
mat4x4 model;
model.translate(point.pos.x(), point.pos.y(), 0.0f);
model.scale(point.scale, point.scale, 1);
point_shader->setVec4("color", render_info.color);
point_shader->setVec4("use_texture", render_info.blend);
point_shader->setFloat("z_index", (z_index - draw.z_min) * denominator);
point_shader->setMatrix("model", model);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
draw.draw_count++;
}
objects.clear();
}
post_reset();
}
void batch_renderer_2d::render_reset()
{
draw.z_min = std::numeric_limits<f32>::max();
draw.z_max = std::numeric_limits<f32>::min();
}
void batch_renderer_2d::pre_reset()
{
draw.draw_count = 0;
}
void batch_renderer_2d::post_reset()
{
} }
} }

View File

@ -29,7 +29,6 @@ void error_callback(int error, const char* description)
namespace blt::gfx namespace blt::gfx
{ {
struct struct
{ {
/* GLFW Window Object */ /* GLFW Window Object */
@ -95,9 +94,7 @@ namespace blt::gfx
}); });
/* Setup mouse scroll callback */ /* Setup mouse scroll callback */
glfwSetScrollCallback(window_state.window, [](GLFWwindow*, double, double s) { glfwSetScrollCallback(window_state.window, [](GLFWwindow*, double, double s) { window_state.inputManager.updateScroll(s); });
window_state.inputManager.updateScroll(s);
});
/* Setup drop input callback */ /* Setup drop input callback */
glfwSetDropCallback(window_state.window, [](GLFWwindow*, int count, const char** paths) { glfwSetDropCallback(window_state.window, [](GLFWwindow*, int count, const char** paths) {
@ -114,8 +111,8 @@ namespace blt::gfx
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style // Setup Dear ImGui style
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
@ -127,13 +124,13 @@ namespace blt::gfx
ImFontConfig config; ImFontConfig config;
config.MergeMode = true; config.MergeMode = true;
config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0}; static constexpr ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
io.Fonts->AddFontFromMemoryCompressedBase85TTF(fontAwesomeRegular_compressed_data_base85, 13.0f, &config, icon_ranges); io.Fonts->AddFontFromMemoryCompressedBase85TTF(fontAwesomeRegular_compressed_data_base85, 13.0f, &config, icon_ranges);
io.Fonts->AddFontFromMemoryCompressedTTF(fontAwesomeSolid_compressed_data, static_cast<int>(fontAwesomeSolid_compressed_size), 13.0, &config, io.Fonts->AddFontFromMemoryCompressedTTF(fontAwesomeSolid_compressed_data, static_cast<int>(fontAwesomeSolid_compressed_size), 13.0, &config,
icon_ranges); icon_ranges);
io.Fonts io.Fonts->AddFontFromMemoryCompressedTTF(fontAwesomeBrands_compressed_data, static_cast<int>(fontAwesomeBrands_compressed_size), 13.0,
->AddFontFromMemoryCompressedTTF(fontAwesomeBrands_compressed_data, static_cast<int>(fontAwesomeBrands_compressed_size), 13.0, &config, &config,
icon_ranges); icon_ranges);
//ImGui::StyleColorsLight(); //ImGui::StyleColorsLight();
@ -158,7 +155,7 @@ namespace blt::gfx
data.width = window_state.width; data.width = window_state.width;
data.height = window_state.height; data.height = window_state.height;
// TODO: user option for this // TODO: user option for this
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
/* -- Begin the next ImGUI frame -- */ /* -- Begin the next ImGUI frame -- */
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
@ -178,7 +175,7 @@ namespace blt::gfx
glfwPollEvents(); glfwPollEvents();
/* -- Update Frame Timing Information -- */ /* -- Update Frame Timing Information -- */
auto current_time = blt::system::nanoTime(); const auto current_time = system::nanoTime();
window_state.deltaTime = current_time - window_state.lastTime; window_state.deltaTime = current_time - window_state.lastTime;
window_state.lastTime = current_time; window_state.lastTime = current_time;
window_state.nanoDelta = static_cast<double>(window_state.deltaTime) / 1e9f; window_state.nanoDelta = static_cast<double>(window_state.deltaTime) / 1e9f;
@ -278,40 +275,19 @@ namespace blt::gfx
glfwTerminate(); glfwTerminate();
} }
double getMouseX() double getMouseX() { return window_state.inputManager.mouseX; }
{
return window_state.inputManager.mouseX;
}
double getMouseY() double getMouseY() { return window_state.inputManager.mouseY; }
{
return window_state.inputManager.mouseY;
}
double getMouseDX() double getMouseDX() { return window_state.inputManager.deltaX; }
{
return window_state.inputManager.deltaX;
}
double getMouseDY() double getMouseDY() { return window_state.inputManager.deltaY; }
{
return window_state.inputManager.deltaY;
}
void lockCursor() void lockCursor() { glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); }
{
glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
void unlockCursor() void unlockCursor() { glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); }
{
glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
bool isCursorLocked() bool isCursorLocked() { return glfwGetInputMode(window_state.window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; }
{
return glfwGetInputMode(window_state.window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED;
}
bool isCursorInWindow() bool isCursorInWindow()
{ {
@ -342,55 +318,25 @@ namespace blt::gfx
#endif #endif
} }
void setClipboard(const std::string& str) void setClipboard(const std::string& str) { glfwSetClipboardString(window_state.window, str.c_str()); }
{
glfwSetClipboardString(window_state.window, str.c_str());
}
std::string getClipboard() std::string getClipboard() { return glfwGetClipboardString(window_state.window); }
{
return glfwGetClipboardString(window_state.window);
}
bool isMousePressed(int button) bool isMousePressed(int button) { return window_state.inputManager.isMousePressed(button); }
{
return window_state.inputManager.isMousePressed(button);
}
bool isKeyPressed(int key) bool isKeyPressed(int key) { return window_state.inputManager.isKeyPressed(key); }
{
return window_state.inputManager.isKeyPressed(key);
}
double getFrameDeltaSeconds() double getFrameDeltaSeconds() { return window_state.nanoDelta; }
{
return window_state.nanoDelta;
}
double getFrameDeltaMilliseconds() double getFrameDeltaMilliseconds() { return window_state.millisDelta; }
{
return window_state.millisDelta;
}
std::int64_t getFrameDelta() std::int64_t getFrameDelta() { return window_state.deltaTime; }
{
return window_state.deltaTime;
}
bool mouseMovedLastFrame() bool mouseMovedLastFrame() { return window_state.inputManager.mouse_moved; }
{
return window_state.inputManager.mouse_moved;
}
bool mousePressedLastFrame() bool mousePressedLastFrame() { return window_state.inputManager.mouse_pressed; }
{
return window_state.inputManager.mouse_pressed;
}
bool keyPressedLastFrame() bool keyPressedLastFrame() { return window_state.inputManager.key_pressed; }
{
return window_state.inputManager.key_pressed;
}
window_data& window_data::setWindowSize(int32_t new_width, int32_t new_height) window_data& window_data::setWindowSize(int32_t new_width, int32_t new_height)
{ {