aboutsummaryrefslogtreecommitdiff
path: root/09-september/tomcat/particles/particles.c
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/particles.c
Initial commit
Diffstat (limited to '09-september/tomcat/particles/particles.c')
-rw-r--r--09-september/tomcat/particles/particles.c153
1 files changed, 153 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;
+}