summaryrefslogtreecommitdiff
path: root/in_practice/breakout/particle.c
diff options
context:
space:
mode:
Diffstat (limited to 'in_practice/breakout/particle.c')
-rw-r--r--in_practice/breakout/particle.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/in_practice/breakout/particle.c b/in_practice/breakout/particle.c
new file mode 100644
index 0000000..8c71520
--- /dev/null
+++ b/in_practice/breakout/particle.c
@@ -0,0 +1,104 @@
+#include "particle.h"
+#include "types.h"
+#include "shader.h"
+
+#include <stdlib.h>
+#include <float.h>
+
+void respawn_particle(struct particle *particle, struct object object, v2 offset)
+{
+ f32 random = ((rand() % 100) - 50) / 10.0f;
+ particle->pos = addf_v2(add_v2(object.pos, offset), random);
+ particle->vel = scale_v2(object.vel, 0.1f);
+ random = 0.5f + ((rand() % 100) / 100.0f);
+ particle->color = (v4){random, random, random, 1.0f};
+ particle->life = 1.0f;
+}
+
+i32 find_unused_particle(struct particle_generator generator)
+{
+ f32 min = FLT_MAX;
+ i32 mini = 0;
+ for (i32 i = 0; i < MAX_PARTICLES; i++) {
+ f32 life = generator.particles[i].life;
+ if (life <= 0.0f) {
+ return i;
+ } else if (life < min) {
+ min = life;
+ mini = i;
+ }
+ }
+ return mini;
+}
+
+struct particle_generator init_generator(i32 new, u32 shader, u32 texture)
+{
+ struct particle_generator generator = {0};
+ reset_particles(&generator);
+ generator.new = new;
+ generator.shader = shader;
+ generator.texture = texture;
+ f32 vertices[] = {
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f,
+
+ 1.0f, 0.0f, 1.0f, 0.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f, 1.0f
+ };
+ u32 vao, vbo;
+ glGenVertexArrays(1, &vao);
+ glGenBuffers(1, &vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+ glBindVertexArray(vao);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 4, GL_FLOAT, 0, 4 * sizeof(f32), 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ generator.vao = vao;
+ return generator;
+}
+
+void update_particles(struct particle_generator *generator, struct object object, f32 dt, v2 offset)
+{
+ for (i32 i = 0; i < generator->new; i++) {
+ i32 unused = find_unused_particle(*generator);
+ respawn_particle(generator->particles + unused, object, offset);
+ }
+ for (i32 i = 0; i < MAX_PARTICLES; i++) {
+ struct particle *particle = generator->particles + i;
+ particle->life -= dt;
+ if (particle->life > 0.0f) {
+ particle->pos = sub_v2(particle->pos, scale_v2(particle->vel, dt));
+ particle->color.w -= dt * 2.0f;
+ }
+ }
+}
+
+void render_particles(struct particle_generator generator)
+{
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ glUseProgram(generator.shader);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, generator.texture);
+ glBindVertexArray(generator.vao);
+ for (i32 i = 0; i < MAX_PARTICLES; i++) {
+ struct particle *particle = generator.particles + i;
+ if (particle->life > 0.0f) {
+ uniform_v2(generator.shader, "offset", particle->pos);
+ uniform_v4(generator.shader, "color", particle->color);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ }
+ }
+ glBindVertexArray(0);
+ glUseProgram(0);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void reset_particles(struct particle_generator *generator)
+{
+ for (i32 i = 0; i < MAX_PARTICLES; i++)
+ generator->particles[i] = (struct particle)default_particle;
+}