瀏覽代碼

Add fixes and support for Steam-compatible build (standalone)

master
Nathaniel Walizer 10 月之前
父節點
當前提交
5f8334d425
共有 12 個檔案被更改,包括 331 行新增167 行删除
  1. +3
    -2
      Makefile
  2. +0
    -4
      src/ini.h
  3. +10
    -4
      src/input.h
  4. +37
    -47
      src/menu.c
  5. +7
    -7
      src/menu.h
  6. +61
    -55
      src/nese.c
  7. +6
    -0
      src/render.h
  8. +168
    -46
      src/sdl_input.c
  9. +3
    -1
      src/sdl_overlay.c
  10. +11
    -1
      src/sdl_render.c
  11. +7
    -0
      src/state.c
  12. +18
    -0
      src/state.h

+ 3
- 2
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/


+ 0
- 4
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,


+ 10
- 4
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);
}




+ 37
- 47
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);
}

+ 7
- 7
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_

+ 61
- 55
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;
}

+ 6
- 0
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);


+ 168
- 46
src/sdl_input.c 查看文件

@@ -1,26 +1,51 @@
#include <SDL.h>

#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;
}



+ 3
- 1
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;
}
}



+ 11
- 1
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,


+ 7
- 0
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);


+ 18
- 0
src/state.h 查看文件

@@ -5,6 +5,24 @@
#include <stdio.h>
#include <stdlib.h>

#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;


Loading…
取消
儲存