1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-08 20:25:47 +00:00

Add save state slots.

This commit is contained in:
Themaister 2011-01-23 23:09:54 +01:00
parent 2267c7d048
commit 17663bbe46
9 changed files with 150 additions and 54 deletions

View File

@ -169,6 +169,8 @@ static const struct snes_keybind snes_keybinds_1[] = {
{ SSNES_LOAD_STATE_KEY, SDLK_F4, NO_BTN, AXIS_NONE },
{ SSNES_FULLSCREEN_TOGGLE_KEY, SDLK_f, NO_BTN, AXIS_NONE },
{ SSNES_QUIT_KEY, SDLK_ESCAPE, NO_BTN, AXIS_NONE },
{ SSNES_STATE_SLOT_MINUS, SDLK_F6, NO_BTN, AXIS_NONE },
{ SSNES_STATE_SLOT_PLUS, SDLK_F7, NO_BTN, AXIS_NONE },
{ -1 }
};

View File

@ -32,6 +32,8 @@ enum
SSNES_SAVE_STATE_KEY,
SSNES_FULLSCREEN_TOGGLE_KEY,
SSNES_QUIT_KEY,
SSNES_STATE_SLOT_PLUS,
SSNES_STATE_SLOT_MINUS,
};
struct snes_keybind

19
file.c
View File

@ -135,47 +135,53 @@ error:
}
// Dump stuff to file.
static void dump_to_file(const char *path, const void *data, size_t size)
static bool dump_to_file(const char *path, const void *data, size_t size)
{
FILE *file = fopen(path, "wb");
if (!file)
{
SSNES_ERR("Couldn't dump to file %s\n", path);
return false;
}
else
{
fwrite(data, 1, size, file);
fclose(file);
return true;
}
}
void save_state(const char* path)
bool save_state(const char* path)
{
SSNES_LOG("Saving state: \"%s\".\n", path);
size_t size = psnes_serialize_size();
if (size == 0)
return;
return false;
void *data = malloc(size);
if (!data)
{
SSNES_ERR("Failed to allocate memory for save state buffer.\n");
return;
return false;
}
SSNES_LOG("State size: %d bytes.\n", (int)size);
psnes_serialize(data, size);
dump_to_file(path, data, size);
bool ret = dump_to_file(path, data, size);
free(data);
return ret;
}
void load_state(const char* path)
bool load_state(const char* path)
{
SSNES_LOG("Loading state: \"%s\".\n", path);
void *buf = NULL;
ssize_t size = read_file(path, &buf);
if (size < 0)
{
SSNES_ERR("Failed to load state.\n");
return false;
}
else
{
SSNES_LOG("State size: %d bytes.\n", (int)size);
@ -183,6 +189,7 @@ void load_state(const char* path)
}
free(buf);
return true;
}
void load_ram_file(const char* path, int type)

4
file.h
View File

@ -26,8 +26,8 @@
#include <sys/types.h>
#include "general.h"
void load_state(const char* path);
void save_state(const char* path);
bool load_state(const char* path);
bool save_state(const char* path);
void load_ram_file(const char* path, int type);
void save_ram_file(const char* path, int type);

View File

