aboutsummaryrefslogtreecommitdiff
path: root/09-september/tomcat/particles
diff options
context:
space:
mode:
authorThomas Guillermo Albers Raviola <thomas@thomaslabs.org>2026-01-16 23:02:32 +0100
committerThomas Guillermo Albers Raviola <thomas@thomaslabs.org>2026-01-16 23:02:32 +0100
commit6b8af9cf83851c075c6c9514b1deaa931c2b19a4 (patch)
tree428986b49c32e21d3f7a3c2dfa41858ae0153209 /09-september/tomcat/particles
Initial commit
Diffstat (limited to '09-september/tomcat/particles')
-rw-r--r--09-september/tomcat/particles/particles.c153
-rw-r--r--09-september/tomcat/particles/particles.h62
2 files changed, 215 insertions, 0 deletions
diff --git a/09-september/tomcat/particles/particles.c b/09-september/tomcat/particles/particles.c
new file mode 100644
index 0000000..5e99e06
--- /dev/null
+++ b/09-september/tomcat/particles/particles.c
@@ -0,0 +1,153 @@
+#include "particles.h"
+#include "../util/util_time.h"
+#include "../util/util.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+ParticleManager particles;
+
+static int compare_particles(const void *_a, const void *_b);
+
+void Particles_Init()
+{
+ memset( &particles, 0, sizeof(ParticleManager) );
+}
+
+ParticleSystem *Particles_AddSystem()
+{
+ if(particles.num_systems >= MAX_PARTICLES_SYSTEMS)
+ return NULL;
+
+ ParticleSystem *s = malloc( sizeof(ParticleSystem) );
+ particles.systems[particles.num_systems] = s;
+ memset( s, 0, sizeof(ParticleSystem) );
+
+ particles.num_systems += 1;
+
+ return s;
+}
+
+void Particles_RemoveSystem(ParticleSystem *system)
+{
+ int index = &system - particles.systems;
+
+ if(index > MAX_PARTICLES_SYSTEMS || index < 0)
+ {
+ fprintf(stderr, "Invalid particle system!\n");
+ return;
+ }
+ /* TODO: Finish this function */
+}
+
+void Particles_EmitParticle(ParticleSystem *system, Particle *p)
+{
+ if(system->num_particles >= MAX_PARTICLES_PER_SYSTEM)
+ return;
+
+ Particle *dest = &system->particles[system->num_particles];
+ memcpy(dest, p, sizeof(Particle));
+
+ system->num_particles += 1;
+}
+
+void Particles_Update(const Vec3 *camera_position)
+{
+ Particle *c = NULL; /* Current particle */
+ ParticleSystem *s = NULL; /* Current particle system */
+ Texture *t = NULL; /* Texture of the current system */
+ Vec3 d; /* Vector for calculating the distance to the camera */
+ Vec3 velocity;
+
+ int i, j;
+ for(i = 0; i < particles.num_systems; i++)
+ {
+ s = particles.systems[i];
+ t = s->texture;
+
+ /* We ceil it so we dont truncate the decimal part and get always 0 */
+ int particles_to_emit = (int)ceil( s->emit_rate * Time_GetFrameTime() );
+
+ /* Emit the automatically emited particles */
+ for(j = 0; j < particles_to_emit; j++)
+ {
+ velocity.x = Util_RandomF(0.0f, 50.0f);
+ velocity.y = Util_RandomF(0.0f, 50.0f);
+ velocity.z = Util_RandomF(0.0f, 50.0f);
+ velocity = vec3_normalize(&velocity);
+
+ if(s->num_particles >= MAX_PARTICLES_PER_SYSTEM)
+ break; /* So we dont overflow */
+
+ c = &s->particles[s->num_particles ++];
+ memset(c, 0, sizeof(Particle));
+
+ c->life_length = s->life_length;
+ c->position = s->position;
+ c->scale = 10.0f;
+ c->weight = s->weight;
+ c->velocity = vec3_scalar_mul(&velocity, s->speed);
+ }
+
+ for(j = 0; j < s->num_particles; j++)
+ {
+ c = &s->particles[j];
+
+ /* Update each particle -.- */
+ c->velocity.y += c->weight * Time_GetFrameTime();
+ Vec3 velocity = vec3_scalar_mul(&c->velocity, Time_GetFrameTime());
+ c->position = vec3_add(&c->position, &velocity);
+
+ /* Update animations
+ * How far into its life the particle is */
+ float life_factor = c->elapsed_time / c->life_length;
+ /* How many different stages there are */
+ int stage_count = t->number_of_rows * t->number_of_rows;
+ float atlas_progression = life_factor * stage_count;
+ int index = floor(atlas_progression);
+
+ int column = index % t->number_of_rows;
+ int row = index / t->number_of_rows;
+ c->tex_offset.x = (float)column / t->number_of_rows;
+ c->tex_offset.y = (float)row / t->number_of_rows;
+ /* End of animation update */
+
+ c->elapsed_time += Time_GetFrameTime();
+
+ if(c->elapsed_time > c->life_length)
+ {
+ /* "Kill" the particle by overriding it with the last particle on the array */
+ memmove( c, &s->particles[s->num_particles], sizeof(Particle) );
+ s->num_particles -= 1;
+ }
+ else
+ {
+ d = vec3_sub(camera_position, &c->position);
+ c->distance_to_camera = vec3_length2(&d);
+ }
+ }
+ /*Sort all particles on system by distance to camera */
+ qsort(s->particles, s->num_particles, sizeof(Particle), compare_particles);
+ }
+}
+
+void Particles_Shutdown()
+{
+ int i;
+ for(i = 0; i < particles.num_systems; i++)
+ {
+ if(particles.systems[i])
+ free(particles.systems[i]);
+ }
+ memset(&particles, 0, sizeof(ParticleManager));
+}
+
+static int compare_particles(const void *_a, const void *_b)
+{
+ Particle *a = (Particle *)_a;
+ Particle *b = (Particle *)_b;
+
+ if(a->distance_to_camera < b->distance_to_camera) return -1;
+ if(a->distance_to_camera > b->distance_to_camera) return 1;
+ return 0;
+}
diff --git a/09-september/tomcat/particles/particles.h b/09-september/tomcat/particles/particles.h
new file mode 100644
index 0000000..8404ff4
--- /dev/null
+++ b/09-september/tomcat/particles/particles.h
@@ -0,0 +1,62 @@
+#ifndef PARTICLES_H
+#define PARTICLES_H
+
+#include "../renderer/renderer_types.h"
+#include "../math/vector.h"
+
+#define MAX_PARTICLES_PER_SYSTEM 10000
+#define MAX_PARTICLES_SYSTEMS 10
+
+typedef struct _Particle
+{
+ Vec3 position;
+ Vec3 velocity;
+
+ Vec2 tex_offset; /* Used for animating */
+
+ GLfloat weight; /* How does the gravity affect the particle (In theory it should be a vector)*/
+ GLfloat life_length;
+ GLfloat rotation;
+ GLfloat scale;
+ GLfloat distance_to_camera; /* Used for sorting the systems */
+
+ GLfloat elapsed_time;
+} Particle;
+
+typedef struct _ParticleSystem
+{
+ Vec3 position;
+
+ GLint emit_rate;
+ GLfloat speed;
+ GLfloat weight;
+ GLfloat life_length;
+
+ bool additive; /* Additive vs alpha blending */
+
+ Texture *texture;
+ Particle particles[MAX_PARTICLES_PER_SYSTEM];
+ int num_particles;
+
+} ParticleSystem;
+
+typedef struct
+{
+ ParticleSystem *systems[MAX_PARTICLES_SYSTEMS];
+ int num_systems;
+} ParticleManager;
+
+extern ParticleManager particles;
+
+extern void Particles_Init();
+
+extern ParticleSystem *Particles_AddSystem();
+extern void Particles_RemoveSystem(ParticleSystem *system);
+/* Used for manual emission */
+extern void Particles_EmitParticle(ParticleSystem *system, Particle *p);
+/* Removes a particle if it "dies" */
+extern void Particles_Update(const Vec3 *camera_position);
+/* We need to delete all dynamically allocated particles that still remains */
+extern void Particles_Shutdown();
+
+#endif // PARTICLES_H