diff --git a/CMakeLists.txt b/CMakeLists.txt index 73ef4bd..d317969 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/include/shaders/particle.frag b/include/shaders/particle.frag index af9de9c..572360a 100644 --- a/include/shaders/particle.frag +++ b/include/shaders/particle.frag @@ -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)); } ")"; diff --git a/include/shaders/particle.vert b/include/shaders/particle.vert index f2e6ddb..3e0f927 100644 --- a/include/shaders/particle.vert +++ b/include/shaders/particle.vert @@ -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); } diff --git a/include/vao.h b/include/vao.h index 9a2ee7e..5ca4d91 100644 --- a/include/vao.h +++ b/include/vao.h @@ -21,6 +21,7 @@ #include #include +#include #include namespace blt::gfx @@ -32,7 +33,7 @@ namespace blt::gfx struct vao_vbo_storage_t { std::unique_ptr vbo; - std::optional> attribute_numbers; + std::optional> 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> 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> 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> 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) diff --git a/res/images_4.jpeg b/res/images_4.jpeg new file mode 100644 index 0000000..c1d099c Binary files /dev/null and b/res/images_4.jpeg differ diff --git a/res/silly.png b/res/silly.png new file mode 100644 index 0000000..f768fe2 Binary files /dev/null and b/res/silly.png differ diff --git a/src/main.cpp b/src/main.cpp index 8cc193b..aa06639 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 particle_vao; -std::unique_ptr particle_shader; +class gpu_particle_renderer +{ +public: + gpu_particle_renderer() + { + using namespace blt::gfx; -std::vector alive_particles; -std::vector dead_particles; -std::vector 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::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(alive_particles.size()), GL_UNSIGNED_INT, nullptr); + } + +private: + blt::gfx::unique_vao_t particle_vao; + std::unique_ptr particle_shader; + + std::vector alive_particles; + std::vector dead_particles; + std::vector particles; +}; + +std::optional particle_renderer; void init(const blt::gfx::window_data&) { using namespace blt::gfx; + resources.setPrefixDirectory("../"); - particle_shader = std::unique_ptr(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(); diff --git a/src/vao.cpp b/src/vao.cpp index bdbc1f3..dc14483 100644 --- a/src/vao.cpp +++ b/src/vao.cpp @@ -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(v) == attribute_number) - goto use; - } - vec->push_back(attribute_number); - } - use: + if (!vbo.attribute_numbers) + vbo.attribute_numbers = hashset_t(); + 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(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;