Преглед на файлове

Add FPS and Turbo controls; Simplify action inputs

v2
Nathaniel Walizer преди 7 месеца
родител
ревизия
ded5f91e7f
променени са 4 файла, в които са добавени 128 реда и са изтрити 39 реда
  1. +98
    -37
      src/linux/port.c
  2. +1
    -1
      src/nes.c
  3. +27
    -1
      src/overlay.c
  4. +2
    -0
      src/overlay.h

+ 98
- 37
src/linux/port.c Целия файл

@@ -90,6 +90,10 @@ typedef struct {
void* cart_data;
} cart_info;

typedef enum {
Flag_Turbo = 0b1,
} Platform_Flags;

typedef struct {
nes* sys;
cart_info cart;
@@ -101,6 +105,8 @@ typedef struct {
SDL_Surface* screen;
SDL_Rect view;
Overlay overlay;
int fps_msg_id;
Platform_Flags flags;
} platform_data;


@@ -115,6 +121,9 @@ typedef enum {
Action_Save,
Action_Menu,
Action_Cancel,
Action_FPS,
Action_Turbo,
Action_Max
} nese_Action;

int nese_update_input(void* plat_data, nes_Input* input) {
@@ -122,12 +131,16 @@ int nese_update_input(void* plat_data, nes_Input* input) {
return 0;
}

static const int sdl_action_keycodes[Action_Max] = {
[Action_Menu] = SDLK_ESCAPE,
[Action_Reset] = SDLK_BACKSPACE,
[Action_Load] = SDLK_F2,
[Action_Save] = SDLK_F1,
[Action_FPS] = SDLK_f,
[Action_Turbo] = SDLK_t,
};

#define sdl_save_key (SDLK_F1)
#define sdl_load_key (SDLK_F2)
#define sdl_alt_start_key (SDLK_RETURN)

static const int sdl_keycodes[nes_controller_num_buttons] = {
static const int sdl_button_keycodes[nes_controller_num_buttons] = {
SDLK_a,
SDLK_s,
SDLK_q,
@@ -138,21 +151,23 @@ static const int sdl_keycodes[nes_controller_num_buttons] = {
SDLK_RIGHT,
};

static int button_index(int keycode, const int* codes) {
int index = nes_controller_num_buttons - 1;
#define sdl_alt_start_key (SDLK_RETURN)

static int keycode_index(int keycode, const int* codes, int n_codes) {
int index = n_codes - 1;
for ( ; index >= 0 && keycode != codes[index]; --index);
return index;
}

// TODO: Return an action enum?
static int process_events(nes* sys) {
int status = 0;
static nese_Action process_events(nes* sys) {
nese_Action action = Action_OK;
nes_Input* input = &sys->core.memory.input;

SDL_Event event = {0};
while (0 == status && 0 != SDL_PollEvent(&event)) {
while (Action_OK == action && 0 != SDL_PollEvent(&event)) {
if (SDL_QUIT == event.type) {
status = -1;
action = Action_Quit;

} else if ( ( SDL_KEYDOWN == event.type ||
SDL_KEYUP == event.type) &&
@@ -160,9 +175,11 @@ static int process_events(nes* sys) {
) {
int index = ( sdl_alt_start_key ==
event.key.keysym.sym) ?
Button_Start : button_index(
event.key.keysym.sym,
sdl_keycodes);
Button_Start : keycode_index(
event.key.keysym.sym,
sdl_button_keycodes,
nes_controller_num_buttons
);
if (index >= 0) {
uint8_t mask = (1 << index);
if (SDL_KEYDOWN == event.type) {
@@ -172,22 +189,17 @@ static int process_events(nes* sys) {
}

} else if (SDL_KEYDOWN == event.type) {
switch (event.key.keysym.sym) {
case sdl_save_key:
status = Action_Save;
break;

case sdl_load_key:
status = Action_Load;
break;
}
index = keycode_index(
event.key.keysym.sym,
sdl_action_keycodes, Action_Max
);
if (index >= 0) action = index;
}
// TODO: Menu or other hotkeys
}
// TODO: Controller inputs
}

return status;
return action;
}


@@ -245,13 +257,13 @@ int nese_line_ready(void* plat_data, uint8_t* buffer, int line) {
}


#define NS_PER_S (1000U * 1000U * 1000U)
#define NS_PER_S (1000L * 1000L * 1000L)
#define FRAME_TIME_NS (16639267L)

uint64_t time_now(void) {
struct timespec ts_now = {0};
clock_gettime(CLOCK_REALTIME, &ts_now);
return ((int64_t)ts_now.tv_sec * NS_PER_S) + ts_now.tv_nsec;
return (ts_now.tv_sec * NS_PER_S) + ts_now.tv_nsec;
}

int64_t time_sleep_until(int64_t t_target) {
@@ -318,27 +330,76 @@ int nese_frame_ready(void* plat_data) {

SDL_RenderPresent(plat->renderer);

status = process_events(plat->sys);

if (Action_Save == status) {
nese_Action action = process_events(plat->sys);
switch (action) {
case Action_Menu:
case Action_Quit:
status = -1;
break;

case Action_Save:
status = save_state(plat->sys, plat->cart.filename);
} else if (Action_Load == status) {
break;

case Action_Load:
status = load_state(plat->sys, plat->cart.filename);
break;

case Action_FPS:
if (plat->fps_msg_id <= 0) {
plat->fps_msg_id = overlay_add_message(&plat->overlay, "", 0);
} else {
overlay_clear_message(&plat->overlay, plat->fps_msg_id);
plat->fps_msg_id = 0;
}
break;

case Action_Turbo:
plat->flags ^= Flag_Turbo;
break;

default:
}

// TODO: Perform more actions

#ifndef NESE_TURBO
if (0 == status) {
plat->t_target += FRAME_TIME_NS;
int64_t slept_ns = time_sleep_until(plat->t_target);
if (slept_ns <= -FRAME_TIME_NS) {
// We're way out of sync.
plat->t_target = time_now();
printf("Out of sync: %d\n", (int)slept_ns);
int64_t slept_ns = 0;
if (plat->flags & Flag_Turbo) {
int64_t now = time_now();
slept_ns = plat->t_target - now;
plat->t_target = now;
} else {
slept_ns = time_sleep_until(plat->t_target);
if (slept_ns <= -FRAME_TIME_NS) {
// We're way out of sync.
plat->t_target = time_now();
printf("Out of sync: %d\n", (int)slept_ns);
}
}

static int frame = 0;
static int64_t slept_total = 0;
slept_total += slept_ns;
if (60 == ++frame) {
if (plat->fps_msg_id > 0) {
int64_t game_elapsed = frame * FRAME_TIME_NS;
int64_t cpu_elapsed = game_elapsed - slept_total;
float fps = (double)(NS_PER_S * frame) / cpu_elapsed;

char message[32];
snprintf(message, sizeof(message), "%.1f fps", fps);
overlay_update_message(&plat->overlay, plat->fps_msg_id, message);
}

slept_total = 0;
frame = 0;
}

}
#endif // NESE_TURBO

return status;
}


+ 1
- 1
src/nes.c Целия файл

@@ -3,7 +3,7 @@
#include "nes.h"
#include "port.h"

#define NESE_DEBUG "NES"
//#define NESE_DEBUG "NES"
#include "log.h"




+ 27
- 1
src/overlay.c Целия файл

@@ -178,7 +178,7 @@ typedef struct Overlay_message_t {

int overlay_init(Overlay* overlay, SDL_Renderer* rend) {
overlay->messages = NULL;
overlay->next_id = 0;
overlay->next_id = 1;
overlay_font_init(&overlay->font, rend);
return 0;
}
@@ -203,6 +203,32 @@ void overlay_done(Overlay* overlay) {
overlay_font_done(&overlay->font);
}

static Overlay_message* overlay_find_message(Overlay* overlay, int id) {
Overlay_message* message = overlay->messages;
for ( ;
NULL != message && message->id != id;
message = message->next
);
return message;
}

int overlay_update_message(Overlay* overlay, int id, const char* string) {
Overlay_message* msg = overlay_find_message(overlay, id);
if (NULL != msg) {
free(msg->string);
msg->string = strdup(string);
}
return (NULL == msg) ? -1 : 0;
}

int overlay_update_expiry(Overlay* overlay, int id, int expiry) {
Overlay_message* msg = overlay_find_message(overlay, id);
if (NULL != msg) {
msg->expiry = expiry;
}
return (NULL == msg) ? -1 : 0;
}

int overlay_clear_message(Overlay* overlay, int id) {
int result = -1;
Overlay_message* last = NULL;


+ 2
- 0
src/overlay.h Целия файл

@@ -35,6 +35,8 @@ int overlay_init(Overlay*, SDL_Renderer*);
void overlay_done(Overlay*);

int overlay_add_message(Overlay*, const char*, int expiry);
int overlay_update_message(Overlay*, int id, const char*);
int overlay_update_expiry(Overlay*, int id, int expiry);
int overlay_clear_message(Overlay*, int id);
int overlay_clear(Overlay*);



Loading…
Отказ
Запис