diff --git a/Makefile b/Makefile index f55a87b233..234a7ae941 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ ifeq ($(HAVE_COREAUDIO), 1) endif ifeq ($(HAVE_SDL), 1) - OBJ += gfx/sdl.o gfx/gl.o input/sdl.o audio/sdl.o fifo_buffer.o + OBJ += gfx/sdl.o gfx/gl.o gfx/sdlwrap.o input/sdl.o audio/sdl.o fifo_buffer.o DEFINES += $(SDL_CFLAGS) $(BSD_LOCAL_INC) LIBS += $(SDL_LIBS) ifeq ($(OSX),1) diff --git a/Makefile.win b/Makefile.win index f97079996e..b3a77a5e73 100644 --- a/Makefile.win +++ b/Makefile.win @@ -32,7 +32,7 @@ LDFLAGS = -L. -static-libgcc -s LDCXXFLAGS = -static-libstdc++ ifeq ($(HAVE_SDL), 1) - OBJ += gfx/sdl.o gfx/gl.o input/sdl.o audio/sdl.o fifo_buffer.o + OBJ += gfx/sdl.o gfx/gl.o gfx/sdlwrap.o input/sdl.o audio/sdl.o fifo_buffer.o LIBS += -lSDL -lopengl32 DEFINES += -ISDL -DHAVE_SDL endif diff --git a/driver.h b/driver.h index 7c14b5abf7..4041d9f2c4 100644 --- a/driver.h +++ b/driver.h @@ -56,7 +56,7 @@ enum struct snes_keybind { int id; - uint16_t key; + uint32_t key; uint16_t joykey; uint32_t joyaxis; }; diff --git a/gfx/ext.c b/gfx/ext.c index 0720227776..f4d845cc51 100644 --- a/gfx/ext.c +++ b/gfx/ext.c @@ -24,6 +24,7 @@ #include #include "dynamic.h" #include "general.h" +#include "sdlwrap.h" static bool g_input_dead = true; static bool g_video_dead = true; @@ -272,6 +273,11 @@ static bool setup_video(ext_t *ext, const video_info_t *video, const input_drive static void* video_ext_init(const video_info_t *video, const input_driver_t **input, void **input_data) { +#if SDL_MODERN + SSNES_ERR("External driver API not compatible with SDL 1.3 input API!\n"); + return NULL; +#endif + ext_t *ext = calloc(1, sizeof(*ext)); if (!ext) return NULL; diff --git a/gfx/gfx_common.c b/gfx/gfx_common.c index 7f7086653d..342449543c 100644 --- a/gfx/gfx_common.c +++ b/gfx/gfx_common.c @@ -112,23 +112,3 @@ void gfx_set_dwm(void) } #endif - -#include "SDL_syswm.h" -#include "SDL.h" - -#if !defined(__APPLE__) && !defined(_WIN32) -void gfx_get_window_size(unsigned *width, unsigned *height) -{ - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - SDL_GetWMInfo(&info); - XWindowAttributes target; - info.info.x11.lock_func(); - XGetWindowAttributes(info.info.x11.display, info.info.x11.window, - &target); - info.info.x11.unlock_func(); - - *width = target.width; - *height = target.height; -} -#endif diff --git a/gfx/gfx_common.h b/gfx/gfx_common.h index 3fd765cae3..e73f757f02 100644 --- a/gfx/gfx_common.h +++ b/gfx/gfx_common.h @@ -28,8 +28,4 @@ void gfx_window_title_reset(void); void gfx_set_dwm(void); #endif -#if !defined(__APPLE__) && !defined(_WIN32) -void gfx_get_window_size(unsigned *width, unsigned *height); -#endif - #endif diff --git a/gfx/gl.c b/gfx/gl.c index 6946c8dc86..e50c4c1480 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -33,6 +33,7 @@ #include "gl_common.h" #include "gfx_common.h" +#include "sdlwrap.h" #define NO_SDL_GLEXT #include "SDL.h" @@ -689,43 +690,20 @@ static inline void set_texture_coords(GLfloat *coords, GLfloat xamt, GLfloat yam static void check_window(gl_t *gl) { - SDL_Event event; + bool quit, resize; - // Search for events we care about ... - while (SDL_PollEvent(&event)) + sdlwrap_check_window(&quit, + &resize, &gl->win_width, &gl->win_height, + gl->frame_count); + + if (quit) { - 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; - } + gl->quitting = true; } - -#if !defined(__APPLE__) && !defined(_WIN32) - // Hack to workaround limitations in tiling WMs ... - if (!gl->should_resize && !gl->fullscreen) + else if (resize) { - unsigned new_width, new_height; - gfx_get_window_size(&new_width, &new_height); - if ((new_width != gl->win_width || new_height != gl->win_height) || (gl->frame_count == 10)) // Ugly hack :D - { - gl->should_resize = true; - gl->win_width = new_width; - gl->win_height = new_height; - SSNES_LOG("GL: Verified window size: %u x %u\n", gl->win_width, gl->win_height); - } + gl->should_resize = true; } -#endif } static bool gl_frame(void *data, const void* frame, unsigned width, unsigned height, unsigned pitch, const char *msg) @@ -806,13 +784,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei { gl->should_resize = false; - // Resizing is broken on OSX, yay. :) -#ifndef __APPLE__ - const int resizable_ = SDL_RESIZABLE; -#else - const int resizable_ = 0; -#endif - SDL_SetVideoMode(gl->win_width, gl->win_height, 0, SDL_OPENGL | (g_settings.video.fullscreen ? SDL_FULLSCREEN : resizable_)); + sdlwrap_set_video_mode(gl->win_width, gl->win_height, 0, g_settings.video.fullscreen); #ifdef HAVE_FBO if (!gl->render_to_tex) @@ -884,7 +856,7 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei #endif #ifdef HAVE_FBO - // Need to preserve the "flipped" state when in FBO too to have + // Need to preserve the "flipped" state when in FBO as well to have // consistent texture coordinates. if (gl->render_to_tex) glVertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), vertexes); @@ -996,8 +968,9 @@ static bool gl_frame(void *data, const void* frame, unsigned width, unsigned hei char buf[128]; if (gfx_window_title(buf, sizeof(buf))) - SDL_WM_SetCaption(buf, NULL); - SDL_GL_SwapBuffers(); + sdlwrap_wm_set_caption(buf); + + sdlwrap_swap_buffers(); return true; } @@ -1027,41 +1000,13 @@ static void gl_free(void *data) free(gl); } -#ifdef __APPLE__ -#include -#endif - static void gl_set_nonblock_state(void *data, bool state) { gl_t *gl = data; if (gl->vsync) { SSNES_LOG("GL VSync => %s\n", state ? "off" : "on"); -#if defined(_WIN32) - static BOOL (APIENTRY *wgl_swap_interval)(int) = NULL; - if (!wgl_swap_interval) - { - SDL_SYM_WRAP(wgl_swap_interval, "wglSwapIntervalEXT"); - } - if (wgl_swap_interval) wgl_swap_interval(state ? 0 : 1); -#elif defined(__APPLE__) - GLint val = state ? 0 : 1; - CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &val); -#else - static int (*glx_swap_interval)(int) = NULL; - if (!glx_swap_interval) - { - SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalSGI"); - } - if (!glx_swap_interval) - { - SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalMESA"); - } - if (glx_swap_interval) - glx_swap_interval(state ? 0 : 1); - else - SSNES_WARN("Could not find GLX VSync call. :(\n"); -#endif + sdlwrap_set_swap_interval(state ? 0 : 1, true); } } @@ -1080,22 +1025,16 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo 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); + sdlwrap_set_swap_interval(video->vsync ? 1 : 0, false); - // Resizing is broken on OSX, yay. :) -#ifndef __APPLE__ - const int resizable_ = SDL_RESIZABLE; -#else - const int resizable_ = 0; -#endif - if (!SDL_SetVideoMode(video->width, video->height, g_settings.video.force_16bit ? 16 : 0, SDL_OPENGL | (video->fullscreen ? SDL_FULLSCREEN : resizable_))) + if (!sdlwrap_set_video_mode(video->width, video->height, + g_settings.video.force_16bit ? 16 : 0, video->fullscreen)) return NULL; gfx_window_title_reset(); char buf[128]; if (gfx_window_title(buf, sizeof(buf))) - SDL_WM_SetCaption(buf, NULL); + sdlwrap_wm_set_caption(buf); // Remove that ugly mouse :D SDL_ShowCursor(SDL_DISABLE); @@ -1120,18 +1059,7 @@ static void* gl_init(const video_info_t *video, const input_driver_t **input, vo gl->vsync = video->vsync; gl->fullscreen = video->fullscreen; - int attr = 0; - SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &attr); - if (attr <= 0 && video->vsync) - { - SSNES_WARN("SDL failed to setup VSync, attempting to recover using native calls!\n"); - gl_set_nonblock_state(gl, false); - } - attr = 0; - SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &attr); - if (attr <= 0) - SSNES_WARN("GL double buffer has not been enabled!\n"); - + gl->full_x = full_x; gl->full_y = full_y; diff --git a/gfx/gl_common.h b/gfx/gl_common.h index 300bb13786..5ddb26e904 100644 --- a/gfx/gl_common.h +++ b/gfx/gl_common.h @@ -106,13 +106,6 @@ struct gl_tex_info GLfloat coord[8]; }; -// Not legal to cast void* to fn-pointer. Need dirty hack to be compilant. -// sizeof(void*) == sizeof(void (*)(void)) is asserted earlier. -#define SDL_SYM_WRAP(sym, symbol) { \ - void *sym__ = SDL_GL_GetProcAddress(symbol); \ - memcpy(&(sym), &sym__, sizeof(void*)); \ -} - // Windows ... <_< #if (defined(HAVE_XML) || defined(HAVE_CG)) && defined(_WIN32) extern PFNGLCLIENTACTIVETEXTUREPROC pglClientActiveTexture; diff --git a/gfx/sdlwrap.c b/gfx/sdlwrap.c new file mode 100644 index 0000000000..6f9830a09f --- /dev/null +++ b/gfx/sdlwrap.c @@ -0,0 +1,203 @@ +/* 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 . + */ + +#include "sdlwrap.h" +#include "SDL_syswm.h" +#include "general.h" +#include + +#ifdef __APPLE__ +#include +#endif + +// SDL 1.2 is portable, sure, but you still need some platform specific workarounds ;) +// Hopefully SDL 1.3 will solve this more cleanly :D + +static bool g_fullscreen; + +static unsigned g_interval; +void sdlwrap_set_swap_interval(unsigned interval, bool inited) +{ + g_interval = interval; + + if (inited) + { +#if defined(_WIN32) + static BOOL (APIENTRY *wgl_swap_interval)(int) = NULL; + if (!wgl_swap_interval) + { + SDL_SYM_WRAP(wgl_swap_interval, "wglSwapIntervalEXT"); + } + if (wgl_swap_interval) wgl_swap_interval(g_interval); + +#elif defined(__APPLE__) + GLint val = g_interval; + CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &val); +#else + static int (*glx_swap_interval)(int) = NULL; + if (!glx_swap_interval) + { + SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalSGI"); + } + if (!glx_swap_interval) + { + SDL_SYM_WRAP(glx_swap_interval, "glXSwapIntervalMESA"); + } + if (glx_swap_interval) + glx_swap_interval(g_interval); + else + SSNES_WARN("Could not find GLX VSync call. :(\n"); +#endif + } +} + +bool sdlwrap_set_video_mode( + unsigned width, unsigned height, + unsigned bits, bool fullscreen) +{ + // Resizing in windowed mode appears to be broken on OSX. Yay! +#ifndef __APPLE__ + static const int resizable = SDL_RESIZABLE; +#else + static const int resizable = 0; +#endif + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + +#if !SDL_MODERN + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, g_interval); +#endif + + if (!SDL_SetVideoMode(width, height, bits, + SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : resizable))) + return false; + + int attr = 0; +#if SDL_MODERN + SDL_GL_SetSwapInterval(g_interval); +#else + SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &attr); + if (attr <= 0 && g_interval) + { + SSNES_WARN("SDL failed to setup VSync, attempting to recover using native calls!\n"); + sdlwrap_set_swap_interval(g_interval, true); + } +#endif + + g_fullscreen = fullscreen; + + attr = 0; + SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &attr); + if (attr <= 0) + SSNES_WARN("GL double buffer has not been enabled!\n"); + + return true; +} + +void sdlwrap_wm_set_caption(const char *str) +{ + SDL_WM_SetCaption(str, NULL); +} + +void sdlwrap_swap_buffers(void) +{ + SDL_GL_SwapBuffers(); +} + +bool sdlwrap_key_pressed(int key) +{ + int num_keys; +#if SDL_MODERN + Uint8 *keymap = SDL_GetKeyboardState(&num_keys); + key = SDL_GetScancodeFromKey(key); + if (key >= num_keys) + return false; + + return keymap[key]; +#else + Uint8 *keymap = SDL_GetKeyState(&num_keys); + if (key >= num_keys) + return false; + + return keymap[key]; +#endif +} + +#if !defined(__APPLE__) && !defined(_WIN32) +static void sdlwrap_get_window_size(unsigned *width, unsigned *height) +{ + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + SDL_GetWMInfo(&info); + XWindowAttributes target; + +#if SDL_MODERN + XGetWindowAttributes(info.info.x11.display, info.info.x11.window, + &target); +#else + info.info.x11.lock_func(); + XGetWindowAttributes(info.info.x11.display, info.info.x11.window, + &target); + info.info.x11.unlock_func(); +#endif + + *width = target.width; + *height = target.height; +} +#endif + +void sdlwrap_check_window(bool *quit, + bool *resize, unsigned *width, unsigned *height, unsigned frame_count) +{ + *quit = false; + *resize = false; + + SDL_Event event; + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + *quit = true; + break; + + case SDL_VIDEORESIZE: + *resize = true; + *width = event.resize.w; + *height = event.resize.h; + break; + } + } + +#if !defined(__APPLE__) && !defined(_WIN32) + // Hack to workaround limitations in tiling WMs ... + if (!*resize && !g_fullscreen) + { + unsigned new_width, new_height; + sdlwrap_get_window_size(&new_width, &new_height); + if ((new_width != *width || new_height != *height) || (frame_count == 10)) // Ugly hack :D + { + *resize = true; + *width = new_width; + *height = new_height; + SSNES_LOG("GL: Verified window size: %u x %u\n", *width, *height); + } + } +#endif +} + diff --git a/gfx/sdlwrap.h b/gfx/sdlwrap.h new file mode 100644 index 0000000000..9efbfada14 --- /dev/null +++ b/gfx/sdlwrap.h @@ -0,0 +1,62 @@ +/* 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 . + */ + +// Compatibility wrapper between SDL 1.2/1.3 for OpenGL. +// Wraps functions which differ in 1.2 and 1.3. + +#ifndef __SDLWRAP_H +#define __SDLWRAP_H + +#include + +#include "SDL.h" +#include "SDL_version.h" + +#if SDL_VERSION_ATLEAST(1, 3, 0) +#define SDL_MODERN 1 +#else +#define SDL_MODERN 0 +#endif + +//#if SDL_MODERN +//#error "SDL 1.3 support not yet implemented!" +//#endif + +// Not legal to cast void* to fn-pointer. Need workaround to be compliant. +#define SDL_SYM_WRAP(sym, symbol) { \ + assert(sizeof(void*) == sizeof(void (*)(void))); \ + void *sym__ = SDL_GL_GetProcAddress(symbol); \ + memcpy(&(sym), &sym__, sizeof(void*)); \ +} + +void sdlwrap_set_swap_interval(unsigned interval, bool inited); + +bool sdlwrap_set_video_mode( + unsigned width, unsigned height, + unsigned bits, bool fullscreen); + +void sdlwrap_wm_set_caption(const char *str); + +void sdlwrap_swap_buffers(void); + +bool sdlwrap_key_pressed(int key); + +void sdlwrap_check_window(bool *quit, + bool *resize, unsigned *width, unsigned *height, unsigned frame_count); + +#endif + diff --git a/gfx/shader_glsl.c b/gfx/shader_glsl.c index 027146102f..ccaed4120d 100644 --- a/gfx/shader_glsl.c +++ b/gfx/shader_glsl.c @@ -33,7 +33,7 @@ #define NO_SDL_GLEXT -#include "SDL.h" +#include "sdlwrap.h" #include "SDL_opengl.h" #include #include diff --git a/input/sdl.c b/input/sdl.c index 6c5db31f77..a948e01cde 100644 --- a/input/sdl.c +++ b/input/sdl.c @@ -17,7 +17,7 @@ #include "driver.h" -#include "SDL.h" +#include "../gfx/sdlwrap.h" #include #include "general.h" #include @@ -76,16 +76,9 @@ static void* sdl_input_init(void) return sdl; } - static bool sdl_key_pressed(int key) { - int num_keys; - Uint8 *keymap = SDL_GetKeyState(&num_keys); - - if (key >= num_keys) - return false; - - return keymap[key]; + return sdlwrap_key_pressed(key); } #ifndef HAVE_DINPUT diff --git a/input/x11_input.c b/input/x11_input.c index 42ca2cd320..751956a84b 100644 --- a/input/x11_input.c +++ b/input/x11_input.c @@ -41,7 +41,11 @@ struct key_bind int sdl; }; -static int keysym_lut[SDLK_LAST]; +#define LUT_SIZE 1024 +#define LUT_MASK (LUT_SIZE - 1) + +static int keysym_lut[LUT_SIZE]; + static const struct key_bind lut_binds[] = { { XK_Left, SDLK_LEFT }, { XK_Right, SDLK_RIGHT }, @@ -130,7 +134,7 @@ static void init_lut(void) { memset(keysym_lut, 0, sizeof(keysym_lut)); for (unsigned i = 0; i < sizeof(lut_binds) / sizeof(lut_binds[0]); i++) - keysym_lut[lut_binds[i].sdl] = lut_binds[i].x; + keysym_lut[lut_binds[i].sdl & LUT_MASK] = lut_binds[i].x; } static void* x_input_init(void) @@ -161,7 +165,7 @@ static void* x_input_init(void) static bool x_key_pressed(x11_input_t *x11, int key) { - key = keysym_lut[key]; + key = keysym_lut[key & LUT_MASK]; int keycode = XKeysymToKeycode(x11->display, key); bool ret = x11->state[keycode >> 3] & (1 << (keycode & 7)); return ret; diff --git a/qb/config.libs.sh b/qb/config.libs.sh index 34a6e26f7d..a4bf9b23b2 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -58,12 +58,7 @@ check_pkgconf PULSE libpulse check_lib COREAUDIO "-framework AudioUnit" AudioUnitInitialize check_pkgconf SDL sdl 1.2.10 -check_critical SDL "Cannot find SDL 1.2 library." -check_pkgconf SDL_NEW sdl 1.3 -if [ $HAVE_SDL_NEW = yes ]; then - echo "SSNES is not compatible with SDL 1.3 API, please use a recent 1.2 release." - exit 1 -fi +check_critical SDL "Cannot find SDL library." # On some distros, -lCg doesn't link against -lstdc++ it seems ... check_lib_cxx CG -lCg cgCreateContext