18#define N_FLUID_U_FIELD 0
20#define N_FLUID_V_FIELD 1
22#define N_FLUID_S_FIELD 2
32void n_memset(
void *dst ,
void *val ,
size_t size ,
size_t count )
37 memcpy( ptr , val , size );
78N_FLUID *
new_n_fluid(
double density ,
double gravity ,
size_t numIters ,
double dt ,
double overRelaxation ,
size_t sx ,
size_t sy )
85 fluid -> density = density ;
86 fluid -> gravity = gravity ;
87 fluid -> numIters = numIters ;
89 fluid -> h = 1.0 / 100.0 ;
90 fluid -> overRelaxation = overRelaxation ;
91 fluid -> numX = sx + 2 ;
92 fluid -> numY = sy + 2 ;
94 fluid -> numCells = fluid -> numX * fluid -> numY * fluid -> numZ;
96 Malloc( fluid -> u ,
double , fluid -> numCells );
97 Malloc( fluid -> newU ,
double , fluid -> numCells );
98 Malloc( fluid -> v ,
double , fluid -> numCells );
99 Malloc( fluid -> newV ,
double , fluid -> numCells );
100 Malloc( fluid -> p ,
double , fluid -> numCells );
101 Malloc( fluid -> s ,
double , fluid -> numCells );
102 Malloc( fluid -> m ,
double , fluid -> numCells );
103 Malloc( fluid -> newM ,
double , fluid -> numCells );
105 fluid -> showSmoke = 1 ;
106 fluid -> showPressure = 0 ;
107 fluid -> showPaint = 0 ;
108 fluid -> fluid_production_percentage = 0.1 ;
109 fluid -> cScale = 16.0 ;
111 fluid -> negative_float_tolerance = -0.00001 ;
112 fluid -> positive_float_tolerance = 0.00001 ;
115 n_memset( fluid -> m , &d_val ,
sizeof( d_val ) , fluid -> numCells );
128 size_t steps = fluid -> numX / nb_cores ;
132 for(
size_t i = 1 ; i < fluid -> numX ; i +=steps )
135 params -> ptr = fluid ;
136 params -> x_start = i ;
137 params -> x_end = i+steps ;
138 params -> y_start = 1 ;
139 params -> y_end = fluid -> numY - 1 ;
140 list_push( fluid -> integrate_chunk_list , params , &free );
144 params -> x_end = fluid -> numX ;
147 for(
size_t i = 1 ; i < fluid -> numX - 1 ; i +=steps )
150 params -> ptr = fluid ;
151 params -> x_start = i ;
152 params -> x_end = i+steps ;
153 params -> y_start = 1 ;
154 params -> y_end = fluid -> numY - 1 ;
155 list_push( fluid -> solveIncompressibility_chunk_list , params , &free );
159 params -> x_end = fluid -> numX - 1 ;
162 for(
size_t i = 1 ; i < fluid -> numX ; i +=steps )
165 params -> ptr = fluid ;
166 params -> x_start = i ;
167 params -> x_end = i+steps ;
168 params -> y_start = 1 ;
169 params -> y_end = fluid -> numY ;
170 list_push( fluid -> advectVel_chunk_list , params , &free );
174 params -> x_end = fluid -> numX ;
178 for(
size_t i = 1 ; i < fluid -> numX -1 ; i +=steps )
181 params -> ptr = fluid ;
182 params -> x_start = i ;
183 params -> x_end = i+steps ;
184 params -> y_start = 1 ;
185 params -> y_end = fluid -> numY - 1;
186 list_push( fluid -> advectSmoke_chunk_list , params , &free );
190 params -> x_end = fluid -> numX -1 ;
207 size_t n = fluid -> numY;
208 for(
size_t i = params -> x_start ; i < params -> x_end ; i++ )
210 for(
size_t j = params -> y_start ; j < params -> y_end ; 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 ;
229 size_t n = fluid -> numY;
230 for(
size_t i = 1 ; i < fluid -> numX ; i++ )
232 for(
size_t j = 1; j < fluid -> numY - 1 ; j++ )
234 if( !
_z( fluid , s[ i*n + j ] ) && !
_z( fluid , s[ i*n + j-1 ] ) )
235 fluid -> v[ i*n + j ] += fluid -> gravity * fluid -> dt ;
253 double cp = ( fluid -> density * fluid -> h ) / fluid -> dt ;
255 size_t n = fluid -> numY;
256 for(
size_t i = params -> x_start ; i < params -> x_end ; i++ )
258 for(
size_t j = params -> y_start ; j < params -> y_end ; j++ )
260 if(
_z( fluid , s[ i*n + j ] ) )
263 double sx0 = fluid ->
s[ (i - 1)*n + j ];
264 double sx1 = fluid ->
s[ (i + 1)*n + j ];
265 double sy0 = fluid ->
s[ i*n + j - 1 ];
266 double sy1 = fluid ->
s[ i*n + j + 1 ];
267 double s = sx0 + sx1 + sy0 + sy1;
268 if(
_zd( fluid , s ) )
271 double div = fluid ->
u[(i+1)*n + j] - fluid ->u[i*n + j] + fluid ->v[i*n + j+1] - fluid ->v[i*n + j];
272 double p = ( -div * fluid -> overRelaxation ) / s ;
273 fluid ->
p[i*n + j] += cp * p;
274 fluid ->
u[i*n + j] -= sx0 * p;
275 fluid ->
u[(i+1)*n + j] += sx1 * p;
276 fluid ->
v[i*n + j] -= sy0 * p;
277 fluid ->
v[i*n + j+1] += sy1 * p;
292 size_t n = fluid -> numY ;
294 double cp = ( fluid -> density * fluid -> h ) / fluid -> dt ;
296 for(
size_t iter = 0 ; iter < fluid -> numIters ; iter++ )
298 for(
size_t i = 1 ; i < fluid -> numX - 1 ; i++ )
300 for(
size_t j = 1 ; j < fluid -> numY - 1 ; j++ )
302 if(
_z( fluid , s[ i*n + j ] ) )
305 double sx0 = fluid ->
s[ (i - 1)*n + j ];
306 double sx1 = fluid ->
s[ (i + 1)*n + j ];
307 double sy0 = fluid ->
s[ i*n + j - 1 ];
308 double sy1 = fluid ->
s[ i*n + j + 1 ];
309 double s = sx0 + sx1 + sy0 + sy1;
310 if(
_zd( fluid , s ) )
313 double div = fluid ->
u[(i+1)*n + j] - fluid ->u[i*n + j] + fluid ->v[i*n + j+1] - fluid ->v[i*n + j];
314 double p = ( -div * fluid -> overRelaxation ) / s ;
315 fluid ->
p[i*n + j] += cp * p;
316 fluid ->
u[i*n + j] -= sx0 * p;
317 fluid ->
u[(i+1)*n + j] += sx1 * p;
318 fluid ->
v[i*n + j] -= sy0 * p;
319 fluid ->
v[i*n + j+1] += sy1 * p;
336 size_t n = fluid -> numY ;
337 for(
size_t i = 0; i < fluid ->
numX ; i++ )
339 fluid ->
u[ i*n + 0 ] = fluid ->
u[i*n + 1];
340 fluid ->
u[ i*n + fluid ->
numY-1 ] = fluid ->
u[i*n + fluid ->
numY-2];
342 for(
size_t j = 0; j < fluid ->
numY; j++)
344 fluid ->
v[0*n + j] = fluid ->
v[1*n + j];
345 fluid ->
v[(fluid ->
numX-1)*n + j] = fluid ->v[(fluid ->numX-2)*n + j] ;
362 size_t n = fluid -> numY;
363 double h1 = 1.0 / fluid -> h ;
364 double h2 = 0.5 * fluid -> h ;
366 x = MAX( MIN( x , fluid ->numX * fluid -> h ) , fluid -> h );
367 y = MAX( MIN( y , fluid ->numY * fluid -> h ) , fluid -> h );
380 double x0 = MIN( floor( (x-dx) * h1 ) , fluid ->numX - 1 );
381 double tx = ((x-dx) - x0 * fluid -> h ) * h1;
382 double x1 = MIN(x0 + 1, fluid ->numX-1);
384 double y0 = MIN( floor( (y-dy)*h1 ) , fluid ->numY - 1 );
385 double ty = ((y-dy) - y0 * fluid -> h ) * h1;
386 double y1 = MIN( y0 + 1 , fluid ->numY-1 );
388 double sx = 1.0 - tx;
389 double sy = 1.0 - ty;
391 double val = sx*sy * f[(size_t)(x0*n + y0)] +
392 tx*sy * f[(size_t)(x1*n + y0)] +
393 tx*ty * f[(size_t)(x1*n + y1)] +
394 sx*ty * f[(size_t)(x0*n + y1)];
411 size_t n = fluid ->
numY ;
412 double u = (fluid ->
u[i*n + j-1] + fluid ->
u[i*n + j] +
413 fluid ->
u[(i+1)*n + j-1] + fluid ->u[(i+1)*n + j]) * 0.25;
431 size_t n = fluid ->
numY;
432 double v = (fluid ->
v[(i-1)*n + j] + fluid ->v[i*n + j] +
433 fluid ->v[(i-1)*n + j+1] + fluid ->
v[i*n + j+1]) * 0.25;
449 size_t n = fluid ->
numY;
450 double h2 = 0.5 * fluid -> h ;
451 for(
size_t i = params -> x_start ; i < params -> x_end ; i++ )
453 for(
size_t j = params -> y_start ; j < params -> y_end ; j++ )
455 size_t index = i*n + j ;
457 if( !
_z( fluid , s[index] ) && !
_z( fluid , s[ (i-1)*n + j ] ) && j < fluid -> numY - 1)
459 double x = i * fluid -> h;
460 double y = j * fluid -> h + h2;
461 double u = fluid -> u[index];
464 x = x - fluid -> dt * u;
465 y = y - fluid -> dt * v;
467 fluid ->
newU[index] = u;
470 if( !
_z( fluid , s[index] ) && !
_z( fluid , s[index-1] ) && i < fluid ->numX - 1) {
471 double x = i * fluid -> h + h2;
472 double y = j * fluid -> h ;
475 double v = fluid ->
v[index];
476 x = x - fluid -> dt*u;
477 y = y - fluid -> dt*v;
479 fluid ->
newV[index] = v;
496 memcpy( fluid -> newU , fluid -> u , fluid -> numCells *
sizeof(
double ) );
497 memcpy( fluid -> newV , fluid -> v , fluid -> numCells *
sizeof(
double ) );
499 size_t n = fluid ->
numY;
500 double h2 = 0.5 * fluid -> h ;
501 for(
size_t i = 1; i < fluid -> numX ; i++ )
503 for(
size_t j = 1; j < fluid -> numY ; j++ )
505 size_t index = i*n + j ;
507 if( !
_z( fluid , s[index] ) && !
_z( fluid , s[ (i-1)*n + j ] ) && j < fluid -> numY - 1)
509 double x = i * fluid -> h;
510 double y = j * fluid -> h + h2;
511 double u = fluid -> u[index];
514 x = x - fluid -> dt * u;
515 y = y - fluid -> dt * v;
517 fluid ->
newU[index] = u;
520 if( !
_z( fluid , s[index] ) && !
_z( fluid , s[index-1] ) && i < fluid ->numX - 1) {
521 double x = i * fluid -> h + h2;
522 double y = j * fluid -> h ;
525 double v = fluid ->
v[index];
526 x = x - fluid -> dt*u;
527 y = y - fluid -> dt*v;
529 fluid ->
newV[index] = v;
533 double *ptr = fluid -> u ;
534 fluid -> u = fluid -> newU ;
535 fluid -> newU = ptr ;
538 fluid -> v = fluid -> newV ;
539 fluid -> newV = ptr ;
555 size_t n = fluid ->
numY;
556 double h2 = 0.5 * fluid -> h ;
557 for(
size_t i = params -> x_start ; i < params -> x_end ; i++ )
559 for(
size_t j = params -> y_start ; j < params -> y_end ; j++ )
561 size_t index = i*n + j ;
562 if( !
_z( fluid , s[ index ] ) )
564 double u = (fluid ->
u[ index ] + fluid ->
u[ (i+1)*n + j ] ) * 0.5;
565 double v = (fluid ->
v[ index ] + fluid ->
v[ index + 1]) * 0.5;
566 double x = i * fluid -> h + h2 - fluid -> dt*u;
567 double y = j * fluid -> h + h2 - fluid -> dt*v;
586 size_t n = fluid ->
numY;
587 double h2 = 0.5 * fluid -> h ;
589 memcpy( fluid -> newM , fluid -> m , fluid -> numCells *
sizeof(
double ) );
591 for(
size_t i = 1; i < fluid -> numX - 1 ; i++ )
593 for(
size_t j = 1; j < fluid -> numY - 1 ; j++ )
595 size_t index = i*n + j ;
596 if( !
_z( fluid , s[ index ] ) )
598 double u = (fluid ->
u[ index ] + fluid ->
u[ (i+1)*n + j ] ) * 0.5;
599 double v = (fluid ->
v[ index ] + fluid ->
v[ index + 1]) * 0.5;
600 double x = i * fluid -> h + h2 - fluid -> dt*u;
601 double y = j * fluid -> h + h2 - fluid -> dt*v;
607 double *ptr = fluid -> m ;
608 fluid -> m = fluid -> newM ;
609 fluid -> newM = ptr ;
625 memset( fluid -> p , 0 , fluid -> numCells *
sizeof(
double ) );
655 memset( fluid -> p , 0 , fluid -> numCells *
sizeof(
double ) );
658 for(
size_t iter = 0 ; iter < fluid -> numIters ; iter++ )
660 list_foreach( node , fluid -> solveIncompressibility_chunk_list )
673 memcpy( fluid -> newU , fluid -> u , fluid -> numCells *
sizeof(
double ) );
674 memcpy( fluid -> newV , fluid -> v , fluid -> numCells *
sizeof(
double ) );
684 double *ptr = fluid -> u ;
685 fluid -> u = fluid -> newU ;
686 fluid -> newU = ptr ;
689 fluid -> v = fluid -> newV ;
690 fluid -> newV = ptr ;
694 memcpy( fluid -> newM , fluid -> m , fluid -> numCells *
sizeof(
double ) );
704 fluid -> m = fluid -> newM ;
705 fluid -> newM = ptr ;
726 size_t n = fluid -> numY;
727 for(
size_t i = 1; i < fluid -> numX - 2 ; i++ )
729 for(
size_t j = 1 ; j < fluid -> numY - 2 ; j++ )
732 double dx = (i + 0.5) - x;
733 double dy = (j + 0.5) - y;
735 if( i > 7 && ( dx * dx + dy * dy < r * r) )
737 fluid -> s[i*n + j] = 0.0;
738 fluid -> m[i*n + j] = 1.0;
739 fluid -> u[i*n + j] = vx;
740 fluid -> u[(i+1)*n + j] = vx;
741 fluid -> v[i*n + j] = vy;
742 fluid -> v[i*n + j+1] = vy;
760 size_t n = fluid -> numY;
761 for(
size_t i = 1; i < fluid -> numX - 2 ; i++ )
763 for(
size_t j = 1 ; j < fluid -> numY - 2 ; j++ )
765 fluid -> s[ i*n + j ] = 1.0 ;
788 al_lock_bitmap( bitmap , al_get_bitmap_format( bitmap ) , ALLEGRO_LOCK_READONLY );
790 size_t n = fluid -> numY;
791 for(
size_t i = 1; i < fluid -> numX - 2 ; i++ )
793 for(
size_t j = 1 ; j < fluid -> numY - 2 ; j++ )
796 double dx = (i + 0.5) - x;
797 double dy = (j + 0.5) - y;
799 if( i > 7 && ( dx * dx + dy * dy < r * r) )
801 fluid -> s[i*n + j] = 0.0;
802 fluid -> m[i*n + j] = 1.0;
803 fluid -> u[i*n + j] = vx;
804 fluid -> v[i*n + j] = vy;
806 fluid -> u[(i+1)*n + j] = vx;
807 fluid -> v[i*n + j+1] = vy;
812 al_unlock_bitmap( bitmap );
829 val = MIN( MAX( val , minVal ) , maxVal - 0.0001 );
830 double d = maxVal - minVal;
831 if(
_zd( fluid , d ) )
837 val = (val - minVal) / d ;
840 size_t num = floor( val / m );
841 double s = (val - num * m) / m;
842 double r = 0.0 , g = 0.0 , b = 0.0 ;
844 case 0 : r = 0.0; g = s; b = 1.0;
break;
845 case 1 : r = 0.0; g = 1.0; b = 1.0-s;
break;
846 case 2 : r = s; g = 1.0; b = 0.0;
break;
847 case 3 : r = 1.0; g = 1.0 - s; b = 0.0;
break;
850 return al_map_rgb_f( r , g , b );
865 size_t n = fluid -> numY ;
867 double minP = fluid -> p[0];
868 double maxP = fluid -> p[0];
870 if( fluid -> showPressure )
872 for(
size_t i = 0; i < fluid -> numCells; i++)
874 minP = MIN( minP , fluid -> p[i] );
875 maxP = MAX( maxP , fluid -> p[i] );
879 ALLEGRO_COLOR color ;
880 double cScale = fluid -> cScale ;
882 for (
size_t i = 0; i < fluid -> numX; i++)
884 for (
size_t j = 0; j < fluid -> numY; j++)
886 int64_t x = i * cScale ;
887 int64_t y = j * cScale ;
888 int64_t cx = x + cScale ;
889 int64_t cy = y + cScale ;
891 double s = fluid -> m[i*n + j];
893 if( fluid -> showPaint )
897 else if( fluid -> showPressure)
899 float color_vec_f[ 3 ] = { 0.0 , 0.0 , 0.0 };
900 double p = fluid -> p[i*n + j];
902 if( fluid -> showSmoke )
904 al_unmap_rgb_f( color , color_vec_f , color_vec_f + 1 , color_vec_f + 2 );
905 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) );
908 else if( fluid -> showSmoke )
910 color = al_map_rgb_f( 1.0 - s , 0.0 , 0.0 );
914 color = al_map_rgb_f( s , s , s );
916 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
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(int 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 numX
number of cells in X
double * u
holder for u arrays
double * newV
holder for newV arrays
double * s
holder for s arrays
double * v
holder for v arrays
double * m
holder for m arrays
double * newM
holder for newM arrays
double * p
holder for p arrays
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
int n_fluid_simulate_threaded(N_FLUID *fluid, THREAD_POOL *thread_pool)
a threaded version of N_FLUID global processing function
#define _z(__fluid, __componant)
test if componant is near zero, according to fluid's precision
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 exectution in the thread pool.
int get_nb_cpu_cores()
get number of core of current system
#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
Structure of a trhead pool.
Common headers and low-level hugly 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",...