diff --git a/include/blt/gfx/renderer/2d_textured.frag b/include/blt/gfx/renderer/2d_textured.frag new file mode 100644 index 0000000..89df101 --- /dev/null +++ b/include/blt/gfx/renderer/2d_textured.frag @@ -0,0 +1,24 @@ +#ifdef __cplusplus +#include +const std::string shader_2d_textured_frag = R"(" +#version 300 es +precision mediump float; + +out vec4 FragColor; +in vec2 uv; +in vec2 pos; + +uniform sampler2D tex; +uniform vec4 color; +uniform vec4 use_texture; + +vec4 linear_iter(vec4 i, vec4 p, float factor){ + return (i + p) * factor; +} + +void main() { + FragColor = (texture(tex, uv) * use_texture) + color; +} + +")"; +#endif \ No newline at end of file diff --git a/include/blt/gfx/renderer/2d_textured.vert b/include/blt/gfx/renderer/2d_textured.vert new file mode 100644 index 0000000..9547b35 --- /dev/null +++ b/include/blt/gfx/renderer/2d_textured.vert @@ -0,0 +1,31 @@ +#ifdef __cplusplus +#include +const std::string shader_2d_textured_vert = R"(" +#version 300 es +precision mediump float; + +layout (location = 0) in vec3 vertex; +layout (location = 1) in vec2 uv_in; + +out vec2 pos; +out vec2 uv; + +layout (std140) uniform GlobalMatrices +{ + mat4 projection; + mat4 ortho; + mat4 view; + mat4 pvm; + mat4 ovm; +}; + +uniform mat4 model; + +void main() { + gl_Position = ortho * model * vec4(vertex, 1.0); + pos = vertex.xy; + uv = uv_in; +} + +")"; +#endif \ No newline at end of file diff --git a/include/blt/gfx/renderer/batch_2d_renderer.h b/include/blt/gfx/renderer/batch_2d_renderer.h index 53eb826..481d0a8 100644 --- a/include/blt/gfx/renderer/batch_2d_renderer.h +++ b/include/blt/gfx/renderer/batch_2d_renderer.h @@ -21,26 +21,86 @@ #include "blt/gfx/model.h" #include "blt/gfx/shader.h" +#include "blt/gfx/renderer/resource_manager.h" +#include +#include +#include +#include +#include namespace blt::gfx { - - struct rectangle + struct rectangle_t { - float x, y, width, height; + float x, y, width, height, rotation = 0; + + rectangle_t(float x, float y, float width, float height, float rotation): x(x), y(y), width(width), height(height), rotation(rotation) + {} + + rectangle_t(float x, float y, float width, float height): x(x), y(y), width(width), height(height) + {} + }; + + struct draw_state + { + // texture to use + std::string texture_name; + // color to use + blt::vec4 color; + // how much to blend the texture into the color? note blending is always additive! + blt::vec4 blend; }; class batch_renderer_2d { private: - vertex_array* square_vao; - shader_t* shader; + struct vec_hash + { + std::size_t operator()(const blt::vec4& key) const + { + using namespace blt::mem; + return type_cast(key.x()) ^ type_cast(key.y()) ^ type_cast(key.y()) ^ + type_cast(key.z()); + } + }; + + private: + vertex_array* square_vao = nullptr; + shader_t* shader = nullptr; + resource_manager& resources; + HASHMAP, vec_hash>, vec_hash>> complex_rectangles; + size_t draw_count_ = 0; public: - /** - * @param use_view_matrix should we use the view matrix when rendering? Defaults to false as the assumption is the view matrix is 3d - */ - void create(bool use_view_matrix = false); + explicit batch_renderer_2d(resource_manager& resources): resources(resources) + {} + + void create(); + + inline void drawRectangle(std::string_view texture, const rectangle_t& rectangle) + { + const static blt::vec4 empty {0,0,0,0}; + const static blt::vec4 full {1,1,1,1}; + complex_rectangles[texture][empty][full].push_back(rectangle); + } + + inline void drawRectangle(const blt::vec4& color, const rectangle_t& rectangle) + { + const static blt::vec4 empty {0,0,0,0}; + complex_rectangles[""][color][empty].push_back(rectangle); + } + + inline void drawRectangle(const draw_state& draw_info, const rectangle_t& rectangle) + { + complex_rectangles[draw_info.texture_name][draw_info.color][draw_info.blend].push_back(rectangle); + } + + void render(); + void cleanup(); + + [[nodiscard]] inline size_t draw_count(){ + return draw_count_; + } }; } diff --git a/include/blt/gfx/renderer/resource_manager.h b/include/blt/gfx/renderer/resource_manager.h index f1e085a..d1273b6 100644 --- a/include/blt/gfx/renderer/resource_manager.h +++ b/include/blt/gfx/renderer/resource_manager.h @@ -21,8 +21,11 @@ #include #include -#include +#include +#include +#include #include +#include "blt/compatibility.h" namespace blt::gfx { @@ -53,8 +56,10 @@ namespace blt::gfx void load_resources(std::size_t threads = 8); - inline texture_gl2D* get(const std::string& name) + inline std::optional get(const std::string& name) { + if (name.empty() || textures_2d.find(name) == textures_2d.end()) + return {}; return textures_2d[name]; } diff --git a/libraries/BLT b/libraries/BLT index d882b76..8411810 160000 --- a/libraries/BLT +++ b/libraries/BLT @@ -1 +1 @@ -Subproject commit d882b76d83749273b05e71fb0361d8778cc6ad94 +Subproject commit 8411810ab5df8f330f9d7cf96a96179375dc4704 diff --git a/src/blt/gfx/renderer/batch_2d_renderer.cpp b/src/blt/gfx/renderer/batch_2d_renderer.cpp index 888aab7..0aca933 100644 --- a/src/blt/gfx/renderer/batch_2d_renderer.cpp +++ b/src/blt/gfx/renderer/batch_2d_renderer.cpp @@ -16,6 +16,8 @@ * along with this program. If not, see . */ #include +#include +#include float square_vertices[20] = { // positions // texture coords @@ -32,13 +34,64 @@ const unsigned int square_indices[6] = { namespace blt::gfx { - void batch_renderer_2d::create(bool use_view_matrix) + void batch_renderer_2d::create() { - + vbo_t vertices_vbo; + vbo_t indices_vbo; + + vertices_vbo.create(); + indices_vbo.create(GL_ELEMENT_ARRAY_BUFFER); + + vertices_vbo.allocate(sizeof(square_vertices), square_vertices); + indices_vbo.allocate(sizeof(square_indices), square_indices); + + square_vao = new vertex_array(); + square_vao->bindVBO(vertices_vbo, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); + square_vao->bindVBO(vertices_vbo, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); + square_vao->bindElement(indices_vbo); + + shader = new shader_t(shader_2d_textured_vert, shader_2d_textured_frag); + shader->bindAttribute(0, "vertex"); + shader->bindAttribute(1, "uv_in"); } void batch_renderer_2d::cleanup() { + delete square_vao; + delete shader; + } + void batch_renderer_2d::render() + { + draw_count_ = 0; + shader->bind(); + square_vao->bind(); + glActiveTexture(GL_TEXTURE0); + 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) + { + shader->setVec4("color", colors.first); + for (auto& blend_factors : colors.second) + { + shader->setVec4("use_texture", blend_factors.first); + for (auto& rect : blend_factors.second) + { + blt::mat4x4 model; + model.translate(rect.x, rect.y, 0.0f); + model.scale(rect.width, rect.height, 1); + if (rect.rotation != 0) + model.rotateZ(blt::toRadians(rect.rotation)); + shader->setMatrix("model", model); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + draw_count_++; + } + blend_factors.second.clear(); + } + } + } } } \ No newline at end of file diff --git a/src/blt/gfx/renderer/resource_manager.cpp b/src/blt/gfx/renderer/resource_manager.cpp index 89fc772..e564308 100644 --- a/src/blt/gfx/renderer/resource_manager.cpp +++ b/src/blt/gfx/renderer/resource_manager.cpp @@ -17,6 +17,7 @@ */ #include #include +#include namespace blt::gfx { diff --git a/tests/include/shaders/test.frag b/tests/include/shaders/test.frag index 6104832..8a1985d 100644 --- a/tests/include/shaders/test.frag +++ b/tests/include/shaders/test.frag @@ -1,6 +1,6 @@ #ifdef __cplusplus #include -std::string shader_test_frag = R"(" +const std::string shader_test_frag = R"(" #version 300 es precision mediump float; diff --git a/tests/include/shaders/test.vert b/tests/include/shaders/test.vert index 0d51994..86e66bd 100644 --- a/tests/include/shaders/test.vert +++ b/tests/include/shaders/test.vert @@ -1,6 +1,6 @@ #ifdef __cplusplus #include -std::string shader_test_vert = R"(" +const std::string shader_test_vert = R"(" #version 300 es precision mediump float; @@ -22,7 +22,6 @@ layout (std140) uniform GlobalMatrices uniform mat4 model; void main() { - //gl_Position = projection * view * vec4(vertex.x, vertex.y, vertex.z, 1.0); gl_Position = ortho * model * vec4(vertex, 1.0); pos = vertex.xy; uv = uv_in; diff --git a/tests/src/main.cpp b/tests/src/main.cpp index 2947229..c21ac9b 100644 --- a/tests/src/main.cpp +++ b/tests/src/main.cpp @@ -7,15 +7,13 @@ #include #include "blt/gfx/imgui/IconsFontAwesome5.h" -#include -#include #include "blt/gfx/renderer/resource_manager.h" +#include "blt/gfx/renderer/batch_2d_renderer.h" -blt::gfx::vertex_array* vao; -blt::gfx::shader_t* shader; blt::gfx::matrix_state_manager global_matrices; blt::gfx::resource_manager resources; +blt::gfx::batch_renderer_2d renderer_2d(resources); float x = 0, y = 0, z = 0; float bx = 500, by = 500; float mx = 0, my = -9.8; @@ -46,71 +44,36 @@ void handle_input() global_matrices.setView(view); } -void draw(float x_, float y_, float width_, float height_, float rot = 0) -{ - blt::mat4x4 model; - model.translate(x_, y_, 0.0f); - model.scale(width_, height_, 1); - model.rotateZ(blt::toRadians(rot)); - - shader->setMatrix("model", model); - - vao->bind(); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); -} - void init() { using namespace blt::gfx; - vbo_t vertices_vbo; - vbo_t indices_vbo; - - vertices_vbo.create(); - indices_vbo.create(GL_ELEMENT_ARRAY_BUFFER); - - vertices_vbo.allocate(sizeof(vertices), vertices); - indices_vbo.allocate(sizeof(indices), indices); - - vao = new vertex_array(); - vao->bindVBO(vertices_vbo, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); - vao->bindVBO(vertices_vbo, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); - vao->bindElement(indices_vbo); - - shader = new shader_t(shader_test_vert, shader_test_frag); - shader->bindAttribute(0, "vertex"); - shader->bindAttribute(1, "uv_in"); - resources.enqueue("../resources/textures/cumdollar.jpg", "ibuythat"); resources.enqueue("../resources/textures/dfoedbi-28157978-1555-45c3-b2f4-d5e5fe25b253.png", "niko"); global_matrices.create_internals(); resources.load_resources(); + renderer_2d.create(); } void update(std::int32_t width, std::int32_t height) { global_matrices.update_perspectives(width, height); ImGui::ShowDemoWindow(); - ImGui::SetNextWindowSize(ImVec2(150, 65)); + ImGui::SetNextWindowSize(ImVec2(150, 85)); ImGui::Begin("Debug Info Panel", nullptr, ImGuiWindowFlags_NoResize); ImGui::Text("%s FPS: %f", ICON_FA_WRENCH, 1.0e9 / static_cast(blt::gfx::getFrameDelta())); + ImGui::Text("Draw Count: %zu", renderer_2d.draw_count()); ImGui::End(); handle_input(); global_matrices.update(); - shader->bind(); - const float w = 120, h = 120, cf = 30, rf = 15, crf = 10; - glActiveTexture(GL_TEXTURE0); - resources.get("ibuythat")->bind(); - draw(width / 2.0, height / 2.0, width, height, 90); - - resources.get("niko")->bind(); - draw(bx, by, w, h, 0); + renderer_2d.drawRectangle("ibuythat", blt::gfx::rectangle_t(width/2.0, height/2.0, width, height, 90)); + renderer_2d.drawRectangle("niko", {bx, by, w, h}); bx += mx * blt::gfx::getFrameDeltaSeconds() * cf; by += my * blt::gfx::getFrameDeltaSeconds() * cf; @@ -131,15 +94,16 @@ void update(std::int32_t width, std::int32_t height) } if (my > 100 || my < -100) my = my * 0.2; + + renderer_2d.render(); } int main() { blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update}.setSyncInterval(1)); - delete vao; - delete shader; global_matrices.cleanup(); resources.cleanup(); + renderer_2d.cleanup(); blt::gfx::cleanup(); return 0; }