@ -35,7 +35,7 @@
#define MAX_PLAYERS 5
#define MAX_BINDS 18 // Needs to be increased every time there are new binds added.
#define MAX_BINDS 20 // Needs to be increased every time there are new binds added.
#define SSNES_NO_JOYPAD 0xFFFF
struct settings
{
@ -126,6 +126,8 @@ struct global
char savefile_name_bsrm[512];
char savestate_name[256];
unsigned state_slot;
struct
{
float *data;

View File

@ -176,19 +176,22 @@ static inline void gl_shader_set_params(unsigned width, unsigned height,
static inline void gl_init_font(gl_t *gl, const char *font_path, unsigned font_size)
{
#ifdef HAVE_FREETYPE
gl->font = font_renderer_new(font_path, font_size);
if (gl->font)
if (strlen(font_path) > 0)
{
glGenTextures(1, &gl->font_tex);
glBindTexture(GL_TEXTURE_2D, gl->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, gl->texture);
gl->font = font_renderer_new(font_path, font_size);
if (gl->font)
{
glGenTextures(1, &gl->font_tex);
glBindTexture(GL_TEXTURE_2D, gl->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, gl->texture);
}
else
SSNES_WARN("Couldn't init font renderer with font \"%s\"...\n", font_path);
}
else
SSNES_WARN("Couldn't init font renderer with font \"%s\"...\n", font_path);
#endif
}

View File

@ -103,8 +103,6 @@ static void set_defaults(void)
#endif
#ifdef HAVE_FREETYPE
// Just grab one font path for now... :)
strncpy(g_settings.video.font_path, "/usr/share/fonts/TTF/DejaVuSans.ttf", sizeof(g_settings.video.font_path) - 1);
g_settings.video.font_size = font_size;
g_settings.video.msg_pos_x = message_pos_offset_x;
g_settings.video.msg_pos_y = message_pos_offset_y;
@ -399,6 +397,8 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY)
DECLARE_BIND(save_state, SSNES_SAVE_STATE_KEY)
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(state_slot_increase, SSNES_STATE_SLOT_PLUS)
DECLARE_BIND(state_slot_decrease, SSNES_STATE_SLOT_MINUS)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
},
@ -418,6 +418,8 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY)
DECLARE_BIND(save_state, SSNES_SAVE_STATE_KEY)
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(state_slot_increase, SSNES_STATE_SLOT_PLUS)
DECLARE_BIND(state_slot_decrease, SSNES_STATE_SLOT_MINUS)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
},
@ -437,6 +439,8 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY)
DECLARE_BIND(save_state, SSNES_SAVE_STATE_KEY)
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(state_slot_increase, SSNES_STATE_SLOT_PLUS)
DECLARE_BIND(state_slot_decrease, SSNES_STATE_SLOT_MINUS)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
},
@ -456,6 +460,8 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY)
DECLARE_BIND(save_state, SSNES_SAVE_STATE_KEY)
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(state_slot_increase, SSNES_STATE_SLOT_PLUS)
DECLARE_BIND(state_slot_decrease, SSNES_STATE_SLOT_MINUS)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
},
@ -475,6 +481,8 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(toggle_fast_forward, SSNES_FAST_FORWARD_KEY)
DECLARE_BIND(save_state, SSNES_SAVE_STATE_KEY)
DECLARE_BIND(load_state, SSNES_LOAD_STATE_KEY)
DECLARE_BIND(state_slot_increase, SSNES_STATE_SLOT_PLUS)
DECLARE_BIND(state_slot_decrease, SSNES_STATE_SLOT_MINUS)
DECLARE_BIND(exit_emulator, SSNES_QUIT_KEY)
DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY)
},

129
ssnes.c
View File

