Add some more abstractions for file loading. Also add initial SGB rom

loading!
This commit is contained in:
Themaister 2011-01-12 18:05:57 +01:00
parent 90a5059b5b
commit e6aa065781
6 changed files with 203 additions and 62 deletions

View File

@ -52,6 +52,10 @@ unsigned (*psnes_library_revision_minor)(void);
unsigned (*psnes_library_revision_major)(void);
bool (*psnes_load_cartridge_normal)(const char*, const uint8_t*, unsigned);
bool (*psnes_load_cartridge_super_game_boy)(
const char*, const uint8_t*, unsigned,
const char*, const uint8_t*, unsigned);
void (*psnes_set_controller_port_device)(bool, unsigned);
bool (*psnes_get_region)(void);
@ -89,6 +93,7 @@ static void load_dynamic(void)
SYM(snes_run);
SYM(snes_get_region);
SYM(snes_load_cartridge_normal);
SYM(snes_load_cartridge_super_game_boy);
SYM(snes_set_controller_port_device);
SYM(snes_serialize_size);
SYM(snes_serialize);
@ -118,6 +123,7 @@ static void set_statics(void)
SSYM(snes_run);
SSYM(snes_get_region);
SSYM(snes_load_cartridge_normal);
SSYM(snes_load_cartridge_super_game_boy);
SSYM(snes_set_controller_port_device);
SSYM(snes_serialize_size);
SSYM(snes_serialize);

View File

@ -35,6 +35,10 @@ extern unsigned (*psnes_library_revision_minor)(void);
extern unsigned (*psnes_library_revision_major)(void);
extern bool (*psnes_load_cartridge_normal)(const char*, const uint8_t*, unsigned);
extern bool (*psnes_load_cartridge_super_game_boy)(
const char*, const uint8_t*, unsigned,
const char*, const uint8_t*, unsigned);
extern void (*psnes_set_controller_port_device)(bool, unsigned);
extern bool (*psnes_get_region)(void);

104
file.c
View File

@ -165,3 +165,107 @@ void save_file(const char* path, int type)
if ( data && size > 0 )
write_file(path, data, size);
}
static bool load_sgb_rom(void)
{
void *rom_buf;
ssize_t rom_len = 0;
FILE *extra_rom;
void *extra_rom_buf;
ssize_t extra_rom_len = 0;
if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1)
{
SSNES_ERR("Could not read ROM file.\n");
goto error;
}
extra_rom = fopen(g_extern.gb_rom_path, "rb");
if (!extra_rom)
{
SSNES_ERR("Couldn't open GameBoy ROM!\n");
goto error;
}
if ((extra_rom_len = read_file(extra_rom, &extra_rom_buf)) == -1)
{
SSNES_ERR("Cannot read GameBoy rom.\n");
goto error;
}
if (!psnes_load_cartridge_super_game_boy(
NULL, rom_buf, rom_len,
NULL, extra_rom_buf, extra_rom_len))
{
SSNES_ERR("Cannot load SGB/GameBoy rom.\n");
goto error;
}
if (g_extern.rom_file)
fclose(g_extern.rom_file);
if (extra_rom)
fclose(extra_rom);
free(rom_buf);
free(extra_rom_buf);
return true;
error:
if (g_extern.rom_file)
fclose(g_extern.rom_file);
if (extra_rom)
fclose(extra_rom);
free(rom_buf);
free(extra_rom_buf);
return false;
}
static bool load_normal_rom(void)
{
void *rom_buf;
ssize_t rom_len = 0;
if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1)
{
SSNES_ERR("Could not read ROM file.\n");
return false;
}
if (g_extern.rom_file != NULL)
fclose(g_extern.rom_file);
SSNES_LOG("ROM size: %d bytes\n", (int)rom_len);
if (!psnes_load_cartridge_normal(NULL, rom_buf, rom_len))
{
SSNES_ERR("ROM file is not valid!\n");
free(rom_buf);
return false;
}
free(rom_buf);
return true;
}
bool init_rom_file(void)
{
switch (g_extern.game_type)
{
case SSNES_CART_SGB:
if (!load_sgb_rom())
return false;
break;
case SSNES_CART_NORMAL:
if (!load_normal_rom())
return false;
break;
default:
SSNES_ERR("Invalid ROM type!\n");
return false;
}
return true;
}

