diff --git a/.gitignore b/.gitignore index 03d8ad6..089a689 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ _UpgradeReport_Files /.cproject /.project /.settings +/skeldal.local.ini diff --git a/game/automap.c b/game/automap.c index 45cf88c..cb5b718 100644 --- a/game/automap.c +++ b/game/automap.c @@ -583,7 +583,6 @@ void draw_automap(int xr,int yr) outtext(s); } ukaz_mysku(); - wait_retrace(); showview(0,16,640,360); } void *map_keyboard(EVENT_MSG *msg,void **usr); diff --git a/game/builder.c b/game/builder.c index 46d6a8d..b74f112 100644 --- a/game/builder.c +++ b/game/builder.c @@ -232,7 +232,6 @@ void chveni(int i) if (i) count=i; count--; if (!count) pos=0; - wait_retrace(); setvesa_displaystart(8*pos,0); pos=!pos; } diff --git a/game/default_font.in.cpp b/game/default_font.in.cpp index 0085906..56fb787 100644 --- a/game/default_font.in.cpp +++ b/game/default_font.in.cpp @@ -1,4 +1,4 @@ -#include +#include constexpr binary_data font_data ="@CONTENT@"; diff --git a/game/engine1.c b/game/engine1.c index f8271af..0128a40 100644 --- a/game/engine1.c +++ b/game/engine1.c @@ -947,9 +947,6 @@ void general_engine_init() create_zooming(); clear_screen(GetScreenAdr(),0); clear_screen(GetBuffer2nd(),0); - int32_t scr_linelen2 = GetScreenPitch(); - - screen_buffer_size=scr_linelen2*480*2; } void map_pos(int celx,int cely,int posx,int posy,int posz,int *x,int *y) diff --git a/game/globals.h b/game/globals.h index 12a5beb..6075374 100644 --- a/game/globals.h +++ b/game/globals.h @@ -268,7 +268,7 @@ static __inline int rangrnd(int a, int b) {return rnd(b-a+1)+a;} #define concat(c,s1,s2) c=strcat(strcpy((char *)alloca(strlen(s1)+strlen(s2)+1),s1),s2) -#define local_strdup(c) strcpy((char *)strlen(c)+1, c) +#define local_strdup(c) strcpy((char *)alloca(strlen(c)+1), c) #define concat2(s1,s2) strcat(strcpy((char *)alloca(strlen(s1)+strlen(s2)+1),s1),s2) #define concat3(s1,s2,s3) strcat(strcat(strcpy((char *)alloca(strlen(s1)+strlen(s2)+strlen(s3)+1),s1),s2),s3) #define concat4(s1,s2,s3,s4) strcat(strcat(strcat(strcpy((char *)alloca(strlen(s1)+strlen(s2)+strlen(s3)+strlen(s4)+1),s1),s2),s3),s4) @@ -332,14 +332,14 @@ typedef enum skeldal_folders_tag { SR_FONT, SR_MAP, SR_MUSIC, - SR_BGRAFIKA, + SR_TEMP, /* = unused group */ + SR_BGRAFIKA , SR_ITEMS, SR_ENEMIES, SR_VIDEO, SR_DIALOGS, SR_SAVES, SR_WORK, - SR_CD, SR_COUNT} SKELDAL_FOLDERS_TAG; @@ -555,7 +555,7 @@ extern int viewsector; //aktualni sektor vyhledu extern int viewdir; //aktualni smer vyhledu extern THE_TIMER timer_tree; //strom casovych udalosti extern D_ACTION *d_action; //spojovy seznam zpozdenych akci -extern char *gpathtable[SR_COUNT]; //tabulka adresaru +extern const char *gpathtable[SR_COUNT]; //tabulka adresaru extern char level_preload; //informace o preloadingu extern char **texty; //globalni tabulka textu extern char **level_texts; //lokalni tabulka textu @@ -565,7 +565,6 @@ extern int hl_ptr; //ukazatel na konec staticke tabulky registra extern int end_ptr; //ukazatel na uplny konec tabulky registraci extern short **map_items; //ukazatel na mapu predmetu extern int default_ms_cursor; //cislo zakladniho mysiho kurzoru -extern void *cur_xlat; //aktualni tabulka pro 256 barev extern void (*unwire_proc)(void); //procedura zajistujici odpojeni prave ukoncovane interakce extern void (*wire_proc)(void); //procedura zajistujici pripojeni drive ukoncene interakce extern char cur_mode; //cislo aktualni interakce @@ -642,7 +641,6 @@ extern char marker; //tato promenna je 0, jen v pripade ze je 1 probehne assert //builder - skeldal -int set_video(int mode); void *game_keyboard(EVENT_MSG *msg,void **usr); void calc_animations(void); int load_map(char *filename); diff --git a/game/interfac.c b/game/interfac.c index b7b9bca..1b5e035 100644 --- a/game/interfac.c +++ b/game/interfac.c @@ -1599,11 +1599,8 @@ void show_jrc_logo(char *filename) palw[i]=b | (r<<11) | (g<<6); } } - if (!bnk) - wait_retrace(); put_picture(xp, yp, pcx); if (bnk) { - wait_retrace(); showview(xp, yp, pcxw[0], pcxw[1]); } ccc=cdiff; diff --git a/game/menu.c b/game/menu.c index c1c4c56..45196f2 100644 --- a/game/menu.c +++ b/game/menu.c @@ -374,11 +374,13 @@ char *get_next_title(signed char control,char *filename) switch(control) { case 1: - path = local_strdup(build_pathname(2, gpathtable[SR_MAP],filename)); + path = build_pathname(2, gpathtable[SR_MAP],filename); + path = local_strdup(path); titles=enc_open(path); if (titles==NULL) { - const char *path2 = local_strdup(build_pathname(2, gpathtable[SR_DATA],filename)); + const char *path2 = build_pathname(2, gpathtable[SR_DATA],filename); + path2 = local_strdup(path2); titles=enc_open(path2); if (titles==NULL) { diff --git a/game/realgame.c b/game/realgame.c index 9dc3208..236d6d5 100644 --- a/game/realgame.c +++ b/game/realgame.c @@ -222,10 +222,11 @@ int load_map(char *filename) char snd_load=0; void *mob_template; int32_t mob_size; - int suc; + int suc = 0; map_with_password=0; const char *mpath = build_pathname(2, gpathtable[SR_MAP], filename); + mpath = local_strdup(mpath); schovej_mysku(); if (level_preload) show_loading_picture("LOADING.HI"); change_music("?"); diff --git a/game/skeldal.c b/game/skeldal.c index 0497ddd..f8a30d3 100644 --- a/game/skeldal.c +++ b/game/skeldal.c @@ -1,42 +1,33 @@ #include #include #include - #include -#include -#include #include -#include - #include -#include #include #include -#include #include #include #include #include #include #include -#include #include #include +#include +#include #include "globals.h" -#include "engine1.h" -#include "wizard.h" -#include "version.h" #include "default_font.h" - +// #include "advconfig.h" -#include + #define CONFIG_NAME SKELDALINI #define INI_TEXT 1 #define INI_INT 2 #define ERR_GENERAL 1 -char *gpathtable[SR_COUNT]; +const char *gpathtable[SR_COUNT]; /* char *pathtable[]= @@ -66,7 +57,6 @@ int charmax=3; int autoopenaction=0; int autoopendata=0; -void *cur_xlat; void redraw_desktop_call(void); @@ -99,12 +89,7 @@ void (*wire_proc)(void); char cur_mode,battle_mode; static int init_music_vol=127; static int init_gfx_vol=255; -static char full_video=0; static char titles_on=0; -static char windowed=0; -static char windowedzoom=1; -static char monitor=0; -static int refresh=0; void pcx_fade_decomp(void **p,int32_t *s); void pcx_15bit_decomp(void **p,int32_t *s); @@ -290,49 +275,6 @@ INIS sinit[]= int last_ms_cursor=-1; int vmode=2; -int set_video(int mode) - { - int er=0; - - int32_t scr_linelen2 = GetScreenPitch(); - - report_mode(1); - er=initmode_dx(windowed,windowedzoom,monitor,refresh); -/* - switch(mode) - { - case 1:er=initmode256(cur_xlat); - if (banking) report_mode(5); else report_mode(2); - - break; - case 2:er=initmode32(); - if (banking) report_mode(4); else report_mode(1); - - break; - case 0:er=initmode_lo(cur_xlat); - report_mode(3); - - break; - case 3: free(cur_xlat);cur_xlat=create_blw_palette16(); - er=initmode16(cur_xlat); - - report_mode(3); - break; - case 4:er=init_empty_mode(); - report_mode(3); - - break; - case 5:free(cur_xlat);cur_xlat=create_hixlat(); - er=initmode64(cur_xlat); - if (banking) report_mode(7); else report_mode(6); - - break; - - default:er=-1; - }*/ - screen_buffer_size=scr_linelen2*2*480; - return er; - } void purge_temps(char _) { temp_storage_clear(); @@ -989,31 +931,27 @@ static void patch_error(int err) void init_skeldal(const INI_CONFIG *cfg) { - int verr; + boldcz=LoadDefaultFont(); cti_texty(); timer_tree.next=NULL; - - srand(clock()); - - cur_xlat=create_special_palette(); - init_events(); - verr=set_video(vmode); - if (verr) + char verr = game_display_init(ini_section_open(cfg, "video"), "Skeldal"); + if (!verr) { - exit(ERR_GENERAL); + exit(1); } + showview = game_display_update_rect; general_engine_init(); atexit(done_skeldal); /* install_dos_error(device_error,(char *)getmem(4096)+4096);*/ - swap_error=swap_error_exception; - const char *ddlfile = local_strdup(build_pathname(2, gpathtable[SR_DATA],"SKELDAL.DDL")); + const char *ddlfile = build_pathname(2, gpathtable[SR_DATA],"SKELDAL.DDL"); + ddlfile = local_strdup(ddlfile); init_manager(ddlfile, NULL); SEND_LOG("(GAME) Memory manager initialized. Using DDL: '%s'",ddlfile); @@ -1037,8 +975,6 @@ void init_skeldal(const INI_CONFIG *cfg) send_message(E_ADD,E_PRGERROR,error_exception); - if (debug_enabled) install_wizard(); - add_to_timer(TM_BACK_MUSIC,5,-1,back_music); add_game_window(); @@ -1323,24 +1259,7 @@ void set_verify(char state); */ void play_movie_seq(const char *s,int y) { - int hic=full_video?SMD_HICOLOR+128:SMD_HICOLOR,cc=full_video?SMD_256+128:SMD_256; - word *lbuffer=GetScreenAdr(); - set_play_attribs(lbuffer,0,banking,vmode==5); - switch (vmode) - { - case 1:if (!banking) - play_animation(s,cc,y,snd_devnum!=DEV_NOSOUND); - else - { - set_play_attribs(GetScreenAdr(),1,0,vmode==5); - play_animation(s,hic,y,snd_devnum!=DEV_NOSOUND); - } - break; - case 5: - case 2:play_animation(s,hic,y,snd_devnum!=DEV_NOSOUND);break; - default: set_play_attribs(GetScreenAdr(),1,0,vmode==5); - play_animation(s,hic,y,snd_devnum!=DEV_NOSOUND);break; - } + play_animation(s,0,y,0); } @@ -1369,68 +1288,6 @@ void play_anim(int anim_num) } -/*main(int argc,char *argv[]) - { - int err;int sect;int dir=0; - - //if (argc<2) help(); - - dir; - set_verify(0); - mman_pathlist=&pathtable; - //nofloors=1; - zoom_speed(1); - turn_speed(1); - configure("skeldal.ini",config_skeldal); - purge_temps(1); - textmode_effekt(); - clrscr(); - init_skeldal(); - enter_menu(); - if (argc<2) - { - invex_anim(); - // send_message(E_ADD,E_MOUSE,waiter); - // send_message(E_ADD,E_KEYBOARD,waiter); - // add_to_timer(TM_WAITER,1,-1,timer_waiter); - strncpy(loadlevel.name,default_map,12); - } - else strncpy(loadlevel.name,argv[1],12); - err=load_map(loadlevel.name); - if (argc>=3) sscanf(argv[2],"%d",§); - else - { - sect=mglob.start_sector; - dir=mglob.direction; - } - loadlevel.start_pos=sect; - loadlevel.dir=dir; - init_game(); - while (loadlevel.name[0]) - { - if (err) - { - closemode(); - switch (err) - { - case -1: printf("Error while loading map....file not found\n");break; - case -2: printf("Missing -1 at the end of map string table");break; - case -3: printf("Map file is corrupted!\n");break; - default: printf("Error in string table at line %d",err);break; - } - exit(1); - } - viewsector=loadlevel.start_pos; - viewdir=loadlevel.dir; - loadlevel.name[0]=0; - enter_game(); - leave_current_map(); - if (loadlevel.name[0]!=0)err=load_map(loadlevel.name); - } - closemode(); - } - -*/ #define V_NOVA_HRA 0 #define V_OBNOVA_HRY 1 @@ -1661,9 +1518,80 @@ void disable_intro(void) update_config(); } +/* + * -char def_path[]=""; +-char graph_path[]="graphics" PATH_SEPARATOR; +-char basc_graph[]="graphics" PATH_SEPARATOR "basic" PATH_SEPARATOR; +-char item_graph[]="graphics" PATH_SEPARATOR "items" PATH_SEPARATOR; +-char sample_path[]="samples" PATH_SEPARATOR; +-char font_path[]="font" PATH_SEPARATOR; +-char map_path[]="maps" PATH_SEPARATOR; +-char music_path[]="music" PATH_SEPARATOR; +-char org_music_path[]="music" PATH_SEPARATOR; +-char temp_path[]="?"; +-char enemies_path[]="graphics" PATH_SEPARATOR "enemies" PATH_SEPARATOR; +-char video_path[]="video" PATH_SEPARATOR; +-char dialogs_path[]="graphics" PATH_SEPARATOR "dialogs" PATH_SEPARATOR; +-char saves_path[]=""; +-char work_path[]=""; +-char cd_path[]=""; +-char map2_path[]=""; +-char plugins_path[]=""; + */ -void new_configure(const INI_CONFIG *) { +//returns game root +const char *configure_pathtable(const INI_CONFIG *cfg) { +#define DEFAULT_SUBPATHS 4 +#define DEFAULT_SUBPATHS_LEN 20 + const char *sub_paths[DEFAULT_SUBPATHS] = { + "basic", "dialogs", "enemies","items" + }; + + static char default_subpaths[DEFAULT_SUBPATHS][DEFAULT_SUBPATHS_LEN]; + for (int i = 0; i < DEFAULT_SUBPATHS; ++i) { + strncpy(default_subpaths[i], build_pathname(2, "graphics", sub_paths[i]), DEFAULT_SUBPATHS_LEN); + } + + const INI_CONFIG_SECTION *paths = ini_section_open(cfg, "paths"); + const char *groot = ini_get_string(paths, "root", "./"); + gpathtable[SR_BGRAFIKA] = ini_get_string(paths, "gui", default_subpaths[0]); + gpathtable[SR_DIALOGS] = ini_get_string(paths, "dialogs", default_subpaths[1]); + gpathtable[SR_ENEMIES] = ini_get_string(paths, "enemies", default_subpaths[2]); + gpathtable[SR_FONT] = ini_get_string(paths, "fonts", "font"); + gpathtable[SR_GRAFIKA] = ini_get_string(paths, "graphics", "graphics"); + gpathtable[SR_ITEMS] = ini_get_string(paths, "items", default_subpaths[3]); + gpathtable[SR_MAP] = ini_get_string(paths, "maps", "maps"); + gpathtable[SR_MUSIC] = ini_get_string(paths, "music", "music"); + gpathtable[SR_ZVUKY] = ini_get_string(paths, "sounds", "sounds"); + gpathtable[SR_VIDEO] = ini_get_string(paths, "video", "video"); + gpathtable[SR_SAVES] = ini_get_string(paths, "savegame", get_default_savegame_directory()); + gpathtable[SR_DATA]= ini_get_string(paths, "data", "./"); + + + return groot; +} + + +void show_help(const char *arg0) { + printf( + "Brany Skeldalu (Gates of Skeldal) portable game player\n" + "Copyright (c) 2025 Ondrej Novak. All rights reserved.\n\n" + "This work is licensed under the terms of the MIT license.\n" + "For a copy, see .\n" + "\n" + "Usage:" + ); + printf("%s [-f ] [-a ] [-h]\n\n", arg0); + + printf("-f path to configuration file\n" + "-a path for adventure file (.adv)\n" + "-h this help\n"); + exit(0); +} + +void show_help_short() { + printf("add -h to print help\n"); } int main(int argc,char *argv[]) @@ -1671,39 +1599,47 @@ int main(int argc,char *argv[]) def_mman_group_table(gpathtable); zoom_speed(1); turn_speed(1); + const char *config_name = CONFIG_NAME; + const char *adv_config_file = NULL; + for (int optchr = -1; (optchr = getopt(argc, argv, "hf:a:")) != -1; ) { + switch (optchr) { + case 'f': config_name = local_strdup(optarg);break; + case 'a': adv_config_file = local_strdup(optarg);break; + case 'h': show_help(argv[0]);break; + default: show_help_short(); + return 1; + } + } - INI_CONFIG *cfg = ini_open(CONFIG_NAME); + INI_CONFIG *cfg = ini_open(config_name); if (cfg == NULL) { fprintf(stderr, "Failed to open configuration file: %s\n", CONFIG_NAME); + show_help_short(); return 1; } - if (argc >= 2) { - TSTR_LIST adv_config=read_config(argv[1]);; + if (adv_config_file) { + TSTR_LIST adv_config=read_config(adv_config_file); adv_patch_config(cfg, adv_config); release_list(adv_config); } - new_configure(cfg); + const char *groot = configure_pathtable(cfg); + if (!change_current_directory(groot)) { + fprintf(stderr, "Can't change directory to %s", groot); + return 1; + } + start_check(); purge_temps(1); -// textmode_effekt(); clrscr(); init_skeldal(cfg); + add_task(65536,start); - //add_task(32768,check_number_1phase,argv[0]); - - - add_task(65536,start); - -/* position(200,200); - set_font(H_FBIG,RGB(200,200,200)); - outtext("Ahoj lidi"); - showview(0,0,0,0);*/ escape(); closemode(); diff --git a/libs/bgraph.h b/libs/bgraph.h index e2a04b1..a1b512a 100644 --- a/libs/bgraph.h +++ b/libs/bgraph.h @@ -17,11 +17,7 @@ void RedirectScreenBufferSecond(void); extern word curcolor,charcolors[7]; extern word *curfont,*writepos,writeposx; extern byte fontdsize; -extern byte *palmem,*xlatmem; extern void (*showview)(word,word,word,word); -extern char line480; -extern int32_t screen_buffer_size; -extern char banking; extern char __skip_change_line_test; extern char no_restore_mode; @@ -98,7 +94,7 @@ void showview32(word x,word y,word xs,word ys); void showview256(word x,word y,word xs,word ys); void showview_lo(word x,word y,word xs,word ys); void outtext(const char *text); -int initmode_dx(char inwindow, char zoom, char monitor, int refresh); +int initmode(const INI_CONFIG_SECTION *, const char *app_name); int initmode32(void); int initmode32b(void); int initmode256(void *paletefile); @@ -119,15 +115,9 @@ void redraw_ms_cursor_on_screen(void); int text_height(char *text); int text_width(char *text); void set_aligned_position(int x,int y,char alignx, char aligny,char *text); -void wait_retrace(void); -void pal_optimize(void); void rectangle(int x1,int y1,int x2,int y2,int color); word *mapvesaadr1(word *a); -void *create_special_palette(void); -void *create_special_palette2(void); -void *create_blw_palette16(void); void rel_position_x(word x); -int init_empty_mode(void); void put_8bit_clipped(void *src,void *trg,int startline,int velx,int vely); //#pragma aux put_8bit_clipped parm [ESI][EDI][EAX][EBX][EDX] modify [ECX]; diff --git a/libs/bgraph2.c b/libs/bgraph2.c index 9ca240c..6275601 100644 --- a/libs/bgraph2.c +++ b/libs/bgraph2.c @@ -10,11 +10,9 @@ word *screen; word curcolor,charcolors[7] = {0x0000,RGB555(0,31,0),RGB555(0,28,0),RGB555(0,24,0),RGB555(0,20,0),0x0000,0x0000}; word *curfont,*writepos,writeposx; byte fontdsize=0; -byte *palmem=NULL,*xlatmem=NULL; void (*showview)(word,word,word,word); char line480=0; int32_t screen_buffer_size=0; -char banking=0; char screenstate=0; char __skip_change_line_test=0; char no_restore_mode=0; @@ -289,10 +287,10 @@ void switchvesabank(word bank) } */ -int initmode_dx(char inwindow, char zoom, char monitor, int refresh) +int initmode(const INI_CONFIG_SECTION *display_config, const char *app_name) { - if (!DXInit64(inwindow,zoom,monitor,refresh)) return -1; - showview=showview_dx; + if (!game_display_init(display_config, app_name)) return -1; + showview=game_display_update_rect; screenstate=1; return 0; } @@ -400,25 +398,12 @@ void closemode() { if (screenstate) { - palmem=NULL; - DXCloseMode(); + game_display_close(); } screenstate=0; } -void showview_dx(word x,word y,word xs,word ys) - { -// register longint a; - - if (x>DxGetResX() || y>DxGetResY()) return; - if (xs==0) xs=DxGetResX(); - if (ys==0) ys=DxGetResY(); - xs+=2;ys+=2; - if (x+xs>DxGetResX()) xs=DxGetResX()-x; - if (y+ys>DxGetResY()) ys=DxGetResY()-y; - DXCopyRects64(x,y,xs,ys); - } /* static void showview64b(word x,word y,word xs,word ys) { @@ -593,70 +578,6 @@ void set_aligned_position(int x,int y,char alignx,char aligny,char *text) position(x,y); } -/*void pal_optimize() - { - int32_t *stattable; - word *c; - char *d; - int i; - int32_t maxr,maxg,maxb,max; - int j; - - if (palmem==NULL) return; - stattable=(int32_t *)getmem(32768*sizeof(int32_t)); - memset(stattable,0,32768*sizeof(int32_t)); - c=screen; - for(i=0;imax) - { - *((word *)xlatmem+j)=i; - max=stattable[i]; - } - stattable[*((word *)xlatmem+j)]=-1; - } - d=palmem; - c=(word *)xlatmem; - for(i=0;i<256;i++) - { - j=*c++; - *d++=((j>>9)& 0x3e); - *d++=((j>>4)& 0x3e); - *d++=(j & 0x1f)<<1; - } - setpal((void *)palmem); - memset(xlatmem,0,65536); - for(j=0;j<32768;j++) - { - int r1,g1,b1; - int r2,g2,b2,dif; - char *c; - maxr=maxg=maxb=999999999; - r1=(j>>9)& 0x3e;g1=(j>>4)& 0x3e;b1=(j & 0x1f)<<1; - c=palmem; - for(i=0;i<256;i++) - { - r2=abs(r1-*c++); - g2=abs(g1-*c++); - b2=abs(b1-*c++); - dif=r2+b2+g2; - if (dif<=maxb) - { - if (dif640 || y>480) return; - if (xs==0) xs=640; - if (ys==0) ys=480; - if (x+xs>640) xs=640-x; - if (y+ys>480) ys=480-y; - if (xs>550 && ys>400) - { - redraw16(screen,lbuffer,xlatmem); - return; - } - x1=x & ~0x7; - x2=(x+xs+7) & ~0x7; - redrawbox16((x2-x1)/8,ys,screen+x1+640*y,(char *)lbuffer+x1/8+80*y,xlatmem); - } - -void init16colors(); -#pragma aux init16colors modify [eax]=\ - "mov eax,12h"\ - "int 10h"\ - -int initmode16(void *palette) - { - palette; - init16colors(); - lbuffer=(word *)0xa0000; - screen=lbuffer; - linelen=640*2; - showview=showview16; - screen=(void *)malloc(screen_buffer_size); - palmem=(char *)palette; - xlatmem=palmem+768; - setpal((void *)palmem); - banking=0; - screenstate=1; - return 0; - } - -void empty_show_view(int x,int y,int xs,int ys) - { - x,y,xs,ys; - } - - -int init_empty_mode() - { - screen=(void *)malloc(screen_buffer_size); - showview=empty_show_view; - banking=1; - lbuffer=NULL; - screenstate=1; - return 0; - } -*/ diff --git a/libs/logfile.h b/libs/logfile.h new file mode 100644 index 0000000..dafcb05 --- /dev/null +++ b/libs/logfile.h @@ -0,0 +1,20 @@ +#ifndef _SKELDAL_LOGFILE_HEADER +#define _SKELDAL_LOGFILE_HEADER + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LOGFILE +void send_log_impl(const char *format, ...) __attribute__((format(printf, 1, 2))); +#define SEND_LOG(...) send_log_impl( __VA_ARGS__) +#else +#define SEND_LOG(...) +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/memman.c b/libs/memman.c index 0237079..567240b 100644 --- a/libs/memman.c +++ b/libs/memman.c @@ -20,7 +20,7 @@ void bonz_table(); #define NON_GETMEM_RESERVED (4*1024) -char *const* mman_pathlist=NULL; +static const char ** mman_pathlist=NULL; static char swap_status=0; static FILE *swap = NULL; @@ -34,7 +34,7 @@ void (*mman_action)(int action)=NULL; int32_t last_load_size; -void def_mman_group_table(char *const * p) { +void def_mman_group_table(const char ** p) { mman_pathlist = p; } @@ -42,7 +42,6 @@ void standard_mem_error(size_t size) { char buff[256]; SEND_LOG("(ERROR) Memory allocation error detected, %lu bytes missing",size); - DXCloseMode(); sprintf(buff,"Memory allocation error\n Application can't allocate %lu bytes of memory (%xh)\n",size,memman_handle); display_error(buff); exit(1); @@ -52,10 +51,6 @@ void load_error(const char *filename) { char buff[256]; SEND_LOG("(ERROR) Load error detected, system can't load file: %s",filename); - #ifdef LOGFILE - // bonz_table(); - #endif - DXCloseMode(); sprintf(buff,"Load error while loading file: %s", filename); display_error(buff); exit(1); @@ -64,7 +59,6 @@ void load_error(const char *filename) void standard_swap_error() { char buff[256]; - DXCloseMode(); sprintf(buff,"Swap error. Maybe disk is full"); display_error(buff); exit(1); @@ -531,7 +525,6 @@ void *ablock(int handle) if (h->status==BK_NOT_LOADED) { void *p;int32_t s; - char c[200]; SEND_LOG("(LOAD) Loading file as block '%-.12s' %04X",h->src_file,handle); if (h->seekpos==0) @@ -539,10 +532,8 @@ void *ablock(int handle) if (h->src_file[0]!=0) { if (mman_action!=NULL) mman_action(MMA_READ); - strcpy(c,mman_pathlist[h->path]); - strcat(c,h->src_file); - c[strlen(mman_pathlist[h->path])+12]='\0'; - p=load_file(c); + const char *name = build_pathname(2,mman_pathlist[h->path], h->src_file); + p=load_file(name); s=last_load_size; } else diff --git a/libs/memman.h b/libs/memman.h index 2875144..923866f 100644 --- a/libs/memman.h +++ b/libs/memman.h @@ -2,6 +2,7 @@ #include +#include "logfile.h" #ifndef _MEMMAN_H_ @@ -66,16 +67,14 @@ typedef handle_list *handle_groups[BK_MAJOR_HANDLES]; #define BK_PRELOAD 8 #define BK_HSWAP 16 -extern char *const * mman_pathlist; //tento pointer musi byt naplnen ukazatelem na tabulku cest -extern void (*mem_error)(size_t); //pokud neni NULL je tato funkce volana vzdy kdyz dojde pamet a system si s tim nevi rady -extern void (*swap_error)(void); +//extern char *const * mman_pathlist; //tento pointer musi byt naplnen ukazatelem na tabulku cest extern int memman_handle; //cislo handle naposled zpracovavaneho prikazem ablock extern char mman_patch; //jednicka zapina moznost pouziti patchu void *getmem(int32_t size); //alokace pameti pres memman. alokovat pomoci malloc lze ale hrozi nebezpeci ze vrati NULL void *grealloc(void *m,int32_t size); //realokace pameti pres memman void *load_file(const char *filename); //obycejne natahne soubor do pameti a vrati ukazatel. void init_manager(const char *filename,const char *swp); //inicializuje manager. Jmeno filename i swapname nejsou povinne (musi byt NULL kdyz nejsou pouzity) -void def_mman_group_table( char *const * ); //define pointer to table of paths, for each group there is path +void def_mman_group_table(const char ** ); //define pointer to table of paths, for each group there is path THANDLE_DATA *def_handle(int handle,const char *filename,void *decompress,char path); //deklaruje rukojet. promenna decompress je ukazatel na funkci ktera upravi data pred vracenim ukazatele void *ablock(int handle); //vraci ukazatel bloku spojeneho s handlem void alock(int handle); //zamyka blok @@ -115,22 +114,11 @@ extern void (*mman_action)(int action); //udalost volajici se pri akci mmanager void display_status(void); //zobrazi na display status memmanageru -#ifdef LOGFILE -char *get_time_str(void); -int q_current_task(void); -void send_log_impl(int task, const char *format, ...) __attribute__((format(printf, 2, 3))); -#define OPEN_LOG(log) memcpy(stderr,fopen_icase(log,"w"),sizeof(FILE)); -#define SEND_LOG(...) send_log_impl(q_current_task(), __VA_ARGS__) -#define CLOSE_LOG(void) fclose(logfile); -#else -#define OPEN_LOG(log) -#define SEND_LOG(...) -#define CLOSE_LOG(void) -#endif #ifdef __cplusplus } #endif + #endif diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt index 0692d44..5761bbf 100644 --- a/platform/CMakeLists.txt +++ b/platform/CMakeLists.txt @@ -14,6 +14,7 @@ target_sources(skeldal_platform PRIVATE config.cpp error.cpp timer.cpp + getopt.c ) # Podmínky pro platformu Windows diff --git a/platform/config.cpp b/platform/config.cpp index 9b459d0..0b915a4 100644 --- a/platform/config.cpp +++ b/platform/config.cpp @@ -5,10 +5,16 @@ #include #include #include + +typedef struct ini_config_section_tag { + using Section = std::map>; + Section data; +} INI_CONFIG_SECTION; + typedef struct ini_config_tag { - using Section = std::map>; - using Config = std::map>; + + using Config = std::map>; Config data; } INI_CONFIG; @@ -44,7 +50,7 @@ void parseIniStream(std::istream& input, Callback &&callback) { if (eqPos != std::string_view::npos) { std::string_view key_view = trim(line_view.substr(0, eqPos)); std::string_view value_view = trim(line_view.substr(eqPos + 1)); - callback(currentSection, std::string(key_view), std::string(value_view)); + callback(currentSection, key_view, value_view); } } } @@ -59,9 +65,9 @@ INI_CONFIG* ini_open(const char *filename) { parseIniStream(input, [&](std::string_view section, std::string_view key, std::string_view value) { INI_CONFIG::Config::iterator iter = c->data.find(section); if (iter == c->data.end()) { - iter = c->data.emplace(std::string(section), INI_CONFIG::Section()).first; + iter = c->data.emplace(std::string(section), INI_CONFIG_SECTION()).first; } - iter->second.emplace(std::string(key), std::string(value)); + iter->second.data.emplace(std::string(key), std::string(value)); }); return c; } @@ -73,15 +79,14 @@ void ini_close(INI_CONFIG *config) { const INI_CONFIG_SECTION* ini_section_open(const INI_CONFIG *cfg, const char *section) { auto iter = cfg->data.find(std::string_view(section)); if (iter == cfg->data.end()) return NULL; - else return reinterpret_cast(&iter->second); + else return &iter->second; } const char* ini_find_key(const INI_CONFIG_SECTION *section, const char *key) { if (section == NULL) return NULL; - const INI_CONFIG::Section *s = reinterpret_cast(section); - auto iter = s->find(std::string_view(key)); - if (iter == s->end()) return NULL; + auto iter = section->data.find(std::string_view(key)); + if (iter == section->data.end()) return NULL; return iter->second.c_str(); } @@ -171,8 +176,7 @@ int ini_get_boolean(const INI_CONFIG_SECTION *section, const char *key, } void ini_replace_key( INI_CONFIG_SECTION *section, const char *key, const char *value) { - auto s = reinterpret_cast(section); - (*s)[std::string(key)] = std::string(value); + section->data[std::string(key)] = std::string(value); } INI_CONFIG_SECTION* ini_create_section(INI_CONFIG *cfg, const char *section_name) { @@ -189,7 +193,7 @@ void ini_store_to_file(const INI_CONFIG *config, const char *filename) { std::ofstream out(filename,std::ios::out|std::ios::trunc); for (const auto &[sname, s]: config->data) { out << '[' << sname << ']' << std::endl; - for (const auto &[k,v]: s) { + for (const auto &[k,v]: s.data) { out << k << '=' << v << std::endl; } } diff --git a/platform/error.cpp b/platform/error.cpp index eee4023..d69c23d 100644 --- a/platform/error.cpp +++ b/platform/error.cpp @@ -1,10 +1,10 @@ +#include "legacy_coroutines.h" + #include #include #include #include -extern "C" { #include "error.h" -} #include "platform.h" @@ -15,8 +15,9 @@ void display_error(const char *text) { static std::uint32_t gtick = get_game_tick_count(); -void send_log_impl(int task, const char *format, ...) { +void send_log_impl(const char *format, ...) { va_list args; + int task = q_current_task(); char buff2[1000]; va_start(args, format); auto reltik = get_game_tick_count() - gtick; diff --git a/platform/error.h b/platform/error.h index 307c36f..15e28e6 100644 --- a/platform/error.h +++ b/platform/error.h @@ -1,4 +1,14 @@ #pragma once + +#ifdef __cplusplus +extern "C" { +#endif + + void display_error(const char *text); -void send_log_impl(int task, const char *format, ...); +void send_log_impl(const char *format, ...); + +#ifdef __cplusplus +} +#endif diff --git a/platform/file_access.cpp b/platform/file_access.cpp index b4d531b..affb318 100644 --- a/platform/file_access.cpp +++ b/platform/file_access.cpp @@ -2,6 +2,7 @@ #include #include +#include "../libs/logfile.h" std::filesystem::path break_and_compose_path(const std::string_view &pathname, char sep) { @@ -67,6 +68,8 @@ FILE *fopen_icase(const char *pathname, const char *mode) { static thread_local std::string build_pathname_buffer; + + const char * build_pathname(size_t nparts, const char *part1, ...) { va_list lst; va_start(lst, part1); @@ -76,6 +79,7 @@ const char * build_pathname(size_t nparts, const char *part1, ...) { p = p / va_arg(lst, const char *); } build_pathname_buffer = p; + SEND_LOG("(BUILD_PATHNAME) %s", build_pathname_buffer.c_str()); return build_pathname_buffer.c_str(); } @@ -84,3 +88,10 @@ char create_directories(const char *path) { std::error_code ec; return std::filesystem::create_directories(p, ec)?1:0; } + + +char change_current_directory(const char *path) { + std::error_code ec; + std::filesystem::current_path(std::filesystem::path(path), ec); + return ec == std::error_code{}?1:0; +} diff --git a/platform/getopt.c b/platform/getopt.c new file mode 100644 index 0000000..9a73084 --- /dev/null +++ b/platform/getopt.c @@ -0,0 +1,117 @@ +// Put this in a separate .h file (called "getopt.h"). +// The prototype for the header file is: +/* +#ifndef GETOPT_H +#define GETOPT_H + +int getopt(int nargc, char * const nargv[], const char *ostr) ; + +#endif +*/ + +#include "getopt.h" // make sure you construct the header file as dictated above + +/* +* Copyright (c) 1987, 1993, 1994 +* The Regents of the University of California. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. All advertising materials mentioning features or use of this software +* must display the following acknowledgement: +* This product includes software developed by the University of +* California, Berkeley and its contributors. +* 4. Neither the name of the University nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +*/ + +#include +#include + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int getopt(int nargc, char * const nargv[], const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + const char *oli; /* option letter list index */ + + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (optopt == (int)'-') + return (-1); + if (!*place) + ++optind; + if (opterr && *ostr != ':') + (void)printf("illegal option -- %c\n", optopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)printf("option requires an argument -- %c\n", optopt); + return (BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return (optopt); /* dump back option letter */ +} diff --git a/platform/getopt.h b/platform/getopt.h new file mode 100644 index 0000000..59a4da8 --- /dev/null +++ b/platform/getopt.h @@ -0,0 +1,13 @@ +#ifndef GETOPT_H + +#define GETOPT_H + +extern int opterr; /* if error message should be printed */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern int optreset; /* reset getopt */ +extern char *optarg; /* argument associated with option */ + +int getopt(int nargc, char * const nargv[], const char *ostr); + +#endif diff --git a/platform/linux/save_folder.cpp b/platform/linux/save_folder.cpp index dad3a32..f85b41e 100644 --- a/platform/linux/save_folder.cpp +++ b/platform/linux/save_folder.cpp @@ -17,9 +17,10 @@ static std::string get_default_savegame_dir() { -const char *get_default_savegame_directory() { +const char *get_default_savegame_directory(void) { static std::string dir = get_default_savegame_dir(); return dir.c_str(); + } diff --git a/platform/platform.h b/platform/platform.h index c7a3865..09a7e4c 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -41,6 +41,13 @@ const char * build_pathname(size_t nparts, const char *part1, ...); * @retval 0 failure */ char create_directories(const char *path); +///change current directory +/** + * @param path path + * @retval 1 success + * @retval 0 failure + */ +char change_current_directory(const char *path); @@ -71,7 +78,7 @@ void sleep_ms(uint32_t); } #endif -//------------- BGRAPH DX wrapper ------------------- + #include "sdl/BGraph2.h" #define WM_RELOADMAP (WM_APP+215) diff --git a/platform/save_folder.h b/platform/save_folder.h index e730256..5cacad7 100644 --- a/platform/save_folder.h +++ b/platform/save_folder.h @@ -1,11 +1,15 @@ -#ifdef __cplusplus__ +#ifndef _SKELDAL_PLATFORM_SAVE_FOLDER +#define _SKELDAL_PLATFORM_SAVE_FOLDER +#ifdef __cplusplus extern "C" { #endif #define SAVEGAME_FOLDERNAME "Skeldal"; -const char *get_default_savegame_directory(); +const char *get_default_savegame_directory(void); -#ifdef __cplusplus__ +#ifdef __cplusplus } #endif + +#endif diff --git a/platform/sdl/BGraph2.cpp b/platform/sdl/BGraph2.cpp index ea2b125..bd42c32 100644 --- a/platform/sdl/BGraph2.cpp +++ b/platform/sdl/BGraph2.cpp @@ -1,4 +1,5 @@ #include "BGraph2.h" +#include "../platform.h" #include "sdl_context.h" #include "global_context.h" @@ -9,34 +10,50 @@ static std::unique_ptr buffer2nd; static uint16_t *render_target; static uint16_t screen_pitch = 640; -char DXInit64(char inwindow,int zoom,int monitor, int refresh) { +char game_display_init(const INI_CONFIG_SECTION *display_section, const char *title) { - SDLContext::DisplayMode mode; - if (inwindow) { - if (zoom) { - mode = SDLContext::double_window; - } else { - mode = SDLContext::native_window; - } - } else { - mode = SDLContext::fullscreen; + SDLContext::Config cfg = {}; + const char *aspect_str; + + aspect_str = ini_get_string(display_section, "aspect_ratio", "4:3"); + if (sscanf(aspect_str, "%d:%d",&cfg.aspect_x, &cfg.aspect_y) != 2) { + cfg.aspect_x = cfg.aspect_y = 0; } + cfg.fullscreen = ini_get_boolean(display_section, "fullscreen", 1) == 1; + const char *comp = ini_get_string(display_section, "composer", "auto"); + if (stricmp(comp, "hardware") == 0 || stricmp(comp, "hw") == 0) { + cfg.composer = SDL_RENDERER_ACCELERATED; + } else if (stricmp(comp, "software") == 0 || stricmp(comp, "sw") == 0) { + cfg.composer = SDL_RENDERER_SOFTWARE; + } else { + cfg.composer = 0; + } + cfg.scale_quality = ini_get_string(display_section, "scale_quality", "auto"); + cfg.window_height = ini_get_int(display_section, "window_height", 480); + cfg.window_width = ini_get_int(display_section, "window_width", 640); + cfg.crt_filter = ini_get_boolean(display_section, "crt_filter", 1) == 1; + + + + + + screen_pitch = 640; - get_sdl_global_context().init_screen(mode, "Skeldal"); //todo allow change + get_sdl_global_context().init_video(cfg, title); screen_buffer = std::make_unique(screen_pitch*480); buffer2nd = std::make_unique(screen_pitch*480); std::fill(screen_buffer.get(), screen_buffer.get()+screen_pitch*480,0); render_target = screen_buffer.get(); return 1; + } -void DXCloseMode() { - get_sdl_global_context().close_screen(); +void game_display_close(void) { + get_sdl_global_context().close_video(); } - uint16_t *GetScreenAdr() { return render_target; } @@ -84,11 +101,26 @@ void StripBlt(void *data, unsigned int startline, uint32_t width) { } -void DXCopyRects64(unsigned short x,unsigned short y,unsigned short xs,unsigned short ys) { +static void DXCopyRects64(unsigned short x,unsigned short y,unsigned short xs,unsigned short ys) { get_sdl_global_context().present_rect(screen_buffer.get(), screen_pitch, x,y,xs,ys); } + +void game_display_update_rect(unsigned short x,unsigned short y,unsigned short xs,unsigned short ys) + { + + if (x>DxGetResX() || y>DxGetResY()) return; + if (xs==0) xs=DxGetResX(); + if (ys==0) ys=DxGetResY(); + if (x+xs>DxGetResX()) xs=DxGetResX()-x; + if (y+ys>DxGetResY()) ys=DxGetResY()-y; + DXCopyRects64(x,y,xs,ys); + } + + + + void *DxPrepareWalk(int ypos) { auto &sdl = get_sdl_global_context(); sdl.swap_render_buffers(); diff --git a/platform/sdl/BGraph2.h b/platform/sdl/BGraph2.h index d4116d7..83d85ba 100644 --- a/platform/sdl/BGraph2.h +++ b/platform/sdl/BGraph2.h @@ -1,4 +1,5 @@ #include +#include "../config.h" #ifndef __BGRAPH_DX_WRAPPER_ #define __BGRAPH_DX_WRAPPER_ @@ -17,16 +18,11 @@ void RedirectScreen(uint16_t *newaddr); void RestoreScreen(void); void RedirectScreenBufferSecond(void); +char game_display_init(const INI_CONFIG_SECTION *display_section, const char *title); +void game_display_close(void); +void game_display_update_rect(unsigned short x,unsigned short y,unsigned short xs,unsigned short ys); -//inicializuje a otevira rezim 640x480x16b v DX - otevre okno, pripravi vse pro beh hry -//Vraci 1 pri uspechu -char DXInit64(char inwindow,int zoom,int monitor, int refresh); -//uzavre rezim grafiky -void DXCloseMode(void); - -//void DXCopyRects32(unsigned short x,unsigned short y,unsigned short xs,unsigned short ys); -void DXCopyRects64(unsigned short x,unsigned short y,unsigned short xs,unsigned short ys); void *DxPrepareWalk(int ypos); void DxZoomWalk(void *handle, int ypos, int *points,float phase, void *lodka); diff --git a/platform/sdl/sdl_context.cpp b/platform/sdl/sdl_context.cpp index 145c220..3277dbc 100644 --- a/platform/sdl/sdl_context.cpp +++ b/platform/sdl/sdl_context.cpp @@ -60,11 +60,10 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur int pitch; SDL_LockTexture(*texture, nullptr, &pixels, &pitch); - bool wider_lines = height > 1024; + bool wider_lines = height > 1350; - // Vyplň texturu patternem (liché řádky tmavší) Uint32* pixelArray = (Uint32*)pixels; - Uint32 darkPixel = wider_lines?0x808080FF:0xC0C0C0FF; // Černá s částečnou průhledností + Uint32 darkPixel = wider_lines?0x808080FF:0xA0A0A0FF; Uint32 transparentPixel = wider_lines ?0xFFFFFFE0:0xFFFFFFC0; int step = wider_lines ?3:2; @@ -81,7 +80,7 @@ void SDLContext::generateCRTTexture(SDL_Renderer* renderer, SDL_Texture** textur -void SDLContext::init_screen(DisplayMode mode, const char *title) { +void SDLContext::init_video(const Config &config, const char *title) { char buff[256]; static Uint32 update_request_event = SDL_RegisterEvents(1); _update_request_event = update_request_event; @@ -89,14 +88,14 @@ void SDLContext::init_screen(DisplayMode mode, const char *title) { assert(!_render_thread.joinable()); - int width = 640; - int height = 480; - if (mode == double_window) { - width*=2; - height*=2; - } + int width = config.window_width; + int height = config.window_height; + aspect_x = config.aspect_x; + aspect_y = config.aspect_y; + crt_filter_enabled = config.crt_filter; - _fullscreen_mode = mode == fullscreen; + + _fullscreen_mode = config.fullscreen; std::atomic done = false; std::exception_ptr e; @@ -105,20 +104,31 @@ void SDLContext::init_screen(DisplayMode mode, const char *title) { try { SDL_Window *window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - width, height, SDL_WINDOW_RESIZABLE|(mode==fullscreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0)); + width, height, SDL_WINDOW_RESIZABLE|(_fullscreen_mode?SDL_WINDOW_FULLSCREEN_DESKTOP:0)); if (!window) { snprintf(buff, sizeof(buff), "SDL Error create window: %s\n", SDL_GetError()); throw std::runtime_error(buff); } - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2"); _window.reset(window); - SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, 0); + SDL_Renderer *renderer = SDL_CreateRenderer(_window.get(), -1, config.composer); if (!renderer) { - snprintf(buff,sizeof(buff), "Chyba při vytváření rendereru: %s\n", SDL_GetError()); + snprintf(buff,sizeof(buff), "Failed to create composer: %s\n", SDL_GetError()); throw std::runtime_error(buff); } + + SDL_RendererInfo rinfo; + SDL_GetRendererInfo(renderer, &rinfo); + + if (stricmp(config.scale_quality, "auto") == 0) { + if (rinfo.flags & SDL_RENDERER_ACCELERATED) { + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); + } + } else { + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, config.scale_quality); + } + _renderer.reset(renderer); SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, 640, 480); if (!texture) { @@ -159,7 +169,7 @@ void SDLContext::init_screen(DisplayMode mode, const char *title) { } -void SDLContext::close_screen() { +void SDLContext::close_video() { _render_thread.request_stop(); _render_thread.join(); } @@ -358,7 +368,7 @@ void SDLContext::update_screen() { SDL_SetTextureAlphaMod(_visible_texture, 255); SDL_RenderCopy(_renderer.get(), _visible_texture, NULL, &winrc); } - if (winrc.h > 900) { + if (winrc.h > 900 && crt_filter_enabled) { if (!_crt_effect) { SDL_Texture *txt; generateCRTTexture(_renderer.get(), &txt, 128, std::min(1440, winrc.h)); @@ -431,21 +441,28 @@ SDL_Rect SDLContext::get_window_aspect_rect() const { int ww; int wh; SDL_GetWindowSizeInPixels(_window.get(), &ww, &wh); - int apw = wh * 4 / 3; - int aph = ww * 3 / 4; - int fw; - int fh; - if (apw > ww) { - fw = ww; - fh = aph; + if (aspect_x && aspect_y) { + int apw = wh * aspect_x / aspect_y; + int aph = ww * aspect_y / aspect_x; + int fw; + int fh; + if (apw > ww) { + fw = ww; + fh = aph; + } else { + fw = apw; + fh = wh; + } + w.h = fh; + w.w = fw; + w.x = (ww - fw)/2; + w.y = (wh - fh)/2; } else { - fw = apw; - fh = wh; + w.x = 0; + w.y = 0; + w.w = ww; + w.h = wh; } - w.h = fh; - w.w = fw; - w.x = (ww - fw)/2; - w.y = (wh - fh)/2; return w; } diff --git a/platform/sdl/sdl_context.h b/platform/sdl/sdl_context.h index bce774e..ec260f5 100644 --- a/platform/sdl/sdl_context.h +++ b/platform/sdl/sdl_context.h @@ -14,16 +14,21 @@ public: SDLContext(); - enum DisplayMode { - native_window, - double_window, - fullscreen + struct Config { + int window_width; + int window_height; + bool crt_filter; + int composer; + const char *scale_quality; + bool fullscreen; + int aspect_x; + int aspect_y; }; - void init_screen(DisplayMode mode, const char *title); + void init_video(const Config &config, const char *title); - void close_screen(); + void close_video(); void present_rect(uint16_t *pixels, unsigned int pitch, unsigned int x, unsigned int y, unsigned int xs,unsigned ys); @@ -89,6 +94,9 @@ protected: MS_EVENT ms_event; mutable std::mutex _mx; + int aspect_x = 4; + int aspect_y = 3; + bool crt_filter_enabled = false; std::unique_ptr _window; std::unique_ptr _renderer; diff --git a/skeldal.ini b/skeldal.ini index da18ded..7a2e43a 100644 --- a/skeldal.ini +++ b/skeldal.ini @@ -1,19 +1,21 @@ ##### path # -# game_path = path to root of the game -# maps = relative path to maps -# video = relative path to videp +# root = path to root of the game. All other paths are relative to this path +# maps = relative path to maps +# video = relative path to video # data = relative path to skeldal.ddl # savegame = path to savegame, if not defined, retrieved from platform settings [paths] -game_path=/home/ondra/skeldal_game/ +# root=./ # maps=./maps/ # video=./video/ # data=./ # savegame = determine default + + #### video settings # @@ -28,15 +30,17 @@ game_path=/home/ondra/skeldal_game/ # best - best scale quality (SDL = linear) # linear - use linear filtering (Direct3D and OpenGL) # nearest - use nearest filtering +# aspect_ratio = x:y, none = don't keep fixed ratio' # [video] -fullscreen=on +#fullscreen=on #window_width=640 #window_height=480 #crt_filter=on -#smooth_scale=auto +#scale_quality=auto #composer=auto -#scale_quality +#aspect_ratio=4:3 -[audio] \ No newline at end of file + +[audio]