18#define N_FLUID_U_FIELD 0
20#define N_FLUID_V_FIELD 1
22#define N_FLUID_S_FIELD 2
31void n_memset(
void* dst,
void* val,
size_t size,
size_t count) {
34 memcpy(ptr, val, size);
71N_FLUID*
new_n_fluid(
double density,
double gravity,
size_t numIters,
double dt,
double overRelaxation,
size_t sx,
size_t sy) {
81 fluid->h = 1.0 / 100.0;
116 if (nb_cores == -1) {
119 size_t steps = fluid->
numX / nb_cores;
123 for (
size_t i = 1; i < fluid->
numX; i += steps) {
127 params->
x_end = i + steps;
137 for (
size_t i = 1; i < fluid->
numX - 1; i += steps) {
141 params->
x_end = i + steps;
151 for (
size_t i = 1; i < fluid->
numX; i += steps) {
155 params->
x_end = i + steps;
165 for (
size_t i = 1; i < fluid->
numX - 1; i += steps) {
169 params->
x_end = i + steps;
190 size_t n = fluid->
numY;
191 for (
size_t i = params->
x_start; i < params->
x_end; i++) {
192 for (
size_t j = params->
y_start; j < params->
y_end; j++) {
193 if (!
_z(fluid, s[i * n + j]) && !
_z(fluid, s[i * n + j - 1]))
194 fluid->
v[i * n + j] += fluid->
gravity * fluid->
dt;
208 size_t n = fluid->
numY;
209 for (
size_t i = 1; i < fluid->
numX; i++) {
210 for (
size_t j = 1; j < fluid->
numY - 1; j++) {
211 if (!
_z(fluid, s[i * n + j]) && !
_z(fluid, s[i * n + j - 1]))
212 fluid->
v[i * n + j] += fluid->
gravity * fluid->
dt;
227 double cp = (fluid->
density * fluid->h) / fluid->
dt;
229 size_t n = fluid->
numY;
230 for (
size_t i = params->
x_start; i < params->
x_end; i++) {
231 for (
size_t j = params->
y_start; j < params->
y_end; j++) {
232 if (
_z(fluid, s[i * n + j]))
235 double sx0 = fluid->
s[(i - 1) * n + j];
236 double sx1 = fluid->
s[(i + 1) * n + j];
237 double sy0 = fluid->
s[i * n + j - 1];
238 double sy1 = fluid->
s[i * n + j + 1];
239 double s = sx0 + sx1 + sy0 + sy1;
243 double div = fluid->
u[(i + 1) * n + j] - fluid->
u[i * n + j] + fluid->
v[i * n + j + 1] - fluid->
v[i * n + j];
245 fluid->
p[i * n + j] += cp * p;
246 fluid->
u[i * n + j] -= sx0 * p;
247 fluid->
u[(i + 1) * n + j] += sx1 * p;
248 fluid->
v[i * n + j] -= sy0 * p;
249 fluid->
v[i * n + j + 1] += sy1 * p;
262 size_t n = fluid->
numY;
264 double cp = (fluid->
density * fluid->h) / fluid->
dt;
266 for (
size_t iter = 0; iter < fluid->
numIters; iter++) {
267 for (
size_t i = 1; i < fluid->
numX - 1; i++) {
268 for (
size_t j = 1; j < fluid->
numY - 1; j++) {
269 if (
_z(fluid, s[i * n + j]))
272 double sx0 = fluid->
s[(i - 1) * n + j];
273 double sx1 = fluid->
s[(i + 1) * n + j];
274 double sy0 = fluid->
s[i * n + j - 1];
275 double sy1 = fluid->
s[i * n + j + 1];
276 double s = sx0 + sx1 + sy0 + sy1;
280 double div = fluid->
u[(i + 1) * n + j] - fluid->
u[i * n + j] + fluid->
v[i * n + j + 1] - fluid->
v[i * n + j];
282 fluid->
p[i * n + j] += cp * p;
283 fluid->
u[i * n + j] -= sx0 * p;
284 fluid->
u[(i + 1) * n + j] += sx1 * p;
285 fluid->
v[i * n + j] -= sy0 * p;
286 fluid->
v[i * n + j + 1] += sy1 * p;
300 size_t n = fluid->
numY;
301 for (
size_t i = 0; i < fluid->
numX; i++) {
302 fluid->
u[i * n + 0] = fluid->
u[i * n + 1];
303 fluid->
u[i * n + fluid->
numY - 1] = fluid->
u[i * n + fluid->
numY - 2];
305 for (
size_t j = 0; j < fluid->
numY; j++) {
306 fluid->
v[0 * n + j] = fluid->
v[1 * n + j];
307 fluid->
v[(fluid->
numX - 1) * n + j] = fluid->
v[(fluid->
numX - 2) * n + j];
322 size_t n = fluid->
numY;
323 double h1 = 1.0 / fluid->h;
324 double h2 = 0.5 * fluid->h;
326 x = MAX(MIN(x, fluid->
numX * fluid->h), fluid->h);
327 y = MAX(MIN(y, fluid->
numY * fluid->h), fluid->h);
349 double x0 = MIN(floor((x - dx) * h1), fluid->
numX - 1);
350 double tx = ((x - dx) - x0 * fluid->h) * h1;
351 double x1 = MIN(x0 + 1, fluid->
numX - 1);
353 double y0 = MIN(floor((y - dy) * h1), fluid->
numY - 1);
354 double ty = ((y - dy) - y0 * fluid->h) * h1;
355 double y1 = MIN(y0 + 1, fluid->
numY - 1);
357 double sx = 1.0 - tx;
358 double sy = 1.0 - ty;
360 double val = sx * sy * f[(size_t)(x0 * n + y0)] +
361 tx * sy * f[(size_t)(x1 * n + y0)] +
362 tx * ty * f[(size_t)(x1 * n + y1)] +
363 sx * ty * f[(size_t)(x0 * n + y1)];
377 size_t n = fluid->
numY;
378 double u = (fluid->
u[i * n + j - 1] + fluid->
u[i * n + j] +
379 fluid->
u[(i + 1) * n + j - 1] + fluid->
u[(i + 1) * n + j]) *
394 size_t n = fluid->
numY;
395 double v = (fluid->
v[(i - 1) * n + j] + fluid->
v[i * n + j] +
396 fluid->
v[(i - 1) * n + j + 1] + fluid->
v[i * n + j + 1]) *
410 size_t n = fluid->
numY;
411 double h2 = 0.5 * fluid->h;
412 for (
size_t i = params->
x_start; i < params->
x_end; i++) {
413 for (
size_t j = params->
y_start; j < params->
y_end; j++) {
414 size_t index = i * n + j;
416 if (!
_z(fluid, s[index]) && !
_z(fluid, s[(i - 1) * n + j]) && j < fluid->
numY - 1) {
417 double x = i * fluid->h;
418 double y = j * fluid->h + h2;
419 double u = fluid->
u[index];
422 x = x - fluid->
dt * u;
423 y = y - fluid->
dt * v;
425 fluid->
newU[index] = u;
428 if (!
_z(fluid, s[index]) && !
_z(fluid, s[index - 1]) && i < fluid->numX - 1) {
429 double x = i * fluid->h + h2;
430 double y = j * fluid->h;
433 double v = fluid->
v[index];
434 x = x - fluid->
dt * u;
435 y = y - fluid->
dt * v;
437 fluid->
newV[index] = v;
452 memcpy(fluid->
newU, fluid->
u, fluid->
numCells *
sizeof(
double));
453 memcpy(fluid->
newV, fluid->
v, fluid->
numCells *
sizeof(
double));
455 size_t n = fluid->
numY;
456 double h2 = 0.5 * fluid->h;
457 for (
size_t i = 1; i < fluid->
numX; i++) {
458 for (
size_t j = 1; j < fluid->
numY; j++) {
459 size_t index = i * n + j;
461 if (!
_z(fluid, s[index]) && !
_z(fluid, s[(i - 1) * n + j]) && j < fluid->numY - 1) {
462 double x = i * fluid->h;
463 double y = j * fluid->h + h2;
464 double u = fluid->
u[index];
467 x = x - fluid->
dt * u;
468 y = y - fluid->
dt * v;
470 fluid->
newU[index] = u;
473 if (!
_z(fluid, s[index]) && !
_z(fluid, s[index - 1]) && i < fluid->numX - 1) {
474 double x = i * fluid->h + h2;
475 double y = j * fluid->h;
478 double v = fluid->
v[index];
479 x = x - fluid->
dt * u;
480 y = y - fluid->
dt * v;
482 fluid->
newV[index] = v;
486 double* ptr = fluid->
u;
487 fluid->
u = fluid->
newU;
491 fluid->
v = fluid->
newV;
506 size_t n = fluid->
numY;
507 double h2 = 0.5 * fluid->h;
508 for (
size_t i = params->
x_start; i < params->
x_end; i++) {
509 for (
size_t j = params->
y_start; j < params->
y_end; j++) {
510 size_t index = i * n + j;
511 if (!
_z(fluid, s[index])) {
512 double u = (fluid->
u[index] + fluid->
u[(i + 1) * n + j]) * 0.5;
513 double v = (fluid->
v[index] + fluid->
v[index + 1]) * 0.5;
514 double x = i * fluid->h + h2 - fluid->
dt * u;
515 double y = j * fluid->h + h2 - fluid->
dt * v;
532 size_t n = fluid->
numY;
533 double h2 = 0.5 * fluid->h;
535 memcpy(fluid->
newM, fluid->
m, fluid->
numCells *
sizeof(
double));
537 for (
size_t i = 1; i < fluid->
numX - 1; i++) {
538 for (
size_t j = 1; j < fluid->
numY - 1; j++) {
539 size_t index = i * n + j;
540 if (!
_z(fluid, s[index])) {
541 double u = (fluid->
u[index] + fluid->
u[(i + 1) * n + j]) * 0.5;
542 double v = (fluid->
v[index] + fluid->
v[index + 1]) * 0.5;
543 double x = i * fluid->h + h2 - fluid->
dt * u;
544 double y = j * fluid->h + h2 - fluid->
dt * v;
550 double* ptr = fluid->
m;
551 fluid->
m = fluid->
newM;
565 memset(fluid->
p, 0, fluid->
numCells *
sizeof(
double));
591 memset(fluid->
p, 0, fluid->
numCells *
sizeof(
double));
594 for (
size_t iter = 0; iter < fluid->
numIters; iter++) {
607 memcpy(fluid->
newU, fluid->
u, fluid->
numCells *
sizeof(
double));
608 memcpy(fluid->
newV, fluid->
v, fluid->
numCells *
sizeof(
double));
617 double* ptr = fluid->
u;
618 fluid->
u = fluid->
newU;
622 fluid->
v = fluid->
newV;
626 memcpy(fluid->
newM, fluid->
m, fluid->
numCells *
sizeof(
double));
635 fluid->
m = fluid->
newM;
654 size_t n = fluid->
numY;
655 for (
size_t i = 1; i < fluid->
numX - 2; i++) {
656 for (
size_t j = 1; j < fluid->
numY - 2; j++) {
657 double dx = (i + 0.5) - x;
658 double dy = (j + 0.5) - y;
660 if (i > 7 && (dx * dx + dy * dy < r * r)) {
661 fluid->
s[i * n + j] = 0.0;
662 fluid->
m[i * n + j] = 1.0;
663 fluid->
u[i * n + j] = vx;
664 fluid->
u[(i + 1) * n + j] = vx;
665 fluid->
v[i * n + j] = vy;
666 fluid->
v[i * n + j + 1] = vy;
681 size_t n = fluid->
numY;
682 for (
size_t i = 1; i < fluid->
numX - 2; i++) {
683 for (
size_t j = 1; j < fluid->
numY - 2; j++) {
684 fluid->
s[i * n + j] = 1.0;
705 al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_READONLY);
707 size_t n = fluid->
numY;
708 for (
size_t i = 1; i < fluid->
numX - 2; i++) {
709 for (
size_t j = 1; j < fluid->
numY - 2; j++) {
710 double dx = (i + 0.5) - x;
711 double dy = (j + 0.5) - y;
713 if (i > 7 && (dx * dx + dy * dy < r * r)) {
714 fluid->
s[i * n + j] = 0.0;
715 fluid->
m[i * n + j] = 1.0;
716 fluid->
u[i * n + j] = vx;
717 fluid->
v[i * n + j] = vy;
719 fluid->
u[(i + 1) * n + j] = vx;
720 fluid->
v[i * n + j + 1] = vy;
725 al_unlock_bitmap(bitmap);
739 val = MIN(MAX(val, minVal), maxVal - 0.0001);
740 double d = maxVal - minVal;
744 val = (val - minVal) / d;
747 size_t num = floor(val / m);
748 double s = (val - num * m) / m;
749 double r = 0.0, g = 0.0, b = 0.0;
773 return al_map_rgb_f(r, g, b);
784 size_t n = fluid->
numY;
786 double minP = fluid->
p[0];
787 double maxP = fluid->
p[0];
790 for (
size_t i = 0; i < fluid->
numCells; i++) {
791 minP = MIN(minP, fluid->
p[i]);
792 maxP = MAX(maxP, fluid->
p[i]);
797 double cScale = fluid->
cScale;
799 for (
size_t i = 0; i < fluid->
numX; i++) {
800 for (
size_t j = 0; j < fluid->
numY; j++) {
801 int64_t x = i * cScale;
802 int64_t y = j * cScale;
803 int64_t cx = x + cScale;
804 int64_t cy = y + cScale;
806 double s = fluid->
m[i * n + j];
811 float color_vec_f[3] = {0.0, 0.0, 0.0};
812 double p = fluid->
p[i * n + j];
815 al_unmap_rgb_f(color, color_vec_f, color_vec_f + 1, color_vec_f + 2);
816 color = al_map_rgb_f(MAX(0.0, color_vec_f[0] - s), MAX(0.0, color_vec_f[1] - s), MAX(0.0, color_vec_f[2] - s));
819 color = al_map_rgb_f(1.0 - s, 0.0, 0.0);
821 color = al_map_rgb_f(s, s, s);
823 al_draw_filled_rectangle(x, y, cx, cy, color);
#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.
#define MAX_LIST_ITEMS
flag to pass to new_generic_list for the maximum possible number of item in a list
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
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
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_avgU(N_FLUID *fluid, size_t i, size_t j)
compute the average U value at a fluid position using it's surrounding
double n_fluid_sampleField(N_FLUID *fluid, double x, double y, uint32_t field)
compute a sample value at a field position
ALLEGRO_COLOR n_fluid_getSciColor(N_FLUID *fluid, double val, double minVal, double maxVal)
get fonky colors for the fluid
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
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)
ddestroy a fluid structure
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)
!
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
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 trhead pool.
Common headers and low-level functions & define.
void n_memset(void *dst, void *val, size_t size, size_t count)
memset bytes to a custom value
#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
fluid management port from "How to write an Eulerian fluid simulator with 200 lines of code",...