Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_fluids.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
26#include <math.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <stdint.h>
30#include <stdbool.h>
31#include <strings.h>
32#include "nilorea/n_fluids.h"
33#include "nilorea/n_common.h"
35
37#define N_FLUID_U_FIELD 0
39#define N_FLUID_V_FIELD 1
41#define N_FLUID_S_FIELD 2
42
50void n_memset(void* dst, const void* val, size_t size, size_t count) {
51 char* ptr = (char*)dst;
52 while (count-- > 0) {
53 memcpy(ptr, val, size);
54 ptr += size;
55 }
56}
57
64 __n_assert((*fluid), return FALSE);
65
66 list_destroy(&(*fluid)->integrate_chunk_list);
67 list_destroy(&(*fluid)->solveIncompressibility_chunk_list);
68 list_destroy(&(*fluid)->advectVel_chunk_list);
69 list_destroy(&(*fluid)->advectSmoke_chunk_list);
70
71 FreeNoLog((*fluid)->u);
72 FreeNoLog((*fluid)->newU);
73 FreeNoLog((*fluid)->v);
74 FreeNoLog((*fluid)->newV);
75 FreeNoLog((*fluid)->p);
76 FreeNoLog((*fluid)->s);
77 FreeNoLog((*fluid)->m);
78 FreeNoLog((*fluid)->newM);
79 FreeNoLog((*fluid));
80
81 return TRUE;
82}
83
95N_FLUID* new_n_fluid(double density, double gravity, size_t numIters, double dt, double overRelaxation, size_t sx, size_t sy) {
96 N_FLUID* fluid = NULL;
97
98 Malloc(fluid, N_FLUID, 1);
99 __n_assert(fluid, return NULL);
100
101 fluid->density = density;
102 fluid->gravity = gravity;
103 fluid->numIters = numIters;
104 fluid->dt = dt;
105 fluid->h = 1.0 / 100.0;
106 fluid->overRelaxation = overRelaxation;
107 fluid->numX = sx + 2;
108 fluid->numY = sy + 2;
109 fluid->numZ = 1; /* Z expansion not yet implemented */
110 fluid->numCells = fluid->numX * fluid->numY * fluid->numZ;
111
112 Malloc(fluid->u, double, fluid->numCells);
113 if (!fluid->u) goto cleanup_fluid;
114 Malloc(fluid->newU, double, fluid->numCells);
115 if (!fluid->newU) goto cleanup_fluid;
116 Malloc(fluid->v, double, fluid->numCells);
117 if (!fluid->v) goto cleanup_fluid;
118 Malloc(fluid->newV, double, fluid->numCells);
119 if (!fluid->newV) goto cleanup_fluid;
120 Malloc(fluid->p, double, fluid->numCells);
121 if (!fluid->p) goto cleanup_fluid;
122 Malloc(fluid->s, double, fluid->numCells);
123 if (!fluid->s) goto cleanup_fluid;
124 Malloc(fluid->m, double, fluid->numCells);
125 if (!fluid->m) goto cleanup_fluid;
126 Malloc(fluid->newM, double, fluid->numCells);
127 if (!fluid->newM) goto cleanup_fluid;
128
129 fluid->showSmoke = 1;
130 fluid->showPressure = 0;
131 fluid->showPaint = 0;
132 fluid->fluid_production_percentage = 0.1;
133 fluid->cScale = 16.0;
134 // double precision. Taking 'value', if( fabs( value ) < float_tolerance ) value is considered as zero
135 fluid->negative_float_tolerance = -0.00001;
136 fluid->positive_float_tolerance = 0.00001;
137
138 double d_val = 1.0;
139 n_memset(fluid->m, &d_val, sizeof(d_val), fluid->numCells);
140
141 long int nb_cores_l = get_nb_cpu_cores();
142 if (nb_cores_l <= 0) {
143 nb_cores_l = 1;
144 }
145 size_t nb_cores = (size_t)nb_cores_l;
146
147 // precalculate and allocated N_PROC_PARAMS lists for threaded computing
148 fluid->integrate_chunk_list = new_generic_list(nb_cores);
150 fluid->advectVel_chunk_list = new_generic_list(nb_cores);
151 fluid->advectSmoke_chunk_list = new_generic_list(nb_cores);
152
153 size_t steps = (fluid->numX / nb_cores > 0) ? fluid->numX / nb_cores : 1;
154
155 N_FLUID_THREAD_PARAMS* params = NULL;
156 /* integrate */
157 for (size_t i = 1; i < fluid->numX - 1; i += steps) {
158 Malloc(params, N_FLUID_THREAD_PARAMS, 1);
159 params->ptr = fluid;
160 params->x_start = i;
161 params->x_end = i + steps;
162 params->y_start = 1;
163 params->y_end = fluid->numY - 1;
164 list_push(fluid->integrate_chunk_list, params, &free);
165 }
166 /* set the last batch to cover the full x range */
167 if (fluid->integrate_chunk_list->end) {
169 params->x_end = fluid->numX;
170 }
171
172 /* solveIncompressibility */
173 for (size_t i = 1; i < fluid->numX - 1; i += steps) {
174 Malloc(params, N_FLUID_THREAD_PARAMS, 1);
175 params->ptr = fluid;
176 params->x_start = i;
177 params->x_end = i + steps;
178 params->y_start = 1;
179 params->y_end = fluid->numY - 1;
180 list_push(fluid->solveIncompressibility_chunk_list, params, &free);
181 }
182 /* set the last batch to cover the full x range */
185 params->x_end = fluid->numX - 1;
186 }
187
188 /* advectVel */
189 for (size_t i = 1; i < fluid->numX - 1; i += steps) {
190 Malloc(params, N_FLUID_THREAD_PARAMS, 1);
191 params->ptr = fluid;
192 params->x_start = i;
193 params->x_end = i + steps;
194 params->y_start = 1;
195 params->y_end = fluid->numY;
196 list_push(fluid->advectVel_chunk_list, params, &free);
197 }
198 /* set the last batch to cover the full x range */
199 if (fluid->advectVel_chunk_list->end) {
201 params->x_end = fluid->numX;
202 }
203
204 /* advectSmoke */
205 for (size_t i = 1; i < fluid->numX - 1; i += steps) {
206 Malloc(params, N_FLUID_THREAD_PARAMS, 1);
207 params->ptr = fluid;
208 params->x_start = i;
209 params->x_end = i + steps;
210 params->y_start = 1;
211 params->y_end = fluid->numY - 1;
212 list_push(fluid->advectSmoke_chunk_list, params, &free);
213 }
214 /* set the last batch to cover the full x range */
215 if (fluid->advectSmoke_chunk_list->end) {
217 params->x_end = fluid->numX - 1;
218 }
219
220 return fluid;
221
222cleanup_fluid:
223 FreeNoLog(fluid->u);
224 FreeNoLog(fluid->newU);
225 FreeNoLog(fluid->v);
226 FreeNoLog(fluid->newV);
227 FreeNoLog(fluid->p);
228 FreeNoLog(fluid->s);
229 FreeNoLog(fluid->m);
230 FreeNoLog(fluid->newM);
231 FreeNoLog(fluid);
232 return NULL;
233} /* new_n_fluid */
234
240void* n_fluid_integrate_proc(void* ptr) {
242 N_FLUID* fluid = (N_FLUID*)params->ptr;
243
244 size_t n = fluid->numY;
245 for (size_t i = params->x_start; i < params->x_end; i++) {
246 for (size_t j = params->y_start; j < params->y_end; j++) {
247 if (!_z(fluid, s[i * n + j]) && !_z(fluid, s[i * n + j - 1]))
248 fluid->v[i * n + j] += fluid->gravity * fluid->dt;
249 }
250 }
251 return NULL;
252}
253
260 __n_assert(fluid, return FALSE);
261
262 size_t n = fluid->numY;
263 for (size_t i = 1; i < fluid->numX; i++) {
264 for (size_t j = 1; j < fluid->numY - 1; j++) {
265 if (!_z(fluid, s[i * n + j]) && !_z(fluid, s[i * n + j - 1]))
266 fluid->v[i * n + j] += fluid->gravity * fluid->dt;
267 }
268 }
269 return TRUE;
270}
271
279 N_FLUID* fluid = (N_FLUID*)params->ptr;
280
281 double cp = (fluid->density * fluid->h) / fluid->dt;
282
283 size_t n = fluid->numY;
284 for (size_t i = params->x_start; i < params->x_end; i++) {
285 for (size_t j = params->y_start; j < params->y_end; j++) {
286 if (_z(fluid, s[i * n + j]))
287 continue;
288
289 double sx0 = fluid->s[(i - 1) * n + j];
290 double sx1 = fluid->s[(i + 1) * n + j];
291 double sy0 = fluid->s[i * n + j - 1];
292 double sy1 = fluid->s[i * n + j + 1];
293 double s = sx0 + sx1 + sy0 + sy1;
294 if (_zd(fluid, s))
295 continue;
296
297 double div = fluid->u[(i + 1) * n + j] - fluid->u[i * n + j] + fluid->v[i * n + j + 1] - fluid->v[i * n + j];
298 double p = (-div * fluid->overRelaxation) / s;
299 fluid->p[i * n + j] += cp * p;
300 fluid->u[i * n + j] -= sx0 * p;
301 fluid->u[(i + 1) * n + j] += sx1 * p;
302 fluid->v[i * n + j] -= sy0 * p;
303 fluid->v[i * n + j + 1] += sy1 * p;
304 }
305 }
306 return NULL;
307}
308
315 __n_assert(fluid, return FALSE);
316 size_t n = fluid->numY;
317
318 double cp = (fluid->density * fluid->h) / fluid->dt;
319
320 for (size_t iter = 0; iter < fluid->numIters; iter++) {
321 for (size_t i = 1; i < fluid->numX - 1; i++) {
322 for (size_t j = 1; j < fluid->numY - 1; j++) {
323 if (_z(fluid, s[i * n + j]))
324 continue;
325
326 double sx0 = fluid->s[(i - 1) * n + j];
327 double sx1 = fluid->s[(i + 1) * n + j];
328 double sy0 = fluid->s[i * n + j - 1];
329 double sy1 = fluid->s[i * n + j + 1];
330 double s = sx0 + sx1 + sy0 + sy1;
331 if (_zd(fluid, s))
332 continue;
333
334 double div = fluid->u[(i + 1) * n + j] - fluid->u[i * n + j] + fluid->v[i * n + j + 1] - fluid->v[i * n + j];
335 double p = (-div * fluid->overRelaxation) / s;
336 fluid->p[i * n + j] += cp * p;
337 fluid->u[i * n + j] -= sx0 * p;
338 fluid->u[(i + 1) * n + j] += sx1 * p;
339 fluid->v[i * n + j] -= sy0 * p;
340 fluid->v[i * n + j + 1] += sy1 * p;
341 }
342 }
343 }
344 return TRUE;
345}
346
353 __n_assert(fluid, return FALSE);
354 size_t n = fluid->numY;
355 for (size_t i = 0; i < fluid->numX; i++) {
356 fluid->u[i * n + 0] = fluid->u[i * n + 1];
357 fluid->u[i * n + fluid->numY - 1] = fluid->u[i * n + fluid->numY - 2];
358 }
359 for (size_t j = 0; j < fluid->numY; j++) {
360 fluid->v[0 * n + j] = fluid->v[1 * n + j];
361 fluid->v[(fluid->numX - 1) * n + j] = fluid->v[(fluid->numX - 2) * n + j];
362 }
363 return TRUE;
364}
365
374double n_fluid_sampleField(N_FLUID* fluid, double x, double y, uint32_t field) {
375 __n_assert(fluid, return FALSE);
376 size_t n = fluid->numY;
377 double h1 = 1.0 / fluid->h;
378 double h2 = 0.5 * fluid->h;
379
380 x = MAX(MIN(x, (double)fluid->numX * fluid->h), fluid->h);
381 y = MAX(MIN(y, (double)fluid->numY * fluid->h), fluid->h);
382
383 double dx = 0.0;
384 double dy = 0.0;
385
386 const double* f = NULL;
387 switch (field) {
388 case N_FLUID_U_FIELD:
389 f = fluid->u;
390 dy = h2;
391 break;
392 case N_FLUID_V_FIELD:
393 f = fluid->v;
394 dx = h2;
395 break;
396 case N_FLUID_S_FIELD:
397 f = fluid->m;
398 dx = h2;
399 dy = h2;
400 break;
401 default:
402 f = NULL;
403 return 0.0;
404 }
405
406 if (!f) return 0.0;
407
408 double x0 = MIN(floor((x - dx) * h1), (double)(fluid->numX - 1));
409 double tx = ((x - dx) - x0 * fluid->h) * h1;
410 double x1 = MIN(x0 + 1, (double)(fluid->numX - 1));
411
412 double y0 = MIN(floor((y - dy) * h1), (double)(fluid->numY - 1));
413 double ty = ((y - dy) - y0 * fluid->h) * h1;
414 double y1 = MIN(y0 + 1, (double)(fluid->numY - 1));
415
416 double sx = 1.0 - tx;
417 double sy = 1.0 - ty;
418
419 double val = sx * sy * f[(size_t)(x0 * (double)n + y0)] +
420 tx * sy * f[(size_t)(x1 * (double)n + y0)] +
421 tx * ty * f[(size_t)(x1 * (double)n + y1)] +
422 sx * ty * f[(size_t)(x0 * (double)n + y1)];
423
424 return val;
425}
426
434double n_fluid_avgU(N_FLUID* fluid, size_t i, size_t j) {
435 __n_assert(fluid, return FALSE);
436 if (j == 0) return 0.0;
437 size_t n = fluid->numY;
438 double u = (fluid->u[i * n + j - 1] + fluid->u[i * n + j] +
439 fluid->u[(i + 1) * n + j - 1] + fluid->u[(i + 1) * n + j]) *
440 0.25;
441
442 return u;
443}
444
452double n_fluid_avgV(N_FLUID* fluid, size_t i, size_t j) {
453 __n_assert(fluid, return FALSE);
454 if (i == 0) return 0.0;
455 size_t n = fluid->numY;
456 double v = (fluid->v[(i - 1) * n + j] + fluid->v[i * n + j] +
457 fluid->v[(i - 1) * n + j + 1] + fluid->v[i * n + j + 1]) *
458 0.25;
459 return v;
460}
461
467void* n_fluid_advectVel_proc(void* ptr) {
469 N_FLUID* fluid = (N_FLUID*)params->ptr;
470
471 size_t n = fluid->numY;
472 double h2 = 0.5 * fluid->h;
473 for (size_t i = params->x_start; i < params->x_end; i++) {
474 for (size_t j = params->y_start; j < params->y_end; j++) {
475 size_t index = i * n + j;
476 // u component
477 if (!_z(fluid, s[index]) && !_z(fluid, s[(i - 1) * n + j]) && j < fluid->numY - 1) {
478 double x = (double)i * fluid->h;
479 double y = (double)j * fluid->h + h2;
480 double u = fluid->u[index];
481 double v = n_fluid_avgV(fluid, i, j);
482 // double v = n_fluid_sampleField( fluid , x , y , N_FLUID_V_FIELD );
483 x = x - fluid->dt * u;
484 y = y - fluid->dt * v;
485 u = n_fluid_sampleField(fluid, x, y, N_FLUID_U_FIELD);
486 fluid->newU[index] = u;
487 }
488 // v component
489 if (!_z(fluid, s[index]) && !_z(fluid, s[index - 1]) && i < fluid->numX - 1) {
490 double x = (double)i * fluid->h + h2;
491 double y = (double)j * fluid->h;
492 double u = n_fluid_avgU(fluid, i, j);
493 // double u = n_fluid_sampleField( fluid , x , y , N_FLUID_U_FIELD );
494 double v = fluid->v[index];
495 x = x - fluid->dt * u;
496 y = y - fluid->dt * v;
497 v = n_fluid_sampleField(fluid, x, y, N_FLUID_V_FIELD);
498 fluid->newV[index] = v;
499 }
500 }
501 }
502 return NULL;
503}
504
511 __n_assert(fluid, return FALSE);
512
513 memcpy(fluid->newU, fluid->u, fluid->numCells * sizeof(double));
514 memcpy(fluid->newV, fluid->v, fluid->numCells * sizeof(double));
515
516 size_t n = fluid->numY;
517 double h2 = 0.5 * fluid->h;
518 for (size_t i = 1; i < fluid->numX; i++) {
519 for (size_t j = 1; j < fluid->numY; j++) {
520 size_t index = i * n + j;
521 // u component
522 if (!_z(fluid, s[index]) && !_z(fluid, s[(i - 1) * n + j]) && j < fluid->numY - 1) {
523 double x = (double)i * fluid->h;
524 double y = (double)j * fluid->h + h2;
525 double u = fluid->u[index];
526 double v = n_fluid_avgV(fluid, i, j);
527 // double v = n_fluid_sampleField( fluid , x , y , N_FLUID_V_FIELD );
528 x = x - fluid->dt * u;
529 y = y - fluid->dt * v;
530 u = n_fluid_sampleField(fluid, x, y, N_FLUID_U_FIELD);
531 fluid->newU[index] = u;
532 }
533 // v component
534 if (!_z(fluid, s[index]) && !_z(fluid, s[index - 1]) && i < fluid->numX - 1) {
535 double x = (double)i * fluid->h + h2;
536 double y = (double)j * fluid->h;
537 double u = n_fluid_avgU(fluid, i, j);
538 // double u = n_fluid_sampleField( fluid , x , y , N_FLUID_U_FIELD );
539 double v = fluid->v[index];
540 x = x - fluid->dt * u;
541 y = y - fluid->dt * v;
542 v = n_fluid_sampleField(fluid, x, y, N_FLUID_V_FIELD);
543 fluid->newV[index] = v;
544 }
545 }
546 }
547 double* ptr = fluid->u;
548 fluid->u = fluid->newU;
549 fluid->newU = ptr;
550
551 ptr = fluid->v;
552 fluid->v = fluid->newV;
553 fluid->newV = ptr;
554
555 return TRUE;
556}
557
563void* n_fluid_advectSmoke_proc(void* ptr) {
565 N_FLUID* fluid = (N_FLUID*)params->ptr;
566
567 size_t n = fluid->numY;
568 double h2 = 0.5 * fluid->h;
569 for (size_t i = params->x_start; i < params->x_end; i++) {
570 for (size_t j = params->y_start; j < params->y_end; j++) {
571 size_t index = i * n + j;
572 if (!_z(fluid, s[index])) {
573 double u = (fluid->u[index] + fluid->u[(i + 1) * n + j]) * 0.5;
574 double v = (fluid->v[index] + fluid->v[index + 1]) * 0.5;
575 double x = (double)i * fluid->h + h2 - fluid->dt * u;
576 double y = (double)j * fluid->h + h2 - fluid->dt * v;
577
578 fluid->newM[index] = n_fluid_sampleField(fluid, x, y, N_FLUID_S_FIELD);
579 }
580 }
581 }
582 return NULL;
583}
584
591 __n_assert(fluid, return FALSE);
592
593 size_t n = fluid->numY;
594 double h2 = 0.5 * fluid->h;
595
596 memcpy(fluid->newM, fluid->m, fluid->numCells * sizeof(double));
597
598 for (size_t i = 1; i < fluid->numX - 1; i++) {
599 for (size_t j = 1; j < fluid->numY - 1; j++) {
600 size_t index = i * n + j;
601 if (!_z(fluid, s[index])) {
602 double u = (fluid->u[index] + fluid->u[(i + 1) * n + j]) * 0.5;
603 double v = (fluid->v[index] + fluid->v[index + 1]) * 0.5;
604 double x = (double)i * fluid->h + h2 - fluid->dt * u;
605 double y = (double)j * fluid->h + h2 - fluid->dt * v;
606
607 fluid->newM[index] = n_fluid_sampleField(fluid, x, y, N_FLUID_S_FIELD);
608 }
609 }
610 }
611 double* ptr = fluid->m;
612 fluid->m = fluid->newM;
613 fluid->newM = ptr;
614
615 return TRUE;
616}
617
624 __n_assert(fluid, return FALSE);
625 n_fluid_integrate(fluid);
626 memset(fluid->p, 0, fluid->numCells * sizeof(double));
628 n_fluid_extrapolate(fluid);
629 n_fluid_advectVel(fluid);
630 n_fluid_advectSmoke(fluid);
631 return TRUE;
632}
633
641 __n_assert(fluid, return FALSE);
642
643 // n_fluid_integrate( fluid );
644 list_foreach(node, fluid->integrate_chunk_list) {
646 }
650
651 // set pressure to 0
652 memset(fluid->p, 0, fluid->numCells * sizeof(double));
653
654 // n_fluid_solveIncompressibility( fluid );
655 for (size_t iter = 0; iter < fluid->numIters; iter++) {
658 }
662 }
663
664 // extrapolate
665 n_fluid_extrapolate(fluid);
666
667 // n_fluid_advectVel( fluid );
668 memcpy(fluid->newU, fluid->u, fluid->numCells * sizeof(double));
669 memcpy(fluid->newV, fluid->v, fluid->numCells * sizeof(double));
670
671 list_foreach(node, fluid->advectVel_chunk_list) {
673 }
677
678 double* ptr = fluid->u;
679 fluid->u = fluid->newU;
680 fluid->newU = ptr;
681
682 ptr = fluid->v;
683 fluid->v = fluid->newV;
684 fluid->newV = ptr;
685
686 // n_fluid_advectSmoke( fluid );
687 memcpy(fluid->newM, fluid->m, fluid->numCells * sizeof(double));
690 }
694
695 ptr = fluid->m;
696 fluid->m = fluid->newM;
697 fluid->newM = ptr;
698
699 return TRUE;
700}
701
712int n_fluid_setObstacle(N_FLUID* fluid, double x, double y, double vx, double vy, double r) {
713 __n_assert(fluid, return FALSE);
714
715 size_t n = fluid->numY;
716 for (size_t i = 1; i < fluid->numX - 2; i++) {
717 for (size_t j = 1; j < fluid->numY - 2; j++) {
718 double dx = ((double)i + 0.5) - x;
719 double dy = ((double)j + 0.5) - y;
720
721 if (i > 7 && (dx * dx + dy * dy < r * r)) {
722 fluid->s[i * n + j] = 0.0;
723 fluid->m[i * n + j] = 1.0;
724 fluid->u[i * n + j] = vx;
725 fluid->u[(i + 1) * n + j] = vx;
726 fluid->v[i * n + j] = vy;
727 fluid->v[i * n + j + 1] = vy;
728 }
729 }
730 }
731 return TRUE;
732}
733
740 __n_assert(fluid, return FALSE);
741
742 size_t n = fluid->numY;
743 for (size_t i = 1; i < fluid->numX - 2; i++) {
744 for (size_t j = 1; j < fluid->numY - 2; j++) {
745 fluid->s[i * n + j] = 1.0;
746 }
747 }
748
749 return TRUE;
750}
751
763int n_fluid_setObstacleFromBitmap(N_FLUID* fluid, ALLEGRO_BITMAP* bitmap, double x, double y, double vx, double vy, double r) {
764 __n_assert(fluid, return FALSE);
765
766 al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_READONLY);
767
768 size_t n = fluid->numY;
769 for (size_t i = 1; i < fluid->numX - 2; i++) {
770 for (size_t j = 1; j < fluid->numY - 2; j++) {
771 double dx = ((double)i + 0.5) - x;
772 double dy = ((double)j + 0.5) - y;
773
774 if (i > 7 && (dx * dx + dy * dy < r * r)) {
775 fluid->s[i * n + j] = 0.0;
776 fluid->m[i * n + j] = 1.0;
777 fluid->u[i * n + j] = vx;
778 fluid->v[i * n + j] = vy;
779
780 fluid->u[(i + 1) * n + j] = vx;
781 fluid->v[i * n + j + 1] = vy;
782 }
783 }
784 }
785
786 al_unlock_bitmap(bitmap);
787
788 return TRUE;
789}
790
799ALLEGRO_COLOR n_fluid_getSciColor(const N_FLUID* fluid, double val, double minVal, double maxVal) {
800 val = MIN(MAX(val, minVal), maxVal - 0.0001);
801 double d = maxVal - minVal;
802 if (_zd(fluid, d)) {
803 val = 0.5;
804 } else {
805 val = (val - minVal) / d;
806 }
807 double m = 0.25;
808 size_t num = (size_t)floor(val / m);
809 double s = (val - (double)num * m) / m;
810 double r = 0.0, g = 0.0, b = 0.0;
811 switch (num) {
812 case 0:
813 r = 0.0;
814 g = s;
815 b = 1.0;
816 break;
817 case 1:
818 r = 0.0;
819 g = 1.0;
820 b = 1.0 - s;
821 break;
822 case 2:
823 r = s;
824 g = 1.0;
825 b = 0.0;
826 break;
827 case 3:
828 r = 1.0;
829 g = 1.0 - s;
830 b = 0.0;
831 break;
832 }
833 // return[255*r,255*g,255*b, 255]
834 return al_map_rgb_f((float)r, (float)g, (float)b);
835}
836
843 __n_assert(fluid, return FALSE);
844
845 size_t n = fluid->numY;
846
847 double minP = fluid->p[0];
848 double maxP = fluid->p[0];
849
850 if (fluid->showPressure) {
851 for (size_t i = 0; i < fluid->numCells; i++) {
852 minP = MIN(minP, fluid->p[i]);
853 maxP = MAX(maxP, fluid->p[i]);
854 }
855 }
856
857 ALLEGRO_COLOR color;
858 double cScale = fluid->cScale;
859
860 for (size_t i = 0; i < fluid->numX; i++) {
861 for (size_t j = 0; j < fluid->numY; j++) {
862 double xd = (double)i * cScale;
863 double yd = (double)j * cScale;
864 double cxd = xd + cScale;
865 double cyd = yd + cScale;
866
867 double s = fluid->m[i * n + j];
868
869 if (fluid->showPaint) {
870 color = n_fluid_getSciColor(fluid, s, 0.0, 1.0);
871 } else if (fluid->showPressure) {
872 double p = fluid->p[i * n + j];
873 color = n_fluid_getSciColor(fluid, p, minP, maxP);
874 if (fluid->showSmoke) {
875 float color_vec_f[3] = {0.0, 0.0, 0.0};
876 al_unmap_rgb_f(color, color_vec_f, color_vec_f + 1, color_vec_f + 2);
877 color = al_map_rgb_f((float)MAX(0.0, color_vec_f[0] - s), (float)MAX(0.0, color_vec_f[1] - s), (float)MAX(0.0, color_vec_f[2] - s));
878 }
879 } else if (fluid->showSmoke) {
880 color = al_map_rgb_f((float)(1.0 - s), 0.0f, 0.0f);
881 } else {
882 color = al_map_rgb_f((float)s, (float)s, (float)s);
883 }
884 al_draw_filled_rectangle((float)xd, (float)yd, (float)cxd, (float)cyd, color);
885 }
886 }
887 return TRUE;
888}
THREAD_POOL * thread_pool
Definition ex_fluid.c:77
#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
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
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 list_foreach(__ITEM_, __LIST_)
ForEach macro helper, safe for node removal during iteration.
Definition n_list.h:88
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
double h
Definition n_fluids.h:85
double * newU
holder for newU arrays
Definition n_fluids.h:110
size_t numY
number of cells in Y
Definition n_fluids.h:73
size_t y_start
y start point
Definition n_fluids.h:63
double fluid_production_percentage
size of the produced fluid
Definition n_fluids.h:103
bool showSmoke
display fluid as a colored cloud instead of black and white, can be combined with showPressure
Definition n_fluids.h:91
size_t numX
number of cells in X
Definition n_fluids.h:71
LIST * advectSmoke_chunk_list
preprocessed list of threaded procs parameters, for n_fluid_advectSmoke
Definition n_fluids.h:134
double overRelaxation
over relaxation
Definition n_fluids.h:89
bool showPressure
display fluids pressures as color variations, can be combined with showSmoke
Definition n_fluids.h:95
void * ptr
pointer to data which will be used in the proc
Definition n_fluids.h:57
double positive_float_tolerance
fluid double positive precision setting
Definition n_fluids.h:100
LIST * solveIncompressibility_chunk_list
preprocessed list of threaded procs parameters, for n_fluid_solveIncompressibility
Definition n_fluids.h:130
size_t x_end
x end point
Definition n_fluids.h:61
bool showPaint
activate a fonky palette, override smoke and pressure display
Definition n_fluids.h:93
double * u
holder for u arrays
Definition n_fluids.h:108
LIST * integrate_chunk_list
preprocessed list of threaded procs parameters, for n_fluid_integrate
Definition n_fluids.h:128
double * newV
holder for newV arrays
Definition n_fluids.h:115
double dt
time between frames
Definition n_fluids.h:83
double * s
holder for s arrays
Definition n_fluids.h:120
double * v
holder for v arrays
Definition n_fluids.h:113
size_t numCells
total number of cells
Definition n_fluids.h:77
size_t numIters
number of fluid processing iterations for each frame
Definition n_fluids.h:79
double density
density of the fluid (not working ?)
Definition n_fluids.h:81
LIST * advectVel_chunk_list
preprocessed list of threaded procs parameters, for n_fluid_advectVel
Definition n_fluids.h:132
double * m
holder for m arrays
Definition n_fluids.h:123
double cScale
scale used to deduce cellX and cellY from screen/window width and height
Definition n_fluids.h:105
double * newM
holder for newM arrays
Definition n_fluids.h:125
size_t numZ
number of cells in Z
Definition n_fluids.h:75
double * p
holder for p arrays
Definition n_fluids.h:118
size_t x_start
x start point
Definition n_fluids.h:59
double gravity
gravity on Y
Definition n_fluids.h:87
size_t y_end
y end point
Definition n_fluids.h:65
double negative_float_tolerance
fluid double negative precision setting
Definition n_fluids.h:98
double n_fluid_avgV(N_FLUID *fluid, size_t i, size_t j)
compute the average V value at a fluid position using it's surrounding
Definition n_fluids.c:452
int n_fluid_draw(N_FLUID *fluid)
draw a N_FLUID on screen / targert bitmap
Definition n_fluids.c:842
#define _z(__fluid, __component)
test if component is near zero, according to fluid's precision
Definition n_fluids.h:46
int n_fluid_simulate_threaded(N_FLUID *fluid, THREAD_POOL *thread_pool)
a threaded version of N_FLUID global processing function
Definition n_fluids.c:640
int n_fluid_simulate(N_FLUID *fluid)
non threaded version of N_FLUID global processing function
Definition n_fluids.c:623
double n_fluid_avgU(N_FLUID *fluid, size_t i, size_t j)
compute the average U value at a fluid position using it's surrounding
Definition n_fluids.c:434
double n_fluid_sampleField(N_FLUID *fluid, double x, double y, uint32_t field)
compute a sample value at a field position
Definition n_fluids.c:374
int n_fluid_extrapolate(N_FLUID *fluid)
non threaded extrapolation function
Definition n_fluids.c:352
int n_fluid_advectSmoke(N_FLUID *fluid)
non threaded version of add smoke function
Definition n_fluids.c:590
int n_fluid_solveIncompressibility(N_FLUID *fluid)
non threaded version of incompressibility solving function
Definition n_fluids.c:314
ALLEGRO_COLOR n_fluid_getSciColor(const N_FLUID *fluid, double val, double minVal, double maxVal)
get funky colors for the fluid
Definition n_fluids.c:799
int n_fluid_resetObstacles(N_FLUID *fluid)
reset the obstacles set in a N_FLUID
Definition n_fluids.c:739
#define _zd(__fluid, __value)
test if value is near zero, according to fluid's precision
Definition n_fluids.h:51
int n_fluid_integrate(N_FLUID *fluid)
non threaded version of integration function
Definition n_fluids.c:259
int n_fluid_setObstacle(N_FLUID *fluid, double x, double y, double vx, double vy, double r)
set an obstacle in the fluid grid
Definition n_fluids.c:712
int destroy_n_fluid(N_FLUID **fluid)
destroy a fluid structure
Definition n_fluids.c:63
int n_fluid_advectVel(N_FLUID *fluid)
non threaded version of add velocities function
Definition n_fluids.c:510
N_FLUID * new_n_fluid(double density, double gravity, size_t numIters, double dt, double overRelaxation, size_t sx, size_t sy)
return a newly allocated fluid
Definition n_fluids.c:95
structure of a fluid
Definition n_fluids.h:69
structure passed to a threaded fluid process
Definition n_fluids.h:55
int start_threaded_pool(THREAD_POOL *thread_pool)
Launch the process waiting for execution in the thread pool.
#define SYNCED_PROC
processing mode for added func, synced start, not queued
int add_threaded_process(THREAD_POOL *thread_pool, void *(*func_ptr)(void *param), void *param, int mode)
add a function and params to a thread pool
int refresh_thread_pool(THREAD_POOL *thread_pool)
try to add some waiting DIRECT_PROCs on some free thread slots, else do nothing
int wait_for_synced_threaded_pool(THREAD_POOL *thread_pool)
wait for all the launched process, blocking but light on the CPU as there is no polling
long int get_nb_cpu_cores()
get number of core of current system
Structure of a thread pool.
Common headers and low-level functions & define.
#define N_FLUID_S_FIELD
array number for s
Definition n_fluids.c:41
#define N_FLUID_U_FIELD
array number for u
Definition n_fluids.c:37
void * n_fluid_integrate_proc(void *ptr)
ready to be threaded integration function
Definition n_fluids.c:240
void * n_fluid_advectVel_proc(void *ptr)
ready to be threaded add velocities function
Definition n_fluids.c:467
void * n_fluid_advectSmoke_proc(void *ptr)
ready to be threaded add smoke function
Definition n_fluids.c:563
int n_fluid_setObstacleFromBitmap(N_FLUID *fluid, ALLEGRO_BITMAP *bitmap, double x, double y, double vx, double vy, double r)
set an obstacle in the fluid grid from a bitmap mask
Definition n_fluids.c:763
#define N_FLUID_V_FIELD
array number for v
Definition n_fluids.c:39
void * n_fluid_solveIncompressibility_proc(void *ptr)
ready to be threaded incompressibility solving function
Definition n_fluids.c:277
void n_memset(void *dst, const void *val, size_t size, size_t count)
memset bytes to a custom value
Definition n_fluids.c:50
Fluid management port from "How to write an Eulerian fluid simulator with 200 lines of code",...
Thread pool declaration.