working batch renderer for 2d rectangles

main
Brett 2024-01-02 02:38:56 -05:00
parent e37fc6b321
commit 26c659fc3f
10 changed files with 200 additions and 63 deletions

View File

@ -0,0 +1,24 @@
#ifdef __cplusplus
#include <string>
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

View File

@ -0,0 +1,31 @@
#ifdef __cplusplus
#include <string>
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

View File

@ -21,26 +21,86 @@
#include "blt/gfx/model.h" #include "blt/gfx/model.h"
#include "blt/gfx/shader.h" #include "blt/gfx/shader.h"
#include "blt/gfx/renderer/resource_manager.h"
#include <blt/std/hashmap.h>
#include <blt/std/memory_util.h>
#include <blt/math/vectors.h>
#include <string_view>
#include <vector>
namespace blt::gfx namespace blt::gfx
{ {
struct rectangle_t
struct rectangle
{ {
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 class batch_renderer_2d
{ {
private: private:
vertex_array* square_vao; struct vec_hash
shader_t* shader; {
std::size_t operator()(const blt::vec4& key) const
{
using namespace blt::mem;
return type_cast<std::int32_t>(key.x()) ^ type_cast<std::int32_t>(key.y()) ^ type_cast<std::int32_t>(key.y()) ^
type_cast<std::int32_t>(key.z());
}
};
private:
vertex_array* square_vao = nullptr;
shader_t* shader = nullptr;
resource_manager& resources;
HASHMAP<std::string, HASHMAP<blt::vec4, HASHMAP<blt::vec4, std::vector<rectangle_t>, vec_hash>, vec_hash>> complex_rectangles;
size_t draw_count_ = 0;
public: public:
/** explicit batch_renderer_2d(resource_manager& resources): resources(resources)
* @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); 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(); void cleanup();
[[nodiscard]] inline size_t draw_count(){
return draw_count_;
}
}; };
} }

View File

@ -21,8 +21,11 @@
#include <blt/std/hashmap.h> #include <blt/std/hashmap.h>
#include <blt/gfx/texture.h> #include <blt/gfx/texture.h>
#include <blt/std/thread.h> #include <mutex>
#include <vector>
#include <optional>
#include <string> #include <string>
#include "blt/compatibility.h"
namespace blt::gfx namespace blt::gfx
{ {
@ -53,8 +56,10 @@ namespace blt::gfx
void load_resources(std::size_t threads = 8); void load_resources(std::size_t threads = 8);
inline texture_gl2D* get(const std::string& name) inline std::optional<texture_gl2D*> get(const std::string& name)
{ {
if (name.empty() || textures_2d.find(name) == textures_2d.end())
return {};
return textures_2d[name]; return textures_2d[name];
} }

@ -1 +1 @@
Subproject commit d882b76d83749273b05e71fb0361d8778cc6ad94 Subproject commit 8411810ab5df8f330f9d7cf96a96179375dc4704

View File

@ -16,6 +16,8 @@
* 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/2d_textured.frag>
float square_vertices[20] = { float square_vertices[20] = {
// positions // texture coords // positions // texture coords
@ -32,13 +34,64 @@ const unsigned int square_indices[6] = {
namespace blt::gfx 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() 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();
}
}
}
} }
} }

View File

@ -17,6 +17,7 @@
*/ */
#include <blt/gfx/renderer/resource_manager.h> #include <blt/gfx/renderer/resource_manager.h>
#include <blt/std/logging.h> #include <blt/std/logging.h>
#include <blt/std/thread.h>
namespace blt::gfx namespace blt::gfx
{ {

View File

@ -1,6 +1,6 @@
#ifdef __cplusplus #ifdef __cplusplus
#include <string> #include <string>
std::string shader_test_frag = R"(" const std::string shader_test_frag = R"("
#version 300 es #version 300 es
precision mediump float; precision mediump float;

View File

@ -1,6 +1,6 @@
#ifdef __cplusplus #ifdef __cplusplus
#include <string> #include <string>
std::string shader_test_vert = R"(" const std::string shader_test_vert = R"("
#version 300 es #version 300 es
precision mediump float; precision mediump float;
@ -22,7 +22,6 @@ layout (std140) uniform GlobalMatrices
uniform mat4 model; uniform mat4 model;
void main() { void main() {
//gl_Position = projection * view * vec4(vertex.x, vertex.y, vertex.z, 1.0);
gl_Position = ortho * model * vec4(vertex, 1.0); gl_Position = ortho * model * vec4(vertex, 1.0);
pos = vertex.xy; pos = vertex.xy;
uv = uv_in; uv = uv_in;

View File

@ -7,15 +7,13 @@
#include <imgui.h> #include <imgui.h>
#include "blt/gfx/imgui/IconsFontAwesome5.h" #include "blt/gfx/imgui/IconsFontAwesome5.h"
#include <shaders/test.vert>
#include <shaders/test.frag>
#include "blt/gfx/renderer/resource_manager.h" #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::matrix_state_manager global_matrices;
blt::gfx::resource_manager resources; blt::gfx::resource_manager resources;
blt::gfx::batch_renderer_2d renderer_2d(resources);
float x = 0, y = 0, z = 0; float x = 0, y = 0, z = 0;
float bx = 500, by = 500; float bx = 500, by = 500;
float mx = 0, my = -9.8; float mx = 0, my = -9.8;
@ -46,71 +44,36 @@ void handle_input()
global_matrices.setView(view); 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() void init()
{ {
using namespace blt::gfx; 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/cumdollar.jpg", "ibuythat");
resources.enqueue("../resources/textures/dfoedbi-28157978-1555-45c3-b2f4-d5e5fe25b253.png", "niko"); resources.enqueue("../resources/textures/dfoedbi-28157978-1555-45c3-b2f4-d5e5fe25b253.png", "niko");
global_matrices.create_internals(); global_matrices.create_internals();
resources.load_resources(); resources.load_resources();
renderer_2d.create();
} }
void update(std::int32_t width, std::int32_t height) void update(std::int32_t width, std::int32_t height)
{ {
global_matrices.update_perspectives(width, height); global_matrices.update_perspectives(width, height);
ImGui::ShowDemoWindow(); ImGui::ShowDemoWindow();
ImGui::SetNextWindowSize(ImVec2(150, 65)); ImGui::SetNextWindowSize(ImVec2(150, 85));
ImGui::Begin("Debug Info Panel", nullptr, ImGuiWindowFlags_NoResize); ImGui::Begin("Debug Info Panel", nullptr, ImGuiWindowFlags_NoResize);
ImGui::Text("%s FPS: %f", ICON_FA_WRENCH, 1.0e9 / static_cast<double>(blt::gfx::getFrameDelta())); ImGui::Text("%s FPS: %f", ICON_FA_WRENCH, 1.0e9 / static_cast<double>(blt::gfx::getFrameDelta()));
ImGui::Text("Draw Count: %zu", renderer_2d.draw_count());
ImGui::End(); ImGui::End();
handle_input(); handle_input();
global_matrices.update(); global_matrices.update();
shader->bind();
const float w = 120, h = 120, cf = 30, rf = 15, crf = 10; const float w = 120, h = 120, cf = 30, rf = 15, crf = 10;
glActiveTexture(GL_TEXTURE0); renderer_2d.drawRectangle("ibuythat", blt::gfx::rectangle_t(width/2.0, height/2.0, width, height, 90));
resources.get("ibuythat")->bind(); renderer_2d.drawRectangle("niko", {bx, by, w, h});
draw(width / 2.0, height / 2.0, width, height, 90);
resources.get("niko")->bind();
draw(bx, by, w, h, 0);
bx += mx * blt::gfx::getFrameDeltaSeconds() * cf; bx += mx * blt::gfx::getFrameDeltaSeconds() * cf;
by += my * 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) if (my > 100 || my < -100)
my = my * 0.2; my = my * 0.2;
renderer_2d.render();
} }
int main() int main()
{ {
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update}.setSyncInterval(1)); blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update}.setSyncInterval(1));
delete vao;
delete shader;
global_matrices.cleanup(); global_matrices.cleanup();
resources.cleanup(); resources.cleanup();
renderer_2d.cleanup();
blt::gfx::cleanup(); blt::gfx::cleanup();
return 0; return 0;
} }