Refactored and improved menus and transitions
This commit is contained in:
parent
fb50b87ffe
commit
57053210dd
28 changed files with 369 additions and 253 deletions
18
src/events.c
18
src/events.c
|
@ -15,10 +15,10 @@
|
|||
void handle_events(EventHandler handler, EventFlags flags, void *arg) {
|
||||
SDL_Event event;
|
||||
|
||||
int kbd = flags & EF_Keyboard;
|
||||
int text = flags & EF_Text;
|
||||
int menu = flags & EF_Menu;
|
||||
int game = flags & EF_Game;
|
||||
bool kbd = flags & EF_Keyboard;
|
||||
bool text = flags & EF_Text;
|
||||
bool menu = flags & EF_Menu;
|
||||
bool game = flags & EF_Game;
|
||||
|
||||
// TODO: rewrite text input handling to properly support multibyte characters and IMEs
|
||||
|
||||
|
@ -35,6 +35,7 @@ void handle_events(EventHandler handler, EventFlags flags, void *arg) {
|
|||
while(SDL_PollEvent(&event)) {
|
||||
SDL_Scancode scan = event.key.keysym.scancode;
|
||||
SDL_Keymod mod = event.key.keysym.mod;
|
||||
bool repeat = event.key.repeat;
|
||||
|
||||
switch(event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
|
@ -45,14 +46,13 @@ void handle_events(EventHandler handler, EventFlags flags, void *arg) {
|
|||
handler(E_SubmitText, 0, arg);
|
||||
else if(scan == SDL_SCANCODE_BACKSPACE)
|
||||
handler(E_CharErased, 0, arg);
|
||||
} else {
|
||||
} else if(!repeat) {
|
||||
if(scan == config_get_int(CONFIG_KEY_SCREENSHOT)) {
|
||||
take_screenshot();
|
||||
break;
|
||||
}
|
||||
|
||||
if((scan == SDL_SCANCODE_RETURN && (mod & KMOD_ALT)) || scan == config_get_int(CONFIG_KEY_FULLSCREEN)) {
|
||||
// video_toggle_fullscreen();
|
||||
config_set_int(CONFIG_FULLSCREEN, !config_get_int(CONFIG_FULLSCREEN));
|
||||
break;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ void handle_events(EventHandler handler, EventFlags flags, void *arg) {
|
|||
handler(E_KeyDown, scan, arg);
|
||||
}
|
||||
|
||||
if(menu) {
|
||||
if(menu && (!repeat || transition.state == TRANS_IDLE)) {
|
||||
if(scan == config_get_int(CONFIG_KEY_DOWN) || scan == SDL_SCANCODE_DOWN) {
|
||||
handler(E_CursorDown, 0, arg);
|
||||
} else if(scan == config_get_int(CONFIG_KEY_UP) || scan == SDL_SCANCODE_UP) {
|
||||
|
@ -78,7 +78,7 @@ void handle_events(EventHandler handler, EventFlags flags, void *arg) {
|
|||
}
|
||||
}
|
||||
|
||||
if(game && !event.key.repeat) {
|
||||
if(game && !repeat) {
|
||||
if(scan == config_get_int(CONFIG_KEY_PAUSE) || scan == SDL_SCANCODE_ESCAPE) {
|
||||
handler(E_Pause, 0, arg);
|
||||
} else {
|
||||
|
@ -95,7 +95,7 @@ void handle_events(EventHandler handler, EventFlags flags, void *arg) {
|
|||
handler(E_KeyUp, scan, arg);
|
||||
}
|
||||
|
||||
if(game && !event.key.repeat) {
|
||||
if(game && !repeat) {
|
||||
int key = config_key_from_scancode(scan);
|
||||
if(key >= 0)
|
||||
handler(E_PlrKeyUp, key, arg);
|
||||
|
|
|
@ -199,7 +199,6 @@ int main(int argc, char **argv) {
|
|||
global.diff = atoi(argv[2]);
|
||||
}
|
||||
|
||||
|
||||
printf("** Entering %s.\n", stg->title);
|
||||
|
||||
do {
|
||||
|
@ -215,11 +214,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
MenuData menu;
|
||||
create_main_menu(&menu);
|
||||
printf("-- menu\n");
|
||||
set_sfx_volume(config_get_float(CONFIG_SFX_VOLUME));
|
||||
set_bgm_volume(config_get_float(CONFIG_BGM_VOLUME));
|
||||
start_bgm("bgm_menu");
|
||||
main_menu_loop(&menu);
|
||||
menu_loop(&menu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -20,20 +20,28 @@ void set_shotmode(MenuData *m, void *p) {
|
|||
|
||||
void create_shottype_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->transition = NULL;
|
||||
|
||||
add_menu_entry(m, "Laser Sign|Mirror Sign", set_shotmode, (void *) YoumuOpposite);
|
||||
add_menu_entry(m, "Star Sign|Haunting Sign", set_shotmode, (void *) YoumuHoming);
|
||||
}
|
||||
|
||||
void char_menu_input(MenuData*);
|
||||
void draw_char_menu(MenuData*);
|
||||
void free_char_menu(MenuData*);
|
||||
|
||||
void create_char_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
|
||||
m->input = char_menu_input;
|
||||
m->draw = draw_char_menu;
|
||||
m->end = free_char_menu;
|
||||
m->transition = TransMenuDark;
|
||||
m->flags = MF_Abortable | MF_Transient;
|
||||
m->context = malloc(sizeof(MenuData));
|
||||
create_shottype_menu(m->context);
|
||||
|
||||
add_menu_entry(m, "dialog/marisa|Kirisame Marisa|Black Magician", set_player, (void *)Marisa);
|
||||
add_menu_entry(m, "dialog/youmu|Konpaku Yōmu|Half-Phantom Girl", set_player, (void *)Youmu);
|
||||
add_menu_entry(m, "dialog/marisa|Kirisame Marisa|Black Magician", set_player, (void *)Marisa)->transition = TransFadeBlack;
|
||||
add_menu_entry(m, "dialog/youmu|Konpaku Yōmu|Half-Phantom Girl", set_player, (void *)Youmu)->transition = TransFadeBlack;
|
||||
}
|
||||
|
||||
void draw_char_menu(MenuData *menu) {
|
||||
|
@ -168,7 +176,3 @@ void free_char_menu(MenuData *menu) {
|
|||
destroy_menu(mod);
|
||||
free(mod);
|
||||
}
|
||||
|
||||
int char_menu_loop(MenuData *menu) {
|
||||
return menu_loop(menu, char_menu_input, draw_char_menu, free_char_menu);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,5 @@
|
|||
|
||||
void create_char_menu(MenuData *m);
|
||||
void draw_char_menu(MenuData *menu);
|
||||
int char_menu_loop(MenuData *menu);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,13 +26,13 @@ troll:
|
|||
|
||||
if(stagediff == D_Any) {
|
||||
create_difficulty_menu(&m);
|
||||
if(difficulty_menu_loop(&m) == -1) {
|
||||
if(menu_loop(&m) == -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
create_char_menu(&m);
|
||||
if(char_menu_loop(&m) == -1) {
|
||||
if(menu_loop(&m) == -1) {
|
||||
if(stagediff != D_Any) {
|
||||
return;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ troll2:
|
|||
case 2: {
|
||||
MenuData m;
|
||||
create_saverpy_menu(&m);
|
||||
saverpy_menu_loop(&m);
|
||||
menu_loop(&m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -162,5 +162,5 @@ void animate_menu_list(MenuData *m) {
|
|||
}
|
||||
|
||||
void menu_commonaction_close(MenuData *menu, void *arg) {
|
||||
kill_menu(menu);
|
||||
menu->state = MS_Dead;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ void set_difficulty(MenuData *m, void *d) {
|
|||
|
||||
void create_difficulty_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
|
||||
m->draw = draw_difficulty_menu;
|
||||
m->transition = TransMenuDark;
|
||||
m->flags = MF_Transient | MF_Abortable;
|
||||
|
||||
add_menu_entry(m, "Easy\nfor fearful fairies", set_difficulty, (void *)D_Easy);
|
||||
|
@ -53,7 +54,3 @@ void draw_difficulty_menu(MenuData *menu) {
|
|||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
int difficulty_menu_loop(MenuData *menu) {
|
||||
return menu_loop(menu, NULL, draw_difficulty_menu, NULL);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,5 @@
|
|||
|
||||
void create_difficulty_menu(MenuData *menu);
|
||||
void draw_difficulty_menu(MenuData *m);
|
||||
int difficulty_menu_loop(MenuData *m);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "menu.h"
|
||||
#include "gameovermenu.h"
|
||||
#include "ingamemenu.h"
|
||||
#include "global.h"
|
||||
|
||||
void continue_game(MenuData *m, void *arg)
|
||||
|
@ -36,9 +37,10 @@ void restart_game(MenuData *m, void *arg);
|
|||
|
||||
void create_gameover_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->draw = draw_ingame_menu;
|
||||
|
||||
m->flags = MF_Transient | MF_AlwaysProcessInput;
|
||||
m->transition = NULL;
|
||||
m->transition = TransEmpty;
|
||||
|
||||
if(global.stage->type == STAGE_SPELL) {
|
||||
m->context = "Spell Failed";
|
||||
|
@ -58,4 +60,6 @@ void create_gameover_menu(MenuData *m) {
|
|||
if(!c)
|
||||
m->cursor = 1;
|
||||
}
|
||||
|
||||
set_transition(TransEmpty, 0, m->transition_out_time);
|
||||
}
|
||||
|
|
|
@ -24,11 +24,13 @@ void restart_game(MenuData *m, void *arg) {
|
|||
|
||||
void create_ingame_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->draw = draw_ingame_menu;
|
||||
m->flags = MF_Abortable | MF_Transient | MF_AlwaysProcessInput;
|
||||
m->transition = NULL;
|
||||
m->transition = TransEmpty;
|
||||
add_menu_entry(m, "Return to Game", return_to_game, NULL);
|
||||
add_menu_entry(m, "Restart the Game", restart_game, NULL)->transition = TransFadeBlack;
|
||||
add_menu_entry(m, "Return to Title", return_to_title, NULL)->transition = TransFadeBlack;
|
||||
set_transition(TransEmpty, 0, m->transition_out_time);
|
||||
}
|
||||
|
||||
void draw_ingame_menu_bg(float f) {
|
||||
|
@ -89,7 +91,3 @@ void draw_ingame_menu(MenuData *menu) {
|
|||
|
||||
draw_hud();
|
||||
}
|
||||
|
||||
int ingame_menu_loop(MenuData *m) {
|
||||
return menu_loop(m, NULL, draw_ingame_menu, NULL);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,5 @@ void draw_ingame_menu_bg(float f);
|
|||
|
||||
void create_ingame_menu(MenuData *menu);
|
||||
void draw_ingame_menu(MenuData *menu);
|
||||
int ingame_menu_loop(MenuData *menu);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,25 +22,25 @@
|
|||
void enter_options(MenuData *menu, void *arg) {
|
||||
MenuData m;
|
||||
create_options_menu(&m);
|
||||
options_menu_loop(&m);
|
||||
menu_loop(&m);
|
||||
}
|
||||
|
||||
void enter_stagemenu(MenuData *menu, void *arg) {
|
||||
MenuData m;
|
||||
create_stage_menu(&m);
|
||||
stage_menu_loop(&m);
|
||||
menu_loop(&m);
|
||||
}
|
||||
|
||||
void enter_replayview(MenuData *menu, void *arg) {
|
||||
MenuData m;
|
||||
create_replayview_menu(&m);
|
||||
replayview_menu_loop(&m);
|
||||
menu_loop(&m);
|
||||
}
|
||||
|
||||
void enter_spellpractice(MenuData *menu, void *arg) {
|
||||
MenuData m;
|
||||
create_spell_menu(&m);
|
||||
spell_menu_loop(&m);
|
||||
menu_loop(&m);
|
||||
}
|
||||
|
||||
static MenuEntry *spell_practice_entry;
|
||||
|
@ -60,8 +60,15 @@ void main_menu_update_spellpractice(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void begin_main_menu(MenuData *m) {
|
||||
start_bgm("bgm_menu");
|
||||
set_transition(TransLoader, 0, FADE_TIME*2);
|
||||
}
|
||||
|
||||
void create_main_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->draw = draw_main_menu;
|
||||
m->begin = begin_main_menu;
|
||||
|
||||
add_menu_entry(m, "Start Story", start_game, NULL);
|
||||
add_menu_entry(m, "Start Extra", NULL, NULL);
|
||||
|
@ -71,7 +78,7 @@ void create_main_menu(MenuData *m) {
|
|||
#endif
|
||||
add_menu_entry(m, "Replays", enter_replayview, NULL);
|
||||
add_menu_entry(m, "Options", enter_options, NULL);
|
||||
add_menu_entry(m, "Quit", (MenuAction)kill_menu, m);
|
||||
add_menu_entry(m, "Quit", menu_commonaction_close, NULL)->transition = TransFadeBlack;;
|
||||
|
||||
spell_practice_entry = m->entries + 2;
|
||||
main_menu_update_spellpractice();
|
||||
|
@ -126,8 +133,3 @@ void draw_main_menu(MenuData *menu) {
|
|||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void main_menu_loop(MenuData *menu) {
|
||||
set_transition(TransLoader, -1, FADE_TIME*2);
|
||||
menu_loop(menu, NULL, draw_main_menu, NULL);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
void create_main_menu(MenuData *m);
|
||||
void draw_main_menu_bg(MenuData *m);
|
||||
void draw_main_menu(MenuData *m);
|
||||
void main_menu_loop(MenuData *m);
|
||||
void main_menu_update_spellpractice(void);
|
||||
|
||||
#endif
|
||||
|
|
129
src/menu/menu.c
129
src/menu/menu.c
|
@ -5,40 +5,32 @@
|
|||
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "menu.h"
|
||||
#include "global.h"
|
||||
#include "video.h"
|
||||
|
||||
MenuEntry *add_menu_entry(MenuData *menu, char *name, MenuAction action, void *arg) {
|
||||
return add_menu_entry_f(menu, name, action, arg, 0);
|
||||
}
|
||||
|
||||
MenuEntry *add_menu_entry_f(MenuData *menu, char *name, MenuAction action, void *arg, int flags) {
|
||||
menu->entries = realloc(menu->entries, (++menu->ecount)*sizeof(MenuEntry));
|
||||
MenuEntry *e = &(menu->entries[menu->ecount-1]);
|
||||
MenuEntry *e = menu->entries + menu->ecount - 1;
|
||||
memset(e, 0, sizeof(MenuEntry));
|
||||
|
||||
e->name = malloc(strlen(name)+1);
|
||||
strcpy(e->name, name);
|
||||
stralloc(&e->name, name);
|
||||
e->action = action;
|
||||
e->arg = arg;
|
||||
e->flags = flags;
|
||||
e->transition = menu->transition;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
void add_menu_separator(MenuData *menu) {
|
||||
menu->entries = realloc(menu->entries, (++menu->ecount)*sizeof(MenuEntry));
|
||||
memset(&(menu->entries[menu->ecount-1]), 0, sizeof(MenuEntry));
|
||||
memset(menu->entries + menu->ecount - 1, 0, sizeof(MenuEntry));
|
||||
}
|
||||
|
||||
void destroy_menu(MenuData *menu) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < menu->ecount; i++) {
|
||||
MenuEntry *e = &(menu->entries[i]);
|
||||
|
||||
free(e->name);
|
||||
for(int i = 0; i < menu->ecount; i++) {
|
||||
free(menu->entries[i].name);
|
||||
}
|
||||
|
||||
free(menu->entries);
|
||||
|
@ -48,33 +40,50 @@ void create_menu(MenuData *menu) {
|
|||
memset(menu, 0, sizeof(MenuData));
|
||||
|
||||
menu->selected = -1;
|
||||
menu->quitdelay = FADE_TIME;
|
||||
menu->transition = TransFadeBlack;
|
||||
menu->transition = TransMenu; // TransFadeBlack;
|
||||
menu->transition_in_time = FADE_TIME;
|
||||
menu->transition_out_time = FADE_TIME;
|
||||
menu->fade = 1.0;
|
||||
menu->logic = menu_logic;
|
||||
menu->input = menu_input;
|
||||
}
|
||||
|
||||
void close_menu_finish(MenuData *menu) {
|
||||
menu->state = MS_Dead;
|
||||
|
||||
if(menu->selected != -1 && menu->entries[menu->selected].action != NULL) {
|
||||
if(!(menu->flags & MF_Transient)) {
|
||||
menu->state = MS_Normal;
|
||||
}
|
||||
|
||||
menu->entries[menu->selected].action(menu, menu->entries[menu->selected].arg);
|
||||
}
|
||||
}
|
||||
|
||||
void close_menu(MenuData *menu) {
|
||||
TransitionRule trans = menu->transition;
|
||||
|
||||
if(menu->selected != -1)
|
||||
assert(menu->state != MS_Dead);
|
||||
menu->state = MS_FadeOut;
|
||||
|
||||
if(menu->selected != -1) {
|
||||
trans = menu->entries[menu->selected].transition;
|
||||
}
|
||||
|
||||
set_transition(trans, menu->quitdelay, menu->quitdelay);
|
||||
|
||||
menu->quitframe = menu->frames;
|
||||
}
|
||||
|
||||
void kill_menu(MenuData *menu) {
|
||||
menu->state = MS_Dead;
|
||||
if(trans) {
|
||||
set_transition_callback(
|
||||
trans,
|
||||
menu->transition_in_time,
|
||||
menu->transition_out_time,
|
||||
(TransitionCallback)close_menu_finish, menu
|
||||
);
|
||||
} else {
|
||||
close_menu_finish(menu);
|
||||
}
|
||||
}
|
||||
|
||||
float menu_fade(MenuData *menu) {
|
||||
if(menu->frames < menu->quitdelay)
|
||||
return 1.0 - menu->frames/(float)menu->quitdelay;
|
||||
|
||||
if(menu->quitframe && menu->frames >= menu->quitframe)
|
||||
return (menu->frames - menu->quitframe)/(float)menu->quitdelay;
|
||||
|
||||
return 0.0;
|
||||
return transition.fade;
|
||||
}
|
||||
|
||||
void menu_event(EventType type, int state, void *arg) {
|
||||
|
@ -121,48 +130,44 @@ void menu_input(MenuData *menu) {
|
|||
handle_events(menu_event, EF_Menu, (void*)menu);
|
||||
}
|
||||
|
||||
void menu_logic(MenuData *menu) {
|
||||
menu->frames++;
|
||||
|
||||
if(menu->quitframe && menu->frames >= menu->quitframe)
|
||||
menu->state = MS_FadeOut;
|
||||
|
||||
if(menu->quitframe && menu->frames >= menu->quitframe + menu->quitdelay*!(menu->state & MF_InstantSelect || menu->selected != -1 && menu->entries[menu->selected].flags & MF_InstantSelect)) {
|
||||
menu->state = MS_Dead;
|
||||
if(menu->selected != -1 && menu->entries[menu->selected].action != NULL) {
|
||||
if(!(menu->flags & MF_Transient)) {
|
||||
menu->state = MS_Normal;
|
||||
menu->quitframe = 0;
|
||||
}
|
||||
|
||||
menu->entries[menu->selected].action(menu, menu->entries[menu->selected].arg);
|
||||
}
|
||||
}
|
||||
void menu_no_input(MenuData *menu) {
|
||||
handle_events(NULL, 0, NULL);
|
||||
}
|
||||
|
||||
int menu_loop(MenuData *menu, void (*input)(MenuData*), void (*draw)(MenuData*), void (*end)(MenuData*)) {
|
||||
void menu_logic(MenuData *menu) {
|
||||
menu->frames++;
|
||||
}
|
||||
|
||||
int menu_loop(MenuData *menu) {
|
||||
set_ortho();
|
||||
|
||||
if(menu->begin) {
|
||||
menu->begin(menu);
|
||||
}
|
||||
|
||||
while(menu->state != MS_Dead) {
|
||||
menu_logic(menu);
|
||||
assert(menu->logic);
|
||||
menu->logic(menu);
|
||||
|
||||
if(menu->state != MS_FadeOut || menu->flags & MF_AlwaysProcessInput) {
|
||||
if(input)
|
||||
input(menu);
|
||||
else
|
||||
menu_input(menu);
|
||||
} else handle_events(NULL, 0, NULL);
|
||||
assert(menu->input);
|
||||
menu->input(menu);
|
||||
} else {
|
||||
menu_no_input(menu);
|
||||
}
|
||||
|
||||
draw(menu);
|
||||
if(!(menu->flags & MF_ManualDrawTransition))
|
||||
draw_transition();
|
||||
assert(menu->draw);
|
||||
menu->draw(menu);
|
||||
draw_transition();
|
||||
|
||||
SDL_GL_SwapWindow(video.window);
|
||||
frame_rate(&menu->lasttime);
|
||||
}
|
||||
|
||||
if(end)
|
||||
end(menu);
|
||||
destroy_menu(menu);
|
||||
if(menu->end) {
|
||||
menu->end(menu);
|
||||
}
|
||||
|
||||
destroy_menu(menu);
|
||||
return menu->selected;
|
||||
}
|
||||
|
|
|
@ -23,29 +23,20 @@ typedef struct MenuData MenuData;
|
|||
|
||||
typedef void (*MenuAction)(MenuData*, void*);
|
||||
typedef bool (*MenuCallback)(MenuData*);
|
||||
typedef void (*MenuProc)(MenuData*);
|
||||
|
||||
typedef struct MenuEntry {
|
||||
char *name;
|
||||
MenuAction action;
|
||||
void *arg;
|
||||
|
||||
int flags;
|
||||
|
||||
float drawdata;
|
||||
TransitionRule transition;
|
||||
} MenuEntry;
|
||||
|
||||
// enum EntryFlag {
|
||||
// MF_InstantSelect = 4
|
||||
// };
|
||||
|
||||
enum MenuFlag {
|
||||
MF_Transient = 1, // whether to close on selection or not.
|
||||
MF_Abortable = 2,
|
||||
|
||||
MF_InstantSelect = 4,
|
||||
MF_ManualDrawTransition = 8, // the menu will not call draw_transition() automatically
|
||||
MF_AlwaysProcessInput = 16 // the menu will process input even during fadeouts
|
||||
MF_Transient = 1, // the menu will be automatically closed on selection
|
||||
MF_Abortable = 2, // the menu can be closed with the escape key
|
||||
MF_AlwaysProcessInput = 4 // the menu will process input when it's fading out
|
||||
};
|
||||
|
||||
enum MenuState {
|
||||
|
@ -54,7 +45,7 @@ enum MenuState {
|
|||
MS_Dead
|
||||
};
|
||||
|
||||
struct MenuData{
|
||||
struct MenuData {
|
||||
int flags;
|
||||
|
||||
int cursor;
|
||||
|
@ -67,14 +58,21 @@ struct MenuData{
|
|||
int lasttime;
|
||||
|
||||
int state;
|
||||
int quitframe;
|
||||
int quitdelay;
|
||||
int transition_in_time;
|
||||
int transition_out_time;
|
||||
float fade;
|
||||
|
||||
TransitionRule transition;
|
||||
|
||||
float drawdata[4];
|
||||
|
||||
void *context;
|
||||
|
||||
MenuProc draw;
|
||||
MenuProc input;
|
||||
MenuProc logic;
|
||||
MenuProc begin;
|
||||
MenuProc end;
|
||||
};
|
||||
|
||||
MenuEntry *add_menu_entry(MenuData *menu, char *name, MenuAction action, void *arg);
|
||||
|
@ -86,13 +84,13 @@ void destroy_menu(MenuData *menu);
|
|||
|
||||
void menu_logic(MenuData *menu);
|
||||
void menu_input(MenuData *menu);
|
||||
void menu_no_input(MenuData *menu);
|
||||
|
||||
void close_menu(MenuData *menu); // softly close menu (should be used in most cases)
|
||||
void kill_menu(MenuData *menu); // quit action for persistent menus
|
||||
void close_menu(MenuData *menu);
|
||||
|
||||
void menu_key_action(MenuData *menu, int sym);
|
||||
|
||||
int menu_loop(MenuData *menu, void (*input)(MenuData*), void (*draw)(MenuData*), void (*end)(MenuData*));
|
||||
int menu_loop(MenuData *menu);
|
||||
|
||||
float menu_fade(MenuData *menu);
|
||||
|
||||
|
|
|
@ -281,10 +281,16 @@ void destroy_options_menu(MenuData *m) {
|
|||
|
||||
static void do_nothing(MenuData *menu, void *arg) { }
|
||||
|
||||
void create_options_sub(MenuData *m, char *s) {
|
||||
void options_menu_input(MenuData*);
|
||||
|
||||
void create_options_menu_basic(MenuData *m, char *s) {
|
||||
create_menu(m);
|
||||
m->transition = TransMenuDark;
|
||||
m->flags = MF_Abortable;
|
||||
m->context = s;
|
||||
m->input = options_menu_input;
|
||||
m->draw = draw_options_menu;
|
||||
m->end = destroy_options_menu;
|
||||
}
|
||||
|
||||
#define bind_onoff(b) bind_addvalue(b, "on"); bind_addvalue(b, "off")
|
||||
|
@ -294,7 +300,7 @@ void options_sub_video(MenuData *parent, void *arg) {
|
|||
OptionBinding *b;
|
||||
m = &menu;
|
||||
|
||||
create_options_sub(m, "Video Options");
|
||||
create_options_menu_basic(m, "Video Options");
|
||||
|
||||
add_menu_entry(m, "Resolution", do_nothing,
|
||||
b = bind_resolution()
|
||||
|
@ -332,7 +338,7 @@ void options_sub_video(MenuData *parent, void *arg) {
|
|||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_commonaction_close, NULL);
|
||||
|
||||
options_menu_loop(m);
|
||||
menu_loop(m);
|
||||
parent->frames = 0;
|
||||
}
|
||||
|
||||
|
@ -352,7 +358,7 @@ void options_sub_gamepad_controls(MenuData *parent, void *arg) {
|
|||
MenuData menu, *m;
|
||||
m = &menu;
|
||||
|
||||
create_options_sub(m, "Gamepad Controls");
|
||||
create_options_menu_basic(m, "Gamepad Controls");
|
||||
|
||||
add_menu_entry(m, "Fire / Accept", do_nothing,
|
||||
bind_gpbinding(CONFIG_GAMEPAD_KEY_SHOT)
|
||||
|
@ -397,7 +403,7 @@ void options_sub_gamepad_controls(MenuData *parent, void *arg) {
|
|||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_commonaction_close, NULL);
|
||||
|
||||
options_menu_loop(m);
|
||||
menu_loop(m);
|
||||
parent->frames = 0;
|
||||
gamepad_restart();
|
||||
}
|
||||
|
@ -407,7 +413,7 @@ void options_sub_gamepad(MenuData *parent, void *arg) {
|
|||
OptionBinding *b;
|
||||
m = &menu;
|
||||
|
||||
create_options_sub(m, "Gamepad Options");
|
||||
create_options_menu_basic(m, "Gamepad Options");
|
||||
|
||||
add_menu_entry(m, "Enable Gamepad/Joystick support", do_nothing,
|
||||
b = bind_option(CONFIG_GAMEPAD_ENABLED, bind_common_onoffget, bind_common_onoffset)
|
||||
|
@ -464,7 +470,7 @@ void options_sub_gamepad(MenuData *parent, void *arg) {
|
|||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_commonaction_close, NULL);
|
||||
|
||||
options_menu_loop(m);
|
||||
menu_loop(m);
|
||||
parent->frames = 0;
|
||||
gamepad_restart();
|
||||
}
|
||||
|
@ -473,7 +479,7 @@ void options_sub_controls(MenuData *parent, void *arg) {
|
|||
MenuData menu, *m;
|
||||
m = &menu;
|
||||
|
||||
create_options_sub(m, "Controls");
|
||||
create_options_menu_basic(m, "Controls");
|
||||
|
||||
add_menu_entry(m, "Move up", do_nothing,
|
||||
bind_keybinding(CONFIG_KEY_UP)
|
||||
|
@ -534,16 +540,14 @@ void options_sub_controls(MenuData *parent, void *arg) {
|
|||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_commonaction_close, NULL);
|
||||
|
||||
options_menu_loop(m);
|
||||
menu_loop(m);
|
||||
parent->frames = 0;
|
||||
}
|
||||
|
||||
void create_options_menu(MenuData *m) {
|
||||
OptionBinding *b;
|
||||
|
||||
create_menu(m);
|
||||
m->flags = MF_Abortable;
|
||||
m->context = "Options";
|
||||
create_options_menu_basic(m, "Options");
|
||||
|
||||
add_menu_entry(m, "Player name", do_nothing,
|
||||
b = bind_stroption(CONFIG_PLAYERNAME)
|
||||
|
@ -943,8 +947,3 @@ void options_menu_input(MenuData *menu) {
|
|||
} else
|
||||
handle_events(options_input_event, EF_Menu, menu);
|
||||
}
|
||||
|
||||
int options_menu_loop(MenuData *menu) {
|
||||
return menu_loop(menu, options_menu_input, draw_options_menu, destroy_options_menu);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
#include "menu.h"
|
||||
|
||||
void create_options_menu(MenuData *m);
|
||||
|
||||
void draw_options_menu(MenuData *m);
|
||||
int options_menu_loop(MenuData *m);
|
||||
|
||||
#define OPTIONS_TEXT_INPUT_BUFSIZE 50
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
typedef struct ReplayviewContext {
|
||||
MenuData *submenu;
|
||||
int pickedstage;
|
||||
double sub_fade;
|
||||
} ReplayviewContext;
|
||||
|
||||
// Type of MenuEntry.arg (which should be renamed to context, probably...)
|
||||
|
@ -44,14 +45,17 @@ void start_replay(MenuData *menu, void *arg) {
|
|||
start_bgm("bgm_menu");
|
||||
}
|
||||
|
||||
static void replayview_draw_stagemenu(MenuData*);
|
||||
|
||||
MenuData* replayview_sub_stageselect(MenuData *menu, ReplayviewItemContext *ictx) {
|
||||
MenuData *m = malloc(sizeof(MenuData));
|
||||
Replay *rpy = ictx->replay;
|
||||
|
||||
create_menu(m);
|
||||
m->draw = replayview_draw_stagemenu;
|
||||
m->context = menu->context;
|
||||
m->flags = MF_Transient | MF_Abortable;
|
||||
m->transition = 0;
|
||||
m->transition = NULL;
|
||||
|
||||
for(int i = 0; i < rpy->numstages; ++i) {
|
||||
add_menu_entry(m, stage_get(rpy->stages[i].stage)->title, start_replay, ictx)->transition = TransFadeBlack;
|
||||
|
@ -99,7 +103,7 @@ static void replayview_draw_stagemenu(MenuData *m) {
|
|||
// this context is shared with the parent menu
|
||||
ReplayviewContext *ctx = m->context;
|
||||
|
||||
float alpha = 1-menu_fade(m);
|
||||
float alpha = 1 - ctx->sub_fade;
|
||||
int i;
|
||||
|
||||
float height = (1+m->ecount) * 20;
|
||||
|
@ -209,6 +213,26 @@ static void replayview_drawitem(void *n, int item, int cnt) {
|
|||
}
|
||||
}
|
||||
|
||||
static void replayview_logic(MenuData *m) {
|
||||
ReplayviewContext *ctx = m->context;
|
||||
|
||||
if(ctx->submenu) {
|
||||
MenuData *sm = ctx->submenu;
|
||||
|
||||
if(sm->state == MS_Dead) {
|
||||
if(ctx->sub_fade == 1.0) {
|
||||
destroy_menu(sm);
|
||||
ctx->submenu = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->sub_fade = approach(ctx->sub_fade, 1.0, 1.0/FADE_TIME);
|
||||
} else {
|
||||
ctx->sub_fade = approach(ctx->sub_fade, 0.0, 1.0/FADE_TIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void replayview_draw(MenuData *m) {
|
||||
ReplayviewContext *ctx = m->context;
|
||||
|
||||
|
@ -222,14 +246,7 @@ static void replayview_draw(MenuData *m) {
|
|||
draw_menu_list(m, 100, 100, replayview_drawitem);
|
||||
|
||||
if(ctx->submenu) {
|
||||
MenuData *sm = ctx->submenu;
|
||||
menu_logic(sm);
|
||||
if(sm->state == MS_Dead) {
|
||||
destroy_menu(sm);
|
||||
ctx->submenu = NULL;
|
||||
} else {
|
||||
replayview_draw_stagemenu(sm);
|
||||
}
|
||||
ctx->submenu->draw(ctx->submenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,7 +290,7 @@ int fill_replayview_menu(MenuData *m) {
|
|||
ictx->replayname = malloc(strlen(e->d_name) + 1);
|
||||
strcpy(ictx->replayname, e->d_name);
|
||||
|
||||
add_menu_entry_f(m, " ", replayview_run, ictx, (rpy->numstages > 1)*MF_InstantSelect)->transition = rpy->numstages < 2 ? TransFadeBlack : NULL;
|
||||
add_menu_entry(m, " ", replayview_run, ictx)->transition = rpy->numstages < 2 ? TransFadeBlack : NULL;
|
||||
++rpys;
|
||||
}
|
||||
|
||||
|
@ -282,8 +299,41 @@ int fill_replayview_menu(MenuData *m) {
|
|||
return rpys;
|
||||
}
|
||||
|
||||
void replayview_menu_input(MenuData *m) {
|
||||
ReplayviewContext *ctx = (ReplayviewContext*)m->context;
|
||||
MenuData *sub = ctx->submenu;
|
||||
|
||||
if(transition.state == TRANS_FADE_IN) {
|
||||
menu_no_input(m);
|
||||
} else {
|
||||
if(sub && sub->state != MS_Dead) {
|
||||
sub->input(sub);
|
||||
} else {
|
||||
menu_input(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void replayview_free(MenuData *m) {
|
||||
if(m->context) {
|
||||
free(m->context);
|
||||
m->context = NULL;
|
||||
}
|
||||
|
||||
for(int i = 0; i < m->ecount; i++) {
|
||||
if(m->entries[i].action == replayview_run) {
|
||||
replayview_freearg(m->entries[i].arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void create_replayview_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->logic = replayview_logic;
|
||||
m->input = replayview_menu_input;
|
||||
m->draw = replayview_draw;
|
||||
m->end = replayview_free;
|
||||
m->transition = TransMenuDark;
|
||||
|
||||
ReplayviewContext *ctx = malloc(sizeof(ReplayviewContext));
|
||||
memset(ctx, 0, sizeof(ReplayviewContext));
|
||||
|
@ -302,26 +352,3 @@ void create_replayview_menu(MenuData *m) {
|
|||
add_menu_entry(m, "Back", menu_commonaction_close, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void replayview_menu_input(MenuData *m) {
|
||||
ReplayviewContext *ctx = (ReplayviewContext*)m->context;
|
||||
menu_input(ctx->submenu ? ctx->submenu : m);
|
||||
}
|
||||
|
||||
void replayview_free(MenuData *m) {
|
||||
if(m->context) {
|
||||
free(m->context);
|
||||
m->context = NULL;
|
||||
}
|
||||
|
||||
for(int i = 0; i < m->ecount; i++) {
|
||||
if(m->entries[i].action == replayview_run) {
|
||||
replayview_freearg(m->entries[i].arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int replayview_menu_loop(MenuData *m) {
|
||||
return menu_loop(m, replayview_menu_input, replayview_draw, replayview_free);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#ifndef RPYVIEW_H
|
||||
#define RPYVIEW_H
|
||||
|
||||
#include "menu.h"
|
||||
|
||||
void create_replayview_menu(MenuData *m);
|
||||
int replayview_menu_loop(MenuData *m);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,15 +38,6 @@ void save_rpy(MenuData *menu, void *a) {
|
|||
replay_save(rpy, name);
|
||||
}
|
||||
|
||||
void create_saverpy_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
|
||||
m->flags = MF_Transient;
|
||||
|
||||
add_menu_entry(m, "Yes", save_rpy, m);
|
||||
add_menu_entry(m, "No", (MenuAction) kill_menu, m);
|
||||
}
|
||||
|
||||
void draw_saverpy_menu(MenuData *m) {
|
||||
int i;
|
||||
|
||||
|
@ -95,6 +86,13 @@ void saverpy_menu_input(MenuData *menu) {
|
|||
handle_events(saverpy_input_event, EF_Menu, menu);
|
||||
}
|
||||
|
||||
int saverpy_menu_loop(MenuData *m) {
|
||||
return menu_loop(m, saverpy_menu_input, draw_saverpy_menu, NULL);
|
||||
void create_saverpy_menu(MenuData *m) {
|
||||
create_menu(m);
|
||||
m->input = saverpy_menu_input;
|
||||
m->draw = draw_saverpy_menu;
|
||||
|
||||
m->flags = MF_Transient;
|
||||
|
||||
add_menu_entry(m, "Yes", save_rpy, NULL);
|
||||
add_menu_entry(m, "No", menu_commonaction_close, NULL);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,5 @@
|
|||
|
||||
void save_rpy(MenuData *menu, void*);
|
||||
void create_saverpy_menu(MenuData*);
|
||||
int saverpy_menu_loop(MenuData*);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,12 +10,21 @@
|
|||
#include "options.h"
|
||||
#include "global.h"
|
||||
|
||||
void draw_spell_menu(MenuData *m) {
|
||||
draw_options_menu_bg(m);
|
||||
draw_menu_title(m, "Spell Practice");
|
||||
animate_menu_list(m);
|
||||
draw_menu_list(m, 100, 100, NULL);
|
||||
}
|
||||
|
||||
void create_spell_menu(MenuData *m) {
|
||||
char title[128];
|
||||
Difficulty lastdiff = D_Any;
|
||||
|
||||
create_menu(m);
|
||||
m->draw = draw_spell_menu;
|
||||
m->flags = MF_Abortable;
|
||||
m->transition = TransMenuDark;
|
||||
|
||||
for(StageInfo *stg = stages; stg->loop; ++stg) {
|
||||
if(stg->type != STAGE_SPELL) {
|
||||
|
@ -45,14 +54,3 @@ void create_spell_menu(MenuData *m) {
|
|||
++m->cursor;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_spell_menu(MenuData *m) {
|
||||
draw_options_menu_bg(m);
|
||||
draw_menu_title(m, "Spell Practice");
|
||||
animate_menu_list(m);
|
||||
draw_menu_list(m, 100, 100, NULL);
|
||||
}
|
||||
|
||||
int spell_menu_loop(MenuData *m) {
|
||||
return menu_loop(m, NULL, draw_spell_menu, NULL);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,5 @@
|
|||
#include "menu.h"
|
||||
|
||||
void create_spell_menu(MenuData *m);
|
||||
int spell_menu_loop(MenuData *m);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,12 +13,21 @@
|
|||
#include "stageselect.h"
|
||||
#include "common.h"
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void create_stage_menu(MenuData *m) {
|
||||
char title[STGMENU_MAX_TITLE_LENGTH];
|
||||
Difficulty lastdiff = D_Any;
|
||||
|
||||
create_menu(m);
|
||||
m->draw = draw_stage_menu;
|
||||
m->flags = MF_Abortable;
|
||||
m->transition = TransMenuDark;
|
||||
|
||||
for(int i = 0; stages[i].loop; ++i) {
|
||||
if(stages[i].difficulty < lastdiff || (stages[i].difficulty && !lastdiff)) {
|
||||
|
@ -34,14 +43,3 @@ void create_stage_menu(MenuData *m) {
|
|||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_commonaction_close, NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int stage_menu_loop(MenuData *m) {
|
||||
return menu_loop(m, NULL, draw_stage_menu, NULL);
|
||||
}
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
#ifndef STGMENU_H
|
||||
#define STGMENU_H
|
||||
|
||||
#include "menu.h"
|
||||
|
||||
#define STGMENU_MAX_TITLE_LENGTH 128
|
||||
|
||||
void create_stage_menu(MenuData *m);
|
||||
int stage_menu_loop(MenuData *m);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,6 +49,9 @@ int init_mixer_if_needed(void) {
|
|||
warnx("Mix_OpenAudio(): %s.\n", Mix_GetError());
|
||||
}
|
||||
|
||||
set_sfx_volume(config_get_float(CONFIG_SFX_VOLUME));
|
||||
set_bgm_volume(config_get_float(CONFIG_BGM_VOLUME));
|
||||
|
||||
mixer_loaded = 1;
|
||||
return 1;
|
||||
}
|
||||
|
@ -86,7 +89,7 @@ int init_sfx(void)
|
|||
|
||||
if (config_get_int(CONFIG_NO_AUDIO)) return 1;
|
||||
if (!init_mixer_if_needed()) return 0;
|
||||
|
||||
|
||||
int channels = Mix_AllocateChannels(SNDCHAN_COUNT);
|
||||
if (!channels)
|
||||
{
|
||||
|
@ -96,7 +99,7 @@ int init_sfx(void)
|
|||
return 0;
|
||||
}
|
||||
if (channels < SNDCHAN_COUNT) warnx("init_sfx(): allocated only %d of %d channels.\n", channels, SNDCHAN_COUNT);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -324,16 +324,16 @@ void stage_pause(void) {
|
|||
MenuData menu;
|
||||
stop_bgm();
|
||||
create_ingame_menu(&menu);
|
||||
ingame_menu_loop(&menu);
|
||||
menu_loop(&menu);
|
||||
continue_bgm();
|
||||
}
|
||||
|
||||
void stage_gameover(void) {
|
||||
MenuData m;
|
||||
MenuData menu;
|
||||
save_bgm();
|
||||
start_bgm("bgm_gameover");
|
||||
create_gameover_menu(&m);
|
||||
ingame_menu_loop(&m);
|
||||
create_gameover_menu(&menu);
|
||||
menu_loop(&menu);
|
||||
restore_bgm();
|
||||
}
|
||||
|
||||
|
|
118
src/transition.c
118
src/transition.c
|
@ -9,48 +9,120 @@
|
|||
#include "menu/ingamemenu.h"
|
||||
#include "global.h"
|
||||
|
||||
static Transition transition;
|
||||
|
||||
float trans_fade(Transition *t) {
|
||||
if(t->frames <= t->dur1)
|
||||
return t->frames/(float)t->dur1;
|
||||
else
|
||||
return (t->dur1+t->dur2-t->frames)/(float)t->dur2;
|
||||
}
|
||||
Transition transition;
|
||||
|
||||
void TransFadeBlack(Transition *t) {
|
||||
fade_out(trans_fade(t));
|
||||
fade_out(t->fade);
|
||||
}
|
||||
|
||||
void TransFadeWhite(Transition *t) {
|
||||
colorfill(1,1,1,trans_fade(t));
|
||||
colorfill(1,1,1,t->fade);
|
||||
}
|
||||
|
||||
void TransLoader(Transition *t) {
|
||||
glColor4f(1,1,1,trans_fade(t));
|
||||
glColor4f(1,1,1,t->fade);
|
||||
draw_texture(SCREEN_W/2,SCREEN_H/2,"loading");
|
||||
glColor4f(1,1,1,1);
|
||||
}
|
||||
|
||||
void set_transition(TransitionRule rule, int dur1, int dur2) {
|
||||
if(!rule)
|
||||
return;
|
||||
void TransMenu(Transition *t) {
|
||||
glColor4f(1,1,1,t->fade);
|
||||
draw_texture(SCREEN_W/2, SCREEN_H/2, "mainmenu/mainmenubg");
|
||||
glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
memset(&transition, 0, sizeof(Transition));
|
||||
transition.rule = rule;
|
||||
transition.dur1 = dur1;
|
||||
transition.dur2 = dur2;
|
||||
void TransMenuDark(Transition *t) {
|
||||
glColor4f(0.3,0.3,0.3,t->fade);
|
||||
draw_texture(SCREEN_W/2, SCREEN_H/2, "mainmenu/mainmenubg");
|
||||
glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
void TransEmpty(Transition *t) { }
|
||||
|
||||
static bool popq(void) {
|
||||
if(transition.queued.rule) {
|
||||
transition.rule = transition.queued.rule;
|
||||
transition.dur1 = transition.queued.dur1;
|
||||
transition.dur2 = transition.queued.dur2;
|
||||
transition.callback = transition.queued.callback;
|
||||
transition.arg = transition.queued.arg;
|
||||
transition.queued.rule = NULL;
|
||||
|
||||
if(transition.dur1 <= 0) {
|
||||
transition.fade = 1.0;
|
||||
transition.state = TRANS_FADE_OUT;
|
||||
} else {
|
||||
transition.state = TRANS_FADE_IN;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void setq(TransitionRule rule, int dur1, int dur2, TransitionCallback cb, void *arg) {
|
||||
transition.queued.rule = rule;
|
||||
transition.queued.dur1 = dur1;
|
||||
transition.queued.dur2 = dur2;
|
||||
transition.queued.callback = cb;
|
||||
transition.queued.arg = arg;
|
||||
}
|
||||
|
||||
static void call_callback(void) {
|
||||
if(transition.callback) {
|
||||
transition.callback(transition.arg);
|
||||
transition.callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void set_transition_callback(TransitionRule rule, int dur1, int dur2, TransitionCallback cb, void *arg) {
|
||||
static bool initialized = false;
|
||||
|
||||
if(!rule) {
|
||||
return;
|
||||
}
|
||||
|
||||
setq(rule, dur1, dur2, cb, arg);
|
||||
|
||||
if(!initialized) {
|
||||
popq();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if(transition.state == TRANS_IDLE || rule == transition.rule) {
|
||||
popq();
|
||||
}
|
||||
}
|
||||
|
||||
void set_transition(TransitionRule rule, int dur1, int dur2) {
|
||||
set_transition_callback(rule, dur1, dur2, NULL, NULL);
|
||||
}
|
||||
|
||||
void draw_transition(void) {
|
||||
if(!transition.rule)
|
||||
if(transition.state == TRANS_IDLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!transition.rule) {
|
||||
transition.state = TRANS_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
transition.rule(&transition);
|
||||
|
||||
transition.frames++;
|
||||
|
||||
if(transition.frames > transition.dur1 + transition.dur2)
|
||||
memset(&transition, 0, sizeof(Transition));
|
||||
if(transition.state == TRANS_FADE_IN) {
|
||||
transition.fade = approach(transition.fade, 1.0, 1.0/transition.dur1);
|
||||
if(transition.fade == 1.0) {
|
||||
transition.state = TRANS_FADE_OUT;
|
||||
call_callback();
|
||||
}
|
||||
} else if(transition.state == TRANS_FADE_OUT) {
|
||||
transition.fade = transition.dur2 ? approach(transition.fade, 0.0, 1.0/transition.dur2) : 0.0;
|
||||
if(transition.fade == 0.0) {
|
||||
transition.state = TRANS_IDLE;
|
||||
popq();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,22 +8,47 @@
|
|||
#ifndef TRANSITION_H
|
||||
#define TRANSITION_H
|
||||
|
||||
#include <stdbool.h>
|
||||