Compare commits

...
29 Commits
Author SHA1 Message Date
Themaister d679f8b24f v0.4.1 updates. 2011-04-26 19:00:50 +02:00
Themaister d2f2ab6a9d Windowed width with xscale depends on aspect ratio. 2011-04-24 02:44:02 +02:00
Themaister 3e1e08ca9a Variadic shifts. Optimizes the path when format matches. 2011-04-23 19:15:15 +02:00
Themaister bb93f20be9 Hopefully make conversions more portable ... 2011-04-23 18:33:56 +02:00
Themaister 54dc289cde SDL fixes. 2011-04-23 18:06:48 +02:00
Themaister fcebad2589 FreeConsole() to avoid ugly console. 2011-04-23 14:47:50 +02:00
Themaister 4b60f98603 Might fix some odd warnings. 2011-04-22 04:27:53 +02:00
Themaister d304960c21 0.4.1-beta I suppose. 2011-04-22 03:17:31 +02:00
Themaister 8da13b716a Simple font rendering with SDL. 2011-04-22 03:13:09 +02:00
Themaister a6c08a24d7 Fix 32-bit 2011-04-21 14:30:54 +02:00
Themaister 6713272809 Hrm... Seems to work, except for 32-bit -> 32-bit <_< 2011-04-21 13:12:45 +02:00
Themaister 8d7cf23b40 Meh, SDL performs like shit :p 2011-04-21 03:39:03 +02:00
Themaister d317a9773f Start on SDL video driver. 2011-04-21 03:23:44 +02:00
Themaister e8806c48c9 Default keybinds and stuff. 2011-04-17 16:55:31 +02:00
Themaister abd7bab43a Cheat support... Somewhat. 2011-04-17 16:53:19 +02:00
Themaister 66464c2cce Parsing seems to work at least. 2011-04-17 15:58:18 +02:00
Themaister 092fa9d531 Get initial cheat support down. 2011-04-17 13:30:59 +02:00
Themaister 1005d7fa9b SHA256 support. Now onto cheats ... 2011-04-17 12:29:58 +02:00
Themaister 079549cbd2 Fix an edge case with strlcat(). 2011-04-11 21:28:03 +02:00
Themaister 0f0a4d0a5e Fix fullscreen state flickering with XVideo. 2011-04-09 13:15:14 +02:00
Themaister f0bbeb901d Fix some error handling for XVideo. 2011-04-08 20:53:11 +02:00
Themaister 8027a25016 Fix include issue in windows. 2011-04-07 21:31:58 +02:00
Themaister a1426c96f8 Update for Win32. 2011-04-07 21:26:02 +02:00
Themaister a4c901df57 Bit more logging when saving SRAM to be sure. 0.4! :D 2011-04-07 21:20:11 +02:00
Themaister f2cc19d1a7 Some fixups for SGB etc. 2011-04-07 21:06:31 +02:00
Themaister ad55829890 Convert to strlcpy/strlcat. More sane. 2011-04-03 22:29:36 +02:00
Themaister 6b8eea6363 Start with strlcpy/strlcat ... 2011-04-03 22:16:59 +02:00
Themaister b2d214ee79 Should fix path issues with UPS patching.
When filename had two dots ('.') in it,
using fill_pathname on g_extern.basename was wrong.
Added fill_pathname_noext to countermeasure this.
2011-04-03 21:43:25 +02:00
Themaister f5fb113563 Should fix case where we have 1 pass and scale attributes. 2011-03-30 23:09:29 +02:00
25 changed files with 1328 additions and 102 deletions

No files matched your search

