Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_particles.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
27#include "nilorea/n_particles.h"
28#include "math.h"
29
40int init_particle_system(PARTICLE_SYSTEM** psys, int max, double x, double y, double z, int max_sprites) {
41 __n_assert(!(*psys), n_log(LOG_ERR, "particle system %p already initialized", (*psys)); return FALSE);
42
43 Malloc((*psys), PARTICLE_SYSTEM, 1);
44 __n_assert((*psys), return FALSE);
45
46 start_HiTimer(&(*psys)->timer);
47
48 size_t list_max = (max <= 0) ? UNLIMITED_LIST_ITEMS : (size_t)max;
49 (*psys)->list = new_generic_list(list_max);
50
51 (*psys)->source[0] = x;
52 (*psys)->source[1] = y;
53 (*psys)->source[2] = z;
54
55 if (max_sprites > 0)
56 (*psys)->sprites = (ALLEGRO_BITMAP**)calloc((size_t)max_sprites, sizeof(ALLEGRO_BITMAP*));
57 else
58 (*psys)->sprites = NULL;
59
60 (*psys)->max_sprites = max_sprites;
61
62 (*psys)->emitters = new_generic_list(UNLIMITED_LIST_ITEMS);
63
64 return TRUE;
65} /* init_particle_system() */
66
78int add_particle(PARTICLE_SYSTEM* psys, int spr, int mode, int lifetime, int size, ALLEGRO_COLOR color, PHYSICS object) {
79 int it = 0;
80
81 PARTICLE* new_p = NULL;
82
83 /* nb_max_items == 0 means unlimited (matches list_push behavior) */
84 if (psys->list->nb_max_items > 0 && psys->list->nb_items >= psys->list->nb_max_items)
85 return FALSE;
86
87 for (it = 0; it < 3; it++) {
88 object.position[it] += psys->source[it];
89 }
90
91 Malloc(new_p, PARTICLE, 1);
92 __n_assert(new_p, return FALSE);
93
94 new_p->depth_sort = 1; /* default: depth-sorted */
95 new_p->spr_id = spr;
96 new_p->mode = mode;
97 new_p->lifetime = lifetime;
98 new_p->color = color;
99 new_p->size = size;
100
101 /* Initialize extended fields for backward compatibility:
102 * color_start == color_end means no lerp, age starts at 0 */
103 new_p->color_start = color;
104 new_p->color_end = color;
105 new_p->age = 0;
106 new_p->lifetime_max = lifetime;
107 new_p->size_start = size;
108 new_p->size_end = size;
109
110 memcpy(&new_p->object, &object, sizeof(PHYSICS));
111
112 return list_push(psys->list, new_p, &free);
113} /* add_particle() */
114
133int add_particle_ex(PARTICLE_SYSTEM* psys, int spr, int mode, int off_x, int off_y, int lifetime, int size, ALLEGRO_COLOR color, double vx, double vy, double vz, double ax, double ay, double az) {
134 PHYSICS object;
135 memset(&object, 0, sizeof(PHYSICS));
136 VECTOR3D_SET(object.position, off_x, off_y, 0.0);
137 VECTOR3D_SET(object.speed, vx, vy, vz);
138 VECTOR3D_SET(object.acceleration, ax, ay, az);
139 VECTOR3D_SET(object.orientation, 0.0, 0.0, 0.0);
140 VECTOR3D_SET(object.angular_speed, 0.0, 0.0, 0.0);
141 VECTOR3D_SET(object.angular_acceleration, 0.0, 0.0, 0.0);
142
143 return add_particle(psys, spr, mode, lifetime, size, color, object);
144} /* add_particle_ex () */
145
146/* NOTE: manage_particle_ex delta_t is in MICROSECONDS, matching
147 * update_physics_position() and the internal get_usec() timer.
148 * The header doc says "msecs" but the actual unit is microseconds.
149 * Lifetime and age fields on PARTICLE are in milliseconds. */
150
157static void _emitter_shape_offset(const PARTICLE_EMITTER* em, double* out_x, double* out_y) {
158 double ox = 0.0, oy = 0.0;
159 switch (em->shape) {
160 case 1: { /* line: random point along line of shape_w length */
161 double t = ((double)rand() / (double)RAND_MAX) - 0.5; /* -0.5..0.5 */
162 ox = t * em->shape_w;
163 oy = 0.0;
164 break;
165 }
166 case 2: { /* rect: random point in rectangle shape_w x shape_h */
167 double tx = ((double)rand() / (double)RAND_MAX) - 0.5;
168 double ty = ((double)rand() / (double)RAND_MAX) - 0.5;
169 ox = tx * em->shape_w;
170 oy = ty * em->shape_h;
171 break;
172 }
173 case 3: { /* circle: random point in circle of radius shape_w */
174 double angle = ((double)rand() / (double)RAND_MAX) * 2.0 * 3.14159265358979;
175 double r = sqrt((double)rand() / (double)RAND_MAX) * em->shape_w;
176 ox = cos(angle) * r;
177 oy = sin(angle) * r;
178 break;
179 }
180 default: /* point: no offset */
181 break;
182 }
183 /* Apply rotation */
184 if (em->shape_rotation != 0.0) {
185 double cr = cos(em->shape_rotation);
186 double sr = sin(em->shape_rotation);
187 double rx = ox * cr - oy * sr;
188 double ry = ox * sr + oy * cr;
189 ox = rx;
190 oy = ry;
191 }
192 *out_x = ox;
193 *out_y = oy;
194}
195
202static double _particle_rand_range(double vmin, double vmax) {
203 if (vmin >= vmax) return vmin;
204 return vmin + ((double)rand() / (double)RAND_MAX) * (vmax - vmin);
205}
206
213static int _particle_rand_range_i(int imin, int imax) {
214 if (imin >= imax) return imin;
215 return imin + (rand() % (imax - imin + 1));
216}
217
225static ALLEGRO_COLOR _color_lerp(ALLEGRO_COLOR a, ALLEGRO_COLOR b, float t) {
226 float ar, ag, ab, aa, br, bg, bb, ba;
227 al_unmap_rgba_f(a, &ar, &ag, &ab, &aa);
228 al_unmap_rgba_f(b, &br, &bg, &bb, &ba);
229 return al_map_rgba_f(ar + (br - ar) * t,
230 ag + (bg - ag) * t,
231 ab + (bb - ab) * t,
232 aa + (ba - aa) * t);
233}
234
241int manage_particle_ex(PARTICLE_SYSTEM* psys, double delta_t) {
242 __n_assert(psys, return FALSE);
243
244 /* --- Emitter spawning phase --- */
245 if (psys->emitters) {
246 LIST_NODE* em_node = psys->emitters->start;
247 while (em_node) {
248 PARTICLE_EMITTER* em = (PARTICLE_EMITTER*)em_node->ptr;
249 if (!em || !em->active) {
250 em_node = em_node->next;
251 continue;
252 }
253
254 if (em->burst_count > 0) {
255 /* Burst mode: emit all at once then deactivate */
256 for (int bi = 0; bi < em->burst_count; bi++) {
257 /* Enforce max_particles limit */
258 if (em->max_particles > 0 && em->live_count >= em->max_particles) break;
260 double vx = _particle_rand_range(em->velocity_min[0], em->velocity_max[0]);
261 double vy = _particle_rand_range(em->velocity_min[1], em->velocity_max[1]);
262 double vz = _particle_rand_range(em->velocity_min[2], em->velocity_max[2]);
263 double sox = 0.0, soy = 0.0;
264 _emitter_shape_offset(em, &sox, &soy);
265 add_particle_at(psys, em->spr_id, em->particle_mode,
266 em->position[0] + sox, em->position[1] + soy, em->position[2],
267 lt, em->size_start, em->size_end,
268 em->color_start, em->color_end,
269 vx, vy, vz,
270 em->acceleration[0], em->acceleration[1], em->acceleration[2]);
271 /* Set per-particle flags and back-pointer from emitter */
272 if (psys->list->end) {
273 PARTICLE* np = (PARTICLE*)psys->list->end->ptr;
274 if (np) {
275 np->additive = em->additive_blend;
276 np->depth_sort = em->depth_sort;
277 np->emitter = em;
278 em->live_count++;
279 }
280 }
281 }
282 em->active = 0;
283 } else {
284 /* Continuous mode: accumulate particles over time.
285 * delta_t is in microseconds, emit_rate is particles/second */
286 em->emit_accumulator += em->emit_rate * delta_t / 1000000.0;
287 while (em->emit_accumulator >= 1.0) {
288 /* Enforce max_particles limit */
289 if (em->max_particles > 0 && em->live_count >= em->max_particles) {
290 em->emit_accumulator = 0.0;
291 break;
292 }
293 em->emit_accumulator -= 1.0;
295 double vx = _particle_rand_range(em->velocity_min[0], em->velocity_max[0]);
296 double vy = _particle_rand_range(em->velocity_min[1], em->velocity_max[1]);
297 double vz = _particle_rand_range(em->velocity_min[2], em->velocity_max[2]);
298 double sox = 0.0, soy = 0.0;
299 _emitter_shape_offset(em, &sox, &soy);
300 add_particle_at(psys, em->spr_id, em->particle_mode,
301 em->position[0] + sox, em->position[1] + soy, em->position[2],
302 lt, em->size_start, em->size_end,
303 em->color_start, em->color_end,
304 vx, vy, vz,
305 em->acceleration[0], em->acceleration[1], em->acceleration[2]);
306 if (psys->list->end) {
307 PARTICLE* np = (PARTICLE*)psys->list->end->ptr;
308 if (np) {
309 np->additive = em->additive_blend;
310 np->depth_sort = em->depth_sort;
311 np->emitter = em;
312 em->live_count++;
313 }
314 }
315 }
316 }
317 em_node = em_node->next;
318 }
319 }
320
321 /* --- Particle tick phase --- */
322 LIST_NODE* node = psys->list->start;
323
324 while (node) {
325 PARTICLE* ptr = (PARTICLE*)node->ptr;
326 if (ptr->lifetime == -1) {
327 /* infinite lifetime: just update position */
328 update_physics_position(&ptr->object, delta_t);
329 node = node->next;
330 } else {
331 ptr->lifetime = (int)(ptr->lifetime - (delta_t / 1000.0));
332 if (ptr->lifetime > 0) {
333 update_physics_position(&ptr->object, delta_t);
334
335 /* Update age and lerp color/size.
336 * delta_t is in microseconds; age/lifetime are in milliseconds */
337 ptr->age += (int)(delta_t / 1000.0);
338 if (ptr->lifetime_max > 0) {
339 double ratio = (double)ptr->age / (double)ptr->lifetime_max;
340 if (ratio > 1.0) ratio = 1.0;
341 ptr->color = _color_lerp(ptr->color_start, ptr->color_end, (float)ratio);
342 ptr->size = ptr->size_start + (int)((double)(ptr->size_end - ptr->size_start) * ratio);
343 }
344
345 node = node->next;
346 } else {
347 LIST_NODE* node_to_kill = node;
348 node = node->next;
349 /* Decrement owning emitter's live count */
350 if (ptr->emitter) {
351 ptr->emitter->live_count--;
352 if (ptr->emitter->live_count < 0) ptr->emitter->live_count = 0;
353 }
354 ptr = remove_list_node(psys->list, node_to_kill, PARTICLE);
355 Free(ptr);
356 }
357 }
358 }
359
360 return TRUE;
361} /* manage_particle_ex() */
362
369 __n_assert(psys, return FALSE);
370
371 double delta_t = (double)get_usec(&psys->timer);
372 return manage_particle_ex(psys, delta_t);
373} /* manage_particle() */
374
385int draw_particle(PARTICLE_SYSTEM* psys, double xpos, double ypos, int w, int h, double range) {
386 __n_assert(psys, return FALSE);
387
388 LIST_NODE* node = NULL;
389 PARTICLE* ptr = NULL;
390
391 node = psys->list->start;
392
393 while (node) {
394 double x = 0, y = 0;
395
396 ptr = (PARTICLE*)node->ptr;
397 x = ptr->object.position[0] - xpos;
398 y = ptr->object.position[1] - ypos;
399
400 if ((x < -range) || (x > (w + range)) || (y < -range) || (y > (h + range))) {
401 node = node->next;
402 continue;
403 }
404
405 for (int it = 0; it < 3; it++) {
406 while (ptr->object.orientation[it] < 0.0)
407 ptr->object.orientation[it] += 256.0;
408
409 if (ptr->object.orientation[it] >= 256.0)
410 ptr->object.orientation[it] = fmod(ptr->object.orientation[it], 256.0);
411 }
412
413 if (ptr->mode == SINUS_PART) {
414 if (ptr->object.speed[0] != 0)
415 x = x + ptr->object.speed[0] * sin((ptr->object.position[0] / ptr->object.speed[0]));
416 else
417 x = x + ptr->object.speed[0] * sin(ptr->object.position[0]);
418
419 if (ptr->object.speed[1] != 0)
420 y = y + ptr->object.speed[1] * cos((ptr->object.position[1] / ptr->object.speed[1]));
421 else
422 y = y + ptr->object.speed[1] * sin(ptr->object.position[1]);
423
424 if (ptr->spr_id >= 0 && ptr->spr_id < psys->max_sprites && psys->sprites[ptr->spr_id]) {
425 int spr_w = al_get_bitmap_width(psys->sprites[ptr->spr_id]);
426 int spr_h = al_get_bitmap_height(psys->sprites[ptr->spr_id]);
427
428 al_draw_rotated_bitmap(psys->sprites[ptr->spr_id], (float)(spr_w / 2), (float)(spr_h / 2), (float)(x - spr_w / 2), (float)(y - spr_h / 2), (float)(ptr->object.orientation[2] * (2.0 * M_PI / 256.0)), 0);
429 } else
430 al_draw_circle((float)x, (float)y, (float)ptr->size, ptr->color, 1);
431 }
432
433 if (ptr->mode & NORMAL_PART) {
434 if (ptr->spr_id >= 0 && ptr->spr_id < psys->max_sprites && psys->sprites[ptr->spr_id]) {
435 int bmp_w = al_get_bitmap_width(psys->sprites[ptr->spr_id]);
436 int bmp_h = al_get_bitmap_height(psys->sprites[ptr->spr_id]);
437
438 al_draw_rotated_bitmap(psys->sprites[ptr->spr_id], (float)(bmp_w / 2), (float)(bmp_h / 2), (float)(x - bmp_w / 2), (float)(y - bmp_h / 2), (float)(ptr->object.orientation[2] * (2.0 * M_PI / 256.0)), 0);
439 } else
440 al_draw_circle((float)x, (float)y, (float)ptr->size, ptr->color, 1);
441 } else if (ptr->mode & PIXEL_PART) {
442 al_draw_filled_rectangle((float)(x - ptr->size), (float)(y - ptr->size), (float)(x + ptr->size), (float)(y + ptr->size), ptr->color);
443 } else
444 al_draw_circle((float)x, (float)y, (float)ptr->size, ptr->color, 1);
445 node = node->next;
446 }
447
448 return TRUE;
449} /* draw_particle() */
450
457 __n_assert((*psys), return FALSE);
458
459 while ((*psys)->list->start) {
460 PARTICLE* particle = remove_list_node((*psys)->list, (*psys)->list->start, PARTICLE);
461 Free(particle);
462 }
463 list_destroy(&(*psys)->list);
464 free_emitters((*psys));
465 list_destroy(&(*psys)->emitters);
466 FreeNoLog((*psys)->sprites);
467 Free((*psys));
468
469 return TRUE;
470} /* free_particle_system() */
471
480int move_particles(PARTICLE_SYSTEM* psys, double vx, double vy, double vz) {
481 __n_assert(psys, return FALSE);
482
483 LIST_NODE* node = NULL;
484 PARTICLE* ptr = NULL;
485
486 node = psys->list->start;
487
488 while (node) {
489 ptr = (PARTICLE*)node->ptr;
490 ptr->object.position[0] = ptr->object.position[0] + vx;
491 ptr->object.position[1] = ptr->object.position[1] + vy;
492 ptr->object.position[2] = ptr->object.position[2] + vz;
493 node = node->next;
494 }
495 return TRUE;
496} /* move_particles() */
497
504 __n_assert(psys, return NULL);
505 __n_assert(psys->emitters, return NULL);
506
507 PARTICLE_EMITTER* em = NULL;
508 Malloc(em, PARTICLE_EMITTER, 1);
509 __n_assert(em, return NULL);
510
511 memset(em, 0, sizeof(PARTICLE_EMITTER));
512 em->attached_entity_id = -1;
513 em->spr_id = -1;
514 em->depth_sort = 1; /* default: depth-sorted (caller can override to 0 for overlay) */
515
516 if (!list_push(psys->emitters, em, &free)) {
517 Free(em);
518 return NULL;
519 }
520
521 return em;
522} /* add_emitter() */
523
531 __n_assert(psys, return FALSE);
532 __n_assert(psys->emitters, return FALSE);
533 __n_assert(em, return FALSE);
534
535 /* Clear back-pointers on any particles owned by this emitter */
536 LIST_NODE* pnode = psys->list ? psys->list->start : NULL;
537 while (pnode) {
538 PARTICLE* p = (PARTICLE*)pnode->ptr;
539 if (p && p->emitter == em) {
540 p->emitter = NULL;
541 }
542 pnode = pnode->next;
543 }
544
545 LIST_NODE* node = psys->emitters->start;
546 while (node) {
547 if (node->ptr == em) {
549 Free(removed);
550 return TRUE;
551 }
552 node = node->next;
553 }
554 return FALSE;
555} /* remove_emitter() */
556
563 __n_assert(psys, return FALSE);
564 if (!psys->emitters) return TRUE;
565
566 while (psys->emitters->start) {
568 Free(em);
569 }
570 return TRUE;
571} /* free_emitters() */
572
594int add_particle_at(PARTICLE_SYSTEM* psys, int spr, int mode, double px, double py, double pz, int lifetime, int size_start, int size_end, ALLEGRO_COLOR color_start, ALLEGRO_COLOR color_end, double vx, double vy, double vz, double ax, double ay, double az) {
595 __n_assert(psys, return FALSE);
596
597 /* nb_max_items == 0 means unlimited (matches list_push behavior) */
598 if (psys->list->nb_max_items > 0 && psys->list->nb_items >= psys->list->nb_max_items)
599 return FALSE;
600
601 PARTICLE* new_p = NULL;
602 Malloc(new_p, PARTICLE, 1);
603 __n_assert(new_p, return FALSE);
604
605 new_p->depth_sort = 1;
606 new_p->spr_id = spr;
607 new_p->mode = mode;
608 new_p->lifetime = lifetime;
609 new_p->lifetime_max = lifetime;
610 new_p->age = 0;
611 new_p->color = color_start;
612 new_p->color_start = color_start;
613 new_p->color_end = color_end;
614 new_p->size = size_start;
615 new_p->size_start = size_start;
616 new_p->size_end = size_end;
617
618 VECTOR3D_SET(new_p->object.position, px, py, pz);
619 VECTOR3D_SET(new_p->object.speed, vx, vy, vz);
620 VECTOR3D_SET(new_p->object.acceleration, ax, ay, az);
621 VECTOR3D_SET(new_p->object.orientation, 0.0, 0.0, 0.0);
622 VECTOR3D_SET(new_p->object.angular_speed, 0.0, 0.0, 0.0);
623 VECTOR3D_SET(new_p->object.angular_acceleration, 0.0, 0.0, 0.0);
624
625 return list_push(psys->list, new_p, &free);
626} /* add_particle_at() */
static int mode
#define M_PI
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:271
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:203
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:278
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:262
LIST_NODE * end
pointer to the end of the list
Definition n_list.h:67
void * ptr
void pointer to store
Definition n_list.h:45
size_t nb_max_items
Maximum number of items in the list.
Definition n_list.h:62
LIST_NODE * start
pointer to the start of the list
Definition n_list.h:65
size_t nb_items
number of item currently in the list
Definition n_list.h:60
struct LIST_NODE * next
pointer to the next node
Definition n_list.h:51
#define UNLIMITED_LIST_ITEMS
flag to pass to new_generic_list for an unlimited number of item in the list.
Definition n_list.h:72
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:227
#define remove_list_node(__LIST_, __NODE_, __TYPE_)
Remove macro helper for void pointer casting.
Definition n_list.h:97
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:547
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:36
Structure of a generic list node.
Definition n_list.h:43
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:88
#define LOG_ERR
error conditions
Definition n_log.h:75
int start_HiTimer(N_TIME *timer)
Initialize or restart from zero any N_TIME HiTimer.
Definition n_time.c:84
time_t get_usec(N_TIME *timer)
Poll any N_TIME HiTimer, returning usec, and moving currentTime to startTime.
Definition n_time.c:106
double shape_h
shape dimension 2: rect height (world units)
int size_start
particle size at birth
Definition n_particles.h:99
int particle_mode
particle draw mode (NORMAL_PART, CIRCLE_PART, PIXEL_PART, FIRE_PART, etc.)
N_TIME timer
Internal: particle system timer.
LIST * emitters
list of PARTICLE_EMITTER pointers
int size
current size of particle
Definition n_particles.h:82
int max_sprites
size of the picture library
VECTOR3D velocity_max
random velocity range max
ALLEGRO_COLOR color
color of the particle
Definition n_particles.h:85
ALLEGRO_COLOR color_end
end color for lerp
Definition n_particles.h:93
int additive
1=additive blend, 0=normal alpha
int depth_sort
1=depth-sorted with terrain, 0=flat overlay after iso pass
int active
1=emitting, 0=paused
PHYSICS object
particle physical properties
Definition n_particles.h:88
int spr_id
sprite id in library
Definition n_particles.h:80
int size_end
particle size at death
int lifetime
lifetime (counts down, msecs)
Definition n_particles.h:78
ALLEGRO_COLOR color_start
particle start color
ALLEGRO_COLOR color_end
particle end color (lerp over lifetime)
int shape
emission shape: 0=point, 1=line, 2=rect, 3=circle
VECTOR3D velocity_min
random velocity range min
int live_count
current live particle count for this emitter (managed by system)
VECTOR3D source
Coordinate of emitting point (used by add_particle/add_particle_ex)
double emit_accumulator
internal: fractional particle accumulator
VECTOR3D position
emitter world position
int size_start
particle size at birth
LIST * list
list of PARTICLE pointers
int attached_entity_id
-1=not attached, >=0=entity id
int spr_id
sprite id or -1
struct PARTICLE_EMITTER * emitter
back-pointer to owning emitter (NULL if spawned manually)
int mode
particle mode: NORMAL_PART,SINUS_PART,PIXEL_PART
Definition n_particles.h:76
double emit_rate
particles per second (continuous mode)
int max_particles
per-emitter particle cap (0=unlimited)
ALLEGRO_BITMAP ** sprites
Library of picture for the particles.
int lifetime_min
particle lifetime range min (msecs)
int lifetime_max
original lifetime at birth (needed for lerp ratio = age/lifetime_max)
Definition n_particles.h:97
int size_end
particle size at death
double shape_rotation
shape rotation in radians
int depth_sort
1=depth-sorted with terrain, 0=flat overlay
double shape_w
shape dimension 1: line length, rect width, or circle radius (world units)
int lifetime_max
particle lifetime range max (msecs)
int burst_count
if >0, emit this many instantly then deactivate
ALLEGRO_COLOR color_start
start color for lerp (set by emitter, ignored if color_start == color_end)
Definition n_particles.h:91
VECTOR3D acceleration
constant acceleration (gravity etc.)
int additive_blend
1=additive blend, 0=normal alpha blend
int age
current age in msecs (incremented by manage_particle_ex)
Definition n_particles.h:95
int draw_particle(PARTICLE_SYSTEM *psys, double xpos, double ypos, int w, int h, double range)
draw particles of a particle system
#define NORMAL_PART
classic moving particle
Definition n_particles.h:53
int add_particle_at(PARTICLE_SYSTEM *psys, int spr, int mode, double px, double py, double pz, int lifetime, int size_start, int size_end, ALLEGRO_COLOR color_start, ALLEGRO_COLOR color_end, double vx, double vy, double vz, double ax, double ay, double az)
add a particle at an absolute world position (not relative to psys->source)
int move_particles(PARTICLE_SYSTEM *psys, double vx, double vy, double vz)
move all particles of a particle system by a given offset
PARTICLE_EMITTER * add_emitter(PARTICLE_SYSTEM *psys)
add a new emitter to the particle system
#define PIXEL_PART
pixel particle
Definition n_particles.h:67
int free_emitters(PARTICLE_SYSTEM *psys)
free all emitters in the particle system
int manage_particle_ex(PARTICLE_SYSTEM *psys, double delta_t)
update particles positions using provided delta time
int remove_emitter(PARTICLE_SYSTEM *psys, const PARTICLE_EMITTER *em)
remove an emitter from the particle system and free it
int free_particle_system(PARTICLE_SYSTEM **psys)
destroy and free a particle system
int manage_particle(PARTICLE_SYSTEM *psys)
update particles positions using particle system internal timer
#define SINUS_PART
sinus based moving particle
Definition n_particles.h:55
int add_particle_ex(PARTICLE_SYSTEM *psys, int spr, int mode, int off_x, int off_y, int lifetime, int size, ALLEGRO_COLOR color, double vx, double vy, double vz, double ax, double ay, double az)
add a particle to a particle system, all in line version (you have to set the PHYSICS object paramete...
int add_particle(PARTICLE_SYSTEM *psys, int spr, int mode, int lifetime, int size, ALLEGRO_COLOR color, PHYSICS object)
add a particle to a particle system
Definition n_particles.c:78
int init_particle_system(PARTICLE_SYSTEM **psys, int max, double x, double y, double z, int max_sprites)
initialize a particle system
Definition n_particles.c:40
Structure of a single particle.
Definition n_particles.h:74
Structure of a particle emitter.
Structure of a particle system.
VECTOR3D speed
vx,vy,vz actual speed
Definition n_3d.h:75
VECTOR3D orientation
ax,ay,az actual rotation position
Definition n_3d.h:79
VECTOR3D position
x,y,z actual position
Definition n_3d.h:73
VECTOR3D acceleration
ax,ay,az actual acceleration
Definition n_3d.h:77
VECTOR3D angular_acceleration
rax,ray,raz actual angular acceleration
Definition n_3d.h:83
VECTOR3D angular_speed
rvx,rvy,rvz actual angular speed
Definition n_3d.h:81
#define VECTOR3D_SET(VECTOR, X, Y, Z)
helper to set a VECTOR3D position
Definition n_3d.h:61
int update_physics_position(PHYSICS *object, double delta_t)
Update object position.
Definition n_3d.c:105
structure of the physics of an object
Definition n_3d.h:69
static double _particle_rand_range(double vmin, double vmax)
helper to generate a random double between min and max
static ALLEGRO_COLOR _color_lerp(ALLEGRO_COLOR a, ALLEGRO_COLOR b, float t)
helper to linearly interpolate a color
static void _emitter_shape_offset(const PARTICLE_EMITTER *em, double *out_x, double *out_y)
compute shape-offset spawn position for an emitter
static int _particle_rand_range_i(int imin, int imax)
helper to generate a random int between min and max (inclusive)
Particles management.