@ -626,6 +626,102 @@ static void fill_pathnames(void)
}
}
// Save or load state here.
static void check_savestates(void)
{
static bool old_should_savestate = false;
bool should_savestate = driver.input->key_pressed(driver.input_data, SSNES_SAVE_STATE_KEY);
if (should_savestate && !old_should_savestate)
{
char save_path[strlen(g_extern.savestate_name) * 2];
snprintf(save_path, sizeof(save_path), g_extern.state_slot > 0 ? "%s%u" : "%s", g_extern.savestate_name, g_extern.state_slot);
if(!save_state(save_path))
{
msg_queue_clear(g_extern.msg_queue);
char msg[512];
snprintf(msg, sizeof(msg), "Failed to save state to \"%s\"", save_path);
msg_queue_push(g_extern.msg_queue, msg, 2, 180);
}
else
{
msg_queue_clear(g_extern.msg_queue);
msg_queue_push(g_extern.msg_queue, "Saved state!", 1, 180);
}
}
old_should_savestate = should_savestate;
static bool old_should_loadstate = false;
bool should_loadstate = driver.input->key_pressed(driver.input_data, SSNES_LOAD_STATE_KEY);
if (!should_savestate && should_loadstate && !old_should_loadstate)
{
char load_path[strlen(g_extern.savestate_name) * 2];
snprintf(load_path, sizeof(load_path), g_extern.state_slot ? "%s%u" : "%s", g_extern.savestate_name, g_extern.state_slot);
if(!load_state(load_path))
{
msg_queue_clear(g_extern.msg_queue);
char msg[512];
snprintf(msg, sizeof(msg), "Failed to load state from \"%s\"", load_path);
msg_queue_push(g_extern.msg_queue, msg, 2, 180);
}
else
{
msg_queue_clear(g_extern.msg_queue);
msg_queue_push(g_extern.msg_queue, "Loaded state!", 1, 180);
}
}
old_should_loadstate = should_loadstate;
}
static void check_fullscreen(void)
{
// If we go fullscreen we drop all drivers and reinit to be safe.
if (driver.input->key_pressed(driver.input_data, SSNES_FULLSCREEN_TOGGLE_KEY))
{
g_settings.video.fullscreen = !g_settings.video.fullscreen;
uninit_drivers();
init_drivers();
}
}
static void check_stateslots(void)
{
// Save state slots
static bool old_should_slot_increase = false;
bool should_slot_increase = driver.input->key_pressed(driver.input_data, SSNES_STATE_SLOT_PLUS);
if (should_slot_increase && !old_should_slot_increase)
{
g_extern.state_slot++;
msg_queue_clear(g_extern.msg_queue);
char msg[256];
snprintf(msg, sizeof(msg), "Save state slot: %u", g_extern.state_slot);
msg_queue_push(g_extern.msg_queue, msg, 1, 180);
}
old_should_slot_increase = should_slot_increase;
static bool old_should_slot_decrease = false;
bool should_slot_decrease = driver.input->key_pressed(driver.input_data, SSNES_STATE_SLOT_MINUS);
if (should_slot_decrease && !old_should_slot_decrease)
{
if (g_extern.state_slot > 0)
g_extern.state_slot--;
msg_queue_clear(g_extern.msg_queue);
char msg[256];
snprintf(msg, sizeof(msg), "Save state slot: %u", g_extern.state_slot);
msg_queue_push(g_extern.msg_queue, msg, 1, 180);
}
old_should_slot_decrease = should_slot_decrease;
}
static void do_state_checks(void)
{
set_fast_forward_button(driver.input->key_pressed(driver.input_data, SSNES_FAST_FORWARD_KEY));
check_stateslots();
check_savestates();
check_fullscreen();
}
int main(int argc, char *argv[])
{
@ -669,38 +765,9 @@ int main(int argc, char *argv[])
!driver.video->alive(driver.video_data))
break;
set_fast_forward_button(driver.input->key_pressed(driver.input_data, SSNES_FAST_FORWARD_KEY));
// Save or load state here.
// Checks for stuff like fullscreen, save states, etc.
do_state_checks();
static bool old_should_savestate = false;
bool should_savestate = driver.input->key_pressed(driver.input_data, SSNES_SAVE_STATE_KEY);
if (should_savestate && !old_should_savestate)
{
msg_queue_clear(g_extern.msg_queue);
msg_queue_push(g_extern.msg_queue, "Saving state!", 1, 180);
save_state(g_extern.savestate_name);
}
old_should_savestate = should_savestate;
static bool old_should_loadstate = false;
bool should_loadstate = driver.input->key_pressed(driver.input_data, SSNES_LOAD_STATE_KEY);
if (!should_savestate && should_loadstate && !old_should_loadstate)
{
msg_queue_clear(g_extern.msg_queue);
msg_queue_push(g_extern.msg_queue, "Loading state!", 1, 180);
load_state(g_extern.savestate_name);
}
old_should_loadstate = should_loadstate;
// If we go fullscreen we drop all drivers and reinit to be safe.
if (driver.input->key_pressed(driver.input_data, SSNES_FULLSCREEN_TOGGLE_KEY))
{
g_settings.video.fullscreen = !g_settings.video.fullscreen;
uninit_drivers();
init_drivers();
}
// Run libsnes for one frame.
psnes_run();
}

View File

@ -37,7 +37,7 @@
# CPU-based filter. Valid ones are: hq2x, hq4x, grayscale, bleed, ntsc.
# video_filter = ntsc
# Path to a TTF font used for rendering messages.
# Path to a TTF font used for rendering messages. This path must be defined to enable fonts.
# video_font_path =
# Size of the TTF font rendered.
@ -166,6 +166,11 @@
# Loads state.
# input_load_state = f4
# State slots. With slot set to 0, save state name is *.state (or whatever defined on commandline).
# When slot is != 0, path will be $path%d, where %d is slot number.
# input_state_slot_increase = f7
# input_state_slot_decrease = f6
# Toggles between fast-forwarding and normal speed.
# input_toggle_fast_forward = space