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