+7 -3
View File
@@ -2,7 +2,7 @@ include config.mk
TARGET = ssnes tools/ssnes-joyconfig
OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o
OBJ = ssnes.o file.o driver.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o strl.o
JOYCONFIG_OBJ = tools/ssnes-joyconfig.o conf/config_file.o
HEADERS = $(wildcard */*.h) $(wildcard *.h)
@@ -67,7 +67,7 @@ ifeq ($(HAVE_PULSE), 1)
endif
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/gl.o input/sdl.o audio/sdl.o audio/buffer.o
OBJ += gfx/sdl.o gfx/gl.o input/sdl.o audio/sdl.o audio/buffer.o
DEFINES += $(SDL_CFLAGS)
LIBS += $(SDL_LIBS)
ifeq ($(OSX),1)
@@ -92,7 +92,7 @@ ifeq ($(HAVE_CG), 1)
endif
ifeq ($(HAVE_XML), 1)
OBJ += gfx/shader_glsl.o
OBJ += gfx/shader_glsl.o sha256.o cheats.o
LIBS += $(XML_LIBS)
DEFINES += $(XML_CFLAGS)
endif
@@ -119,6 +119,10 @@ else
LIBS += $(libsnes)
endif
ifeq ($(HAVE_STRL), 1)
DEFINES += -DHAVE_STRL
endif
ifneq ($(V),1)
Q := @
endif
+4 -4
View File
@@ -1,6 +1,6 @@
TARGET = ssnes.exe
JTARGET = ssnes-joyconfig.exe
OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o
OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o movie.o autosave.o gfx/gfx_common.o ups.o strl.o
JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o
CC = gcc
@@ -33,7 +33,7 @@ else
endif
ifeq ($(HAVE_SDL), 1)
OBJ += gfx/gl.o input/sdl.o audio/sdl.o audio/buffer.o
OBJ += gfx/sdl.o gfx/gl.o input/sdl.o audio/sdl.o audio/buffer.o
LIBS += $(SDL_LIBS) -lopengl32
DEFINES += $(SDL_CFLAGS) -DHAVE_SDL
endif
@@ -50,7 +50,7 @@ ifeq ($(HAVE_RSOUND), 1)
endif
ifeq ($(HAVE_XML), 1)
OBJ += gfx/shader_glsl.o
OBJ += gfx/shader_glsl.o sha256.o cheats.o
DEFINES += $(XML_CFLAGS) -DHAVE_XML
LIBS += -lxml2
endif
@@ -116,7 +116,7 @@ clean:
rm -f tools/*.o
dist: all
zip -r ssnes-win32-0.4-beta.zip $(TARGET) ssnes.cfg snes.dll libxml2.dll iconv.dll zlib1.dll SDL.dll freetype6.dll xaudio-c.dll rsound.dll pthreadGC2.dll README.win32.txt $(JTARGET)
zip -r ssnes-win32-0.4.1.zip $(TARGET) ssnes.cfg snes.dll libxml2.dll iconv.dll zlib1.dll SDL.dll freetype6.dll xaudio-c.dll rsound.dll pthreadGC2.dll README.win32.txt $(JTARGET)
libs:
wget https://github.com/downloads/Themaister/SSNES/SSNES-win32-libs.zip --no-check-certificate
+261
View File
@@ -0,0 +1,261 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "cheats.h"
#include "sha256.h"
#include "dynamic.h"
#include "general.h"
#include "strl.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
struct cheat
{
char *desc;
bool state;
char *code;
};
struct cheat_manager
{
struct cheat *cheats;
unsigned ptr;
unsigned size;
unsigned buf_size;
};
static char* strcat_alloc(char *dest, const char *input)
{
size_t dest_len = dest ? strlen(dest) : 0;
size_t input_len = strlen(input);
size_t required_len = dest_len + input_len + 1;
char *output = realloc(dest, required_len);
assert(output);
if (dest)
strlcat(output, input, required_len);
else
strlcpy(output, input, required_len);
return output;
}
static void xml_grab_cheat(struct cheat *cht, xmlNodePtr ptr)
{
memset(cht, 0, sizeof(struct cheat));
bool first = true;
for (xmlNodePtr node = ptr; node; node = node->next)
{
if (strcmp((const char*)node->name, "description") == 0)
{
cht->desc = (char*)xmlNodeGetContent(node);
}
else if (strcmp((const char*)node->name, "code") == 0)
{
if (!first)
cht->code = strcat_alloc(cht->code, "+");
xmlChar *code = xmlNodeGetContent(node);
assert(code);
cht->code = strcat_alloc(cht->code, (const char*)code);
xmlFree(code);
first = false;
}
}
}
static void xml_grab_cheats(cheat_manager_t *handle, xmlNodePtr ptr)
{
xmlNodePtr node = NULL;
for (node = ptr; node; node = node->next)
{
if (strcmp((const char*)node->name, "name") == 0)
{
xmlChar *name = xmlNodeGetContent(node);
if (name)
{
SSNES_LOG("Found cheat for game: \"%s\"\n", name);
xmlFree(name);
}
}
else if (strcmp((const char*)node->name, "cheat") == 0)
{
if (handle->size == handle->buf_size)
{
handle->buf_size *= 2;
handle->cheats = realloc(handle->cheats, handle->buf_size * sizeof(struct cheat));
assert(handle->cheats);
}
xml_grab_cheat(&handle->cheats[handle->size++], node->children);
}
}
}
cheat_manager_t* cheat_manager_new(const char *path)
{
psnes_cheat_reset();
xmlParserCtxtPtr ctx = NULL;
xmlDocPtr doc = NULL;
cheat_manager_t *handle = calloc(1, sizeof(handle));
if (!handle)
return NULL;
handle->buf_size = 32;
handle->cheats = malloc(handle->buf_size * sizeof(struct cheat));
if (!handle->cheats)
{
handle->buf_size = 0;
goto error;
}
ctx = xmlNewParserCtxt();
if (!ctx)
goto error;
doc = xmlCtxtReadFile(ctx, path, NULL, 0);
if (!doc)
{
SSNES_ERR("Failed to parse XML file: %s\n", path);
goto error;
}
if (ctx->valid == 0)
{
SSNES_ERR("Cannot validate XML file: %s\n", path);
goto error;
}
xmlNodePtr head = xmlDocGetRootElement(doc);
xmlNodePtr cur = NULL;
for (cur = head; cur; cur = cur->next)
{
if (cur->type == XML_ELEMENT_NODE && strcmp((const char*)cur->name, "database") == 0)
break;
}
if (!cur)
goto error;
for (cur = cur->children; cur; cur = cur->next)
{
if (cur->type != XML_ELEMENT_NODE)
continue;
if (strcmp((const char*)cur->name, "cartridge") == 0)
{
xmlChar *sha256 = xmlGetProp(cur, (const xmlChar*)"sha256");
if (!sha256)
continue;
if (memcmp(sha256, g_extern.sha256, 64) == 0)
{
xmlFree(sha256);
break;
}
xmlFree(sha256);
}
}
if (!cur)
goto error;
xml_grab_cheats(handle, cur->children);
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctx);
return handle;
error:
cheat_manager_free(handle);
if (doc)
xmlFreeDoc(doc);
if (ctx)
xmlFreeParserCtxt(ctx);
return NULL;
}
void cheat_manager_free(cheat_manager_t *handle)
{
if (!handle)
return;
if (handle->cheats)
{
for (unsigned i = 0; i < handle->size; i++)
{
xmlFree(handle->cheats[i].desc);
free(handle->cheats[i].code);
}
free(handle->cheats);
}
free(handle);
}
static void cheat_manager_update(cheat_manager_t *handle)
{
msg_queue_clear(g_extern.msg_queue);
char msg[256];
snprintf(msg, sizeof(msg), "Cheat: #%u [%s]: %s", handle->ptr, handle->cheats[handle->ptr].state ? "ON" : "OFF", handle->cheats[handle->ptr].desc);
msg_queue_push(g_extern.msg_queue, msg, 1, 180);
SSNES_LOG("%s\n", msg);
}
void cheat_manager_toggle(cheat_manager_t *handle)
{
handle->cheats[handle->ptr].state ^= true;
unsigned index = 0;
psnes_cheat_reset();
for (unsigned i = 0; i < handle->size; i++)
{
if (handle->cheats[handle->ptr].state)
psnes_cheat_set(index++, true, handle->cheats[handle->ptr].code);
}
cheat_manager_update(handle);
}
void cheat_manager_index_next(cheat_manager_t *handle)
{
handle->ptr = (handle->ptr + 1) % handle->size;
cheat_manager_update(handle);
}
void cheat_manager_index_prev(cheat_manager_t *handle)
{
if (handle->ptr == 0)
handle->ptr = handle->size - 1;
else
handle->ptr--;
cheat_manager_update(handle);
}
+30
View File
@@ -0,0 +1,30 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_CHEATS_H
#define __SSNES_CHEATS_H
typedef struct cheat_manager cheat_manager_t;
cheat_manager_t* cheat_manager_new(const char *path);
void cheat_manager_free(cheat_manager_t *handle);
void cheat_manager_index_next(cheat_manager_t *handle);
void cheat_manager_index_prev(cheat_manager_t *handle);
void cheat_manager_toggle(cheat_manager_t *handle);
#endif
+7
View File
@@ -44,6 +44,7 @@
///////////////// Drivers
#define VIDEO_GL 0
#define VIDEO_XVIDEO 11
#define VIDEO_SDL 13
////////////////////////
#define AUDIO_RSOUND 1
#define AUDIO_OSS 2
@@ -107,6 +108,9 @@ static const bool fullscreen = false; // To start in Fullscreen or not
static const unsigned fullscreen_x = 0; // Fullscreen resolution. A value of 0 uses the desktop resolution.
static const unsigned fullscreen_y = 0;
// Force 16-bit colors.
static const bool force_16bit = false;
// Video VSYNC (recommended)
static const bool vsync = true;
@@ -223,6 +227,9 @@ static const struct snes_keybind snes_keybinds_1[] = {
{ SSNES_RESET, SDLK_h, NO_BTN, AXIS_NONE },
{ SSNES_SHADER_NEXT, SDLK_m, NO_BTN, AXIS_NONE },
{ SSNES_SHADER_PREV, SDLK_n, NO_BTN, AXIS_NONE },
{ SSNES_CHEAT_INDEX_PLUS, SDLK_y, NO_BTN, AXIS_NONE },
{ SSNES_CHEAT_INDEX_MINUS, SDLK_t, NO_BTN, AXIS_NONE },
{ SSNES_CHEAT_TOGGLE, SDLK_u, NO_BTN, AXIS_NONE },
{ -1 }
};
+4
View File
@@ -131,5 +131,9 @@ Network port used for netplay. This defaults to 55435. This option affects both
Attempts to apply an UPS patch to the current ROM image. No files are altered.
If this flag is not specified, SSNES will look for a .ups file with same basename as ROM specified.
.TP
\fB-D, --detach\fR
Detach from the current console. This is currently only relevant for Microsoft Windows.
.SH "SEE ALSO"
\fBssnes-joyconfig\fR(1)
+2 -1
View File
@@ -61,6 +61,7 @@ static const audio_driver_t *audio_drivers[] = {
static const video_driver_t *video_drivers[] = {
#ifdef HAVE_SDL
&video_gl,
&video_sdl,
#endif
#ifdef HAVE_XVIDEO
&video_xvideo,
@@ -336,7 +337,7 @@ void init_video_input(void)
scale = g_extern.filter.scale;
video_info_t video = {
.width = (g_settings.video.fullscreen) ? g_settings.video.fullscreen_x : (296 * g_settings.video.xscale),
.width = (g_settings.video.fullscreen) ? g_settings.video.fullscreen_x : (224 * g_settings.video.xscale * g_settings.video.aspect_ratio),
.height = (g_settings.video.fullscreen) ? g_settings.video.fullscreen_y : (224 * g_settings.video.yscale),
.fullscreen = g_settings.video.fullscreen,
.vsync = g_settings.video.vsync,
+5 -1
View File
@@ -42,6 +42,9 @@ enum
SSNES_RESET,
SSNES_SHADER_NEXT,
SSNES_SHADER_PREV,
SSNES_CHEAT_INDEX_PLUS,
SSNES_CHEAT_INDEX_MINUS,
SSNES_CHEAT_TOGGLE
};
@@ -108,7 +111,7 @@ typedef struct input_driver
typedef struct video_driver
{
void* (*init)(video_info_t *video, const input_driver_t **input, void **input_data);
void* (*init)(const video_info_t *video, const input_driver_t **input, void **input_data);
// Should the video driver act as an input driver as well? :) The video init might preinitialize an input driver to override the settings in case the video driver relies on input driver for event handling, e.g.
bool (*frame)(void* data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg); // msg is for showing a message on the screen along with the video frame.
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
@@ -153,6 +156,7 @@ extern const audio_driver_t audio_xa;
extern const audio_driver_t audio_pulse;
extern const video_driver_t video_gl;
extern const video_driver_t video_xvideo;
extern const video_driver_t video_sdl;
extern const input_driver_t input_sdl;
extern const input_driver_t input_x;
////////////////////////////////////////////////
+7
View File
@@ -57,6 +57,9 @@ void (*psnes_set_input_state)(snes_input_state_t);
void (*psnes_reset)(void);
void (*psnes_run)(void);
void (*psnes_cheat_reset)(void);
void (*psnes_cheat_set)(unsigned, bool, const char*);
const char *(*psnes_library_id)(void) = NULL;
unsigned (*psnes_library_revision_minor)(void);
unsigned (*psnes_library_revision_major)(void);
@@ -111,6 +114,8 @@ static void load_dynamic(void)
OPT_SYM(snes_library_id);
SYM(snes_library_revision_minor);
SYM(snes_library_revision_major);
SYM(snes_cheat_reset);
SYM(snes_cheat_set);
SYM(snes_reset);
SYM(snes_run);
SYM(snes_get_region);
@@ -145,6 +150,8 @@ static void set_statics(void)
SSYM(snes_set_input_state);
SSYM(snes_library_revision_minor);
SSYM(snes_library_revision_major);
SSYM(snes_cheat_reset);
SSYM(snes_cheat_set);
SSYM(snes_reset);
SSYM(snes_run);
SSYM(snes_get_region);
+3
View File
@@ -37,6 +37,9 @@ extern void (*psnes_set_audio_sample)(snes_audio_sample_t);
extern void (*psnes_set_input_poll)(snes_input_poll_t);
extern void (*psnes_set_input_state)(snes_input_state_t);
extern void (*psnes_cheat_reset)(void);
extern void (*psnes_cheat_set)(unsigned, bool, const char*);
extern const char* (*psnes_library_id)(void);
extern unsigned (*psnes_library_revision_minor)(void);
extern unsigned (*psnes_library_revision_major)(void);
+18 -30
View File
@@ -24,6 +24,11 @@
#include "dynamic.h"
#include "movie.h"
#include "ups.h"
#include "strl.h"
#ifdef HAVE_XML
#include "sha256.h"
#endif
#ifdef _WIN32
#include <io.h>
@@ -164,9 +169,9 @@ static ssize_t read_rom_file(FILE* file, void** buf)
}
}
else if (*g_extern.ups_name)
SSNES_LOG("Could not find UPS patch.\n");
SSNES_LOG("Could not find UPS patch in: \"%s\".\n", g_extern.ups_name);
// Remove SMC header if present.
// Remove copier header if present (512 first bytes).
if ((ret & 0x7fff) == 512)
{
memmove(ret_buf, ret_buf + 512, ret - 512);
@@ -174,6 +179,10 @@ static ssize_t read_rom_file(FILE* file, void** buf)
}
g_extern.cart_crc = crc32_calculate(ret_buf, ret);
#ifdef HAVE_XML
sha256_hash(g_extern.sha256, ret_buf, ret);
SSNES_LOG("SHA256 sum: %s\n", g_extern.sha256);
#endif
*buf = ret_buf;
return ret;
}
@@ -257,7 +266,7 @@ void save_ram_file(const char* path, int type)
size_t size = psnes_get_memory_size(type);
uint8_t *data = psnes_get_memory_data(type);
if ( data && size > 0 )
if (data && size > 0)
dump_to_file(path, data, size);
}
@@ -276,14 +285,7 @@ static bool load_sgb_rom(void)
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_rom_file(extra_rom, &extra_rom_buf)) == -1)
if ((extra_rom_len = read_file(g_extern.gb_rom_path, &extra_rom_buf)) == -1)
{
SSNES_ERR("Cannot read GameBoy rom.\n");
goto error;
@@ -330,14 +332,7 @@ static bool load_bsx_rom(bool slotted)
goto error;
}
extra_rom = fopen(g_extern.bsx_rom_path, "rb");
if (!extra_rom)
{
SSNES_ERR("Couldn't open BSX game rom!\n");
goto error;
}
if ((extra_rom_len = read_rom_file(extra_rom, &extra_rom_buf)) == -1)
if ((extra_rom_len = read_file(g_extern.bsx_rom_path, &extra_rom_buf)) == -1)
{
SSNES_ERR("Cannot read BSX game rom.\n");
goto error;
@@ -404,16 +399,9 @@ static bool load_sufami_rom(void)
{
if (strlen(roms[i]) > 0)
{
extra_rom[i] = fopen(roms[i], "rb");
if (!extra_rom[i])
if ((extra_rom_len[i] = read_file(roms[i], &extra_rom_buf[i])) == -1)
{
SSNES_ERR("Couldn't open BSX game rom!\n");
goto error;
}
if ((extra_rom_len[i] = read_rom_file(extra_rom[i], &extra_rom_buf[i])) == -1)
{
SSNES_ERR("Cannot read BSX game rom.\n");
SSNES_ERR("Cannot read Sufami game rom.\n");
goto error;
}
}
@@ -537,8 +525,8 @@ char** dir_list_new(const char *dir, const char *ext)
wchar_t wchar_buf[MAX_PATH + 1];
char utf8_buf[MAX_PATH + 3];
strncpy(utf8_buf, dir, MAX_PATH);
strcat(utf8_buf, "/*");
strlcpy(utf8_buf, dir, sizeof(utf8_buf));
strlcat(utf8_buf, "/*", sizeof(utf8_buf));
utf8_buf[MAX_PATH + 2] = '\0';
int ret = MultiByteToWideChar(CP_UTF8, 0, utf8_buf, strlen(utf8_buf), wchar_buf, MAX_PATH);
+10 -1
View File
@@ -29,6 +29,7 @@
#include "autosave.h"
#include "netplay.h"
#include "dynamic.h"
#include "cheats.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -42,7 +43,7 @@
#define MAX_PLAYERS 5
#define MAX_BINDS 28 // Needs to be increased every time there are new binds added.
#define MAX_BINDS 31 // Needs to be increased every time there are new binds added.
#define SSNES_NO_JOYPAD 0xFFFF
enum ssnes_shader_type
@@ -85,6 +86,7 @@ struct settings
float msg_pos_x;
float msg_pos_y;
bool force_16bit;
} video;
struct
@@ -110,6 +112,7 @@ struct settings
} input;
char libsnes[256];
char cheat_database[256];
bool rewind_enable;
unsigned rewind_buffer_size;
@@ -243,6 +246,12 @@ struct global
size_t size;
size_t ptr;
} shader_dir;
char sha256[65];
#ifdef HAVE_XML
cheat_manager_t *cheat;
#endif
};
void parse_config(void);
+1 -1
View File
@@ -35,7 +35,7 @@ bool gfx_window_title(char *buf, size_t size)
if (frames == 0)
{
gettimeofday(&tv, NULL);
snprintf(buf, size, g_extern.title_buf);
snprintf(buf, size, "%s", g_extern.title_buf);
ret = true;
}
+15 -11
View File
@@ -320,7 +320,15 @@ static inline void gl_init_font(gl_t *gl, const char *font_path, unsigned font_s
static void gl_init_fbo(gl_t *gl, unsigned width, unsigned height)
{
#ifdef HAVE_FBO
if (!g_settings.video.render_to_texture && gl_shader_num() <= 1)
if (!g_settings.video.render_to_texture && gl_shader_num() == 0)
return;
struct gl_fbo_scale scale, scale_last;
gl_shader_scale(1, &scale);
gl_shader_scale(gl_shader_num(), &scale_last);
// No need to use FBOs.
if (gl_shader_num() == 1 && !scale.valid && !g_settings.video.render_to_texture)
return;
if (!load_fbo_proc())
@@ -330,13 +338,12 @@ static void gl_init_fbo(gl_t *gl, unsigned width, unsigned height)
}
gl->fbo_pass = gl_shader_num() - 1;
struct gl_fbo_scale scale;
gl_shader_scale(gl_shader_num(), &scale);
if (scale.valid)
if (scale_last.valid)
gl->fbo_pass++;
gl_shader_scale(1, &scale);
if (gl->fbo_pass <= 0)
gl->fbo_pass = 1;
if (!scale.valid)
{
scale.scale_x = g_settings.video.fbo_scale_x;
@@ -385,9 +392,6 @@ static void gl_init_fbo(gl_t *gl, unsigned width, unsigned height)
SSNES_LOG("Creating FBO 0 @ %ux%u\n", gl->fbo_rect[0].width, gl->fbo_rect[0].height);
if (gl->fbo_pass <= 0)
gl->fbo_pass = 1;
for (int i = 1; i < gl->fbo_pass; i++)
{
gl_shader_scale(i + 1, &gl->fbo_scale[i]);
@@ -889,7 +893,7 @@ static void gl_set_nonblock_state(void *data, bool state)
}
}
static void* gl_init(video_info_t *video, const input_driver_t **input, void **input_data)
static void* gl_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
return NULL;
@@ -903,7 +907,7 @@ static void* gl_init(video_info_t *video, const input_driver_t **input, void **i
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, video->vsync ? 1 : 0);
if (!SDL_SetVideoMode(video->width, video->height, 0, SDL_OPENGL | SDL_RESIZABLE | (video->fullscreen ? SDL_FULLSCREEN : 0)))
if (!SDL_SetVideoMode(video->width, video->height, g_settings.video.force_16bit ? 16 : 0, SDL_OPENGL | SDL_RESIZABLE | (video->fullscreen ? SDL_FULLSCREEN : 0)))
return NULL;
// Remove that ugly mouse :D
+497
View File
@@ -0,0 +1,497 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "SDL.h"
#include "driver.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "general.h"
#include "input/ssnes_sdl_input.h"
#include "gfx_common.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_FREETYPE
#include "fonts.h"
#endif
static void convert_15bit_15bit_direct(uint16_t *out, unsigned outpitch, const uint16_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt);
static void convert_32bit_32bit_direct(uint32_t *out, unsigned outpitch, const uint32_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt);
static void convert_15bit_15bit_shift(uint16_t *out, unsigned outpitch, const uint16_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt);
static void convert_32bit_32bit_shift(uint32_t *out, unsigned outpitch, const uint32_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt);
typedef struct sdl_video sdl_video_t;
struct sdl_video
{
SDL_Surface *screen, *buffer;
bool quitting;
bool rgb32;
bool upsample;
void (*convert_15_func)(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned, const SDL_PixelFormat*);
void (*convert_32_func)(uint32_t*, unsigned, const uint32_t*, unsigned, unsigned, unsigned, const SDL_PixelFormat*);
#ifdef HAVE_FREETYPE
font_renderer_t *font;
#endif
};
static void sdl_gfx_free(void *data)
{
sdl_video_t *vid = data;
if (!vid)
return;
if (vid->buffer)
SDL_FreeSurface(vid->buffer);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
#ifdef HAVE_FREETYPE
if (vid->font)
font_renderer_free(vid->font);
#endif
free(vid);
}
static void sdl_init_font(sdl_video_t *vid, const char *font_path, unsigned font_size)
{
#ifdef HAVE_FREETYPE
if (*font_path)
{
vid->font = font_renderer_new(font_path, font_size);
if (!vid->font)
SSNES_WARN("Failed to init font.\n");
}
#else
(void)vid;
(void)font_path;
(void)font_size;
#endif
}
// Not very optimized, but hey :D
static void sdl_render_msg_15(sdl_video_t *vid, SDL_Surface *buffer, const char *msg, unsigned width, unsigned height, const SDL_PixelFormat *fmt)
{
#ifdef HAVE_FREETYPE
struct font_output_list out;
font_renderer_msg(vid->font, msg, &out);
struct font_output *head = out.head;
int base_x = g_settings.video.msg_pos_x * width;
int base_y = (1.0 - g_settings.video.msg_pos_y) * height;
unsigned rshift = fmt->Rshift;
unsigned gshift = fmt->Gshift;
unsigned bshift = fmt->Bshift;
while (head)
{
int rbase_x = base_x + head->off_x;
int rbase_y = base_y - head->off_y;
if (rbase_y >= 0)
{
for (int y = 0; y < head->height && (y + rbase_y) < height; y++)
{
if (rbase_x < 0)
continue;
const uint8_t *a = head->output + head->pitch * y;
uint16_t *out = (uint16_t*)buffer->pixels + (rbase_y - head->height + y) * (buffer->pitch >> 1) + rbase_x;
for (int x = 0; x < head->width && (x + rbase_x) < width; x++)
{
unsigned blend = a[x];
unsigned out_pix = out[x];
unsigned r = (out_pix >> rshift) & 0x1f;
unsigned g = (out_pix >> gshift) & 0x1f;
unsigned b = (out_pix >> bshift) & 0x1f;
unsigned out_r = (r * (256 - blend) + 0x1f * blend) >> 8;
unsigned out_g = (g * (256 - blend) + 0x1f * blend) >> 8;
unsigned out_b = (b * (256 - blend) + 0x1f * blend) >> 8;
out[x] = (out_r << rshift) | (out_g << gshift) | (out_b << bshift);
}
}
}
head = head->next;
}
font_renderer_free_output(&out);
#else
(void)vid;
(void)buffer;
(void)msg;
(void)width;
(void)height;
#endif
}
static void sdl_render_msg_32(sdl_video_t *vid, SDL_Surface *buffer, const char *msg, unsigned width, unsigned height, const SDL_PixelFormat *fmt)
{
#ifdef HAVE_FREETYPE
struct font_output_list out;
font_renderer_msg(vid->font, msg, &out);
struct font_output *head = out.head;
int base_x = g_settings.video.msg_pos_x * width;
int base_y = (1.0 - g_settings.video.msg_pos_y) * height;
unsigned rshift = fmt->Rshift;
unsigned gshift = fmt->Gshift;
unsigned bshift = fmt->Bshift;
while (head)
{
int rbase_x = base_x + head->off_x;
int rbase_y = base_y - head->off_y;
if (rbase_y >= 0)
{
for (int y = 0; y < head->height && (y + rbase_y) < height; y++)
{
if (rbase_x < 0)
continue;
const uint8_t *a = head->output + head->pitch * y;
uint32_t *out = (uint32_t*)buffer->pixels + (rbase_y - head->height + y) * (buffer->pitch >> 2) + rbase_x;
for (int x = 0; x < head->width && (x + rbase_x) < width; x++)
{
unsigned blend = a[x];
unsigned out_pix = out[x];
unsigned r = (out_pix >> rshift) & 0xff;
unsigned g = (out_pix >> gshift) & 0xff;
unsigned b = (out_pix >> bshift) & 0xff;
unsigned out_r = (r * (256 - blend) + 0xff * blend) >> 8;
unsigned out_g = (g * (256 - blend) + 0xff * blend) >> 8;
unsigned out_b = (b * (256 - blend) + 0xff * blend) >> 8;
out[x] = (out_r << rshift) | (out_g << gshift) | (out_b << bshift);
}
}
}
head = head->next;
}
font_renderer_free_output(&out);
#else
(void)vid;
(void)buffer;
(void)msg;
(void)width;
(void)height;
#endif
}
static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
SDL_InitSubSystem(SDL_INIT_VIDEO);
sdl_video_t *vid = calloc(1, sizeof(*vid));
if (!vid)
return NULL;
const SDL_VideoInfo *video_info = SDL_GetVideoInfo();
assert(video_info);
unsigned full_x = video_info->current_w;
unsigned full_y = video_info->current_h;
SSNES_LOG("Detecting desktop resolution %ux%u.\n", full_x, full_y);
if (!video->fullscreen)
SSNES_LOG("Creating window @ %ux%u\n", video->width, video->height);
vid->screen = SDL_SetVideoMode(video->width, video->height, (g_settings.video.force_16bit || !video->rgb32) ? 15 : 32, SDL_HWSURFACE | SDL_HWACCEL | SDL_DOUBLEBUF | (video->fullscreen ? SDL_FULLSCREEN : 0));
if (!vid->screen && !g_settings.video.force_16bit && !video->rgb32)
{
vid->upsample = true;
vid->screen = SDL_SetVideoMode(video->width, video->height, 32, SDL_HWSURFACE | SDL_HWACCEL | SDL_DOUBLEBUF | (video->fullscreen ? SDL_FULLSCREEN : 0));
SSNES_WARN("SDL: 15-bit colors failed, attempting 32-bit colors.\n");
}
if (!vid->screen)
{
SSNES_ERR("Failed to init SDL surface: %s\n", SDL_GetError());
goto error;
}
SDL_ShowCursor(SDL_DISABLE);
const SDL_PixelFormat *fmt = vid->screen->format;
if (!g_settings.video.force_16bit && (video->rgb32 || vid->upsample))
{
SSNES_LOG("SDL: Creating 32-bit buffer.\n");
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 32,
fmt->Rmask, fmt->Bmask, fmt->Gmask, fmt->Amask);
}
else
{
SSNES_LOG("SDL: Creating 15-bit buffer.\n");
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 15,
fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
}
SSNES_LOG("[Debug]: SDL Pixel format: Rshift = %u, Gshift = %u, Bshift = %u\n",
(unsigned)fmt->Rshift, (unsigned)fmt->Gshift, (unsigned)fmt->Bshift);
if (!vid->buffer)
{
SSNES_ERR("SDL_CreateRGBSurface failed: %s\n", SDL_GetError());
goto error;
}
sdl_input_t *sdl_input = input_sdl.init();
if (sdl_input)
{
sdl_input->quitting = &vid->quitting;
*input = &input_sdl;
*input_data = sdl_input;
}
else
*input = NULL;
vid->rgb32 = video->rgb32;
sdl_init_font(vid, g_settings.video.font_path, g_settings.video.font_size);
if (fmt->Rshift == 10 && fmt->Gshift == 5 && fmt->Bshift == 0)
{
SSNES_LOG("SDL: 15-bit format matches. Fast blit.\n");
vid->convert_15_func = convert_15bit_15bit_direct;
}
else
{
SSNES_LOG("SDL: 15-bit format does not match. Needs conversion.\n");
vid->convert_15_func = convert_15bit_15bit_shift;
}
if (fmt->Rshift == 24 && fmt->Gshift == 16 && fmt->Bshift == 8)
{
SSNES_LOG("SDL: 32-bit format matches. Fast blit.\n");
vid->convert_32_func = convert_32bit_32bit_direct;
}
else
{
SSNES_LOG("SDL: 32-bit format does not match. Needs conversion.\n");
vid->convert_32_func = convert_32bit_32bit_shift;
}
return vid;
error:
sdl_gfx_free(vid);
return NULL;
}
static inline uint16_t conv_pixel_32_15(uint32_t pix, const SDL_PixelFormat *fmt)
{
uint16_t r = ((pix & 0xf8000000) >> 27) << fmt->Rshift;
uint16_t g = ((pix & 0x00f80000) >> 19) << fmt->Gshift;
uint16_t b = ((pix & 0x0000f800) >> 11) << fmt->Bshift;
return r | g | b;
}
static inline uint32_t conv_pixel_15_32(uint16_t pix, const SDL_PixelFormat *fmt)
{
uint32_t r = ((pix >> 10) & 0x1f) << (fmt->Rshift + 3);
uint32_t g = ((pix >> 5) & 0x1f) << (fmt->Gshift + 3);
uint32_t b = ((pix >> 0) & 0x1f) << (fmt->Bshift + 3);
return r | g | b;
}
static void convert_32bit_15bit(uint16_t *out, unsigned outpitch, const uint32_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt)
{
for (unsigned y = 0; y < height; y++)
{
for (unsigned x = 0; x < width; x++)
out[x] = conv_pixel_32_15(input[x], fmt);
out += outpitch >> 1;
input += pitch >> 2;
}
}
static void convert_15bit_32bit(uint32_t *out, unsigned outpitch, const uint16_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt)
{
for (unsigned y = 0; y < height; y++)
{
for (unsigned x = 0; x < width; x++)
out[x] = conv_pixel_15_32(input[x], fmt);
out += outpitch >> 2;
input += pitch >> 1;
}
}
static void convert_15bit_15bit_direct(uint16_t *out, unsigned outpitch, const uint16_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt)
{
for (unsigned y = 0; y < height; y++)
{
uint16_t *dest = out + ((y * outpitch) >> 1);
const uint16_t *src = input + ((y * pitch) >> 1);
memcpy(dest, src, width * sizeof(uint16_t));
}
(void)fmt;
}
static void convert_32bit_32bit_direct(uint32_t *out, unsigned outpitch, const uint32_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt)
{
for (unsigned y = 0; y < height; y++)
{
uint32_t *dest = out + ((y * outpitch) >> 2);
const uint32_t *src = input + ((y * pitch) >> 2);
memcpy(dest, src, width * sizeof(uint32_t));
}
(void)fmt;
}
static void convert_15bit_15bit_shift(uint16_t *out, unsigned outpitch, const uint16_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt)
{
for (unsigned y = 0; y < height; y++)
{
uint16_t *dest = out + ((y * outpitch) >> 1);
const uint16_t *src = input + ((y * pitch) >> 1);
for (unsigned x = 0; x < width; x++)
{
uint16_t color = src[x];
uint16_t r = ((color >> 10) & 0x1f) << fmt->Rshift;
uint16_t g = ((color >> 5) & 0x1f) << fmt->Gshift;
uint16_t b = ((color >> 0) & 0x1f) << fmt->Bshift;
dest[x] = r | g | b;
}
}
}
static void convert_32bit_32bit_shift(uint32_t *out, unsigned outpitch, const uint32_t *input, unsigned width, unsigned height, unsigned pitch, const SDL_PixelFormat *fmt)
{
for (unsigned y = 0; y < height; y++)
{
uint32_t *dest = out + ((y * outpitch) >> 2);
const uint32_t *src = input + ((y * pitch) >> 2);
for (unsigned x = 0; x < width; x++)
{
uint32_t color = src[x];
uint32_t r = ((color >> 24) & 0xff) << fmt->Rshift;
uint32_t g = ((color >> 16) & 0xff) << fmt->Gshift;
uint32_t b = ((color >> 8) & 0xff) << fmt->Bshift;
dest[x] = r | g | b;
}
}
}
static bool sdl_gfx_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
sdl_video_t *vid = data;
if (SDL_MUSTLOCK(vid->buffer))
SDL_LockSurface(vid->buffer);
// :(
// 15-bit -> 32-bit (Sometimes 15-bit won't work on "modern" OSes :\)
if (vid->upsample)
{
convert_15bit_32bit(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch, vid->screen->format);
}
// 15-bit -> 15-bit
else if (!vid->rgb32)
{
vid->convert_15_func(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch, vid->screen->format);
}
// 32-bit -> 15-bit
else if (vid->rgb32 && g_settings.video.force_16bit)
{
convert_32bit_15bit(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch, vid->screen->format);
}
// 32-bit -> 32-bit
else
{
vid->convert_32_func(vid->buffer->pixels, vid->buffer->pitch, frame, width, height, pitch, vid->screen->format);
}
if (msg)
{
if ((!vid->rgb32 || g_settings.video.force_16bit) && !vid->upsample)
sdl_render_msg_15(vid, vid->buffer, msg, width, height, vid->screen->format);
else
sdl_render_msg_32(vid, vid->buffer, msg, width, height, vid->screen->format);
}
if (SDL_MUSTLOCK(vid->buffer))
SDL_UnlockSurface(vid->buffer);
SDL_Rect src = {
.x = 0,
.y = 0,
.w = width,
.h = height
};
SDL_Rect dest = {
.x = 0,
.y = 0,
.w = vid->screen->w,
.h = vid->screen->h
};
SDL_SoftStretch(vid->buffer, &src, vid->screen, &dest);
char buf[128];
if (gfx_window_title(buf, sizeof(buf)))
SDL_WM_SetCaption(buf, NULL);
SDL_Flip(vid->screen);
return true;
}
static void sdl_gfx_set_nonblock_state(void *data, bool state)
{
(void)data; // Can SDL even do this?
(void)state;
}
static bool sdl_gfx_alive(void *data)
{
sdl_video_t *vid = data;
return !vid->quitting;
}
static bool sdl_gfx_focus(void *data)
{
(void)data;
return (SDL_GetAppState() & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) == (SDL_APPINPUTFOCUS | SDL_APPACTIVE);
}
const video_driver_t video_sdl = {
.init = sdl_gfx_init,
.frame = sdl_gfx_frame,
.alive = sdl_gfx_alive,
.set_nonblock_state = sdl_gfx_set_nonblock_state,
.focus = sdl_gfx_focus,
.free = sdl_gfx_free,
.ident = "sdl"
};
+5 -5
View File
@@ -77,7 +77,7 @@ static void xv_set_nonblock_state(void *data, bool state)
{
xv_t *xv = data;
Atom atom = XInternAtom(xv->display, "XV_SYNC_TO_VBLANK", true);
if (atom != None && xv->port >= 0)
if (atom != None && xv->port)
XvSetPortAttribute(xv->display, xv->port, atom, !state);
else
SSNES_WARN("Failed to set SYNC_TO_VBLANK attribute.\n");
@@ -177,7 +177,7 @@ static void xv_init_font(xv_t *xv, const char *font_path, unsigned font_size)
{
xv->font = font_renderer_new(font_path, font_size);
if (!xv->font)
SSNES_WARN("Failed to init font\n");
SSNES_WARN("Failed to init font.\n");
}
#endif
}
@@ -298,7 +298,7 @@ static void render32_uyvy(xv_t *xv, const void *input_, unsigned width, unsigned
}
static void* xv_init(video_info_t *video, const input_driver_t **input, void **input_data)
static void* xv_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
xv_t *xv = calloc(1, sizeof(*xv));
if (!xv)
@@ -315,7 +315,7 @@ static void* xv_init(video_info_t *video, const input_driver_t **input, void **i
xv->keep_aspect = video->force_aspect;
// Find an appropriate Xv port.
xv->port = -1;
xv->port = 0;
XvAdaptorInfo *adaptor_info;
unsigned adaptor_count = 0;
XvQueryAdaptors(xv->display, DefaultRootWindow(xv->display), &adaptor_count, &adaptor_info);
@@ -333,7 +333,7 @@ static void* xv_init(video_info_t *video, const input_driver_t **input, void **i
}
XvFreeAdaptorInfo(adaptor_info);
if (xv->port < 0)
if (xv->port == 0)
{
SSNES_ERR("XVideo: Failed to find valid XvPort.\n");
goto error;
+3 -1
View File
@@ -61,8 +61,10 @@ check_lib DYNAMIC -ldl dlopen
check_pkgconf FREETYPE freetype2
check_lib XVIDEO -lXv XvShmCreateImage
check_lib STRL -lc strlcpy
# Creates config.mk and config.h.
VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL FILTER CG XML DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO"
VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL FILTER CG XML DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL"
create_config_make config.mk $VARS
create_config_header config.h $VARS
+1 -1
View File
@@ -1,7 +1,7 @@
. qb/qb.params.sh
PACKAGE_NAME=ssnes
PACKAGE_VERSION=0.4-beta
PACKAGE_VERSION=0.4.1
# Adds a command line opt to ./configure --help
# $1: Variable (HAVE_ALSA, HAVE_OSS, etc)
+28 -6
View File
@@ -18,7 +18,7 @@
#include "general.h"
#include "conf/config_file.h"
#include <assert.h>
#include <string.h>
#include "strl.h"
#include "config.def.h"
#ifdef HAVE_CONFIG_H
@@ -47,6 +47,9 @@ static void set_defaults(void)
case VIDEO_XVIDEO:
def_video = "xvideo";
break;
case VIDEO_SDL:
def_video = "sdl";
break;
default:
break;
}
@@ -94,17 +97,18 @@ static void set_defaults(void)
}
if (def_video)
strncpy(g_settings.video.driver, def_video, sizeof(g_settings.video.driver) - 1);
strlcpy(g_settings.video.driver, def_video, sizeof(g_settings.video.driver));
if (def_audio)
strncpy(g_settings.audio.driver, def_audio, sizeof(g_settings.audio.driver) - 1);
strlcpy(g_settings.audio.driver, def_audio, sizeof(g_settings.audio.driver));
if (def_input)
strncpy(g_settings.input.driver, def_input, sizeof(g_settings.input.driver) - 1);
strlcpy(g_settings.input.driver, def_input, sizeof(g_settings.input.driver));
g_settings.video.xscale = xscale;
g_settings.video.yscale = yscale;
g_settings.video.fullscreen = fullscreen;
g_settings.video.fullscreen_x = fullscreen_x;
g_settings.video.fullscreen_y = fullscreen_y;
g_settings.video.force_16bit = force_16bit;
g_settings.video.vsync = vsync;
g_settings.video.smooth = video_smooth;
g_settings.video.force_aspect = force_aspect;
@@ -129,7 +133,7 @@ static void set_defaults(void)
g_settings.audio.in_rate = in_rate;
g_settings.audio.rate_step = audio_rate_step;
if (audio_device)
strncpy(g_settings.audio.device, audio_device, sizeof(g_settings.audio.device));
strlcpy(g_settings.audio.device, audio_device, sizeof(g_settings.audio.device));
g_settings.audio.latency = out_latency;
g_settings.audio.sync = audio_sync;
@@ -244,7 +248,7 @@ static config_file_t *open_default_config_file(void)
#define CONFIG_GET_STRING(var, key) do { \
if (config_get_string(conf, key, &tmp_str)) \
{ \
strncpy(g_settings.var, tmp_str, sizeof(g_settings.var) - 1); \
strlcpy(g_settings.var, tmp_str, sizeof(g_settings.var)); \
free(tmp_str); \
} \
} while(0)
@@ -282,6 +286,7 @@ static void parse_config_file(void)
CONFIG_GET_INT(video.fullscreen_x, "video_fullscreen_x");
CONFIG_GET_INT(video.fullscreen_y, "video_fullscreen_y");
CONFIG_GET_BOOL(video.fullscreen, "video_fullscreen");
CONFIG_GET_BOOL(video.force_16bit, "video_force_16bit");
CONFIG_GET_BOOL(video.vsync, "video_vsync");
CONFIG_GET_BOOL(video.smooth, "video_smooth");
CONFIG_GET_BOOL(video.force_aspect, "video_force_aspect");
@@ -369,6 +374,8 @@ static void parse_config_file(void)
CONFIG_GET_BOOL(pause_nonactive, "pause_nonactive");
CONFIG_GET_INT(autosave_interval, "autosave_interval");
CONFIG_GET_STRING(cheat_database, "cheat_database_path");
read_keybinds(conf);
config_file_free(conf);
@@ -414,6 +421,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
{
DECLARE_BIND(player2_a, SNES_DEVICE_ID_JOYPAD_A)
@@ -443,6 +453,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
{
DECLARE_BIND(player3_a, SNES_DEVICE_ID_JOYPAD_A)
@@ -472,6 +485,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
{
DECLARE_BIND(player4_a, SNES_DEVICE_ID_JOYPAD_A)
@@ -501,6 +517,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
{
DECLARE_BIND(player5_a, SNES_DEVICE_ID_JOYPAD_A)
@@ -530,6 +549,9 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(reset, SSNES_RESET)
DECLARE_BIND(shader_next, SSNES_SHADER_NEXT)
DECLARE_BIND(shader_prev, SSNES_SHADER_PREV)
DECLARE_BIND(cheat_index_plus, SSNES_CHEAT_INDEX_PLUS)
DECLARE_BIND(cheat_index_minus, SSNES_CHEAT_INDEX_MINUS)
DECLARE_BIND(cheat_toggle, SSNES_CHEAT_TOGGLE)
},
};
+180
View File
@@ -0,0 +1,180 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
// SHA256 implementation from bSNES. Written by valditx.
//
#include "sha256.h"
#include <string.h>
#include <stdio.h>
#define PTR(t, a) ((t*)(a))
#define SWAP32(x) ((uint32_t)( \
(((uint32_t)(x) & 0x000000ff) << 24) | \
(((uint32_t)(x) & 0x0000ff00) << 8) | \
(((uint32_t)(x) & 0x00ff0000) >> 8) | \
(((uint32_t)(x) & 0xff000000) >> 24) \
))
#define ST32(a, d) *PTR(uint32_t, a) = (d)
#define ST32BE(a, d) ST32(a, SWAP32(d))
#define LD32(a) *PTR(uint32_t, a)
#define LD32BE(a) SWAP32(LD32(a))
#define LSL32(x, n) ((uint32_t)(x) << (n))
#define LSR32(x, n) ((uint32_t)(x) >> (n))
#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))
// First 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
static const uint32_t T_H[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
};
// First 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
static const uint32_t T_K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
};
struct sha256_ctx
{
uint8_t in[64];
unsigned inlen;
uint32_t w[64];
uint32_t h[8];
uint64_t len;
};
static void sha256_init(struct sha256_ctx *p)
{
memset(p, 0, sizeof(struct sha256_ctx));
memcpy(p->h, T_H, sizeof(T_H));
}
static void sha256_block(struct sha256_ctx *p)
{
unsigned i;
uint32_t s0, s1;
uint32_t a, b, c, d, e, f, g, h;
uint32_t t1, t2, maj, ch;
for (i = 0; i < 16; i++)
p->w[i] = LD32BE(p->in + i * 4);
for (i = 16; i < 64; i++)
{
s0 = ROR32(p->w[i - 15], 7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15], 3);
s1 = ROR32(p->w[i - 2], 17) ^ ROR32(p->w[i - 2], 19) ^ LSR32(p->w[i - 2], 10);
p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1;
}
a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3];
e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7];
for (i = 0; i < 64; i++)
{
s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);
maj = (a & b) ^ (a & c) ^ (b & c);
t2 = s0 + maj;
s1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);
ch = (e & f) ^ (~e & g);
t1 = h + s1 + ch + T_K[i] + p->w[i];
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d;
p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h;
// Next block
p->inlen = 0;
}
static void sha256_chunk(struct sha256_ctx *p, const uint8_t *s, unsigned len)
{
unsigned l;
p->len += len;
while (len)
{
l = 64 - p->inlen;
l = (len < l) ? len : l;
memcpy(p->in + p->inlen, s, l);
s += l;
p->inlen += l;
len -= l;
if (p->inlen == 64)
sha256_block(p);
}
}
static void sha256_final(struct sha256_ctx *p)
{
uint64_t len;
p->in[p->inlen++] = 0x80;
if (p->inlen > 56)
{
memset(p->in + p->inlen, 0, 64 - p->inlen);
sha256_block(p);
}
memset(p->in + p->inlen, 0, 56 - p->inlen);
len = p->len << 3;
ST32BE(p->in + 56, len >> 32);
ST32BE(p->in + 60, len);
sha256_block(p);
}
static void sha256_subhash(struct sha256_ctx *p, uint32_t *t)
{
for (unsigned i = 0; i < 8; i++)
ST32BE(t++, p->h[i]);
}
void sha256_hash(char *out, const uint8_t *in, size_t size)
{
struct sha256_ctx sha;
union
{
uint32_t u32[8];
uint8_t u8[32];
} shahash;
sha256_init(&sha);
sha256_chunk(&sha, in, size);
sha256_final(&sha);
sha256_subhash(&sha, shahash.u32);
for (unsigned i = 0; i < 32; i++)
snprintf(out + 2 * i, 3, "%02x", (unsigned)shahash.u8[i]);
}
+28
View File
@@ -0,0 +1,28 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_SHA256_H
#define __SSNES_SHA256_H
#include <stdint.h>
#include <stddef.h>
// Hashes sha256 and outputs a human readable string for comparing with the cheat XML values.
void sha256_hash(char *out, const uint8_t *in, size_t size);
#endif
+110 -36
View File
@@ -31,6 +31,8 @@
#include "rewind.h"
#include "movie.h"
#include "netplay.h"
#include "strl.h"
#include "cheats.h"
#include <assert.h>
#ifdef HAVE_SRC
#include <samplerate.h>
@@ -220,16 +222,22 @@ static int16_t input_state(bool port, unsigned device, unsigned index, unsigned
return res;
}
static void fill_pathname(char *out_path, char *in_path, const char *replace)
static void fill_pathname(char *out_path, const char *in_path, const char *replace, size_t size)
{
char tmp_path[strlen(in_path) + 1];
strcpy(tmp_path, in_path);
strlcpy(tmp_path, in_path, sizeof(tmp_path));
char *tok = NULL;
tok = strrchr(tmp_path, '.');
if (tok != NULL)
*tok = '\0';
strcpy(out_path, tmp_path);
strcat(out_path, replace);
assert(strlcpy(out_path, tmp_path, size) < size);
assert(strlcat(out_path, replace, size) < size);
}
static void fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size)
{
assert(strlcpy(out_path, in_path, size) < size);
assert(strlcat(out_path, replace, size) < size);
}
#ifdef _WIN32
@@ -241,7 +249,7 @@ static void fill_pathname(char *out_path, char *in_path, const char *replace)
#endif
#ifdef _WIN32
#define PACKAGE_VERSION "0.4-beta"
#define PACKAGE_VERSION "0.4.1"
#endif
#include "config.features.h"
@@ -308,7 +316,8 @@ static void print_help(void)
puts("\t-r/--record: Path to record video file. Settings for video/audio codecs are found in config file.");
#endif
puts("\t-v/--verbose: Verbose logging");
puts("\t-U/--ups: Specifies path for UPS patch that will be applied to ROM.\n");
puts("\t-U/--ups: Specifies path for UPS patch that will be applied to ROM.");
puts("\t-D/--detach: Detach SSNES from the running console. Not relevant for all platforms.\n");
print_features();
}
@@ -320,7 +329,7 @@ static void set_basename(const char *path)
char *dst = strrchr(tmp, '.');
if (dst)
*dst = '\0';
strncpy(g_extern.basename, tmp, sizeof(g_extern.basename) - 1);
strlcpy(g_extern.basename, tmp, sizeof(g_extern.basename));
}
static void parse_input(int argc, char *argv[])
@@ -360,6 +369,7 @@ static void parse_input(int argc, char *argv[])
{ "frames", 1, NULL, 'F' },
{ "port", 1, &val, 'p' },
{ "ups", 1, NULL, 'U' },
{ "detach", 0, NULL, 'D' },
{ NULL, 0, NULL, 0 }
};
@@ -377,7 +387,7 @@ static void parse_input(int argc, char *argv[])
#define CONFIG_FILE_ARG
#endif
char optstring[] = "hs:vS:m:p4jJg:b:B:Y:Z:P:HC:F:U:" FFMPEG_RECORD_ARG CONFIG_FILE_ARG;
char optstring[] = "hs:vS:m:p4jJg:b:B:Y:Z:P:HC:F:U:D" FFMPEG_RECORD_ARG CONFIG_FILE_ARG;
for(;;)
{
val = 0;
@@ -406,37 +416,37 @@ static void parse_input(int argc, char *argv[])
break;
case 's':
strncpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm) - 1);
strlcpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm));
g_extern.has_set_save_path = true;
break;
case 'g':
strncpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path) - 1);
strlcpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path));
g_extern.game_type = SSNES_CART_SGB;
break;
case 'b':
strncpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path) - 1);
strlcpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path));
g_extern.game_type = SSNES_CART_BSX;
break;
case 'B':
strncpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path) - 1);
strlcpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path));
g_extern.game_type = SSNES_CART_BSX_SLOTTED;
break;
case 'Y':
strncpy(g_extern.sufami_rom_path[0], optarg, sizeof(g_extern.sufami_rom_path[0]) - 1);
strlcpy(g_extern.sufami_rom_path[0], optarg, sizeof(g_extern.sufami_rom_path[0]));
g_extern.game_type = SSNES_CART_SUFAMI;
break;
case 'Z':
strncpy(g_extern.sufami_rom_path[1], optarg, sizeof(g_extern.sufami_rom_path[1]) - 1);
strlcpy(g_extern.sufami_rom_path[1], optarg, sizeof(g_extern.sufami_rom_path[1]));
g_extern.game_type = SSNES_CART_SUFAMI;
break;
case 'S':
strncpy(g_extern.savestate_name, optarg, sizeof(g_extern.savestate_name) - 1);
strlcpy(g_extern.savestate_name, optarg, sizeof(g_extern.savestate_name));
g_extern.has_set_state_path = true;
break;
@@ -461,19 +471,19 @@ static void parse_input(int argc, char *argv[])
#ifdef HAVE_CONFIGFILE
case 'c':
strncpy(g_extern.config_path, optarg, sizeof(g_extern.config_path) - 1);
strlcpy(g_extern.config_path, optarg, sizeof(g_extern.config_path));
break;
#endif
#ifdef HAVE_FFMPEG
case 'r':
strncpy(g_extern.record_path, optarg, sizeof(g_extern.record_path) - 1);
strlcpy(g_extern.record_path, optarg, sizeof(g_extern.record_path));
g_extern.recording = true;
break;
#endif
case 'P':
strncpy(g_extern.bsv_movie_path, optarg, sizeof(g_extern.bsv_movie_path) - 1);
strlcpy(g_extern.bsv_movie_path, optarg, sizeof(g_extern.bsv_movie_path));
g_extern.bsv_movie_playback = true;
break;
@@ -483,7 +493,7 @@ static void parse_input(int argc, char *argv[])
case 'C':
g_extern.netplay_enable = true;
strncpy(g_extern.netplay_server, optarg, sizeof(g_extern.netplay_server) - 1);
strlcpy(g_extern.netplay_server, optarg, sizeof(g_extern.netplay_server));
break;
case 'F':
@@ -493,7 +503,13 @@ static void parse_input(int argc, char *argv[])
break;
case 'U':
strncpy(g_extern.ups_name, optarg, sizeof(g_extern.ups_name) - 1);
strlcpy(g_extern.ups_name, optarg, sizeof(g_extern.ups_name));
break;
case 'D':
#ifdef _WIN32
FreeConsole();
#endif
break;
case 0:
@@ -530,9 +546,9 @@ static void parse_input(int argc, char *argv[])
}
// strl* would be nice :D
if (!g_extern.has_set_save_path)
fill_pathname(g_extern.savefile_name_srm, g_extern.basename, ".srm");
fill_pathname_noext(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm));
if (!g_extern.has_set_state_path)
fill_pathname(g_extern.savestate_name, g_extern.basename, ".state");
fill_pathname_noext(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
}
else if (strlen(g_extern.savefile_name_srm) == 0)
{
@@ -619,22 +635,26 @@ static inline void save_files(void)
switch (g_extern.game_type)
{
case SSNES_CART_NORMAL:
SSNES_LOG("Saving regular SRAM.\n");
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM);
save_ram_file(g_extern.savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);
break;
case SSNES_CART_SGB:
SSNES_LOG("Saving Gameboy SRAM.\n");
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_GAME_BOY_RAM);
save_ram_file(g_extern.savefile_name_rtc, SNES_MEMORY_GAME_BOY_RTC);
break;
case SSNES_CART_BSX:
case SSNES_CART_BSX_SLOTTED:
SSNES_LOG("Saving BSX (P)RAM.\n");
save_ram_file(g_extern.savefile_name_srm, SNES_MEMORY_BSX_RAM);
save_ram_file(g_extern.savefile_name_psrm, SNES_MEMORY_BSX_PRAM);
break;
case SSNES_CART_SUFAMI:
SSNES_LOG("Saving Sufami turbo A/B RAM.\n");
save_ram_file(g_extern.savefile_name_asrm, SNES_MEMORY_SUFAMI_TURBO_A_RAM);
save_ram_file(g_extern.savefile_name_bsrm, SNES_MEMORY_SUFAMI_TURBO_B_RAM);
break;
@@ -697,6 +717,20 @@ static void deinit_msg_queue(void)
msg_queue_free(g_extern.msg_queue);
}
#ifdef HAVE_XML
static void init_cheats(void)
{
if (*g_settings.cheat_database)
g_extern.cheat = cheat_manager_new(g_settings.cheat_database);
}
static void deinit_cheats(void)
{
if (g_extern.cheat)
cheat_manager_free(g_extern.cheat);
}
#endif
static void init_rewind(void)
{
if (g_settings.rewind_enable)
@@ -851,37 +885,37 @@ static void fill_pathnames(void)
case SSNES_CART_BSX_SLOTTED:
// BSX PSRM
if (!g_extern.has_set_save_path)
fill_pathname(g_extern.savefile_name_srm, g_extern.bsx_rom_path, ".srm");
fill_pathname(g_extern.savefile_name_srm, g_extern.bsx_rom_path, ".srm", sizeof(g_extern.savefile_name_srm));
if (!g_extern.has_set_state_path)
fill_pathname(g_extern.savestate_name, g_extern.bsx_rom_path, ".state");
fill_pathname(g_extern.savefile_name_psrm, g_extern.savefile_name_srm, ".psrm");
fill_pathname(g_extern.savestate_name, g_extern.bsx_rom_path, ".state", sizeof(g_extern.savestate_name));
fill_pathname(g_extern.savefile_name_psrm, g_extern.savefile_name_srm, ".psrm", sizeof(g_extern.savefile_name_psrm));
break;
case SSNES_CART_SUFAMI:
// SUFAMI ARAM
fill_pathname(g_extern.savefile_name_asrm, g_extern.savefile_name_srm, ".asrm");
fill_pathname(g_extern.savefile_name_asrm, g_extern.savefile_name_srm, ".asrm", sizeof(g_extern.savefile_name_asrm));
// SUFAMI BRAM
fill_pathname(g_extern.savefile_name_bsrm, g_extern.savefile_name_srm, ".bsrm");
fill_pathname(g_extern.savefile_name_bsrm, g_extern.savefile_name_srm, ".bsrm", sizeof(g_extern.savefile_name_bsrm));
break;
case SSNES_CART_SGB:
if (!g_extern.has_set_save_path)
fill_pathname(g_extern.savefile_name_srm, g_extern.gb_rom_path, ".srm");
fill_pathname(g_extern.savefile_name_srm, g_extern.gb_rom_path, ".srm", sizeof(g_extern.savefile_name_srm));
if (!g_extern.has_set_state_path)
fill_pathname(g_extern.savestate_name, g_extern.gb_rom_path, ".state");
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc");
fill_pathname(g_extern.savestate_name, g_extern.gb_rom_path, ".state", sizeof(g_extern.savestate_name));
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc", sizeof(g_extern.savefile_name_rtc));
break;
default:
// Infer .rtc save path from save ram path.
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc");
fill_pathname(g_extern.savefile_name_rtc, g_extern.savefile_name_srm, ".rtc", sizeof(g_extern.savefile_name_rtc));
}
if (!g_extern.bsv_movie_playback)
fill_pathname(g_extern.bsv_movie_path, g_extern.savefile_name_srm, "");
fill_pathname(g_extern.bsv_movie_path, g_extern.savefile_name_srm, "", sizeof(g_extern.bsv_movie_path));
if (!(*g_extern.ups_name) && *g_extern.basename)
fill_pathname(g_extern.ups_name, g_extern.basename, ".ups");
fill_pathname_noext(g_extern.ups_name, g_extern.basename, ".ups", sizeof(g_extern.ups_name));
}
// Save or load state here.
@@ -942,13 +976,17 @@ static void check_savestates(void)
static void check_fullscreen(void)
{
static bool was_pressed = false;
bool pressed;
// 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))
if ((pressed = driver.input->key_pressed(driver.input_data, SSNES_FULLSCREEN_TOGGLE_KEY)) && !was_pressed)
{
g_settings.video.fullscreen = !g_settings.video.fullscreen;
uninit_drivers();
init_drivers();
}
was_pressed = pressed;
}
static void check_stateslots(void)
@@ -1162,7 +1200,7 @@ static void check_reset(void)
static void check_shader_dir(void)
{
static bool old_pressed_next = false;
static bool old_pressed_prev = true;
static bool old_pressed_prev = false;
if (!g_extern.shader_dir.elems || !driver.video->xml_shader)
return;
@@ -1188,7 +1226,7 @@ static void check_shader_dir(void)
{
const char *shader = g_extern.shader_dir.elems[g_extern.shader_dir.ptr];
strncpy(g_settings.video.bsnes_shader_path, shader, sizeof(g_settings.video.bsnes_shader_path) - 1);
strlcpy(g_settings.video.bsnes_shader_path, shader, sizeof(g_settings.video.bsnes_shader_path));
g_settings.video.shader_type = SSNES_SHADER_BSNES;
msg_queue_clear(g_extern.msg_queue);
@@ -1205,6 +1243,31 @@ static void check_shader_dir(void)
old_pressed_prev = pressed_prev;
}
static void check_cheats(void)
{
if (!g_extern.cheat)
return;
static bool old_pressed_prev = false;
static bool old_pressed_next = false;
static bool old_pressed_toggle = false;
bool pressed_next = driver.input->key_pressed(driver.input_data, SSNES_CHEAT_INDEX_PLUS);
bool pressed_prev = driver.input->key_pressed(driver.input_data, SSNES_CHEAT_INDEX_MINUS);
bool pressed_toggle = driver.input->key_pressed(driver.input_data, SSNES_CHEAT_TOGGLE);
if (pressed_next && !old_pressed_next)
cheat_manager_index_next(g_extern.cheat);
else if (pressed_prev && !old_pressed_prev)
cheat_manager_index_prev(g_extern.cheat);
else if (pressed_toggle && !old_pressed_toggle)
cheat_manager_toggle(g_extern.cheat);
old_pressed_prev = pressed_prev;
old_pressed_next = pressed_next;
old_pressed_toggle = pressed_toggle;
}
#endif
static void do_state_checks(void)
@@ -1212,6 +1275,9 @@ static void do_state_checks(void)
if (!g_extern.netplay)
{
check_reset();
#ifdef HAVE_XML
check_cheats();
#endif
check_pause();
if (g_extern.is_paused)
return;
@@ -1264,6 +1330,10 @@ int main(int argc, char *argv[])
if (!init_rom_file(g_extern.game_type))
goto error;
#ifdef HAVE_XML
init_cheats();
#endif
init_msg_queue();
init_movie();
@@ -1365,6 +1435,10 @@ int main(int argc, char *argv[])
if (!g_extern.netplay)
deinit_rewind();
#ifdef HAVE_XML
deinit_cheats();
#endif
deinit_movie();
deinit_msg_queue();
+12 -1
View File
@@ -5,7 +5,7 @@
#### Video
# Windowed xscale and yscale (Real x res: 296 * xscale, real y scale: 224 * xscale)
# Windowed xscale and yscale (Real x res: 224 * xscale * aspect_ratio, real y scale: 224 * xscale)
# video_xscale = 3.0
# video_yscale = 3.0
@@ -16,6 +16,9 @@
# Start in fullscreen. Can be changed at runtime.
# video_fullscreen = false
# Force 16-bit colors. Apparently some video cards in use today have troubles with 32-bit ...
# video_force_16bit = false
# Video vsync.
# video_vsync = true
@@ -252,3 +255,11 @@
# When being client over netplay, use keybinds for player 1.
# netplay_client_swap_input = false
# Path to XML cheat database (as used by bSNES).
# cheat_database_path =
# Cheats.
# input_cheat_index_plus = y
# input_cheat_index_minus = t
# input_cheat_toggle = u
+52
View File
@@ -0,0 +1,52 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "strl.h"
#ifndef HAVE_STRL
// Implementation of strlcpy()/strlcat() based on OpenBSD.
size_t strlcpy(char *dest, const char *source, size_t size)
{
size_t src_size = 0;
size_t n = size;
if (n)
while (--n && (*dest++ = *source++)) src_size++;
if (!n)
{
if (size) *dest = '\0';
while (*source++) src_size++;
}
return src_size;
}
size_t strlcat(char *dest, const char *source, size_t size)
{
size_t len = strlen(dest);
dest += len;
if (len > size)
size = 0;
else
size -= len;
return len + strlcpy(dest, source, size);
}
#endif
+38
View File
@@ -0,0 +1,38 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_STRL_H
#define __SSNES_STRL_H
#include <string.h>
#include <stddef.h>
#ifdef HAVE_CONFIG
#include "config.h"
#endif
#ifndef HAVE_STRL
// Avoid possible naming collitions during link since we prefer to use the actual name.
#define strlcpy(dst, src, size) __strlcpy_ssnes(dst, src, size)
#define strlcat(dst, src, size) __strlcat_ssnes(dst, src, size)
size_t strlcpy(char *dest, const char *source, size_t size);
size_t strlcat(char *dest, const char *source, size_t size);
#endif
#endif