16#include <allegro5/allegro.h>
17#include <allegro5/allegro_ttf.h>
18#include "allegro5/allegro_audio.h"
19#include "allegro5/allegro_acodec.h"
20#include <allegro5/allegro_font.h>
21#include <allegro5/allegro_image.h>
22#include <allegro5/allegro_primitives.h>
24#include "ex_fluid_config.h"
27#define RESERVED_SAMPLES 16
29#define MAX_SAMPLE_DATA 10
31ALLEGRO_DISPLAY *display = NULL ;
41double drawFPS = 60.0 ;
42double logicFPS = 120.0 ;
44ALLEGRO_TIMER *fps_timer = NULL ;
45ALLEGRO_TIMER *logic_timer = NULL ;
57int main(
int argc,
char *argv[] )
61 setlocale (LC_ALL,
"POSIX");
70 char ver_str[ 128 ] =
"" ;
72 while( ( getoptret = getopt( argc, argv,
"hvV:L:" ) ) != EOF )
77 n_log(
LOG_NOTICE,
"\n %s -h help -v version -V DEBUGLEVEL (NOLOG,VERBOSE,NOTICE,ERROR,DEBUG)\n", argv[ 0 ] );
80 sprintf( ver_str,
"%s %s", __DATE__, __TIME__ );
84 if( !strncmp(
"INFO", optarg, 6 ) )
89 {
if( !strncmp(
"NOTICE", optarg, 6 ) )
94 if( !strncmp(
"VERBOSE", optarg, 7 ) )
100 if( !strncmp(
"ERROR", optarg, 5 ) )
106 if( !strncmp(
"DEBUG", optarg, 5 ) )
112 n_log(
LOG_ERR,
"%s is not a valid log level", optarg );
131 n_log(
LOG_ERR,
"\nPlease specify a log level after -V. \nAvailable values: NOLOG,VERBOSE,NOTICE,ERROR,DEBUG" );
134 n_log(
LOG_ERR,
"\nPlease specify a log file after -L" );
139 __attribute__ ((fallthrough));
141 n_log(
LOG_ERR,
"\n %s -h help -v version -V DEBUGLEVEL (NOLOG,VERBOSE,NOTICE,ERROR,DEBUG) -L logfile", argv[ 0 ] );
148 int threadedProcessing = 0 ;
151 if( load_app_state(
"CONFIGS/ex_fluid.cfg" , &WIDTH , &HEIGHT , &fullscreen , &bgmusic , &drawFPS , &logicFPS , fluid_data , &threadedProcessing ) != TRUE )
153 n_log(
LOG_ERR ,
"couldn't load CONFIGS/ex_fluid.cfg !");
156 double fluid_factor = fluid_data -> cScale ;
157 n_log(
LOG_DEBUG ,
"%s starting with params: %dx%d fullscreen(%d), music: %s" , argv[ 0 ] , WIDTH , HEIGHT , fullscreen ,
_str( bgmusic ) );
162 n_abort(
"Could not init Allegro.\n");
164 if( !al_init_acodec_addon() )
166 n_abort(
"Could not register addons.\n");
168 if (!al_install_audio())
170 n_log(
LOG_ERR ,
"Unable to initialize audio addon, disabling bgmusic\n");
173 if (!al_init_acodec_addon())
175 n_abort(
"Unable to initialize acoded addon\n");
177 if (!al_init_image_addon())
179 n_abort(
"Unable to initialize image addon\n");
181 if (!al_init_primitives_addon() )
183 n_abort(
"Unable to initialize primitives addon\n");
185 if( !al_init_font_addon() )
187 n_abort(
"Unable to initialize font addon\n");
189 if( !al_init_ttf_addon() )
191 n_abort(
"Unable to initialize ttf_font addon\n");
193 if( !al_install_keyboard() )
195 n_abort(
"Unable to initialize keyboard handler\n");
197 if( !al_install_mouse())
199 n_abort(
"Unable to initialize mouse handler\n");
202 if( bgmusic && !al_reserve_samples( RESERVED_SAMPLES ) )
204 n_abort(
"Could not set up voice and mixer.\n");
207 ALLEGRO_SAMPLE *sample_data[MAX_SAMPLE_DATA] = {NULL};
208 memset(sample_data, 0,
sizeof(sample_data));
210 ALLEGRO_EVENT_QUEUE *event_queue = NULL;
212 event_queue = al_create_event_queue();
215 fprintf(stderr,
"failed to create event_queue!\n");
221 al_set_new_display_flags( ALLEGRO_OPENGL|ALLEGRO_FULLSCREEN_WINDOW );
225 al_set_new_display_flags( ALLEGRO_OPENGL|ALLEGRO_WINDOWED );
228 al_set_new_bitmap_flags( ALLEGRO_VIDEO_BITMAP|ALLEGRO_NO_PRESERVE_TEXTURE );
230 display = al_create_display( WIDTH, HEIGHT );
233 n_abort(
"Unable to create display\n");
236 al_set_window_title( display, argv[ 0 ] );
238 ALLEGRO_FONT *font = al_load_font(
"DATAS/2Dumb.ttf", 18, 0 );
241 n_abort(
"Unable to load font DATAS/2Dumb.ttf\n");
245 fps_timer = al_create_timer( 1.0 / drawFPS );
246 logic_timer = al_create_timer( 1.0 / logicFPS );
248 al_register_event_source(event_queue, al_get_display_event_source(display));
249 al_start_timer( fps_timer );
250 al_start_timer( logic_timer );
251 al_register_event_source(event_queue, al_get_timer_event_source(fps_timer));
252 al_register_event_source(event_queue, al_get_timer_event_source(logic_timer));
254 al_register_event_source(event_queue, al_get_keyboard_event_source());
255 al_register_event_source(event_queue, al_get_mouse_event_source());
257 bool backbuffer = 1 ;
258 ALLEGRO_BITMAP *scrbuf = NULL ;
259 ALLEGRO_BITMAP *bitmap = al_create_bitmap( WIDTH , HEIGHT );
261 al_hide_mouse_cursor(display);
266 KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_ESC, KEY_SPACE, KEY_CTRL , KEY_SHIFT , KEY_PAD_MINUS , KEY_PAD_PLUS , KEY_PAD_ENTER , KEY_M , KEY_W , KEY_F1 , KEY_F2 , KEY_F3 , KEY_F4 , KEY_F5 , KEY_F6
268 int key[ 19 ] = {
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false};
272 if( !( sample_data[ 0 ] = al_load_sample( bgmusic ) ) )
277 al_play_sample(sample_data[ 0 ] , 1 , 0 , 1 , ALLEGRO_PLAYMODE_LOOP , NULL );
283 fluid_sim =
new_n_fluid( fluid_data -> density , fluid_data -> gravity , fluid_data -> numIters , fluid_data -> fluid_production_percentage , fluid_data -> overRelaxation , WIDTH / fluid_factor , HEIGHT / fluid_factor );
285 fluid_sim -> density = fluid_data -> density ;
286 fluid_sim -> gravity = fluid_data -> gravity ;
287 fluid_sim -> numIters = fluid_data -> numIters ;
288 fluid_sim -> fluid_production_percentage = fluid_data -> fluid_production_percentage ;
289 fluid_sim -> overRelaxation = fluid_data -> overRelaxation ;
290 fluid_sim -> cScale = fluid_data -> cScale ;
293 fluid_sim -> dt = 1.0 / logicFPS ;
295 size_t n = fluid_sim -> numY;
297 for(
size_t i = 0; i < fluid_sim -> numX; i++)
299 for (
size_t j = 0; j < fluid_sim -> numY; j++)
302 if (i == 0 || j == 0 || j == fluid_sim -> numY-1)
305 fluid_sim -> s[i*n + j] = s ;
308 fluid_sim -> u[i*n + j] = inVel;
312 double pipeH = fluid_sim -> fluid_production_percentage * fluid_sim -> numY;
313 size_t minJ = floor( 0.5 * fluid_sim -> numY - 0.5 * pipeH );
314 size_t maxJ = floor( 0.5 * fluid_sim -> numY + 0.5 * pipeH );
315 for(
size_t j = 0 ; j < minJ ; j ++ )
316 fluid_sim -> m[j] = 1.0;
317 for (
size_t j = minJ; j < maxJ; j++)
318 fluid_sim -> m[j] = 0.0;
319 for(
size_t j = maxJ ; j < fluid_sim -> numY ; j ++ )
320 fluid_sim -> m[j] = 1.0;
322 bool do_draw = 1 , do_logic = 1 ;
323 int mx = WIDTH/3 , my = HEIGHT/2 , mouse_button = 0 , mouse_b1 = 0 , mouse_b2 = 0 ;
327 al_flush_event_queue( event_queue );
328 al_set_mouse_xy( display , WIDTH/3 , HEIGHT/2 );
330 int w = al_get_display_width( display );
331 int h = al_get_display_height( display );
333 bitmap = al_create_bitmap( WIDTH, HEIGHT );
335 size_t logic_duration = 0 ;
336 size_t drawing_duration = 0 ;
343 al_wait_for_event(event_queue, &ev);
345 if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
347 switch(ev.keyboard.keycode)
352 case ALLEGRO_KEY_DOWN:
355 case ALLEGRO_KEY_LEFT:
358 case ALLEGRO_KEY_RIGHT:
361 case ALLEGRO_KEY_ESCAPE:
364 case ALLEGRO_KEY_SPACE:
367 case ALLEGRO_KEY_LSHIFT:
368 case ALLEGRO_KEY_RSHIFT:
371 case ALLEGRO_KEY_PAD_MINUS:
372 key[KEY_PAD_MINUS] = 1 ;
374 case ALLEGRO_KEY_PAD_PLUS:
375 key[KEY_PAD_PLUS] = 1 ;
377 case ALLEGRO_KEY_PAD_ENTER:
378 key[KEY_PAD_ENTER] = 1 ;
386 case ALLEGRO_KEY_LCTRL:
387 case ALLEGRO_KEY_RCTRL:
412 else if(ev.type == ALLEGRO_EVENT_KEY_UP)
414 switch(ev.keyboard.keycode)
419 case ALLEGRO_KEY_DOWN:
422 case ALLEGRO_KEY_LEFT:
425 case ALLEGRO_KEY_RIGHT:
428 case ALLEGRO_KEY_ESCAPE:
431 case ALLEGRO_KEY_SPACE:
434 case ALLEGRO_KEY_LSHIFT:
435 case ALLEGRO_KEY_RSHIFT:
438 case ALLEGRO_KEY_PAD_MINUS:
439 key[KEY_PAD_MINUS] = 0 ;
441 case ALLEGRO_KEY_PAD_PLUS:
442 key[KEY_PAD_PLUS] = 0 ;
444 case ALLEGRO_KEY_PAD_ENTER:
445 key[KEY_PAD_ENTER] = 0 ;
453 case ALLEGRO_KEY_LCTRL:
454 case ALLEGRO_KEY_RCTRL:
481 else if( ev.type == ALLEGRO_EVENT_TIMER )
483 if( al_get_timer_event_source( fps_timer ) == ev.any.source )
487 else if( al_get_timer_event_source( logic_timer ) == ev.any.source )
492 else if( ev.type == ALLEGRO_EVENT_MOUSE_AXES )
497 else if( ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN )
499 if( ev.mouse.button == 1 )
501 if( ev.mouse.button == 2 )
504 else if( ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP )
506 if( ev.mouse.button == 1 )
508 if( ev.mouse.button == 2 )
518 else if( ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN || ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT )
520 al_clear_keyboard_state( display );
521 al_flush_event_queue( event_queue );
529 fluid_sim -> showSmoke = 1 ;
533 fluid_sim -> showSmoke = 0 ;
537 fluid_sim -> showPressure = 1 ;
541 fluid_sim -> showPressure = 0 ;
545 fluid_sim -> showPaint = 1 ;
549 fluid_sim -> showPaint = 0 ;
553 fluid_sim -> density += 100.0 ;
557 fluid_sim -> density -= 100.0 ;
558 if( fluid_sim -> density < 1.0 ) fluid_sim -> density = 1.0 ;
562 fluid_sim -> numIters ++ ;
566 fluid_sim -> numIters -- ;
567 if( fluid_sim -> numIters < 1.0 ) fluid_sim -> numIters = 1.0 ;
569 if( key[KEY_PAD_PLUS] )
571 fluid_sim -> fluid_production_percentage += 0.01 ;
572 if( fluid_sim -> fluid_production_percentage > 1.0 ) fluid_sim -> fluid_production_percentage = 1.0 ;
574 if( key[KEY_PAD_MINUS] )
576 fluid_sim -> fluid_production_percentage -= 0.01 ;
577 if( fluid_sim -> fluid_production_percentage < 0.1 ) fluid_sim -> fluid_production_percentage = 0.1 ;
579 if( mouse_button != -1 )
584 }
while( !al_is_event_queue_empty( event_queue) );
589 static int old_mx = -1 , old_my = -1 ;
590 double vx = 0.0 , vy = 0.0 ;
591 if( old_mx != mx || old_my != my )
593 if( old_mx != -1 && old_my != -1 )
595 vx = (old_mx - mx ) / logicFPS ;
596 vy = (old_my - my ) / logicFPS ;
601 n_fluid_setObstacle( fluid_sim , mx / fluid_factor , ( my / fluid_factor ) - 20.0 , vx , vy , fluid_factor/2 );
602 n_fluid_setObstacle( fluid_sim , (mx / fluid_factor ) - 15 , my / fluid_factor , vx , vy , fluid_factor/2 + fluid_factor/3 );
603 n_fluid_setObstacle( fluid_sim , (mx / fluid_factor ) + 15 , my / fluid_factor - 10.0 , vx , vy , fluid_factor/2 + fluid_factor/2 );
604 n_fluid_setObstacle( fluid_sim , (mx / fluid_factor ) + 15 , my / fluid_factor + 10.0 , vx , vy , fluid_factor/2 + fluid_factor/2 );
605 n_fluid_setObstacle( fluid_sim , mx / fluid_factor , ( my / fluid_factor ) + 20.0 , vx , vy , fluid_factor/2 );
608 double pipeH = fluid_sim -> fluid_production_percentage * fluid_sim -> numY;
609 size_t minJ = floor( 0.5 * fluid_sim -> numY - 0.5 * pipeH );
610 size_t maxJ = floor( 0.5 * fluid_sim -> numY + 0.5 * pipeH );
611 for(
size_t j = 0 ; j < minJ ; j ++ )
612 fluid_sim -> m[j] = 1.0;
613 for (
size_t j = minJ; j < maxJ; j++)
614 fluid_sim -> m[j] = 0.0;
615 for(
size_t j = maxJ ; j < fluid_sim -> numY ; j ++ )
616 fluid_sim -> m[j] = 1.0;
617 for (
size_t j = minJ; j < maxJ; j++)
618 fluid_sim -> m[j] = 0.0;
620 if( threadedProcessing == 1 )
625 logic_duration = ( logic_duration +
get_usec( &logic_chrono ) ) / 2;
633 scrbuf = al_get_backbuffer(display);
637 al_set_target_bitmap( scrbuf );
640 al_lock_bitmap( scrbuf , al_get_bitmap_format( scrbuf ) , ALLEGRO_LOCK_READWRITE );
644 al_draw_circle( mx , my - 20 * fluid_factor , fluid_factor * fluid_factor / 2 , al_map_rgb( 255 , 0 , 0 ) , 2.0 );
645 al_draw_circle( mx - 15 * fluid_factor , my , fluid_factor * fluid_factor / 2 + (fluid_factor*fluid_factor)/3 , al_map_rgb( 255 , 0 , 0 ) , 2.0 );
646 al_draw_circle( mx + 15 * fluid_factor , my + 10.0 * fluid_factor , fluid_factor * fluid_factor / 2 + (fluid_factor*fluid_factor)/2 , al_map_rgb( 255 , 0 , 0 ) , 2.0 );
647 al_draw_circle( mx + 15 * fluid_factor , my - 10.0 * fluid_factor , fluid_factor * fluid_factor / 2 + (fluid_factor*fluid_factor)/2 , al_map_rgb( 255 , 0 , 0 ) , 2.0 );
648 al_draw_circle( mx , my + 20 * fluid_factor , fluid_factor *fluid_factor / 2 , al_map_rgb( 255 , 0 , 0 ) , 2.0 );
651 static N_STR *textout = NULL ;
652 nstrprintf( textout ,
"[F1/F2]:showSmoke:%d [F3/F4]:showPressure:%d [F5/F6]:showPaint:%d" , fluid_sim -> showSmoke , fluid_sim -> showPressure , fluid_sim -> showPaint );
653 al_draw_text( font, al_map_rgb( 0 , 0 , 255 ), WIDTH , 10 , ALLEGRO_ALIGN_RIGHT ,
_nstr( textout ) );
655 nstrprintf( textout ,
"numIters: %zd production: %3.3g density: %3.3g" , fluid_sim -> numIters , fluid_sim -> fluid_production_percentage , fluid_sim -> density );
656 al_draw_text( font, al_map_rgb( 0 , 0 , 255 ), WIDTH , 25 , ALLEGRO_ALIGN_RIGHT ,
_nstr( textout ) );
658 nstrprintf( textout ,
"logic(max %zd): %zd usecs" , (
size_t)(1000000.0/logicFPS) , logic_duration );
659 al_draw_text( font, al_map_rgb( 0 , 0 , 255 ), 5 , 10 , ALLEGRO_ALIGN_LEFT ,
_nstr( textout ) );
661 nstrprintf( textout ,
"drawing(max %zd): %zd usecs" , (
size_t)(1000000.0/drawFPS) , drawing_duration );
662 al_draw_text( font, al_map_rgb( 0 , 0 , 255 ), 5 , 30 , ALLEGRO_ALIGN_LEFT ,
_nstr( textout ) );
666 al_unlock_bitmap( scrbuf );
667 al_set_target_bitmap(al_get_backbuffer(display));
668 al_draw_bitmap( scrbuf, w/2 - al_get_bitmap_width( scrbuf ) /2, h/2 - al_get_bitmap_height( scrbuf ) / 2, 0 );
671 drawing_duration = ( drawing_duration +
get_usec( &drawing_chrono ) ) / 2;
679 while( !key[KEY_ESC] && !DONE );
681 al_uninstall_system();
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define _str(__PTR)
define true
void n_abort(char const *format,...)
abort program with a text
#define Free(__ptr)
Free Handler to get errors.
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
int set_log_file(char *file)
Set the logging to a file instead of stderr.
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
#define LOG_NOTICE
normal but significant condition
#define LOG_INFO
informational
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
int n_fluid_simulate(N_FLUID *fluid)
non threaded version of N_FLUID global processing function
int n_fluid_resetObstacles(N_FLUID *fluid)
reset the obstacles set in a N_FLUID
int n_fluid_setObstacle(N_FLUID *fluid, double x, double y, double vx, double vy, double r)
set an obstacle in the fluid grid
N_FLUID * new_n_fluid(double density, double gravity, size_t numIters, double dt, double overRelaxation, size_t sx, size_t sy)
!
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
#define nstrprintf(__nstr_var,...)
Macro to quickly allocate and sprintf to N_STR *.
A box including a string and his lenght.
int start_HiTimer(N_TIME *timer)
Initialize or restart from zero any N_TIME HiTimer.
time_t get_usec(N_TIME *timer)
Poll any N_TIME HiTimer, returning usec, and moving currentTime to startTime.
int get_nb_cpu_cores()
get number of core of current system
THREAD_POOL * new_thread_pool(int nbmaxthr, int nb_max_waiting)
Create a new pool of nbmaxthr threads.
Structure of a trhead pool.
Common headers and low-level hugly functions & define.
fluid management port from "How to write an Eulerian fluid simulator with 200 lines of code",...
List structures and definitions.
static FILE * log_file
static FILE handling if logging to file is enabled
N_STR and string function declaration.