diff --git a/src/config.h b/src/config.h index b3d488fb..c14bbc9d 100644 --- a/src/config.h +++ b/src/config.h @@ -34,7 +34,8 @@ enum { NO_SHADER, NO_AUDIO, - NO_STAGEBG + NO_STAGEBG, + NO_STAGEBG_FPSLIMIT }; void parse_config(char *filename); diff --git a/src/config.l b/src/config.l index 9e034eb8..9fbede56 100644 --- a/src/config.l +++ b/src/config.l @@ -37,6 +37,7 @@ "disable_shader" { yylval = NO_SHADER; return tNO_SHADER; } "disable_audio" {yylval = NO_AUDIO; return tNO_AUDIO; } "disable_stagebg" { yylval = NO_STAGEBG; return tNO_STAGEBG; } +"disable_stagebg_auto_fpslimit" { yylval = NO_STAGEBG_FPSLIMIT; return tNO_STAGEBG_FPSLIMIT; } "shift" { yylval = SDLK_LSHIFT; return SKEY; } "ctrl" { yylval = SDLK_LCTRL; return SKEY; } diff --git a/src/config.y b/src/config.y index e5647566..8ab8e1d2 100644 --- a/src/config.y +++ b/src/config.y @@ -48,6 +48,7 @@ %token tNO_SHADER %token tNO_AUDIO %token tNO_STAGEBG +%token tNO_STAGEBG_FPSLIMIT %token SKEY @@ -86,7 +87,8 @@ key_key : tKEY_UP | tNO_SHADER | tNO_AUDIO | tFULLSCREEN - | tNO_STAGEBG; + | tNO_STAGEBG + | tNO_STAGEBG_FPSLIMIT; nl : LB { lineno++; }; %% @@ -137,4 +139,5 @@ void config_preset() { tconfig.intval[NO_AUDIO] = 0; tconfig.intval[NO_STAGEBG] = 0; + tconfig.intval[NO_STAGEBG_FPSLIMIT] = 40; } diff --git a/src/global.h b/src/global.h index d602438d..dd0697cd 100644 --- a/src/global.h +++ b/src/global.h @@ -104,6 +104,7 @@ typedef struct { FPSCounter fps; + int nostagebg; // I don't want the automatic stagebg handling to mess with the config, and I don't want that longass if in more than one place either. } Global; extern Global global; diff --git a/src/main.c b/src/main.c index 33f335e0..81fcd367 100644 --- a/src/main.c +++ b/src/main.c @@ -103,7 +103,6 @@ int main(int argc, char** argv) { atexit(taisei_shutdown); - #ifdef DEBUG printf("** Compiled with DEBUG flag!\n"); if(argc >= 2 && argv[1]) { diff --git a/src/menu/options.c b/src/menu/options.c index b17849fc..56ca013c 100644 --- a/src/menu/options.c +++ b/src/menu/options.c @@ -111,37 +111,60 @@ int bind_addvalue(OptionBinding *b, char *val) return b->valcount-1; } +void bind_setvaluerange(OptionBinding *b, int vmin, int vmax) { + b->valrange_min = vmin; + b->valrange_max = vmax; +} + // Called to select a value of a BT_IntValue type binding by index -int binding_setvalue(OptionBinding *b, int v) +int bind_setvalue(OptionBinding *b, int v) { return b->selected = b->setter(b, v); } // Called to get the selected value of a BT_IntValue type binding by index -int binding_getvalue(OptionBinding *b) +int bind_getvalue(OptionBinding *b) { // query AND update return b->selected = b->getter(b); } // Selects the next to current value of a BT_IntValue type binding -int binding_setnext(OptionBinding *b) +int bind_setnext(OptionBinding *b) { - int s = b->selected + 1; - if(s >= b->valcount) + int s = b->selected +1; + + if(b->valrange_max) { + if(s > b->valrange_max) + s = b->valrange_min; + } else if(s >= b->valcount) s = 0; - - return binding_setvalue(b, s); + + return bind_setvalue(b, s); } // Selects the previous to current value of a BT_IntValue type binding -int binding_setprev(OptionBinding *b) +int bind_setprev(OptionBinding *b) { int s = b->selected - 1; - if(s < 0) + + if(b->valrange_max) { + if(s < b->valrange_min) + s = b->valrange_max; + } else if(s < 0) s = b->valcount - 1; - return binding_setvalue(b, s); + return bind_setvalue(b, s); +} + +void bind_setdependence(OptionBinding *b, BindingDependence dep) { + b->dependence = dep; +} + +int bind_isactive(OptionBinding *b) { + if(!b->dependence) + return True; + return b->dependence(); } // Initializes selection for all BT_IntValue type bindings @@ -152,7 +175,7 @@ void bindings_initvalues(MenuData *m) int i; for(i = 0; i < m->ecount; ++i) if(binds[i].enabled && binds[i].type == BT_IntValue) - binding_getvalue(&(binds[i])); + bind_getvalue(&(binds[i])); } // --- Shared binding callbacks --- // @@ -177,6 +200,9 @@ int bind_common_onoffset_inverted(void *b, int v) return tconfig.intval[((OptionBinding*)b)->configentry] = v; } +#define bind_common_intget bind_common_onoffget_inverted +#define bind_common_intset bind_common_onoffset_inverted + // --- Binding callbacks for individual options --- // int bind_fullscreen_set(void *b, int v) @@ -227,6 +253,10 @@ int bind_noshader_set(void *b, int v) return i; } +int bind_stagebg_fpslimit_dependence() { + return tconfig.intval[NO_STAGEBG] == 2; +} + // --- Config saving --- // void menu_save_config(MenuData *m, char *filename) @@ -293,7 +323,7 @@ void backtomain(void *arg) } void create_options_menu(MenuData *m) { - OptionBinding* b; + OptionBinding *b; create_menu(m); m->type = MT_Persistent; @@ -317,10 +347,18 @@ void create_options_menu(MenuData *m) { bind_onoff(b); add_menu_entry(m, "Stage Background", do_nothing, NULL); - b = bind_option(m, "disable_stagebg", NO_STAGEBG, bind_common_onoffget_inverted, - bind_common_onoffset_inverted); - bind_onoff(b); - + b = bind_option(m, "disable_stagebg", NO_STAGEBG, bind_common_intget, + bind_common_intset); + bind_addvalue(b, "on"); + bind_addvalue(b, "off"); + bind_addvalue(b, "auto"); + + add_menu_entry(m, "Minimum FPS", do_nothing, NULL); + b = bind_option(m, "disable_stagebg_auto_fpslimit", NO_STAGEBG_FPSLIMIT, bind_common_intget, + bind_common_intset); + bind_setvaluerange(b, 20, 60); + bind_setdependence(b, bind_stagebg_fpslimit_dependence); + add_menu_entry(m, " ", NULL, NULL); allocate_binding(m); @@ -403,37 +441,46 @@ void draw_options_menu(MenuData *menu) { for(i = 0; i < menu->ecount; i++) { menu->entries[i].drawdata += 0.2 * (10*(i == menu->cursor) - menu->entries[i].drawdata); + bind = &(binds[i]); + int hasbind = bind->enabled; + float alpha = (!hasbind || bind_isactive(bind))? 1 : 0.5; + if(menu->entries[i].action == NULL && clr != 0) { clr = 0; - glColor4f(0.5, 0.5, 0.5, 0.7); + glColor4f(0.5, 0.5, 0.5, 0.7 * alpha); } else if(i == menu->cursor && clr != 1) { clr = 1; - glColor4f(1,1,0,0.7); + glColor4f(1,1,0,0.7 * alpha); } else if(clr != 2) { clr = 2; - glColor4f(1, 1, 1, 0.7); + glColor4f(1, 1, 1, 0.7 * alpha); } - draw_text(AL_Left, 20 - menu->entries[i].drawdata, 20*i, menu->entries[i].name, _fonts.standard); + draw_text(AL_Left, + ((hasbind && bind->dependence)? 20 : 0) // hack hack hack + + 20 - menu->entries[i].drawdata, 20*i, menu->entries[i].name, _fonts.standard); - bind = &(binds[i]); - if(bind->enabled) + if(hasbind) { int j, origin = SCREEN_W - 220; + switch(bind->type) { case BT_IntValue: - for(j = bind->valcount-1; j+1; --j) - { + if(bind->valrange_max) { + char tmp[16]; // who'd use a 16-digit number here anyway? + snprintf(tmp, 16, "%d", bind_getvalue(bind)); + draw_text(AL_Right, origin, 20*i, tmp, _fonts.standard); + } else for(j = bind->valcount-1; j+1; --j) { if(j != bind->valcount-1) origin -= strlen(bind->values[j+1])/2.0 * 20; - if(binding_getvalue(bind) == j && clr != 1) { + if(bind_getvalue(bind) == j) { clr = 1; - glColor4f(1,1,0,0.7); + glColor4f(1,1,0,0.7 * alpha); } else if(clr != 0) { clr = 0; - glColor4f(0.5,0.5,0.5,0.7); + glColor4f(0.5,0.5,0.5,0.7 * alpha); } draw_text(AL_Right, origin, 20*i, bind->values[j], _fonts.standard); @@ -473,7 +520,7 @@ void draw_options_menu(MenuData *menu) { // --- Input processing --- // -void binding_input(MenuData *menu, OptionBinding *b) +void bind_input(MenuData *menu, OptionBinding *b) { // yes, no global_input() here. @@ -499,20 +546,22 @@ void binding_input(MenuData *menu, OptionBinding *b) } static void options_key_action(MenuData *menu, int sym) { + #define SHOULD_SKIP (!menu->entries[menu->cursor].action || (((OptionBinding*)menu->context)[menu->cursor].enabled && !bind_isactive(&(((OptionBinding*)menu->context)[menu->cursor])))) + if(sym == tconfig.intval[KEY_DOWN] || sym == SDLK_DOWN) { menu->drawdata[3] = 10; do { menu->cursor++; if(menu->cursor >= menu->ecount) menu->cursor = 0; - } while(!menu->entries[menu->cursor].action); + } while SHOULD_SKIP; } else if(sym == tconfig.intval[KEY_UP] || sym == SDLK_UP) { menu->drawdata[3] = 10; do { menu->cursor--; if(menu->cursor < 0) menu->cursor = menu->ecount - 1; - } while(!menu->entries[menu->cursor].action); + } while SHOULD_SKIP; } else if((sym == tconfig.intval[KEY_SHOT] || sym == SDLK_RETURN) && menu->entries[menu->cursor].action) { menu->selected = menu->cursor; @@ -521,7 +570,7 @@ static void options_key_action(MenuData *menu, int sym) { if(bind->enabled) switch(bind->type) { - case BT_IntValue: binding_setnext(bind); break; + case BT_IntValue: bind_setnext(bind); break; case BT_KeyBinding: bind->blockinput = True; break; } else @@ -532,14 +581,14 @@ static void options_key_action(MenuData *menu, int sym) { OptionBinding *bind = &(binds[menu->selected]); if(bind->enabled && bind->type == BT_IntValue) - binding_setprev(bind); + 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) - binding_setnext(bind); + bind_setnext(bind); } else if(sym == SDLK_ESCAPE) { menu->quit = 2; } @@ -553,7 +602,7 @@ void options_menu_input(MenuData *menu) { if((b = get_input_blocking_binding(menu)) != NULL) { - binding_input(menu, b); + bind_input(menu, b); return; } diff --git a/src/menu/options.h b/src/menu/options.h index d3a2229f..adf39aeb 100644 --- a/src/menu/options.h +++ b/src/menu/options.h @@ -18,6 +18,7 @@ int options_menu_loop(MenuData *m); typedef int (*BindingGetter)(void*); typedef int (*BindingSetter)(void*, int); +typedef int (*BindingDependence)(); typedef enum BindingType { BT_IntValue, @@ -27,8 +28,11 @@ typedef enum BindingType { typedef struct OptionBinding { char **values; int valcount; + int valrange_min; + int valrange_max; BindingGetter getter; BindingSetter setter; + BindingDependence dependence; int selected; int configentry; int enabled; diff --git a/src/stage.c b/src/stage.c index 66471dea..89bc4a0a 100644 --- a/src/stage.c +++ b/src/stage.c @@ -16,6 +16,7 @@ void stage_start() { global.frames = 0; global.game_over = 0; global.points = 0; + global.nostagebg = False; } void stage_input() { @@ -129,9 +130,14 @@ void stage_draw(StageRule bgdraw, ShaderRule *shaderrules, int time) { glTranslatef(-(VIEWPORT_X+VIEWPORT_W/2.0), -(VIEWPORT_Y+VIEWPORT_H/2.0),0); glEnable(GL_DEPTH_TEST); - if(!global.menu && !tconfig.intval[NO_STAGEBG]) + // NO_STAGEBG == 2 means "automatic mode". Do we need a derpenum for this? + // global.fps.fps is unreliable here, show_fps is better + + if(!global.nostagebg && ((!global.menu && !tconfig.intval[NO_STAGEBG]) || + (tconfig.intval[NO_STAGEBG] == 2 && (global.fps.show_fps == 0 || global.fps.show_fps > tconfig.intval[NO_STAGEBG_FPSLIMIT])))) bgdraw(); - + else global.nostagebg = True; + glPopMatrix(); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -234,7 +240,7 @@ void apply_bg_shaders(ShaderRule *shaderrules) { glPopMatrix(); glBindFramebuffer(GL_FRAMEBUFFER, 0); - } else if(!tconfig.intval[NO_STAGEBG]) { + } else if(!global.nostagebg) { for(i = 0; shaderrules != NULL && shaderrules[i] != NULL; i++) { glBindFramebuffer(GL_FRAMEBUFFER, resources.fbg[!fbonum].fbo); shaderrules[i](fbonum); @@ -357,9 +363,6 @@ void stage_loop(StageRule start, StageRule end, StageRule draw, StageRule event, SDL_GL_SwapBuffers(); frame_rate(&global.lasttime); - - if(global.fps.fps <= 40) - tconfig.intval[NO_STAGEBG] = 1; } end(); @@ -371,4 +374,4 @@ void draw_stage_title(int t, int dur, char *stage, char *subtitle) { return; draw_text(AL_Center, VIEWPORT_W/2, VIEWPORT_H/2, stage, _fonts.mainmenu); -} \ No newline at end of file +}