mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-09 03:29:43 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a48dc55c41 | ||
|
|
202a458524 | ||
|
|
b4de704a09 | ||
|
|
fef5edfac8 | ||
|
|
a6e74775b1 | ||
|
|
ee66a28d05 | ||
|
|
5e28d82af2 | ||
|
|
c2a06bfa09 | ||
|
|
66510e21aa | ||
|
|
ec5e3355b9 | ||
|
|
0522a2d6a0 | ||
|
|
fad89f9d2d | ||
|
|
97f937ec6d | ||
|
|
9647006a2b | ||
|
|
418ba455f8 | ||
|
|
197d62860b | ||
|
|
402451626f | ||
|
|
3739cbfc70 | ||
|
|
235355ffc7 | ||
|
|
4856d0cac3 | ||
|
|
77a2723bb0 | ||
|
|
41cd6e21c3 | ||
|
|
1fc99c7123 | ||
|
|
fddcc3447c |
No files matched your search
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
////////////////
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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--;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 : ∅
|
||||
break;
|
||||
case SSNES_STATE_APURAM:
|
||||
tracker->info[i].ptr = info->apuram;
|
||||
tracker->info[i].ptr = info->apuram ? info->apuram : ∅
|
||||
break;
|
||||
case SSNES_STATE_OAM:
|
||||
tracker->info[i].ptr = info->oam;
|
||||
tracker->info[i].ptr = info->oam ? info->oam : ∅
|
||||
break;
|
||||
case SSNES_STATE_CGRAM:
|
||||
tracker->info[i].ptr = info->cgram;
|
||||
tracker->info[i].ptr = info->cgram ? info->cgram : ∅
|
||||
break;
|
||||
case SSNES_STATE_VRAM:
|
||||
tracker->info[i].ptr = info->vram;
|
||||
tracker->info[i].ptr = info->vram ? info->vram : ∅
|
||||
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 = ∅
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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");
|
||||
|
||||
|
||||
@@ -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(¶ms.out_width, ¶ms.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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user