Skip to content

Commit

Permalink
Add save state slots.
Browse files Browse the repository at this point in the history
  • Loading branch information
Themaister committed Jan 23, 2011
1 parent 2267c7d commit 17663bb
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 54 deletions.
2 changes: 2 additions & 0 deletions config.def.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
};

Expand Down
2 changes: 2 additions & 0 deletions driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 13 additions & 6 deletions file.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,54 +135,61 @@ static ssize_t read_file(const char *path, void **buf)
}

// 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);
psnes_unserialize(buf, size);
}

free(buf);
return true;
}

void load_ram_file(const char* path, int type)
Expand Down
4 changes: 2 additions & 2 deletions file.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion general.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -126,6 +126,8 @@ struct global
char savefile_name_bsrm[512];
char savestate_name[256];

unsigned state_slot;

struct
{
float *data;
Expand Down
25 changes: 14 additions & 11 deletions gfx/gl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
12 changes: 10 additions & 2 deletions settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
},
Expand All @@ -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)
},
Expand All @@ -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)
},
Expand All @@ -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)
},
Expand All @@ -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)
},
Expand Down
129 changes: 98 additions & 31 deletions ssnes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[])
{
Expand Down Expand Up @@ -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();
}
Expand Down
7 changes: 6 additions & 1 deletion ssnes.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit 17663bb

Please sign in to comment.