3
file.h
View File

@ -19,6 +19,7 @@
#ifndef __SSNES_FILE_H
#define __SSNES_FILE_H
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
@ -31,4 +32,6 @@ void write_file(const char* path, uint8_t* data, size_t size);
void load_save_file(const char* path, int type);
void save_file(const char* path, int type);
bool init_rom_file(void);
#endif

View File

@ -78,6 +78,12 @@ struct settings
char libsnes[256];
};
enum ssnes_game_type
{
SSNES_CART_NORMAL = 0,
SSNES_CART_SGB
};
struct global
{
bool verbose;
@ -92,10 +98,15 @@ struct global
bool has_multitap;
FILE *rom_file;
enum ssnes_game_type game_type;
char gb_rom_path[256];
char config_path[256];
char basename[256];
char savefile_name_srm[256];
char savefile_name_rtc[260]; // Make sure that fill_pathname has space.
char savestate_name[256];
#ifdef HAVE_FFMPEG

137
ssnes.c
View File

@ -36,6 +36,7 @@
struct global g_extern = {
.video_active = true,
.audio_active = true,
.game_type = SSNES_CART_NORMAL,
};
// To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then.
@ -237,11 +238,12 @@ static void print_help(void)
puts("=================================================");
puts("ssnes: Simple Super Nintendo Emulator (libsnes)");
puts("=================================================");
puts("Usage: ssnes [rom file] [-h/--help | -c/--config | -v/--verbose | -4/--multitap | -j/--justifier | -k/--justifiers | -t/--savestate | -m/--mouse | -p/--scope | -s/--save" FFMPEG_HELP_QUARK "]");
puts("Usage: ssnes [rom file] [-h/--help | -c/--config | -v/--verbose | -4/--multitap | -j/--justifier | -k/--justifiers | -t/--savestate | -m/--mouse | -g/--gameboy | -p/--scope | -s/--save" FFMPEG_HELP_QUARK "]");
puts("\t-h/--help: Show this help message");
puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin");
puts("\t-t/--savestate: Path to use for save states. If not selected, *.state will be assumed.");
puts("\t-c/--config: Path for config file." SSNES_DEFAULT_CONF_PATH_STR);
puts("\t-g/--gameboy: Path to Gameboy ROM. Load SuperGameBoy as the regular rom.");
puts("\t-m/--mouse: Connect a virtual mouse into designated port of the SNES (1 or 2).");
puts("\t\tThis argument can be specified several times to connect more mice.");
puts("\t-p/--scope: Connect a virtual SuperScope into port 2 of the SNES.");
@ -270,6 +272,7 @@ static void parse_input(int argc, char *argv[])
{ "record", 1, NULL, 'r' },
#endif
{ "verbose", 0, NULL, 'v' },
{ "gameboy", 1, NULL, 'g' },
{ "config", 0, NULL, 'c' },
{ "mouse", 1, NULL, 'm' },
{ "scope", 0, NULL, 'p' },
@ -288,7 +291,7 @@ static void parse_input(int argc, char *argv[])
#define FFMPEG_RECORD_ARG
#endif
char optstring[] = "hs:vc:t:m:p4jk" FFMPEG_RECORD_ARG;
char optstring[] = "hs:vc:t:m:p4jkg:" FFMPEG_RECORD_ARG;
for(;;)
{
int c = getopt_long(argc, argv, optstring, opts, &option_index);
@ -319,6 +322,11 @@ static void parse_input(int argc, char *argv[])
strncpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm) - 1);
break;
case 'g':
strncpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path) - 1);
g_extern.game_type = SSNES_CART_SGB;
break;
case 't':
strncpy(g_extern.savestate_name, optarg, sizeof(g_extern.savestate_name) - 1);
break;
@ -443,63 +451,21 @@ static void init_controllers(void)
}
}
int main(int argc, char *argv[])
static inline void load_save_files(void)
{
parse_input(argc, argv);
parse_config();
init_dlsym();
psnes_init();
if (strlen(g_extern.basename) > 0)
psnes_set_cartridge_basename(g_extern.basename);
SSNES_LOG("Version of libsnes API: %u.%u\n", psnes_library_revision_major(), psnes_library_revision_minor());
void *rom_buf;
ssize_t rom_len = 0;
if ((rom_len = read_file(g_extern.rom_file, &rom_buf)) == -1)
{
SSNES_ERR("Could not read ROM file.\n");
exit(1);
}
SSNES_LOG("ROM size: %d bytes\n", (int)rom_len);
if (g_extern.rom_file != NULL)
fclose(g_extern.rom_file);
// Infer .rtc save path from save ram path.
char savefile_name_rtc[strlen(g_extern.savefile_name_srm)+strlen(".rtc")+1];
fill_pathname(savefile_name_rtc, g_extern.savefile_name_srm, ".rtc");
init_drivers();
psnes_set_video_refresh(video_frame);
psnes_set_audio_sample(audio_sample);
psnes_set_input_poll(input_poll);
psnes_set_input_state(input_state);
// TODO: Load other types of ROMs as well!
if (!psnes_load_cartridge_normal(NULL, rom_buf, rom_len))
{
SSNES_ERR("ROM file is not valid!\n");
goto error;
}
free(rom_buf);
init_controllers();
unsigned serial_size = psnes_serialize_size();
uint8_t *serial_data = malloc(serial_size);
if (serial_data == NULL)
{
SSNES_ERR("Failed to allocate memory for states!\n");
goto error;
}
load_save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM);
load_save_file(savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);
load_save_file(g_extern.savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);
}
static inline void save_files(void)
{
save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM);
save_file(g_extern.savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);
}
#ifdef HAVE_FFMPEG
static void init_recording(void)
{
// Hardcode these options at the moment. Should be specificed in the config file later on.
if (g_extern.recording)
{
@ -525,6 +491,58 @@ int main(int argc, char *argv[])
g_extern.recording = false;
}
}
}
static void deinit_recording(void)
{
if (g_extern.recording)
{
ffemu_finalize(g_extern.rec);
ffemu_free(g_extern.rec);
}
}
#endif
int main(int argc, char *argv[])
{
parse_input(argc, argv);
parse_config();
init_dlsym();
psnes_init();
if (strlen(g_extern.basename) > 0)
psnes_set_cartridge_basename(g_extern.basename);
SSNES_LOG("Version of libsnes API: %u.%u\n", psnes_library_revision_major(), psnes_library_revision_minor());
// Infer .rtc save path from save ram path.
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc");
if (!init_rom_file())
goto error;
init_drivers();
psnes_set_video_refresh(video_frame);
psnes_set_audio_sample(audio_sample);
psnes_set_input_poll(input_poll);
psnes_set_input_state(input_state);
init_controllers();
unsigned serial_size = psnes_serialize_size();
uint8_t *serial_data = malloc(serial_size);
if (serial_data == NULL)
{
SSNES_ERR("Failed to allocate memory for states!\n");
goto error;
}
load_save_files();
#ifdef HAVE_FFMPEG
init_recording();
#endif
// Main loop
@ -556,16 +574,11 @@ int main(int argc, char *argv[])
}
#ifdef HAVE_FFMPEG
if (g_extern.recording)
{
ffemu_finalize(g_extern.rec);
ffemu_free(g_extern.rec);
}
deinit_recording();
#endif
// Flush out SRAM (and RTC)
save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM);
save_file(savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);
save_files();
psnes_unload_cartridge();
psnes_term();