From 3d59ba51e42e1a0909d68bd9e18b5726ea3a5831 Mon Sep 17 00:00:00 2001 From: "Andrew \"Akari\" Alexeyew" Date: Sat, 28 Jul 2012 23:53:53 +0300 Subject: [PATCH] user-adjustable resolution, fuck yeah --- src/CMakeLists.txt | 1 + src/config.h | 5 +- src/config.l | 3 ++ src/config.y | 9 ++++ src/global.c | 16 +----- src/global.h | 5 +- src/main.c | 17 ++---- src/menu/options.c | 88 ++++++++++++++++++++++++++----- src/menu/options.h | 3 +- src/stage.c | 3 +- src/video.c | 127 +++++++++++++++++++++++++++++++++++++++++++++ src/video.h | 33 ++++++++++++ 12 files changed, 266 insertions(+), 44 deletions(-) create mode 100644 src/video.c create mode 100644 src/video.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9a8080f6..21221fa5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,7 @@ set(SRCs vbo.c stageutils.c matrix.c + video.c menu/menu.c menu/mainmenu.c menu/options.c diff --git a/src/config.h b/src/config.h index 50604dee..07ce1dfa 100644 --- a/src/config.h +++ b/src/config.h @@ -37,7 +37,10 @@ enum { NO_STAGEBG, NO_STAGEBG_FPSLIMIT, - SAVE_RPY + SAVE_RPY, + + VID_WIDTH, + VID_HEIGHT, }; void parse_config(char *filename); diff --git a/src/config.l b/src/config.l index 6fb243fd..d4ec43d4 100644 --- a/src/config.l +++ b/src/config.l @@ -41,6 +41,9 @@ "save_rpy" { yylval = SAVE_RPY; return tSAVE_RPY; } +"vid_width" { yylval = VID_WIDTH; return tVID_WIDTH; } +"vid_height" { yylval = VID_HEIGHT; return tVID_HEIGHT; } + "shift" { yylval = SDLK_LSHIFT; return SKEY; } "ctrl" { yylval = SDLK_LCTRL; return SKEY; } "return" { yylval = SDLK_RETURN; return SKEY; } diff --git a/src/config.y b/src/config.y index 9f059bee..e4af4f47 100644 --- a/src/config.y +++ b/src/config.y @@ -7,6 +7,7 @@ %{ #include "config.h" + #include "global.h" #include #include #include @@ -51,6 +52,9 @@ %token tNO_STAGEBG_FPSLIMIT %token tSAVE_RPY +%token tVID_WIDTH +%token tVID_HEIGHT + %token SKEY %token NUMBER @@ -90,6 +94,8 @@ key_key : tKEY_UP | tFULLSCREEN | tNO_STAGEBG | tNO_STAGEBG_FPSLIMIT + | tVID_WIDTH + | tVID_HEIGHT | tSAVE_RPY; nl : LB { lineno++; }; @@ -144,6 +150,9 @@ void config_preset() { tconfig.intval[NO_STAGEBG_FPSLIMIT] = 40; tconfig.intval[SAVE_RPY] = 2; + + tconfig.intval[VID_WIDTH] = RESX; + tconfig.intval[VID_HEIGHT] = RESY; } int config_sym2key(int sym) { diff --git a/src/global.c b/src/global.c index a3c3dbac..c3792f0c 100644 --- a/src/global.c +++ b/src/global.c @@ -6,6 +6,7 @@ */ #include "global.h" +#include "video.h" #include #include #include @@ -79,19 +80,6 @@ void fade_out(float f) { glColor4f(1,1,1,1); } -extern SDL_Surface *display; - -void toggle_fullscreen() -{ - int newflags = display->flags; - newflags ^= SDL_FULLSCREEN; - tconfig.intval[FULLSCREEN] = newflags & SDL_FULLSCREEN; - - SDL_FreeSurface(display); - if((display = SDL_SetVideoMode(RESX, RESY, 32, newflags)) == NULL) - errx(-1, "Error opening screen: %s", SDL_GetError()); -} - void take_screenshot() { FILE *out; @@ -165,6 +153,6 @@ void global_processevent(SDL_Event *event) if(sym == tconfig.intval[KEY_SCREENSHOT]) take_screenshot(); if((sym == SDLK_RETURN && (keys[SDLK_LALT] || keys[SDLK_RALT])) || sym == tconfig.intval[KEY_FULLSCREEN]) - toggle_fullscreen(); + video_toggle_fullscreen(); } } diff --git a/src/global.h b/src/global.h index b773dcae..4915f80f 100644 --- a/src/global.h +++ b/src/global.h @@ -35,9 +35,10 @@ #define FILE_PREFIX PREFIX "/share/taisei/" #define CONFIG_FILE "config" -enum { +enum { + // defaults RESX = 800, - RESY = 600, + RESY = 600, SCREEN_W = 800, SCREEN_H = 600, diff --git a/src/main.c b/src/main.c index 70730222..6f0dd18c 100644 --- a/src/main.c +++ b/src/main.c @@ -12,12 +12,11 @@ #include "taisei_err.h" #include "global.h" +#include "video.h" #include "stage.h" #include "menu/mainmenu.h" #include "paths/native.h" -SDL_Surface *display; - void init_gl() { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); @@ -35,7 +34,7 @@ void taisei_shutdown() { free_resources(); - SDL_FreeSurface(display); + video_shutdown(); SDL_Quit(); printf("-- Good Bye.\n"); } @@ -63,17 +62,9 @@ int main(int argc, char** argv) { SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - int flags = SDL_OPENGL; - if(tconfig.intval[FULLSCREEN]) - flags |= SDL_FULLSCREEN; - - if((display = SDL_SetVideoMode(RESX, RESY, 32, flags)) == NULL) - errx(-1, "Error opening screen: %s", SDL_GetError()); - + video_init(); printf("-- SDL viewport\n"); - - SDL_WM_SetCaption("TaiseiProject", NULL); - + init_gl(); printf("-- GL\n"); diff --git a/src/menu/options.c b/src/menu/options.c index b0c7082c..92bed5d6 100644 --- a/src/menu/options.c +++ b/src/menu/options.c @@ -10,6 +10,7 @@ #include "menu.h" #include "options.h" #include "global.h" +#include "video.h" #include "paths/native.h" #include "taisei_err.h" @@ -90,6 +91,26 @@ OptionBinding* bind_keybinding(MenuData *m, char *optname, int cfgentry) return bind; } +// Super-special binding type for the resulution setting +OptionBinding* bind_resulution(MenuData *m) { + OptionBinding *bind; + bind = allocate_binding(m); + + bind->enabled = True; + bind->type = BT_Resolution; + bind->valcount = video.mcount; + bind->selected = -1; + + int i; for(i = 0; i < video.mcount; ++i) { + VideoMode *m = &(video.modes[i]); + + if(m->width == video.intended.width && m->height == video.intended.height) + bind->selected = i; + } + + return bind; +} + // Returns a pointer to the first found binding that blocks input. If none found, returns NULL. OptionBinding* get_input_blocking_binding(MenuData *m) { @@ -119,14 +140,20 @@ void bind_setvaluerange(OptionBinding *b, int vmin, int vmax) { // Called to select a value of a BT_IntValue type binding by index int bind_setvalue(OptionBinding *b, int v) { - return b->selected = b->setter(b, v); + if(b->setter) + return b->selected = b->setter(b, v); + else + return b->selected = v; } // Called to get the selected value of a BT_IntValue type binding by index int bind_getvalue(OptionBinding *b) { - // query AND update - return b->selected = b->getter(b); + if(b->getter) + // query AND update + return b->selected = b->getter(b); + else + return b->selected; } // Selects the next to current value of a BT_IntValue type binding @@ -207,7 +234,7 @@ int bind_common_onoffset_inverted(void *b, int v) int bind_fullscreen_set(void *b, int v) { - toggle_fullscreen(); + video_toggle_fullscreen(); return bind_common_onoffset(b, v); } @@ -313,6 +340,11 @@ void menu_save_config(MenuData *m, char *filename) fprintf(out, "%s = K%i\n", bind->optname, tconfig.intval[bind->configentry]); break; + case BT_Resolution: + // at this point, the intended resolution is what the user has picked + fprintf(out, "vid_width = %i\nvid_height = %i\n", video.intended.width, video.intended.height); + break; + default: printf("FIXME: unhandled BindingType %i, option '%s' will NOT be saved!\n", bind->type, bind->optname); } @@ -327,6 +359,19 @@ void menu_save_config(MenuData *m, char *filename) void destroy_options_menu(void *menu) { MenuData *m = (MenuData*)menu; + OptionBinding *binds = (OptionBinding*)m->context; + int i; + + for(i = 0; i < m->ecount; ++i) { + if(binds[i].type == BT_Resolution) { + if(binds[i].selected != -1) { + VideoMode *m = &(video.modes[binds[i].selected]); + video_setmode(m->width, m->height, tconfig.intval[FULLSCREEN]); + } + break; + } + } + menu_save_config(m, CONFIG_FILE); free_bindings(menu); } @@ -348,6 +393,9 @@ void create_options_menu(MenuData *m) { #define bind_onoff(b) bind_addvalue(b, "on"); bind_addvalue(b, "off") + add_menu_entry(m, "Video Mode", do_nothing, NULL); + b = bind_resulution(m); + add_menu_entry(m, "Fullscreen", do_nothing, NULL); b = bind_option(m, "fullscreen", FULLSCREEN, bind_common_onoffget, bind_fullscreen_set); bind_onoff(b); @@ -357,7 +405,7 @@ void create_options_menu(MenuData *m) { bind_noaudio_set); bind_onoff(b); - add_menu_entry(m, "Shader", do_nothing, NULL); + add_menu_entry(m, "Shaders", do_nothing, NULL); b = bind_option(m, "disable_shader", NO_SHADER, bind_common_onoffget_inverted, bind_noshader_set); bind_onoff(b); @@ -519,6 +567,24 @@ void draw_options_menu(MenuData *menu) { else draw_text(AL_Right, origin, 20*i, SDL_GetKeyName(tconfig.intval[bind->configentry]), _fonts.standard); break; + + case BT_Resolution: { + char tmp[16]; + int w, h; + + if(bind->selected == -1) { + w = video.intended.width; + h = video.intended.height; + } else { + VideoMode *m = &(video.modes[bind->selected]); + w = m->width; + h = m->height; + } + + snprintf(tmp, 16, "%dx%d", w, h); + draw_text(AL_Right, origin, 20*i, tmp, _fonts.standard); + break; + } } } } @@ -582,24 +648,22 @@ static void options_key_action(MenuData *menu, int sym) { if(bind->enabled) switch(bind->type) { - case BT_IntValue: bind_setnext(bind); break; - case BT_KeyBinding: bind->blockinput = True; break; - } - else - menu->quit = 1; + case BT_IntValue: case BT_Resolution: bind_setnext(bind); break; + case BT_KeyBinding: bind->blockinput = True; break; + } else menu->quit = 1; } else if(sym == tconfig.intval[KEY_LEFT] || sym == SDLK_LEFT) { menu->selected = menu->cursor; OptionBinding *binds = (OptionBinding*)menu->context; OptionBinding *bind = &(binds[menu->selected]); - if(bind->enabled && bind->type == BT_IntValue) + if(bind->enabled && (bind->type == BT_IntValue || bind->type == BT_Resolution)) bind_setprev(bind); } else if(sym == tconfig.intval[KEY_RIGHT] || sym == SDLK_RIGHT) { menu->selected = menu->cursor; OptionBinding *binds = (OptionBinding*)menu->context; OptionBinding *bind = &(binds[menu->selected]); - if(bind->enabled && bind->type == BT_IntValue) + if(bind->enabled && (bind->type == BT_IntValue || bind->type == BT_Resolution)) bind_setnext(bind); } else if(sym == SDLK_ESCAPE) { menu->quit = 1; diff --git a/src/menu/options.h b/src/menu/options.h index adf39aeb..8f9ea79b 100644 --- a/src/menu/options.h +++ b/src/menu/options.h @@ -22,7 +22,8 @@ typedef int (*BindingDependence)(); typedef enum BindingType { BT_IntValue, - BT_KeyBinding + BT_KeyBinding, + BT_Resolution } BindingType; typedef struct OptionBinding { diff --git a/src/stage.c b/src/stage.c index 8d506dcd..b6341448 100644 --- a/src/stage.c +++ b/src/stage.c @@ -10,6 +10,7 @@ #include #include #include "global.h" +#include "video.h" #include "replay.h" #include "config.h" #include "player.h" @@ -246,7 +247,7 @@ void stage_draw(StageInfo *info, StageRule bgdraw, ShaderRule *shaderrules, int if(!tconfig.intval[NO_SHADER]) { glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0,0,RESX,RESY); + glViewport(0, 0, video.current.width, video.current.height); glPushMatrix(); if(global.plr.cha == Marisa && global.plr.shot == MarisaLaser && global.frames - global.plr.recovery < 0) glTranslatef(8*sin(global.frames),8*sin(global.frames+3),0); diff --git a/src/video.c b/src/video.c new file mode 100644 index 00000000..90af3fc5 --- /dev/null +++ b/src/video.c @@ -0,0 +1,127 @@ +/* + * This software is licensed under the terms of the MIT-License + * See COPYING for further information. + * --- + * Copyright (C) 2011, Lukas Weber + * Copyright (C) 2012, Alexeyew Andrew + */ + +#include "global.h" +#include "video.h" +#include "taisei_err.h" +#include + +static VideoMode common_modes[] = { + {RESX, RESY}, + + {640, 480}, + {800, 600}, + {1024, 768}, + {1280, 960}, + {1152, 864}, + {1400, 1050}, + {1440, 1080}, + + {0, 0}, +}; + +static void video_add_mode(int width, int height) { + if(video.modes) { + int i; for(i = 0; i < video.mcount; ++i) { + VideoMode *m = &(video.modes[i]); + if(m->width == width && m->height == height) + return; + } + } + + video.modes = (VideoMode*)realloc(video.modes, (++video.mcount) * sizeof(VideoMode)); + video.modes[video.mcount-1].width = width; + video.modes[video.mcount-1].height = height; +} + +static int video_compare_modes(const void *a, const void *b) { + VideoMode *va = (VideoMode*)a; + VideoMode *vb = (VideoMode*)b; + return va->width * va->height - vb->width * vb->height; +} + +static void _video_setmode(int w, int h, int fs, int fallback) { + int flags = SDL_OPENGL; + if(fs) flags |= SDL_FULLSCREEN; + + if(!fallback) { + video.intended.width = w; + video.intended.height = h; + } + + if(display) + SDL_FreeSurface(display); + + if(!(display = SDL_SetVideoMode(w, h, 32, flags))) { + if(fallback) { + errx(-1, "video_setmode(): error opening screen: %s", SDL_GetError()); + return; + } + + warnx("video_setmode(): setting %dx%d failed, falling back to %dx%d", w, h, RESX, RESY); + _video_setmode(RESX, RESY, fs, True); + } + + const SDL_VideoInfo *info = SDL_GetVideoInfo(); + video.current.width = info->current_w; + video.current.height = info->current_h; + + glViewport(0, 0, video.current.width, video.current.height); +} + +void video_setmode(int w, int h, int fs) { + _video_setmode(w, h, fs, False); +} + +int video_isfullscreen(void) { + return !!(display->flags & SDL_FULLSCREEN); +} + +void video_toggle_fullscreen(void) { + video_setmode(video.intended.width, video.intended.height, !video_isfullscreen()); +} + +void video_init(void) { + SDL_Rect **modes; + int i; + + memset(&video, 0, sizeof(video)); + + // First register all resolutions that are available in fullscreen + modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE); + if(!modes) { + warnx("video_init(): no available fullscreen modes"); + tconfig.intval[FULLSCREEN] = False; + } else if(modes == (SDL_Rect**)-1) { + warnx("video_init(): you seem to have a weird video driver"); + } else { + for(i = 0; modes[i]; ++i) { + video_add_mode(modes[i]->w, modes[i]->h); + } + } + + // Then, add some common 4:3 modes for the windowed mode if they are not there yet. + // This is required for some multihead setups. + for(i = 0; common_modes[i].width; ++i) + video_add_mode(common_modes[i].width, common_modes[i].height); + + // sort it, mainly for the options menu + qsort(video.modes, video.mcount, sizeof(VideoMode), video_compare_modes); + + for(i = 0; i < video.mcount; ++i) { + printf(" +++ %dx%d\n", video.modes[i].width, video.modes[i].height); + } + + video_setmode(tconfig.intval[VID_WIDTH], tconfig.intval[VID_HEIGHT], tconfig.intval[FULLSCREEN]); + SDL_WM_SetCaption("TaiseiProject", NULL); +} + +void video_shutdown(void) { + SDL_FreeSurface(display); + free(video.modes); +} diff --git a/src/video.h b/src/video.h new file mode 100644 index 00000000..054b0d8f --- /dev/null +++ b/src/video.h @@ -0,0 +1,33 @@ +/* + * This software is licensed under the terms of the MIT-License + * See COPYING for further information. + * --- + * Copyright (C) 2011, Lukas Weber + * Copyright (C) 2012, Alexeyew Andrew + */ + +#ifndef VIDEO_H +#define VIDEO_H + +typedef struct VideoMode { + unsigned int width; + unsigned int height; +} VideoMode; + +typedef struct { + VideoMode *modes; + int mcount; + VideoMode intended; + VideoMode current; +} Video; + +Video video; +SDL_Surface *display; + +void video_init(void); +void video_shutdown(void); +void video_setmode(int w, int h, int fs); +int video_isfullscreen(void); +void video_toggle_fullscreen(void); + +#endif