frameskip option for slow GPUs
This commit is contained in:
parent
d66793a117
commit
48b13cd83a
21 changed files with 246 additions and 122 deletions
|
@ -78,6 +78,7 @@
|
|||
CONFIGDEF_INT (VID_HEIGHT, "vid_height", RESY) \
|
||||
CONFIGDEF_INT (VID_RESIZABLE, "vid_resizable", 0) \
|
||||
CONFIGDEF_INT (VID_LATE_SWAP, "vid_late_swap", 0) \
|
||||
CONFIGDEF_INT (VID_FRAMESKIP, "vid_frameskip", 1) \
|
||||
CONFIGDEF_INT (VSYNC, "vsync", 0) \
|
||||
CONFIGDEF_INT (MIXER_CHUNKSIZE, "mixer_chunksize", 1024) \
|
||||
CONFIGDEF_FLOAT (SFX_VOLUME, "sfx_volume", 1.0) \
|
||||
|
|
|
@ -262,18 +262,22 @@ void credits_preload(void) {
|
|||
NULL);
|
||||
}
|
||||
|
||||
static FrameAction credits_frame(void *arg) {
|
||||
static FrameAction credits_logic_frame(void *arg) {
|
||||
update_transition();
|
||||
events_poll(NULL, 0);
|
||||
credits_process();
|
||||
credits_draw();
|
||||
global.frames++;
|
||||
return credits.end == 0 ? FRAME_STOP : FRAME_SWAP;
|
||||
return credits.end == 0 ? LFRAME_STOP : LFRAME_WAIT;
|
||||
}
|
||||
|
||||
static FrameAction credits_render_frame(void *arg) {
|
||||
credits_draw();
|
||||
return RFRAME_SWAP;
|
||||
}
|
||||
|
||||
void credits_loop(void) {
|
||||
credits_preload();
|
||||
credits_init();
|
||||
loop_at_fps(credits_frame, NULL, NULL, FPS);
|
||||
loop_at_fps(credits_logic_frame, credits_render_frame, NULL, FPS);
|
||||
credits_free();
|
||||
}
|
||||
|
|
15
src/ending.c
15
src/ending.c
|
@ -151,17 +151,16 @@ void ending_preload(void) {
|
|||
preload_resource(RES_BGM, "ending", RESF_OPTIONAL);
|
||||
}
|
||||
|
||||
static FrameAction ending_frame(void *arg) {
|
||||
static FrameAction ending_logic_frame(void *arg) {
|
||||
Ending *e = arg;
|
||||
|
||||
update_transition();
|
||||
events_poll(NULL, 0);
|
||||
|
||||
if(e->pos >= e->count - 1) {
|
||||
return FRAME_STOP;
|
||||
return LFRAME_STOP;
|
||||
}
|
||||
|
||||
ending_draw(e);
|
||||
global.frames++;
|
||||
|
||||
if(global.frames >= e->entries[e->pos+1].time) {
|
||||
|
@ -173,7 +172,13 @@ static FrameAction ending_frame(void *arg) {
|
|||
set_transition(TransFadeWhite, ENDING_FADE_OUT, ENDING_FADE_OUT);
|
||||
}
|
||||
|
||||
return FRAME_SWAP;
|
||||
return LFRAME_WAIT;
|
||||
}
|
||||
|
||||
static FrameAction ending_render_frame(void *arg) {
|
||||
Ending *e = arg;
|
||||
ending_draw(e);
|
||||
return RFRAME_SWAP;
|
||||
}
|
||||
|
||||
void ending_loop(void) {
|
||||
|
@ -183,6 +188,6 @@ void ending_loop(void) {
|
|||
global.frames = 0;
|
||||
set_ortho();
|
||||
start_bgm("ending");
|
||||
loop_at_fps(ending_frame, NULL, &e, FPS);
|
||||
loop_at_fps(ending_logic_frame, ending_render_frame, &e, FPS);
|
||||
free_ending(&e);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ void init_global(CLIAction *cli) {
|
|||
if(global.frameskip) {
|
||||
log_warn("FPS limiter disabled. Gotta go fast! (frameskip = %i)", global.frameskip);
|
||||
}
|
||||
|
||||
fpscounter_reset(&global.fps.logic);
|
||||
fpscounter_reset(&global.fps.render);
|
||||
fpscounter_reset(&global.fps.busy);
|
||||
}
|
||||
|
||||
// Inputdevice-agnostic method of checking whether a game control is pressed.
|
||||
|
|
|
@ -107,8 +107,11 @@ typedef struct {
|
|||
|
||||
int game_over;
|
||||
|
||||
FPSCounter fps;
|
||||
FPSCounter fps_busy;
|
||||
struct {
|
||||
FPSCounter logic;
|
||||
FPSCounter render;
|
||||
FPSCounter busy;
|
||||
} fps;
|
||||
|
||||
Replay replay;
|
||||
ReplayMode replaymode;
|
||||
|
|
|
@ -38,10 +38,17 @@ void char_menu_input(MenuData*);
|
|||
void draw_char_menu(MenuData*);
|
||||
void free_char_menu(MenuData*);
|
||||
|
||||
void update_char_menu(MenuData *menu) {
|
||||
for(int i = 0; i < menu->ecount; i++) {
|
||||
menu->entries[i].drawdata += 0.08*(1.0*(menu->cursor != i) - menu->entries[i].drawdata);
|
||||
}
|
||||
}
|
||||
|
||||
void create_char_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->input = char_menu_input;
|
||||
m->draw = draw_char_menu;
|
||||
m->logic = update_char_menu;
|
||||
m->end = free_char_menu;
|
||||
m->transition = TransMenuDark;
|
||||
m->flags = MF_Abortable | MF_Transient;
|
||||
|
@ -86,8 +93,6 @@ void draw_char_menu(MenuData *menu) {
|
|||
current_char = pchar->id;
|
||||
}
|
||||
|
||||
menu->entries[i].drawdata += 0.08*(1.0*(menu->cursor != i) - menu->entries[i].drawdata);
|
||||
|
||||
glColor4f(1,1,1,1-menu->entries[i].drawdata*2);
|
||||
draw_texture(SCREEN_W/3-200*menu->entries[i].drawdata, 2*SCREEN_H/3, tex);
|
||||
|
||||
|
@ -195,7 +200,7 @@ bool char_menu_input_handler(SDL_Event *event, void *arg) {
|
|||
void char_menu_input(MenuData *menu) {
|
||||
events_poll((EventHandler[]){
|
||||
{ .proc = char_menu_input_handler, .arg = menu },
|
||||
{NULL}
|
||||
{ NULL }
|
||||
}, EFLAG_MENU);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,14 @@ void set_difficulty(MenuData *m, void *d) {
|
|||
progress.game_settings.difficulty = (Difficulty)(uintptr_t)d;
|
||||
}
|
||||
|
||||
void update_difficulty_menu(MenuData *menu) {
|
||||
menu->drawdata[0] += (menu->cursor-menu->drawdata[0])*0.1;
|
||||
}
|
||||
|
||||
void create_difficulty_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->draw = draw_difficulty_menu;
|
||||
m->logic = update_difficulty_menu;
|
||||
m->transition = TransMenuDark;
|
||||
m->flags = MF_Transient | MF_Abortable;
|
||||
|
||||
|
@ -45,7 +50,6 @@ void draw_difficulty_menu(MenuData *menu) {
|
|||
|
||||
static Color clr = 0;
|
||||
|
||||
menu->drawdata[0] += (menu->cursor-menu->drawdata[0])*0.1;
|
||||
clr = approach_color(clr, difficulty_color(menu->cursor + D_Easy), 0.1);
|
||||
parse_color_call(multiply_colors(clr, rgba(0.1, 0.1, 0.1, 0.7)), glColor4f);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ static void give_up(MenuData *m, void *arg) {
|
|||
void create_gameover_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->draw = draw_ingame_menu;
|
||||
|
||||
m->logic = update_ingame_menu;
|
||||
m->flags = MF_Transient | MF_AlwaysProcessInput;
|
||||
m->transition = TransEmpty;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ void restart_game(MenuData *m, void *arg) {
|
|||
void create_ingame_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->draw = draw_ingame_menu;
|
||||
m->logic = update_ingame_menu;
|
||||
m->flags = MF_Abortable | MF_AlwaysProcessInput;
|
||||
m->transition = TransEmpty;
|
||||
m->cursor = 1;
|
||||
|
@ -49,6 +50,7 @@ static void skip_stage(MenuData *m, void *arg) {
|
|||
void create_ingame_menu_replay(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->draw = draw_ingame_menu;
|
||||
m->logic = update_ingame_menu;
|
||||
m->flags = MF_Abortable | MF_AlwaysProcessInput;
|
||||
m->transition = TransEmpty;
|
||||
m->cursor = 1;
|
||||
|
@ -77,6 +79,11 @@ void draw_ingame_menu_bg(MenuData *menu, float f) {
|
|||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void update_ingame_menu(MenuData *menu) {
|
||||
menu->drawdata[0] += (menu->cursor*35 - menu->drawdata[0])/7.0;
|
||||
menu->drawdata[1] += (stringwidth(menu->entries[menu->cursor].name, _fonts.standard) - menu->drawdata[1])/10.0;
|
||||
}
|
||||
|
||||
void draw_ingame_menu(MenuData *menu) {
|
||||
glPushMatrix();
|
||||
|
||||
|
@ -88,9 +95,6 @@ void draw_ingame_menu(MenuData *menu) {
|
|||
|
||||
draw_menu_selector(0, menu->drawdata[0], menu->drawdata[1]*2, 41, menu->frames);
|
||||
|
||||
menu->drawdata[0] += (menu->cursor*35 - menu->drawdata[0])/7.0;
|
||||
menu->drawdata[1] += (stringwidth(menu->entries[menu->cursor].name, _fonts.standard) - menu->drawdata[1])/10.0;
|
||||
|
||||
if(menu->context) {
|
||||
float s = 0.3 + 0.2 * sin(menu->frames/10.0);
|
||||
glColor4f(1-s/2, 1-s/2, 1-s, 1-menu_fade(menu));
|
||||
|
|
|
@ -17,4 +17,6 @@ void draw_ingame_menu(MenuData *menu);
|
|||
void create_ingame_menu(MenuData *menu);
|
||||
void create_ingame_menu_replay(MenuData *m);
|
||||
|
||||
void update_ingame_menu(MenuData *menu);
|
||||
|
||||
void restart_game(MenuData *m, void *arg);
|
||||
|
|
|
@ -66,13 +66,16 @@ void main_menu_update_practice_menus(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void begin_main_menu(MenuData *m) {
|
||||
static void begin_main_menu(MenuData *m) {
|
||||
start_bgm("menu");
|
||||
}
|
||||
|
||||
static void update_main_menu(MenuData *menu);
|
||||
|
||||
void create_main_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->draw = draw_main_menu;
|
||||
m->logic = update_main_menu;
|
||||
m->begin = begin_main_menu;
|
||||
|
||||
add_menu_entry(m, "Start Story", start_game, NULL);
|
||||
|
@ -101,6 +104,15 @@ void draw_main_menu_bg(MenuData* menu) {
|
|||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
static void update_main_menu(MenuData *menu) {
|
||||
menu->drawdata[1] += (stringwidth(menu->entries[menu->cursor].name, _fonts.mainmenu) - menu->drawdata[1])/10.0;
|
||||
menu->drawdata[2] += (35*menu->cursor - menu->drawdata[2])/10.0;
|
||||
|
||||
for(int i = 0; i < menu->ecount; i++) {
|
||||
menu->entries[i].drawdata += 0.2 * ((i == menu->cursor) - menu->entries[i].drawdata);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_main_menu(MenuData *menu) {
|
||||
draw_main_menu_bg(menu);
|
||||
|
||||
|
@ -118,14 +130,8 @@ void draw_main_menu(MenuData *menu) {
|
|||
draw_texture_p(0,0,bg);
|
||||
glPopMatrix();
|
||||
|
||||
int i;
|
||||
|
||||
menu->drawdata[1] += (stringwidth(menu->entries[menu->cursor].name, _fonts.mainmenu) - menu->drawdata[1])/10.0;
|
||||
menu->drawdata[2] += (35*menu->cursor - menu->drawdata[2])/10.0;
|
||||
|
||||
for(i = 0; i < menu->ecount; i++) {
|
||||
for(int i = 0; i < menu->ecount; i++) {
|
||||
float s = 5*sin(menu->frames/80.0 + 20*i);
|
||||
menu->entries[i].drawdata += 0.2 * ((i == menu->cursor) - menu->entries[i].drawdata);
|
||||
|
||||
if(menu->entries[i].action == NULL) {
|
||||
glColor4f(0.2,0.3,0.5,0.7);
|
||||
|
|
|
@ -46,7 +46,6 @@ void create_menu(MenuData *menu) {
|
|||
menu->transition_in_time = FADE_TIME;
|
||||
menu->transition_out_time = FADE_TIME;
|
||||
menu->fade = 1.0;
|
||||
menu->logic = menu_logic;
|
||||
menu->input = menu_input;
|
||||
}
|
||||
|
||||
|
@ -134,7 +133,7 @@ bool menu_input_handler(SDL_Event *event, void *arg) {
|
|||
void menu_input(MenuData *menu) {
|
||||
events_poll((EventHandler[]){
|
||||
{ .proc = menu_input_handler, .arg = menu },
|
||||
{NULL}
|
||||
{ NULL }
|
||||
}, EFLAG_MENU);
|
||||
}
|
||||
|
||||
|
@ -142,14 +141,14 @@ void menu_no_input(MenuData *menu) {
|
|||
events_poll(NULL, 0);
|
||||
}
|
||||
|
||||
void menu_logic(MenuData *menu) {
|
||||
menu->frames++;
|
||||
}
|
||||
|
||||
static FrameAction menu_frame(void *arg) {
|
||||
static FrameAction menu_logic_frame(void *arg) {
|
||||
MenuData *menu = arg;
|
||||
|
||||
menu->logic(menu);
|
||||
if(menu->logic) {
|
||||
menu->logic(menu);
|
||||
}
|
||||
|
||||
menu->frames++;
|
||||
|
||||
if(menu->state != MS_FadeOut || menu->flags & MF_AlwaysProcessInput) {
|
||||
assert(menu->input);
|
||||
|
@ -159,11 +158,16 @@ static FrameAction menu_frame(void *arg) {
|
|||
}
|
||||
|
||||
update_transition();
|
||||
|
||||
return menu->state == MS_Dead ? LFRAME_STOP : LFRAME_WAIT;
|
||||
}
|
||||
|
||||
static FrameAction menu_render_frame(void *arg) {
|
||||
MenuData *menu = arg;
|
||||
assert(menu->draw);
|
||||
menu->draw(menu);
|
||||
draw_transition();
|
||||
|
||||
return menu->state == MS_Dead ? FRAME_STOP : FRAME_SWAP;
|
||||
return RFRAME_SWAP;
|
||||
}
|
||||
|
||||
int menu_loop(MenuData *menu) {
|
||||
|
@ -173,8 +177,7 @@ int menu_loop(MenuData *menu) {
|
|||
menu->begin(menu);
|
||||
}
|
||||
|
||||
assert(menu->logic != NULL);
|
||||
loop_at_fps(menu_frame, NULL, menu, FPS);
|
||||
loop_at_fps(menu_logic_frame, menu_render_frame, menu, FPS);
|
||||
|
||||
if(menu->end) {
|
||||
menu->end(menu);
|
||||
|
|
|
@ -82,7 +82,6 @@ void add_menu_separator(MenuData *menu);
|
|||
void create_menu(MenuData *menu);
|
||||
void destroy_menu(MenuData *menu);
|
||||
|
||||
void menu_logic(MenuData *menu);
|
||||
void menu_input(MenuData *menu);
|
||||
void menu_no_input(MenuData *menu);
|
||||
|
||||
|
|
|
@ -285,6 +285,15 @@ int bind_common_onoffplus_set(OptionBinding *b, int v) {
|
|||
#define bind_common_int_get bind_common_onoff_inverted_get
|
||||
#define bind_common_int_set bind_common_onoff_inverted_set
|
||||
|
||||
int bind_common_intplus1_get(OptionBinding *b) {
|
||||
return config_get_int(b->configentry) - 1;
|
||||
}
|
||||
|
||||
int bind_common_intplus1_set(OptionBinding *b, int v) {
|
||||
return config_set_int(b->configentry, v + 1) - 1;
|
||||
}
|
||||
|
||||
|
||||
// --- Binding callbacks for individual options --- //
|
||||
|
||||
bool bind_audio_dependence(void) {
|
||||
|
@ -344,7 +353,7 @@ void destroy_options_menu(MenuData *m) {
|
|||
}
|
||||
|
||||
static void do_nothing(MenuData *menu, void *arg) { }
|
||||
|
||||
static void update_options_menu(MenuData *menu);
|
||||
void options_menu_input(MenuData*);
|
||||
|
||||
void create_options_menu_basic(MenuData *m, char *s) {
|
||||
|
@ -354,6 +363,7 @@ void create_options_menu_basic(MenuData *m, char *s) {
|
|||
m->context = s;
|
||||
m->input = options_menu_input;
|
||||
m->draw = draw_options_menu;
|
||||
m->logic = update_options_menu;
|
||||
m->end = destroy_options_menu;
|
||||
}
|
||||
|
||||
|
@ -370,19 +380,6 @@ void options_sub_video(MenuData *parent, void *arg) {
|
|||
b = bind_option(CONFIG_FULLSCREEN, bind_common_onoff_get, bind_common_onoff_set)
|
||||
); bind_onoff(b);
|
||||
|
||||
add_menu_entry(m, "Vertical synchronization", do_nothing,
|
||||
b = bind_option(CONFIG_VSYNC, bind_common_onoffplus_get, bind_common_onoffplus_set)
|
||||
); bind_addvalue(b, "on");
|
||||
bind_addvalue(b, "off");
|
||||
bind_addvalue(b, "adaptive");
|
||||
|
||||
#ifdef DEBUG
|
||||
add_menu_entry(m, "Swap buffers", do_nothing,
|
||||
b = bind_option(CONFIG_VID_LATE_SWAP, bind_common_onoff_get, bind_common_onoff_set)
|
||||
); bind_addvalue(b, "late");
|
||||
bind_addvalue(b, "early");
|
||||
#endif
|
||||
|
||||
add_menu_entry(m, "Window size", do_nothing,
|
||||
b = bind_resolution()
|
||||
); b->setter = bind_resolution_set;
|
||||
|
@ -399,6 +396,27 @@ void options_sub_video(MenuData *parent, void *arg) {
|
|||
|
||||
add_menu_separator(m);
|
||||
|
||||
add_menu_entry(m, "Vertical synchronization", do_nothing,
|
||||
b = bind_option(CONFIG_VSYNC, bind_common_onoffplus_get, bind_common_onoffplus_set)
|
||||
); bind_addvalue(b, "on");
|
||||
bind_addvalue(b, "off");
|
||||
bind_addvalue(b, "adaptive");
|
||||
|
||||
#ifdef DEBUG
|
||||
add_menu_entry(m, "Swap buffers", do_nothing,
|
||||
b = bind_option(CONFIG_VID_LATE_SWAP, bind_common_onoff_get, bind_common_onoff_set)
|
||||
); bind_addvalue(b, "late");
|
||||
bind_addvalue(b, "early");
|
||||
#endif
|
||||
|
||||
add_menu_entry(m, "Skip frames", do_nothing,
|
||||
b = bind_option(CONFIG_VID_FRAMESKIP, bind_common_intplus1_get, bind_common_intplus1_set)
|
||||
); bind_addvalue(b, "0");
|
||||
bind_addvalue(b, "½");
|
||||
bind_addvalue(b, "⅔");
|
||||
|
||||
add_menu_separator(m);
|
||||
|
||||
add_menu_entry(m, "Stage background", do_nothing,
|
||||
b = bind_option(CONFIG_NO_STAGEBG, bind_common_int_get, bind_common_int_set)
|
||||
); bind_onoff(b);
|
||||
|
@ -687,6 +705,20 @@ void draw_options_menu_bg(MenuData* menu) {
|
|||
glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
static void update_options_menu(MenuData *menu) {
|
||||
menu->drawdata[0] += ((SCREEN_W/2 - 100) - menu->drawdata[0])/10.0;
|
||||
menu->drawdata[1] += ((SCREEN_W - 200) * 1.75 - menu->drawdata[1])/10.0;
|
||||
menu->drawdata[2] += (20*menu->cursor - menu->drawdata[2])/10.0;
|
||||
|
||||
for(int i = 0; i < menu->ecount; i++) {
|
||||
MenuEntry *e = menu->entries + i;
|
||||
|
||||
if(e->name) {
|
||||
e->drawdata += 0.2 * (10*(i == menu->cursor) - e->drawdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_options_menu(MenuData *menu) {
|
||||
draw_options_menu_bg(menu);
|
||||
draw_menu_title(menu, menu->context);
|
||||
|
@ -696,10 +728,6 @@ void draw_options_menu(MenuData *menu) {
|
|||
|
||||
draw_menu_selector(menu->drawdata[0], menu->drawdata[2], menu->drawdata[1], 34, menu->frames);
|
||||
|
||||
menu->drawdata[0] += ((SCREEN_W/2 - 100) - menu->drawdata[0])/10.0;
|
||||
menu->drawdata[1] += ((SCREEN_W - 200) * 1.75 - menu->drawdata[1])/10.0;
|
||||
menu->drawdata[2] += (20*menu->cursor - menu->drawdata[2])/10.0;
|
||||
|
||||
int i, caption_drawn = 2;
|
||||
|
||||
for(i = 0; i < menu->ecount; i++) {
|
||||
|
@ -709,7 +737,6 @@ void draw_options_menu(MenuData *menu) {
|
|||
if(!e->name)
|
||||
continue;
|
||||
|
||||
e->drawdata += 0.2 * (10*(i == menu->cursor) - e->drawdata);
|
||||
float a = e->drawdata * 0.1;
|
||||
float alpha = (!bind || bind_isactive(bind))? 1 : 0.5;
|
||||
|
||||
|
|
|
@ -220,6 +220,10 @@ static void replayview_logic(MenuData *m) {
|
|||
ctx->sub_fade = approach(ctx->sub_fade, 0.0, 1.0/FADE_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
m->drawdata[0] = SCREEN_W/2 - 100;
|
||||
m->drawdata[1] = (SCREEN_W - 200)*1.75;
|
||||
m->drawdata[2] += (20*m->cursor - m->drawdata[2])/10.0;
|
||||
}
|
||||
|
||||
static void replayview_draw(MenuData *m) {
|
||||
|
@ -228,10 +232,6 @@ static void replayview_draw(MenuData *m) {
|
|||
draw_options_menu_bg(m);
|
||||
draw_menu_title(m, "Replays");
|
||||
|
||||
m->drawdata[0] = SCREEN_W/2 - 100;
|
||||
m->drawdata[1] = (SCREEN_W - 200)*1.75;
|
||||
m->drawdata[2] += (20*m->cursor - m->drawdata[2])/10.0;
|
||||
|
||||
draw_menu_list(m, 100, 100, replayview_drawitem);
|
||||
|
||||
if(ctx->submenu) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
void draw_stgpract_menu(MenuData *m) {
|
||||
draw_options_menu_bg(m);
|
||||
draw_menu_title(m, "Stage Practice");
|
||||
animate_menu_list(m);
|
||||
draw_menu_list(m, 100, 100, NULL);
|
||||
}
|
||||
|
||||
|
@ -25,6 +24,7 @@ void create_stgpract_menu(MenuData *m, Difficulty diff) {
|
|||
|
||||
create_menu(m);
|
||||
m->draw = draw_stgpract_menu;
|
||||
m->logic = animate_menu_list;
|
||||
m->flags = MF_Abortable;
|
||||
m->transition = TransMenuDark;
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
void draw_stage_menu(MenuData *m) {
|
||||
draw_options_menu_bg(m);
|
||||
draw_menu_title(m, "Select Stage");
|
||||
animate_menu_list(m);
|
||||
draw_menu_list(m, 100, 100, NULL);
|
||||
}
|
||||
|
||||
|
@ -28,6 +27,7 @@ void create_stage_menu(MenuData *m) {
|
|||
|
||||
create_menu(m);
|
||||
m->draw = draw_stage_menu;
|
||||
m->logic = animate_menu_list;
|
||||
m->flags = MF_Abortable;
|
||||
m->transition = TransMenuDark;
|
||||
|
||||
|
|
31
src/stage.c
31
src/stage.c
|
@ -540,13 +540,9 @@ typedef struct StageFrameState {
|
|||
uint16_t last_replay_fps;
|
||||
} StageFrameState;
|
||||
|
||||
static bool stage_fpslimit_condition(void *arg) {
|
||||
return (global.replaymode != REPLAY_PLAY || !gamekeypressed(KEY_SKIP)) && !global.frameskip;
|
||||
}
|
||||
|
||||
static void stage_update_fps(StageFrameState *fstate) {
|
||||
if(global.replaymode == REPLAY_RECORD) {
|
||||
uint16_t replay_fps = (uint16_t)rint(global.fps.fps);
|
||||
uint16_t replay_fps = (uint16_t)rint(global.fps.logic.fps);
|
||||
|
||||
if(replay_fps != fstate->last_replay_fps) {
|
||||
replay_stage_event(global.replay_stage, global.frames, EV_FPS, replay_fps);
|
||||
|
@ -555,7 +551,7 @@ static void stage_update_fps(StageFrameState *fstate) {
|
|||
}
|
||||
}
|
||||
|
||||
static FrameAction stage_frame(void *arg) {
|
||||
static FrameAction stage_logic_frame(void *arg) {
|
||||
StageFrameState *fstate = arg;
|
||||
StageInfo *stage = fstate->stage;
|
||||
|
||||
|
@ -586,8 +582,23 @@ static FrameAction stage_frame(void *arg) {
|
|||
progress.hiscore = global.plr.points;
|
||||
}
|
||||
|
||||
if(global.game_over > 0) {
|
||||
return LFRAME_STOP;
|
||||
}
|
||||
|
||||
if(global.frameskip || (global.replaymode == REPLAY_PLAY && gamekeypressed(KEY_SKIP))) {
|
||||
return LFRAME_SKIP;
|
||||
}
|
||||
|
||||
return LFRAME_WAIT;
|
||||
}
|
||||
|
||||
static FrameAction stage_render_frame(void *arg) {
|
||||
StageFrameState *fstate = arg;
|
||||
StageInfo *stage = fstate->stage;
|
||||
|
||||
if(global.frameskip && global.frames % global.frameskip) {
|
||||
return FRAME_DROP;
|
||||
return RFRAME_DROP;
|
||||
}
|
||||
|
||||
tsrand_lock(&global.rand_game);
|
||||
|
@ -597,10 +608,9 @@ static FrameAction stage_frame(void *arg) {
|
|||
END_DRAW_CODE();
|
||||
tsrand_unlock(&global.rand_game);
|
||||
tsrand_switch(&global.rand_game);
|
||||
|
||||
draw_transition();
|
||||
|
||||
return (global.game_over > 0) ? FRAME_STOP : FRAME_SWAP;
|
||||
return RFRAME_SWAP;
|
||||
}
|
||||
|
||||
void stage_loop(StageInfo *stage) {
|
||||
|
@ -676,8 +686,7 @@ void stage_loop(StageInfo *stage) {
|
|||
display_stage_title(stage);
|
||||
|
||||
StageFrameState fstate = { .stage = stage };
|
||||
fpscounter_reset(&global.fps);
|
||||
loop_at_fps(stage_frame, stage_fpslimit_condition, &fstate, FPS);
|
||||
loop_at_fps(stage_logic_frame, stage_render_frame, &fstate, FPS);
|
||||
|
||||
if(global.replaymode == REPLAY_RECORD) {
|
||||
replay_stage_event(global.replay_stage, global.frames, EV_OVER, 0);
|
||||
|
|
|
@ -573,10 +573,24 @@ void stage_draw_hud_text(struct labels_s* labels) {
|
|||
// Warning: pops outer matrix!
|
||||
glPopMatrix();
|
||||
|
||||
#ifdef DEBUG
|
||||
snprintf(buf, sizeof(buf), "%.2f fps, timer: %d, frames: %d", global.fps.fps, global.timer, global.frames);
|
||||
#ifdef DEBUGe
|
||||
snprintf(buf, sizeof(buf), "%.2f lfps, %.2f rfps, timer: %d, frames: %d",
|
||||
global.fps.logic.fps,
|
||||
global.fps.render.fps,
|
||||
global.timer,
|
||||
global.frames
|
||||
);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "%.2f fps", global.fps.fps);
|
||||
if(get_effective_frameskip() > 1) {
|
||||
snprintf(buf, sizeof(buf), "%.2f lfps, %.2f rfps",
|
||||
global.fps.logic.fps,
|
||||
global.fps.render.fps
|
||||
);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%.2f fps",
|
||||
global.fps.logic.fps
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
draw_text(AL_Right | AL_Flag_NoAdjust, SCREEN_W, rint(SCREEN_H - 0.5 * stringheight(buf, _fonts.monosmall)), buf, _fonts.monosmall);
|
||||
|
@ -653,7 +667,7 @@ static void stage_draw_framerate_graphs(void) {
|
|||
|
||||
glUseProgram(s->prog);
|
||||
|
||||
fill_graph(NUM_SAMPLES, samples, &global.fps);
|
||||
fill_graph(NUM_SAMPLES, samples, &global.fps.logic);
|
||||
glUniform3f(u_colors[0], 0.0, 1.0, 1.0);
|
||||
glUniform3f(u_colors[1], 1.0, 1.0, 0.0);
|
||||
glUniform3f(u_colors[2], 1.0, 0.0, 0.0);
|
||||
|
@ -663,7 +677,7 @@ static void stage_draw_framerate_graphs(void) {
|
|||
// x -= w * 1.1;
|
||||
y += h + 1;
|
||||
|
||||
fill_graph(NUM_SAMPLES, samples, &global.fps_busy);
|
||||
fill_graph(NUM_SAMPLES, samples, &global.fps.busy);
|
||||
glUniform3f(u_colors[0], 0.0, 1.0, 0.0);
|
||||
glUniform3f(u_colors[1], 1.0, 0.0, 0.0);
|
||||
glUniform3f(u_colors[2], 1.0, 0.0, 0.5);
|
||||
|
|
101
src/util.c
101
src/util.c
|
@ -338,38 +338,67 @@ void fpscounter_update(FPSCounter *fps) {
|
|||
fps->last_update_time = time_get();
|
||||
}
|
||||
|
||||
void loop_at_fps(FrameAction (*frame_func)(void*), bool (*limiter_cond_func)(void*), void *arg, uint32_t fps) {
|
||||
assert(frame_func != NULL);
|
||||
uint32_t get_effective_frameskip(void) {
|
||||
uint32_t frameskip;
|
||||
|
||||
if(global.frameskip > 0) {
|
||||
frameskip = global.frameskip;
|
||||
} else {
|
||||
frameskip = config_get_int(CONFIG_VID_FRAMESKIP);
|
||||
}
|
||||
|
||||
return frameskip;
|
||||
}
|
||||
|
||||
void loop_at_fps(LogicFrameFunc logic_frame, RenderFrameFunc render_frame, void *arg, uint32_t fps) {
|
||||
assert(logic_frame != NULL);
|
||||
assert(render_frame != NULL);
|
||||
assert(fps > 0);
|
||||
|
||||
hrtime_t frame_start_time = time_get();
|
||||
hrtime_t next_frame_time = frame_start_time;
|
||||
hrtime_t target_frame_time = ((hrtime_t)1.0) / fps;
|
||||
|
||||
FrameAction last_frame_action = FRAME_SWAP;
|
||||
FrameAction rframe_action = RFRAME_SWAP;
|
||||
FrameAction lframe_action = LFRAME_WAIT;
|
||||
|
||||
int32_t delay = getenvint("TAISEI_FRAMELIMITER_SLEEP", 0);
|
||||
bool exact_delay = getenvint("TAISEI_FRAMELIMITER_SLEEP_EXACT", 1);
|
||||
bool compensate = getenvint("TAISEI_FRAMELIMITER_COMPENSATE", 1);
|
||||
bool late_swap = config_get_int(CONFIG_VID_LATE_SWAP);
|
||||
|
||||
while(last_frame_action != FRAME_STOP) {
|
||||
uint32_t frame_num = 0;
|
||||
|
||||
while(lframe_action != LFRAME_STOP) {
|
||||
frame_start_time = time_get();
|
||||
|
||||
begin_frame:
|
||||
if(late_swap && last_frame_action == FRAME_SWAP) {
|
||||
if(late_swap && rframe_action == RFRAME_SWAP) {
|
||||
video_swap_buffers();
|
||||
}
|
||||
|
||||
global.fps_busy.last_update_time = time_get();
|
||||
last_frame_action = frame_func(arg);
|
||||
global.fps.busy.last_update_time = time_get();
|
||||
|
||||
if(!late_swap && last_frame_action == FRAME_SWAP) {
|
||||
++frame_num;
|
||||
lframe_action = logic_frame(arg);
|
||||
|
||||
if(frame_num % get_effective_frameskip()) {
|
||||
rframe_action = RFRAME_DROP;
|
||||
} else {
|
||||
rframe_action = render_frame(arg);
|
||||
fpscounter_update(&global.fps.render);
|
||||
}
|
||||
|
||||
fpscounter_update(&global.fps.logic);
|
||||
fpscounter_update(&global.fps.busy);
|
||||
|
||||
if(!late_swap && rframe_action == RFRAME_SWAP) {
|
||||
video_swap_buffers();
|
||||
}
|
||||
|
||||
fpscounter_update(&global.fps);
|
||||
fpscounter_update(&global.fps_busy);
|
||||
if(lframe_action == LFRAME_SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if(gamekeypressed(KEY_FPSLIMIT_OFF)) {
|
||||
|
@ -377,38 +406,36 @@ begin_frame:
|
|||
}
|
||||
#endif
|
||||
|
||||
if(!limiter_cond_func || limiter_cond_func(arg)) {
|
||||
next_frame_time = frame_start_time + target_frame_time;
|
||||
next_frame_time = frame_start_time + target_frame_time;
|
||||
|
||||
if(compensate) {
|
||||
hrtime_t rt = time_get();
|
||||
hrtime_t diff = rt - next_frame_time;
|
||||
if(compensate) {
|
||||
hrtime_t rt = time_get();
|
||||
hrtime_t diff = rt - next_frame_time;
|
||||
|
||||
if(diff >= 0) {
|
||||
// frame took too long...
|
||||
// try to compensate in the next frame to avoid slowdown
|
||||
frame_start_time = rt - min(diff, target_frame_time);
|
||||
goto begin_frame;
|
||||
if(diff >= 0) {
|
||||
// frame took too long...
|
||||
// try to compensate in the next frame to avoid slowdown
|
||||
frame_start_time = rt - min(diff, target_frame_time);
|
||||
goto begin_frame;
|
||||
}
|
||||
}
|
||||
|
||||
if(delay > 0) {
|
||||
int32_t realdelay = delay;
|
||||
int32_t maxdelay = (int32_t)(1000 * (next_frame_time - time_get()));
|
||||
|
||||
if(realdelay > maxdelay) {
|
||||
if(exact_delay) {
|
||||
log_debug("Delay of %i ignored. Minimum is %i but TAISEI_FRAMELIMITER_SLEEP_EXACT is active", realdelay, maxdelay);
|
||||
realdelay = 0;
|
||||
} else {
|
||||
log_debug("Delay reduced from %i to %i", realdelay, maxdelay);
|
||||
realdelay = maxdelay;
|
||||
}
|
||||
}
|
||||
|
||||
if(delay > 0) {
|
||||
int32_t realdelay = delay;
|
||||
int32_t maxdelay = (int32_t)(1000 * (next_frame_time - time_get()));
|
||||
|
||||
if(realdelay > maxdelay) {
|
||||
if(exact_delay) {
|
||||
log_debug("Delay of %i ignored. Minimum is %i but TAISEI_FRAMELIMITER_SLEEP_EXACT is active", realdelay, maxdelay);
|
||||
realdelay = 0;
|
||||
} else {
|
||||
log_debug("Delay reduced from %i to %i", realdelay, maxdelay);
|
||||
realdelay = maxdelay;
|
||||
}
|
||||
}
|
||||
|
||||
if(realdelay > 0) {
|
||||
SDL_Delay(realdelay);
|
||||
}
|
||||
if(realdelay > 0) {
|
||||
SDL_Delay(realdelay);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
15
src/util.h
15
src/util.h
|
@ -106,12 +106,19 @@ typedef struct {
|
|||
} FPSCounter;
|
||||
|
||||
typedef enum FrameAction {
|
||||
FRAME_SWAP,
|
||||
FRAME_DROP,
|
||||
FRAME_STOP,
|
||||
RFRAME_SWAP,
|
||||
RFRAME_DROP,
|
||||
|
||||
LFRAME_WAIT,
|
||||
LFRAME_SKIP,
|
||||
LFRAME_STOP,
|
||||
} FrameAction;
|
||||
|
||||
void loop_at_fps(FrameAction (*frame_func)(void*), bool (*limiter_cond_func)(void*), void *arg, uint32_t fps);
|
||||
typedef FrameAction (*LogicFrameFunc)(void*);
|
||||
typedef FrameAction (*RenderFrameFunc)(void*);
|
||||
|
||||
uint32_t get_effective_frameskip(void);
|
||||
void loop_at_fps(LogicFrameFunc logic_frame, RenderFrameFunc render_frame, void *arg, uint32_t fps);
|
||||
void fpscounter_reset(FPSCounter *fps);
|
||||
void fpscounter_update(FPSCounter *fps);
|
||||
void set_ortho(void);
|
||||
|
|
Loading…
Reference in a new issue