Compare commits

..
19 Commits
Author SHA1 Message Date
Themaister 336adb9f85 Preparations for 0.3.1 2011-03-01 21:45:04 +01:00
Themaister 7053006e77 Add more verbose messages, should fix netplay hangup on Win32. 2011-03-01 14:46:58 +01:00
Themaister bbf4804d12 Obey CFLAGS and LDFLAGS when testing libs (nice when profiling.) 2011-02-28 22:30:06 +01:00
Themaister 7c16424ba3 Shader enabling, and automatic resolution detection. 2011-02-28 16:59:31 +01:00
Themaister de9dc686ac Add hicontrast. 2011-02-27 20:42:02 +01:00
Themaister 069e9b574f Some waterpaint shader :) 2011-02-27 01:16:33 +01:00
Themaister d5319a879a Had missed out pause binding completely. 2011-02-27 00:24:50 +01:00
Themaister f64880aee1 Try glFlush() to remedy occational font flicker... 2011-02-26 23:56:45 +01:00
Themaister fed1857918 Might fix odd font flickering. 2011-02-26 19:32:59 +01:00
Themaister 9aeb40155e Add a comment or two. 2011-02-26 18:49:41 +01:00
Themaister e49aeb1071 Remove redundant define. 2011-02-26 18:48:17 +01:00
Themaister 13f8ec6f3b Added "nul" binds. 2011-02-26 18:47:32 +01:00
Themaister f75c6df270 Should force granularity to 1 when using movies. 2011-02-26 15:09:04 +01:00
Themaister 60b0afce95 Is this it? :D 2011-02-26 01:13:52 +01:00
Themaister f24653768f It does work, somewhat! :D 2011-02-26 00:59:17 +01:00
Themaister f135972a6b Arghh... This is so goddamn annoying :( 2011-02-26 00:31:13 +01:00
Themaister 42c68e21a2 Movie rewind still very broken :( 2011-02-25 12:37:05 +01:00
Themaister e8865060ca A start on movie rewind. 2011-02-25 11:47:27 +01:00
Themaister b07827a856 Should fix GLSL issue on OSX. 2011-02-22 23:53:01 +01:00
18 changed files with 452 additions and 64 deletions

No files matched your search

+1 -1
View File
@@ -113,7 +113,7 @@ ifneq ($(V),1)
Q := @
endif
CFLAGS = -Wall -O3 -g -std=gnu99 -I.
CFLAGS += -Wall -O3 -g -std=gnu99 -I.
all: $(TARGET) config.mk
+1 -1
View File
@@ -99,7 +99,7 @@ clean:
rm -f tools/*.o
dist: all
zip -r ssnes-win32-0.3.zip $(TARGET) ssnes.cfg snes.dll libxml2.dll iconv.dll zlib1.dll SDL.dll freetype6.dll xaudio-c.dll rsound.dll pthreadGC2.dll README.win32.txt $(JTARGET)
zip -r ssnes-win32-0.3.1.zip $(TARGET) ssnes.cfg snes.dll libxml2.dll iconv.dll zlib1.dll SDL.dll freetype6.dll xaudio-c.dll rsound.dll pthreadGC2.dll README.win32.txt $(JTARGET)
libs:
wget https://github.com/downloads/Themaister/SSNES/SSNES-win32-libs.zip --no-check-certificate
+2 -2
View File
@@ -94,8 +94,8 @@ static const float yscale = 3.0; // Real y res = 224 * yscale
// Fullscreen
static const bool fullscreen = false; // To start in Fullscreen or not
static const unsigned fullscreen_x = 1280;
static const unsigned fullscreen_y = 720;
static const unsigned fullscreen_x = 0; // Fullscreen resolution. A value of 0 uses the desktop resolution.
static const unsigned fullscreen_y = 0;
// Video VSYNC (recommended)
static const bool vsync = true;
+1 -1
View File
@@ -41,6 +41,7 @@ enum
SSNES_PAUSE_TOGGLE,
};
struct snes_keybind
{
int id;
@@ -78,7 +79,6 @@ typedef struct audio_driver
#define AXIS_NEG_GET(x) (((uint32_t)(x) >> 16) & 0xFFFFU)
#define AXIS_POS_GET(x) ((uint32_t)(x) & 0xFFFFU)
#define AXIS_NONE (0xFFFFFFFFU)
#define NO_BTN ((uint16_t)0xFFFFU) // I hope no joypad will ever have this many buttons ... ;)
+10
View File
@@ -44,6 +44,14 @@
#define MAX_BINDS 25 // Needs to be increased every time there are new binds added.
#define SSNES_NO_JOYPAD 0xFFFF
enum ssnes_shader_type
{
SSNES_SHADER_CG,
SSNES_SHADER_BSNES,
SSNES_SHADER_AUTO,
SSNES_SHADER_NONE
};
// All config related settings go here.
struct settings
{
@@ -62,6 +70,7 @@ struct settings
char cg_shader_path[256];
char bsnes_shader_path[256];
unsigned filter;
enum ssnes_shader_type shader_type;
char font_path[256];
unsigned font_size;
@@ -111,6 +120,7 @@ enum ssnes_game_type
SSNES_CART_SUFAMI,
};
// All run-time- / command line flag-related globals go here.
struct global
{
+60 -9
View File
@@ -24,6 +24,7 @@
#include <sys/time.h>
#include <string.h>
#include "general.h"
#include <assert.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -82,6 +83,8 @@ typedef struct gl
bool quitting;
bool keep_aspect;
unsigned full_x, full_y;
unsigned win_width;
unsigned win_height;
unsigned vp_width;
@@ -99,20 +102,46 @@ typedef struct gl
} gl_t;
////////////////// Shaders
static inline bool gl_shader_init(void)
static bool gl_shader_init(void)
{
if (strlen(g_settings.video.cg_shader_path) > 0 && strlen(g_settings.video.bsnes_shader_path) > 0)
SSNES_WARN("Both Cg and bSNES XML shader are defined in config file. Cg shader will be selected by default.\n");
switch (g_settings.video.shader_type)
{
case SSNES_SHADER_AUTO:
{
if (strlen(g_settings.video.cg_shader_path) > 0 && strlen(g_settings.video.bsnes_shader_path) > 0)
SSNES_WARN("Both Cg and bSNES XML shader are defined in config file. Cg shader will be selected by default.\n");
#ifdef HAVE_CG
if (strlen(g_settings.video.cg_shader_path) > 0)
return gl_cg_init(g_settings.video.cg_shader_path);
if (strlen(g_settings.video.cg_shader_path) > 0)
return gl_cg_init(g_settings.video.cg_shader_path);
#endif
#ifdef HAVE_XML
if (strlen(g_settings.video.bsnes_shader_path) > 0)
return gl_glsl_init(g_settings.video.bsnes_shader_path);
if (strlen(g_settings.video.bsnes_shader_path) > 0)
return gl_glsl_init(g_settings.video.bsnes_shader_path);
#endif
break;
}
#ifdef HAVE_CG
case SSNES_SHADER_CG:
{
return gl_cg_init(g_settings.video.cg_shader_path);
break;
}
#endif
#ifdef HAVE_XML
case SSNES_SHADER_BSNES:
{
return gl_glsl_init(g_settings.video.bsnes_shader_path);
break;
}
#endif
default:
break;
}
return true;
}
@@ -266,6 +295,7 @@ static void gl_render_msg(gl_t *gl, const char *msg)
GL_UNSIGNED_BYTE, head->output);
head = head->next;
glFlush();
glDrawArrays(GL_QUADS, 0, 4);
}
font_renderer_free_output(&out);
@@ -395,6 +425,8 @@ static bool gl_frame(void *data, const uint16_t* frame, unsigned width, unsigned
glTexSubImage2D(GL_TEXTURE_2D,
0, 0, 0, width, height, GL_BGRA,
GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
glFlush();
glDrawArrays(GL_QUADS, 0, 4);
if (msg)
@@ -442,6 +474,12 @@ static void* gl_init(video_info_t *video, const input_driver_t **input, void **i
if (SDL_Init(SDL_INIT_VIDEO) < 0)
return NULL;
const SDL_VideoInfo *video_info = SDL_GetVideoInfo();
assert(video_info);
unsigned full_x = video_info->current_w;
unsigned full_y = video_info->current_h;
SSNES_LOG("Detecting desktop resolution %ux%u.\n", full_x, full_y);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, video->vsync ? 1 : 0);
@@ -462,8 +500,21 @@ static void* gl_init(video_info_t *video, const input_driver_t **input, void **i
if (!gl)
return NULL;
gl->win_width = video->width;
gl->win_height = video->height;
gl->full_x = full_x;
gl->full_y = full_y;
if (video->fullscreen)
{
gl->win_width = video->width ? video->width : gl->full_x;
gl->win_height = video->height ? video->height : gl->full_y;
}
else
{
gl->win_width = video->width;
gl->win_height = video->height;
}
SSNES_LOG("GL: Using resolution %ux%u\n", gl->win_width, gl->win_height);
gl->vsync = video->vsync;
gl->keep_aspect = video->force_aspect;
set_viewport(gl);
+27 -1
View File
@@ -25,7 +25,6 @@
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#else
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
@@ -42,6 +41,25 @@
#include "gl_common.h"
#ifdef __APPLE__
#define pglCreateProgram glCreateProgram
#define pglUseProgram glUseProgram
#define pglCreateShader glCreateShader
#define pglDeleteShader glDeleteShader
#define pglShaderSource glShaderSource
#define pglCompileShader glCompileShader
#define pglAttachShader glAttachShader
#define pglDetachShader glDetachShader
#define pglLinkProgram glLinkProgram
#define pglGetUniformLocation glGetUniformLocation
#define pglUniform1i glUniform1i
#define pglUniform2fv glUniform2fv
#define pglUniform4fv glUniform4fv
#define pglGetShaderiv glGetShaderiv
#define pglGetShaderInfoLog glGetShaderInfoLog
#define pglGetProgramiv glGetProgramiv
#define pglGetProgramInfoLog glGetProgramInfoLog
#else
static PFNGLCREATEPROGRAMPROC pglCreateProgram = NULL;
static PFNGLUSEPROGRAMPROC pglUseProgram = NULL;
static PFNGLCREATESHADERPROC pglCreateShader = NULL;
@@ -59,6 +77,7 @@ static PFNGLGETSHADERIVPROC pglGetShaderiv = NULL;
static PFNGLGETSHADERINFOLOGPROC pglGetShaderInfoLog = NULL;
static PFNGLGETPROGRAMIVPROC pglGetProgramiv = NULL;
static PFNGLGETPROGRAMINFOLOGPROC pglGetProgramInfoLog = NULL;
#endif
static bool glsl_enable = false;
static GLuint gl_program;
@@ -180,6 +199,8 @@ static void print_linker_log(GLuint obj)
bool gl_glsl_init(const char *path)
{
#ifndef __APPLE__
// Load shader functions.
pglCreateProgram = SDL_GL_GetProcAddress("glCreateProgram");
pglUseProgram = SDL_GL_GetProcAddress("glUseProgram");
@@ -198,13 +219,18 @@ bool gl_glsl_init(const char *path)
pglGetShaderInfoLog = SDL_GL_GetProcAddress("glGetShaderInfoLog");
pglGetProgramiv = SDL_GL_GetProcAddress("glGetProgramiv");
pglGetProgramInfoLog = SDL_GL_GetProcAddress("glGetProgramInfoLog");
#endif
SSNES_LOG("Checking GLSL shader support ...\n");
#ifdef __APPLE__
const bool shader_support = true;
#else
bool shader_support = pglCreateProgram && pglUseProgram && pglCreateShader
&& pglDeleteShader && pglShaderSource && pglCompileShader && pglAttachShader
&& pglDetachShader && pglLinkProgram && pglGetUniformLocation
&& pglUniform1i && pglUniform2fv && pglUniform4fv
&& pglGetShaderiv && pglGetShaderInfoLog && pglGetProgramiv && pglGetProgramInfoLog;
#endif
if (!shader_support)
{
+71
View File
@@ -0,0 +1,71 @@
/*
Author: Themaister
License: Public domain
*/
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s0 : TEXUNIT0)
{
float2 texsize = IN.texture_size;
const float scale_factor = 1.0;
float2 delta = 0.5 / (texsize * scale_factor);
float dx = delta.x;
float dy = delta.y;
float3 c00 = tex2D(s0, tex + float2(-dx, -dy)).xyz;
float3 c01 = tex2D(s0, tex + float2(-dx, 0)).xyz;
float3 c02 = tex2D(s0, tex + float2(-dx, dy)).xyz;
float3 c10 = tex2D(s0, tex + float2(0, -dy)).xyz;
float3 c11 = tex2D(s0, tex + float2(0, 0)).xyz;
float3 c12 = tex2D(s0, tex + float2(0, dy)).xyz;
float3 c20 = tex2D(s0, tex + float2(dx, -dy)).xyz;
float3 c21 = tex2D(s0, tex + float2(dx, 0)).xyz;
float3 c22 = tex2D(s0, tex + float2(dx, dy)).xyz;
output OUT;
float3 first = lerp(c00, c20, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 second = lerp(c02, c22, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 mid_horiz = lerp(c01, c21, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 mid_vert = lerp(c10, c12, frac(scale_factor * tex.y * texsize.y + 0.5));
float3 res = lerp(first, second, frac(scale_factor * tex.y * texsize.y + 0.5));
OUT.color = float4(0.28 * (res + mid_horiz + mid_vert) + 4.7 * abs(res - lerp(mid_horiz, mid_vert, 0.5)), 1.0);
return OUT;
}
+76
View File
@@ -0,0 +1,76 @@
/*
Author: Themaister
License: Public domain
*/
/* Default Vertex shader */
void main_vertex
(
float4 position : POSITION,
float4 color : COLOR,
float2 texCoord : TEXCOORD0,
uniform float4x4 modelViewProj,
out float4 oPosition : POSITION,
out float4 oColor : COLOR,
out float2 otexCoord : TEXCOORD
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
otexCoord = texCoord;
}
struct output
{
float4 color : COLOR;
};
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
};
float4 compress(float4 in_color, float threshold, float ratio)
{
float4 diff = in_color - float4(threshold);
diff = clamp(diff, 0.0, 100.0);
return in_color - (diff * (1.0 - 1.0/ratio));
}
output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s0 : TEXUNIT0)
{
float2 texsize = IN.texture_size;
const float scale_factor = 1.0;
float2 delta = 0.5 / (texsize * scale_factor);
float dx = delta.x;
float dy = delta.y;
float3 c00 = tex2D(s0, tex + float2(-dx, -dy)).xyz;
float3 c01 = tex2D(s0, tex + float2(-dx, 0)).xyz;
float3 c02 = tex2D(s0, tex + float2(-dx, dy)).xyz;
float3 c10 = tex2D(s0, tex + float2(0, -dy)).xyz;
float3 c11 = tex2D(s0, tex + float2(0, 0)).xyz;
float3 c12 = tex2D(s0, tex + float2(0, dy)).xyz;
float3 c20 = tex2D(s0, tex + float2(dx, -dy)).xyz;
float3 c21 = tex2D(s0, tex + float2(dx, 0)).xyz;
float3 c22 = tex2D(s0, tex + float2(dx, dy)).xyz;
output OUT;
float3 first = lerp(c00, c20, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 second = lerp(c02, c22, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 mid_horiz = lerp(c01, c21, frac(scale_factor * tex.x * texsize.x + 0.5));
float3 mid_vert = lerp(c10, c12, frac(scale_factor * tex.y * texsize.y + 0.5));
float3 res = lerp(first, second, frac(scale_factor * tex.y * texsize.y + 0.5));
float4 final = float4(0.26 * (res + mid_horiz + mid_vert) + 3.5 * abs(res - lerp(mid_horiz, mid_vert, 0.5)), 1.0);
OUT.color = compress(final, 0.8, 5.0);
return OUT;
}
+67
View File
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include "general.h"
#include "dynamic.h"
#include <assert.h>
// CRC32 implementation taken from BSNES source :)
@@ -87,6 +88,17 @@ struct bsv_movie
{
FILE *file;
uint8_t *state;
long *frame_pos; // A ring buffer keeping track of many key presses were requested per frame.
size_t frame_mask;
uint16_t current_frame_count;
size_t frame_ptr;
bool playback;
unsigned min_file_pos;
bool first_rewind;
bool did_rewind;
};
#define BSV_MAGIC 0x42535631
@@ -127,6 +139,7 @@ static inline uint16_t swap_if_big16(uint16_t val)
static bool init_playback(bsv_movie_t *handle, const char *path)
{
handle->playback = true;
handle->file = fopen(path, "rb");
if (!handle->file)
{
@@ -158,6 +171,8 @@ static bool init_playback(bsv_movie_t *handle, const char *path)
if (!handle->state)
return false;
handle->min_file_pos = sizeof(header) + state_size;
if (fread(handle->state, 1, state_size, handle->file) != state_size)
{
SSNES_ERR("Couldn't read state from movie.\n");
@@ -196,6 +211,8 @@ static bool init_record(bsv_movie_t *handle, const char *path)
if (!handle->state)
return false;
handle->min_file_pos = sizeof(header) + state_size;
psnes_serialize(handle->state, state_size);
fwrite(handle->state, 1, state_size, handle->file);
return true;
@@ -208,6 +225,7 @@ void bsv_movie_free(bsv_movie_t *handle)
if (handle->file)
fclose(handle->file);
free(handle->state);
free(handle->frame_pos);
free(handle);
}
}
@@ -240,9 +258,58 @@ bsv_movie_t *bsv_movie_init(const char *path, enum ssnes_movie_type type)
else if (!init_record(handle, path))
goto error;
if (!(handle->frame_pos = calloc((1 << 20), sizeof(long)))) // Just pick something really large :D
goto error;
handle->frame_mask = (1 << 20) - 1;
return handle;
error:
bsv_movie_free(handle);
return NULL;
}
void bsv_movie_set_frame_start(bsv_movie_t *handle)
{
//fprintf(stderr, "Starting frame: %u, Pos: %ld\n", (unsigned)handle->frame_ptr, ftell(handle->file));
handle->frame_pos[handle->frame_ptr] = ftell(handle->file);
}
void bsv_movie_set_frame_end(bsv_movie_t *handle)
{
//fprintf(stderr, "Frame++\n");
handle->frame_ptr = (handle->frame_ptr + 1) & handle->frame_mask;
handle->first_rewind = !handle->did_rewind;
handle->did_rewind = false;
}
void bsv_movie_frame_rewind(bsv_movie_t *handle)
{
//fprintf(stderr, "Frame--\n");
handle->did_rewind = true;
if (handle->frame_ptr <= 1)
{
handle->frame_ptr = 0;
fseek(handle->file, handle->min_file_pos, SEEK_SET);
}
else
{
handle->frame_ptr = (handle->frame_ptr - (handle->first_rewind ? 1 : 2)) & handle->frame_mask;
fseek(handle->file, handle->frame_pos[handle->frame_ptr], SEEK_SET);
}
if (ftell(handle->file) <= (long)handle->min_file_pos)
{
if (!handle->playback)
{
fseek(handle->file, 4 * sizeof(uint32_t), SEEK_SET);
psnes_serialize(handle->state, psnes_serialize_size());
fwrite(handle->state, 1, psnes_serialize_size(), handle->file);
}
else
fseek(handle->file, handle->min_file_pos, SEEK_SET);
}
}
+5 -3
View File
@@ -37,12 +37,14 @@ bool bsv_movie_get_input(bsv_movie_t *handle, int16_t *input);
// Recording
void bsv_movie_set_input(bsv_movie_t *handle, int16_t input);
// Used for rewinding while playback/record.
void bsv_movie_set_frame_start(bsv_movie_t *handle); // Debugging purposes.
void bsv_movie_set_frame_end(bsv_movie_t *handle);
void bsv_movie_frame_rewind(bsv_movie_t *handle);
void bsv_movie_free(bsv_movie_t *handle);
uint32_t crc32_calculate(const uint8_t *data, unsigned length);
#endif
+21 -5
View File
@@ -408,25 +408,33 @@ static bool send_chunk(netplay_t *handle)
return true;
}
#define MAX_RETRIES 16
#define MAX_RETRIES 64
#define RETRY_MS 500
static int poll_input(netplay_t *handle, bool block)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(handle->udp_fd, &fds);
FD_SET(handle->fd, &fds);
int max_fd = (handle->fd > handle->udp_fd ? handle->fd : handle->udp_fd) + 1;
struct timeval tv = {
.tv_sec = 0,
.tv_usec = block ? 500000 : 0
.tv_usec = block ? (RETRY_MS * 1000) : 0
};
int i = 0;
do
{
if (select(handle->udp_fd + 1, &fds, NULL, NULL, &tv) < 0)
if (select(max_fd, &fds, NULL, NULL, &tv) < 0)
return -1;
// Somewhat hacky, but we aren't using the TCP connection for anything useful atm.
// Will probably add some proper messaging system here later.
if (FD_ISSET(handle->fd, &fds))
return -1;
if (FD_ISSET(handle->udp_fd, &fds))
return 1;
@@ -434,10 +442,18 @@ static int poll_input(netplay_t *handle, bool block)
{
SSNES_WARN("Netplay connection hung up. Will continue without netplay.\n");
handle->has_connection = false;
return false;
return -1;
}
} while (i++ < MAX_RETRIES && block);
if (block)
SSNES_LOG("Network lag of %d ms, resending packet... Attempt %d of %d ...\n", RETRY_MS, i, MAX_RETRIES);
// Seems to be necessary on Win32.
FD_ZERO(&fds);
FD_SET(handle->udp_fd, &fds);
FD_SET(handle->fd, &fds);
} while ((i++ < MAX_RETRIES) && block);
if (block)
return -1;
+1 -1
View File
@@ -1,7 +1,7 @@
. qb/qb.params.sh
PACKAGE_NAME=ssnes
PACKAGE_VERSION=0.3
PACKAGE_VERSION=0.3.1
# Adds a command line opt to ./configure --help
# $1: Variable (HAVE_ALSA, HAVE_OSS, etc)
+2 -2
View File
@@ -50,7 +50,7 @@ check_lib()
extralibs="$4"
$CC -o $TEMP_EXE $TEMP_C $INCLUDE_DIRS $LIBRARY_DIRS $extralibs $2 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes
$CC -o $TEMP_EXE $TEMP_C $INCLUDE_DIRS $LIBRARY_DIRS $CFLAGS $LDFLAGS $extralibs $2 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes
echo $answer
@@ -75,7 +75,7 @@ check_lib_cxx()
extralibs="$4"
$CXX -o $TEMP_EXE $TEMP_CXX $INCLUDE_DIRS $LIBRARY_DIRS $extralibs $2 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes
$CXX -o $TEMP_EXE $TEMP_CXX $INCLUDE_DIRS $LIBRARY_DIRS $CFLAGS $LDFLAGS $extralibs $2 2>/dev/null >/dev/null && answer=yes && eval HAVE_$1=yes
echo $answer
+8 -1
View File
@@ -33,6 +33,7 @@ struct state_manager
size_t top_ptr;
size_t bottom_ptr;
size_t state_size;
bool first_pop;
};
state_manager_t *state_manager_new(size_t state_size, size_t buffer_size, void *init_buffer)
@@ -77,6 +78,11 @@ void state_manager_free(state_manager_t *state)
bool state_manager_pop(state_manager_t *state, void **data)
{
*data = state->tmp_state;
if (state->first_pop)
{
state->first_pop = false;
return true;
}
if (state->top_ptr == 0)
state->top_ptr = state->buf_size - 1;
@@ -126,7 +132,7 @@ static void generate_delta(state_manager_t *state, const void *data)
const uint32_t *new_state = data;
state->buffer[state->top_ptr++] = 0; // For each separate delta, we have a 0 value sentinel in between.
if (state->top_ptr == state->bottom_ptr) // Check if top_ptr and bottom_ptr crossed eachother, which means we need to delete old cruft.
if (state->top_ptr == state->bottom_ptr) // Check if top_ptr and bottom_ptr crossed each other, which means we need to delete old cruft.
crossed = true;
for (uint64_t i = 0; i < state->state_size; i++)
@@ -156,6 +162,7 @@ bool state_manager_push(state_manager_t *state, const void *data)
{
generate_delta(state, data);
memcpy(state->tmp_state, data, state->state_size * sizeof(uint32_t));
state->first_pop = true;
return true;
}
+61 -23
View File
@@ -107,6 +107,7 @@ static void set_defaults(void)
#ifdef HAVE_FILTER
g_settings.video.filter = FILTER_NONE;
#endif
g_settings.video.shader_type = SSNES_SHADER_AUTO;
#ifdef HAVE_FREETYPE
g_settings.video.font_size = font_size;
@@ -320,6 +321,22 @@ static void parse_config_file(void)
}
#endif
#if defined(HAVE_CG) || defined(HAVE_XML)
if (config_get_string(conf, "video_shader_type", &tmp_str))
{
if (strcmp("cg", tmp_str) == 0)
g_settings.video.shader_type = SSNES_SHADER_CG;
else if (strcmp("bsnes", tmp_str) == 0)
g_settings.video.shader_type = SSNES_SHADER_BSNES;
else if (strcmp("auto", tmp_str) == 0)
g_settings.video.shader_type = SSNES_SHADER_AUTO;
else if (strcmp("none", tmp_str) == 0)
g_settings.video.shader_type = SSNES_SHADER_NONE;
free(tmp_str);
}
#endif
CONFIG_GET_DOUBLE(input.axis_threshold, "input_axis_threshold");
CONFIG_GET_BOOL(input.netplay_client_swap_input, "netplay_client_swap_input");
CONFIG_GET_INT(input.joypad_map[0], "input_player1_joypad_index");
@@ -405,6 +422,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS)
DECLARE_BIND(rewind, SSNES_REWIND)
DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE)
DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE)
},
{
DECLARE_BIND(player2_a, SNES_DEVICE_ID_JOYPAD_A)
@@ -430,6 +448,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS)
DECLARE_BIND(rewind, SSNES_REWIND)
DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE)
DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE)
},
{
DECLARE_BIND(player3_a, SNES_DEVICE_ID_JOYPAD_A)
@@ -455,6 +474,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS)
DECLARE_BIND(rewind, SSNES_REWIND)
DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE)
DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE)
},
{
DECLARE_BIND(player4_a, SNES_DEVICE_ID_JOYPAD_A)
@@ -480,6 +500,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS)
DECLARE_BIND(rewind, SSNES_REWIND)
DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE)
DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE)
},
{
DECLARE_BIND(player5_a, SNES_DEVICE_ID_JOYPAD_A)
@@ -505,6 +526,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = {
DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS)
DECLARE_BIND(rewind, SSNES_REWIND)
DECLARE_BIND(movie_record_toggle, SSNES_MOVIE_RECORD_TOGGLE)
DECLARE_BIND(pause_toggle, SSNES_PAUSE_TOGGLE)
},
};
@@ -545,6 +567,7 @@ static const struct key_map sdlk_map[] = {
{ "f10", SDLK_F10 },
{ "f11", SDLK_F11 },
{ "f12", SDLK_F12 },
{ "nul", SDLK_UNKNOWN },
};
static struct snes_keybind *find_snes_bind(unsigned port, int id)
@@ -578,6 +601,7 @@ static int find_sdlk_key(const char *str)
return find_sdlk_bind(str);
}
// Yes, this function needs a good refactor :)
static void read_keybinds(config_file_t *conf)
{
char *tmp_key = NULL;
@@ -592,6 +616,7 @@ static void read_keybinds(config_file_t *conf)
if (!bind)
continue;
// Check keybind
if (bind_maps[j][i].key && config_get_string(conf, bind_maps[j][i].key, &tmp_key))
{
int key = find_sdlk_key(tmp_key);
@@ -603,40 +628,53 @@ static void read_keybinds(config_file_t *conf)
tmp_key = NULL;
}
// Check joybutton bind (hats too)
if (bind_maps[j][i].btn && config_get_string(conf, bind_maps[j][i].btn, &tmp_btn))
{
const char *btn = tmp_btn;
if (*btn++ == 'h')
if (strcmp(tmp_btn, "nul") == 0)
{
if (isdigit(*btn))
{
char *dir = NULL;
int hat = strtol(btn, &dir, 0);
int hat_dir = 0;
if (dir)
{
if (strcasecmp(dir, "up") == 0)
hat_dir = HAT_UP_MASK;
else if (strcasecmp(dir, "down") == 0)
hat_dir = HAT_DOWN_MASK;
else if (strcasecmp(dir, "left") == 0)
hat_dir = HAT_LEFT_MASK;
else if (strcasecmp(dir, "right") == 0)
hat_dir = HAT_RIGHT_MASK;
if (hat_dir)
bind->joykey = HAT_MAP(hat, hat_dir);
}
}
bind->joykey = NO_BTN;
}
else
bind->joykey = strtol(tmp_btn, NULL, 0);
{
if (*btn++ == 'h')
{
if (isdigit(*btn))
{
char *dir = NULL;
int hat = strtol(btn, &dir, 0);
int hat_dir = 0;
if (dir)
{
if (strcasecmp(dir, "up") == 0)
hat_dir = HAT_UP_MASK;
else if (strcasecmp(dir, "down") == 0)
hat_dir = HAT_DOWN_MASK;
else if (strcasecmp(dir, "left") == 0)
hat_dir = HAT_LEFT_MASK;
else if (strcasecmp(dir, "right") == 0)
hat_dir = HAT_RIGHT_MASK;
if (hat_dir)
bind->joykey = HAT_MAP(hat, hat_dir);
}
}
}
else
bind->joykey = strtol(tmp_btn, NULL, 0);
}
free(tmp_btn);
}
// Check joyaxis binds.
if (bind_maps[j][i].axis && config_get_string(conf, bind_maps[j][i].axis, &tmp_axis))
{
if (strlen(tmp_axis) >= 2 && (*tmp_axis == '+' || *tmp_axis == '-'))
if (strcmp(tmp_axis, "nul") == 0)
{
bind->joyaxis = AXIS_NONE;
}
else if (strlen(tmp_axis) >= 2 && (*tmp_axis == '+' || *tmp_axis == '-'))
{
int axis = strtol(tmp_axis + 1, NULL, 0);
if (*tmp_axis == '+')
+28 -10
View File
@@ -285,7 +285,7 @@ static void fill_pathname(char *out_path, char *in_path, const char *replace)
#endif
#ifdef _WIN32
#define PACKAGE_VERSION "0.3"
#define PACKAGE_VERSION "0.3.1"
#endif
#include "config.features.h"
@@ -1037,6 +1037,13 @@ static void check_input_rate(void)
static void check_rewind(void)
{
g_extern.frame_is_reverse = false;
static bool first = true;
if (first)
{
first = false;
return;
}
if (!g_extern.state_manager)
return;
@@ -1046,9 +1053,15 @@ static void check_rewind(void)
void *buf;
if (state_manager_pop(g_extern.state_manager, &buf))
{
g_extern.frame_is_reverse = true;
msg_queue_push(g_extern.msg_queue, "Rewinding!", 0, 30);
psnes_unserialize(buf, psnes_serialize_size());
g_extern.frame_is_reverse = true;
if (g_extern.bsv_movie)
{
for (unsigned i = 0; i < (g_settings.rewind_granularity ? g_settings.rewind_granularity : 1); i++)
bsv_movie_frame_rewind(g_extern.bsv_movie);
}
}
else
msg_queue_push(g_extern.msg_queue, "Reached end of rewind buffer!", 0, 30);
@@ -1057,7 +1070,7 @@ static void check_rewind(void)
{
static unsigned cnt = 0;
cnt = (cnt + 1) % (g_settings.rewind_granularity ? g_settings.rewind_granularity : 1); // Avoid possible SIGFPE.
if (cnt == 0)
if (cnt == 0 || g_extern.bsv_movie)
{
psnes_serialize(g_extern.state_buf, psnes_serialize_size());
state_manager_push(g_extern.state_manager, g_extern.state_buf);
@@ -1174,8 +1187,8 @@ static void do_state_checks(void)
{
check_stateslots();
check_savestates();
check_rewind();
}
check_rewind();
if (!g_extern.bsv_movie_playback)
check_movie_record();
@@ -1207,14 +1220,15 @@ int main(int argc, char *argv[])
init_movie();
if (!g_extern.bsv_movie)
{
load_save_files();
init_rewind();
}
init_netplay();
init_drivers();
if (!g_extern.netplay)
init_rewind();
psnes_set_video_refresh(g_extern.netplay ? video_frame_net : video_frame);
psnes_set_audio_sample(g_extern.netplay ? audio_sample_net : audio_sample);
psnes_set_input_poll(g_extern.netplay ? input_poll_net : input_poll);
@@ -1247,9 +1261,13 @@ int main(int argc, char *argv[])
if (g_extern.netplay)
netplay_pre_frame(g_extern.netplay);
if (g_extern.bsv_movie)
bsv_movie_set_frame_start(g_extern.bsv_movie);
psnes_run();
if (g_extern.bsv_movie)
bsv_movie_set_frame_end(g_extern.bsv_movie);
if (g_extern.netplay)
netplay_post_frame(g_extern.netplay);
@@ -1280,10 +1298,10 @@ int main(int argc, char *argv[])
#endif
if (!g_extern.bsv_movie_playback && !g_extern.netplay_is_client)
{
deinit_rewind();
save_files();
}
if (!g_extern.netplay)
deinit_rewind();
deinit_movie();
deinit_msg_queue();
+10 -4
View File
@@ -9,9 +9,9 @@
# video_xscale = 3.0
# video_yscale = 3.0
# Fullscreen resolution
# video_fullscreen_x = 1920
# video_fullscreen_y = 1200
# Fullscreen resolution. Resolution of 0 uses the resolution of the desktop.
# video_fullscreen_x = 0
# video_fullscreen_y = 0
# Start in fullscreen. Can be changed at runtime.
# video_fullscreen = false
@@ -31,9 +31,13 @@
# Path to Cg shader.
# video_cg_shader = "/path/to/cg/shader.cg"
# Path to bSNES-style XML shader (GLSL only). If both Cg shader path and XML shader path are defined, Cg shader will take priority.
# Path to bSNES-style XML shader (GLSL only). If both Cg shader path and XML shader path are defined,
# Cg shader will take priority unless overridden in video_shader_type.
# video_bsnes_shader = "/path/to/bsnes/xml/shader.shader"
# Which shader type to use. Valid values are "cg", "bsnes", "none" and "auto"
# video_shader_type = auto
# CPU-based filter. Valid ones are: hq2x, hq4x, grayscale, bleed, ntsc.
# video_filter = ntsc
@@ -90,6 +94,8 @@
# input_axis_threshold = 0.5
# Keyboard input. Will recognize normal keypresses and special keys like "left", "right", and so on.
# Keyboard input, Joypad and Joyaxis will all obey the "nul" bind, which disables the bind completely,
# rather than relying on a default.
# input_player1_a = x
# input_player1_b = z
# input_player1_y = a