From 5f8334d425656d3ec3814316f4978d56aa4540cd Mon Sep 17 00:00:00 2001 From: Nathaniel Walizer Date: Mon, 20 Jan 2025 02:06:40 -0800 Subject: [PATCH] Add fixes and support for Steam-compatible build (standalone) --- Makefile | 5 +- src/ini.h | 4 - src/input.h | 14 ++- src/menu.c | 84 ++++++++---------- src/menu.h | 14 +-- src/nese.c | 116 +++++++++++++------------ src/render.h | 6 ++ src/sdl_input.c | 214 ++++++++++++++++++++++++++++++++++++---------- src/sdl_overlay.c | 4 +- src/sdl_render.c | 12 ++- src/state.c | 7 ++ src/state.h | 18 ++++ 12 files changed, 331 insertions(+), 167 deletions(-) diff --git a/Makefile b/Makefile index 80f3888..9e1a7ad 100644 --- a/Makefile +++ b/Makefile @@ -22,12 +22,13 @@ endif CC = $(CROSS_COMPILE)gcc LD = $(CC) PFLAGS += -g -#PFLAGS += -O3 -#PFLAGS += -s +#PFLAGS += -O3 -s +#PFLAGS += -DSTANDALONE #PFLAGS += -DDEBUG_MAPPER #PFLAGS += -DDEBUG_RENDER #PFLAGS += -DDEBUG_PPU -DDEBUG_VRAM -DDEBUG_OAM #PFLAGS += -DDEBUG_APU +#PFLAGS += -DDEBUG_INPUT #PFLAGS += -DE6502_DEBUG PFLAGS += -DE6502_ILLEGAL CFLAGS += $(PFLAGS) -Wall -Werror -Wshadow -Wunused -I../ -Isrc/ diff --git a/src/ini.h b/src/ini.h index 99057f9..ee05e60 100644 --- a/src/ini.h +++ b/src/ini.h @@ -1,10 +1,6 @@ #ifndef NESE_INI_H_ #define NESE_INI_H_ -#define DBG_LOG(...) fprintf(stderr, __VA_ARGS__) -#define ERR_LOG(...) DBG_LOG(__VA_ARGS__) -#define INI_ERR(...) ERR_LOG(__VA_ARGS__) - typedef enum { ini_invalid = -1, diff --git a/src/input.h b/src/input.h index 82add1a..27c825c 100644 --- a/src/input.h +++ b/src/input.h @@ -59,11 +59,15 @@ void nes_input_write(nes_input* input, uint16_t addr, uint8_t val); // System Glue +struct nese_Components; + typedef struct nes_Input_Reader_t { int (*init)(struct nes_Input_Reader_t*); void (*done)(struct nes_Input_Reader_t*); - int (*update)(struct nes_Input_Reader_t*, nes_input*); + int (*update)(struct nes_Input_Reader_t*, + struct nese_Components*); void* data; + int menu_timer; } nes_Input_Reader; static inline int nes_input_init(nes_Input_Reader* reader) { @@ -74,9 +78,11 @@ static inline void nes_input_done(nes_Input_Reader* reader) { reader->done(reader); } -static inline int nes_input_update(nes_Input_Reader* reader, - nes_input* input) { - return reader->update(reader, input); +static inline int nes_input_update( + nes_Input_Reader* reader, + struct nese_Components* comp + ) { + return reader->update(reader, comp); } diff --git a/src/menu.c b/src/menu.c index 3def83c..ee63159 100644 --- a/src/menu.c +++ b/src/menu.c @@ -8,10 +8,9 @@ #include "timer.h" -static int get_input(nes_Input_Reader* reader, - nes_input* input, int *last) { - int status = nes_input_update(reader, input); - int new_buttons = input->controllers[0].buttons; +static int get_input(nese_Components* comp, int *last) { + int status = nes_input_update(comp->reader, comp); + int new_buttons = comp->sys->input.controllers[0].buttons; if (0 == status) { status = (~*last & new_buttons); } else { @@ -21,25 +20,23 @@ static int get_input(nes_Input_Reader* reader, return status; } -static int wait_for_input(nes_Input_Reader* reader, - nes_input* input) { - int buttons = input->controllers[0].buttons; +static int wait_for_input(nese_Components* comp) { + int buttons = comp->sys->input.controllers[0].buttons; int status = 0; for ( ; 0 == status; - status = get_input(reader, input, &buttons) ) { + status = get_input(comp, &buttons) ) { time_sleep(US_PER_S / 60); } return status; } -static int wait_for_input_quiet(nes_Input_Reader* reader, - nes_input* input) { +static int wait_for_input_quiet(nese_Components* comp) { int status = 0; while ( input_Result_Quit != status && - input->controllers[0].buttons) { + comp->sys->input.controllers[0].buttons) { time_sleep(US_PER_S / 60); - status = nes_input_update(reader, input); + status = nes_input_update(comp->reader, comp); } return ( input_Result_Quit == status ? input_Result_Quit : 0); @@ -157,8 +154,8 @@ static void show_menu(const menu_state* menu, int dim, int x, } static int run_menu(menu_state* state, const file_list* files, - int x, nes_Renderer* rend, - nes_Input_Reader* input, nes* sys) { + int x, nese_Components* comp, + const cart_info* cart) { menu_state menu = {0}; if (NULL != state) { menu = *state; @@ -181,14 +178,13 @@ static int run_menu(menu_state* state, const file_list* files, menu.top = (files->count - 1) - visible; } - show_menu(&menu, NULL != sys->cart.mapper, - x, rend, files); + show_menu(&menu, NULL != cart->file, x, + comp->rend, files); - int buttons = wait_for_input(input, &sys->input); + int buttons = wait_for_input(comp); int special = (buttons >> 8); - if ( input_Result_Quit == special || - input_Result_Refresh == special) { + if (input_Result_Quit == special) { status = special; } else if ( input_Result_Menu == special || @@ -220,22 +216,17 @@ static int run_menu(menu_state* state, const file_list* files, } -char* run_main_menu(menu_state* state, nes_Renderer* rend, - nes_Input_Reader* input, nes* sys, - const char* cur_filename) { +char* run_main_menu(menu_state* state, nese_Components* comp, + const cart_info* cart) { char* cart_filename = NULL; DIR* dir = opendir("rom"); if (NULL == dir) { - nes_draw_last_frame(rend, NULL != sys->cart.mapper); - nes_draw_text( - rend, + modal_popup( "No ROMS found!\nPress any key to exit", - 10, 21, color_error + comp, cart ); - nes_draw_done(rend); - wait_for_input(input, &sys->input); } else { file_list files = {0}; @@ -245,18 +236,14 @@ char* run_main_menu(menu_state* state, nes_Renderer* rend, menu_state menu = {0}; if (NULL != state) menu = *state; - if (NULL != cur_filename) { + if (NULL != cart->filename) { // Add 4 to skip past "rom/" - int current = find_file(&files, cur_filename + 4); + int current = find_file(&files, cart->filename + 4); if (current >= 0) menu.cursor = current; } // Don't let window refreshes interrupt us. - int status = input_Result_Refresh; - while (input_Result_Refresh == status) { - status = run_menu(&menu, &files, 20, - rend, input, sys); - } + int status = run_menu(&menu, &files, 20, comp, cart); if (input_Result_Quit == status) { cart_filename = (char*)-1; @@ -280,15 +267,17 @@ char* run_main_menu(menu_state* state, nes_Renderer* rend, return cart_filename; } -int run_game_menu(menu_state* state, nes_Renderer* rend, - nes_Input_Reader* input, nes* sys) { +int run_game_menu(menu_state* state, nese_Components* comp, + const cart_info* cart) { static char* items[] = { "Resume", "Save", "Restore", "Reset", "Select ROM", +#ifndef STANDALONE "Toggle Fullscreen", +#endif "Exit", }; static int choices[] = { @@ -297,7 +286,9 @@ int run_game_menu(menu_state* state, nes_Renderer* rend, input_Result_Load, input_Result_Reset, input_Result_Menu, +#ifndef STANDALONE input_Result_View, +#endif input_Result_Quit, }; static const file_list options = { @@ -308,8 +299,7 @@ int run_game_menu(menu_state* state, nes_Renderer* rend, menu_state menu = {0}; if (NULL != state) menu = *state; - int status = run_menu(&menu, &options, 100, - rend, input, sys); + int status = run_menu(&menu, &options, 100, comp, cart); if (input_Result_Menu == status) { status = input_Result_Cancel; @@ -317,19 +307,19 @@ int run_game_menu(menu_state* state, nes_Renderer* rend, if (0 == status) status = choices[menu.cursor]; - wait_for_input_quiet(input, &sys->input); + wait_for_input_quiet(comp); if (NULL != state) *state = menu; return status; } -int modal_popup(const char* message, nes_Renderer* rend, - nes_Input_Reader* input, nes* sys) { +int modal_popup(const char* message, nese_Components* comp, + const cart_info* cart) { int w = 0; int h = 0; - nes_text_size(rend, message, &w, &h); + nes_text_size(comp->rend, message, &w, &h); int x = ((int)nes_ppu_render_w - w) / 2; int y = ((int)nes_ppu_render_h - h) / 2; @@ -337,9 +327,9 @@ int modal_popup(const char* message, nes_Renderer* rend, if (x < 5) x = 5; if (y < 5) y = 5; - nes_draw_last_frame(rend, NULL != sys->cart.mapper); - nes_draw_text(rend, message, x, y, color_error); - nes_draw_done(rend); + nes_draw_last_frame(comp->rend, NULL != cart->file); + nes_draw_text(comp->rend, message, x, y, color_error); + nes_draw_done(comp->rend); - return wait_for_input(input, &sys->input); + return wait_for_input(comp); } diff --git a/src/menu.h b/src/menu.h index f137bf1..533f760 100644 --- a/src/menu.h +++ b/src/menu.h @@ -4,6 +4,7 @@ #include "nes.h" #include "render.h" #include "input.h" +#include "state.h" #define color_white (0xFFffffffU) @@ -29,16 +30,15 @@ typedef struct { // Returns filename of selected ROM -char* run_main_menu(menu_state*, nes_Renderer*, - nes_Input_Reader*, nes*, - const char* cur_filename); +char* run_main_menu(menu_state*, nese_Components*, + const cart_info*); // Returns nes_Input_Result indicating the choice -int run_game_menu(menu_state*, nes_Renderer*, - nes_Input_Reader*, nes*); +int run_game_menu(menu_state*, nese_Components*, + const cart_info*); -int modal_popup(const char* message, - nes_Renderer*, nes_Input_Reader*, nes*); +int modal_popup(const char* message, nese_Components*, + const cart_info*); #endif // NESE_MENU_H_ diff --git a/src/nese.c b/src/nese.c index 43d3338..84b7654 100644 --- a/src/nese.c +++ b/src/nese.c @@ -107,8 +107,8 @@ static int loadsave_tick(loadsave_state* loadsave) { return action; } -static int select_rom(menu_state* menu, nes_Renderer* rend, - nes_Input_Reader* input, nes* sys, +static int select_rom(menu_state* menu, + nese_Components* comp, cart_info* cur_cart) { int status = 0; cart_info cart = {0}; @@ -120,7 +120,7 @@ static int select_rom(menu_state* menu, nes_Renderer* rend, char message[1024]; snprintf(message, sizeof(message) - 1, "Could not load\n%s", cart.filename + 4); - int button = modal_popup(message, rend, input, sys); + int button = modal_popup(message, comp, cur_cart); if (input_Result_Quit == (button >> 8)) { // Program closed inside modal status = input_Result_Quit; @@ -130,9 +130,7 @@ static int select_rom(menu_state* menu, nes_Renderer* rend, } if (0 == status) { - cart.filename = run_main_menu( - menu, rend, input, sys, cur_cart->filename - ); + cart.filename = run_main_menu(menu, comp, cur_cart); if ((char*)-1 == cart.filename) { // This means that we quit @@ -150,49 +148,43 @@ static int select_rom(menu_state* menu, nes_Renderer* rend, } if (0 == status && NULL != cart.file) { - save_sram(&sys->cart, cur_cart->filename); + save_sram(&comp->sys->cart, cur_cart->filename); - nes_cart_done(&sys->cart); + nes_cart_done(&comp->sys->cart); cart_info_done(cur_cart); - sys->cart = new_cart; + comp->sys->cart = new_cart; *cur_cart = cart; - nes_setup_cart(sys); + nes_setup_cart(comp->sys); } return status; } -static int do_game_menu(menu_state* menu, nes_Renderer* rend, - nes_Input_Reader* input, nes* sys, +static int do_game_menu(menu_state* menu, + nese_Components* comp, nese_State* state) { int status = 0; menu_state rom_menu = {0}; while (1) { - status = run_game_menu(menu, rend, input, sys); + status = run_game_menu(menu, comp, &state->cart); - if ( input_Result_View == status || - input_Result_Refresh == status) { - if (input_Result_View == status) { - state->flags ^= (1 << State_Bit_Fullscreen); - } else { - // We need to do this to flush both buffers - nes_draw_last_frame(rend, 1); - nes_draw_done(rend); - } + if (input_Result_View == status) { +#ifndef STANDALONE + state->flags ^= (1 << State_Bit_Fullscreen); +#endif // We call this both times since it does both // the toggle and the recalculation. nes_render_fullscreen( - rend, + comp->rend, state->flags & (1 << State_Bit_Fullscreen) ); continue; } else if (input_Result_Menu == status) { - status = select_rom(&rom_menu, rend, input, - sys, &state->cart); + status = select_rom(&rom_menu, comp, &state->cart); if (input_Result_Cancel == status) { status = input_Result_OK; @@ -212,31 +204,39 @@ int main(int argc, char* argv[]) { nese_State state = {0}; load_prefs_filename(&state, "nese.prefs"); +#ifdef STANDALONE + state.flags |= (1 << State_Bit_Fullscreen); +#endif + + nes sys = {0}; + if (status == 0) { + status = nes_init(&sys, audio_freq); + } + + nese_Components components = { + .rend = &sdl_renderer, + .reader = &sdl_input, + .audio = &sdl_audio, + .sys = &sys, + }; - nes_Renderer* rend = &sdl_renderer; if (status == 0) { - status = nes_render_init(rend); + status = nes_render_init(components.rend); if (0 == status) { nes_render_fullscreen( - rend, + components.rend, (state.flags & (1 << State_Bit_Fullscreen)) ); + nes_render_refresh(components.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); + status = nes_input_init(components.reader); } - nes sys = {0}; if (status == 0) { - status = nes_init(&sys, audio_freq); + status = nes_audio_init(components.audio, audio_freq); } if (0 == status && argc > 1) { @@ -255,17 +255,16 @@ int main(int argc, char* argv[]) { // If we didn't launch with a file, run the loader if (0 == status && NULL == state.cart.file) { - status = select_rom(NULL, rend, input, - &sys, &state.cart); + status = select_rom(NULL, &components, &state.cart); } if (status == 0) { menu_state game_menu = {0}; loadsave_state loadsave = { - .overlay = &rend->overlay, + .overlay = &components.rend->overlay, }; - nes_render(rend, &sys.ppu); + nes_render(components.rend, &sys.ppu); time_us t_target = time_now(); uint64_t cycle_last_frame = 0; @@ -278,7 +277,7 @@ int main(int argc, char* argv[]) { if ( result == ppu_Result_Ready || result == ppu_Result_VBlank_Off) { - status = nes_render(rend, &sys.ppu); + status = nes_render(components.rend, &sys.ppu); if (status > 0) { // Load/Save Operations @@ -309,25 +308,28 @@ int main(int argc, char* argv[]) { cycle_last_frame = total_cycles; // Update button states every rendered frame - status = nes_input_update(input, &sys.input); + status = nes_input_update(components.reader, + &components); - if (input_Result_Menu == status) { + if (input_Result_Refresh == status) { + status = input_Result_OK; + + } if (input_Result_Menu == status) { status = do_game_menu( - &game_menu, rend, - input, &sys, &state + &game_menu, &components, &state ); if ( input_Result_Load == status || input_Result_Save == status) { loadsave.mode = status; loadsave.timer = 0; - status = 0; + status = input_Result_OK; } // Allow other options to fall through } if (input_Result_Reset == status) { overlay_add_message( - &rend->overlay, + &components.rend->overlay, "Game reset", 60 * 3 ); @@ -351,7 +353,9 @@ int main(int argc, char* argv[]) { if (status == 0) { // Update audio, too - status = nes_audio_fill(audio, &sys.apu); + status = nes_audio_fill( + components.audio, &sys.apu + ); } } } else if (result == ppu_Result_Halt) { @@ -362,9 +366,11 @@ int main(int argc, char* argv[]) { float ms_run = ( total_cycles * 1000. * nes_clock_master_den) / nes_clock_master_num; - fprintf(stdout, "Ran %f ms, %"PRIu64" master cycles (%s)\n", - ms_run, total_cycles, - status == 0 ? "OK" : "Halted"); + fprintf(stdout, + "Ran %f ms, %"PRIu64" master cycles (%s)\n", + ms_run, total_cycles, + status == 0 ? "OK" : "Halted" + ); // Failure might mean there's nothing to save save_sram(&sys.cart, state.cart.filename); @@ -375,9 +381,9 @@ int main(int argc, char* argv[]) { nes_done(&sys); - nes_audio_done(audio); - nes_input_done(input); - nes_render_done(rend); + nes_audio_done(components.audio); + nes_input_done(components.reader); + nes_render_done(components.rend); return status; } diff --git a/src/render.h b/src/render.h index c216e01..6c04a1a 100644 --- a/src/render.h +++ b/src/render.h @@ -9,7 +9,9 @@ typedef struct nes_Renderer_t { int (*init)(struct nes_Renderer_t*); void (*done)(struct nes_Renderer_t*); int (*render)(struct nes_Renderer_t*, nes_ppu*); + void (*fullscreen)(struct nes_Renderer_t*, int enable); + void (*refresh)(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, uint32_t color); @@ -37,6 +39,10 @@ static inline void nes_render_fullscreen(nes_Renderer* rend, rend->fullscreen(rend, enable); } +static inline void nes_render_refresh(nes_Renderer* rend) { + rend->refresh(rend); +} + static inline void nes_draw_last_frame(nes_Renderer* rend, int dim) { rend->draw_last_frame(rend, dim); diff --git a/src/sdl_input.c b/src/sdl_input.c index d53da17..85ac971 100644 --- a/src/sdl_input.c +++ b/src/sdl_input.c @@ -1,26 +1,51 @@ #include #include "input.h" +#include "state.h" + + +#define DBG_LOG(...) printf(__VA_ARGS__) +#define ERR_LOG(...) DBG_LOG(__VA_ARGS__) + +#ifdef DEBUG_INPUT +#define INPUT_DBG DBG_LOG +#define INPUT_INFO DBG_LOG +#else +#define INPUT_DBG(...) +#define INPUT_INFO(...) +#endif +#define INPUT_ERR ERR_LOG + + +#define axis_threshold (8192L) + +typedef struct { + int16_t last_x_axis; + int16_t last_y_axis; + SDL_GameController* gamepad; +} sdl_input_data; + +static sdl_input_data the_input_data = {0}; static SDL_GameController* sdl_find_gamepad() { int i = SDL_NumJoysticks() - 1; - printf("Found %d joysticks\n", i + 1); + INPUT_INFO("Found %d joysticks\n", i + 1); for ( ; i >= 0 && !SDL_IsGameController(i); --i); - if (i >= 0) printf("Joystick %d is a gamepad\n", i); + if (i >= 0) INPUT_INFO("Joystick %d is a gamepad\n", i); return (i < 0 ? NULL : SDL_GameControllerOpen(i)); } -static void sdl_lose_gamepad(void* data) { - SDL_GameController* gamepad = (SDL_GameController*)data; - if (NULL != gamepad) SDL_GameControllerClose(gamepad); +static void sdl_lose_gamepad(SDL_GameController* gamepad) { + if (NULL != gamepad) { + SDL_GameControllerClose(gamepad); + } } -static int sdl_match_gamepad(SDL_JoystickID id, void* data) { - SDL_GameController* gamepad = (SDL_GameController*)data; - return ( SDL_JoystickInstanceID( - SDL_GameControllerGetJoystick(gamepad)) - == id); +static int sdl_match_gamepad(SDL_JoystickID id, + SDL_GameController* gamepad) { + return ( id == SDL_JoystickInstanceID( + SDL_GameControllerGetJoystick(gamepad))); } /* static int sdl_event_filter(void*, SDL_Event* event) { @@ -35,27 +60,32 @@ static int sdl_event_filter(void*, SDL_Event* event) { } */ static int sdl_input_init(nes_Input_Reader* reader) { + reader->data = &the_input_data; + sdl_input_data* data = (sdl_input_data*)reader->data; + int status = SDL_Init(SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER); if (status == 0) { - reader->data = sdl_find_gamepad(); + data->gamepad = sdl_find_gamepad(); // SDL_SetEventFilter(sdl_event_filter, NULL); - if (NULL != reader->data) { - printf("Gamepad found\n"); + if (NULL != data->gamepad) { + INPUT_INFO("Gamepad found\n"); } } return status; } -static void sdl_input_done(nes_Input_Reader* input) { - sdl_lose_gamepad(input->data); +static void sdl_input_done(nes_Input_Reader* reader) { + sdl_input_data* data = (sdl_input_data*)reader->data; + sdl_lose_gamepad(data->gamepad); } static const int sdl_menu_key = SDLK_ESCAPE; static const int sdl_save_key = SDLK_F1; static const int sdl_load_key = SDLK_F2; +static const int sdl_alt_start_key = SDLK_RETURN; static const int sdl_keycodes[nes_controller_num_buttons] = { SDLK_a, @@ -89,10 +119,31 @@ static int button_index(int keycode, const int* codes) { return index; } + +#define input_debug(o, ...) INPUT_DBG(__VA_ARGS__) +/* +static void input_debug(Overlay* overlay, + const char* fmt, ...) { + char msg[100] = {0}; + va_list args; + va_start(args, fmt); + vsnprintf(msg, sizeof(msg) - 1, fmt, args); + va_end(args); + + overlay_add_message(overlay, msg, 60); +} +*/ + static int sdl_input_update(nes_Input_Reader* reader, - nes_input* input) { + nese_Components* comp) { int status = input_Result_OK; + sdl_input_data* data = (sdl_input_data*)reader->data; + + if (reader->menu_timer > 0 && --reader->menu_timer == 0) { + status = input_Result_Menu; + } + SDL_Event event = {0}; while (0 == status && 0 != SDL_PollEvent(&event)) { if (SDL_QUIT == event.type) { @@ -101,6 +152,14 @@ static int sdl_input_update(nes_Input_Reader* reader, } else if (SDL_WINDOWEVENT == event.type) { if ( SDL_WINDOWEVENT_EXPOSED == event.window.event) { + // We need to do this to flush both buffers +// nes_draw_last_frame(comp->rend, 1); +// nes_draw_done(comp->rend); + + // We call this both times since it does both + // the toggle and the recalculation. + nes_render_refresh(comp->rend); + status = input_Result_Refresh; } @@ -108,15 +167,32 @@ static int sdl_input_update(nes_Input_Reader* reader, SDL_KEYUP == event.type) && 0 == event.key.repeat ) { - int index = button_index(event.key.keysym.sym, - sdl_keycodes); + input_debug(&comp->rend->overlay, + "Input: K %d S %d\n", + SDL_KEYDOWN == event.type ? 1 : 0, + event.key.keysym.sym); + + int index = ( sdl_alt_start_key == + event.key.keysym.sym) ? + Button_Start : button_index( + event.key.keysym.sym, + sdl_keycodes); if (index >= 0) { uint8_t mask = (1 << index); if (SDL_KEYDOWN == event.type) { - input->controllers[0].buttons |= mask; + comp->sys->input.controllers[0].buttons |= mask; } else { - input->controllers[0].buttons &= ~mask; + comp->sys->input.controllers[0].buttons &= ~mask; } + /* + input_debug( + &comp->rend->overlay, + "Input: Key: %s %02x\n", + (SDL_KEYDOWN == event.type) ? + "Set" : "Clear", + mask + ); + */ } else if ( sdl_menu_key == event.key.keysym.sym && SDL_KEYDOWN == event.type) { @@ -139,14 +215,37 @@ static int sdl_input_update(nes_Input_Reader* reader, } else if ( SDL_CONTROLLERBUTTONDOWN == event.type || SDL_CONTROLLERBUTTONUP == event.type) { + input_debug(&comp->rend->overlay, + "Input: B %d B %d\n", + SDL_CONTROLLERBUTTONDOWN == event.type ? + 1 : 0, + event.cbutton.button); + int index = button_index(event.cbutton.button, sdl_buttons); if (index >= 0) { uint8_t mask = (1 << index); if (SDL_CONTROLLERBUTTONDOWN == event.type) { - input->controllers[0].buttons |= mask; + comp->sys->input.controllers[0].buttons |= mask; } else { - input->controllers[0].buttons &= ~mask; + comp->sys->input.controllers[0].buttons &= ~mask; + } + /* + input_debug( + &comp->rend->overlay, + "Input: Button: %s %02x\n", + (SDL_CONTROLLERBUTTONDOWN == event.type) ? + "Set" : "Clear", + mask + ); + */ + + if (Button_Start == index) { + if (SDL_CONTROLLERBUTTONDOWN == event.type) { + reader->menu_timer = 60; + } else { + reader->menu_timer = 0; + } } } else if (sdl_menu_button == event.cbutton.button) { @@ -175,50 +274,73 @@ static int sdl_input_update(nes_Input_Reader* reader, uint8_t mask_set = 0; uint8_t mask_clear = 0; + int dir = 0; + if (value <= -axis_threshold) dir = -1; + else if (value >= axis_threshold) dir = 1; + if (SDL_CONTROLLER_AXIS_LEFTX == axis) { - mask_clear = (1 << Button_Left) | - (1 << Button_Right); - if (value <= -8192) { - mask_set = (1 << Button_Left); - } else if (value >= 8192) { - mask_set = (1 << Button_Right); + if (dir != data->last_x_axis) { + mask_clear = (1 << Button_Left) | + (1 << Button_Right); + if (dir < 0) { + mask_set = (1 << Button_Left); + } else if (dir > 0) { + mask_set = (1 << Button_Right); + } } + data->last_x_axis = dir; } else if (SDL_CONTROLLER_AXIS_LEFTY == axis) { - mask_clear = (1 << Button_Down) | - (1 << Button_Up); - if (value <= -8192) { - mask_set = (1 << Button_Up); - } else if (value >= 8192) { - mask_set = (1 << Button_Down); + if (dir != data->last_y_axis) { + mask_clear = (1 << Button_Down) | + (1 << Button_Up); + if (dir < 0) { + mask_set = (1 << Button_Up); + } else if (dir > 0) { + mask_set = (1 << Button_Down); + } } + data->last_y_axis = dir; } - input->controllers[0].buttons &= ~mask_clear; - input->controllers[0].buttons |= mask_set; + uint32_t old_buttons = comp->sys->input.controllers[0].buttons; + uint32_t new_buttons = ((old_buttons & ~mask_clear) | mask_set); + comp->sys->input.controllers[0].buttons = new_buttons; + /* + if (old_buttons != new_buttons) { + input_debug(&comp->rend->overlay, + "Input: Axis: S %02x C %02x V %d\n", + mask_set, mask_clear, value); + } + */ } else if (SDL_CONTROLLERDEVICEADDED == event.type) { - if (NULL == reader->data) { - printf("New gamepad connected\n"); - reader->data = sdl_find_gamepad(); - if (reader->data) printf("Using new gamepad\n"); + if (NULL == data->gamepad) { + INPUT_INFO("New gamepad connected\n"); + data->gamepad = sdl_find_gamepad(); + if (data->gamepad) INPUT_INFO("Using new gamepad\n"); } else { - printf("Redundant gamepad connected\n"); + INPUT_INFO("Redundant gamepad connected\n"); } } else if (SDL_CONTROLLERDEVICEREMOVED == event.type) { if (sdl_match_gamepad(event.cdevice.which, - reader->data)) { - printf("Gamepad disconnected\n"); + data->gamepad)) { + INPUT_INFO("Gamepad disconnected\n"); sdl_lose_gamepad(reader->data); - reader->data = sdl_find_gamepad(); - if (reader->data) printf("Using another gamepad\n"); + data->gamepad = sdl_find_gamepad(); + if (data->gamepad) INPUT_INFO("Using another gamepad\n"); } else { - printf("Redundant gamepad disconnected\n"); + INPUT_INFO("Redundant gamepad disconnected\n"); } } } + if (0 != status) { + input_debug(&comp->rend->overlay, + "Input: Returning %d\n", status); + } + return status; } diff --git a/src/sdl_overlay.c b/src/sdl_overlay.c index b0fe93f..4a6e791 100644 --- a/src/sdl_overlay.c +++ b/src/sdl_overlay.c @@ -164,7 +164,7 @@ int sdl_overlay_frame(Overlay* overlay, sdl_overlay_font* font, overlay_message* last = NULL, *next = NULL; for ( overlay_message* message = overlay->messages; NULL != message; - last = message, message = next) { + message = next) { next = message->next; render_string(rend, x, y, vx, vy, sx, sy, @@ -179,6 +179,8 @@ int sdl_overlay_frame(Overlay* overlay, sdl_overlay_font* font, } free(message->string); free(message); + } else { + last = message; } } diff --git a/src/sdl_render.c b/src/sdl_render.c index c6db849..02d749a 100644 --- a/src/sdl_render.c +++ b/src/sdl_render.c @@ -192,9 +192,12 @@ static void sdl_render_done(nes_Renderer* rend) { static void sdl_render_fullscreen(nes_Renderer* rend, int on) { sdl_render_data* data = (sdl_render_data*)rend->data; - SDL_SetWindowFullscreen(data->window, on ? SDL_WINDOW_FULLSCREEN : 0); +} + +static void sdl_render_refresh(nes_Renderer* rend) { + sdl_render_data* data = (sdl_render_data*)rend->data; SDL_GetWindowSize(data->window, &data->win_w, &data->win_h); @@ -215,6 +218,10 @@ static void sdl_render_fullscreen(nes_Renderer* rend, int on) { data->view.h = h; SDL_RenderSetClipRect(data->renderer, &data->view); + + // We need to do this to flush both buffers +// nes_draw_last_frame(rend, 1); +// nes_draw_done(rend); } static inline void render_sprite_line( @@ -581,6 +588,8 @@ static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { } else { REND_LOG("Scanline %3d -> Postrender\n", ppu->scanline); + SDL_RenderClear(data->renderer); + SDL_UnlockTexture(data->texture); SDL_RenderCopy(data->renderer, data->texture, NULL, &data->view); @@ -653,6 +662,7 @@ nes_Renderer sdl_renderer = { .done = sdl_render_done, .render = sdl_render, .fullscreen = sdl_render_fullscreen, + .refresh = sdl_render_refresh, .draw_last_frame = sdl_redraw_frame, .draw_text = sdl_draw_text, .text_size = sdl_text_size, diff --git a/src/state.c b/src/state.c index 283c7bd..0182edc 100644 --- a/src/state.c +++ b/src/state.c @@ -4,6 +4,13 @@ #include "ini.h" +// Running State + +// TODO + + +// Persistent State + void cart_info_done(cart_info* cart) { if (cart->file) fclose(cart->file); free(cart->filename); diff --git a/src/state.h b/src/state.h index 118736c..20a924d 100644 --- a/src/state.h +++ b/src/state.h @@ -5,6 +5,24 @@ #include #include +#include "input.h" +#include "overlay.h" +#include "render.h" +#include "audio.h" +#include "nes.h" + + +// Running State + +typedef struct nese_Components { + nes_Renderer* rend; + nes_Input_Reader* reader; + nes_Audio_Stream* audio; + nes* sys; +} nese_Components; + + +// Persistent State typedef struct { char* filename;