Compare commits

...
24 Commits
Author SHA1 Message Date
Themaister a48dc55c41 Fix ugly possible segfault. 2011-10-30 16:58:45 +01:00
Themaister 202a458524 Updates for 0.9.1. 2011-10-30 11:24:16 +01:00
Themaister b4de704a09 Style nit. 2011-10-30 02:12:00 +02:00
Themaister fef5edfac8 Change default aspect handling. 2011-10-30 01:58:08 +02:00
Themaister a6e74775b1 Edge trigger reset. 2011-10-29 13:35:01 +02:00
Themaister ee66a28d05 Style nit. 2011-10-29 13:33:15 +02:00
Themaister 5e28d82af2 Fix compile with HAVE_CONFIGFILE=0. 2011-10-28 17:10:58 +02:00
Themaister c2a06bfa09 Replace some magic numbers. 2011-10-28 09:06:34 +02:00
Themaister 66510e21aa Fixup build for non dynamic builds. 2011-10-28 00:34:42 +02:00
Themaister ec5e3355b9 Add some logging. 2011-10-28 00:23:49 +02:00
Themaister 0522a2d6a0 Start implementing some minor extensions to libsnes. 2011-10-27 23:40:34 +02:00
Themaister fad89f9d2d More gracious error handling for state tracker. 2011-10-26 19:51:10 +02:00
Themaister 97f937ec6d Use floating point values for uniforms from Python. 2011-10-26 10:26:09 +02:00
Themaister 9647006a2b Merge branch 'master' of github.com:Themaister/SSNES 2011-10-25 23:03:20 +02:00
Themaister 418ba455f8 Allow the rest of the buttons in Python.
Fix issue where long type was enforced for return values of uniforms.
2011-10-25 23:02:17 +02:00
Themaister 197d62860b Default screenshot directory. 2011-10-24 21:34:30 +02:00
Themaister 402451626f More accurate colors for screenshot. 2011-10-24 19:23:58 +02:00
Themaister 3739cbfc70 Minor cleanup for rewind. 2011-10-23 17:13:16 +02:00
Themaister 235355ffc7 Check more explicitly for XVideo and Xext. 2011-10-23 12:48:44 +02:00
Themaister 4856d0cac3 Allow screenshots while paused. 2011-10-23 12:38:11 +02:00
Themaister 77a2723bb0 Neat optimizations for SSE. 2011-10-23 02:56:33 +02:00
Themaister 41cd6e21c3 Use _mm* intrinsics. 2011-10-22 23:36:02 +02:00
Themaister 1fc99c7123 Fix deprecation warning. 2011-10-22 22:54:36 +02:00
Themaister fddcc3447c Fix build for Clang. 2011-10-22 22:19:54 +02:00
28 changed files with 432 additions and 208 deletions

No files matched your search

