console: Format tabs semi-intelligently
[attac-man.git] / particle.c
blobfa69fd05e54a09f1594df4ebc59ab0bf2cb9d12c
1 /*
2 Pacman Arena
3 Copyright (C) 2003 Nuno Subtil
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 static const char cvsid[] =
21 "$Id: particle.c,v 1.13 2003/11/22 17:07:42 nsubtil Exp $";
23 #ifdef _WIN32
24 #include <windows.h>
25 #endif
27 #include <GL/gl.h>
28 #include <stdlib.h>
29 #include <stdio.h>
31 #include "game.h"
32 #include "player.h"
33 #include "object.h"
34 #include "render.h"
35 #include "gfx.h"
36 #include "m_math.h"
37 #include "map.h"
39 #include "particle.h"
41 struct particle_src *particle_new_src(float life, float fade, float rate, float size,
42 float position[3], float direction[3], float src_speed[3],
43 float spread, float speed, float speed_spread,
44 float gravity, float color[3])
46 struct particle_src *new;
48 new = (struct particle_src *)malloc(sizeof(struct particle_src));
50 new->n_particles = 0;
51 new->particles = NULL;
53 new->particle_life = life;
54 new->particle_fade = fade;
55 new->particle_rate = rate;
56 new->last_particle_time = 0.0;
57 new->particle_size = size;
58 new->position[X] = position[X];
59 new->position[Y] = position[Y];
60 new->position[Z] = position[Z];
61 new->direction[X] = direction[X];
62 new->direction[Y] = direction[Y];
63 new->direction[Z] = direction[Z];
64 new->src_speed[X] = src_speed[X];
65 new->src_speed[Y] = src_speed[Y];
66 new->src_speed[Z] = src_speed[Z];
67 new->gravity = gravity;
68 new->spread = spread;
69 new->speed = speed;
70 new->speed_spread = speed_spread;
71 new->color[R] = color[R];
72 new->color[G] = color[G];
73 new->color[B] = color[B];
75 new->light_src = NULL;
77 return new;
80 int particle_add(struct particle_src *src)
82 int c, ret = -1;
83 struct particle *new;
85 /* look for free particle */
86 new = NULL;
87 for(c = 0; c < src->n_particles; c++)
88 if(src->particles[c].state == PARTICLE_STATE_DEAD)
90 new = &src->particles[c];
91 ret = c;
94 if(new == NULL)
96 /* add a new particle */
97 src->particles = realloc(src->particles,
98 (src->n_particles + 1) * sizeof(struct particle));
99 new = &src->particles[src->n_particles];
100 ret = src->n_particles;
101 src->n_particles++;
104 new->state = PARTICLE_STATE_ACTIVE;
105 new->time = 0.0;
106 MATH_COPY_VEC3(new->position, src->position);
107 MATH_COPY_VEC3(new->color, src->color);
109 new->direction[X] = src->direction[X] + src->spread * (rand() - RAND_MAX/2) / RAND_MAX;
110 new->direction[Y] = src->direction[Y] + src->spread * (rand() - RAND_MAX/2) / RAND_MAX;
111 new->direction[Z] = src->direction[Z] + src->spread * (rand() - RAND_MAX/2) / RAND_MAX;
113 new->speed = src->speed + src->speed_spread * (rand() - RAND_MAX/2) / RAND_MAX;
114 math_len_vec3(new->direction, new->direction, new->speed);
115 new->gravity = src->gravity;
117 return ret;
120 void particle_src_update(struct game *game, struct particle_src *src, float delta)
122 int c;
124 for(c = 0; c < src->n_particles; c++)
125 if(src->particles[c].state == PARTICLE_STATE_ACTIVE)
126 particle_update(game, src, c, delta);
128 if(src->particle_rate > 0.0)
130 float tmp[3];
132 src->last_particle_time += delta;
134 while(src->last_particle_time >= 1.0 / src->particle_rate)
136 int i;
137 float old_position[3];
138 int collision[2];
140 MATH_COPY_VEC3(old_position, src->position);
142 math_scale_vec3(tmp, 1.0 / src->particle_rate, src->src_speed);
143 math_add_vec3(src->position, src->position, tmp);
145 if(map_detect_collision(game, old_position, src->position, collision))
147 float vec[3], coll[3];
148 float norm;
150 math_sub_vec3(vec, old_position, src->position);
151 math_len_vec3(vec, vec, 0.6);
153 MATH_SET_VEC3(coll,
154 (float)collision[X] + 0.5,
155 -0.5,
156 (float)collision[Y] + 0.5);
157 math_add_vec3(src->position, vec, coll);
159 norm = math_norm_vec3(src->src_speed);
160 MATH_SET_VEC3(src->src_speed,
161 0.0,
162 -1.0,
163 0.0);
164 math_len_vec3(src->src_speed, src->src_speed, norm);
166 norm = math_norm_vec3(src->direction);
167 MATH_SET_VEC3(src->direction,
168 0.0,
169 1.0,
170 0.0);
171 math_len_vec3(src->direction, src->direction, norm);
174 i = particle_add(src);
175 src->last_particle_time -= 1.0 / src->particle_rate;
176 particle_update(game, src, i, src->last_particle_time);
181 void particle_update(struct game *game, struct particle_src *src, int particle_no, float delta)
183 struct particle *p;
184 float tmp[3], old_position[3];
185 int collision[2];
187 p = &src->particles[particle_no];
189 p->time += delta;
190 if(p->time >= src->particle_life + src->particle_fade)
192 p->state = PARTICLE_STATE_DEAD;
193 return;
196 MATH_COPY_VEC3(old_position, p->position);
198 math_scale_vec3(tmp, delta, p->direction);
199 math_add_vec3(p->position, p->position, tmp);
200 if(p->position[Y] < 0.0 || !map_inside(game, (int)p->position[X], (int)p->position[Z]))
201 p->direction[Y] += p->gravity * delta;
203 if(!map_inside(game, (int)p->position[X], (int)p->position[Z]))
204 return;
206 if(p->position[Y] > 0.0 && p->direction[Y] > 0.0)
207 /* hit the floor */
208 p->direction[Y] = -0.5 * p->direction[Y];
210 if(map_detect_collision(game, old_position, p->position, collision))
212 switch(MAP(game->map, collision[X], collision[Y]).wall)
214 case MAP_WALL_VERTICAL:
215 if(old_position[X] < (float)collision[X] + 0.5)
216 /* move left */
217 p->position[X] = (float)(collision[X] - 1) + 0.9;
218 else
219 /* move right */
220 p->position[X] = (float)collision[X] + 1.01;
222 /* switch horizontal speed */
223 p->direction[X] = -p->direction[X];
225 /* reduce speed */
226 math_len_vec3(p->direction, p->direction,
227 math_norm_vec3(p->direction) - 0.01);
229 break;
231 case MAP_WALL_HORIZONTAL:
232 if(old_position[Z] < (float)collision[Y] + 0.5)
233 /* move down */
234 p->position[Z] = (float)(collision[Y] - 1) + 0.9;
235 else
236 /* move up */
237 p->position[Z] = (float)collision[Y] + 1.01;
239 /* switch vertical speed */
240 p->direction[Z] = -p->direction[Z];
242 /* reduce speed */
244 math_len_vec3(p->direction, p->direction,
245 math_norm_vec3(p->direction) - 0.01);
247 break;
252 void particle_free_src(struct particle_src *src)
254 if(src->particles)
255 free(src->particles);
257 free(src);
260 int particle_src_all_dead(struct particle_src *src)
262 int c;
264 for(c = 0; c < src->n_particles; c++)
265 if(src->particles[c].state == PARTICLE_STATE_ACTIVE)
266 return 0;
268 return 1;
271 void particle_src_explode(struct particle_src *src, int num_particles_explosion, float max_speed)
273 float saved_position[3], saved_direction[3], saved_color[3], saved_speed, saved_gravity;
274 int c;
276 MATH_COPY_VEC3(saved_position, src->position);
277 MATH_COPY_VEC3(saved_direction, src->direction);
278 MATH_COPY_VEC3(saved_color, src->color);
279 saved_speed = src->speed;
280 saved_gravity = src->gravity;
282 src->particle_size /= 2.0;
283 src->gravity = 5.0;
285 for(c = 0; c < num_particles_explosion; c++)
287 src->color[R] = 0.9 + (rand() / (float)RAND_MAX) * 0.1;
288 src->color[G] = 0.7 + (rand() / (float)RAND_MAX) * 0.2;
289 src->color[B] = 0.5 + (rand() / (float)RAND_MAX) * 0.1;
291 src->direction[X] = (rand() / (float)RAND_MAX) * 2.0 - 1.0;
292 src->direction[Y] = (rand() / (float)RAND_MAX) * 2.0 - 2.0;
293 src->direction[Z] = (rand() / (float)RAND_MAX) * 2.0 - 1.0;
295 src->speed = (rand() / (float)RAND_MAX) * max_speed;
297 particle_add(src);
300 MATH_COPY_VEC3(src->direction, saved_direction);
301 src->speed = saved_speed;
302 src->gravity = saved_gravity;
303 src->particle_size *= 2.0;