1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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;
}
|