19#define N_FLUID_U_FIELD 0
21#define N_FLUID_V_FIELD 1
23#define N_FLUID_S_FIELD 2
32void n_memset(
void* dst,
void* val,
size_t size,
size_t count) {
35 memcpy(ptr, val, size);
72N_FLUID*
new_n_fluid(
double density,
double gravity,
size_t numIters,
double dt,
double overRelaxation,
size_t sx,
size_t sy) {
82 fluid->
h = 1.0 / 100.0;
117 if (nb_cores == -1) {
120 size_t steps = fluid->
numX / nb_cores;
124 for (
size_t i = 1; i < fluid->
numX; i += steps) {
128 params->
x_end = i + steps;
138 for (
size_t i = 1; i < fluid->
numX - 1; i += steps) {
142 params->
x_end = i + steps;
152 for (
size_t i = 1; i < fluid->
numX; i += steps) {
156 params->
x_end = i + steps;
166 for (
size_t i = 1; i < fluid->
numX - 1; i += steps) {
170 params->
x_end = i + steps;
191 size_t n = fluid->
numY;
192 for (
size_t i = params->
x_start; i < params->
x_end; i++) {
193 for (
size_t j = params->
y_start; j < params->
y_end; j++) {
194 if (!
_z(fluid, s[i * n + j]) && !
_z(fluid, s[i * n + j - 1]))
195 fluid->
v[i * n + j] += fluid->
gravity * fluid->
dt;
209 size_t n = fluid->
numY;
210 for (
size_t i = 1; i < fluid->
numX; i++) {
211 for (
size_t j = 1; j < fluid->
numY - 1; j++) {
212 if (!
_z(fluid, s[i * n + j]) && !
_z(fluid, s[i * n + j - 1]))
213 fluid->
v[i * n + j] += fluid->
gravity * fluid->
dt;
228 double cp = (fluid->
density * fluid->
h) / fluid->
dt;
230 size_t n = fluid->
numY;
231 for (
size_t i = params->
x_start; i < params->
x_end; i++) {
232 for (
size_t j = params->
y_start; j < params->
y_end; j++) {
233 if (
_z(fluid, s[i * n + j]))
236 double sx0 = fluid->
s[(i - 1) * n + j];
237 double sx1 = fluid->
s[(i + 1) * n + j];
238 double sy0 = fluid->
s[i * n + j - 1];
239 double sy1 = fluid->
s[i * n + j + 1];
240 double s = sx0 + sx1 + sy0 + sy1;
244 double div = fluid->
u[(i + 1) * n + j] - fluid->
u[i * n + j] + fluid->
v[i * n + j + 1] - fluid->
v[i * n + j];
246 fluid->
p[i * n + j] += cp * p;
247 fluid->
u[i * n + j] -= sx0 * p;
248 fluid->
u[(i + 1) * n + j] += sx1 * p;
249 fluid->
v[i * n + j] -= sy0 * p;
250 fluid->
v[i * n + j + 1] += sy1 * p;
263 size_t n = fluid->
numY;
265 double cp = (fluid->
density * fluid->
h) / fluid->
dt;
267 for (
size_t iter = 0; iter < fluid->
numIters; iter++) {
268 for (
size_t i = 1; i < fluid->
numX - 1; i++) {
269 for (
size_t j = 1; j < fluid->
numY - 1; j++) {
270 if (
_z(fluid, s[i * n + j]))
273 double sx0 = fluid->
s[(i - 1) * n + j];
274 double sx1 = fluid->
s[(i + 1) * n + j];
275 double sy0 = fluid->
s[i * n + j - 1];
276 double sy1 = fluid->
s[i * n + j + 1];
277 double s = sx0 + sx1 + sy0 + sy1;
281 double div = fluid->
u[(i + 1) * n + j] - fluid->
u[i * n + j] + fluid->
v[i * n + j + 1] - fluid->
v[i * n + j];
283 fluid->
p[i * n + j] += cp * p;
284 fluid->
u[i * n + j] -= sx0 * p;
285 fluid->
u[(i + 1) * n + j] += sx1 * p;
286 fluid->
v[i * n + j] -= sy0 * p;
287 fluid->
v[i * n + j + 1] += sy1 * p;
301 size_t n = fluid->
numY;
302 for (
size_t i = 0; i < fluid->
numX; i++) {
303 fluid->
u[i * n + 0] = fluid->
u[i * n + 1];
304 fluid->
u[i * n + fluid->
numY - 1] = fluid->
u[i * n + fluid->
numY - 2];
306 for (
size_t j = 0; j < fluid->
numY; j++) {
307 fluid->
v[0 * n + j] = fluid->
v[1 * n + j];
308 fluid->
v[(fluid->
numX - 1) * n + j] = fluid->
v[(fluid->
numX - 2) * n + j];
323 size_t n = fluid->
numY;
324 double h1 = 1.0 / fluid->
h;
325 double h2 = 0.5 * fluid->
h;
327 x = MAX(MIN(x, fluid->
numX * fluid->
h), fluid->
h);
328 y = MAX(MIN(y, fluid->
numY * fluid->
h), fluid->
h);
350 double x0 = MIN(floor((x - dx) * h1), fluid->
numX - 1);
351 double tx = ((x - dx) - x0 * fluid->
h) * h1;
352 double x1 = MIN(x0 + 1, fluid->
numX - 1);
354 double y0 = MIN(floor((y - dy) * h1), fluid->
numY - 1);
355 double ty = ((y - dy) - y0 * fluid->
h) * h1;
356 double y1 = MIN(y0 + 1, fluid->
numY - 1);
358 double sx = 1.0 - tx;
359 double sy = 1.0 - ty;
361 double val = sx * sy * f[(size_t)(x0 * n + y0)] +
362 tx * sy * f[(size_t)(x1 * n + y0)] +
363 tx * ty * f[(size_t)(x1 * n + y1)] +
364 sx * ty * f[(size_t)(x0 * n + y1)];
378 size_t n = fluid->
numY;
379 double u = (fluid->
u[i * n + j - 1] + fluid->
u[i * n + j] +
380 fluid->
u[(i + 1) * n + j - 1] + fluid->
u[(i + 1) * n + j]) *
395 size_t n = fluid->
numY;
396 double v = (fluid->
v[(i - 1) * n + j] + fluid->
v[i * n + j] +
397 fluid->
v[(i - 1) * n + j + 1] + fluid->
v[i * n + j + 1]) *
411 size_t n = fluid->
numY;
412 double h2 = 0.5 * fluid->
h;
413 for (
size_t i = params->
x_start; i < params->
x_end; i++) {
414 for (
size_t j = params->
y_start; j < params->
y_end; j++) {
415 size_t index = i * n + j;
417 if (!
_z(fluid, s[index]) && !
_z(fluid, s[(i - 1) * n + j]) && j < fluid->
numY - 1) {
418 double x = i * fluid->
h;
419 double y = j * fluid->
h + h2;
420 double u = fluid->
u[index];
423 x = x - fluid->
dt * u;
424 y = y - fluid->
dt * v;
426 fluid->
newU[index] = u;
429 if (!
_z(fluid, s[index]) && !
_z(fluid, s[index - 1]) && i < fluid->numX - 1) {
430 double x = i * fluid->
h + h2;
431 double y = j * fluid->
h;
434 double v = fluid->
v[index];
435 x = x - fluid->
dt * u;
436 y = y - fluid->
dt * v;
438 fluid->
newV[index] = v;
453 memcpy(fluid->
newU, fluid->
u, fluid->
numCells *
sizeof(
double));
454 memcpy(fluid->
newV, fluid->
v, fluid->
numCells *
sizeof(
double));
456 size_t n = fluid->
numY;
457 double h2 = 0.5 * fluid->
h;
458 for (
size_t i = 1; i < fluid->
numX; i++) {
459 for (
size_t j = 1; j < fluid->
numY; j++) {
460 size_t index = i * n + j;
462 if (!
_z(fluid, s[index]) && !
_z(fluid, s[(i - 1) * n + j]) && j < fluid->numY - 1) {
463 double x = i * fluid->
h;
464 double y = j * fluid->
h + h2;
465 double u = fluid->
u[index];
468 x = x - fluid->
dt * u;
469 y = y - fluid->
dt * v;
471 fluid->
newU[index] = u;
474 if (!
_z(fluid, s[index]) && !
_z(fluid, s[index - 1]) && i < fluid->numX - 1) {
475 double x = i * fluid->
h + h2;
476 double y = j * fluid->
h;
479 double v = fluid->
v[index];
480 x = x - fluid->
dt * u;
481 y = y - fluid->
dt * v;
483 fluid->
newV[index] = v;
487 double* ptr = fluid->
u;
488 fluid->
u = fluid->
newU;
492 fluid->
v = fluid->
newV;
507 size_t n = fluid->
numY;
508 double h2 = 0.5 * fluid->
h;
509 for (
size_t i = params->
x_start; i < params->
x_end; i++) {
510 for (
size_t j = params->
y_start; j < params->
y_end; j++) {
511 size_t index = i * n + j;
512 if (!
_z(fluid, s[index])) {
513 double u = (fluid->
u[index] + fluid->
u[(i + 1) * n + j]) * 0.5;
514 double v = (fluid->
v[index] + fluid->
v[index + 1]) * 0.5;
515 double x = i * fluid->
h + h2 - fluid->
dt * u;
516 double y = j * fluid->
h + h2 - fluid->
dt * v;
533 size_t n = fluid->
numY;
534 double h2 = 0.5 * fluid->
h;
536 memcpy(fluid->
newM, fluid->
m, fluid->
numCells *
sizeof(
double));
538 for (
size_t i = 1; i < fluid->
numX - 1; i++) {
539 for (
size_t j = 1; j < fluid->
numY - 1; j++) {
540 size_t index = i * n + j;
541 if (!
_z(fluid, s[index])) {
542 double u = (fluid->
u[index] + fluid->
u[(i + 1) * n + j]) * 0.5;
543 double v = (fluid->
v[index] + fluid->
v[index + 1]) * 0.5;
544 double x = i * fluid->
h + h2 - fluid->
dt * u;
545 double y = j * fluid->
h + h2 - fluid->
dt * v;
551 double* ptr = fluid->
m;
552 fluid->
m = fluid->
newM;
566 memset(fluid->
p, 0, fluid->
numCells *
sizeof(
double));
592 memset(fluid->
p, 0, fluid->
numCells *
sizeof(
double));
595 for (
size_t iter = 0; iter < fluid->
numIters; iter++) {
608 memcpy(fluid->
newU, fluid->
u, fluid->
numCells *
sizeof(
double));
609 memcpy(fluid->
newV, fluid->
v, fluid->
numCells *
sizeof(
double));
618 double* ptr = fluid->
u;
619 fluid->
u = fluid->
newU;
623 fluid->
v = fluid->
newV;
627 memcpy(fluid->
newM, fluid->
m, fluid->
numCells *
sizeof(
double));
636 fluid->
m = fluid->
newM;
655 size_t n = fluid->
numY;
656 for (
size_t i = 1; i < fluid->
numX - 2; i++) {
657 for (
size_t j = 1; j < fluid->
numY - 2; j++) {
658 double dx = (i + 0.5) - x;
659 double dy = (j + 0.5) - y;
661 if (i > 7 && (dx * dx + dy * dy < r * r)) {
662 fluid->
s[i * n + j] = 0.0;
663 fluid->
m[i * n + j] = 1.0;
664 fluid->
u[i * n + j] = vx;
665 fluid->
u[(i + 1) * n + j] = vx;
666 fluid->
v[i * n + j] = vy;
667 fluid->
v[i * n + j + 1] = vy;
682 size_t n = fluid->
numY;
683 for (
size_t i = 1; i < fluid->
numX - 2; i++) {
684 for (
size_t j = 1; j < fluid->
numY - 2; j++) {
685 fluid->
s[i * n + j] = 1.0;
706 al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_READONLY);
708 size_t n = fluid->
numY;
709 for (
size_t i = 1; i < fluid->
numX - 2; i++) {
710 for (
size_t j = 1; j < fluid->
numY - 2; j++) {
711 double dx = (i + 0.5) - x;
712 double dy = (j + 0.5) - y;
714 if (i > 7 && (dx * dx + dy * dy < r * r)) {
715 fluid->
s[i * n + j] = 0.0;
716 fluid->
m[i * n + j] = 1.0;
717 fluid->
u[i * n + j] = vx;
718 fluid->
v[i * n + j] = vy;
720 fluid->
u[(i + 1) * n + j] = vx;
721 fluid->
v[i * n + j + 1] = vy;
726 al_unlock_bitmap(bitmap);
740 val = MIN(MAX(val, minVal), maxVal - 0.0001);
741 double d = maxVal - minVal;
745 val = (val - minVal) / d;
748 size_t num = floor(val / m);
749 double s = (val - num * m) / m;
750 double r = 0.0, g = 0.0, b = 0.0;
774 return al_map_rgb_f(r, g, b);
785 size_t n = fluid->
numY;
787 double minP = fluid->
p[0];
788 double maxP = fluid->
p[0];
791 for (
size_t i = 0; i < fluid->
numCells; i++) {
792 minP = MIN(minP, fluid->
p[i]);
793 maxP = MAX(maxP, fluid->
p[i]);
798 double cScale = fluid->
cScale;
800 for (
size_t i = 0; i < fluid->
numX; i++) {
801 for (
size_t j = 0; j < fluid->
numY; j++) {
802 int64_t x = i * cScale;
803 int64_t y = j * cScale;
804 int64_t cx = x + cScale;
805 int64_t cy = y + cScale;
807 double s = fluid->
m[i * n + j];
812 float color_vec_f[3] = {0.0, 0.0, 0.0};
813 double p = fluid->
p[i * n + j];
816 al_unmap_rgb_f(color, color_vec_f, color_vec_f + 1, color_vec_f + 2);
817 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));
820 color = al_map_rgb_f(1.0 - s, 0.0, 0.0);
822 color = al_map_rgb_f(s, s, s);
824 al_draw_filled_rectangle(x, y, cx, cy, 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.
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
#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)
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 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",...