particles! Weird EBO stuff

main
Brett 2025-06-11 21:52:02 -04:00
parent 8f3fb79f05
commit 8705a1d4e1
8 changed files with 123 additions and 43 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
project(gpu-particles VERSION 0.0.14)
project(gpu-particles VERSION 0.0.15)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)

View File

@ -4,13 +4,21 @@ const std::string shader_particle_2d_frag = R"("
#version 300 es
precision mediump float;
uniform sampler2D tex;
uniform sampler2D tex1;
uniform sampler2D tex2;
in float silly;
layout (location = 0) out vec4 FragColor;
void main()
{
FragColor = texture(tex, gl_PointCoord);
float x = gl_PointCoord.x;
float y = 1.0f - gl_PointCoord.y;
if (silly > 0.0f)
FragColor = texture(tex1, vec2(x, y));
else
FragColor = texture(tex2, vec2(x, y));
}
")";

View File

@ -6,6 +6,8 @@ precision mediump float;
layout (location = 0) in vec2 position;
out float silly;
layout (std140) uniform GlobalMatrices
{
mat4 projection;
@ -17,6 +19,10 @@ layout (std140) uniform GlobalMatrices
void main()
{
if (mod(position.x + position.y, 32.0f) >= 16.0f)
silly = 1.0f;
else
silly = 0.0f;
gl_Position = ovm * vec4(position.x, position.y, 0.0, 1.0);
}

View File

@ -21,6 +21,7 @@
#include <memory>
#include <vbo.h>
#include <blt/std/hashmap.h>
#include <blt/std/vector.h>
namespace blt::gfx
@ -32,7 +33,7 @@ namespace blt::gfx
struct vao_vbo_storage_t
{
std::unique_ptr<unique_vbo_t> vbo;
std::optional<std::vector<u32>> attribute_numbers;
std::optional<hashset_t<u32>> attribute_numbers;
[[nodiscard]] bool is_element() const
{
@ -101,7 +102,6 @@ namespace blt::gfx
vao_context_t& unbind();
vao_vbo_context_t attach_vbo(unique_vbo_t&& vbo) const;
private:
[[nodiscard]] bool is_bound() const;
@ -140,6 +140,39 @@ namespace blt::gfx
detail::vao_context_t bind();
[[nodiscard]] std::optional<ref<unique_vbo_t>> get_attribute(const u32 attribute) const
{
for (const auto& vbo_obj : vbo_list)
{
if (const auto attrs = vbo_obj.attribute_numbers)
{
if (attrs->contains(attribute))
return *vbo_obj.vbo;
}
}
return {};
}
[[nodiscard]] std::optional<ref<unique_vbo_t>> get_buffer_type(const GLuint buffer_type) const
{
for (const auto& vbo_obj : vbo_list)
{
if (vbo_obj.vbo->get_buffer_type() == buffer_type)
return *vbo_obj.vbo;
}
return {};
}
[[nodiscard]] std::optional<ref<unique_vbo_t>> get_element() const
{
for (const auto& vbo_obj : vbo_list)
{
if (vbo_obj.is_element())
return *vbo_obj.vbo;
}
return {};
}
~unique_vao_t()
{
if (vaoID)

BIN
res/images_4.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
res/silly.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

View File

@ -30,7 +30,7 @@ constexpr blt::size_t PARTICLE_COUNT = 8192;
blt::gfx::matrix_state_manager global_matrices;
blt::gfx::resource_manager resources;
blt::gfx::batch_renderer_2d renderer_2d(resources, global_matrices);
blt::gfx::first_person_camera camera;
blt::gfx::first_person_camera_2d camera;
// use types for state that way you are not confused about what is happening?
@ -39,43 +39,80 @@ struct particle_t
blt::vec2 position;
blt::vec2 velocity;
blt::vec2 acceleration;
float mass = 10;
float unused;
static particle_t make_particle()
{
blt::random::random_t random{std::random_device()()};
return {blt::vec2{random.get(0.0f, 500.0f), random.get(0.0f, 500.0f)}, blt::vec2{}, blt::vec2{}};
static blt::random::random_t random{std::random_device()()};
return {blt::vec2{random.get(20.0f, 1880.0f), random.get(20.0f, 1000.0f)}, blt::vec2{}, blt::vec2{}};
}
};
std::optional<blt::gfx::unique_vao_t> particle_vao;
std::unique_ptr<blt::gfx::shader_t> particle_shader;
class gpu_particle_renderer
{
public:
gpu_particle_renderer()
{
using namespace blt::gfx;
std::vector<blt::u32> alive_particles;
std::vector<blt::u32> dead_particles;
std::vector<particle_t> particles;
for (blt::size_t i = 0; i < PARTICLE_COUNT; i++)
{
particles.push_back(particle_t::make_particle());
alive_particles.push_back(i);
}
particle_shader = std::unique_ptr<shader_t>(shader_t::make(shader_particle_2d_vert, shader_particle_2d_frag));
unique_vbo_t particle_vbo(GL_ARRAY_BUFFER);
particle_vbo.bind().upload(sizeof(particle_t) * particles.size(), particles.data(), GL_DYNAMIC_DRAW);
unique_ebo_t alive_particles_ebo;
alive_particles_ebo.bind().upload(sizeof(blt::u32) * alive_particles.size(), alive_particles.data(), GL_DYNAMIC_DRAW);
auto vao_ctx = particle_vao.bind();
vao_ctx.attach_vbo(std::move(particle_vbo)).attribute_ptr(0, 2, GL_FLOAT, sizeof(particle_t), 0);
vao_ctx.attach_vbo(std::move(alive_particles_ebo));
vao_ctx.unbind();
}
void render()
{
glPointSize(25);
particle_shader->bind();
particle_shader->setInt("tex1", 0);
particle_shader->setInt("tex2", 1);
particle_vao.bind();
// particle_vao.get_element()->get().bind();
glActiveTexture(GL_TEXTURE0);
resources.get("silly").value()->bind();
glActiveTexture(GL_TEXTURE1);
resources.get("happy").value()->bind();
glDrawElements(GL_POINTS, static_cast<int>(alive_particles.size()), GL_UNSIGNED_INT, nullptr);
}
private:
blt::gfx::unique_vao_t particle_vao;
std::unique_ptr<blt::gfx::shader_t> particle_shader;
std::vector<blt::u32> alive_particles;
std::vector<blt::u32> dead_particles;
std::vector<particle_t> particles;
};
std::optional<gpu_particle_renderer> particle_renderer;
void init(const blt::gfx::window_data&)
{
using namespace blt::gfx;
resources.setPrefixDirectory("../");
particle_shader = std::unique_ptr<shader_t>(shader_t::make(shader_particle_2d_vert, shader_particle_2d_frag));
resources.enqueue("res/silly.png", "silly");
resources.enqueue("res/images_4.jpeg", "happy");
for (blt::size_t i = 0; i < PARTICLE_COUNT; i++)
{
particles.push_back(particle_t::make_particle());
alive_particles.push_back(i);
}
unique_vbo_t particle_vbo(GL_ARRAY_BUFFER);
particle_vbo.bind().upload(sizeof(particle_t) * particles.size(), particles.data(), GL_DYNAMIC_DRAW);
unique_ebo_t alive_particles_ebo;
alive_particles_ebo.bind().upload(sizeof(blt::u32) * alive_particles.size(), alive_particles.data(), GL_DYNAMIC_DRAW);
particle_vao = unique_vao_t();
const auto vao_ctx = particle_vao->bind();
vao_ctx.attach_vbo(std::move(particle_vbo)).attribute_ptr(0, 2, GL_FLOAT, sizeof(particle_t), 0);
vao_ctx.attach_vbo(std::move(alive_particles_ebo));
particle_renderer = gpu_particle_renderer{};
global_matrices.create_internals();
resources.load_resources();
@ -91,12 +128,13 @@ void update(const blt::gfx::window_data& data)
global_matrices.update();
renderer_2d.render(data.width, data.height);
particle_renderer->render();
}
void destroy(const blt::gfx::window_data&)
{
particle_vao.reset();
particle_shader.reset();
particle_renderer.reset();
global_matrices.cleanup();
resources.cleanup();
renderer_2d.cleanup();

View File

@ -25,22 +25,16 @@ namespace blt::gfx
#define ENSURE_CONTEXT_BOUND BLT_CONTRACT(glfwGetCurrentContext() != nullptr, "Expected active OpenGL context!")
#if blt_debug_has_flag(BLT_DEBUG_CONTRACTS)
GLuint bound_vao_id;
GLuint bound_vao_id = 0;
#endif
detail::vao_vbo_context_t& detail::vao_vbo_context_t::attribute_ptr(const int attribute_number, const int coordinate_size, const GLenum type,
const int stride, const long offset)
{
if (auto& vec = vbo.attribute_numbers)
{
for (const auto& v : *vec)
{
if (static_cast<i32>(v) == attribute_number)
goto use;
}
vec->push_back(attribute_number);
}
use:
if (!vbo.attribute_numbers)
vbo.attribute_numbers = hashset_t<u32>();
if (!vbo.attribute_numbers->contains(attribute_number))
vbo.attribute_numbers->insert(attribute_number);
glEnableVertexAttribArray(attribute_number);
glVertexAttribPointer(attribute_number, coordinate_size, type, GL_FALSE, stride < 0 ? 0 : stride, reinterpret_cast<void*>(offset));
attributed = true;
@ -69,6 +63,7 @@ namespace blt::gfx
detail::vao_context_t& detail::vao_context_t::unbind() // NOLINT
{
ENSURE_CONTEXT_BOUND;
glBindVertexArray(0);
bound_vao_id = 0;
return *this;