Compare commits

...
38 Commits
Author SHA1 Message Date
Themaister f79eafe449 Should perhaps continue if one joypad failed. 2011-06-12 10:42:42 +02:00
Themaister 111b159373 Should fix dinput. 2011-06-12 10:37:04 +02:00
Themaister d744167865 Small cleanup. 2011-06-11 22:46:51 +02:00
Themaister a2fea86c92 Fixes 2-5 player. (Damn o.O) 2011-06-11 22:25:55 +02:00
Themaister 5385806e74 Hrm ... 2011-06-11 22:02:05 +02:00
Themaister 99e85684db Input capturing semantic. 2011-06-11 20:02:17 +02:00
Themaister 45727bf9f5 Fix mask value. (32-bit). 2011-06-11 19:01:34 +02:00
Themaister 2a0abb0618 Unsigned mask. 2011-06-11 18:57:16 +02:00
Themaister 192e3303a1 Update dist and version. 2011-06-11 18:19:00 +02:00
Themaister b6051add6a SDL_image for Win32 2011-06-11 18:13:12 +02:00
Themaister 24d0cda5fd SDL_image seems to work :) 2011-06-11 18:05:52 +02:00
Themaister d0ba59f8b5 Start moving over to SDL_image rather than imlib2.
Imlib2 takes more space, and was a pure bitch to compile for Win32,
so I gave up ... ;)
2011-06-11 16:55:53 +02:00
Themaister 99a1784aaf Move window logic away from SDL input.
We weren't using the event loop anyways ...
2011-06-11 12:54:14 +02:00
Themaister b6ff98cf18 Should fix DInput crash. 2011-06-10 18:01:44 +02:00
Themaister 2dcccc7cda Fix some includes and stuff. 2011-06-10 17:55:40 +02:00
Themaister d03855c655 Add some sanity logging. 2011-06-10 17:47:16 +02:00
Themaister 69227bc1ca Alter design. Use DInput as piggyback only. 2011-06-10 17:34:04 +02:00
Themaister 851debf1e4 Start working on DInput. 2011-06-10 16:55:05 +02:00
Themaister 8c1db1c407 Fix shenanigans. 2011-06-09 23:17:10 +02:00
Themaister 576894e0e8 Build Python in Windows. 2011-06-09 13:56:29 +02:00
Themaister 631c3ca393 Fix link for Clang. 2011-06-08 19:52:03 +02:00
Themaister fd70a1c875 Make sure we only call semantics once per frame. 2011-06-08 17:59:29 +02:00
Themaister 30cb2e4c07 Slight cleanup. 2011-06-08 17:55:32 +02:00
Themaister 7d87cc2d24 Add input hook API to python. 2011-06-08 17:53:15 +02:00
Themaister 0342dcb169 Fix transition_prev. 2011-06-07 21:07:00 +02:00
Themaister f339560550 Put all scripts in <script> 2011-06-07 16:28:58 +02:00
Themaister 11b58d8c69 Clean up error handling a bit. 2011-06-07 15:58:30 +02:00
Themaister 3717f7442c Inline XML python. 2011-06-07 15:33:29 +02:00
Themaister e02d9f41e8 Transition count semantic. 2011-06-06 21:32:10 +02:00
Themaister f62120861a Show if python is compiled in or not. 2011-06-06 20:21:26 +02:00
Themaister 884e2881a0 Add script support to Cg. 2011-06-06 20:18:31 +02:00
Themaister a605628dff :v 2011-06-06 18:50:59 +02:00
Themaister 4d96fbba6a Python works :P 2011-06-06 18:50:36 +02:00
Themaister 9bfeb88e24 Start implementing Python support for game-aware shaders. 2011-06-06 17:44:05 +02:00
Themaister 712f463022 Disable audio sync properly in external driver. 2011-06-06 02:01:21 +02:00
Themaister 713e8624a0 Fixed typo. 2011-06-05 22:23:50 +02:00
Themaister 5c8a549125 Cleanups. 2011-06-05 02:21:35 +02:00
Themaister c3e7a35b62 Fixes case where backdrops are used in second or later pass. 2011-06-05 02:01:44 +02:00
24 changed files with 1330 additions and 234 deletions

No files matched your search

