From e25dad380cb62f8b41d51f82dd784cd9418610a7 Mon Sep 17 00:00:00 2001 From: Brett Date: Fri, 3 May 2024 16:25:02 -0400 Subject: [PATCH] 2d renderer code cleanup --- CMakeLists.txt | 2 +- include/blt/gfx/renderer/batch_2d_renderer.h | 254 +++++++------ .../gfx/renderer/{ => shaders}/2d_line.frag | 0 .../gfx/renderer/{ => shaders}/2d_line.vert | 0 .../renderer/{ => shaders}/2d_textured.frag | 0 .../renderer/{ => shaders}/2d_textured.vert | 0 .../{ => shaders}/2d_textured_circle.frag | 0 .../renderer/{ => shaders}/3d_textured.frag | 0 .../renderer/{ => shaders}/3d_textured.vert | 0 include/blt/gfx/shader.h | 103 +++--- libraries/BLT | 2 +- src/blt/gfx/renderer/batch_2d_renderer.cpp | 350 ++++++++++-------- src/blt/gfx/window.cpp | 210 ++++------- 13 files changed, 472 insertions(+), 449 deletions(-) rename include/blt/gfx/renderer/{ => shaders}/2d_line.frag (100%) rename include/blt/gfx/renderer/{ => shaders}/2d_line.vert (100%) rename include/blt/gfx/renderer/{ => shaders}/2d_textured.frag (100%) rename include/blt/gfx/renderer/{ => shaders}/2d_textured.vert (100%) rename include/blt/gfx/renderer/{ => shaders}/2d_textured_circle.frag (100%) rename include/blt/gfx/renderer/{ => shaders}/3d_textured.frag (100%) rename include/blt/gfx/renderer/{ => shaders}/3d_textured.vert (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2001379..06a4baa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ 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) project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION}) diff --git a/include/blt/gfx/renderer/batch_2d_renderer.h b/include/blt/gfx/renderer/batch_2d_renderer.h index 96c1769..f2cd403 100644 --- a/include/blt/gfx/renderer/batch_2d_renderer.h +++ b/include/blt/gfx/renderer/batch_2d_renderer.h @@ -27,79 +27,121 @@ #include #include #include -#include -#include -#include namespace blt::gfx { struct rectangle2d_t { - blt::vec2f pos, size; - blt::f32 rotation = 0; + vec2f pos, size; + 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 { - blt::vec2f p1; - blt::vec2f p2; - blt::f32 thickness = 1; + vec2f p1; + vec2f p2; + 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 { - blt::vec2f pos; + vec2f pos; 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 - std::string texture_name; - // color to use - blt::color4 color; - // how much to blend the texture into the color? note blending is always additive! - blt::color4 blend; - // should we outline this object? - bool outline; - // what color should we outline with? - blt::color4 outline_color; + private: + constexpr static color4 disabled = color4(0, 0, 0, 0); + constexpr static vec4 empty{0, 0, 0, 1}; + constexpr static vec4 full{1, 1, 1, 1}; + + render_info_t(const std::string_view texture, color4 color, color4 blend): texture_name(texture), color(color), blend(blend) + {} + + public: + // 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 @@ -107,143 +149,125 @@ namespace blt::gfx private: struct vec_hash { - std::size_t operator()(const blt::vec4& key) const + std::size_t operator()(const vec4& key) const { using namespace blt::mem; - return type_cast(key.x()) ^ type_cast(key.y()) ^ type_cast(key.y()) ^ type_cast(key.z()); + return type_cast(key.x()) ^ type_cast(key.y()) ^ type_cast(key.y()) ^ type_cast(key.z()); } }; template struct render_object_t { - blt::f32 z_index; + f32 z_index; 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; using point2d_obj_t = render_object_t; using line2d_obj_t = render_object_t; + + template + using object_container = hashmap_t>>; + private: vertex_array* square_vao = nullptr; vertex_array* line_vao = nullptr; shader_t* square_shader = nullptr; shader_t* point_shader = nullptr; resource_manager& resources; - // texture -> color -> blend factor -> list of rectangles - blt::hashmap_t, vec_hash>, vec_hash>> complex_rectangles; - blt::hashmap_t, vec_hash>, vec_hash>> complex_points; - blt::hashmap_t, vec_hash>, vec_hash>> complex_lines; - size_t draw_count_ = 0; + // texture name -> draw info + struct + { + object_container complex_rectangles; + object_container complex_points; + object_container complex_lines; + size_t draw_count = 0; + f32 z_min = std::numeric_limits::max(); + f32 z_max = std::numeric_limits::min(); + } draw; + + template + static void insert_obj(object_container& 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: explicit batch_renderer_2d(resource_manager& resources): resources(resources) {} void create(); - inline void drawRectangleInternal(std::string_view texture, const rectangle2d_t& rectangle, blt::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); - } + void drawRectangleInternal(std::string_view texture, const rectangle2d_t& rectangle, f32 z_index = 0); - inline void drawRectangleInternal(const blt::vec4& color, const rectangle2d_t& rectangle, blt::f32 z_index = 0) - { - const static blt::vec4 empty{0, 0, 0, 0}; - complex_rectangles[""][color][empty].emplace_back(-z_index, rectangle); - } + void drawRectangleInternal(const vec4& color, const rectangle2d_t& rectangle, f32 z_index = 0); - inline void drawRectangleInternal(const draw_state& draw_info, const rectangle2d_t& rectangle, blt::f32 z_index = 0) - { - complex_rectangles[draw_info.texture_name][draw_info.color][draw_info.blend].emplace_back(-z_index, rectangle); - } + void drawRectangleInternal(const render_info_t& draw_info, const rectangle2d_t& rectangle, f32 z_index = 0); - inline void drawLineInternal(std::string_view texture, const line2d_t& line, blt::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); - } + void drawLineInternal(std::string_view texture, const line2d_t& line, f32 z_index = 0); - inline void drawLineInternal(const blt::vec4& color, const line2d_t& line, blt::f32 z_index = 0) - { - const static blt::vec4 empty{0, 0, 0, 0}; - complex_lines[""][color][empty].emplace_back(-z_index, line); - } + void drawLineInternal(const vec4& color, const line2d_t& line, f32 z_index = 0); - inline void drawLineInternal(const draw_state& draw_info, const line2d_t& line, blt::f32 z_index = 0) - { - complex_lines[draw_info.texture_name][draw_info.color][draw_info.blend].emplace_back(-z_index, line); - } + void drawLineInternal(const render_info_t& draw_info, const line2d_t& line, f32 z_index = 0); - inline void drawPointInternal(std::string_view texture, const point2d_t& point, blt::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); - } + void drawPointInternal(std::string_view texture, const point2d_t& point, f32 z_index = 0); - inline void drawPointInternal(const blt::vec4& color, const point2d_t& point, blt::f32 z_index = 0) - { - const static blt::vec4 empty{0, 0, 0, 0}; - complex_points[""][color][empty].emplace_back(-z_index, point); - } + void drawPointInternal(const vec4& color, const point2d_t& point, f32 z_index = 0); - inline void drawPointInternal(const draw_state& draw_info, const point2d_t& point, blt::f32 z_index = 0) - { - complex_points[draw_info.texture_name][draw_info.color][draw_info.blend].emplace_back(-z_index, point); - } + void drawPointInternal(const render_info_t& draw_info, const point2d_t& point, f32 z_index = 0); template - inline void drawRectangle(const T& render_info, P... p) - { - drawRectangleInternal(render_info, {p...}); - } + void drawRectangle(const T& render_info, P... p) + { drawRectangleInternal(render_info, {p...}); } template - inline void drawPoint(const T& render_info, P... p) - { - drawPointInternal(render_info, {p...}); - } + void drawPoint(const T& render_info, P... p) + { drawPointInternal(render_info, {p...}); } template - inline void drawLine(const T& render_info, P... p) - { - drawLineInternal(render_info, {p...}); - } + void drawLine(const T& render_info, P... p) + { drawLineInternal(render_info, {p...}); } template - inline void drawRectangle(const T& render_info, blt::f32 z_index, P... p) - { - drawRectangleInternal(render_info, {p...}, z_index); - } + void drawRectangle(const T& render_info, f32 z_index, P... p) + { drawRectangleInternal(render_info, {p...}, z_index); } template - inline void drawPoint(const T& render_info, blt::f32 z_index, P... p) - { - drawPointInternal(render_info, {p...}, z_index); - } + void drawPoint(const T& render_info, f32 z_index, P... p) + { drawPointInternal(render_info, {p...}, z_index); } template - inline void drawLine(const T& render_info, blt::f32 z_index, P... p) - { - drawLineInternal(render_info, {p...}, z_index); - } + void drawLine(const T& render_info, f32 z_index, P... p) + { drawLineInternal(render_info, {p...}, z_index); } void render(bool transparency = true); void cleanup(); - [[nodiscard]] inline size_t draw_count() const - { - return draw_count_; - } + [[nodiscard]] size_t draw_count() const + { return draw.draw_count; } }; - } #endif //BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H diff --git a/include/blt/gfx/renderer/2d_line.frag b/include/blt/gfx/renderer/shaders/2d_line.frag similarity index 100% rename from include/blt/gfx/renderer/2d_line.frag rename to include/blt/gfx/renderer/shaders/2d_line.frag diff --git a/include/blt/gfx/renderer/2d_line.vert b/include/blt/gfx/renderer/shaders/2d_line.vert similarity index 100% rename from include/blt/gfx/renderer/2d_line.vert rename to include/blt/gfx/renderer/shaders/2d_line.vert diff --git a/include/blt/gfx/renderer/2d_textured.frag b/include/blt/gfx/renderer/shaders/2d_textured.frag similarity index 100% rename from include/blt/gfx/renderer/2d_textured.frag rename to include/blt/gfx/renderer/shaders/2d_textured.frag diff --git a/include/blt/gfx/renderer/2d_textured.vert b/include/blt/gfx/renderer/shaders/2d_textured.vert similarity index 100% rename from include/blt/gfx/renderer/2d_textured.vert rename to include/blt/gfx/renderer/shaders/2d_textured.vert diff --git a/include/blt/gfx/renderer/2d_textured_circle.frag b/include/blt/gfx/renderer/shaders/2d_textured_circle.frag similarity index 100% rename from include/blt/gfx/renderer/2d_textured_circle.frag rename to include/blt/gfx/renderer/shaders/2d_textured_circle.frag diff --git a/include/blt/gfx/renderer/3d_textured.frag b/include/blt/gfx/renderer/shaders/3d_textured.frag similarity index 100% rename from include/blt/gfx/renderer/3d_textured.frag rename to include/blt/gfx/renderer/shaders/3d_textured.frag diff --git a/include/blt/gfx/renderer/3d_textured.vert b/include/blt/gfx/renderer/shaders/3d_textured.vert similarity index 100% rename from include/blt/gfx/renderer/3d_textured.vert rename to include/blt/gfx/renderer/shaders/3d_textured.vert diff --git a/include/blt/gfx/shader.h b/include/blt/gfx/shader.h index 1cbfa46..37a7ead 100644 --- a/include/blt/gfx/shader.h +++ b/include/blt/gfx/shader.h @@ -20,7 +20,6 @@ #define BLT_WITH_GRAPHICS_SHADER_H #include -#include #include #include #include @@ -33,98 +32,98 @@ namespace blt::gfx GLuint uboID = 0; size_t size_; GLuint location_; + public: explicit uniform_buffer(size_t size, GLuint location = 0); - + uniform_buffer(void* data, size_t size, GLuint location = 0); - + /** * Resizes the internal UBO * @param newSize new size for the UBO */ uniform_buffer& resize(size_t newSize); - + /** * Uploads data to the UBO. This can be an arbitrary locations and does not need to be the whole UBO. */ uniform_buffer& upload(void* data, size_t size, size_t offset = 0); - + uniform_buffer& bind(); - + inline uniform_buffer& unbind() { glBindBuffer(GL_UNIFORM_BUFFER, 0); return *this; } - + ~uniform_buffer(); - - [[nodiscard]] inline size_t size() const - { - return size_; - } - - [[nodiscard]] inline GLuint location() const - { - return location_; - } + + [[nodiscard]] inline size_t size() const { return size_; } + + [[nodiscard]] inline GLuint location() const { return location_; } }; - + class shader_base_t { - friend uniform_buffer; + friend uniform_buffer; + protected: struct IntDefaultedToMinusOne { GLint i = -1; - - inline explicit operator bool() const - { - return i != -1; - } + + inline explicit operator bool() const { return i != -1; } }; - + std::unordered_map uniformVars; GLuint programID = 0; - + IntDefaultedToMinusOne getUniformLocation(const std::string& name); - + public: - inline const shader_base_t& bind() const + const shader_base_t& bind() const { glUseProgram(programID); return *this; } - - inline shader_base_t& unbind() + + shader_base_t& bind() + { + glUseProgram(programID); + return *this; + } + + shader_base_t& unbind() { glUseProgram(0); return *this; } - + shader_base_t& setBool(const std::string& name, bool value); - + shader_base_t& setInt(const std::string& name, int value); - + shader_base_t& setFloat(const std::string& name, float value); - + shader_base_t& setMatrix(const std::string& name, blt::mat4x4& matrix); + // poor solution: TODO shader_base_t& setMatrix(const std::string& name, blt::mat4x4&& matrix); - + shader_base_t& setVec2(const std::string& name, const blt::vec2& vec); - + shader_base_t& setVec3(const std::string& name, const blt::vec3& vec); - + shader_base_t& setVec4(const std::string& name, const blt::vec4& vec); - + shader_base_t& setVec2(const std::string& name, float x, float y); - + shader_base_t& setVec3(const std::string& name, float x, float y, float z); - + shader_base_t& setVec4(const std::string& name, float x, float y, float z, float w); }; - + /** * a basic computer shader class, contains the functions and resources required to use compute shaders! */ @@ -132,27 +131,29 @@ namespace blt::gfx { private: GLuint shaderID = 0; + public: 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(); glDispatchCompute(x, y, z); } - + ~compute_shader_t(); }; - + class shader_t : public shader_base_t { private: GLuint vertexShaderID = 0; GLuint fragmentShaderID = 0; - + static unsigned int createShader(const std::string& source, int type); - + static std::string loadShader(std::string_view file); + public: /** * Creates a shader @@ -162,15 +163,15 @@ namespace blt::gfx * @param load_as_string load the shader as a string (true) or use the string to load the shader as a file (false) */ shader_t(const std::string& vertex, const std::string& fragment, bool load_as_string = true); - + shader_t(shader_t&& move) noexcept; - + // used to set the location of VAOs to the in variables in opengl shaders. void bindAttribute(int attribute, const std::string& name) const; - + // used to set location of shared UBOs like the perspective and view matrix void setUniformBlockLocation(const std::string& name, int location) const; - + ~shader_t(); }; } diff --git a/libraries/BLT b/libraries/BLT index 3f0ea88..9b86278 160000 --- a/libraries/BLT +++ b/libraries/BLT @@ -1 +1 @@ -Subproject commit 3f0ea887cd2923cb2cf390a4929ffce452301670 +Subproject commit 9b86278a2982d80fbac6f87045a182088e07afbe diff --git a/src/blt/gfx/renderer/batch_2d_renderer.cpp b/src/blt/gfx/renderer/batch_2d_renderer.cpp index 320891c..bc274dc 100644 --- a/src/blt/gfx/renderer/batch_2d_renderer.cpp +++ b/src/blt/gfx/renderer/batch_2d_renderer.cpp @@ -16,31 +16,29 @@ * along with this program. If not, see . */ #include -#include -#include -#include -#include -#include +#include +#include +#include // https://stackoverflow.com/questions/60440682/drawing-a-line-in-modern-opengl float square_vertices[20] = { // positions // texture coords 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, 0.0f, 0.0f, // bottom left - -0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left + 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] = { - 0, 1, 3, // first triangle - 1, 2, 3 // second triangle + 0, 1, 3, // first triangle + 1, 2, 3 // second triangle }; float line_vertices[20] = { // positions // texture coords 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, 0.0f, 0.0f, // bottom left - -0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left + 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) @@ -50,7 +48,6 @@ float line_vertices[20] = { namespace blt::gfx { - void batch_renderer_2d::create() { { @@ -64,7 +61,7 @@ namespace blt::gfx indices_vbo.allocate(sizeof(square_indices), square_indices); 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->bindElement(indices_vbo); } @@ -93,6 +90,60 @@ namespace blt::gfx 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() { delete square_vao; @@ -101,7 +152,7 @@ namespace blt::gfx } template - 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) { @@ -119,7 +170,7 @@ namespace blt::gfx } } - void batch_renderer_2d::render(bool transparency) + void batch_renderer_2d::render(const bool transparency) { if (transparency) { @@ -127,142 +178,143 @@ namespace blt::gfx glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glEnable(GL_DEPTH_TEST); - draw_count_ = 0; - square_shader->bind(); - square_vao->bind(); glActiveTexture(GL_TEXTURE0); - // annoying - blt::f32 min = std::numeric_limits::max(); - blt::f32 max = std::numeric_limits::min(); + draw_objects(); - 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); if (transparency) glDisable(GL_BLEND); + + render_reset(); } -} \ No newline at end of file + + 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::max(); + draw.z_max = std::numeric_limits::min(); + } + + void batch_renderer_2d::pre_reset() + { + draw.draw_count = 0; + } + + void batch_renderer_2d::post_reset() + { + + } +} diff --git a/src/blt/gfx/window.cpp b/src/blt/gfx/window.cpp index dcec8d7..88b90a8 100644 --- a/src/blt/gfx/window.cpp +++ b/src/blt/gfx/window.cpp @@ -29,7 +29,6 @@ void error_callback(int error, const char* description) namespace blt::gfx { - struct { /* GLFW Window Object */ @@ -47,7 +46,7 @@ namespace blt::gfx double nanoDelta = 0; double millisDelta = 0; } window_state; - + void create_callbacks() { /* Setup keyboard callback */ @@ -69,7 +68,7 @@ namespace blt::gfx window_state.inputManager.key(key) = state; window_state.inputManager.key_pressed = true; }); - + /* Setup mouse button callback */ glfwSetMouseButtonCallback(window_state.window, [](GLFWwindow*, int button, int action, int) { if (button < 0) @@ -87,56 +86,54 @@ namespace blt::gfx window_state.inputManager.mouse(button) = state; window_state.inputManager.mouse_pressed = true; }); - + /* Setup mouse cursor callback */ glfwSetCursorPosCallback(window_state.window, [](GLFWwindow*, double x, double y) { window_state.inputManager.updateMousePos(x, y); window_state.inputManager.mouse_moved = true; }); - + /* Setup mouse scroll callback */ - glfwSetScrollCallback(window_state.window, [](GLFWwindow*, double, double s) { - window_state.inputManager.updateScroll(s); - }); - + glfwSetScrollCallback(window_state.window, [](GLFWwindow*, double, double s) { window_state.inputManager.updateScroll(s); }); + /* Setup drop input callback */ glfwSetDropCallback(window_state.window, [](GLFWwindow*, int count, const char** paths) { for (int i = 0; i < count; i++) window_state.pendingPaths.emplace(paths[i]); }); } - + void setup_ImGUI() { const char* glsl_version = "#version 100"; - + // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::Spectrum::StyleColorsSpectrum(); ImGui::Spectrum::LoadFont(); ImGui::SetupImGuiStyle(true, 1.0); - + // Setup FA ImFontConfig config; config.MergeMode = true; 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->AddFontFromMemoryCompressedTTF(fontAwesomeSolid_compressed_data, static_cast(fontAwesomeSolid_compressed_size), 13.0, &config, icon_ranges); - io.Fonts - ->AddFontFromMemoryCompressedTTF(fontAwesomeBrands_compressed_data, static_cast(fontAwesomeBrands_compressed_size), 13.0, &config, - icon_ranges); - + io.Fonts->AddFontFromMemoryCompressedTTF(fontAwesomeBrands_compressed_data, static_cast(fontAwesomeBrands_compressed_size), 13.0, + &config, + icon_ranges); + //ImGui::StyleColorsLight(); - + // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window_state.window, true); #ifdef __EMSCRIPTEN__ @@ -148,7 +145,7 @@ namespace blt::gfx io.IniFilename = nullptr; #endif } - + void loop(void* arg) { auto& data = *((window_data*) arg); @@ -158,27 +155,27 @@ namespace blt::gfx data.width = window_state.width; data.height = window_state.height; // 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 -- */ ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); - + /* -- Call user update function -- */ data.call_update(); - + /* -- Render the ImGUI frame -- */ ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - + /* -- Update GLFW state -- */ window_state.inputManager.clear(); glfwSwapBuffers(window_state.window); glfwPollEvents(); - + /* -- 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.lastTime = current_time; window_state.nanoDelta = static_cast(window_state.deltaTime) / 1e9f; @@ -186,27 +183,27 @@ namespace blt::gfx } #ifdef __EMSCRIPTEN__ - + EM_BOOL emscripten_resize_callback(int, const EmscriptenUiEvent* event, void* data) { int width = event->documentBodyClientWidth; int height = event->documentBodyClientHeight; - + glfwSetWindowSize(window_state.window, width, height); - + return false; } - + EM_JS(int, get_screen_width, (), { return document.body.clientWidth; }); - + EM_JS(int, get_screen_height, (), { return document.body.clientHeight; }); #endif - + void init(window_data data) { #ifdef __EMSCRIPTEN__ @@ -220,28 +217,28 @@ namespace blt::gfx /* -- Set up Error Callback -- */ glfwSetErrorCallback(error_callback); BLT_ASSERT(glfwInit() && "Unable to init GLFW. Aborting."); - + /* -- Set up Window Context -- */ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, data.context.GL_MAJOR); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, data.context.GL_MINOR); glfwWindowHint(GLFW_DOUBLEBUFFER, data.context.DOUBLE_BUFFER); glfwWindowHint(GLFW_OPENGL_PROFILE, data.context.GL_PROFILE); glfwWindowHint(GLFW_SAMPLES, data.context.SAMPLES); - + /* -- Create the Window -- */ window_state.window = glfwCreateWindow(data.width, data.height, data.title.c_str(), nullptr, nullptr); BLT_ASSERT(window_state.window && "Unable to create GLFW window."); - + /* -- Set Window Specifics + OpenGL -- */ glfwMakeContextCurrent(window_state.window); #ifndef __EMSCRIPTEN__ glfwSwapInterval(data.sync_interval); gladLoadGL(glfwGetProcAddress); #endif - + /* -- Set up our local callbacks, ImGUI will then call these -- */ create_callbacks(); - + /* -- Set up ImGUI -- */ setup_ImGUI(); @@ -249,7 +246,7 @@ namespace blt::gfx if (data.context.SAMPLES > 0) glEnable(GL_MULTISAMPLE); #endif - + /* -- Call User Provided post-window-init function -- */ data.call_init(); @@ -267,52 +264,31 @@ namespace blt::gfx loop((void*) &data); #endif } - + void cleanup() { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); - + glfwDestroyWindow(window_state.window); glfwTerminate(); } - - double getMouseX() - { - return window_state.inputManager.mouseX; - } - - double getMouseY() - { - return window_state.inputManager.mouseY; - } - - double getMouseDX() - { - return window_state.inputManager.deltaX; - } - - double getMouseDY() - { - return window_state.inputManager.deltaY; - } - - void lockCursor() - { - glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - } - - void unlockCursor() - { - glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - } - - bool isCursorLocked() - { - return glfwGetInputMode(window_state.window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; - } - + + double getMouseX() { return window_state.inputManager.mouseX; } + + double getMouseY() { return window_state.inputManager.mouseY; } + + double getMouseDX() { return window_state.inputManager.deltaX; } + + double getMouseDY() { return window_state.inputManager.deltaY; } + + void lockCursor() { glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); } + + void unlockCursor() { glfwSetInputMode(window_state.window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); } + + bool isCursorLocked() { return glfwGetInputMode(window_state.window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; } + bool isCursorInWindow() { #ifdef __EMSCRIPTEN__ @@ -322,7 +298,7 @@ namespace blt::gfx return glfwGetWindowAttrib(window_state.window, GLFW_HOVERED); #endif } - + void setRawInput(bool state) { #ifdef __EMSCRIPTEN__ @@ -332,7 +308,7 @@ namespace blt::gfx glfwSetInputMode(window_state.window, GLFW_RAW_MOUSE_MOTION, state ? GLFW_TRUE : GLFW_FALSE); #endif } - + bool isRawInput() { #ifdef __EMSCRIPTEN__ @@ -341,57 +317,27 @@ namespace blt::gfx return glfwGetInputMode(window_state.window, GLFW_RAW_MOUSE_MOTION); #endif } - - void setClipboard(const std::string& str) - { - glfwSetClipboardString(window_state.window, str.c_str()); - } - - std::string getClipboard() - { - return glfwGetClipboardString(window_state.window); - } - - bool isMousePressed(int button) - { - return window_state.inputManager.isMousePressed(button); - } - - bool isKeyPressed(int key) - { - return window_state.inputManager.isKeyPressed(key); - } - - double getFrameDeltaSeconds() - { - return window_state.nanoDelta; - } - - double getFrameDeltaMilliseconds() - { - return window_state.millisDelta; - } - - std::int64_t getFrameDelta() - { - return window_state.deltaTime; - } - - bool mouseMovedLastFrame() - { - return window_state.inputManager.mouse_moved; - } - - bool mousePressedLastFrame() - { - return window_state.inputManager.mouse_pressed; - } - - bool keyPressedLastFrame() - { - return window_state.inputManager.key_pressed; - } - + + void setClipboard(const std::string& str) { glfwSetClipboardString(window_state.window, str.c_str()); } + + std::string getClipboard() { return glfwGetClipboardString(window_state.window); } + + bool isMousePressed(int button) { return window_state.inputManager.isMousePressed(button); } + + bool isKeyPressed(int key) { return window_state.inputManager.isKeyPressed(key); } + + double getFrameDeltaSeconds() { return window_state.nanoDelta; } + + double getFrameDeltaMilliseconds() { return window_state.millisDelta; } + + std::int64_t getFrameDelta() { return window_state.deltaTime; } + + bool mouseMovedLastFrame() { return window_state.inputManager.mouse_moved; } + + bool mousePressedLastFrame() { return window_state.inputManager.mouse_pressed; } + + bool keyPressedLastFrame() { return window_state.inputManager.key_pressed; } + window_data& window_data::setWindowSize(int32_t new_width, int32_t new_height) { width = new_width;