+2 -2
View File
@@ -98,8 +98,8 @@ endif
ifeq ($(HAVE_XVIDEO), 1)
OBJ += gfx/xvideo.o input/x11_input.o
LIBS += $(XVIDEO_LIBS)
DEFINES += $(XVIDEO_CFLAGS)
LIBS += $(XVIDEO_LIBS) $(X11_LIBS) $(XEXT_LIBS)
DEFINES += $(XVIDEO_CFLAGS) $(X11_CFLAGS) $(XEXT_CFLAGS)
endif
ifeq ($(HAVE_CG), 1)
+2 -2
View File
@@ -166,10 +166,10 @@ clean:
rm -f tools/*.o
dist_x86: all
zip -r ssnes-win32-0.9.zip $(TARGET) $(JTARGET) ssnes.cfg snes.dll SDL.dll
zip -r ssnes-win32-0.9.1.zip $(TARGET) $(JTARGET) ssnes.cfg snes.dll SDL.dll
dist_x86_64: all
zip -r ssnes-win64-0.9.zip $(TARGET) $(JTARGET) ssnes.cfg snes.dll SDL.dll
zip -r ssnes-win64-0.9.1.zip $(TARGET) $(JTARGET) ssnes.cfg snes.dll SDL.dll
libs_x86:
wget https://github.com/downloads/Themaister/SSNES/SSNES-win32-libs.zip --no-check-certificate
+27 -28
View File
@@ -3,7 +3,8 @@
#include <stdint.h>
#ifdef __SSE2__
#if __SSE2__
#include <mmintrin.h>
#include <emmintrin.h>
#define audio_convert_s16_to_float audio_convert_s16_to_float_SSE2
#define audio_convert_float_to_s16 audio_convert_float_to_s16_SSE2
@@ -29,25 +30,27 @@ static inline void audio_convert_float_to_s16_C(int16_t *out,
}
}
#ifdef __SSE2__
#if __SSE2__
static inline void audio_convert_s16_to_float_SSE2(float *out,
const int16_t *in, unsigned samples)
{
// Not aligned? FML :(
if (((uintptr_t)in & 7) || ((uintptr_t)out & 15))
{
audio_convert_s16_to_float_C(out, in, samples);
return;
}
__m128 factor = _mm_set1_ps(1.0f / 0x7fff);
__m128 factor = _mm_set1_ps(1.0f / (0x7fff * 0x10000));
unsigned i;
for (i = 0; i + 4 <= samples; i += 4, in += 4, out += 4)
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
{
__m64 input = *(const __m64*)in;
__m128 reg = _mm_cvtpi16_ps(input);
__m128 res = _mm_mul_ps(reg, factor);
*(__m128*)out = res;
__m128i input = _mm_loadu_si128((const __m128i *)in);
__m128i regs[2] = {
_mm_unpacklo_epi16(_mm_setzero_si128(), input),
_mm_unpackhi_epi16(_mm_setzero_si128(), input),
};
__m128 output[2] = {
_mm_mul_ps(_mm_cvtepi32_ps(regs[0]), factor),
_mm_mul_ps(_mm_cvtepi32_ps(regs[1]), factor),
};
_mm_storeu_ps(out + 0, output[0]);
_mm_storeu_ps(out + 4, output[1]);
}
audio_convert_s16_to_float_C(out, in, samples - i);
@@ -56,21 +59,17 @@ static inline void audio_convert_s16_to_float_SSE2(float *out,
static inline void audio_convert_float_to_s16_SSE2(int16_t *out,
const float *in, unsigned samples)
{
// Not aligned? FML :(
if (((uintptr_t)in & 7) || ((uintptr_t)out & 15))
{
audio_convert_float_to_s16_C(out, in, samples);
return;
}
__m128 factor = _mm_set1_ps(0x7fff);
__m128 factor = _mm_set1_ps((float)0x7fff);
unsigned i;
for (i = 0; i + 4 <= samples; i += 4, in += 4, out += 4)
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
{
__m128 input = *(const __m128*)in;
__m128 res = _mm_mul_ps(input, factor);
__m64 output = _mm_cvtps_pi16(res);
*(__m64*)out = output;
__m128 input[2] = { _mm_loadu_ps(in + 0), _mm_loadu_ps(in + 4) };
__m128 res[2] = { _mm_mul_ps(input[0], factor), _mm_mul_ps(input[1], factor) };
__m128i ints[2] = { _mm_cvtps_epi32(res[0]), _mm_cvtps_epi32(res[1]) };
__m128i packed = _mm_packs_epi32(ints[0], ints[1]);
_mm_storeu_si128((__m128i *)out, packed);
}
audio_convert_float_to_s16_C(out, in, samples - i);
-3
View File
@@ -111,7 +111,6 @@
// Windowed
static const float xscale = 3.0; // Real x res = aspect * base_size * xscale
static const float yscale = 3.0; // Real y res = base_size * yscale
static const unsigned base_size = 224; // Base size for windowed mode.
// Fullscreen
static const bool fullscreen = false; // To start in Fullscreen or not
@@ -157,8 +156,6 @@ static const bool hires_record = false;
// Record post-filtered (CPU filter) video rather than raw SNES output.
static const bool post_filter_record = false;
#define SNES_ASPECT_RATIO (4.0/3)
////////////////
// Audio
////////////////
+25 -16
View File
@@ -91,7 +91,7 @@ static const input_driver_t *input_drivers[] = {
static void find_audio_driver(void)
{
for (int i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++)
for (unsigned i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++)
{
if (strcasecmp(g_settings.audio.driver, audio_drivers[i]->ident) == 0)
{
@@ -101,7 +101,7 @@ static void find_audio_driver(void)
}
SSNES_ERR("Couldn't find any audio driver named \"%s\"\n", g_settings.audio.driver);
fprintf(stderr, "Available audio drivers are:\n");
for (int i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++)
for (unsigned i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++)
fprintf(stderr, "\t%s\n", audio_drivers[i]->ident);
exit(1);
@@ -109,7 +109,7 @@ static void find_audio_driver(void)
static void find_video_driver(void)
{
for (int i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++)
for (unsigned i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++)
{
if (strcasecmp(g_settings.video.driver, video_drivers[i]->ident) == 0)
{
@@ -127,7 +127,7 @@ static void find_video_driver(void)
static void find_input_driver(void)
{
for (int i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++)
for (unsigned i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++)
{
if (strcasecmp(g_settings.input.driver, input_drivers[i]->ident) == 0)
{
@@ -330,17 +330,17 @@ static void init_filter(void)
g_extern.filter.active = true;
unsigned width = 512;
unsigned height = 512;
unsigned width = g_extern.system.geom.max_width;
unsigned height = g_extern.system.geom.max_height;
g_extern.filter.psize(&width, &height);
unsigned pow2_x = next_pow2(ceil(width));
unsigned pow2_y = next_pow2(ceil(height));
unsigned maxsize = pow2_x > pow2_y ? pow2_x : pow2_y;
g_extern.filter.scale = maxsize / 256;
g_extern.filter.scale = maxsize / SSNES_SCALE_BASE;
g_extern.filter.buffer = malloc(256 * 256 * g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
g_extern.filter.pitch = 256 * g_extern.filter.scale * sizeof(uint32_t);
g_extern.filter.buffer = malloc(SSNES_SCALE_BASE * SSNES_SCALE_BASE * g_extern.filter.scale * g_extern.filter.scale * sizeof(uint32_t));
g_extern.filter.pitch = SSNES_SCALE_BASE * g_extern.filter.scale * sizeof(uint32_t);
assert(g_extern.filter.buffer);
g_extern.filter.colormap = malloc(32768 * sizeof(uint32_t));
@@ -412,8 +412,9 @@ void init_video_input(void)
init_shader_dir();
#endif
// We use at least 512x512 textures to accomodate for hi-res games.
unsigned scale = 2;
unsigned max_dim = max(g_extern.system.geom.max_width, g_extern.system.geom.max_height);
unsigned scale = max_dim / SSNES_SCALE_BASE;
scale = max(scale, 1);
find_video_driver();
find_input_driver();
@@ -430,18 +431,26 @@ void init_video_input(void)
}
else
{
if (g_settings.video.force_aspect)
if (g_settings.video.force_aspect && (g_settings.video.aspect_ratio > 0.0f))
{
width = roundf(g_settings.video.base_size * g_settings.video.xscale * g_settings.video.aspect_ratio);
height = roundf(g_settings.video.base_size * g_settings.video.yscale);
width = roundf(g_extern.system.geom.base_height * g_settings.video.xscale * g_settings.video.aspect_ratio);
height = roundf(g_extern.system.geom.base_height * g_settings.video.yscale);
}
else
{
width = roundf(8.0f / 7.0f * g_settings.video.base_size * g_settings.video.xscale); // Assume 8:7 aspect.
height = roundf(g_settings.video.base_size * g_settings.video.yscale);
width = roundf(g_extern.system.geom.base_width * g_settings.video.xscale);
height = roundf(g_extern.system.geom.base_height * g_settings.video.yscale);
}
}
if (g_settings.video.aspect_ratio < 0.0f)
{
g_settings.video.aspect_ratio = (float)g_extern.system.geom.base_width / g_extern.system.geom.base_height;
SSNES_LOG("Adjusting aspect ratio to %.2f\n", g_settings.video.aspect_ratio);
}
SSNES_LOG("Video @ %ux%u\n", width, height);
video_info_t video = {
.width = width,
.height = height,
+3 -1
View File
@@ -26,9 +26,11 @@
#include <unistd.h>
#include "input/keysym.h"
// SNES has 12 buttons from 0-11 (libsnes.hpp)
#define SSNES_FIRST_META_KEY 12
enum
{
SSNES_FAST_FORWARD_KEY = 12, // SNES has 12 buttons from 0-11 (libsnes.hpp)
SSNES_FAST_FORWARD_KEY = SSNES_FIRST_META_KEY,
SSNES_FAST_FORWARD_HOLD_KEY,
SSNES_LOAD_STATE_KEY,
SSNES_SAVE_STATE_KEY,
+97 -21
View File
@@ -96,6 +96,10 @@ unsigned (*psnes_get_memory_size)(unsigned);
void (*psnes_unload_cartridge)(void);
void (*psnes_term)(void);
#ifdef HAVE_DYLIB
static void set_environment(void);
#endif
#ifdef HAVE_DYNAMIC
static void load_dynamic(void)
{
@@ -181,29 +185,22 @@ static void set_statics(void)
void init_dlsym(void)
{
// Guarantee that we can do "dirty" casting. Every OS that this program supports should pass this ...
// Guarantee that we can do "dirty" casting.
// Every OS that this program supports should pass this ...
assert(sizeof(void*) == sizeof(void (*)(void)));
#ifdef HAVE_DYNAMIC
#ifndef _WIN32 // Try to verify that -lsnes was not linked in from other modules
// since loading it dynamically and with -l will fail hard.
void *lib = dlopen(NULL, RTLD_LAZY);
if (lib)
// Try to verify that -lsnes was not linked in from other modules
// since loading it dynamically and with -l will fail hard.
function_t sym = dylib_proc(NULL, "snes_init");
if (sym)
{
void *sym = dlsym(lib, "snes_init");
if (sym)
{
SSNES_ERR("Serious problem! SSNES wants to load libsnes dyamically, but it is already linked!\n");
SSNES_ERR("This could happen if other modules SSNES depends on link against libsnes directly.\n");
SSNES_ERR("Proceeding could cause a crash! Aborting ...\n");
dlclose(lib);
exit(1);
}
dlclose(lib);
SSNES_ERR("Serious problem! SSNES wants to load libsnes dyamically, but it is already linked!\n");
SSNES_ERR("This could happen if other modules SSNES depends on link against libsnes directly.\n");
SSNES_ERR("Proceeding could cause a crash! Aborting ...\n");
exit(1);
}
#endif
if (!*g_settings.libsnes)
{
@@ -220,6 +217,10 @@ void init_dlsym(void)
#else
set_statics();
#endif
#ifdef HAVE_DYLIB
set_environment();
#endif
}
void uninit_dlsym(void)
@@ -243,16 +244,26 @@ dylib_t dylib_load(const char *path)
function_t dylib_proc(dylib_t lib, const char *proc)
{
#ifdef _WIN32
function_t sym = (function_t)GetProcAddress(lib, proc);
function_t sym = (function_t)GetProcAddress(lib ? lib : GetModuleHandle(NULL), proc);
#else
void *ptr_sym = NULL;
if (lib)
ptr_sym = dlsym(lib, proc);
else
{
void *handle = dlopen(NULL, RTLD_LAZY);
if (handle)
{
ptr_sym = dlsym(handle, proc);
dlclose(handle);
}
}
// Dirty hack to workaround the non-legality of void* -> fn-pointer casts.
void *ptr_sym = dlsym(lib, proc);
function_t sym;
memcpy(&sym, &ptr_sym, sizeof(void*));
#endif
if (!sym)
SSNES_WARN("Failed to load symbol \"%s\"\n", proc);
return sym;
}
@@ -265,3 +276,68 @@ void dylib_close(dylib_t lib)
#endif
}
static bool environment_cb(unsigned cmd, void *data)
{
switch (cmd)
{
case SNES_ENVIRONMENT_GET_FULLPATH:
*(const char**)data = g_extern.system.fullpath;
SSNES_LOG("FULLPATH: \"%s\"\n", g_extern.system.fullpath);
break;
case SNES_ENVIRONMENT_SET_GEOMETRY:
g_extern.system.geom = *(const struct snes_geometry*)data;
g_extern.system.geom.max_width = next_pow2(g_extern.system.geom.max_width);
g_extern.system.geom.max_height = next_pow2(g_extern.system.geom.max_height);
SSNES_LOG("SET_GEOMETRY: (%ux%u) / (%ux%u)\n",
g_extern.system.geom.base_width,
g_extern.system.geom.base_height,
g_extern.system.geom.max_width,
g_extern.system.geom.max_height);
break;
case SNES_ENVIRONMENT_SET_PITCH:
g_extern.system.pitch = *(const unsigned*)data;
SSNES_LOG("SET_PITCH: %u\n", g_extern.system.pitch);
break;
default:
return false;
}
return true;
}
#ifdef HAVE_DYLIB
// Assume SNES as defaults.
static void set_environment_defaults(void)
{
g_extern.system.pitch = 0; // 0 is classic libsnes semantics.
g_extern.system.geom = (struct snes_geometry) {
.base_width = 256,
.base_height = 224,
.max_width = 512,
.max_height = 512,
};
}
// SSNES extension hooks. Totally optional 'n shizz :)
static void set_environment(void)
{
#ifdef HAVE_DYNAMIC
dylib_t lib = lib_handle;
#else
dylib_t lib = NULL;
#endif
void (*psnes_set_environment)(snes_environment_t) =
(void (*)(snes_environment_t))dylib_proc(lib, "snes_set_environment");
if (psnes_set_environment)
psnes_set_environment(environment_cb);
set_environment_defaults();
}
#endif
+1 -1
View File
@@ -510,7 +510,7 @@ void load_ram_file(const char *path, int type)
void *buf = NULL;
ssize_t rc = read_file(path, &buf);
if (rc <= size)
memcpy(data, buf, size);
memcpy(data, buf, rc);
free(buf);
}
+17 -3
View File
@@ -74,7 +74,6 @@ struct settings
char driver[32];
float xscale;
float yscale;
unsigned base_size;
bool fullscreen;
unsigned fullscreen_x;
unsigned fullscreen_y;
@@ -208,6 +207,13 @@ struct global
unsigned state_slot;
struct
{
struct snes_geometry geom;
unsigned pitch; // If 0, has classic libsnes semantics.
char fullpath[MAXPATHLEN];
} system;
struct
{
hermite_resampler_t *source;
@@ -303,8 +309,6 @@ struct global
char sha256[64 + 1];
bool do_screenshot;
#ifdef HAVE_XML
cheat_manager_t *cheat;
#endif
@@ -331,6 +335,16 @@ extern struct global g_extern;
fflush(stderr); \
} while (0)
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#define SSNES_SCALE_BASE 256
static inline uint32_t next_pow2(uint32_t v)
{
v--;
+3 -3
View File
@@ -43,7 +43,7 @@ typedef struct
void *handle;
} input_ext_t;
static void* input_ext_init(void)
static void *input_ext_init(void)
{
g_input_dead = false;
return calloc(1, sizeof(input_ext_t));
@@ -199,7 +199,7 @@ static bool video_ext_frame(void *data, const void *frame, unsigned width, unsig
return ext->driver->frame(ext->handle, frame, width, height, pitch, msg);
}
static void* setup_input(ext_t *ext, const ssnes_input_driver_t *driver)
static void *setup_input(ext_t *ext, const ssnes_input_driver_t *driver)
{
int joypad_index[5];
for (unsigned i = 0; i < 5; i++)
@@ -292,7 +292,7 @@ static bool setup_video(ext_t *ext, const video_info_t *video, const input_drive
return true;
}
static void* video_ext_init(const video_info_t *video, const input_driver_t **input, void **input_data)
static void *video_ext_init(const video_info_t *video, const input_driver_t **input, void **input_data)
{
ext_t *ext = calloc(1, sizeof(*ext));
if (!ext)
+4 -3
View File
@@ -1226,7 +1226,8 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
SSNES_LOG("GL: Loaded %u program(s).\n", gl_shader_num());
// Set up render to texture.
gl_init_fbo(gl, 256 * video->input_scale, 256 * video->input_scale);
gl_init_fbo(gl, SSNES_SCALE_BASE * video->input_scale,
SSNES_SCALE_BASE * video->input_scale);
gl->keep_aspect = video->force_aspect;
@@ -1277,8 +1278,8 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
set_lut_texture_coords(tex_coords);
gl->tex_w = 256 * video->input_scale;
gl->tex_h = 256 * video->input_scale;
gl->tex_w = SSNES_SCALE_BASE * video->input_scale;
gl->tex_h = SSNES_SCALE_BASE * video->input_scale;
// Empty buffer that we use to clear out the texture with on res change.
gl->empty_buf = calloc(gl->tex_w * gl->tex_h, gl->base_size);
+61 -26
View File
@@ -60,7 +60,7 @@ PY_READ_FUNC(APURAM)
PY_READ_FUNC(CGRAM)
PY_READ_FUNC(OAM)
static PyObject* py_read_input(PyObject *self, PyObject *args)
static PyObject *py_read_input(PyObject *self, PyObject *args)
{
(void)self;
@@ -72,7 +72,7 @@ static PyObject* py_read_input(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "II", &player, &key))
return NULL;
if (player > MAX_PLAYERS || player < 1)
if (player > MAX_PLAYERS || player < 1 || key >= SSNES_FIRST_META_KEY)
return NULL;
const struct snes_keybind *binds[MAX_PLAYERS];
@@ -88,6 +88,24 @@ static PyObject* py_read_input(PyObject *self, PyObject *args)
return PyBool_FromLong((long)res);
}
static PyObject *py_read_input_meta(PyObject *self, PyObject *args)
{
(void)self;
if (!driver.input_data)
return PyBool_FromLong(0);
unsigned key;
if (!PyArg_ParseTuple(args, "I", &key))
return NULL;
if (key < SSNES_FIRST_META_KEY)
return NULL;
bool ret = driver.input->key_pressed(driver.input_data, key);
return PyBool_FromLong((long)ret);
}
static PyMethodDef SNESMethods[] = {
{ "read_wram", PY_READ_FUNC_DECL(WRAM), METH_VARARGS, "Read WRAM from SNES." },
{ "read_vram", PY_READ_FUNC_DECL(VRAM), METH_VARARGS, "Read VRAM from SNES." },
@@ -95,23 +113,49 @@ static PyMethodDef SNESMethods[] = {
{ "read_cgram", PY_READ_FUNC_DECL(CGRAM), METH_VARARGS, "Read CGRAM from SNES." },
{ "read_oam", PY_READ_FUNC_DECL(OAM), METH_VARARGS, "Read OAM from SNES." },
{ "input", py_read_input, METH_VARARGS, "Read input state from SNES." },
{ "input_meta", py_read_input_meta, METH_VARARGS, "Read SSNES specific input." },
{ NULL, NULL, 0, NULL }
};
#define DECL_ATTR_SNES(attr) PyObject_SetAttrString(mod, #attr, PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_##attr))
#define DECL_ATTR_SSNES(attr) PyObject_SetAttrString(mod, #attr, PyLong_FromLong(SSNES_##attr))
static void py_set_attrs(PyObject *mod)
{
PyObject_SetAttrString(mod, "B", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_B));
PyObject_SetAttrString(mod, "Y", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_Y));
PyObject_SetAttrString(mod, "SELECT", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_SELECT));
PyObject_SetAttrString(mod, "START", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_START));
PyObject_SetAttrString(mod, "UP", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_UP));
PyObject_SetAttrString(mod, "DOWN", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_DOWN));
PyObject_SetAttrString(mod, "LEFT", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_LEFT));
PyObject_SetAttrString(mod, "RIGHT", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_RIGHT));
PyObject_SetAttrString(mod, "A", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_A));
PyObject_SetAttrString(mod, "X", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_X));
PyObject_SetAttrString(mod, "L", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_L));
PyObject_SetAttrString(mod, "R", PyLong_FromLong(SNES_DEVICE_ID_JOYPAD_R));
DECL_ATTR_SNES(B);
DECL_ATTR_SNES(Y);
DECL_ATTR_SNES(SELECT);
DECL_ATTR_SNES(START);
DECL_ATTR_SNES(UP);
DECL_ATTR_SNES(DOWN);
DECL_ATTR_SNES(LEFT);
DECL_ATTR_SNES(RIGHT);
DECL_ATTR_SNES(A);
DECL_ATTR_SNES(X);
DECL_ATTR_SNES(L);
DECL_ATTR_SNES(R);
DECL_ATTR_SSNES(FAST_FORWARD_KEY);
DECL_ATTR_SSNES(FAST_FORWARD_HOLD_KEY);
DECL_ATTR_SSNES(LOAD_STATE_KEY);
DECL_ATTR_SSNES(SAVE_STATE_KEY);
DECL_ATTR_SSNES(FULLSCREEN_TOGGLE_KEY);
DECL_ATTR_SSNES(QUIT_KEY);
DECL_ATTR_SSNES(STATE_SLOT_PLUS);
DECL_ATTR_SSNES(STATE_SLOT_MINUS);
DECL_ATTR_SSNES(AUDIO_INPUT_RATE_PLUS);
DECL_ATTR_SSNES(AUDIO_INPUT_RATE_MINUS);
DECL_ATTR_SSNES(REWIND);
DECL_ATTR_SSNES(MOVIE_RECORD_TOGGLE);
DECL_ATTR_SSNES(PAUSE_TOGGLE);
DECL_ATTR_SSNES(FRAMEADVANCE);
DECL_ATTR_SSNES(RESET);
DECL_ATTR_SSNES(SHADER_NEXT);
DECL_ATTR_SSNES(SHADER_PREV);
DECL_ATTR_SSNES(CHEAT_INDEX_PLUS);
DECL_ATTR_SSNES(CHEAT_INDEX_MINUS);
DECL_ATTR_SSNES(CHEAT_TOGGLE);
DECL_ATTR_SSNES(SCREENSHOT);
DECL_ATTR_SSNES(DSP_CONFIG);
}
static PyModuleDef SNESModule = {
@@ -260,7 +304,7 @@ void py_state_free(py_state_t *handle)
Py_Finalize();
}
int py_state_get(py_state_t *handle, const char *id,
float py_state_get(py_state_t *handle, const char *id,
unsigned frame_count)
{
PyObject *ret = PyObject_CallMethod(handle->inst, (char*)id, (char*)"I", frame_count);
@@ -269,19 +313,10 @@ int py_state_get(py_state_t *handle, const char *id,
if (!handle->warned_ret)
SSNES_WARN("Didn't get return value from script! Bug?\n");
handle->warned_ret = true;
return 0;
}
int retval = 0;
if (PyLong_Check(ret))
retval = (int)PyLong_AsLong(ret);
else
{
if (!handle->warned_type)
SSNES_WARN("Didn't get long compatible value from script! Bug?\n");
handle->warned_type = true;
return 0.0f;
}
float retval = (float)PyFloat_AsDouble(ret);
Py_DECREF(ret);
return retval;
}
+1 -1
View File
@@ -26,7 +26,7 @@ typedef struct py_state py_state_t;
py_state_t *py_state_new(const char *program, bool is_file, const char *pyclass);
void py_state_free(py_state_t *handle);
int py_state_get(py_state_t *handle,
float py_state_get(py_state_t *handle,
const char *id, unsigned frame_count);
#endif
+4 -2
View File
@@ -288,13 +288,15 @@ static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu
if (vid->render32)
{
SSNES_LOG("SDL: Creating 32-bit buffer.\n");
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 256 * video->input_scale, 256 * video->input_scale, 32,
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, SSNES_SCALE_BASE * video->input_scale,
SSNES_SCALE_BASE * 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,
vid->buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, SSNES_SCALE_BASE * video->input_scale,
SSNES_SCALE_BASE * 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",
+11 -8
View File
@@ -131,7 +131,9 @@ static unsigned lut_textures[MAX_TEXTURES];
static unsigned lut_textures_num = 0;
static char lut_textures_uniform[MAX_TEXTURES][64];
#ifdef HAVE_CONFIGFILE
static snes_tracker_t *snes_tracker = NULL;
#endif
void gl_cg_set_proj_matrix(void)
{
@@ -242,6 +244,7 @@ void gl_cg_set_params(unsigned width, unsigned height,
}
}
#ifdef HAVE_CONFIGFILE
// Set state parameters
if (snes_tracker)
{
@@ -259,6 +262,7 @@ void gl_cg_set_params(unsigned width, unsigned height,
set_param_1f(param_f, info[i].value);
}
}
#endif
}
}
@@ -276,11 +280,13 @@ void gl_cg_deinit(void)
glDeleteTextures(lut_textures_num, lut_textures);
lut_textures_num = 0;
#ifdef HAVE_CONFIGFILE
if (snes_tracker)
{
snes_tracker_free(snes_tracker);
snes_tracker = NULL;
}
#endif
cgDestroyContext(cgCtx);
}
@@ -490,8 +496,8 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
unsigned addr = 0;
#ifdef HAVE_PYTHON
if (tracker_type != SSNES_STATE_PYTHON)
{
#endif
{
unsigned input_slot = 0;
if (config_get_hex(conf, input_slot_buf, &input_slot))
{
@@ -525,11 +531,9 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
SSNES_ERR("No address assigned to semantic.\n");
goto error;
}
#ifdef HAVE_PYTHON
}
#endif
int memtype = 0;
unsigned memtype;
switch (ram_type)
{
case SSNES_STATE_WRAM:
@@ -549,10 +553,10 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
break;
default:
memtype = SNES_MEMORY_WRAM;
memtype = -1u;
}
if (addr >= psnes_get_memory_size(memtype))
if ((memtype != -1u) && (addr >= psnes_get_memory_size(memtype)))
{
SSNES_ERR("Address out of bounds.\n");
goto error;
@@ -581,7 +585,7 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
.oam = psnes_get_memory_data(SNES_MEMORY_OAM),
.apuram = psnes_get_memory_data(SNES_MEMORY_APURAM),
.info = info,
.info_elem = info_cnt
.info_elem = info_cnt,
};
#ifdef HAVE_PYTHON
@@ -613,7 +617,6 @@ static bool load_imports(const char *dir_path, config_file_t *conf)
#endif
free(imports);
return true;
error:
+10 -9
View File
@@ -55,6 +55,7 @@
#define pglLinkProgram glLinkProgram
#define pglGetUniformLocation glGetUniformLocation
#define pglUniform1i glUniform1i
#define pglUniform1f glUniform1f
#define pglUniform2fv glUniform2fv
#define pglUniform4fv glUniform4fv
#define pglGetShaderiv glGetShaderiv
@@ -78,6 +79,7 @@ static PFNGLDETACHSHADERPROC pglDetachShader = NULL;
static PFNGLLINKPROGRAMPROC pglLinkProgram = NULL;
static PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation = NULL;
static PFNGLUNIFORM1IPROC pglUniform1i = NULL;
static PFNGLUNIFORM1FPROC pglUniform1f = NULL;
static PFNGLUNIFORM2FVPROC pglUniform2fv = NULL;
static PFNGLUNIFORM4FVPROC pglUniform4fv = NULL;
static PFNGLGETSHADERIVPROC pglGetShaderiv = NULL;
@@ -481,13 +483,13 @@ static bool get_import_value(xmlNodePtr ptr)
goto error;
}
enum snes_ram_type ram_type = SSNES_STATE_WRAM;
enum snes_ram_type ram_type = SSNES_STATE_NONE;
uint32_t addr = 0;
#ifdef HAVE_PYTHON
if (tracker_type != SSNES_STATE_PYTHON)
{
#endif
{
if (input)
{
unsigned slot = strtoul((const char*)input, NULL, 0);
@@ -515,11 +517,9 @@ static bool get_import_value(xmlNodePtr ptr)
SSNES_ERR("No RAM address specificed for import value.\n");
goto error;
}
#ifdef HAVE_PYTHON
}
#endif
int memtype = 0;
unsigned memtype;
switch (ram_type)
{
case SSNES_STATE_WRAM:
@@ -539,10 +539,10 @@ static bool get_import_value(xmlNodePtr ptr)
break;
default:
memtype = SNES_MEMORY_WRAM;
memtype = -1u;
}
if (addr >= psnes_get_memory_size(memtype))
if ((memtype != -1u) && (addr >= psnes_get_memory_size(memtype)))
{
SSNES_ERR("Address out of bounds.\n");
goto error;
@@ -842,6 +842,7 @@ bool gl_glsl_init(const char *path)
LOAD_GL_SYM(LinkProgram);
LOAD_GL_SYM(GetUniformLocation);
LOAD_GL_SYM(Uniform1i);
LOAD_GL_SYM(Uniform1f);
LOAD_GL_SYM(Uniform2fv);
LOAD_GL_SYM(Uniform4fv);
LOAD_GL_SYM(GetShaderiv);
@@ -862,7 +863,7 @@ bool gl_glsl_init(const char *path)
bool shader_support = pglCreateProgram && pglUseProgram && pglCreateShader
&& pglDeleteShader && pglShaderSource && pglCompileShader && pglAttachShader
&& pglDetachShader && pglLinkProgram && pglGetUniformLocation
&& pglUniform1i && pglUniform2fv && pglUniform4fv
&& pglUniform1i && pglUniform1f && pglUniform2fv && pglUniform4fv
&& pglGetShaderiv && pglGetShaderInfoLog && pglGetProgramiv && pglGetProgramInfoLog
&& pglDeleteProgram && pglGetAttachedShaders
&& pglGetAttribLocation && pglEnableVertexAttribArray
@@ -1148,7 +1149,7 @@ void gl_glsl_set_params(unsigned width, unsigned height,
for (unsigned i = 0; i < cnt; i++)
{
location = pglGetUniformLocation(gl_program[active_index], info[i].id);
pglUniform1i(location, info[i].value);
pglUniform1f(location, info[i].value);
}
}
}
+9 -9
View File
@@ -88,32 +88,32 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
strlcpy(tracker->info[i].id, info->info[i].id, sizeof(tracker->info[i].id));
tracker->info[i].addr = info->info[i].addr;
tracker->info[i].type = info->info[i].type;
tracker->info[i].mask = (info->info[i].mask == 0) ? 0xffffffffu : info->info[i].mask;
tracker->info[i].mask = (info->info[i].mask == 0) ? -1u : info->info[i].mask;
#ifdef HAVE_PYTHON
if (info->info[i].type == SSNES_STATE_PYTHON)
tracker->info[i].py = tracker->py;
#endif
assert(info->wram && info->vram && info->cgram &&
info->oam && info->apuram);
// If we don't have a valid pointer.
static const uint8_t empty = 0;
switch (info->info[i].ram_type)
{
case SSNES_STATE_WRAM:
tracker->info[i].ptr = info->wram;
tracker->info[i].ptr = info->wram ? info->wram : &empty;
break;
case SSNES_STATE_APURAM:
tracker->info[i].ptr = info->apuram;
tracker->info[i].ptr = info->apuram ? info->apuram : &empty;
break;
case SSNES_STATE_OAM:
tracker->info[i].ptr = info->oam;
tracker->info[i].ptr = info->oam ? info->oam : &empty;
break;
case SSNES_STATE_CGRAM:
tracker->info[i].ptr = info->cgram;
tracker->info[i].ptr = info->cgram ? info->cgram : &empty;
break;
case SSNES_STATE_VRAM:
tracker->info[i].ptr = info->vram;
tracker->info[i].ptr = info->vram ? info->vram : &empty;
break;
case SSNES_STATE_INPUT_SLOT1:
tracker->info[i].input_ptr = &tracker->input_state[0];
@@ -125,7 +125,7 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
break;
default:
tracker->info[i].ptr = NULL;
tracker->info[i].ptr = &empty;
}
}
+2 -1
View File
@@ -39,6 +39,7 @@ enum snes_tracker_type
enum snes_ram_type
{
SSNES_STATE_NONE,
SSNES_STATE_WRAM,
SSNES_STATE_APURAM,
SSNES_STATE_OAM,
@@ -78,7 +79,7 @@ struct snes_tracker_info
struct snes_tracker_uniform
{
const char *id;
int value;
float value;
};
typedef struct snes_tracker snes_tracker_t;
+4 -4
View File
@@ -387,8 +387,8 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
attributes.border_pixel = 0;
attributes.event_mask = StructureNotifyMask | DestroyNotify | ClientMessage;
unsigned width = video->fullscreen ? ((video->width == 0) ? 256 : video->width) : video->width;
unsigned height = video->fullscreen ? ((video->height == 0) ? 224 : video->height) : video->height;
unsigned width = video->fullscreen ? ((video->width == 0) ? g_extern.system.geom.base_width : video->width) : video->width;
unsigned height = video->fullscreen ? ((video->height == 0) ? g_extern.system.geom.base_height : video->height) : video->height;
xv->window = XCreateWindow(xv->display, DefaultRootWindow(xv->display),
0, 0, width, height,
0, xv->depth, InputOutput, visualinfo->visual,
@@ -471,8 +471,8 @@ static void* xv_init(const video_info_t *video, const input_driver_t **input, vo
goto error;
}
xv->width = 512;
xv->height = 512;
xv->width = g_extern.system.geom.max_width;
xv->height = g_extern.system.geom.max_height;
xv->image = XvShmCreateImage(xv->display, xv->port, xv->fourcc, NULL, xv->width, xv->height, &xv->shminfo);
if (!xv->image)
+19
View File
@@ -66,6 +66,25 @@ extern "C" {
#define SNES_MEMORY_OAM 103
#define SNES_MEMORY_CGRAM 104
// SSNES extension. Not required to be implemented for a working implementation.
#define SNES_ENVIRONMENT_GET_FULLPATH 0 // const char **
#define SNES_ENVIRONMENT_SET_GEOMETRY 1 // const struct snes_geometry *
#define SNES_ENVIRONMENT_SET_PITCH 2 // const unsigned *
struct snes_geometry
{
unsigned base_width; // Nominal video width of system.
unsigned base_height; // Nominal video height of system.
unsigned max_width; // Maximum possible width of system.
unsigned max_height; // Maximum possible height of system.
};
typedef bool (*snes_environment_t)(unsigned cmd, void *data);
// Must be called before calling snes_init().
void snes_set_environment(snes_environment_t);
////
typedef void (*snes_video_refresh_t)(const uint16_t *data, unsigned width, unsigned height);
typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right);
typedef void (*snes_input_poll_t)(void);
+10 -2
View File
@@ -80,12 +80,20 @@ if [ $HAVE_FFMPEG = yes ]; then
check_lib FFMPEG_AVCODEC_OPEN2 "$AVCODEC_LIBS" avcodec_open2
check_lib FFMPEG_AVIO_OPEN "$AVFORMAT_LIBS" avio_open
check_lib FFMPEG_AVFORMAT_WRITE_HEADER "$AVFORMAT_LIBS" avformat_write_header
check_lib FFMPEG_AVFORMAT_NEW_STREAM "$AVFORMAT_LIBS" avformat_new_stream
fi
check_lib DYNAMIC $DYLIB dlopen
check_pkgconf FREETYPE freetype2
check_pkgconf XVIDEO xv
check_pkgconf X11 x11
check_pkgconf XEXT xext
if [ "$HAVE_X11" = "yes" ] && [ "$HAVE_XEXT" = "yes" ]; then
check_pkgconf XVIDEO xv
else
echo "X11 or Xext not present. Skipping XVideo."
HAVE_XVIDEO=no
fi
check_lib STRL -lc strlcpy
@@ -94,7 +102,7 @@ check_pkgconf PYTHON python3
add_define_make OS $OS
# Creates config.mk and config.h.
VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL DYLIB CG XML SDL_IMAGE DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER X264RGB"
VARS="ALSA OSS OSS_BSD OSS_LIB AL RSOUND ROAR JACK COREAUDIO PULSE SDL DYLIB CG XML SDL_IMAGE DYNAMIC FFMPEG AVCODEC AVFORMAT AVUTIL SWSCALE CONFIGFILE FREETYPE XVIDEO X11 XEXT NETPLAY FBO STRL PYTHON FFMPEG_ALLOC_CONTEXT3 FFMPEG_AVCODEC_OPEN2 FFMPEG_AVIO_OPEN FFMPEG_AVFORMAT_WRITE_HEADER FFMPEG_AVFORMAT_NEW_STREAM X264RGB"
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.9
PACKAGE_VERSION=0.9.1
# Adds a command line opt to ./configure --help
# $1: Variable (HAVE_ALSA, HAVE_OSS, etc)
+14
View File
@@ -22,6 +22,7 @@
struct video_info
{
AVCodecContext *codec;
AVCodec *encoder;
AVFrame *conv_frame;
uint8_t *conv_frame_buf;
@@ -42,6 +43,7 @@ struct video_info
struct audio_info
{
AVCodecContext *codec;
AVCodec *encoder;
int16_t *buffer;
size_t frames_in_buffer;
@@ -85,6 +87,8 @@ static bool init_audio(struct audio_info *audio, struct ffemu_params *param)
if (!codec)
return false;
audio->encoder = codec;
// FFmpeg just loves to deprecate stuff :)
#ifdef HAVE_FFMPEG_ALLOC_CONTEXT3
audio->codec = avcodec_alloc_context3(codec);
@@ -129,6 +133,8 @@ static bool init_video(struct video_info *video, const struct ffemu_params *para
if (!codec)
return false;
video->encoder = codec;
#if AV_HAVE_BIGENDIAN
video->fmt = PIX_FMT_RGB555BE;
#else
@@ -222,8 +228,12 @@ static bool init_muxer(ffemu_t *handle)
return false;
}
#ifdef HAVE_FFMPEG_AVFORMAT_NEW_STREAM
AVStream *stream = avformat_new_stream(ctx, handle->video.encoder);
#else
int stream_cnt = 0;
AVStream *stream = av_new_stream(ctx, stream_cnt++);
#endif
stream->codec = handle->video.codec;
if (ctx->oformat->flags & AVFMT_GLOBALHEADER)
@@ -231,7 +241,11 @@ static bool init_muxer(ffemu_t *handle)
handle->muxer.vstream = stream;
handle->muxer.vstream->sample_aspect_ratio = handle->video.codec->sample_aspect_ratio;
#ifdef HAVE_FFMPEG_AVFORMAT_NEW_STREAM
stream = avformat_new_stream(ctx, handle->audio.encoder);
#else
stream = av_new_stream(ctx, stream_cnt++);
#endif
stream->codec = handle->audio.codec;
if (ctx->oformat->flags & AVFMT_GLOBALHEADER)
+4 -8
View File
@@ -22,8 +22,6 @@
#include <string.h>
#include <assert.h>
//#include <stdio.h>
struct state_manager
{
uint64_t *buffer;
@@ -125,7 +123,6 @@ static void reassign_bottom(state_manager_t *state)
static void generate_delta(state_manager_t *state, const void *data)
{
//unsigned patch_size = 0;
bool crossed = false;
const uint32_t *old_state = state->tmp_state;
const uint32_t *new_state = data;
@@ -138,11 +135,12 @@ static void generate_delta(state_manager_t *state, const void *data)
{
uint64_t xor = old_state[i] ^ new_state[i];
// If the data differs (xor != 0), we push that xor on the stack with index and xor. This can be reversed by reapplying the xor.
// This, if states don't really differ much, we'll save lots of space :) Hopefully this will work really well with save states.
// If the data differs (xor != 0), we push that xor on the stack with index and xor.
// This can be reversed by reapplying the xor.
// This, if states don't really differ much, we'll save lots of space :)
// Hopefully this will work really well with save states.
if (xor)
{
//patch_size++;
state->buffer[state->top_ptr] = (i << 32) | xor;
state->top_ptr = (state->top_ptr + 1) % state->buf_size;
@@ -153,8 +151,6 @@ static void generate_delta(state_manager_t *state, const void *data)
if (crossed)
reassign_bottom(state);
//fprintf(stderr, "DELTA SIZE: %u, ORIG SIZE: %u\n", (unsigned)patch_size << 3, (unsigned)state->state_size << 2);
}
bool state_manager_push(state_manager_t *state, const void *data)
+6 -6
View File
@@ -69,12 +69,12 @@ static void dump_content(FILE *file, const uint16_t *frame, unsigned width, unsi
for (unsigned i = 0; i < width; i++)
{
uint16_t pixel = *src++;
uint8_t b = (pixel & 0x1f) << 3;
uint8_t g = (pixel & 0x03e0) >> 2;
uint8_t r = (pixel & 0x7c00) >> 7;
*dst++ = b;
*dst++ = g;
*dst++ = r;
uint8_t b = (pixel >> 0) & 0x1f;
uint8_t g = (pixel >> 5) & 0x1f;
uint8_t r = (pixel >> 10) & 0x1f;
*dst++ = (b << 3) | (b >> 2);
*dst++ = (g << 3) | (g >> 2);
*dst++ = (r << 3) | (r >> 2);
}
fwrite(line, 1, sizeof(line), file);
+1 -3
View File
@@ -120,7 +120,6 @@ static void set_defaults(void)
g_settings.video.xscale = xscale;
g_settings.video.yscale = yscale;
g_settings.video.base_size = base_size;
g_settings.video.fullscreen = g_extern.force_fullscreen ? true : fullscreen;
g_settings.video.fullscreen_x = fullscreen_x;
g_settings.video.fullscreen_y = fullscreen_y;
@@ -130,7 +129,7 @@ static void set_defaults(void)
g_settings.video.smooth = video_smooth;
g_settings.video.force_aspect = force_aspect;
g_settings.video.crop_overscan = crop_overscan;
g_settings.video.aspect_ratio = SNES_ASPECT_RATIO;
g_settings.video.aspect_ratio = -1.0f; // Automatic
g_settings.video.shader_type = SSNES_SHADER_AUTO;
#ifdef HAVE_FREETYPE
@@ -302,7 +301,6 @@ static void parse_config_file(void)
CONFIG_GET_DOUBLE(video.xscale, "video_xscale");
CONFIG_GET_DOUBLE(video.yscale, "video_yscale");
CONFIG_GET_INT(video.base_size, "video_base_size");
CONFIG_GET_INT(video.fullscreen_x, "video_fullscreen_x");
CONFIG_GET_INT(video.fullscreen_y, "video_fullscreen_y");
+94 -42
View File
@@ -85,13 +85,31 @@ static void set_fast_forward_button(bool new_button_state, bool new_hold_button_
old_hold_button_state = new_hold_button_state;
}
static void take_screenshot(const uint16_t *frame, unsigned width, unsigned height)
static inline unsigned lines_to_pitch(unsigned height)
{
if (g_extern.system.pitch == 0) // SNES semantics
return ((height == 448) || (height == 478)) ? 1024 : 2048;
else
return g_extern.system.pitch;
}
static void video_cached_frame(void);
static void take_screenshot(void)
{
if (!(*g_settings.screenshot_directory))
return;
bool ret = screenshot_dump(g_settings.screenshot_directory, frame,
width, height, (height == 448 || height == 478) ? 1024 : 2048);
bool ret = false;
if (g_extern.frame_cache.data)
{
const uint16_t *data = g_extern.frame_cache.data;
unsigned width = g_extern.frame_cache.width;
unsigned height = g_extern.frame_cache.height;
ret = screenshot_dump(g_settings.screenshot_directory,
data,
width, height,
lines_to_pitch(height));
}
const char *msg = NULL;
if (ret)
@@ -106,7 +124,33 @@ static void take_screenshot(const uint16_t *frame, unsigned width, unsigned heig
}
msg_queue_clear(g_extern.msg_queue);
msg_queue_push(g_extern.msg_queue, msg, 1, 180);
if (g_extern.is_paused)
{
msg_queue_push(g_extern.msg_queue, msg, 1, 1);
video_cached_frame();
}
else
msg_queue_push(g_extern.msg_queue, msg, 1, 180);
}
static inline void adjust_crop(const uint16_t **data, unsigned *height)
{
// Rather SNES specific.
if (g_settings.video.crop_overscan)
{
if (*height == 239)
{
*data += 7 * 1024; // Skip 7 top scanlines.
*height = 224;
}
else if (*height == 478)
{
*data += 15 * 512; // Skip 15 top scanlines.
*height = 448;
}
}
}
// libsnes: 0.065
@@ -116,22 +160,7 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
if (!g_extern.video_active)
return;
if (g_settings.video.crop_overscan)
{
if (height == 239)
{
data += 7 * 1024; // Skip 7 top scanlines.
height = 224;
}
else if (height == 478)
{
data += 15 * 512; // Skip 15 top scanlines.
height = 448;
}
}
if (g_extern.do_screenshot)
take_screenshot(data, width, height);
adjust_crop(&data, &height);
// Slightly messy code,
// but we really need to do processing before blocking on VSync for best possible scheduling.
@@ -140,7 +169,7 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
{
struct ffemu_video_data ffemu_data = {
.data = data,
.pitch = height == 448 || height == 478 ? 1024 : 2048,
.pitch = lines_to_pitch(height),
.width = width,
.height = height,
};
@@ -157,7 +186,7 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
unsigned oheight = height;
g_extern.filter.psize(&owidth, &oheight);
g_extern.filter.prender(g_extern.filter.colormap, g_extern.filter.buffer,
g_extern.filter.pitch, data, (height == 448 || height == 478) ? 1024 : 2048, width, height);
g_extern.filter.pitch, data, lines_to_pitch(height), width, height);
#ifdef HAVE_FFMPEG
if (g_extern.recording && g_settings.video.post_filter_record)
@@ -175,10 +204,10 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
if (!driver.video->frame(driver.video_data, g_extern.filter.buffer, owidth, oheight, g_extern.filter.pitch, msg))
g_extern.video_active = false;
}
else if (!driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048, msg))
else if (!driver.video->frame(driver.video_data, data, width, height, lines_to_pitch(height), msg))
g_extern.video_active = false;
#else
if (!driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048, msg))
if (!driver.video->frame(driver.video_data, data, width, height, lines_to_pitch(height), msg))
g_extern.video_active = false;
#endif
@@ -343,7 +372,7 @@ static int16_t input_state(bool port, unsigned device, unsigned index, unsigned
};
int16_t res = 0;
if (id < 12)
if (id < SSNES_FIRST_META_KEY)
res = driver.input->input_state(driver.input_data, binds, port, device, index, id);
if (g_extern.bsv_movie && !g_extern.bsv_movie_playback)
@@ -361,7 +390,7 @@ static int16_t input_state(bool port, unsigned device, unsigned index, unsigned
#endif
#ifdef _WIN32
#define PACKAGE_VERSION "0.9"
#define PACKAGE_VERSION "0.9.1"
#endif
#include "config.features.h"
@@ -431,8 +460,8 @@ static void print_help(void)
#endif
#ifdef HAVE_FFMPEG
puts("\t-r/--record: Path to record video file.\n\t\tUsing .mkv extension is recommended, and codecs used are FFV1/FLAC.");
puts("\t--size: Overrides output video size when recording with FFmpeg (format: widthxheight).");
puts("\t-r/--record: Path to record video file.\n\t\tUsing .mkv extension is recommended.");
puts("\t--size: Overrides output video size when recording with FFmpeg (format: WIDTHxHEIGHT).");
#endif
puts("\t-v/--verbose: Verbose logging.");
puts("\t-U/--ups: Specifies path for UPS patch that will be applied to ROM.");
@@ -443,6 +472,8 @@ static void print_help(void)
static void set_basename(const char *path)
{
strlcpy(g_extern.system.fullpath, path, sizeof(g_extern.system.fullpath));
strlcpy(g_extern.basename, path, sizeof(g_extern.basename));
char *dst = strrchr(g_extern.basename, '.');
if (dst)
@@ -476,6 +507,8 @@ static void set_paths(const char *path)
fill_pathname_dir(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
SSNES_LOG("Redirecting save state to \"%s\".\n", g_extern.savestate_name);
}
#ifdef HAVE_CONFIGFILE
if (*g_extern.config_path && path_is_directory(g_extern.config_path))
{
fill_pathname_dir(g_extern.config_path, g_extern.basename, ".cfg", sizeof(g_extern.config_path));
@@ -486,6 +519,7 @@ static void set_paths(const char *path)
SSNES_LOG("Did not find config file. Using system default.\n");
}
}
#endif
}
static void verify_stdin_paths(void)
@@ -515,12 +549,15 @@ static void verify_stdin_paths(void)
print_help();
exit(1);
}
#ifdef HAVE_CONFIGFILE
else if (path_is_directory(g_extern.config_path))
{
SSNES_ERR("Cannot specify directory for config file (--config) when reading from stdin.\n");
print_help();
exit(1);
}
#endif
}
static void parse_input(int argc, char *argv[])
@@ -907,10 +944,10 @@ static void init_recording(void)
struct ffemu_rational ntsc_fps = {60000, 1000};
struct ffemu_rational pal_fps = {50000, 1000};
struct ffemu_params params = {
.out_width = 256,
.out_height = 224,
.fb_width = 512,
.fb_height = 512,
.out_width = g_extern.system.geom.base_width,
.out_height = g_extern.system.geom.base_height,
.fb_width = g_extern.system.geom.max_width,
.fb_height = g_extern.system.geom.max_height,
.channels = 2,
.samplerate = 32000,
.filename = g_extern.record_path,
@@ -925,11 +962,11 @@ static void init_recording(void)
}
else if (g_settings.video.hires_record)
{
params.out_width = 512;
params.out_height = 448;
params.out_width *= 2;
params.out_height *= 2;
}
if (g_settings.video.force_aspect)
if (g_settings.video.force_aspect && (g_settings.video.aspect_ratio > 0.0f))
params.aspect_ratio = g_settings.video.aspect_ratio;
else
params.aspect_ratio = (float)params.out_width / params.out_height;
@@ -939,8 +976,8 @@ static void init_recording(void)
g_extern.filter.psize(&params.out_width, &params.out_height);
params.rgb32 = true;
unsigned max_width = 512;
unsigned max_height = 512;
unsigned max_width = params.fb_width;
unsigned max_height = params.fb_height;
g_extern.filter.psize(&max_width, &max_height);
params.fb_width = next_pow2(max_width);
params.fb_height = next_pow2(max_height);
@@ -999,7 +1036,7 @@ static void init_rewind(void)
if (g_settings.rewind_enable)
{
size_t serial_size = psnes_serialize_size();
g_extern.state_buf = malloc((serial_size + 3) & ~3); // Make sure we allocate at least 4-byte multiple.
g_extern.state_buf = calloc(1, (serial_size + 3) & ~3); // Make sure we allocate at least 4-byte multiple.
psnes_serialize(g_extern.state_buf, serial_size);
SSNES_LOG("Initing rewind buffer with size: %u MB\n", (unsigned)g_settings.rewind_buffer_size / 1000000);
g_extern.state_manager = state_manager_new((serial_size + 3) & ~3, g_settings.rewind_buffer_size, g_extern.state_buf);
@@ -1234,6 +1271,16 @@ static void fill_pathnames(void)
if (!(*g_extern.xml_name))
fill_pathname_noext(g_extern.xml_name, g_extern.basename, ".xml", sizeof(g_extern.xml_name));
if (!(*g_settings.screenshot_directory))
{
strlcpy(g_settings.screenshot_directory, g_extern.basename, sizeof(g_settings.screenshot_directory));
char *dir = strrchr(g_settings.screenshot_directory, '/');
if (!dir)
dir = strrchr(g_settings.screenshot_directory, '\\');
if (dir)
*dir = '\0';
}
}
}
@@ -1563,7 +1610,9 @@ static void check_oneshot(void)
static void check_reset(void)
{
if (driver.input->key_pressed(driver.input_data, SSNES_RESET))
static bool old_state = false;
bool new_state = driver.input->key_pressed(driver.input_data, SSNES_RESET);
if (new_state && !old_state)
{
SSNES_LOG("Resetting game!\n");
msg_queue_clear(g_extern.msg_queue);
@@ -1571,6 +1620,8 @@ static void check_reset(void)
psnes_reset();
init_controllers(); // bSNES since v073r01 resets controllers to JOYPAD after a reset, so just enforce it here.
}
old_state = new_state;
}
#ifdef HAVE_XML
@@ -1650,7 +1701,9 @@ static void check_screenshot(void)
{
static bool old_pressed = false;
bool pressed = driver.input->key_pressed(driver.input_data, SSNES_SCREENSHOT);
g_extern.do_screenshot = pressed && !old_pressed;
if (pressed && !old_pressed)
take_screenshot();
old_pressed = pressed;
}
@@ -1671,6 +1724,7 @@ static void check_dsp_config(void)
static void do_state_checks(void)
{
check_screenshot();
if (!g_extern.netplay)
{
check_pause();
@@ -1714,8 +1768,6 @@ static void do_state_checks(void)
if (!g_extern.audio_data.dsp_plugin)
#endif
check_input_rate();
check_screenshot();
}
static void fill_title_buf(void)
-3
View File
@@ -24,9 +24,6 @@
# video_xscale = 3.0
# video_yscale = 3.0
# Base size for windowed mode calculations. Generally 224 for SNES, but can be modified.
# video_base_size = 224
# Fullscreen resolution. Resolution of 0 uses the resolution of the desktop.
# video_fullscreen_x = 0
# video_fullscreen_y = 0