+11 -4
View File
@@ -79,7 +79,7 @@ endif
ifeq ($(HAVE_XVIDEO), 1)
OBJ += gfx/xvideo.o input/x11_input.o
LIBS += -lXv -lX11
LIBS += -lX11 -lXext -lXv
endif
ifeq ($(HAVE_CG), 1)
@@ -104,9 +104,9 @@ ifeq ($(HAVE_FREETYPE), 1)
DEFINES += $(FREETYPE_CFLAGS)
endif
ifeq ($(HAVE_IMLIB), 1)
LIBS += $(IMLIB_LIBS)
DEFINES += $(IMLIB_CFLAGS)
ifeq ($(HAVE_SDL_IMAGE), 1)
LIBS += $(SDL_IMAGE_LIBS)
DEFINES += $(SDL_IMAGE_CFLAGS)
endif
ifeq ($(HAVE_FFMPEG), 1)
@@ -125,6 +125,12 @@ ifeq ($(HAVE_STRL), 1)
DEFINES += -DHAVE_STRL
endif
ifeq ($(HAVE_PYTHON), 1)
DEFINES += $(PYTHON_CFLAGS) -Wno-unused-parameter
LIBS += $(PYTHON_LIBS)
OBJ += gfx/py_state/py_state.o
endif
ifneq ($(V),1)
Q := @
endif
@@ -177,6 +183,7 @@ clean:
rm -f audio/*.o
rm -f conf/*.o
rm -f gfx/*.o
rm -f gfx/py_state/*.o
rm -f record/*.o
rm -f input/*.o
rm -f tools/*.o
+20 -6
View File
@@ -6,8 +6,10 @@ JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o
CC = gcc
CXX = g++
HAVE_DINPUT = 1
HAVE_SRC = 0
HAVE_SDL = 1
HAVE_SDL_IMAGE = 1
HAVE_XML = 1
HAVE_FREETYPE = 1
HAVE_XAUDIO = 1
@@ -15,8 +17,8 @@ HAVE_RSOUND = 1
HAVE_DYLIB = 1
HAVE_NETPLAY = 1
HAVE_FBO = 1
HAVE_CG = 0
HAVE_IMLIB = 0
HAVE_CG = 1
HAVE_PYTHON = 1
libsnes ?= -lsnes
LIBS = -lm
@@ -40,6 +42,11 @@ ifeq ($(HAVE_SDL), 1)
DEFINES += $(SDL_CFLAGS) -DHAVE_SDL
endif
ifeq ($(HAVE_SDL_IMAGE), 1)
LIBS += -lSDL_image
DEFINES += -DHAVE_SDL_IMAGE
endif
ifeq ($(HAVE_CG), 1)
OBJ += gfx/shader_cg.o
LIBS += -lcg -lcgGL
@@ -93,11 +100,17 @@ ifeq ($(HAVE_DYLIB), 1)
OBJ += gfx/ext.o audio/ext.o
endif
ifeq ($(HAVE_IMLIB), 1)
LIBS += -lImlib2
DEFINES += -DHAVE_IMLIB
ifeq ($(HAVE_PYTHON), 1)
LIBS += -lpython32
DEFINES += -DHAVE_PYTHON -Ipython
OBJ += gfx/py_state/py_state.o
endif
ifeq ($(HAVE_DINPUT), 1)
LIBS += -ldinput8 -ldxguid -lole32
DEFINES += -DHAVE_DINPUT
OBJ += input/dinput.o
endif
ifneq ($(V),1)
Q := @
@@ -125,6 +138,7 @@ clean:
rm -f audio/*.o
rm -f conf/*.o
rm -f gfx/*.o
rm -f gfx/py_state/*.o
rm -f record/*.o
rm -f hqflt/*.o
rm -f input/*.o
@@ -134,7 +148,7 @@ clean:
rm -f tools/*.o
dist: all
zip -r ssnes-win32-0.5.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)
zip -r ssnes-win32-0.5.2.zip $(TARGET) ssnes.cfg snes.dll libxml2.dll iconv.dll zlib1.dll SDL.dll freetype6.dll xaudio-c.dll rsound.dll pthreadGC2.dll cg.dll cgGL.dll libjpeg-8.dll libpng15-15.dll python32.dll SDL_image.dll $(JTARGET)
libs:
wget https://github.com/downloads/Themaister/SSNES/SSNES-win32-libs.zip --no-check-certificate
+13 -4
View File
@@ -6,6 +6,7 @@ JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o
CC = gcc
CXX = g++
HAVE_DINPUT = 1
HAVE_SRC = 0
HAVE_SDL = 1
HAVE_XML = 1
@@ -16,7 +17,7 @@ HAVE_DYLIB = 1
HAVE_NETPLAY = 1
HAVE_FBO = 1
HAVE_CG = 0
HAVE_IMLIB = 0
HAVE_PYTHON = 0
libsnes ?= -lsnes
LIBS = -lm
@@ -93,11 +94,19 @@ ifeq ($(HAVE_DYLIB), 1)
OBJ += gfx/ext.o audio/ext.o
endif
ifeq ($(HAVE_IMLIB), 1)
LIBS += -lImlib2
DEFINES += -DHAVE_IMLIB
ifeq ($(HAVE_PYTHON), 1)
LIBS += -lpython32
DEFINES += -DHAVE_PYTHON -Ipython
OBJ += gfx/py_state/py_state.o
endif
ifeq ($(HAVE_DINPUT), 1)
LIBS += -ldinput8 -ldxguid -lole32
DEFINES += -DHAVE_DINPUT
OBJ += input/dinput.o
endif
ifneq ($(V),1)
Q := @
endif
+4 -1
View File
@@ -83,7 +83,7 @@ static void* audio_ext_init(const char *device, unsigned rate, unsigned latency)
if (ext->driver->api_version != SSNES_AUDIO_API_VERSION)
{
SSNES_ERR("API mismatch in external video plugin. SSNES: %d, Plugin: %d ...\n", SSNES_AUDIO_API_VERSION, ext->driver->api_version);
SSNES_ERR("API mismatch in external audio plugin. SSNES: %d, Plugin: %d ...\n", SSNES_AUDIO_API_VERSION, ext->driver->api_version);
goto error;
}
@@ -103,6 +103,9 @@ static void* audio_ext_init(const char *device, unsigned rate, unsigned latency)
if (ext->driver->sample_rate)
g_settings.audio.out_rate = ext->driver->sample_rate(ext->handle);
if (!g_settings.audio.sync)
ext->driver->set_nonblock_state(ext->handle, SSNES_TRUE);
return ext;
error:
+3
View File
@@ -72,6 +72,9 @@ static void* __xa_init(const char* device, unsigned rate, unsigned latency)
if (!init_lib())
return NULL;
if (latency < 8)
latency = 8; // Do not allow shenanigans.
xa_t *xa = calloc(1, sizeof(xa_t));
if (xa == NULL)
return NULL;
+12
View File
@@ -253,6 +253,18 @@ static const struct snes_keybind snes_keybinds_1[] = {
// Player 2-5
static const struct snes_keybind snes_keybinds_rest[] = {
{ SNES_DEVICE_ID_JOYPAD_A, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_B, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_X, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_Y, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_L, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_R, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_LEFT, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_RIGHT, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_UP, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_DOWN, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_START, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ SNES_DEVICE_ID_JOYPAD_SELECT, SDLK_UNKNOWN, NO_BTN, AXIS_NONE },
{ -1 }
};
+9 -3
View File
@@ -80,10 +80,10 @@ static const bool _xml_supp = true;
static const bool _xml_supp = false;
#endif
#ifdef HAVE_IMLIB
static const bool _imlib_supp = true;
#ifdef HAVE_SDL_IMAGE
static const bool _sdl_image_supp = true;
#else
static const bool _imlib_supp = false;
static const bool _sdl_image_supp = false;
#endif
#ifdef HAVE_FBO
@@ -128,4 +128,10 @@ static const bool _netplay_supp = true;
static const bool _netplay_supp = false;
#endif
#ifdef HAVE_PYTHON
static const bool _python_supp = true;
#else
static const bool _python_supp = false;
#endif
#endif
+2 -2
View File
@@ -132,7 +132,7 @@ static void find_input_driver(void)
SSNES_ERR("Couldn't find any input driver named \"%s\"\n", g_settings.input.driver);
fprintf(stderr, "Available input drivers are:\n");
for (int i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++)
fprintf(stderr, "\t%s\n", video_drivers[i]->ident);
fprintf(stderr, "\t%s\n", input_drivers[i]->ident);
exit(1);
}
@@ -452,7 +452,7 @@ void init_video_input(void)
if ( driver.video_data == NULL )
{
SSNES_ERR("Cannot open video driver... Exiting ...\n");
SSNES_ERR("Cannot open video driver ... Exiting ...\n");
exit(1);
}
+77 -50
View File
@@ -52,14 +52,17 @@
#include "fonts.h"
#endif
static const GLfloat vertexes[] = {
// Used for the last pass when rendering to the back buffer.
static const GLfloat vertexes_flipped[] = {
0, 0,
0, 1,
1, 1,
1, 0
};
static const GLfloat vertexes_flipped[] = {
// Used when rendering to an FBO.
// Texture coords have to be aligned with vertex coordinates.
static const GLfloat vertexes[] = {
0, 1,
0, 0,
1, 0,
@@ -73,12 +76,6 @@ static const GLfloat tex_coords[] = {
1, 1
};
static const GLfloat fbo_tex_coords[] = {
0, 0,
0, 1,
1, 1,
1, 0
};
#ifdef HAVE_FBO
#ifdef _WIN32
@@ -655,18 +652,64 @@ static void gl_render_msg(gl_t *gl, const char *msg)
// Go back to old rendering path.
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
glBindTexture(GL_TEXTURE_2D, gl->texture);
glDisable(GL_BLEND);
#endif
}
static inline void set_lut_texture_coords(const GLfloat *coords)
{
#if defined(HAVE_XML) || defined(HAVE_CG)
// For texture images.
pglClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), coords);
pglClientActiveTexture(GL_TEXTURE0);
#else
(void)coords;
#endif
}
static inline void set_texture_coords(GLfloat *coords, GLfloat xamt, GLfloat yamt)
{
coords[1] = yamt;
coords[4] = xamt;
coords[6] = xamt;
coords[7] = yamt;
}
static void check_window(gl_t *gl)
{
SDL_Event event;
// Search for events we care about ...
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
gl->quitting = true;
break;
case SDL_VIDEORESIZE:
gl->should_resize = true;
gl->win_width = event.resize.w;
gl->win_height = event.resize.h;
break;
default:
break;
}
}
}
static bool gl_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
gl_t *gl = data;
check_window(gl);
gl_shader_use(1);
gl->frame_count++;
#ifdef HAVE_FBO
@@ -791,13 +834,10 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
0, 0, 0, gl->tex_w, gl->tex_h, gl->texture_type,
gl->texture_fmt, gl->empty_buf);
GLfloat x = (GLfloat)width / gl->tex_w;
GLfloat y = (GLfloat)height / gl->tex_h;
GLfloat xamt = (GLfloat)width / gl->tex_w;
GLfloat yamt = (GLfloat)height / gl->tex_h;
gl->tex_coords[1] = y;
gl->tex_coords[4] = x;
gl->tex_coords[6] = x;
gl->tex_coords[7] = y;
set_texture_coords(gl->tex_coords, xamt, yamt);
}
// Work around a certain issue a Cg where not using TEXUNIT0
@@ -812,7 +852,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
// Need to preserve the "flipped" state when in FBO too to have
// consistent texture coordinates.
if (gl->render_to_tex)
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes);
#endif
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch / gl->base_size);
@@ -838,10 +878,6 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
#ifdef HAVE_FBO
if (gl->fbo_inited)
{
// Go back to non-flipped.
if (gl->render_to_tex)
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes);
// Render the rest of our passes.
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->fbo_tex_coords);
@@ -860,10 +896,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
GLfloat xamt = (GLfloat)prev_rect->img_width / prev_rect->width;
GLfloat yamt = (GLfloat)prev_rect->img_height / prev_rect->height;
gl->fbo_tex_coords[3] = yamt;
gl->fbo_tex_coords[4] = xamt;
gl->fbo_tex_coords[5] = yamt;
gl->fbo_tex_coords[6] = xamt;
set_texture_coords(gl->fbo_tex_coords, xamt, yamt);
fbo_info->tex = gl->fbo_texture[i - 1];
fbo_info->input_size[0] = prev_rect->img_width;
@@ -895,10 +928,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
GLfloat xamt = (GLfloat)prev_rect->img_width / prev_rect->width;
GLfloat yamt = (GLfloat)prev_rect->img_height / prev_rect->height;
gl->fbo_tex_coords[3] = yamt;
gl->fbo_tex_coords[4] = xamt;
gl->fbo_tex_coords[5] = yamt;
gl->fbo_tex_coords[6] = xamt;
set_texture_coords(gl->fbo_tex_coords, xamt, yamt);
// Render our FBO texture to back buffer.
pglBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -915,10 +945,9 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei
&tex_info, fbo_tex_info, fbo_tex_info_cnt);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
glDrawArrays(GL_QUADS, 0, 4);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes);
}
#endif
@@ -1007,7 +1036,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
SDL_ShowCursor(SDL_DISABLE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#if (defined(HAVE_XML) || defined(HAVE_CG)) && defined(_WIN32)
#if (defined(HAVE_XML) || defined(HAVE_CG)) && defined(_WIN32)
// Win32 GL lib doesn't have some functions needed for XML shaders.
// Need to load dynamically :(
if (!load_gl_proc())
@@ -1065,7 +1094,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
// Set up render to texture.
gl_init_fbo(gl, 256 * video->input_scale, 256 * video->input_scale);
gl->keep_aspect = video->force_aspect;
// Apparently need to set viewport for passes when we aren't using FBOs.
@@ -1109,18 +1138,12 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes);
glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes_flipped);
memcpy(gl->tex_coords, tex_coords, sizeof(tex_coords));
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), gl->tex_coords);
#ifdef HAVE_XML
// For texture images.
pglClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), tex_coords);
pglClientActiveTexture(GL_TEXTURE0);
#endif
set_lut_texture_coords(tex_coords);
gl->tex_w = 256 * video->input_scale;
gl->tex_h = 256 * video->input_scale;
@@ -1139,10 +1162,6 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
sdl_input_t *sdl_input = input_sdl.init();
if (sdl_input)
{
sdl_input->quitting = &gl->quitting;
sdl_input->should_resize = &gl->should_resize;
sdl_input->new_width = &gl->win_width;
sdl_input->new_height = &gl->win_height;
*input = &input_sdl;
*input_data = sdl_input;
}
@@ -1150,7 +1169,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo
*input = NULL;
gl_init_font(gl, g_settings.video.font_path, g_settings.video.font_size);
if (!gl_check_error())
{
SDL_QuitSubSystem(SDL_INIT_VIDEO);
@@ -1177,7 +1196,13 @@ static bool gl_focus(void *data)
static bool gl_xml_shader(void *data, const char *path)
{
gl_t *gl = data;
gl_shader_deinit();
//if (!gl_check_error())
// SSNES_WARN("Error happened before deinit!\n");
//if (!gl_check_error())
// SSNES_WARN("Error happened in deinit!\n");
#ifdef HAVE_FBO
if (gl->fbo_inited)
@@ -1190,13 +1215,15 @@ static bool gl_xml_shader(void *data, const char *path)
gl->render_to_tex = false;
gl->fbo_pass = 0;
if (!gl_check_error())
SSNES_WARN("Failed to deinit FBO properly!\n");
glBindTexture(GL_TEXTURE_2D, gl->texture);
}
#endif
gl_shader_deinit();
//if (!gl_check_error())
// SSNES_WARN("Failed to deinit rendering path properly!\n");
if (!gl_glsl_init(path))
return false;
+55 -14
View File
@@ -27,35 +27,76 @@
#include <stddef.h>
#include "general.h"
#ifdef HAVE_IMLIB
#ifdef HAVE_SDL_IMAGE
#include <Imlib2.h>
#include "SDL_image.h"
bool texture_image_load(const char *path, struct texture_image *out_img)
{
Imlib_Image img;
img = imlib_load_image(path);
SDL_Surface *img = IMG_Load(path);
if (!img)
return false;
imlib_context_set_image(img);
out_img->width = imlib_image_get_width();
out_img->height = imlib_image_get_height();
out_img->width = img->w;
out_img->height = img->h;
size_t size = out_img->width * out_img->height * sizeof(uint32_t);
out_img->pixels = malloc(size);
if (!out_img->pixels)
{
imlib_free_image();
SDL_FreeSurface(img);
return false;
}
const uint32_t *read = imlib_image_get_data_for_reading_only();
// Convert ARGB -> RGBA.
for (unsigned i = 0; i < size / sizeof(uint32_t); i++)
out_img->pixels[i] = (read[i] >> 24) | (read[i] << 8);
const SDL_PixelFormat *fmt = img->format;
SSNES_LOG("SDL_image: %dx%d @ %d bpp\n", img->w, img->h, img->format->BitsPerPixel);
if (img->format->BitsPerPixel == 32)
{
for (unsigned y = 0; y < img->h; y++)
{
uint32_t *dst = out_img->pixels + y * img->w;
const uint32_t *src = (const uint32_t*)img->pixels + y * img->pitch / sizeof(uint32_t);
for (unsigned x = 0; x < img->w; x++)
{
uint32_t r = (src[x] & fmt->Rmask) >> fmt->Rshift;
uint32_t g = (src[x] & fmt->Gmask) >> fmt->Gshift;
uint32_t b = (src[x] & fmt->Bmask) >> fmt->Bshift;
uint32_t a = (src[x] & fmt->Amask) >> fmt->Ashift;
dst[x] = (r << 24) | (g << 16) | (b << 8) | a;
}
}
}
else if (img->format->BitsPerPixel == 24)
{
for (unsigned y = 0; y < img->h; y++)
{
uint32_t *dst = out_img->pixels + y * img->w;
const uint8_t *src = (const uint8_t*)img->pixels + y * img->pitch;
for (unsigned x = 0; x < img->w; x++)
{
// Correct?
uint32_t color = 0;
color |= src[3 * x + 0] << 0;
color |= src[3 * x + 1] << 8;
color |= src[3 * x + 2] << 16;
uint32_t r = (color & fmt->Rmask) >> fmt->Rshift;
uint32_t g = (color & fmt->Gmask) >> fmt->Gshift;
uint32_t b = (color & fmt->Bmask) >> fmt->Bshift;
dst[x] = (r << 24) | (g << 16) | (b << 8) | 0xff;
}
}
}
else
{
SSNES_ERR("8-bit and 16-bit image support are not implemented.\n");
SDL_FreeSurface(img);
return false;
}
SDL_FreeSurface(img);
imlib_free_image();
return true;
}
+288
View File
@@ -0,0 +1,288 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <Python.h>
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dynamic.h"
#include "libsnes.hpp"
#include "py_state.h"
#include "general.h"
#include "strl.h"
#define PY_READ_FUNC_DECL(RAMTYPE) py_read_##RAMTYPE
#define PY_READ_FUNC(RAMTYPE) \
static PyObject* PY_READ_FUNC_DECL(RAMTYPE) (PyObject *self, PyObject *args) \
{ \
(void)self; \
\
const uint8_t *data = psnes_get_memory_data(SNES_MEMORY_##RAMTYPE); \
if (!data) \
{ \
Py_INCREF(Py_None); \
return Py_None; \
} \
unsigned max = psnes_get_memory_size(SNES_MEMORY_##RAMTYPE); \
\
unsigned addr; \
if (!PyArg_ParseTuple(args, "I", &addr)) \
return NULL; \
\
if (addr >= max || addr < 0) \
{ \
Py_INCREF(Py_None); \
return Py_None; \
} \
\
return PyLong_FromLong((long)data[addr]); \
}
PY_READ_FUNC(WRAM)
PY_READ_FUNC(VRAM)
PY_READ_FUNC(APURAM)
PY_READ_FUNC(CGRAM)
PY_READ_FUNC(OAM)
static PyObject* py_read_input(PyObject *self, PyObject *args)
{
(void)self;
if (!driver.input_data)
return PyBool_FromLong(0);
unsigned player;
unsigned key;
if (!PyArg_ParseTuple(args, "II", &player, &key))
return NULL;
if (player > MAX_PLAYERS || player < 1)
return NULL;
const struct snes_keybind *binds[MAX_PLAYERS];
for (int i = 0; i < MAX_PLAYERS; i++)
binds[i] = g_settings.input.binds[i];
int16_t res = driver.input->input_state(driver.input_data,
binds, player > 1,
player > 2 ? SNES_DEVICE_MULTITAP : SNES_DEVICE_JOYPAD,
player > 2 ? player - 2 : 0,
key);
return PyBool_FromLong((long)res);
}
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." },
{ "read_apuram", PY_READ_FUNC_DECL(APURAM), METH_VARARGS, "Read APURAM from SNES." },
{ "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." },
{ NULL, NULL, 0, NULL }
};
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));
}
static PyModuleDef SNESModule = {
PyModuleDef_HEAD_INIT, "snes", NULL, -1, SNESMethods,
NULL, NULL, NULL, NULL
};
static PyObject* PyInit_SNES(void)
{
PyObject *mod = PyModule_Create(&SNESModule);
if (!mod)
return NULL;
py_set_attrs(mod);
return mod;
}
struct py_state
{
PyObject *main;
PyObject *dict;
PyObject *inst;
bool warned_ret;
bool warned_type;
};
static char *dupe_newline(const char *str)
{
if (!str)
return NULL;
unsigned size = strlen(str) + 2;
char *ret = malloc(size);
if (!ret)
return NULL;
strlcpy(ret, str, size);
ret[size - 2] = '\n';
ret[size - 1] = '\0';
return ret;
}
// Need to make sure that first-line indentation is 0. :(
static char* align_program(const char *program)
{
char *prog = strdup(program);
if (!prog)
return NULL;
size_t prog_size = strlen(program) + 1;
char *new_prog = calloc(1, prog_size);
if (!new_prog)
return NULL;
char *line = dupe_newline(strtok(prog, "\n"));
if (!line)
{
free(prog);
return NULL;
}
unsigned skip_chars = 0;
while (isblank(line[skip_chars]) && line[skip_chars])
skip_chars++;
while (line)
{
unsigned length = strlen(line);
unsigned skip_len = skip_chars > length ? length : skip_chars;
strlcat(new_prog, line + skip_len, prog_size);
free(line);
line = dupe_newline(strtok(NULL, "\n"));
}
free(prog);
return new_prog;
}
py_state_t *py_state_new(const char *script, bool is_file, const char *pyclass)
{
PyImport_AppendInittab("snes", &PyInit_SNES);
Py_Initialize();
py_state_t *handle = calloc(1, sizeof(*handle));
handle->main = PyImport_AddModule("__main__");
if (!handle->main)
goto error;
if (is_file)
{
FILE *file = fopen(script, "r");
if (!file)
goto error;
PyRun_SimpleFile(file, script);
fclose(file);
}
else
{
char *script_ = align_program(script);
if (script_)
{
PyRun_SimpleString(script_);
free(script_);
}
}
handle->dict = PyModule_GetDict(handle->main);
if (!handle->dict)
goto error;
PyObject *hook = PyDict_GetItemString(handle->dict, pyclass);
if (!hook)
goto error;
handle->inst = PyObject_CallFunction(hook, NULL);
if (!handle->inst)
goto error;
return handle;
error:
PyErr_Print();
py_state_free(handle);
return NULL;
}
void py_state_free(py_state_t *handle)
{
if (handle)
{
if (handle->main)
Py_DECREF(handle->main);
if (handle->dict)
Py_DECREF(handle->dict);
if (handle->inst)
Py_DECREF(handle->inst);
free(handle);
}
Py_Finalize();
}
int 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);
if (!ret)
{
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;
}
Py_DECREF(ret);
return retval;
}
+32
View File
@@ -0,0 +1,32 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_PY_STATE_H
#define __SSNES_PY_STATE_H
#include <stdint.h>
#include <stdbool.h>
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,
const char *id, unsigned frame_count);
#endif
+18 -1
View File
@@ -270,7 +270,6 @@ static void* sdl_gfx_init(const video_info_t *video, const input_driver_t **inpu
sdl_input_t *sdl_input = input_sdl.init();
if (sdl_input)
{
sdl_input->quitting = &vid->quitting;
*input = &input_sdl;
*input_data = sdl_input;
}
@@ -407,9 +406,27 @@ static void convert_32bit_32bit_shift(uint32_t *out, unsigned outpitch, const ui
}
}
static void check_window(sdl_video_t *vid)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
vid->quitting = true;
break;
default:
break;
}
}
}
static bool sdl_gfx_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg)
{
sdl_video_t *vid = data;
check_window(vid);
if (SDL_MUSTLOCK(vid->buffer))
SDL_LockSurface(vid->buffer);
+87 -22
View File
@@ -227,8 +227,12 @@ void gl_cg_set_params(unsigned width, unsigned height,
// Set state parameters
if (snes_tracker)
{
struct snes_tracker_uniform info[MAX_VARIABLES];
unsigned cnt = snes_get_uniform(snes_tracker, info, MAX_VARIABLES, frame_count);
static struct snes_tracker_uniform info[MAX_VARIABLES];
static unsigned cnt = 0;
if (active_index == 1)
cnt = snes_get_uniform(snes_tracker, info, MAX_VARIABLES, frame_count);
for (unsigned i = 0; i < cnt; i++)
{
CGparameter param_v = cgGetNamedParameter(prg[active_index].vprg, info[i].id);
@@ -242,8 +246,9 @@ void gl_cg_set_params(unsigned width, unsigned height,
void gl_cg_deinit(void)
{
if (cg_active)
cgDestroyContext(cgCtx);
if (!cg_active)
return;
cg_active = false;
cg_shader_num = 0;
memset(prg, 0, sizeof(prg));
@@ -258,6 +263,8 @@ void gl_cg_deinit(void)
snes_tracker_free(snes_tracker);
snes_tracker = NULL;
}
cgDestroyContext(cgCtx);
}
static bool load_plain(const char *path)
@@ -374,7 +381,7 @@ error:
return false;
}
static bool load_imports(config_file_t *conf)
static bool load_imports(const char *dir_path, config_file_t *conf)
{
char *imports = NULL;
@@ -389,6 +396,7 @@ static bool load_imports(config_file_t *conf)
{
char semantic_buf[64];
char wram_buf[64];
char input_slot_buf[64];
char apuram_buf[64];
char oam_buf[64];
char cgram_buf[64];
@@ -397,6 +405,7 @@ static bool load_imports(config_file_t *conf)
print_buf(semantic_buf, "%s_semantic", id);
print_buf(wram_buf, "%s_wram", id);
print_buf(input_slot_buf, "%s_input_slot", id);
print_buf(apuram_buf, "%s_apuram", id);
print_buf(oam_buf, "%s_oam", id);
print_buf(cgram_buf, "%s_cgram", id);
@@ -414,38 +423,69 @@ static bool load_imports(config_file_t *conf)
}
enum snes_tracker_type tracker_type;
enum snes_ram_type ram_type;
enum snes_ram_type ram_type = SNES_MEMORY_WRAM;
if (strcmp(semantic, "capture") == 0)
tracker_type = SSNES_STATE_CAPTURE;
else if (strcmp(semantic, "transition") == 0)
tracker_type = SSNES_STATE_TRANSITION;
else if (strcmp(semantic, "transition_count") == 0)
tracker_type = SSNES_STATE_TRANSITION_COUNT;
else if (strcmp(semantic, "capture_previous") == 0)
tracker_type = SSNES_STATE_CAPTURE_PREV;
else if (strcmp(semantic, "transition_previous") == 0)
tracker_type = SSNES_STATE_TRANSITION_PREV;
#ifdef HAVE_PYTHON
else if (strcmp(semantic, "python") == 0)
tracker_type = SSNES_STATE_PYTHON;
#endif
else
{
SSNES_ERR("Invalid semantic.\n");
goto error;
}
unsigned addr;
if (config_get_hex(conf, wram_buf, &addr))
ram_type = SSNES_STATE_WRAM;
else if (config_get_hex(conf, apuram_buf, &addr))
ram_type = SSNES_STATE_APURAM;
else if (config_get_hex(conf, oam_buf, &addr))
ram_type = SSNES_STATE_OAM;
else if (config_get_hex(conf, cgram_buf, &addr))
ram_type = SSNES_STATE_CGRAM;
else if (config_get_hex(conf, vram_buf, &addr))
ram_type = SSNES_STATE_VRAM;
else
unsigned addr = 0;
#ifdef HAVE_PYTHON
if (tracker_type != SSNES_STATE_PYTHON)
{
SSNES_ERR("No address assigned to semantic.\n");
goto error;
#endif
unsigned input_slot = 0;
if (config_get_hex(conf, input_slot_buf, &input_slot))
{
switch (input_slot)
{
case 1:
ram_type = SSNES_STATE_INPUT_SLOT1;
break;
case 2:
ram_type = SSNES_STATE_INPUT_SLOT2;
break;
default:
SSNES_ERR("Invalid input slot for import.\n");
goto error;
}
}
else if (config_get_hex(conf, wram_buf, &addr))
ram_type = SSNES_STATE_WRAM;
else if (config_get_hex(conf, apuram_buf, &addr))
ram_type = SSNES_STATE_APURAM;
else if (config_get_hex(conf, oam_buf, &addr))
ram_type = SSNES_STATE_OAM;
else if (config_get_hex(conf, cgram_buf, &addr))
ram_type = SSNES_STATE_CGRAM;
else if (config_get_hex(conf, vram_buf, &addr))
ram_type = SSNES_STATE_VRAM;
else
{
SSNES_ERR("No address assigned to semantic.\n");
goto error;
}
#ifdef HAVE_PYTHON
}
#endif
int memtype = 0;
switch (ram_type)
@@ -465,8 +505,9 @@ static bool load_imports(config_file_t *conf)
case SSNES_STATE_CGRAM:
memtype = SNES_MEMORY_CGRAM;
break;
default:
break;
memtype = SNES_MEMORY_WRAM;
}
if (addr >= psnes_get_memory_size(memtype))
@@ -501,10 +542,34 @@ static bool load_imports(config_file_t *conf)
.info_elem = info_cnt
};
#ifdef HAVE_PYTHON
char script_path[128];
char *script = NULL;
char *script_class = NULL;
if (config_get_string(conf, "import_script", &script))
{
strlcpy(script_path, dir_path, sizeof(script_path));
strlcat(script_path, script, sizeof(script_path));
tracker_info.script = script_path;
}
if (config_get_string(conf, "import_script_class", &script_class))
tracker_info.script_class = script_class;
tracker_info.script_is_file = true;
#endif
snes_tracker = snes_tracker_init(&tracker_info);
if (!snes_tracker)
SSNES_WARN("Failed to init SNES tracker.\n");
#ifdef HAVE_PYTHON
if (script)
free(script);
if (script_class)
free(script_class);
#endif
free(imports);
return true;
@@ -752,7 +817,7 @@ static bool load_preset(const char *path)
goto error;
}
if (!load_imports(conf))
if (!load_imports(dir_path, conf))
{
SSNES_ERR("Failed to load imports ...\n");
goto error;
+179 -40
View File
@@ -116,6 +116,9 @@ static char gl_teximage_uniforms[MAX_TEXTURES][64];
static snes_tracker_t *gl_snes_tracker = NULL;
static struct snes_tracker_uniform_info gl_tracker_info[MAX_VARIABLES];
static unsigned gl_tracker_info_cnt = 0;
static char gl_tracker_script[256];
static char gl_tracker_script_class[64];
static xmlChar *gl_script_program = NULL;
struct shader_program
{
@@ -378,6 +381,60 @@ error:
return false;
}
#ifdef HAVE_PYTHON
static bool get_script(const char *path, xmlNodePtr ptr)
{
if (*gl_tracker_script || gl_script_program)
{
SSNES_ERR("Script already imported.\n");
return false;
}
xmlChar *script_class = xmlGetProp(ptr, (const xmlChar*)"class");
if (script_class)
{
strlcpy(gl_tracker_script_class, (const char*)script_class, sizeof(gl_tracker_script_class));
xmlFree(script_class);
}
xmlChar *language = xmlGetProp(ptr, (const xmlChar*)"language");
if (!language || strcmp((const char*)language, "python") != 0)
{
SSNES_ERR("Script language is not Python!\n");
if (language)
xmlFree(language);
return false;
}
if (language)
xmlFree(language);
xmlChar *src = xmlGetProp(ptr, (const xmlChar*)"src");
if (src)
{
strlcpy(gl_tracker_script, path, sizeof(gl_tracker_script));
char *dir_ptr = strrchr(gl_tracker_script, '/');
if (!dir_ptr) dir_ptr = strrchr(gl_tracker_script, '\\');
if (dir_ptr) dir_ptr[1] = '\0';
strlcat(gl_tracker_script, (const char*)src, sizeof(gl_tracker_script));
xmlFree(src);
}
else
{
xmlChar *script = xmlNodeGetContent(ptr);
if (!script)
{
SSNES_ERR("No content in script!\n");
return false;
}
gl_script_program = script;
}
return true;
}
#endif
static bool get_import_value(xmlNodePtr ptr)
{
if (gl_tracker_info_cnt >= MAX_VARIABLES)
@@ -389,6 +446,7 @@ static bool get_import_value(xmlNodePtr ptr)
xmlChar *id = xmlGetProp(ptr, (const xmlChar*)"id");
xmlChar *semantic = xmlGetProp(ptr, (const xmlChar*)"semantic");
xmlChar *wram = xmlGetProp(ptr, (const xmlChar*)"wram");
xmlChar *input = xmlGetProp(ptr, (const xmlChar*)"input_slot");
xmlChar *apuram = xmlGetProp(ptr, (const xmlChar*)"apuram");
xmlChar *vram = xmlGetProp(ptr, (const xmlChar*)"vram");
xmlChar *oam = xmlGetProp(ptr, (const xmlChar*)"oam");
@@ -400,22 +458,67 @@ static bool get_import_value(xmlNodePtr ptr)
SSNES_ERR("No semantic or ID for import value!\n");
goto error;
}
enum snes_ram_type ram_type;
enum snes_tracker_type tracker_type;
uint32_t addr = 0;
if (wram) { addr = strtoul((const char*)wram, NULL, 16); ram_type = SSNES_STATE_WRAM; }
else if (apuram) { addr = strtoul((const char*)apuram, NULL, 16); ram_type = SSNES_STATE_APURAM; }
else if (vram) { addr = strtoul((const char*)vram, NULL, 16); ram_type = SSNES_STATE_VRAM; }
else if (oam) { addr = strtoul((const char*)oam, NULL, 16); ram_type = SSNES_STATE_OAM; }
else if (cgram) { addr = strtoul((const char*)cgram, NULL, 16); ram_type = SSNES_STATE_CGRAM; }
enum snes_tracker_type tracker_type;
if (strcmp((const char*)semantic, "capture") == 0)
tracker_type = SSNES_STATE_CAPTURE;
else if (strcmp((const char*)semantic, "capture_previous") == 0)
tracker_type = SSNES_STATE_CAPTURE_PREV;
else if (strcmp((const char*)semantic, "transition") == 0)
tracker_type = SSNES_STATE_TRANSITION;
else if (strcmp((const char*)semantic, "transition_count") == 0)
tracker_type = SSNES_STATE_TRANSITION_COUNT;
else if (strcmp((const char*)semantic, "transition_previous") == 0)
tracker_type = SSNES_STATE_TRANSITION_PREV;
#ifdef HAVE_PYTHON
else if (strcmp((const char*)semantic, "python") == 0)
tracker_type = SSNES_STATE_PYTHON;
#endif
else
{
SSNES_ERR("No RAM address specificed for import value.\n");
SSNES_ERR("Invalid semantic for import value.\n");
goto error;
}
enum snes_ram_type ram_type = SSNES_STATE_WRAM;
uint32_t addr = 0;
#ifdef HAVE_PYTHON
if (tracker_type != SSNES_STATE_PYTHON)
{
#endif
if (input)
{
unsigned slot = strtoul((const char*)input, NULL, 0);
switch (slot)
{
case 1:
ram_type = SSNES_STATE_INPUT_SLOT1;
break;
case 2:
ram_type = SSNES_STATE_INPUT_SLOT2;
break;
default:
SSNES_ERR("Invalid input slot for import!\n");
goto error;
}
}
else if (wram) { addr = strtoul((const char*)wram, NULL, 16); ram_type = SSNES_STATE_WRAM; }
else if (apuram) { addr = strtoul((const char*)apuram, NULL, 16); ram_type = SSNES_STATE_APURAM; }
else if (vram) { addr = strtoul((const char*)vram, NULL, 16); ram_type = SSNES_STATE_VRAM; }
else if (oam) { addr = strtoul((const char*)oam, NULL, 16); ram_type = SSNES_STATE_OAM; }
else if (cgram) { addr = strtoul((const char*)cgram, NULL, 16); ram_type = SSNES_STATE_CGRAM; }
else
{
SSNES_ERR("No RAM address specificed for import value.\n");
goto error;
}
#ifdef HAVE_PYTHON
}
#endif
int memtype = 0;
switch (ram_type)
{
@@ -434,8 +537,9 @@ static bool get_import_value(xmlNodePtr ptr)
case SSNES_STATE_CGRAM:
memtype = SNES_MEMORY_CGRAM;
break;
default:
break;
memtype = SNES_MEMORY_WRAM;
}
if (addr >= psnes_get_memory_size(memtype))
@@ -444,20 +548,6 @@ static bool get_import_value(xmlNodePtr ptr)
goto error;
}
if (strcmp((const char*)semantic, "capture") == 0)
tracker_type = SSNES_STATE_CAPTURE;
else if (strcmp((const char*)semantic, "capture_previous") == 0)
tracker_type = SSNES_STATE_CAPTURE_PREV;
else if (strcmp((const char*)semantic, "transition") == 0)
tracker_type = SSNES_STATE_TRANSITION;
else if (strcmp((const char*)semantic, "transition_previous") == 0)
tracker_type = SSNES_STATE_TRANSITION_PREV;
else
{
SSNES_ERR("Invalid semantic for import value.\n");
goto error;
}
unsigned mask_value = 0;
if (bitmask)
mask_value = strtoul((const char*)bitmask, NULL, 16);
@@ -472,6 +562,7 @@ static bool get_import_value(xmlNodePtr ptr)
if (id) xmlFree(id);
if (semantic) xmlFree(semantic);
if (wram) xmlFree(wram);
if (input) xmlFree(input);
if (apuram) xmlFree(apuram);
if (vram) xmlFree(vram);
if (oam) xmlFree(oam);
@@ -483,6 +574,7 @@ error:
if (id) xmlFree(id);
if (semantic) xmlFree(semantic);
if (wram) xmlFree(wram);
if (input) xmlFree(input);
if (apuram) xmlFree(apuram);
if (vram) xmlFree(vram);
if (oam) xmlFree(oam);
@@ -588,6 +680,16 @@ static unsigned get_xml_shaders(const char *path, struct shader_program *prog, s
goto error;
}
}
#ifdef HAVE_PYTHON
else if (strcmp((const char*)cur->name, "script") == 0)
{
if (!get_script(path, cur))
{
SSNES_ERR("Script is invalid.\n");
goto error;
}
}
#endif
}
if (num == 0)
@@ -648,13 +750,30 @@ static bool compile_shader(GLuint shader, const char *program)
return status == GL_TRUE;
}
static bool link_program(GLuint prog)
{
pglLinkProgram(prog);
GLint status;
pglGetProgramiv(prog, GL_LINK_STATUS, &status);
print_linker_log(prog);
if (status == GL_TRUE)
{
pglUseProgram(prog);
return true;
}
else
return false;
}
static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size_t num)
{
for (unsigned i = 0; i < num; i++)
{
gl_prog[i] = pglCreateProgram();
if (!gl_check_error() || gl_prog[i] == 0)
if (gl_prog[i] == 0)
{
SSNES_ERR("Failed to create GL program #%u.\n", i);
return false;
@@ -691,20 +810,16 @@ static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size
if (progs[i].vertex || progs[i].fragment)
{
SSNES_LOG("Linking GLSL program.\n");
pglLinkProgram(gl_prog[i]);
pglUseProgram(gl_prog[i]);
print_linker_log(gl_prog[i]);
if (!link_program(gl_prog[i]))
{
SSNES_ERR("Failed to link program #%u\n", i);
return false;
}
GLint location = pglGetUniformLocation(gl_prog[i], "rubyTexture");
pglUniform1i(location, 0);
pglUseProgram(0);
}
if (!gl_check_error())
{
SSNES_ERR("Failed to link program #%u\n", i);
return false;
}
}
return true;
@@ -800,8 +915,8 @@ bool gl_glsl_init(const char *path)
}
}
if (!gl_check_error())
return false;
//if (!gl_check_error())
// SSNES_WARN("Detected GL error!\n");
if (gl_tracker_info_cnt > 0)
{
@@ -812,8 +927,21 @@ bool gl_glsl_init(const char *path)
.apuram = psnes_get_memory_data(SNES_MEMORY_APURAM),
.oam = psnes_get_memory_data(SNES_MEMORY_OAM),
.info = gl_tracker_info,
.info_elem = gl_tracker_info_cnt
.info_elem = gl_tracker_info_cnt,
};
#ifdef HAVE_PYTHON
if (*gl_tracker_script)
info.script = gl_tracker_script;
else if (gl_script_program)
info.script = (const char*)gl_script_program;
else
info.script = NULL;
info.script_class = *gl_tracker_script_class ? gl_tracker_script_class : NULL;
info.script_is_file = *gl_tracker_script;
#endif
gl_snes_tracker = snes_tracker_init(&info);
if (!gl_snes_tracker)
SSNES_WARN("Failed to init SNES tracker!\n");
@@ -858,6 +986,13 @@ void gl_glsl_deinit(void)
gl_tracker_info_cnt = 0;
memset(gl_tracker_info, 0, sizeof(gl_tracker_info));
memset(gl_tracker_script, 0, sizeof(gl_tracker_script));
memset(gl_tracker_script_class, 0, sizeof(gl_tracker_script_class));
if (gl_script_program)
{
xmlFree(gl_script_program);
gl_script_program = NULL;
}
if (gl_snes_tracker)
{
snes_tracker_free(gl_snes_tracker);
@@ -976,8 +1111,12 @@ void gl_glsl_set_params(unsigned width, unsigned height,
if (gl_snes_tracker)
{
struct snes_tracker_uniform info[MAX_VARIABLES];
unsigned cnt = snes_get_uniform(gl_snes_tracker, info, MAX_VARIABLES, frame_count);
static struct snes_tracker_uniform info[MAX_VARIABLES];
static unsigned cnt = 0;
if (active_index == 1)
cnt = snes_get_uniform(gl_snes_tracker, info, MAX_VARIABLES, frame_count);
for (unsigned i = 0; i < cnt; i++)
{
location = pglGetUniformLocation(gl_program[active_index], info[i].id);
+116 -11
View File
@@ -19,26 +19,47 @@
#include <stdlib.h>
#include <assert.h>
#include "strl.h"
#include "general.h"
#include <libsnes.hpp>
#ifdef HAVE_PYTHON
#include "py_state/py_state.h"
#endif
struct snes_tracker_internal
{
char id[64];
bool is_input;
unsigned input_slot;
const uint16_t *input_ptr;
const uint8_t *ptr;
#ifdef HAVE_PYTHON
py_state_t *py;
#endif
uint32_t addr;
uint8_t mask;
unsigned mask;
enum snes_tracker_type type;
uint8_t prev[2];
uint32_t prev[2];
int frame_count;
uint8_t old_value;
int frame_count_prev;
uint32_t old_value;
int transition_count;
};
struct snes_tracker
{
struct snes_tracker_internal *info;
unsigned info_elem;
uint16_t input_state[2];
#ifdef HAVE_PYTHON
py_state_t *py;
#endif
};
snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
@@ -47,6 +68,19 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
if (!tracker)
return NULL;
#ifdef HAVE_PYTHON
if (info->script)
{
tracker->py = py_state_new(info->script, info->script_is_file, info->script_class ? info->script_class : "GameAware");
if (!tracker->py)
{
free(tracker);
SSNES_ERR("Failed to init Python script.\n");
return NULL;
}
}
#endif
tracker->info = calloc(info->info_elem, sizeof(struct snes_tracker_internal));
tracker->info_elem = info->info_elem;
@@ -55,7 +89,12 @@ 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) ? 0xff : info->info[i].mask;
tracker->info[i].mask = (info->info[i].mask == 0) ? 0xffffffffu : 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);
@@ -77,23 +116,35 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
case SSNES_STATE_VRAM:
tracker->info[i].ptr = info->vram;
break;
case SSNES_STATE_INPUT_SLOT1:
tracker->info[i].input_ptr = &tracker->input_state[0];
tracker->info[i].input_slot = 0;
tracker->info[i].is_input = true;
break;
case SSNES_STATE_INPUT_SLOT2:
tracker->info[i].input_ptr = &tracker->input_state[1];
tracker->info[i].input_slot = 1;
tracker->info[i].is_input = true;
break;
default:
tracker->info[i].ptr = NULL;
}
}
return tracker;
}
void snes_tracker_free(snes_tracker_t *tracker)
{
free(tracker->info);
#ifdef HAVE_PYTHON
py_state_free(tracker->py);
#endif
free(tracker);
}
#define fetch() (info->ptr[info->addr] & info->mask)
#define fetch() ((info->is_input ? info->input_ptr[info->input_slot] : info->ptr[info->addr]) & info->mask)
static void update_element(
struct snes_tracker_uniform *uniform,
@@ -124,21 +175,33 @@ static void update_element(
info->frame_count = frame_count;
}
uniform->value = info->frame_count;
break;
case SSNES_STATE_TRANSITION_COUNT:
if (info->old_value != fetch())
{
info->old_value = fetch();
info->transition_count++;
}
uniform->value = info->transition_count;
break;
case SSNES_STATE_TRANSITION_PREV:
if (info->prev[0] != fetch())
if (info->old_value != fetch())
{
info->old_value = fetch();
info->prev[1] = info->prev[0];
info->prev[0] = frame_count;
info->frame_count_prev = info->frame_count;
info->frame_count = frame_count;
}
uniform->value = info->prev[1];
uniform->value = info->frame_count_prev;
break;
#ifdef HAVE_PYTHON
case SSNES_STATE_PYTHON:
uniform->value = py_state_get(info->py, info->id, frame_count);
break;
#endif
default:
break;
}
@@ -146,10 +209,52 @@ static void update_element(
#undef fetch
// Updates 16-bit input in same format as SNES itself.
static void update_input(snes_tracker_t *tracker)
{
if (!driver.input_data)
return;
static const unsigned buttons[] = {
SNES_DEVICE_ID_JOYPAD_R,
SNES_DEVICE_ID_JOYPAD_L,
SNES_DEVICE_ID_JOYPAD_X,
SNES_DEVICE_ID_JOYPAD_A,
SNES_DEVICE_ID_JOYPAD_RIGHT,
SNES_DEVICE_ID_JOYPAD_LEFT,
SNES_DEVICE_ID_JOYPAD_DOWN,
SNES_DEVICE_ID_JOYPAD_UP,
SNES_DEVICE_ID_JOYPAD_START,
SNES_DEVICE_ID_JOYPAD_SELECT,
SNES_DEVICE_ID_JOYPAD_Y,
SNES_DEVICE_ID_JOYPAD_B
};
static const struct snes_keybind *binds[MAX_PLAYERS] = {
g_settings.input.binds[0],
g_settings.input.binds[1],
g_settings.input.binds[2],
g_settings.input.binds[3],
g_settings.input.binds[4]
};
uint16_t state[2] = {0};
for (unsigned i = 4; i < 16; i++)
{
state[0] |= (driver.input->input_state(driver.input_data, binds, SNES_PORT_1, SNES_DEVICE_JOYPAD, 0, buttons[i - 4]) ? 1 : 0) << i;
state[1] |= (driver.input->input_state(driver.input_data, binds, SNES_PORT_2, SNES_DEVICE_JOYPAD, 0, buttons[i - 4]) ? 1 : 0) << i;
}
for (unsigned i = 0; i < 2; i++)
tracker->input_state[i] = state[i];
}
unsigned snes_get_uniform(snes_tracker_t *tracker, struct snes_tracker_uniform *uniforms, unsigned elem, unsigned frame_count)
{
unsigned elems = tracker->info_elem < elem ? tracker->info_elem : elem;
update_input(tracker);
for (unsigned i = 0; i < elems; i++)
update_element(&uniforms[i], &tracker->info[i], frame_count);
+21 -4
View File
@@ -19,13 +19,22 @@
#define __SSNES_SNES_STATE_H
#include <stdint.h>
#include <stdbool.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
enum snes_tracker_type
{
SSNES_STATE_CAPTURE,
SSNES_STATE_TRANSITION,
SSNES_STATE_CAPTURE_PREV,
SSNES_STATE_TRANSITION_PREV
SSNES_STATE_TRANSITION,
SSNES_STATE_TRANSITION_COUNT,
SSNES_STATE_TRANSITION_PREV,
#ifdef HAVE_PYTHON
SSNES_STATE_PYTHON
#endif
};
enum snes_ram_type
@@ -34,7 +43,9 @@ enum snes_ram_type
SSNES_STATE_APURAM,
SSNES_STATE_OAM,
SSNES_STATE_CGRAM,
SSNES_STATE_VRAM
SSNES_STATE_VRAM,
SSNES_STATE_INPUT_SLOT1,
SSNES_STATE_INPUT_SLOT2
};
struct snes_tracker_uniform_info
@@ -43,7 +54,7 @@ struct snes_tracker_uniform_info
uint32_t addr;
enum snes_tracker_type type;
enum snes_ram_type ram_type;
uint8_t mask;
unsigned mask;
};
struct snes_tracker_info
@@ -56,6 +67,12 @@ struct snes_tracker_info
const struct snes_tracker_uniform_info *info;
unsigned info_elem;
#ifdef HAVE_PYTHON
const char *script;
const char *script_class;
bool script_is_file;
#endif
};
struct snes_tracker_uniform
+249
View File
@@ -0,0 +1,249 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "SDL.h"
#include "SDL_syswm.h"
#include <stdbool.h>
#include "ssnes_dinput.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
void sdl_dinput_free(sdl_dinput_t *di)
{
if (di)
{
for (unsigned i = 0; i < MAX_PLAYERS; i++)
{
if (di->joypad[i])
{
IDirectInputDevice8_Unacquire(di->joypad[i]);
IDirectInputDevice8_Release(di->joypad[i]);
}
}
if (di->ctx)
IDirectInput8_Release(di->ctx);
free(di);
}
}
static BOOL CALLBACK enum_axes_cb(const DIDEVICEOBJECTINSTANCE *inst, void *p)
{
IDirectInputDevice8 *joypad = p;
DIPROPRANGE range;
memset(&range, 0, sizeof(range));
range.diph.dwSize = sizeof(DIPROPRANGE);
range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
range.diph.dwHow = DIPH_BYID;
range.diph.dwObj = inst->dwType;
range.lMin = -32768;
range.lMax = 32767;
IDirectInputDevice8_SetProperty(joypad, DIPROP_RANGE, &range.diph);
return DIENUM_CONTINUE;
}
static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p)
{
sdl_dinput_t *di = p;
unsigned active = 0;
unsigned n;
for (n = 0; n < MAX_PLAYERS; n++)
{
if (!di->joypad[n] && g_settings.input.joypad_map[n] == di->joypad_cnt)
break;
if (di->joypad[n])
active++;
}
if (active == MAX_PLAYERS) return DIENUM_STOP;
di->joypad_cnt++;
if (n == MAX_PLAYERS)
return DIENUM_CONTINUE;
if (FAILED(IDirectInput8_CreateDevice(di->ctx, &inst->guidInstance, &di->joypad[n], NULL)))
return DIENUM_CONTINUE;
IDirectInputDevice8_SetDataFormat(di->joypad[n], &c_dfDIJoystick2);
IDirectInputDevice8_SetCooperativeLevel(di->joypad[n], di->hWnd,
DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
IDirectInputDevice8_EnumObjects(di->joypad[n], enum_axes_cb,
di->joypad[n], DIDFT_ABSAXIS);
return DIENUM_CONTINUE;
}
sdl_dinput_t* sdl_dinput_init(void)
{
sdl_dinput_t *di = calloc(1, sizeof(*di));
if (!di)
return NULL;
CoInitialize(NULL);
SDL_SysWMinfo info;
if (!SDL_GetWMInfo(&info))
{
SSNES_ERR("Failed to get SysWM info.\n");
goto error;
}
di->hWnd = info.window;
if (FAILED(DirectInput8Create(
GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8,
(void**)&di->ctx, NULL)))
{
SSNES_ERR("Failed to init DirectInput.\n");
goto error;
}
SSNES_LOG("Enumerating DInput devices ...\n");
IDirectInput8_EnumDevices(di->ctx, DI8DEVCLASS_GAMECTRL, enum_joypad_cb, di, DIEDFL_ATTACHEDONLY);
SSNES_LOG("Done enumerating DInput devices ...\n");
return di;
error:
sdl_dinput_free(di);
return NULL;
}
static bool dinput_joykey_pressed(sdl_dinput_t *di, unsigned port_num, uint16_t joykey)
{
if (joykey == NO_BTN)
return false;
// Check hat.
if (GET_HAT_DIR(joykey))
{
unsigned hat = GET_HAT(joykey);
unsigned elems = sizeof(di->joy_state[0].rgdwPOV) / sizeof(di->joy_state[0].rgdwPOV[0]);
if (hat >= elems)
return false;
unsigned pov = di->joy_state[port_num].rgdwPOV[hat];
// Magic numbers I'm not sure where originate from.
if (pov < 36000)
{
switch (GET_HAT_DIR(joykey))
{
case HAT_UP_MASK:
return (pov >= 31500) || (pov <= 4500);
case HAT_RIGHT_MASK:
return (pov >= 4500) && (pov <= 13500);
case HAT_DOWN_MASK:
return (pov >= 13500) && (pov <= 22500);
case HAT_LEFT_MASK:
return (pov >= 22500) && (pov <= 31500);
}
}
return false;
}
else
{
unsigned elems = sizeof(di->joy_state[0].rgbButtons) / sizeof(di->joy_state[0].rgbButtons[0]);
if (joykey < elems)
return di->joy_state[port_num].rgbButtons[joykey];
}
return false;
}
static bool dinput_joyaxis_pressed(sdl_dinput_t *di, unsigned port_num, uint32_t joyaxis)
{
if (joyaxis == AXIS_NONE)
return false;
int min = -32678 * g_settings.input.axis_threshold;
int max = 32677 * g_settings.input.axis_threshold;
switch (AXIS_NEG_GET(joyaxis))
{
case 0:
return di->joy_state[port_num].lX <= min;
case 1:
return di->joy_state[port_num].lY <= min;
case 2:
return di->joy_state[port_num].lZ <= min;
case 3:
return di->joy_state[port_num].lRx <= min;
case 4:
return di->joy_state[port_num].lRy <= min;
case 5:
return di->joy_state[port_num].lRz <= min;
}
switch (AXIS_POS_GET(joyaxis))
{
case 0:
return di->joy_state[port_num].lX >= max;
case 1:
return di->joy_state[port_num].lY >= max;
case 2:
return di->joy_state[port_num].lZ >= max;
case 3:
return di->joy_state[port_num].lRx >= max;
case 4:
return di->joy_state[port_num].lRy >= max;
case 5:
return di->joy_state[port_num].lRz >= max;
}
return false;
}
bool sdl_dinput_pressed(sdl_dinput_t *di, unsigned port_num, const struct snes_keybind *key)
{
if (di->joypad[port_num] == NULL)
return false;
if (dinput_joykey_pressed(di, port_num, key->joykey))
return true;
if (dinput_joyaxis_pressed(di, port_num, key->joyaxis))
return true;
return false;
}
void sdl_dinput_poll(sdl_dinput_t *di)
{
memset(di->joy_state, 0, sizeof(di->joy_state));
for (unsigned i = 0; i < MAX_PLAYERS; i++)
{
if (di->joypad[i])
{
if (FAILED(IDirectInputDevice8_Poll(di->joypad[i])))
{
IDirectInputDevice8_Acquire(di->joypad[i]);
continue;
}
IDirectInputDevice8_GetDeviceState(di->joypad[i], sizeof(DIJOYSTATE2), &di->joy_state[i]);
}
}
}
+59 -58
View File
@@ -25,12 +25,22 @@
#include <libsnes.hpp>
#include "ssnes_sdl_input.h"
static void* sdl_input_init(void)
{
sdl_input_t *sdl = calloc(1, sizeof(*sdl));
if (!sdl)
return NULL;
#ifdef HAVE_DINPUT
sdl->di = sdl_dinput_init();
if (!sdl->di)
{
free(sdl);
SSNES_ERR("Failed to init SDL/DInput.\n");
return NULL;
}
#else
if (SDL_Init(SDL_INIT_JOYSTICK) < 0)
return NULL;
@@ -60,9 +70,9 @@ static void* sdl_input_init(void)
sdl->num_hats[i] = SDL_JoystickNumHats(sdl->joysticks[i]);
}
}
#endif
sdl->use_keyboard = true;
return sdl;
}
@@ -78,8 +88,12 @@ static bool sdl_key_pressed(int key)
return keymap[key];
}
#ifndef HAVE_DINPUT
static bool sdl_joykey_pressed(sdl_input_t *sdl, int port_num, uint16_t joykey)
{
if (joykey == NO_BTN)
return false;
// Check hat.
if (GET_HAT_DIR(joykey))
{
@@ -120,37 +134,43 @@ static bool sdl_joykey_pressed(sdl_input_t *sdl, int port_num, uint16_t joykey)
static bool sdl_axis_pressed(sdl_input_t *sdl, int port_num, uint32_t joyaxis)
{
if (joyaxis != AXIS_NONE)
if (joyaxis == AXIS_NONE)
return false;
if (AXIS_NEG_GET(joyaxis) < sdl->num_axes[port_num])
{
if (AXIS_NEG_GET(joyaxis) < sdl->num_axes[port_num])
{
Sint16 val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_NEG_GET(joyaxis));
float scaled = (float)val / 0x8000;
if (scaled < -g_settings.input.axis_threshold)
return true;
}
if (AXIS_POS_GET(joyaxis) < sdl->num_axes[port_num])
{
Sint16 val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_POS_GET(joyaxis));
float scaled = (float)val / 0x8000;
if (scaled > g_settings.input.axis_threshold)
return true;
}
Sint16 val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_NEG_GET(joyaxis));
float scaled = (float)val / 0x8000;
if (scaled < -g_settings.input.axis_threshold)
return true;
}
if (AXIS_POS_GET(joyaxis) < sdl->num_axes[port_num])
{
Sint16 val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_POS_GET(joyaxis));
float scaled = (float)val / 0x8000;
if (scaled > g_settings.input.axis_threshold)
return true;
}
return false;
}
#endif
static bool sdl_is_pressed(sdl_input_t *sdl, int port_num, const struct snes_keybind *key)
static bool sdl_is_pressed(sdl_input_t *sdl, unsigned port_num, const struct snes_keybind *key)
{
if (sdl->use_keyboard && sdl_key_pressed(key->key))
return true;
#ifdef HAVE_DINPUT
return sdl_dinput_pressed(sdl->di, port_num, key);
#else
if (sdl->joysticks[port_num] == NULL)
return false;
if (sdl_joykey_pressed(sdl, port_num, key->joykey))
return true;
if (sdl_axis_pressed(sdl, port_num, key->joyaxis))
return true;
#endif
return false;
}
@@ -159,7 +179,7 @@ static bool sdl_bind_button_pressed(void *data, int key)
{
// Only let player 1 use special binds called from main loop.
const struct snes_keybind *binds = g_settings.input.binds[0];
for (int i = 0; binds[i].id != -1; i++)
for (unsigned i = 0; binds[i].id != -1; i++)
{
if (binds[i].id == key)
return sdl_is_pressed(data, 0, &binds[i]);
@@ -168,23 +188,21 @@ static bool sdl_bind_button_pressed(void *data, int key)
}
static int16_t sdl_joypad_device_state(sdl_input_t *sdl, const struct snes_keybind **binds,
int port_num, unsigned device, unsigned index, unsigned id)
unsigned port_num, int id)
{
const struct snes_keybind *snes_keybinds = binds[port_num];
for (int i = 0; snes_keybinds[i].id != -1; i++)
for (unsigned i = 0; snes_keybinds[i].id != -1; i++)
{
if (snes_keybinds[i].id == (int)id)
return sdl_is_pressed(sdl, port_num, &snes_keybinds[i]);
if (snes_keybinds[i].id == id)
return sdl_is_pressed(sdl, port_num, &snes_keybinds[i]) ? 1 : 0;
}
return false;
return 0;
}
static int16_t sdl_mouse_device_state(sdl_input_t *sdl, bool port, unsigned id)
static int16_t sdl_mouse_device_state(sdl_input_t *sdl, unsigned id)
{
// Might implement support for joypad mapping later.
(void)port;
switch (id)
{
case SNES_DEVICE_ID_MOUSE_LEFT:
@@ -248,11 +266,11 @@ static int16_t sdl_input_state(void *data, const struct snes_keybind **binds, bo
switch (device)
{
case SNES_DEVICE_JOYPAD:
return sdl_joypad_device_state(data, binds, (port == SNES_PORT_1) ? 0 : 1, device, index, id);
return sdl_joypad_device_state(data, binds, (port == SNES_PORT_1) ? 0 : 1, id);
case SNES_DEVICE_MULTITAP:
return sdl_joypad_device_state(data, binds, (port == SNES_PORT_2) ? 1 + index : 0, device, index, id);
return sdl_joypad_device_state(data, binds, (port == SNES_PORT_2) ? 1 + index : 0, id);
case SNES_DEVICE_MOUSE:
return sdl_mouse_device_state(data, port, id);
return sdl_mouse_device_state(data, id);
case SNES_DEVICE_SUPER_SCOPE:
return sdl_scope_device_state(data, id);
case SNES_DEVICE_JUSTIFIER:
@@ -273,14 +291,19 @@ static void sdl_input_free(void *data)
while (SDL_PollEvent(&event));
sdl_input_t *sdl = data;
#ifdef HAVE_DINPUT
sdl_dinput_free(sdl->di);
#else
for (int i = 0; i < MAX_PLAYERS; i++)
{
if (sdl->joysticks[i])
SDL_JoystickClose(sdl->joysticks[i]);
}
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
#endif
free(data);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
}
@@ -298,37 +321,15 @@ static void sdl_poll_mouse(sdl_input_t *sdl)
static void sdl_input_poll(void *data)
{
SDL_PumpEvents();
SDL_Event event;
SDL_JoystickUpdate();
sdl_poll_mouse(data);
sdl_input_t *sdl = data;
// Search for events...
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
if (sdl->quitting)
{
*sdl->quitting = true;
return;
}
break;
case SDL_VIDEORESIZE:
if (sdl->should_resize)
{
*sdl->new_width = event.resize.w;
*sdl->new_height = event.resize.h;
*sdl->should_resize = true;
}
break;
#ifdef HAVE_DINPUT
sdl_dinput_poll(sdl->di);
#else
SDL_JoystickUpdate();
#endif
default:
break;
}
}
sdl_poll_mouse(sdl);
}
const input_driver_t input_sdl = {
+48
View File
@@ -0,0 +1,48 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_DINPUT_H
#define __SSNES_DINPUT_H
#undef DIRECTINPUT_VERSION
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <stdbool.h>
#include "general.h"
// Piggyback joypad driver for SDL.
typedef struct sdl_dinput
{
HWND hWnd;
IDirectInput8 *ctx;
IDirectInputDevice8 *joypad[MAX_PLAYERS];
unsigned joypad_cnt;
DIJOYSTATE2 joy_state[MAX_PLAYERS];
} sdl_dinput_t;
sdl_dinput_t *sdl_dinput_init(void);
void sdl_dinput_free(sdl_dinput_t *di);
bool sdl_dinput_pressed(sdl_dinput_t *di, unsigned port_num,
const struct snes_keybind *key);
void sdl_dinput_poll(sdl_dinput_t *di);
#endif
+10 -5
View File
@@ -20,20 +20,25 @@
#include "SDL.h"
#include "general.h"
#ifdef HAVE_DINPUT
#include "ssnes_dinput.h"
#endif
typedef struct sdl_input
{
#ifdef HAVE_DINPUT
sdl_dinput_t *di;
#else
SDL_Joystick *joysticks[MAX_PLAYERS];
unsigned num_axes[MAX_PLAYERS];
unsigned num_buttons[MAX_PLAYERS];
unsigned num_hats[MAX_PLAYERS];
unsigned num_joysticks;
#endif
bool use_keyboard;
// A video driver could pre-init with the SDL driver and have it handle resizing events...
bool *quitting;
bool *should_resize;
unsigned *new_width;
unsigned *new_height;
int16_t mouse_x, mouse_y;
int16_t mouse_l, mouse_r, mouse_m;
} sdl_input_t;
+4 -2
View File
@@ -43,7 +43,7 @@ check_critical SDL "Cannot find SDL library."
check_lib CG -lCg cgCreateContext
check_pkgconf XML libxml-2.0
check_pkgconf IMLIB imlib2
check_pkgconf SDL_IMAGE SDL_image
if [ $HAVE_FFMPEG != no ]; then
check_pkgconf AVCODEC libavcodec
@@ -64,8 +64,10 @@ check_lib XVIDEO -lXv XvShmCreateImage
check_lib STRL -lc strlcpy
check_pkgconf PYTHON python3
# Creates config.mk and config.h.
VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL DYLIB CG XML IMLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL"
VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL DYLIB CG XML SDL_IMAGE DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL PYTHON"
create_config_make config.mk $VARS
create_config_header config.h $VARS
+3 -2
View File
@@ -1,7 +1,7 @@
. qb/qb.params.sh
PACKAGE_NAME=ssnes
PACKAGE_VERSION=0.5.1
PACKAGE_VERSION=0.5.2
# Adds a command line opt to ./configure --help
# $1: Variable (HAVE_ALSA, HAVE_OSS, etc)
@@ -26,4 +26,5 @@ add_command_line_enable JACK "Enable JACK support" auto
add_command_line_enable PULSE "Enable PulseAudio support" auto
add_command_line_enable FREETYPE "Enable FreeType support" auto
add_command_line_enable XVIDEO "Enable XVideo support" auto
add_command_line_enable IMLIB "Enable imlib2 support" auto
add_command_line_enable SDL_IMAGE "Enable SDL_image support" auto
add_command_line_enable PYTHON "Enable Python 3 support for shaders" no
+10 -5
View File
@@ -295,9 +295,13 @@ static int16_t input_state(bool port, unsigned device, unsigned index, unsigned
}
}
const struct snes_keybind *binds[MAX_PLAYERS];
for (int i = 0; i < MAX_PLAYERS; i++)
binds[i] = g_settings.input.binds[i];
static const struct snes_keybind *binds[MAX_PLAYERS] = {
g_settings.input.binds[0],
g_settings.input.binds[1],
g_settings.input.binds[2],
g_settings.input.binds[3],
g_settings.input.binds[4]
};
int16_t res = driver.input->input_state(driver.input_data, binds, port, device, index, id);
if (g_extern.bsv_movie && !g_extern.bsv_movie_playback)
@@ -333,7 +337,7 @@ static void fill_pathname_noext(char *out_path, const char *in_path, const char
#endif
#ifdef _WIN32
#define PACKAGE_VERSION "0.5.1"
#define PACKAGE_VERSION "0.5.2"
#endif
#include "config.features.h"
@@ -355,7 +359,7 @@ static void print_features(void)
_PSUPP(dylib, "External", "External filter and driver support");
_PSUPP(cg, "Cg", "Cg pixel shaders");
_PSUPP(xml, "XML", "bSNES XML pixel shaders");
_PSUPP(imlib, "Imlib2", "Imlib2 image loading");
_PSUPP(sdl_image, "SDL_image", "SDL_image image loading");
_PSUPP(fbo, "FBO", "OpenGL render-to-texture (multi-pass shaders)");
_PSUPP(dynamic, "Dynamic", "Dynamic run-time loading of libsnes library");
_PSUPP(ffmpeg, "FFmpeg", "On-the-fly recording of gameplay with libavcodec");
@@ -363,6 +367,7 @@ static void print_features(void)
_PSUPP(configfile, "Config file", "Configuration file support");
_PSUPP(freetype, "FreeType", "TTF font rendering with FreeType");
_PSUPP(netplay, "Netplay", "Peer-to-peer netplay");
_PSUPP(python, "Python", "Script support in shaders");
}
#undef _PSUPP