| @@ -108,30 +108,3 @@ int nes_cart_init_file(nes_cart* cart, FILE* file) { | |||
| return status; | |||
| } | |||
| FILE* nes_load_cart(nes_cart* cart, const char* cart_filename) { | |||
| int status = 0; | |||
| FILE* cart_file = fopen(cart_filename, "rb"); | |||
| if (NULL == cart_file) { | |||
| status = -1; | |||
| fprintf(stderr, "Could not open %s\n", cart_filename); | |||
| } | |||
| if (status == 0) { | |||
| status = nes_cart_init_file(cart, cart_file); | |||
| } | |||
| if (status == 0) { | |||
| // Failure might mean there's nothing to load | |||
| load_sram(cart, cart_filename); | |||
| } | |||
| if (status != 0 && NULL != cart_file) { | |||
| fclose(cart_file); | |||
| cart_file = NULL; | |||
| } | |||
| return cart_file; | |||
| } | |||
| @@ -28,7 +28,5 @@ int nes_cart_init_file(nes_cart*, FILE* file); | |||
| int nes_cart_init_mem(nes_cart*, void*, int len); | |||
| void nes_cart_done(nes_cart*); | |||
| FILE* nes_load_cart(nes_cart* cart, const char* cart_filename); | |||
| #endif // NES_CART_H_ | |||
| @@ -9,12 +9,13 @@ | |||
| typedef enum { | |||
| input_Result_Error = -1, | |||
| input_Result_OK = 0, | |||
| input_Result_Quit = 1, | |||
| input_Result_Reset = 2, | |||
| input_Result_Save = 3, | |||
| input_Result_Load = 4, | |||
| input_Result_Cancel = 5, | |||
| input_Result_OK, | |||
| input_Result_Quit, | |||
| input_Result_Menu, | |||
| input_Result_Reset, | |||
| input_Result_Save, | |||
| input_Result_Load, | |||
| input_Result_Cancel, | |||
| } nes_Input_Result; | |||
| #define nes_controller_num_buttons (8U) | |||
| @@ -66,7 +66,6 @@ static void nes_irq(void* sys, int active) { | |||
| int nes_init(nes* sys, int audio_freq) { | |||
| e6502_init(&sys->cpu, (e6502_Read*)nes_mem_read, | |||
| (e6502_Write*)nes_mem_write, sys); | |||
| nes_map_set_irq(sys->cart.mapper, nes_irq, sys); | |||
| nes_ppu_init(&sys->ppu, &sys->cart); | |||
| return nes_apu_init( | |||
| &sys->apu, | |||
| @@ -77,6 +76,18 @@ int nes_init(nes* sys, int audio_freq) { | |||
| ); | |||
| } | |||
| void nes_done(nes* sys) { | |||
| nes_cart_done(&sys->cart); | |||
| nes_apu_done(&sys->apu); | |||
| } | |||
| int nes_setup_cart(nes* sys) { | |||
| nes_map_set_irq(sys->cart.mapper, nes_irq, sys); | |||
| sys->ppu.mapper = sys->cart.mapper; | |||
| nes_reset(sys); | |||
| return 0; | |||
| } | |||
| void nes_reset(nes* sys) { | |||
| e6502_reset(&sys->cpu); | |||
| nes_ppu_reset(&sys->ppu); | |||
| @@ -58,6 +58,10 @@ void nes_mem_write(nes*, uint16_t addr, uint8_t); | |||
| int nes_init(nes*, int audio_freq); | |||
| void nes_done(nes*); | |||
| int nes_setup_cart(nes*); | |||
| void nes_reset(nes*); | |||
| nes_ppu_Result nes_step(nes*, int* run); | |||
| @@ -22,7 +22,32 @@ extern nes_Input_Reader sdl_input; | |||
| extern nes_Audio_Stream sdl_audio; | |||
| static nes sys = {0}; | |||
| static FILE* nes_load_cart(nes_cart* cart, | |||
| const char* cart_filename) { | |||
| int status = 0; | |||
| FILE* cart_file = fopen(cart_filename, "rb"); | |||
| if (NULL == cart_file) { | |||
| status = -1; | |||
| fprintf(stderr, "Could not open %s\n", cart_filename); | |||
| } | |||
| if (status == 0) { | |||
| status = nes_cart_init_file(cart, cart_file); | |||
| } | |||
| if (status == 0) { | |||
| // Failure might mean there's nothing to load | |||
| load_sram(cart, cart_filename); | |||
| } | |||
| if (status != 0 && NULL != cart_file) { | |||
| fclose(cart_file); | |||
| cart_file = NULL; | |||
| } | |||
| return cart_file; | |||
| } | |||
| typedef struct { | |||
| @@ -32,7 +57,7 @@ typedef struct { | |||
| int mode; | |||
| } loadsave_state; | |||
| void loadsave_start(loadsave_state* loadsave, int mode) { | |||
| static void loadsave_start(loadsave_state* loadsave, int mode) { | |||
| if (0 != loadsave->mode) { | |||
| // We can't do two things at once. | |||
| overlay_clear_message(loadsave->overlay, loadsave->id); | |||
| @@ -54,18 +79,15 @@ void loadsave_start(loadsave_state* loadsave, int mode) { | |||
| } | |||
| } | |||
| int loadsave_tick(loadsave_state* loadsave) { | |||
| static int loadsave_tick(loadsave_state* loadsave) { | |||
| int action = 0; | |||
| if (loadsave->mode != 0 && --loadsave->timer <= 0) { | |||
| const char *op = NULL; | |||
| if (input_Result_Load == loadsave->mode) { | |||
| //load_state(&sys, cart_filename); | |||
| op = "restored"; | |||
| } else if (input_Result_Save == loadsave->mode) { | |||
| //save_state(&sys, cart_filename); | |||
| op = "saved"; | |||
| } | |||
| @@ -84,73 +106,138 @@ int loadsave_tick(loadsave_state* loadsave) { | |||
| return action; | |||
| } | |||
| typedef struct { | |||
| char* filename; | |||
| FILE* file; | |||
| } cart_info; | |||
| int main(int argc, char* argv[]) { | |||
| int status = 0; | |||
| nes_Renderer* rend = &sdl_renderer; | |||
| if (status == 0) { | |||
| status = nes_render_init(rend); | |||
| } | |||
| nes_Input_Reader* input = &sdl_input; | |||
| if (status == 0) { | |||
| status = nes_input_init(input); | |||
| } | |||
| nes_Audio_Stream* audio = &sdl_audio; | |||
| if (status == 0) { | |||
| status = nes_audio_init(audio, audio_freq); | |||
| } | |||
| static void cleanup_cart_info(cart_info* cart) { | |||
| if (cart->file) fclose(cart->file); | |||
| free(cart->filename); | |||
| } | |||
| char* cart_filename = NULL; | |||
| FILE* cart_file = NULL; | |||
| if (0 == status && argc > 1) { | |||
| cart_filename = strdup(argv[1]); | |||
| cart_file = nes_load_cart(&sys.cart, argv[1]); | |||
| } | |||
| static int select_rom(menu_state* menu, nes_Renderer* rend, | |||
| nes_Input_Reader* input, nes* sys, | |||
| cart_info* cur_cart) { | |||
| int status = 0; | |||
| cart_info cart = {0}; | |||
| nes_cart new_cart = {0}; | |||
| menu_state menu = {0}; | |||
| while (0 == status && NULL == cart_file) { | |||
| while (0 == status && NULL == cart.file) { | |||
| // Display a load failure message? | |||
| if (NULL != cart_filename) { | |||
| if (NULL != cart.filename) { | |||
| char message[1024]; | |||
| snprintf(message, sizeof(message) - 1, | |||
| "Could not load\n%s", cart_filename); | |||
| int button = modal_popup(message, rend, input, &sys); | |||
| "Could not load\n%s", cart.filename); | |||
| int button = modal_popup(message, rend, input, sys); | |||
| if (input_Result_Quit == (button >> 8)) { | |||
| // Program closed inside modal | |||
| status = -1; | |||
| status = input_Result_Quit; | |||
| } | |||
| } | |||
| if (0 == status) { | |||
| // If we didn't launch with a file, run the loader | |||
| cart_filename = run_main_menu(&menu, rend, | |||
| input, &sys); | |||
| cart.filename = run_main_menu(menu, rend, | |||
| input, sys); | |||
| if (NULL == cart_filename) { | |||
| if ( NULL == cart.filename || | |||
| (char*)-1 == cart.filename ) { | |||
| // This means that we dumped out of the loader | |||
| cart.filename = NULL; | |||
| status = -1; | |||
| } else { | |||
| cart_file = nes_load_cart(&sys.cart, | |||
| cart_filename); | |||
| cart.file = nes_load_cart(&new_cart, | |||
| cart.filename); | |||
| } | |||
| } | |||
| } | |||
| if (0 == status && NULL != cart.file) { | |||
| save_sram(&sys->cart, cur_cart->filename); | |||
| nes_cart_done(&sys->cart); | |||
| cleanup_cart_info(cur_cart); | |||
| sys->cart = new_cart; | |||
| *cur_cart = cart; | |||
| nes_setup_cart(sys); | |||
| } | |||
| return status; | |||
| } | |||
| static int do_game_menu(menu_state* state, nes_Renderer* rend, | |||
| nes_Input_Reader* input, nes* sys, | |||
| cart_info* cart) { | |||
| int status = 0; | |||
| menu_state rom_menu = {0}; | |||
| while (1) { | |||
| status = run_game_menu(state, rend, input, sys); | |||
| if (input_Result_Menu == status) { | |||
| status = select_rom(&rom_menu, rend, input, | |||
| sys, cart); | |||
| if (input_Result_Cancel == status) { | |||
| continue; | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| return status; | |||
| } | |||
| int main(int argc, char* argv[]) { | |||
| int status = 0; | |||
| nes_Renderer* rend = &sdl_renderer; | |||
| if (status == 0) { | |||
| status = nes_render_init(rend); | |||
| } | |||
| nes_Input_Reader* input = &sdl_input; | |||
| if (status == 0) { | |||
| status = nes_input_init(input); | |||
| } | |||
| nes_Audio_Stream* audio = &sdl_audio; | |||
| if (status == 0) { | |||
| status = nes_audio_init(audio, audio_freq); | |||
| } | |||
| nes sys = {0}; | |||
| if (status == 0) { | |||
| status = nes_init(&sys, audio_freq); | |||
| } | |||
| cart_info cart = {0}; | |||
| if (0 == status && argc > 1) { | |||
| cart.filename = strdup(argv[1]); | |||
| cart.file = nes_load_cart(&sys.cart, cart.filename); | |||
| if (NULL != cart.file) { | |||
| nes_setup_cart(&sys); | |||
| } | |||
| } | |||
| menu_state main_menu = {0}; | |||
| if (0 == status && NULL == cart.file) { | |||
| status = select_rom(&main_menu, rend, input, | |||
| &sys, &cart); | |||
| } | |||
| if (status == 0) { | |||
| menu_state game_menu = {0}; | |||
| loadsave_state loadsave = { | |||
| .overlay = &rend->overlay, | |||
| }; | |||
| nes_reset(&sys); | |||
| nes_render(rend, &sys.ppu); | |||
| time_us t_target = time_now(); | |||
| @@ -170,9 +257,9 @@ int main(int argc, char* argv[]) { | |||
| // Load/Save Operations | |||
| int action = loadsave_tick(&loadsave); | |||
| if (input_Result_Load == action) { | |||
| load_state(&sys, cart_filename); | |||
| load_state(&sys, cart.filename); | |||
| } else if (input_Result_Save == action) { | |||
| save_state(&sys, cart_filename); | |||
| save_state(&sys, cart.filename); | |||
| } | |||
| // Sleep to catch up to master clock | |||
| @@ -197,6 +284,20 @@ int main(int argc, char* argv[]) { | |||
| // Update button states every rendered frame | |||
| status = nes_input_update(input, &sys.input); | |||
| if (input_Result_Menu == status) { | |||
| status = do_game_menu( | |||
| &game_menu, rend, | |||
| input, &sys, &cart | |||
| ); | |||
| if ( input_Result_Load == status || | |||
| input_Result_Save == status) { | |||
| loadsave.mode = status; | |||
| loadsave.timer = 0; | |||
| status = 0; | |||
| } | |||
| // Allow other options to fall through | |||
| } | |||
| if (input_Result_Reset == status) { | |||
| overlay_add_message( | |||
| &rend->overlay, | |||
| @@ -239,11 +340,15 @@ int main(int argc, char* argv[]) { | |||
| status == 0 ? "OK" : "Halted"); | |||
| // Failure might mean there's nothing to save | |||
| save_sram(&sys.cart, cart_filename); | |||
| save_sram(&sys.cart, cart.filename); | |||
| } | |||
| if (NULL != cart_file) fclose(cart_file); | |||
| free(cart_filename); | |||
| nes_done(&sys); | |||
| cleanup_cart_info(&cart); | |||
| nes_audio_done(audio); | |||
| nes_input_done(input); | |||
| nes_render_done(rend); | |||
| return status; | |||
| } | |||
| @@ -10,7 +10,7 @@ typedef struct nes_Renderer_t { | |||
| void (*done)(struct nes_Renderer_t*); | |||
| int (*render)(struct nes_Renderer_t*, nes_ppu*); | |||
| void (*draw_last_frame)(struct nes_Renderer_t*); | |||
| void (*draw_last_frame)(struct nes_Renderer_t*, int dim); | |||
| void (*draw_text)(struct nes_Renderer_t*, const char*, int x, int y); | |||
| void (*text_size)(struct nes_Renderer_t*, const char*, int* w, int* h); | |||
| void (*draw_done)(struct nes_Renderer_t*); | |||
| @@ -31,8 +31,9 @@ static inline int nes_render(nes_Renderer* rend, nes_ppu* ppu) { | |||
| return rend->render(rend, ppu); | |||
| } | |||
| static inline void nes_draw_last_frame(nes_Renderer* rend) { | |||
| rend->draw_last_frame(rend); | |||
| static inline void nes_draw_last_frame(nes_Renderer* rend, | |||
| int dim) { | |||
| rend->draw_last_frame(rend, dim); | |||
| } | |||
| static inline void nes_text_size(nes_Renderer* rend, | |||
| @@ -37,16 +37,18 @@ int load_sram(nes_cart* cart, const char* cart_filename) { | |||
| int save_sram(const nes_cart* cart, const char* cart_filename) { | |||
| int status = -1; | |||
| int sram_size = cart->mapper->sram_size ? | |||
| cart->mapper->sram_size(cart->mapper) : 0; | |||
| const void* sram = cart->mapper->sram ? | |||
| cart->mapper->sram(cart->mapper) : NULL; | |||
| if (sram_size > 0 && NULL != sram) { | |||
| char sram_filename[FILENAME_MAX] = {0}; | |||
| make_sram_filename(sram_filename, FILENAME_MAX - 1, | |||
| cart_filename); | |||
| status = write_file(sram_filename, sram, sram_size); | |||
| if (NULL != cart->mapper) { | |||
| int sram_size = cart->mapper->sram_size ? | |||
| cart->mapper->sram_size(cart->mapper) : 0; | |||
| const void* sram = cart->mapper->sram ? | |||
| cart->mapper->sram(cart->mapper) : NULL; | |||
| if (sram_size > 0 && NULL != sram) { | |||
| char sram_filename[FILENAME_MAX] = {0}; | |||
| make_sram_filename(sram_filename, FILENAME_MAX - 1, | |||
| cart_filename); | |||
| status = write_file(sram_filename, sram, sram_size); | |||
| } | |||
| } | |||
| return status; | |||
| @@ -53,7 +53,7 @@ static void sdl_input_done(nes_Input_Reader* input) { | |||
| sdl_lose_gamepad(input->data); | |||
| } | |||
| static const int sdl_reset_key = SDLK_ESCAPE; | |||
| static const int sdl_menu_key = SDLK_ESCAPE; | |||
| static const int sdl_save_key = SDLK_F1; | |||
| static const int sdl_load_key = SDLK_F2; | |||
| @@ -111,9 +111,9 @@ static int sdl_input_update(nes_Input_Reader* reader, | |||
| input->controllers[0].buttons &= ~mask; | |||
| } | |||
| } else if ( sdl_reset_key == event.key.keysym.sym && | |||
| } else if ( sdl_menu_key == event.key.keysym.sym && | |||
| SDL_KEYDOWN == event.type) { | |||
| status = input_Result_Reset; | |||
| status = input_Result_Menu; | |||
| } else if (sdl_save_key == event.key.keysym.sym) { | |||
| if (SDL_KEYDOWN == event.type) { | |||
| @@ -22,7 +22,7 @@ static int get_input(nes_Input_Reader* reader, | |||
| } | |||
| static int wait_for_input(nes_Input_Reader* reader, | |||
| nes_input* input) { | |||
| nes_input* input) { | |||
| int buttons = input->controllers[0].buttons; | |||
| int status = 0; | |||
| for ( ; | |||
| @@ -95,16 +95,21 @@ static void fix_filename(char* dst, int n, const char* src) { | |||
| } | |||
| static inline int n_visible(void) { | |||
| return (((nes_ppu_render_h - 30) - 1) / 11) - 1; | |||
| return ((nes_ppu_render_h - 20) / 11); | |||
| } | |||
| static void show_menu(const menu_state* menu, | |||
| nes_Renderer* rend, file_list* files) { | |||
| nes_draw_last_frame(rend); | |||
| static void show_menu(const menu_state* menu, int dim, int x, | |||
| nes_Renderer* rend, | |||
| const file_list* files) { | |||
| nes_draw_last_frame(rend, dim); | |||
| int bottom = menu->top + n_visible(); | |||
| int bottom = menu->top + n_visible() - 1; | |||
| for ( int n = menu->top, y = 10; | |||
| int max = n_visible(); | |||
| if (max > files->count) max = files->count; | |||
| int y = (nes_ppu_render_h - (max * 11)) / 2; | |||
| for ( int n = menu->top; | |||
| n < files->count && n <= bottom; | |||
| ++n, y += 11 ) { | |||
| char filename[100]; | |||
| @@ -115,13 +120,73 @@ static void show_menu(const menu_state* menu, | |||
| ( (menu->top == n && 0 != menu->top) || | |||
| (bottom == n && files->count - 1 > bottom) ) ? | |||
| "..." : filename, | |||
| 20, y); | |||
| if (menu->cursor == n) nes_draw_text(rend, ">", 10, y); | |||
| x, y); | |||
| if (menu->cursor == n) { | |||
| nes_draw_text(rend, ">", x - 10, y); | |||
| } | |||
| } | |||
| nes_draw_done(rend); | |||
| } | |||
| static int run_menu(menu_state* state, const file_list* files, | |||
| int x, nes_Renderer* rend, | |||
| nes_Input_Reader* input, nes* sys) { | |||
| menu_state menu = {0}; | |||
| if (NULL != state) { | |||
| menu = *state; | |||
| if (menu.cursor < 0) { | |||
| menu.cursor = 0; | |||
| } else if (menu.cursor >= files->count) { | |||
| menu.cursor = files->count - 1; | |||
| } | |||
| } | |||
| int status = 0; | |||
| while (0 == status) { | |||
| // Scrolling (do this first to ensure menu is valid) | |||
| const int visible = n_visible() - 1; | |||
| menu.top = menu.cursor - (visible / 2); | |||
| if (menu.top <= 0) { | |||
| // We use <= so we don't readjust the top from 0 | |||
| menu.top = 0; | |||
| } else if (menu.top + visible >= files->count) { | |||
| menu.top = (files->count - 1) - visible; | |||
| } | |||
| show_menu(&menu, NULL != sys->cart.mapper, | |||
| x, rend, files); | |||
| int buttons = wait_for_input(input, &sys->input); | |||
| int special = (buttons >> 8); | |||
| if (input_Result_Quit == special) { | |||
| status = special; | |||
| } else if (buttons & (1 << Button_B)) { | |||
| status = input_Result_Cancel; | |||
| } else if (buttons & ( (1 << Button_A) | | |||
| (1 << Button_Start) )) { | |||
| // Select | |||
| break; | |||
| } else if (buttons & (1 << Button_Up)) { | |||
| if (menu.cursor > 0) --menu.cursor; | |||
| } else if (buttons & ( (1 << Button_Down) | | |||
| (1 << Button_Select) )) { | |||
| if (menu.cursor < (files->count - 1)) { | |||
| ++menu.cursor; | |||
| } | |||
| } | |||
| } | |||
| if (NULL != state) *state = menu; | |||
| return status; | |||
| } | |||
| char* run_main_menu(menu_state* state, nes_Renderer* rend, | |||
| nes_Input_Reader* input, nes* sys) { | |||
| @@ -130,7 +195,7 @@ char* run_main_menu(menu_state* state, nes_Renderer* rend, | |||
| DIR* dir = opendir("rom"); | |||
| if (NULL == dir) { | |||
| nes_draw_last_frame(rend); | |||
| nes_draw_last_frame(rend, NULL != sys->cart.mapper); | |||
| nes_draw_text(rend, "No ROMS found!", 10, 10); | |||
| nes_draw_text(rend, "Press any key to exit", 10, 21); | |||
| nes_draw_done(rend); | |||
| @@ -142,55 +207,19 @@ char* run_main_menu(menu_state* state, nes_Renderer* rend, | |||
| closedir(dir); | |||
| menu_state menu = {0}; | |||
| if (NULL != state) { | |||
| menu = *state; | |||
| if (menu.cursor < 0) { | |||
| menu.cursor = 0; | |||
| } else if (menu.cursor >= files.count) { | |||
| menu.cursor = files.count - 1; | |||
| } | |||
| } | |||
| while (1) { | |||
| // Scrolling (do this first to ensure menu is valid) | |||
| const int visible = n_visible(); | |||
| menu.top = menu.cursor - (visible / 2); | |||
| if (menu.top <= 0) { | |||
| // We use <= so we don't readjust the top from 0 | |||
| menu.top = 0; | |||
| } else if (menu.top + visible >= files.count) { | |||
| menu.top = (files.count - 1) - visible; | |||
| } | |||
| show_menu(&menu, rend, &files); | |||
| if (NULL != state) menu = *state; | |||
| int buttons = wait_for_input(input, &sys->input); | |||
| int special = (buttons >> 8); | |||
| int status = run_menu(&menu, &files, 20, | |||
| rend, input, sys); | |||
| if ( input_Result_Quit == special || | |||
| (buttons & (1 << Button_B))) { | |||
| // Cancel | |||
| menu.cursor = -1; | |||
| break; | |||
| if (input_Result_Quit == status) { | |||
| cart_filename = (char*)-1; | |||
| } else if (buttons & ( (1 << Button_A) | | |||
| (1 << Button_Start) )) { | |||
| // Select | |||
| break; | |||
| } else if (input_Result_Cancel == status) { | |||
| cart_filename = NULL; | |||
| } else if (buttons & (1 << Button_Up)) { | |||
| if (menu.cursor > 0) --menu.cursor; | |||
| } else if (buttons & ( (1 << Button_Down) | | |||
| (1 << Button_Select) )) { | |||
| if (menu.cursor < (files.count - 1)) { | |||
| ++menu.cursor; | |||
| } | |||
| } | |||
| } | |||
| // Selection has been made (or cancelled) | |||
| if (menu.cursor >= 0 && menu.cursor < files.count) { | |||
| } else if ( menu.cursor >= 0 && | |||
| menu.cursor < files.count) { | |||
| char filename[1024]; | |||
| snprintf(filename, sizeof(filename) - 1, | |||
| "%s/%s", "rom", files.files[menu.cursor]); | |||
| @@ -199,15 +228,48 @@ char* run_main_menu(menu_state* state, nes_Renderer* rend, | |||
| free_file_list(&files); | |||
| if (NULL != state) { | |||
| *state = menu; | |||
| if (menu.cursor < 0) state->cursor = 0; | |||
| } | |||
| if (NULL != state) *state = menu; | |||
| } | |||
| return cart_filename; | |||
| } | |||
| int run_game_menu(menu_state* state, nes_Renderer* rend, | |||
| nes_Input_Reader* input, nes* sys) { | |||
| static char* items[] = { | |||
| "Resume", | |||
| "Save", | |||
| "Load", | |||
| "Reset", | |||
| "Select ROM", | |||
| "Exit", | |||
| }; | |||
| static int choices[] = { | |||
| input_Result_OK, | |||
| input_Result_Save, | |||
| input_Result_Load, | |||
| input_Result_Reset, | |||
| input_Result_Menu, | |||
| input_Result_Quit, | |||
| }; | |||
| static const file_list options = { | |||
| .files = items, | |||
| .count = (sizeof(items) / sizeof(*items)), | |||
| }; | |||
| menu_state menu = {0}; | |||
| if (NULL != state) menu = *state; | |||
| int status = run_menu(&menu, &options, 100, | |||
| rend, input, sys); | |||
| if (NULL != state) *state = menu; | |||
| if (0 == status) status = choices[menu.cursor]; | |||
| return status; | |||
| } | |||
| int modal_popup(const char* message, nes_Renderer* rend, | |||
| nes_Input_Reader* input, nes* sys) { | |||
| int w = 0; | |||
| @@ -218,7 +280,7 @@ int modal_popup(const char* message, nes_Renderer* rend, | |||
| int x = (nes_ppu_render_w - w) / 2; | |||
| int y = (nes_ppu_render_h - h) / 2; | |||
| nes_draw_last_frame(rend); | |||
| nes_draw_last_frame(rend, NULL != sys->cart.mapper); | |||
| nes_draw_text(rend, message, x, y); | |||
| nes_draw_done(rend); | |||
| @@ -148,7 +148,7 @@ static int sdl_render_init(nes_Renderer* rend) { | |||
| } else { | |||
| SDL_LockTextureToSurface(data->texture, NULL, | |||
| &data->target); | |||
| SDL_FillRect(data->target, NULL, 0x556677FF); | |||
| SDL_FillRect(data->target, NULL, 0x006677FF); | |||
| } | |||
| } | |||
| @@ -560,11 +560,24 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { | |||
| } | |||
| static void sdl_redraw_frame(nes_Renderer* rend) { | |||
| static void sdl_redraw_frame(nes_Renderer* rend, int dim) { | |||
| sdl_render_data* data = (sdl_render_data*)rend->data; | |||
| if (dim) { | |||
| SDL_SetTextureAlphaMod(data->texture, 0x7F); | |||
| SDL_SetTextureBlendMode(data->texture, | |||
| SDL_BLENDMODE_BLEND); | |||
| SDL_RenderClear(data->renderer); | |||
| } | |||
| SDL_UnlockTexture(data->texture); | |||
| SDL_RenderCopy(data->renderer, data->texture, NULL, NULL); | |||
| SDL_LockTextureToSurface(data->texture, NULL, &data->target); | |||
| if (dim) { | |||
| SDL_SetTextureBlendMode(data->texture, | |||
| SDL_BLENDMODE_NONE); | |||
| } | |||
| } | |||
| static void sdl_draw_present(nes_Renderer* rend) { | |||