38#define N_FLUID_U_FIELD 0
40#define N_FLUID_V_FIELD 1
42#define N_FLUID_S_FIELD 2
51void n_memset(
void* dst,
const void* val,
size_t size,
size_t count) {
52 char* ptr = (
char*)dst;
54 memcpy(ptr, val, size);
68 list_destroy(&(*fluid)->solveIncompressibility_chunk_list);
96N_FLUID*
new_n_fluid(
double density,
double gravity,
size_t numIters,
double dt,
double overRelaxation,
size_t sx,
size_t sy) {
106 fluid->
h = 1.0 / 100.0;
108 fluid->
numX = sx + 2;
109 fluid->
numY = sy + 2;
114 if (!fluid->
u)
goto cleanup_fluid;
116 if (!fluid->
newU)
goto cleanup_fluid;
118 if (!fluid->
v)
goto cleanup_fluid;
120 if (!fluid->
newV)
goto cleanup_fluid;
122 if (!fluid->
p)
goto cleanup_fluid;
124 if (!fluid->
s)
goto cleanup_fluid;
126 if (!fluid->
m)
goto cleanup_fluid;
128 if (!fluid->
newM)
goto cleanup_fluid;
143 if (nb_cores_l <= 0) {
146 size_t nb_cores = (size_t)nb_cores_l;
154 size_t steps = (fluid->
numX / nb_cores > 0) ? fluid->
numX / nb_cores : 1;
158 for (
size_t i = 1; i < fluid->
numX - 1; i += steps) {
162 params->
x_end = i + steps;
174 for (
size_t i = 1; i < fluid->
numX - 1; i += steps) {
178 params->
x_end = i + steps;
190 for (
size_t i = 1; i < fluid->
numX - 1; i += steps) {
194 params->
x_end = i + steps;
206 for (
size_t i = 1; i < fluid->
numX - 1; i += steps) {
210 params->
x_end = i + steps;
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;
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;
282 double cp = (fluid->
density * fluid->
h) / fluid->
dt;
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]))
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;
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];
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;
317 size_t n = fluid->
numY;
319 double cp = (fluid->
density * fluid->
h) / fluid->
dt;
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]))
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;
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];
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;
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];
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];
377 size_t n = fluid->
numY;
378 double h1 = 1.0 / fluid->
h;
379 double h2 = 0.5 * fluid->
h;
381 x = MAX(MIN(x, (
double)fluid->
numX * fluid->
h), fluid->
h);
382 y = MAX(MIN(y, (
double)fluid->
numY * fluid->
h), fluid->
h);
387 const double* f = NULL;
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));
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));
417 double sx = 1.0 - tx;
418 double sy = 1.0 - ty;
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)];
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]) *
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]) *
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;
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];
484 x = x - fluid->
dt * u;
485 y = y - fluid->
dt * v;
487 fluid->
newU[index] = u;
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;
495 double v = fluid->
v[index];
496 x = x - fluid->
dt * u;
497 y = y - fluid->
dt * v;
499 fluid->
newV[index] = v;
514 memcpy(fluid->
newU, fluid->
u, fluid->
numCells *
sizeof(
double));
515 memcpy(fluid->
newV, fluid->
v, fluid->
numCells *
sizeof(
double));
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;
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];
529 x = x - fluid->
dt * u;
530 y = y - fluid->
dt * v;
532 fluid->
newU[index] = u;
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;
540 double v = fluid->
v[index];
541 x = x - fluid->
dt * u;
542 y = y - fluid->
dt * v;
544 fluid->
newV[index] = v;
548 double* ptr = fluid->
u;
549 fluid->
u = fluid->
newU;
553 fluid->
v = fluid->
newV;
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;
594 size_t n = fluid->
numY;
595 double h2 = 0.5 * fluid->
h;
597 memcpy(fluid->
newM, fluid->
m, fluid->
numCells *
sizeof(
double));
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;
612 double* ptr = fluid->
m;
613 fluid->
m = fluid->
newM;
627 memset(fluid->
p, 0, fluid->
numCells *
sizeof(
double));
653 memset(fluid->
p, 0, fluid->
numCells *
sizeof(
double));
656 for (
size_t iter = 0; iter < fluid->
numIters; iter++) {
669 memcpy(fluid->
newU, fluid->
u, fluid->
numCells *
sizeof(
double));
670 memcpy(fluid->
newV, fluid->
v, fluid->
numCells *
sizeof(
double));
679 double* ptr = fluid->
u;
680 fluid->
u = fluid->
newU;
684 fluid->
v = fluid->
newV;
688 memcpy(fluid->
newM, fluid->
m, fluid->
numCells *
sizeof(
double));
697 fluid->
m = fluid->
newM;
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;
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;
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;
767 al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_READONLY);
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;
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;
781 fluid->
u[(i + 1) * n + j] = vx;
782 fluid->
v[i * n + j + 1] = vy;
787 al_unlock_bitmap(bitmap);
801 val = MIN(MAX(val, minVal), maxVal - 0.0001);
802 double d = maxVal - minVal;
806 val = (val - minVal) / d;
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;
835 return al_map_rgb_f((
float)r, (
float)g, (
float)b);
846 size_t n = fluid->
numY;
848 double minP = fluid->
p[0];
849 double maxP = fluid->
p[0];
852 for (
size_t i = 0; i < fluid->
numCells; i++) {
853 minP = MIN(minP, fluid->
p[i]);
854 maxP = MAX(maxP, fluid->
p[i]);
859 double cScale = fluid->
cScale;
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;
868 double s = fluid->
m[i * n + j];
873 double p = fluid->
p[i * n + j];
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));
881 color = al_map_rgb_f((
float)(1.0 - s), 0.0f, 0.0f);
883 color = al_map_rgb_f((
float)s, (
float)s, (
float)s);
885 al_draw_filled_rectangle((
float)xd, (
float)yd, (
float)cxd, (
float)cyd, color);
THREAD_POOL * thread_pool
#define FreeNoLog(__ptr)
Free Handler without log.
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define __n_assert(__ptr, __ret)
macro to assert things
LIST_NODE * end
pointer to the end of the list
void * ptr
void pointer to store
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper, safe for node removal during iteration.
int list_destroy(LIST **list)
Empty and Free a list container.
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
double * newU
holder for newU arrays
size_t numY
number of cells in Y
size_t y_start
y start point
double fluid_production_percentage
size of the produced fluid
bool showSmoke
display fluid as a colored cloud instead of black and white, can be combined with showPressure
size_t numX
number of cells in X
LIST * advectSmoke_chunk_list
preprocessed list of threaded procs parameters, for n_fluid_advectSmoke
double overRelaxation
over relaxation
bool showPressure
display fluids pressures as color variations, can be combined with showSmoke
void * ptr
pointer to data which will be used in the proc
double positive_float_tolerance
fluid double positive precision setting
LIST * solveIncompressibility_chunk_list
preprocessed list of threaded procs parameters, for n_fluid_solveIncompressibility
bool showPaint
activate a fonky palette, override smoke and pressure display
double * u
holder for u arrays
LIST * integrate_chunk_list
preprocessed list of threaded procs parameters, for n_fluid_integrate
double * newV
holder for newV arrays
double dt
time between frames
double * s
holder for s arrays
double * v
holder for v arrays
size_t numCells
total number of cells
size_t numIters
number of fluid processing iterations for each frame
double density
density of the fluid (not working ?)
LIST * advectVel_chunk_list
preprocessed list of threaded procs parameters, for n_fluid_advectVel
double * m
holder for m arrays
double cScale
scale used to deduce cellX and cellY from screen/window width and height
double * newM
holder for newM arrays
size_t numZ
number of cells in Z
double * p
holder for p arrays
size_t x_start
x start point
double gravity
gravity on Y
double negative_float_tolerance
fluid double negative precision setting
int n_fluid_draw(N_FLUID *fluid)
draw a N_FLUID on screen / targert bitmap
#define _z(__fluid, __component)
test if component is near zero, according to fluid's precision
int n_fluid_simulate_threaded(N_FLUID *fluid, THREAD_POOL *thread_pool)
a threaded version of N_FLUID global processing function
int n_fluid_simulate(N_FLUID *fluid)
non threaded version of N_FLUID global processing function
double n_fluid_sampleField(N_FLUID *fluid, double x, double y, uint32_t field)
compute a sample value at a field position
int n_fluid_extrapolate(N_FLUID *fluid)
non threaded extrapolation function
int n_fluid_advectSmoke(N_FLUID *fluid)
non threaded version of add smoke function
int n_fluid_solveIncompressibility(N_FLUID *fluid)
non threaded version of incompressibility solving function
ALLEGRO_COLOR n_fluid_getSciColor(const N_FLUID *fluid, double val, double minVal, double maxVal)
get funky colors for the fluid
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
int n_fluid_resetObstacles(N_FLUID *fluid)
reset the obstacles set in a N_FLUID
#define _zd(__fluid, __value)
test if value is near zero, according to fluid's precision
int n_fluid_integrate(N_FLUID *fluid)
non threaded version of integration function
int n_fluid_setObstacle(N_FLUID *fluid, double x, double y, double vx, double vy, double r)
set an obstacle in the fluid grid
int destroy_n_fluid(N_FLUID **fluid)
destroy a fluid structure
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
int n_fluid_advectVel(N_FLUID *fluid)
non threaded version of add velocities function
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
structure passed to a threaded fluid process
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
#define N_FLUID_U_FIELD
array number for u
void * n_fluid_integrate_proc(void *ptr)
ready to be threaded integration function
void * n_fluid_advectVel_proc(void *ptr)
ready to be threaded add velocities function
void * n_fluid_advectSmoke_proc(void *ptr)
ready to be threaded add smoke function
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
#define N_FLUID_V_FIELD
array number for v
void * n_fluid_solveIncompressibility_proc(void *ptr)
ready to be threaded incompressibility solving function
void n_memset(void *dst, const void *val, size_t size, size_t count)
memset bytes to a custom value
Fluid management port from "How to write an Eulerian fluid simulator with 200 lines of code",...