2012-12-23 14:29:54 +01:00
/*! \file main.c
* \ brief Main file of SuperDerpy engine .
2012-02-28 13:09:12 +01:00
*
2012-12-23 14:29:54 +01:00
* Contains basic functions shared by all views .
2012-02-28 13:09:12 +01:00
*/
2012-03-04 13:32:42 +01:00
/*
* Copyright ( c ) Sebastian Krzyszkowiak < dos @ dosowisko . net >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2012-09-19 01:20:24 +02:00
*
* Also , ponies .
2012-03-04 13:32:42 +01:00
*/
2016-11-06 03:10:43 +01:00
# ifdef LIBSUPERDERPY_MOUSE_EMULATION
# define ALLEGRO_UNSTABLE
# endif
2012-02-15 23:57:06 +01:00
# include <stdio.h>
2012-03-03 21:09:49 +01:00
# include <math.h>
2012-05-07 22:44:39 +02:00
# include <locale.h>
2012-12-26 02:25:56 +01:00
# include <dlfcn.h>
2016-07-03 20:34:31 +02:00
# include <unistd.h>
2016-07-05 01:30:06 +02:00
# include <libgen.h>
2016-09-08 00:32:21 +02:00
# include <sys/param.h>
2016-08-27 00:46:38 +02:00
# include "internal.h"
# include "libsuperderpy.h"
# include "3rdparty/valgrind.h"
2016-07-02 23:23:08 +02:00
# ifdef ALLEGRO_MACOSX
# include <mach-o/dyld.h>
# endif
2012-02-15 23:57:06 +01:00
2016-09-08 00:32:21 +02:00
SYMBOL_EXPORT struct Game * libsuperderpy_init ( int argc , char * * argv , const char * name , struct Viewport viewport ) {
2016-06-27 21:21:59 +02:00
2016-11-08 22:11:10 +01:00
struct Game * game = calloc ( 1 , sizeof ( struct Game ) ) ;
2012-08-04 21:58:31 +02:00
2016-07-03 22:38:36 +02:00
game - > name = name ;
2016-08-23 02:13:15 +02:00
game - > viewport_config = viewport ;
2012-07-03 23:44:03 +02:00
2016-07-02 23:23:08 +02:00
# ifdef ALLEGRO_MACOSX
2016-09-08 00:32:21 +02:00
getcwd ( game - > _priv . cwd , MAXPATHLEN ) ;
2016-07-02 23:23:08 +02:00
char exe_path [ MAXPATHLEN ] ;
uint32_t size = sizeof ( exe_path ) ;
_NSGetExecutablePath ( exe_path , & size ) ;
2016-07-05 01:30:06 +02:00
chdir ( dirname ( exe_path ) ) ;
2016-07-02 23:23:08 +02:00
# endif
2016-07-03 22:38:36 +02:00
2012-09-03 02:25:32 +02:00
if ( ! al_init ( ) ) {
fprintf ( stderr , " failed to initialize allegro! \n " ) ;
2016-07-03 22:38:36 +02:00
return NULL ;
2012-09-03 02:25:32 +02:00
}
2012-09-03 02:08:12 +02:00
2016-07-03 22:38:36 +02:00
InitConfig ( game ) ;
2012-02-16 12:48:48 +01:00
2016-07-03 22:38:36 +02:00
game - > _priv . fps_count . frames_done = 0 ;
game - > _priv . fps_count . fps = 0 ;
game - > _priv . fps_count . old_time = 0 ;
2012-12-23 14:29:54 +01:00
2016-07-03 22:38:36 +02:00
game - > _priv . font_bsod = NULL ;
game - > _priv . console = NULL ;
2016-08-16 23:20:00 +02:00
game - > _priv . console_tmp = NULL ;
2012-12-24 19:41:12 +01:00
2016-08-15 04:37:27 +02:00
game - > _priv . garbage = NULL ;
2016-11-08 22:11:10 +01:00
game - > eventHandler = NULL ;
2016-07-03 22:38:36 +02:00
game - > config . fullscreen = atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " fullscreen " , " 1 " ) ) ;
game - > config . music = atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " music " , " 10 " ) ) ;
game - > config . voice = atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " voice " , " 10 " ) ) ;
game - > config . fx = atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " fx " , " 10 " ) ) ;
game - > config . debug = atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " debug " , " 0 " ) ) ;
game - > config . width = atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " width " , " 1280 " ) ) ;
if ( game - > config . width < 320 ) game - > config . width = 320 ;
game - > config . height = atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " height " , " 720 " ) ) ;
if ( game - > config . height < 180 ) game - > config . height = 180 ;
2012-02-26 12:59:45 +01:00
2016-08-16 18:01:12 +02:00
game - > _priv . showconsole = game - > config . debug ;
2012-02-25 22:26:31 +01:00
if ( ! al_init_image_addon ( ) ) {
fprintf ( stderr , " failed to initialize image addon! \n " ) ;
2012-04-14 22:26:33 +02:00
/*al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
2016-07-02 23:23:08 +02:00
NULL , ALLEGRO_MESSAGEBOX_ERROR ) ; */
2016-07-03 22:38:36 +02:00
return NULL ;
2012-02-25 22:26:31 +01:00
}
2012-02-15 23:57:06 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_init_acodec_addon ( ) ) {
fprintf ( stderr , " failed to initialize audio codecs! \n " ) ;
2016-07-03 22:38:36 +02:00
return NULL ;
2012-02-25 22:26:31 +01:00
}
2012-02-19 19:17:04 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_install_audio ( ) ) {
fprintf ( stderr , " failed to initialize audio! \n " ) ;
2016-07-03 22:38:36 +02:00
return NULL ;
2012-02-25 22:26:31 +01:00
}
2012-02-15 23:57:06 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_install_keyboard ( ) ) {
fprintf ( stderr , " failed to initialize keyboard! \n " ) ;
2016-07-03 22:38:36 +02:00
return NULL ;
2012-02-25 22:26:31 +01:00
}
2012-02-15 23:57:06 +01:00
2012-05-09 10:58:45 +02:00
if ( ! al_init_primitives_addon ( ) ) {
fprintf ( stderr , " failed to initialize primitives! \n " ) ;
2016-07-03 22:38:36 +02:00
return NULL ;
2012-05-09 10:58:45 +02:00
}
2016-06-27 21:21:59 +02:00
2016-07-02 23:23:08 +02:00
if ( ! al_install_mouse ( ) ) {
fprintf ( stderr , " failed to initialize the mouse! \n " ) ;
2016-07-03 22:38:36 +02:00
return NULL ;
2016-07-02 23:23:08 +02:00
}
2012-02-25 22:26:31 +01:00
al_init_font_addon ( ) ;
2012-02-15 23:57:06 +01:00
2012-02-25 22:26:31 +01:00
if ( ! al_init_ttf_addon ( ) ) {
fprintf ( stderr , " failed to initialize fonts! \n " ) ;
2016-07-03 22:38:36 +02:00
return NULL ;
2012-02-25 22:26:31 +01:00
}
2012-02-16 12:48:48 +01:00
2016-11-08 22:11:10 +01:00
game - > touch = false ;
if ( ! atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " disableTouch " , " 0 " ) ) ) {
game - > touch = al_install_touch_input ( ) ;
}
2016-11-06 03:10:43 +01:00
# ifdef LIBSUPERDERPY_MOUSE_EMULATION
2016-11-08 22:11:10 +01:00
if ( game - > touch ) {
2016-11-08 17:56:19 +01:00
al_set_mouse_emulation_mode ( ALLEGRO_MOUSE_EMULATION_TRANSPARENT ) ;
}
2016-11-06 03:10:43 +01:00
# endif
2016-12-05 23:56:41 +01:00
al_install_joystick ( ) ;
2016-11-08 17:42:23 +01:00
al_set_new_display_flags ( ALLEGRO_PROGRAMMABLE_PIPELINE | ( game - > config . fullscreen ? ALLEGRO_FULLSCREEN_WINDOW : ALLEGRO_WINDOWED ) | ALLEGRO_RESIZABLE | ALLEGRO_OPENGL ) ; // TODO: make ALLEGRO_PROGRAMMABLE_PIPELINE game-optional
2016-07-03 22:38:36 +02:00
al_set_new_display_option ( ALLEGRO_VSYNC , 2 - atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " vsync " , " 1 " ) ) , ALLEGRO_SUGGEST ) ;
al_set_new_display_option ( ALLEGRO_OPENGL , atoi ( GetConfigOptionDefault ( game , " SuperDerpy " , " opengl " , " 1 " ) ) , ALLEGRO_SUGGEST ) ;
2017-06-26 03:18:54 +02:00
# ifdef LIBSUPERDERPY_ORIENTATION_LANDSCAPE
al_set_new_display_option ( ALLEGRO_SUPPORTED_ORIENTATIONS , ALLEGRO_DISPLAY_ORIENTATION_LANDSCAPE , ALLEGRO_SUGGEST ) ;
# elif defined(LIBSUPERDERPY_ORIENTATION_PORTRAIT)
al_set_new_display_option ( ALLEGRO_SUPPORTED_ORIENTATIONS , ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT , ALLEGRO_SUGGEST ) ;
# endif
2016-06-27 21:20:02 +02:00
# ifdef ALLEGRO_WINDOWS
al_set_new_window_position ( 20 , 40 ) ; // workaround nasty Windows bug with window being created off-screen
# endif
2012-05-10 20:02:22 +02:00
2016-08-23 02:13:15 +02:00
al_set_new_window_title ( game - > name ) ;
2016-07-03 22:38:36 +02:00
game - > display = al_create_display ( game - > config . width , game - > config . height ) ;
if ( ! game - > display ) {
2012-02-25 22:26:31 +01:00
fprintf ( stderr , " failed to create display! \n " ) ;
2016-07-03 22:38:36 +02:00
return NULL ;
2012-02-25 22:26:31 +01:00
}
2012-12-24 19:41:12 +01:00
2016-11-06 03:10:43 +01:00
# ifdef ALLEGRO_ANDROID
al_android_set_apk_file_interface ( ) ;
al_android_set_apk_fs_interface ( ) ;
# endif
2016-08-23 02:13:15 +02:00
SetupViewport ( game , viewport ) ;
2012-12-28 02:55:52 +01:00
2016-07-03 22:38:36 +02:00
PrintConsole ( game , " Viewport %dx%d " , game - > viewport . width , game - > viewport . height ) ;
2012-12-28 02:55:52 +01:00
2016-07-03 22:38:36 +02:00
ALLEGRO_BITMAP * icon = al_load_bitmap ( GetDataFilePath ( game , GetGameName ( game , " icons/%s.png " ) ) ) ;
al_set_display_icon ( game - > display , icon ) ;
2012-09-19 01:20:24 +02:00
al_destroy_bitmap ( icon ) ;
2016-07-03 22:38:36 +02:00
if ( game - > config . fullscreen ) al_hide_mouse_cursor ( game - > display ) ;
2016-07-02 23:23:08 +02:00
al_inhibit_screensaver ( true ) ;
2012-02-29 23:00:59 +01:00
2016-06-27 21:20:02 +02:00
al_set_new_bitmap_flags ( ALLEGRO_MIN_LINEAR ) ;
2012-02-29 23:00:59 +01:00
2016-07-03 22:38:36 +02:00
game - > _priv . gamestates = NULL ;
2016-08-16 18:41:50 +02:00
game - > _priv . gamestate_scheduled = false ;
2012-12-25 00:22:03 +01:00
2016-08-29 22:47:55 +02:00
al_init_user_event_source ( & ( game - > event_source ) ) ;
2016-07-03 22:38:36 +02:00
game - > _priv . event_queue = al_create_event_queue ( ) ;
if ( ! game - > _priv . event_queue ) {
FatalError ( game , true , " Failed to create event queue. " ) ;
al_destroy_display ( game - > display ) ;
return NULL ;
2012-02-25 22:26:31 +01:00
}
2012-02-15 23:57:06 +01:00
2016-07-03 22:38:36 +02:00
game - > audio . v = al_create_voice ( 44100 , ALLEGRO_AUDIO_DEPTH_INT16 , ALLEGRO_CHANNEL_CONF_2 ) ;
game - > audio . mixer = al_create_mixer ( 44100 , ALLEGRO_AUDIO_DEPTH_FLOAT32 , ALLEGRO_CHANNEL_CONF_2 ) ;
game - > audio . fx = al_create_mixer ( 44100 , ALLEGRO_AUDIO_DEPTH_FLOAT32 , ALLEGRO_CHANNEL_CONF_2 ) ;
game - > audio . music = al_create_mixer ( 44100 , ALLEGRO_AUDIO_DEPTH_FLOAT32 , ALLEGRO_CHANNEL_CONF_2 ) ;
game - > audio . voice = al_create_mixer ( 44100 , ALLEGRO_AUDIO_DEPTH_FLOAT32 , ALLEGRO_CHANNEL_CONF_2 ) ;
al_attach_mixer_to_voice ( game - > audio . mixer , game - > audio . v ) ;
al_attach_mixer_to_mixer ( game - > audio . fx , game - > audio . mixer ) ;
al_attach_mixer_to_mixer ( game - > audio . music , game - > audio . mixer ) ;
al_attach_mixer_to_mixer ( game - > audio . voice , game - > audio . mixer ) ;
al_set_mixer_gain ( game - > audio . fx , game - > config . fx / 10.0 ) ;
al_set_mixer_gain ( game - > audio . music , game - > config . music / 10.0 ) ;
al_set_mixer_gain ( game - > audio . voice , game - > config . voice / 10.0 ) ;
setlocale ( LC_NUMERIC , " C " ) ;
2016-06-27 21:20:02 +02:00
2016-07-04 00:06:50 +02:00
game - > _priv . argc = argc ;
game - > _priv . argv = argv ;
2012-02-24 13:08:44 +01:00
2016-07-03 22:38:36 +02:00
game - > data = NULL ;
2012-05-07 22:44:39 +02:00
2016-07-03 22:38:36 +02:00
game - > shuttingdown = false ;
game - > restart = false ;
2012-12-24 19:41:12 +01:00
2016-08-20 03:32:32 +02:00
game - > show_loading_on_launch = false ;
2016-07-03 22:38:36 +02:00
return game ;
}
2012-04-09 16:41:10 +02:00
2016-07-04 01:12:55 +02:00
SYMBOL_EXPORT int libsuperderpy_run ( struct Game * game ) {
2016-07-03 22:38:36 +02:00
al_register_event_source ( game - > _priv . event_queue , al_get_display_event_source ( game - > display ) ) ;
al_register_event_source ( game - > _priv . event_queue , al_get_mouse_event_source ( ) ) ;
al_register_event_source ( game - > _priv . event_queue , al_get_keyboard_event_source ( ) ) ;
2016-12-05 23:56:41 +01:00
al_register_event_source ( game - > _priv . event_queue , al_get_joystick_event_source ( ) ) ;
2016-11-08 22:11:10 +01:00
if ( game - > touch ) {
2016-11-08 17:56:19 +01:00
al_register_event_source ( game - > _priv . event_queue , al_get_touch_input_event_source ( ) ) ;
2016-11-06 03:10:43 +01:00
# ifdef LIBSUPERDERPY_MOUSE_EMULATION
2016-11-08 17:56:19 +01:00
al_register_event_source ( game - > _priv . event_queue , al_get_touch_input_mouse_emulation_event_source ( ) ) ;
2016-11-06 03:10:43 +01:00
# endif
2016-11-08 17:56:19 +01:00
}
2016-08-29 22:47:55 +02:00
al_register_event_source ( game - > _priv . event_queue , & ( game - > event_source ) ) ;
2012-04-09 16:41:10 +02:00
2016-07-03 22:38:36 +02:00
al_clear_to_color ( al_map_rgb ( 0 , 0 , 0 ) ) ;
game - > _priv . timer = al_create_timer ( ALLEGRO_BPS_TO_SECS ( 60 ) ) ; // logic timer
if ( ! game - > _priv . timer ) {
FatalError ( game , true , " Failed to create logic timer. " ) ;
return 1 ;
}
al_register_event_source ( game - > _priv . event_queue , al_get_timer_event_source ( game - > _priv . timer ) ) ;
al_flip_display ( ) ;
al_start_timer ( game - > _priv . timer ) ;
struct Gamestate * tmp = game - > _priv . gamestates ;
while ( tmp ) {
2016-08-20 03:32:32 +02:00
// don't show loading screen on init if requested
tmp - > showLoading = game - > show_loading_on_launch ;
2016-07-03 22:38:36 +02:00
tmp = tmp - > next ;
}
2012-12-24 19:41:12 +01:00
2012-12-28 03:42:59 +01:00
char libname [ 1024 ] = { } ;
2016-07-03 22:38:36 +02:00
snprintf ( libname , 1024 , " libsuperderpy-%s-loading " LIBRARY_EXTENSION , game - > name ) ;
2015-04-18 18:07:29 +02:00
void * handle = dlopen ( libname , RTLD_NOW ) ;
2012-12-28 03:42:59 +01:00
if ( ! handle ) {
2016-07-05 01:30:06 +02:00
FatalError ( game , true , " Error while initializing loading screen: %s " , dlerror ( ) ) ;
2016-07-03 22:38:36 +02:00
return 2 ;
2012-12-28 03:42:59 +01:00
} else {
2016-07-03 22:38:36 +02:00
# define GS_LOADINGERROR FatalError(game, true, "Error on resolving loading symbol: %s", dlerror()); return 3;
2012-12-28 03:42:59 +01:00
2016-07-03 22:38:36 +02:00
if ( ! ( game - > _priv . loading . Draw = dlsym ( handle , " Draw " ) ) ) { GS_LOADINGERROR ; }
if ( ! ( game - > _priv . loading . Load = dlsym ( handle , " Load " ) ) ) { GS_LOADINGERROR ; }
if ( ! ( game - > _priv . loading . Start = dlsym ( handle , " Start " ) ) ) { GS_LOADINGERROR ; }
if ( ! ( game - > _priv . loading . Stop = dlsym ( handle , " Stop " ) ) ) { GS_LOADINGERROR ; }
if ( ! ( game - > _priv . loading . Unload = dlsym ( handle , " Unload " ) ) ) { GS_LOADINGERROR ; }
2012-12-28 03:42:59 +01:00
}
2016-07-03 22:38:36 +02:00
game - > _priv . loading . data = ( * game - > _priv . loading . Load ) ( game ) ;
2012-12-28 03:42:59 +01:00
2012-12-25 00:22:03 +01:00
bool redraw = false ;
2016-11-06 03:10:43 +01:00
game - > _priv . draw = true ;
2012-12-25 00:22:03 +01:00
2012-02-25 22:26:31 +01:00
while ( 1 ) {
2016-11-08 22:11:10 +01:00
ClearGarbage ( game ) ;
2016-09-08 00:32:21 +02:00
// TODO: split mainloop to functions to make it readable
2012-02-25 22:26:31 +01:00
ALLEGRO_EVENT ev ;
2016-11-08 10:34:32 +01:00
if ( game - > _priv . draw & & ( ( redraw & & al_is_event_queue_empty ( game - > _priv . event_queue ) ) | | ( game - > _priv . gamestate_scheduled ) ) ) {
2012-12-25 00:22:03 +01:00
2016-08-16 18:41:50 +02:00
game - > _priv . gamestate_scheduled = false ;
2016-07-03 22:38:36 +02:00
struct Gamestate * tmp = game - > _priv . gamestates ;
2016-08-13 18:01:46 +02:00
2016-08-16 18:41:50 +02:00
game - > _priv . tmp_gamestate . toLoad = 0 ;
game - > _priv . tmp_gamestate . loaded = 0 ;
2012-12-28 00:00:37 +01:00
2016-09-08 00:32:21 +02:00
// TODO: support gamestate dependences
2012-12-25 00:22:03 +01:00
while ( tmp ) {
2016-08-13 20:03:58 +02:00
if ( tmp - > pending_stop ) {
2016-07-03 22:38:36 +02:00
PrintConsole ( game , " Stopping gamestate \" %s \" ... " , tmp - > name ) ;
2016-08-16 18:41:50 +02:00
game - > _priv . current_gamestate = tmp ;
2016-08-20 03:02:39 +02:00
( * tmp - > api - > Gamestate_Stop ) ( game , tmp - > data ) ;
2012-12-26 20:02:40 +01:00
tmp - > started = false ;
2016-08-13 20:03:58 +02:00
tmp - > pending_stop = false ;
2012-12-27 21:05:28 +01:00
}
2016-08-16 18:41:50 +02:00
if ( tmp - > pending_load ) game - > _priv . tmp_gamestate . toLoad + + ;
2012-12-27 21:05:28 +01:00
tmp = tmp - > next ;
}
2016-07-03 22:38:36 +02:00
tmp = game - > _priv . gamestates ;
2012-12-28 00:00:37 +01:00
2016-08-16 18:41:50 +02:00
game - > _priv . tmp_gamestate . t = - 1 ;
2016-06-27 21:21:59 +02:00
2012-12-27 21:05:28 +01:00
while ( tmp ) {
2016-08-13 20:03:58 +02:00
if ( tmp - > pending_unload ) {
2016-07-03 22:38:36 +02:00
PrintConsole ( game , " Unloading gamestate \" %s \" ... " , tmp - > name ) ;
al_stop_timer ( game - > _priv . timer ) ;
2012-12-26 20:02:40 +01:00
tmp - > loaded = false ;
2016-08-13 20:03:58 +02:00
tmp - > pending_unload = false ;
2016-08-16 18:41:50 +02:00
game - > _priv . current_gamestate = tmp ;
2016-08-20 03:02:39 +02:00
( * tmp - > api - > Gamestate_Unload ) ( game , tmp - > data ) ;
2016-08-21 21:58:47 +02:00
al_resume_timer ( game - > _priv . timer ) ;
2016-08-13 20:03:58 +02:00
}
if ( tmp - > pending_load ) {
2016-07-03 22:38:36 +02:00
al_stop_timer ( game - > _priv . timer ) ;
2012-12-28 02:55:52 +01:00
2016-08-20 03:02:39 +02:00
if ( ! tmp - > api ) {
PrintConsole ( game , " Opening gamestate \" %s \" ... " , tmp - > name ) ;
char libname [ 1024 ] ;
snprintf ( libname , 1024 , " libsuperderpy-%s-%s " LIBRARY_EXTENSION , game - > name , tmp - > name ) ;
tmp - > handle = dlopen ( libname , RTLD_NOW ) ;
if ( ! tmp - > handle ) {
FatalError ( game , false , " Error while opening gamestate \" %s \" : %s " , tmp - > name , dlerror ( ) ) ;
2012-12-26 02:25:56 +01:00
2016-08-20 03:02:39 +02:00
tmp - > pending_load = false ;
tmp - > pending_start = false ;
} else {
2012-12-26 02:25:56 +01:00
2016-08-20 03:02:39 +02:00
tmp - > api = malloc ( sizeof ( struct Gamestate_API ) ) ;
2012-12-26 02:25:56 +01:00
2016-08-20 03:02:39 +02:00
# define GS_ERROR FatalError(game, false, "Error on resolving gamestate symbol: %s", dlerror()); tmp->pending_load = false; tmp->pending_start = false; tmp=tmp->next; continue;
2012-12-26 02:25:56 +01:00
2016-08-20 03:02:39 +02:00
if ( ! ( tmp - > api - > Gamestate_Draw = dlsym ( tmp - > handle , " Gamestate_Draw " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api - > Gamestate_Logic = dlsym ( tmp - > handle , " Gamestate_Logic " ) ) ) { GS_ERROR ; }
2012-12-26 02:25:56 +01:00
2016-08-20 03:02:39 +02:00
if ( ! ( tmp - > api - > Gamestate_Load = dlsym ( tmp - > handle , " Gamestate_Load " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api - > Gamestate_Start = dlsym ( tmp - > handle , " Gamestate_Start " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api - > Gamestate_Pause = dlsym ( tmp - > handle , " Gamestate_Pause " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api - > Gamestate_Resume = dlsym ( tmp - > handle , " Gamestate_Resume " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api - > Gamestate_Stop = dlsym ( tmp - > handle , " Gamestate_Stop " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api - > Gamestate_Unload = dlsym ( tmp - > handle , " Gamestate_Unload " ) ) ) { GS_ERROR ; }
2012-12-26 02:25:56 +01:00
2016-08-20 03:02:39 +02:00
if ( ! ( tmp - > api - > Gamestate_ProcessEvent = dlsym ( tmp - > handle , " Gamestate_ProcessEvent " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api - > Gamestate_Reload = dlsym ( tmp - > handle , " Gamestate_Reload " ) ) ) { GS_ERROR ; }
if ( ! ( tmp - > api - > Gamestate_ProgressCount = dlsym ( tmp - > handle , " Gamestate_ProgressCount " ) ) ) { GS_ERROR ; }
}
}
if ( tmp - > api ) {
PrintConsole ( game , " Loading gamestate \" %s \" ... " , tmp - > name ) ;
2016-08-16 18:41:50 +02:00
game - > _priv . tmp_gamestate . p = 0 ;
2012-12-28 00:00:37 +01:00
2016-07-03 22:38:36 +02:00
DrawGamestates ( game ) ;
2015-03-15 05:38:15 +01:00
if ( tmp - > showLoading ) {
2016-08-16 18:41:50 +02:00
( * game - > _priv . loading . Draw ) ( game , game - > _priv . loading . data , game - > _priv . tmp_gamestate . loaded / ( float ) game - > _priv . tmp_gamestate . toLoad ) ;
2015-03-15 05:38:15 +01:00
}
2016-07-03 22:38:36 +02:00
DrawConsole ( game ) ;
2016-08-16 18:41:50 +02:00
if ( al_get_time ( ) - game - > _priv . tmp_gamestate . t > = 1 / 60.0 ) {
2016-06-27 21:21:59 +02:00
al_flip_display ( ) ;
2016-08-16 18:41:50 +02:00
game - > _priv . tmp_gamestate . t = al_get_time ( ) ;
2016-06-27 21:21:59 +02:00
}
2016-08-16 18:41:50 +02:00
game - > _priv . tmp_gamestate . tmp = tmp ;
game - > _priv . current_gamestate = tmp ;
2016-08-20 03:02:39 +02:00
tmp - > data = ( * tmp - > api - > Gamestate_Load ) ( game , & GamestateProgress ) ;
2016-08-16 18:41:50 +02:00
game - > _priv . tmp_gamestate . loaded + + ;
2012-12-26 02:25:56 +01:00
tmp - > loaded = true ;
tmp - > pending_load = false ;
}
2016-08-21 21:58:47 +02:00
al_resume_timer ( game - > _priv . timer ) ;
2012-12-25 00:22:03 +01:00
}
2012-12-26 13:38:15 +01:00
2012-12-27 21:05:28 +01:00
tmp = tmp - > next ;
}
bool gameActive = false ;
2016-07-03 22:38:36 +02:00
tmp = game - > _priv . gamestates ;
2012-12-27 21:05:28 +01:00
while ( tmp ) {
2016-08-13 20:03:58 +02:00
if ( ( tmp - > pending_start ) & & ( tmp - > loaded ) ) {
2016-07-03 22:38:36 +02:00
PrintConsole ( game , " Starting gamestate \" %s \" ... " , tmp - > name ) ;
al_stop_timer ( game - > _priv . timer ) ;
2016-08-16 18:41:50 +02:00
game - > _priv . current_gamestate = tmp ;
2012-12-27 21:05:28 +01:00
tmp - > started = true ;
tmp - > pending_start = false ;
2016-09-04 01:26:41 +02:00
( * tmp - > api - > Gamestate_Start ) ( game , tmp - > data ) ;
al_resume_timer ( game - > _priv . timer ) ;
2012-12-27 21:05:28 +01:00
}
2012-12-26 13:38:15 +01:00
2012-12-27 21:05:28 +01:00
if ( ( tmp - > started ) | | ( tmp - > pending_start ) | | ( tmp - > pending_load ) ) gameActive = true ;
2012-12-25 00:22:03 +01:00
tmp = tmp - > next ;
}
2012-12-24 19:41:12 +01:00
2012-12-26 13:38:15 +01:00
if ( ! gameActive ) {
2016-07-03 22:38:36 +02:00
PrintConsole ( game , " No gamestates left, exiting... " ) ;
2012-12-26 13:38:15 +01:00
break ;
}
2016-07-03 22:38:36 +02:00
DrawGamestates ( game ) ;
DrawConsole ( game ) ;
2012-02-25 22:19:12 +01:00
al_flip_display ( ) ;
2012-12-25 00:22:03 +01:00
redraw = false ;
2012-12-24 19:41:12 +01:00
2012-09-26 03:19:10 +02:00
} else {
2012-12-24 19:41:12 +01:00
2016-07-03 22:38:36 +02:00
al_wait_for_event ( game - > _priv . event_queue , & ev ) ;
2012-12-24 19:41:12 +01:00
2016-11-08 22:11:10 +01:00
if ( game - > eventHandler ) {
if ( ( * game - > eventHandler ) ( game , & ev ) ) {
continue ;
}
}
2016-07-03 22:38:36 +02:00
if ( ( ev . type = = ALLEGRO_EVENT_TIMER ) & & ( ev . timer . source = = game - > _priv . timer ) ) {
LogicGamestates ( game ) ;
2012-12-25 00:22:03 +01:00
redraw = true ;
2012-09-26 03:19:10 +02:00
}
else if ( ev . type = = ALLEGRO_EVENT_DISPLAY_CLOSE ) {
break ;
}
2016-11-06 03:10:43 +01:00
else if ( ev . type = = ALLEGRO_EVENT_DISPLAY_HALT_DRAWING ) {
2016-11-11 19:38:26 +01:00
PrintConsole ( game , " Engine halted. " ) ;
2016-11-06 03:10:43 +01:00
game - > _priv . draw = false ;
2016-11-08 10:34:32 +01:00
al_stop_timer ( game - > _priv . timer ) ;
2016-11-06 03:10:43 +01:00
al_detach_voice ( game - > audio . v ) ;
2016-11-09 00:40:13 +01:00
FreezeGamestates ( game ) ;
2017-06-13 14:17:38 +02:00
if ( game - > _priv . console ) Console_Unload ( game ) ;
2016-11-06 03:10:43 +01:00
al_acknowledge_drawing_halt ( game - > display ) ;
}
else if ( ev . type = = ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING ) {
2016-11-08 17:42:23 +01:00
game - > _priv . draw = true ;
2016-11-11 19:38:26 +01:00
al_acknowledge_drawing_resume ( game - > display ) ;
2017-06-13 14:17:38 +02:00
Console_Load ( game ) ;
2016-11-11 19:38:26 +01:00
PrintConsole ( game , " Engine resumed. " ) ;
ReloadGamestates ( game ) ;
2016-11-09 00:40:13 +01:00
UnfreezeGamestates ( game ) ;
2016-11-08 17:42:23 +01:00
al_attach_mixer_to_voice ( game - > audio . mixer , game - > audio . v ) ;
al_resume_timer ( game - > _priv . timer ) ;
2016-11-06 03:10:43 +01:00
}
2016-09-02 00:07:43 +02:00
else if ( ev . type = = ALLEGRO_EVENT_DISPLAY_RESIZE ) {
al_acknowledge_resize ( game - > display ) ;
2016-11-11 19:38:26 +01:00
SetupViewport ( game , game - > viewport_config ) ;
2016-09-02 00:07:43 +02:00
}
2017-06-25 17:37:41 +02:00
# ifdef ALLEGRO_ANDROID
2016-11-07 01:45:12 +01:00
else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_MENU ) ) {
2016-06-27 21:20:02 +02:00
# else
2017-06-25 17:37:41 +02:00
else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( ( ev . keyboard . keycode = = ALLEGRO_KEY_TILDE ) | | ( ev . keyboard . keycode = = ALLEGRO_KEY_BACKQUOTE ) ) ) {
2016-06-27 21:20:02 +02:00
# endif
2016-07-03 22:38:36 +02:00
game - > _priv . showconsole = ! game - > _priv . showconsole ;
2012-12-27 01:02:47 +01:00
}
2016-07-03 22:38:36 +02:00
else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( game - > config . debug ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_F1 ) ) {
2012-12-27 01:02:47 +01:00
int i ;
for ( i = 0 ; i < 512 ; i + + ) {
2016-07-03 22:38:36 +02:00
LogicGamestates ( game ) ;
2012-09-26 03:19:10 +02:00
}
2016-07-03 22:38:36 +02:00
game - > _priv . showconsole = true ;
PrintConsole ( game , " DEBUG: 512 frames skipped... " ) ;
} else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( game - > config . debug ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_F10 ) ) {
double speed = ALLEGRO_BPS_TO_SECS ( al_get_timer_speed ( game - > _priv . timer ) ) ; // inverting
2012-12-27 01:02:47 +01:00
speed - = 10 ;
if ( speed < 10 ) speed = 10 ;
2016-07-03 22:38:36 +02:00
al_set_timer_speed ( game - > _priv . timer , ALLEGRO_BPS_TO_SECS ( speed ) ) ;
game - > _priv . showconsole = true ;
PrintConsole ( game , " DEBUG: Gameplay speed: %.2fx " , speed / 60.0 ) ;
} else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( game - > config . debug ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_F11 ) ) {
double speed = ALLEGRO_BPS_TO_SECS ( al_get_timer_speed ( game - > _priv . timer ) ) ; // inverting
2012-12-27 01:02:47 +01:00
speed + = 10 ;
if ( speed > 600 ) speed = 600 ;
2016-07-03 22:38:36 +02:00
al_set_timer_speed ( game - > _priv . timer , ALLEGRO_BPS_TO_SECS ( speed ) ) ;
game - > _priv . showconsole = true ;
PrintConsole ( game , " DEBUG: Gameplay speed: %.2fx " , speed / 60.0 ) ;
2017-06-25 17:37:41 +02:00
} else if ( ( ev . type = = ALLEGRO_EVENT_KEY_DOWN ) & & ( ev . keyboard . keycode = = ALLEGRO_KEY_F12 ) ) {
2012-12-27 01:02:47 +01:00
ALLEGRO_PATH * path = al_get_standard_path ( ALLEGRO_USER_DOCUMENTS_PATH ) ;
char filename [ 255 ] = { } ;
2016-09-06 01:47:12 +02:00
snprintf ( filename , 255 , " %s_%lld_%ld.png " , game - > name , ( long long ) time ( NULL ) , clock ( ) ) ;
2012-12-27 01:02:47 +01:00
al_set_path_filename ( path , filename ) ;
2016-07-03 22:38:36 +02:00
al_save_bitmap ( al_path_cstr ( path , ALLEGRO_NATIVE_PATH_SEP ) , al_get_backbuffer ( game - > display ) ) ;
PrintConsole ( game , " Screenshot stored in %s " , al_path_cstr ( path , ALLEGRO_NATIVE_PATH_SEP ) ) ;
2012-12-27 01:02:47 +01:00
al_destroy_path ( path ) ;
2016-07-02 23:23:08 +02:00
}
2016-11-08 17:42:23 +01:00
EventGamestates ( game , & ev ) ;
2012-02-25 22:26:31 +01:00
}
}
2016-07-03 22:38:36 +02:00
return 0 ;
}
2016-07-04 01:12:55 +02:00
SYMBOL_EXPORT void libsuperderpy_destroy ( struct Game * game ) {
2016-07-03 22:38:36 +02:00
game - > shuttingdown = true ;
2012-12-24 19:41:12 +01:00
2016-08-16 18:01:12 +02:00
ClearGarbage ( game ) ;
2012-12-26 15:15:02 +01:00
// in case of restart
2016-08-16 18:01:12 +02:00
struct Gamestate * tmp = game - > _priv . gamestates , * pom ;
2012-12-26 13:38:15 +01:00
while ( tmp ) {
if ( tmp - > started ) {
2016-07-03 22:38:36 +02:00
PrintConsole ( game , " Stopping gamestate \" %s \" ... " , tmp - > name ) ;
2016-08-16 18:41:50 +02:00
game - > _priv . current_gamestate = tmp ;
2016-08-20 03:02:39 +02:00
( * tmp - > api - > Gamestate_Stop ) ( game , tmp - > data ) ;
2012-12-26 13:38:15 +01:00
tmp - > started = false ;
}
if ( tmp - > loaded ) {
2016-07-03 22:38:36 +02:00
PrintConsole ( game , " Unloading gamestate \" %s \" ... " , tmp - > name ) ;
2016-08-16 18:41:50 +02:00
game - > _priv . current_gamestate = tmp ;
2016-08-20 03:02:39 +02:00
( * tmp - > api - > Gamestate_Unload ) ( game , tmp - > data ) ;
2012-12-26 13:38:15 +01:00
tmp - > loaded = false ;
}
2016-08-27 00:46:38 +02:00
if ( tmp - > handle & & ! RUNNING_ON_VALGRIND ) {
2016-08-20 03:02:39 +02:00
PrintConsole ( game , " Closing gamestate \" %s \" ... " , tmp - > name ) ;
dlclose ( tmp - > handle ) ;
}
2016-08-16 18:01:12 +02:00
free ( tmp - > name ) ;
2016-08-20 03:02:39 +02:00
if ( tmp - > api ) {
free ( tmp - > api ) ;
}
2016-08-16 18:01:12 +02:00
pom = tmp - > next ;
free ( tmp ) ;
tmp = pom ;
2012-12-26 13:38:15 +01:00
}
2016-11-08 10:34:32 +01:00
ClearScreen ( game ) ;
2016-07-03 22:38:36 +02:00
PrintConsole ( game , " Shutting down... " ) ;
DrawConsole ( game ) ;
2012-02-17 13:25:06 +01:00
al_flip_display ( ) ;
2016-08-16 18:01:12 +02:00
while ( game - > _priv . garbage ) {
free ( game - > _priv . garbage - > data ) ;
game - > _priv . garbage = game - > _priv . garbage - > next ;
}
2016-07-03 22:38:36 +02:00
( * game - > _priv . loading . Unload ) ( game , game - > _priv . loading . data ) ;
al_destroy_timer ( game - > _priv . timer ) ;
Console_Unload ( game ) ;
al_destroy_display ( game - > display ) ;
2016-08-29 22:47:55 +02:00
al_destroy_user_event_source ( & ( game - > event_source ) ) ;
2016-07-03 22:38:36 +02:00
al_destroy_event_queue ( game - > _priv . event_queue ) ;
al_destroy_mixer ( game - > audio . fx ) ;
al_destroy_mixer ( game - > audio . music ) ;
al_destroy_mixer ( game - > audio . mixer ) ;
al_destroy_voice ( game - > audio . v ) ;
2012-02-25 22:26:31 +01:00
al_uninstall_audio ( ) ;
2016-07-03 22:38:36 +02:00
DeinitConfig ( game ) ;
2012-12-26 02:25:56 +01:00
al_uninstall_system ( ) ;
2012-12-24 19:41:12 +01:00
al_shutdown_ttf_addon ( ) ;
al_shutdown_font_addon ( ) ;
2016-07-04 00:06:50 +02:00
char * * argv = game - > _priv . argv ;
2016-08-16 18:01:12 +02:00
bool restart = game - > restart ;
2016-07-03 22:38:36 +02:00
free ( game ) ;
2016-08-16 18:01:12 +02:00
if ( restart ) {
2016-09-08 00:32:21 +02:00
# ifdef ALLEGRO_MACOSX
chdir ( game - > _priv . cwd ) ;
# endif
2016-07-03 22:38:36 +02:00
execv ( argv [ 0 ] , argv ) ; // FIXME: on OSX there's chdir called which might break it
2012-03-08 22:21:02 +01:00
}
2012-02-15 23:57:06 +01:00
}