From 05c23063bb16c44191d5b0b151ac5739eb355142 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 9 Mar 2014 11:06:11 -0700 Subject: [PATCH] Fixed line endings on WinRT source code --- include/SDL_config_winrt.h | 6 +- include/SDL_egl.h | 4 +- include/SDL_main.h | 2 +- include/SDL_platform.h | 336 +- include/SDL_system.h | 370 +- include/begin_code.h | 280 +- src/SDL_log.c | 878 +-- src/atomic/SDL_spinlock.c | 252 +- src/audio/xaudio2/SDL_xaudio2.c | 1086 +-- .../xaudio2/SDL_xaudio2_winrthelpers.cpp | 138 +- src/audio/xaudio2/SDL_xaudio2_winrthelpers.h | 104 +- src/core/winrt/SDL_winrtapp_common.cpp | 30 +- src/core/winrt/SDL_winrtapp_common.h | 18 +- src/core/winrt/SDL_winrtapp_direct3d.cpp | 1326 ++-- src/core/winrt/SDL_winrtapp_direct3d.h | 116 +- src/file/SDL_rwops.c | 1530 ++-- src/filesystem/winrt/SDL_sysfilesystem.cpp | 308 +- src/joystick/SDL_gamecontroller.c | 2494 +++---- src/main/winrt/SDL_winrt_main_NonXAML.cpp | 112 +- src/render/direct3d11/SDL_render_d3d11.cpp | 3132 ++++---- src/thread/stdcpp/SDL_systhread.cpp | 22 +- src/timer/windows/SDL_systimer.c | 22 +- src/video/SDL_sysvideo.h | 802 +- src/video/SDL_video.c | 6586 ++++++++--------- src/video/winrt/SDL_winrtevents.cpp | 180 +- src/video/winrt/SDL_winrtevents_c.h | 6 +- src/video/winrt/SDL_winrtkeyboard.cpp | 600 +- src/video/winrt/SDL_winrtmouse.cpp | 332 +- src/video/winrt/SDL_winrtopengles.cpp | 100 +- src/video/winrt/SDL_winrtopengles.h | 96 +- src/video/winrt/SDL_winrtpointerinput.cpp | 710 +- src/video/winrt/SDL_winrtvideo.cpp | 18 +- src/video/winrt/SDL_winrtvideo_cpp.h | 50 +- test/loopwave.c | 288 +- test/testthread.c | 198 +- 35 files changed, 11266 insertions(+), 11266 deletions(-) diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h index b995205449820..2d925813290f1 100644 --- a/include/SDL_config_winrt.h +++ b/include/SDL_config_winrt.h @@ -166,9 +166,9 @@ typedef unsigned int uintptr_t; #define SDL_VIDEO_DRIVER_WINRT 1 #define SDL_VIDEO_DRIVER_DUMMY 1 -/* Enable OpenGL ES 2.0 (via a modified ANGLE library) */ -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP /* TODO, WinRT: try adding OpenGL ES 2 support for Windows Phone 8 */ -#define SDL_VIDEO_OPENGL_ES2 1 +/* Enable OpenGL ES 2.0 (via a modified ANGLE library) */ +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP /* TODO, WinRT: try adding OpenGL ES 2 support for Windows Phone 8 */ +#define SDL_VIDEO_OPENGL_ES2 1 #define SDL_VIDEO_OPENGL_EGL 1 #endif diff --git a/include/SDL_egl.h b/include/SDL_egl.h index 5a1bc374bc46b..ec6eb105c13dd 100644 --- a/include/SDL_egl.h +++ b/include/SDL_egl.h @@ -393,8 +393,8 @@ typedef enum { #if __WINRT__ #include -typedef IUnknown * EGLNativeWindowType; -typedef int EGLNativeDisplayType; +typedef IUnknown * EGLNativeWindowType; +typedef int EGLNativeDisplayType; typedef HBITMAP EGLNativePixmapType; #else typedef HDC EGLNativeDisplayType; diff --git a/include/SDL_main.h b/include/SDL_main.h index a8969810b504a..97ed0cf0809fe 100644 --- a/include/SDL_main.h +++ b/include/SDL_main.h @@ -140,7 +140,7 @@ extern DECLSPEC void SDLCALL SDL_UnregisterApp(void); * \ret 0 on success, -1 on failure. On failure, use SDL_GetError to retrieve more * information on the failure. */ -extern DECLSPEC int SDLCALL SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * xamlBackgroundPanel); +extern DECLSPEC int SDLCALL SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * xamlBackgroundPanel); #endif /* __WINRT__ */ diff --git a/include/SDL_platform.h b/include/SDL_platform.h index 8cddb432d962a..333044775f9a5 100644 --- a/include/SDL_platform.h +++ b/include/SDL_platform.h @@ -1,168 +1,168 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/** - * \file SDL_platform.h - * - * Try to get a standard set of platform defines. - */ - -#ifndef _SDL_platform_h -#define _SDL_platform_h - -#if defined(_AIX) -#undef __AIX__ -#define __AIX__ 1 -#endif -#if defined(__HAIKU__) -#undef __HAIKU__ -#define __HAIKU__ 1 -#endif -#if defined(bsdi) || defined(__bsdi) || defined(__bsdi__) -#undef __BSDI__ -#define __BSDI__ 1 -#endif -#if defined(_arch_dreamcast) -#undef __DREAMCAST__ -#define __DREAMCAST__ 1 -#endif -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) -#undef __FREEBSD__ -#define __FREEBSD__ 1 -#endif -#if defined(hpux) || defined(__hpux) || defined(__hpux__) -#undef __HPUX__ -#define __HPUX__ 1 -#endif -#if defined(sgi) || defined(__sgi) || defined(__sgi__) || defined(_SGI_SOURCE) -#undef __IRIX__ -#define __IRIX__ 1 -#endif -#if defined(linux) || defined(__linux) || defined(__linux__) -#undef __LINUX__ -#define __LINUX__ 1 -#endif -#if defined(ANDROID) -#undef __ANDROID__ -#undef __LINUX__ /* do we need to do this? */ -#define __ANDROID__ 1 -#endif - -#if defined(__APPLE__) -/* lets us know what version of Mac OS X we're compiling on */ -#include "AvailabilityMacros.h" -#include "TargetConditionals.h" -#if TARGET_OS_IPHONE -/* if compiling for iPhone */ -#undef __IPHONEOS__ -#define __IPHONEOS__ 1 -#undef __MACOSX__ -#else -/* if not compiling for iPhone */ -#undef __MACOSX__ -#define __MACOSX__ 1 -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 -# error SDL for Mac OS X only supports deploying on 10.5 and above. -#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1050 */ -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 -# error SDL for Mac OS X must be built with a 10.6 SDK or above. -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */ -#endif /* TARGET_OS_IPHONE */ -#endif /* defined(__APPLE__) */ - -#if defined(__NetBSD__) -#undef __NETBSD__ -#define __NETBSD__ 1 -#endif -#if defined(__OpenBSD__) -#undef __OPENBSD__ -#define __OPENBSD__ 1 -#endif -#if defined(__OS2__) -#undef __OS2__ -#define __OS2__ 1 -#endif -#if defined(osf) || defined(__osf) || defined(__osf__) || defined(_OSF_SOURCE) -#undef __OSF__ -#define __OSF__ 1 -#endif -#if defined(__QNXNTO__) -#undef __QNXNTO__ -#define __QNXNTO__ 1 -#endif -#if defined(riscos) || defined(__riscos) || defined(__riscos__) -#undef __RISCOS__ -#define __RISCOS__ 1 -#endif -#if defined(__SVR4) -#undef __SOLARIS__ -#define __SOLARIS__ 1 -#endif - -#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) -/* Try to find out if we're compiling for WinRT or non-WinRT */ -#if defined(_MSC_VER) && (_MSC_VER >= 1700) /* _MSC_VER==1700 for MSVC 2012 */ -#include -#endif /* _MSC_VER >= 1700 */ -/* Default to classic, Win32/Win64/Desktop compilation either if: - 1. the version of Windows is explicity set to a 'Desktop' (non-Metro) app - 2. the version of Windows cannot be determined via winapifamily.h - If neither is true, then see if we're compiling for WinRT. - */ -#if ! defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#undef __WINDOWS__ -#define __WINDOWS__ 1 -/* See if we're compiling for WinRT: */ -#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) -#undef __WINRT__ -#define __WINRT__ 1 -#endif /* ! defined(WINAPI_FAMILY_PARTITION) */ -#endif /* defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) */ - -#if defined(__WINDOWS__) -#undef __WIN32__ -#define __WIN32__ 1 -#endif -#if defined(__PSP__) -#undef __PSP__ -#define __PSP__ 1 -#endif - -#include "begin_code.h" -/* Set up for C function definitions, even when using C++ */ -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Gets the name of the platform. - */ -extern DECLSPEC const char * SDLCALL SDL_GetPlatform (void); - -/* Ends C function definitions when using C++ */ -#ifdef __cplusplus -} -#endif -#include "close_code.h" - -#endif /* _SDL_platform_h */ - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/** + * \file SDL_platform.h + * + * Try to get a standard set of platform defines. + */ + +#ifndef _SDL_platform_h +#define _SDL_platform_h + +#if defined(_AIX) +#undef __AIX__ +#define __AIX__ 1 +#endif +#if defined(__HAIKU__) +#undef __HAIKU__ +#define __HAIKU__ 1 +#endif +#if defined(bsdi) || defined(__bsdi) || defined(__bsdi__) +#undef __BSDI__ +#define __BSDI__ 1 +#endif +#if defined(_arch_dreamcast) +#undef __DREAMCAST__ +#define __DREAMCAST__ 1 +#endif +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) +#undef __FREEBSD__ +#define __FREEBSD__ 1 +#endif +#if defined(hpux) || defined(__hpux) || defined(__hpux__) +#undef __HPUX__ +#define __HPUX__ 1 +#endif +#if defined(sgi) || defined(__sgi) || defined(__sgi__) || defined(_SGI_SOURCE) +#undef __IRIX__ +#define __IRIX__ 1 +#endif +#if defined(linux) || defined(__linux) || defined(__linux__) +#undef __LINUX__ +#define __LINUX__ 1 +#endif +#if defined(ANDROID) +#undef __ANDROID__ +#undef __LINUX__ /* do we need to do this? */ +#define __ANDROID__ 1 +#endif + +#if defined(__APPLE__) +/* lets us know what version of Mac OS X we're compiling on */ +#include "AvailabilityMacros.h" +#include "TargetConditionals.h" +#if TARGET_OS_IPHONE +/* if compiling for iPhone */ +#undef __IPHONEOS__ +#define __IPHONEOS__ 1 +#undef __MACOSX__ +#else +/* if not compiling for iPhone */ +#undef __MACOSX__ +#define __MACOSX__ 1 +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 +# error SDL for Mac OS X only supports deploying on 10.5 and above. +#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1050 */ +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 +# error SDL for Mac OS X must be built with a 10.6 SDK or above. +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1060 */ +#endif /* TARGET_OS_IPHONE */ +#endif /* defined(__APPLE__) */ + +#if defined(__NetBSD__) +#undef __NETBSD__ +#define __NETBSD__ 1 +#endif +#if defined(__OpenBSD__) +#undef __OPENBSD__ +#define __OPENBSD__ 1 +#endif +#if defined(__OS2__) +#undef __OS2__ +#define __OS2__ 1 +#endif +#if defined(osf) || defined(__osf) || defined(__osf__) || defined(_OSF_SOURCE) +#undef __OSF__ +#define __OSF__ 1 +#endif +#if defined(__QNXNTO__) +#undef __QNXNTO__ +#define __QNXNTO__ 1 +#endif +#if defined(riscos) || defined(__riscos) || defined(__riscos__) +#undef __RISCOS__ +#define __RISCOS__ 1 +#endif +#if defined(__SVR4) +#undef __SOLARIS__ +#define __SOLARIS__ 1 +#endif + +#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) +/* Try to find out if we're compiling for WinRT or non-WinRT */ +#if defined(_MSC_VER) && (_MSC_VER >= 1700) /* _MSC_VER==1700 for MSVC 2012 */ +#include +#endif /* _MSC_VER >= 1700 */ +/* Default to classic, Win32/Win64/Desktop compilation either if: + 1. the version of Windows is explicity set to a 'Desktop' (non-Metro) app + 2. the version of Windows cannot be determined via winapifamily.h + If neither is true, then see if we're compiling for WinRT. + */ +#if ! defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#undef __WINDOWS__ +#define __WINDOWS__ 1 +/* See if we're compiling for WinRT: */ +#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#undef __WINRT__ +#define __WINRT__ 1 +#endif /* ! defined(WINAPI_FAMILY_PARTITION) */ +#endif /* defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) */ + +#if defined(__WINDOWS__) +#undef __WIN32__ +#define __WIN32__ 1 +#endif +#if defined(__PSP__) +#undef __PSP__ +#define __PSP__ 1 +#endif + +#include "begin_code.h" +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Gets the name of the platform. + */ +extern DECLSPEC const char * SDLCALL SDL_GetPlatform (void); + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* _SDL_platform_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/include/SDL_system.h b/include/SDL_system.h index 5dc64cc9411fc..fecbf1cfb3498 100644 --- a/include/SDL_system.h +++ b/include/SDL_system.h @@ -1,185 +1,185 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/** - * \file SDL_system.h - * - * Include file for platform specific SDL API functions - */ - -#ifndef _SDL_system_h -#define _SDL_system_h - -#include "SDL_stdinc.h" -#include "SDL_keyboard.h" -#include "SDL_render.h" -#include "SDL_video.h" - -#include "begin_code.h" -/* Set up for C function definitions, even when using C++ */ -#ifdef __cplusplus -extern "C" { -#endif - - -/* Platform specific functions for Windows */ -#ifdef __WIN32__ - -/* Returns the D3D9 adapter index that matches the specified display index. - This adapter index can be passed to IDirect3D9::CreateDevice and controls - on which monitor a full screen application will appear. -*/ -extern DECLSPEC int SDLCALL SDL_Direct3D9GetAdapterIndex( int displayIndex ); - -/* Returns the D3D device associated with a renderer, or NULL if it's not a D3D renderer. - Once you are done using the device, you should release it to avoid a resource leak. - */ -typedef struct IDirect3DDevice9 IDirect3DDevice9; -extern DECLSPEC IDirect3DDevice9* SDLCALL SDL_RenderGetD3D9Device(SDL_Renderer * renderer); - -#endif /* __WIN32__ */ - - -/* Platform specific functions for iOS */ -#if defined(__IPHONEOS__) && __IPHONEOS__ - -extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam); -extern DECLSPEC void SDLCALL SDL_iPhoneSetEventPump(SDL_bool enabled); - -#endif /* __IPHONEOS__ */ - - -/* Platform specific functions for Android */ -#if defined(__ANDROID__) && __ANDROID__ - -/* Get the JNI environment for the current thread - This returns JNIEnv*, but the prototype is void* so we don't need jni.h - */ -extern DECLSPEC void * SDLCALL SDL_AndroidGetJNIEnv(); - -/* Get the SDL Activity object for the application - This returns jobject, but the prototype is void* so we don't need jni.h - The jobject returned by SDL_AndroidGetActivity is a local reference. - It is the caller's responsibility to properly release it - (using env->Push/PopLocalFrame or manually with env->DeleteLocalRef) - */ -extern DECLSPEC void * SDLCALL SDL_AndroidGetActivity(); - -/* See the official Android developer guide for more information: - http://developer.android.com/guide/topics/data/data-storage.html -*/ -#define SDL_ANDROID_EXTERNAL_STORAGE_READ 0x01 -#define SDL_ANDROID_EXTERNAL_STORAGE_WRITE 0x02 - -/* Get the path used for internal storage for this application. - This path is unique to your application and cannot be written to - by other applications. - */ -extern DECLSPEC const char * SDLCALL SDL_AndroidGetInternalStoragePath(); - -/* Get the current state of external storage, a bitmask of these values: - SDL_ANDROID_EXTERNAL_STORAGE_READ - SDL_ANDROID_EXTERNAL_STORAGE_WRITE - If external storage is currently unavailable, this will return 0. -*/ -extern DECLSPEC int SDLCALL SDL_AndroidGetExternalStorageState(); - -/* Get the path used for external storage for this application. - This path is unique to your application, but is public and can be - written to by other applications. - */ -extern DECLSPEC const char * SDLCALL SDL_AndroidGetExternalStoragePath(); - -#endif /* __ANDROID__ */ - -/* Platform specific functions for WinRT */ -#if defined(__WINRT__) && __WINRT__ - -/** - * \brief WinRT / Windows Phone path types - */ -typedef enum -{ - /** \brief The installed app's root directory. - Files here are likely to be read-only. */ - SDL_WINRT_PATH_INSTALLED_LOCATION, - - /** \brief The app's local data store. Files may be written here */ - SDL_WINRT_PATH_LOCAL_FOLDER, - - /** \brief The app's roaming data store. Unsupported on Windows Phone. - Files written here may be copied to other machines via a network - connection. - */ - SDL_WINRT_PATH_ROAMING_FOLDER, - - /** \brief The app's temporary data store. Unsupported on Windows Phone. - Files written here may be deleted at any time. */ - SDL_WINRT_PATH_TEMP_FOLDER -} SDL_WinRT_Path; - - -/** - * \brief Retrieves a WinRT defined path on the local file system - * - * \note Documentation on most app-specific path types on WinRT - * can be found on MSDN, at the URL: - * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx - * - * \param pathType The type of path to retrieve. - * \ret A UCS-2 string (16-bit, wide-char) containing the path, or NULL - * if the path is not available for any reason. Not all paths are - * available on all versions of Windows. This is especially true on - * Windows Phone. Check the documentation for the given - * SDL_WinRT_Path for more information on which path types are - * supported where. - */ -extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType); - -/** - * \brief Retrieves a WinRT defined path on the local file system - * - * \note Documentation on most app-specific path types on WinRT - * can be found on MSDN, at the URL: - * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx - * - * \param pathType The type of path to retrieve. - * \ret A UTF-8 string (8-bit, multi-byte) containing the path, or NULL - * if the path is not available for any reason. Not all paths are - * available on all versions of Windows. This is especially true on - * Windows Phone. Check the documentation for the given - * SDL_WinRT_Path for more information on which path types are - * supported where. - */ -extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType); - -#endif /* __WINRT__ */ - - -/* Ends C function definitions when using C++ */ -#ifdef __cplusplus -} -#endif -#include "close_code.h" - -#endif /* _SDL_system_h */ - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/** + * \file SDL_system.h + * + * Include file for platform specific SDL API functions + */ + +#ifndef _SDL_system_h +#define _SDL_system_h + +#include "SDL_stdinc.h" +#include "SDL_keyboard.h" +#include "SDL_render.h" +#include "SDL_video.h" + +#include "begin_code.h" +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + + +/* Platform specific functions for Windows */ +#ifdef __WIN32__ + +/* Returns the D3D9 adapter index that matches the specified display index. + This adapter index can be passed to IDirect3D9::CreateDevice and controls + on which monitor a full screen application will appear. +*/ +extern DECLSPEC int SDLCALL SDL_Direct3D9GetAdapterIndex( int displayIndex ); + +/* Returns the D3D device associated with a renderer, or NULL if it's not a D3D renderer. + Once you are done using the device, you should release it to avoid a resource leak. + */ +typedef struct IDirect3DDevice9 IDirect3DDevice9; +extern DECLSPEC IDirect3DDevice9* SDLCALL SDL_RenderGetD3D9Device(SDL_Renderer * renderer); + +#endif /* __WIN32__ */ + + +/* Platform specific functions for iOS */ +#if defined(__IPHONEOS__) && __IPHONEOS__ + +extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam); +extern DECLSPEC void SDLCALL SDL_iPhoneSetEventPump(SDL_bool enabled); + +#endif /* __IPHONEOS__ */ + + +/* Platform specific functions for Android */ +#if defined(__ANDROID__) && __ANDROID__ + +/* Get the JNI environment for the current thread + This returns JNIEnv*, but the prototype is void* so we don't need jni.h + */ +extern DECLSPEC void * SDLCALL SDL_AndroidGetJNIEnv(); + +/* Get the SDL Activity object for the application + This returns jobject, but the prototype is void* so we don't need jni.h + The jobject returned by SDL_AndroidGetActivity is a local reference. + It is the caller's responsibility to properly release it + (using env->Push/PopLocalFrame or manually with env->DeleteLocalRef) + */ +extern DECLSPEC void * SDLCALL SDL_AndroidGetActivity(); + +/* See the official Android developer guide for more information: + http://developer.android.com/guide/topics/data/data-storage.html +*/ +#define SDL_ANDROID_EXTERNAL_STORAGE_READ 0x01 +#define SDL_ANDROID_EXTERNAL_STORAGE_WRITE 0x02 + +/* Get the path used for internal storage for this application. + This path is unique to your application and cannot be written to + by other applications. + */ +extern DECLSPEC const char * SDLCALL SDL_AndroidGetInternalStoragePath(); + +/* Get the current state of external storage, a bitmask of these values: + SDL_ANDROID_EXTERNAL_STORAGE_READ + SDL_ANDROID_EXTERNAL_STORAGE_WRITE + If external storage is currently unavailable, this will return 0. +*/ +extern DECLSPEC int SDLCALL SDL_AndroidGetExternalStorageState(); + +/* Get the path used for external storage for this application. + This path is unique to your application, but is public and can be + written to by other applications. + */ +extern DECLSPEC const char * SDLCALL SDL_AndroidGetExternalStoragePath(); + +#endif /* __ANDROID__ */ + +/* Platform specific functions for WinRT */ +#if defined(__WINRT__) && __WINRT__ + +/** + * \brief WinRT / Windows Phone path types + */ +typedef enum +{ + /** \brief The installed app's root directory. + Files here are likely to be read-only. */ + SDL_WINRT_PATH_INSTALLED_LOCATION, + + /** \brief The app's local data store. Files may be written here */ + SDL_WINRT_PATH_LOCAL_FOLDER, + + /** \brief The app's roaming data store. Unsupported on Windows Phone. + Files written here may be copied to other machines via a network + connection. + */ + SDL_WINRT_PATH_ROAMING_FOLDER, + + /** \brief The app's temporary data store. Unsupported on Windows Phone. + Files written here may be deleted at any time. */ + SDL_WINRT_PATH_TEMP_FOLDER +} SDL_WinRT_Path; + + +/** + * \brief Retrieves a WinRT defined path on the local file system + * + * \note Documentation on most app-specific path types on WinRT + * can be found on MSDN, at the URL: + * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx + * + * \param pathType The type of path to retrieve. + * \ret A UCS-2 string (16-bit, wide-char) containing the path, or NULL + * if the path is not available for any reason. Not all paths are + * available on all versions of Windows. This is especially true on + * Windows Phone. Check the documentation for the given + * SDL_WinRT_Path for more information on which path types are + * supported where. + */ +extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType); + +/** + * \brief Retrieves a WinRT defined path on the local file system + * + * \note Documentation on most app-specific path types on WinRT + * can be found on MSDN, at the URL: + * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx + * + * \param pathType The type of path to retrieve. + * \ret A UTF-8 string (8-bit, multi-byte) containing the path, or NULL + * if the path is not available for any reason. Not all paths are + * available on all versions of Windows. This is especially true on + * Windows Phone. Check the documentation for the given + * SDL_WinRT_Path for more information on which path types are + * supported where. + */ +extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType); + +#endif /* __WINRT__ */ + + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include "close_code.h" + +#endif /* _SDL_system_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/include/begin_code.h b/include/begin_code.h index 1a5aa31bd6a47..2651ee1b520de 100644 --- a/include/begin_code.h +++ b/include/begin_code.h @@ -1,140 +1,140 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/** - * \file begin_code.h - * - * This file sets things up for C dynamic library function definitions, - * static inlined functions, and structures aligned at 4-byte alignment. - * If you don't like ugly C preprocessor code, don't look at this file. :) - */ - -/* This shouldn't be nested -- included it around code only. */ -#ifdef _begin_code_h -#error Nested inclusion of begin_code.h -#endif -#define _begin_code_h - -#ifndef SDL_DEPRECATED -# if (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */ -# define SDL_DEPRECATED __attribute__((deprecated)) -# else -# define SDL_DEPRECATED -# endif -#endif - -/* Some compilers use a special export keyword */ -#ifndef DECLSPEC -# if defined(__WIN32__) || defined(__WINRT__) -# ifdef __BORLANDC__ -# ifdef BUILD_SDL -# define DECLSPEC -# else -# define DECLSPEC __declspec(dllimport) -# endif -# else -# define DECLSPEC __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && __GNUC__ >= 4 -# define DECLSPEC __attribute__ ((visibility("default"))) -# elif defined(__GNUC__) && __GNUC__ >= 2 -# define DECLSPEC __declspec(dllexport) -# else -# define DECLSPEC -# endif -# endif -#endif - -/* By default SDL uses the C calling convention */ -#ifndef SDLCALL -#if (defined(__WIN32__) || defined(__WINRT__)) && !defined(__GNUC__) -#define SDLCALL __cdecl -#else -#define SDLCALL -#endif -#endif /* SDLCALL */ - -/* Removed DECLSPEC on Symbian OS because SDL cannot be a DLL in EPOC */ -#ifdef __SYMBIAN32__ -#undef DECLSPEC -#define DECLSPEC -#endif /* __SYMBIAN32__ */ - -/* Force structure packing at 4 byte alignment. - This is necessary if the header is included in code which has structure - packing set to an alternate value, say for loading structures from disk. - The packing is reset to the previous value in close_code.h - */ -#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__) -#ifdef _MSC_VER -#pragma warning(disable: 4103) -#endif -#ifdef __BORLANDC__ -#pragma nopackwarning -#endif -#ifdef _M_X64 -/* Use 8-byte alignment on 64-bit architectures, so pointers are aligned */ -#pragma pack(push,8) -#else -#pragma pack(push,4) -#endif -#endif /* Compiler needs structure packing set */ - -#ifndef SDL_INLINE -#if defined(__GNUC__) -#define SDL_INLINE __inline__ -#elif defined(_MSC_VER) || defined(__BORLANDC__) || \ - defined(__DMC__) || defined(__SC__) || \ - defined(__WATCOMC__) || defined(__LCC__) || \ - defined(__DECC) -#define SDL_INLINE __inline -#ifndef __inline__ -#define __inline__ __inline -#endif -#else -#define SDL_INLINE inline -#ifndef __inline__ -#define __inline__ inline -#endif -#endif -#endif /* SDL_INLINE not defined */ - -#ifndef SDL_FORCE_INLINE -#if defined(_MSC_VER) -#define SDL_FORCE_INLINE __forceinline -#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) ) -#define SDL_FORCE_INLINE __attribute__((always_inline)) static __inline__ -#else -#define SDL_FORCE_INLINE static SDL_INLINE -#endif -#endif /* SDL_FORCE_INLINE not defined */ - -/* Apparently this is needed by several Windows compilers */ -#if !defined(__MACH__) -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *)0) -#endif -#endif /* NULL */ -#endif /* ! Mac OS X - breaks precompiled headers */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/** + * \file begin_code.h + * + * This file sets things up for C dynamic library function definitions, + * static inlined functions, and structures aligned at 4-byte alignment. + * If you don't like ugly C preprocessor code, don't look at this file. :) + */ + +/* This shouldn't be nested -- included it around code only. */ +#ifdef _begin_code_h +#error Nested inclusion of begin_code.h +#endif +#define _begin_code_h + +#ifndef SDL_DEPRECATED +# if (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */ +# define SDL_DEPRECATED __attribute__((deprecated)) +# else +# define SDL_DEPRECATED +# endif +#endif + +/* Some compilers use a special export keyword */ +#ifndef DECLSPEC +# if defined(__WIN32__) || defined(__WINRT__) +# ifdef __BORLANDC__ +# ifdef BUILD_SDL +# define DECLSPEC +# else +# define DECLSPEC __declspec(dllimport) +# endif +# else +# define DECLSPEC __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && __GNUC__ >= 4 +# define DECLSPEC __attribute__ ((visibility("default"))) +# elif defined(__GNUC__) && __GNUC__ >= 2 +# define DECLSPEC __declspec(dllexport) +# else +# define DECLSPEC +# endif +# endif +#endif + +/* By default SDL uses the C calling convention */ +#ifndef SDLCALL +#if (defined(__WIN32__) || defined(__WINRT__)) && !defined(__GNUC__) +#define SDLCALL __cdecl +#else +#define SDLCALL +#endif +#endif /* SDLCALL */ + +/* Removed DECLSPEC on Symbian OS because SDL cannot be a DLL in EPOC */ +#ifdef __SYMBIAN32__ +#undef DECLSPEC +#define DECLSPEC +#endif /* __SYMBIAN32__ */ + +/* Force structure packing at 4 byte alignment. + This is necessary if the header is included in code which has structure + packing set to an alternate value, say for loading structures from disk. + The packing is reset to the previous value in close_code.h + */ +#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__) +#ifdef _MSC_VER +#pragma warning(disable: 4103) +#endif +#ifdef __BORLANDC__ +#pragma nopackwarning +#endif +#ifdef _M_X64 +/* Use 8-byte alignment on 64-bit architectures, so pointers are aligned */ +#pragma pack(push,8) +#else +#pragma pack(push,4) +#endif +#endif /* Compiler needs structure packing set */ + +#ifndef SDL_INLINE +#if defined(__GNUC__) +#define SDL_INLINE __inline__ +#elif defined(_MSC_VER) || defined(__BORLANDC__) || \ + defined(__DMC__) || defined(__SC__) || \ + defined(__WATCOMC__) || defined(__LCC__) || \ + defined(__DECC) +#define SDL_INLINE __inline +#ifndef __inline__ +#define __inline__ __inline +#endif +#else +#define SDL_INLINE inline +#ifndef __inline__ +#define __inline__ inline +#endif +#endif +#endif /* SDL_INLINE not defined */ + +#ifndef SDL_FORCE_INLINE +#if defined(_MSC_VER) +#define SDL_FORCE_INLINE __forceinline +#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) ) +#define SDL_FORCE_INLINE __attribute__((always_inline)) static __inline__ +#else +#define SDL_FORCE_INLINE static SDL_INLINE +#endif +#endif /* SDL_FORCE_INLINE not defined */ + +/* Apparently this is needed by several Windows compilers */ +#if !defined(__MACH__) +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif /* NULL */ +#endif /* ! Mac OS X - breaks precompiled headers */ diff --git a/src/SDL_log.c b/src/SDL_log.c index bc9f954fb2c8b..9a9be86a44689 100644 --- a/src/SDL_log.c +++ b/src/SDL_log.c @@ -1,439 +1,439 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_config.h" - -#if defined(__WIN32__) || defined(__WINRT__) -#include "core/windows/SDL_windows.h" -#endif - -/* Simple log messages in SDL */ - -#include "SDL_log.h" - -#if HAVE_STDIO_H -#include -#endif - -#if defined(__ANDROID__) -#include -#endif - -#define DEFAULT_PRIORITY SDL_LOG_PRIORITY_CRITICAL -#define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN -#define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO -#define DEFAULT_TEST_PRIORITY SDL_LOG_PRIORITY_VERBOSE - -/* Forward definition of error function */ -extern int SDL_SetError(const char *fmt, ...); - -typedef struct SDL_LogLevel -{ - int category; - SDL_LogPriority priority; - struct SDL_LogLevel *next; -} SDL_LogLevel; - -/* The default log output function */ -static void SDL_LogOutput(void *userdata, - int category, SDL_LogPriority priority, - const char *message); - -static SDL_LogLevel *SDL_loglevels; -static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY; -static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY; -static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY; -static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY; -static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput; -static void *SDL_log_userdata = NULL; - -static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = { - NULL, - "VERBOSE", - "DEBUG", - "INFO", - "WARN", - "ERROR", - "CRITICAL" -}; - -#ifdef __ANDROID__ -static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = { - "APP", - "ERROR", - "SYSTEM", - "AUDIO", - "VIDEO", - "RENDER", - "INPUT" -}; - -static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = { - ANDROID_LOG_UNKNOWN, - ANDROID_LOG_VERBOSE, - ANDROID_LOG_DEBUG, - ANDROID_LOG_INFO, - ANDROID_LOG_WARN, - ANDROID_LOG_ERROR, - ANDROID_LOG_FATAL -}; -#endif /* __ANDROID__ */ - - -void -SDL_LogSetAllPriority(SDL_LogPriority priority) -{ - SDL_LogLevel *entry; - - for (entry = SDL_loglevels; entry; entry = entry->next) { - entry->priority = priority; - } - SDL_default_priority = priority; - SDL_assert_priority = priority; - SDL_application_priority = priority; -} - -void -SDL_LogSetPriority(int category, SDL_LogPriority priority) -{ - SDL_LogLevel *entry; - - for (entry = SDL_loglevels; entry; entry = entry->next) { - if (entry->category == category) { - entry->priority = priority; - return; - } - } - - /* Create a new entry */ - entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry)); - if (entry) { - entry->category = category; - entry->priority = priority; - entry->next = SDL_loglevels; - SDL_loglevels = entry; - } -} - -SDL_LogPriority -SDL_LogGetPriority(int category) -{ - SDL_LogLevel *entry; - - for (entry = SDL_loglevels; entry; entry = entry->next) { - if (entry->category == category) { - return entry->priority; - } - } - - if (category == SDL_LOG_CATEGORY_TEST) { - return SDL_test_priority; - } else if (category == SDL_LOG_CATEGORY_APPLICATION) { - return SDL_application_priority; - } else if (category == SDL_LOG_CATEGORY_ASSERT) { - return SDL_assert_priority; - } else { - return SDL_default_priority; - } -} - -void -SDL_LogResetPriorities(void) -{ - SDL_LogLevel *entry; - - while (SDL_loglevels) { - entry = SDL_loglevels; - SDL_loglevels = entry->next; - SDL_free(entry); - } - - SDL_default_priority = DEFAULT_PRIORITY; - SDL_assert_priority = DEFAULT_ASSERT_PRIORITY; - SDL_application_priority = DEFAULT_APPLICATION_PRIORITY; - SDL_test_priority = DEFAULT_TEST_PRIORITY; -} - -void -SDL_Log(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); - va_end(ap); -} - -void -SDL_LogVerbose(int category, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap); - va_end(ap); -} - -void -SDL_LogDebug(int category, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap); - va_end(ap); -} - -void -SDL_LogInfo(int category, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap); - va_end(ap); -} - -void -SDL_LogWarn(int category, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap); - va_end(ap); -} - -void -SDL_LogError(int category, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap); - va_end(ap); -} - -void -SDL_LogCritical(int category, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap); - va_end(ap); -} - -void -SDL_LogMessage(int category, SDL_LogPriority priority, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - SDL_LogMessageV(category, priority, fmt, ap); - va_end(ap); -} - -#ifdef __ANDROID__ -static const char * -GetCategoryPrefix(int category) -{ - if (category < SDL_LOG_CATEGORY_RESERVED1) { - return SDL_category_prefixes[category]; - } - if (category < SDL_LOG_CATEGORY_CUSTOM) { - return "RESERVED"; - } - return "CUSTOM"; -} -#endif /* __ANDROID__ */ - -void -SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap) -{ - char *message; - size_t len; - - /* Nothing to do if we don't have an output function */ - if (!SDL_log_function) { - return; - } - - /* Make sure we don't exceed array bounds */ - if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) { - return; - } - - /* See if we want to do anything with this message */ - if (priority < SDL_LogGetPriority(category)) { - return; - } - - message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE); - if (!message) { - return; - } - - SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap); - - /* Chop off final endline. */ - len = SDL_strlen(message); - if ((len > 0) && (message[len-1] == '\n')) { - message[--len] = '\0'; - if ((len > 0) && (message[len-1] == '\r')) { /* catch "\r\n", too. */ - message[--len] = '\0'; - } - } - - SDL_log_function(SDL_log_userdata, category, priority, message); - SDL_stack_free(message); -} - -#if defined(__WIN32__) -/* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */ -static int consoleAttached = 0; - -/* Handle to stderr output of console. */ -static HANDLE stderrHandle = NULL; -#endif - -static void -SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, - const char *message) -{ -#if defined(__WIN32__) || defined(__WINRT__) - /* Way too many allocations here, urgh */ - /* Note: One can't call SDL_SetError here, since that function itself logs. */ - { - char *output; - size_t length; - LPTSTR tstr; - -#ifndef __WINRT__ - BOOL attachResult; - DWORD attachError; - unsigned long charsWritten; - - /* Maybe attach console and get stderr handle */ - if (consoleAttached == 0) { - attachResult = AttachConsole(ATTACH_PARENT_PROCESS); - if (!attachResult) { - attachError = GetLastError(); - if (attachError == ERROR_INVALID_HANDLE) { - OutputDebugString(TEXT("Parent process has no console\r\n")); - consoleAttached = -1; - } else if (attachError == ERROR_GEN_FAILURE) { - OutputDebugString(TEXT("Could not attach to console of parent process\r\n")); - consoleAttached = -1; - } else if (attachError == ERROR_ACCESS_DENIED) { - /* Already attached */ - consoleAttached = 1; - } else { - OutputDebugString(TEXT("Error attaching console\r\n")); - consoleAttached = -1; - } - } else { - /* Newly attached */ - consoleAttached = 1; - } - - if (consoleAttached == 1) { - stderrHandle = GetStdHandle(STD_ERROR_HANDLE); - } - } -#endif /* ifndef __WINRT__ */ - - length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1; - output = SDL_stack_alloc(char, length); - SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message); - tstr = WIN_UTF8ToString(output); - - /* Output to debugger */ - OutputDebugString(tstr); - -#ifndef __WINRT__ - /* Screen output to stderr, if console was attached. */ - if (consoleAttached == 1) { - if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) { - OutputDebugString(TEXT("Error calling WriteConsole\r\n")); - } - if (charsWritten == ERROR_NOT_ENOUGH_MEMORY) { - OutputDebugString(TEXT("Insufficient heap memory to write message\r\n")); - } - } -#endif /* ifndef __WINRT__ */ - - SDL_free(tstr); - SDL_stack_free(output); - } -#elif defined(__ANDROID__) - { - char tag[32]; - - SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category)); - __android_log_write(SDL_android_priority[priority], tag, message); - } -#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA) - /* Technically we don't need SDL_VIDEO_DRIVER_COCOA, but that's where this function is defined for now. - */ - extern void SDL_NSLog(const char *text); - { - char *text; - - text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE); - if (text) { - SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message); - SDL_NSLog(text); - SDL_stack_free(text); - return; - } - } -#elif defined(__PSP__) - { - FILE* pFile; - pFile = fopen ("SDL_Log.txt", "a"); - fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message); - fclose (pFile); - } -#endif -#if HAVE_STDIO_H - fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message); -#endif -} - -void -SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata) -{ - if (callback) { - *callback = SDL_log_function; - } - if (userdata) { - *userdata = SDL_log_userdata; - } -} - -void -SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata) -{ - SDL_log_function = callback; - SDL_log_userdata = userdata; -} - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +#if defined(__WIN32__) || defined(__WINRT__) +#include "core/windows/SDL_windows.h" +#endif + +/* Simple log messages in SDL */ + +#include "SDL_log.h" + +#if HAVE_STDIO_H +#include +#endif + +#if defined(__ANDROID__) +#include +#endif + +#define DEFAULT_PRIORITY SDL_LOG_PRIORITY_CRITICAL +#define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN +#define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO +#define DEFAULT_TEST_PRIORITY SDL_LOG_PRIORITY_VERBOSE + +/* Forward definition of error function */ +extern int SDL_SetError(const char *fmt, ...); + +typedef struct SDL_LogLevel +{ + int category; + SDL_LogPriority priority; + struct SDL_LogLevel *next; +} SDL_LogLevel; + +/* The default log output function */ +static void SDL_LogOutput(void *userdata, + int category, SDL_LogPriority priority, + const char *message); + +static SDL_LogLevel *SDL_loglevels; +static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY; +static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY; +static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY; +static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY; +static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput; +static void *SDL_log_userdata = NULL; + +static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = { + NULL, + "VERBOSE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "CRITICAL" +}; + +#ifdef __ANDROID__ +static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = { + "APP", + "ERROR", + "SYSTEM", + "AUDIO", + "VIDEO", + "RENDER", + "INPUT" +}; + +static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = { + ANDROID_LOG_UNKNOWN, + ANDROID_LOG_VERBOSE, + ANDROID_LOG_DEBUG, + ANDROID_LOG_INFO, + ANDROID_LOG_WARN, + ANDROID_LOG_ERROR, + ANDROID_LOG_FATAL +}; +#endif /* __ANDROID__ */ + + +void +SDL_LogSetAllPriority(SDL_LogPriority priority) +{ + SDL_LogLevel *entry; + + for (entry = SDL_loglevels; entry; entry = entry->next) { + entry->priority = priority; + } + SDL_default_priority = priority; + SDL_assert_priority = priority; + SDL_application_priority = priority; +} + +void +SDL_LogSetPriority(int category, SDL_LogPriority priority) +{ + SDL_LogLevel *entry; + + for (entry = SDL_loglevels; entry; entry = entry->next) { + if (entry->category == category) { + entry->priority = priority; + return; + } + } + + /* Create a new entry */ + entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry)); + if (entry) { + entry->category = category; + entry->priority = priority; + entry->next = SDL_loglevels; + SDL_loglevels = entry; + } +} + +SDL_LogPriority +SDL_LogGetPriority(int category) +{ + SDL_LogLevel *entry; + + for (entry = SDL_loglevels; entry; entry = entry->next) { + if (entry->category == category) { + return entry->priority; + } + } + + if (category == SDL_LOG_CATEGORY_TEST) { + return SDL_test_priority; + } else if (category == SDL_LOG_CATEGORY_APPLICATION) { + return SDL_application_priority; + } else if (category == SDL_LOG_CATEGORY_ASSERT) { + return SDL_assert_priority; + } else { + return SDL_default_priority; + } +} + +void +SDL_LogResetPriorities(void) +{ + SDL_LogLevel *entry; + + while (SDL_loglevels) { + entry = SDL_loglevels; + SDL_loglevels = entry->next; + SDL_free(entry); + } + + SDL_default_priority = DEFAULT_PRIORITY; + SDL_assert_priority = DEFAULT_ASSERT_PRIORITY; + SDL_application_priority = DEFAULT_APPLICATION_PRIORITY; + SDL_test_priority = DEFAULT_TEST_PRIORITY; +} + +void +SDL_Log(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); + va_end(ap); +} + +void +SDL_LogVerbose(int category, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap); + va_end(ap); +} + +void +SDL_LogDebug(int category, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap); + va_end(ap); +} + +void +SDL_LogInfo(int category, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap); + va_end(ap); +} + +void +SDL_LogWarn(int category, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap); + va_end(ap); +} + +void +SDL_LogError(int category, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap); + va_end(ap); +} + +void +SDL_LogCritical(int category, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap); + va_end(ap); +} + +void +SDL_LogMessage(int category, SDL_LogPriority priority, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + SDL_LogMessageV(category, priority, fmt, ap); + va_end(ap); +} + +#ifdef __ANDROID__ +static const char * +GetCategoryPrefix(int category) +{ + if (category < SDL_LOG_CATEGORY_RESERVED1) { + return SDL_category_prefixes[category]; + } + if (category < SDL_LOG_CATEGORY_CUSTOM) { + return "RESERVED"; + } + return "CUSTOM"; +} +#endif /* __ANDROID__ */ + +void +SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap) +{ + char *message; + size_t len; + + /* Nothing to do if we don't have an output function */ + if (!SDL_log_function) { + return; + } + + /* Make sure we don't exceed array bounds */ + if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) { + return; + } + + /* See if we want to do anything with this message */ + if (priority < SDL_LogGetPriority(category)) { + return; + } + + message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE); + if (!message) { + return; + } + + SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap); + + /* Chop off final endline. */ + len = SDL_strlen(message); + if ((len > 0) && (message[len-1] == '\n')) { + message[--len] = '\0'; + if ((len > 0) && (message[len-1] == '\r')) { /* catch "\r\n", too. */ + message[--len] = '\0'; + } + } + + SDL_log_function(SDL_log_userdata, category, priority, message); + SDL_stack_free(message); +} + +#if defined(__WIN32__) +/* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */ +static int consoleAttached = 0; + +/* Handle to stderr output of console. */ +static HANDLE stderrHandle = NULL; +#endif + +static void +SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, + const char *message) +{ +#if defined(__WIN32__) || defined(__WINRT__) + /* Way too many allocations here, urgh */ + /* Note: One can't call SDL_SetError here, since that function itself logs. */ + { + char *output; + size_t length; + LPTSTR tstr; + +#ifndef __WINRT__ + BOOL attachResult; + DWORD attachError; + unsigned long charsWritten; + + /* Maybe attach console and get stderr handle */ + if (consoleAttached == 0) { + attachResult = AttachConsole(ATTACH_PARENT_PROCESS); + if (!attachResult) { + attachError = GetLastError(); + if (attachError == ERROR_INVALID_HANDLE) { + OutputDebugString(TEXT("Parent process has no console\r\n")); + consoleAttached = -1; + } else if (attachError == ERROR_GEN_FAILURE) { + OutputDebugString(TEXT("Could not attach to console of parent process\r\n")); + consoleAttached = -1; + } else if (attachError == ERROR_ACCESS_DENIED) { + /* Already attached */ + consoleAttached = 1; + } else { + OutputDebugString(TEXT("Error attaching console\r\n")); + consoleAttached = -1; + } + } else { + /* Newly attached */ + consoleAttached = 1; + } + + if (consoleAttached == 1) { + stderrHandle = GetStdHandle(STD_ERROR_HANDLE); + } + } +#endif /* ifndef __WINRT__ */ + + length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1; + output = SDL_stack_alloc(char, length); + SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message); + tstr = WIN_UTF8ToString(output); + + /* Output to debugger */ + OutputDebugString(tstr); + +#ifndef __WINRT__ + /* Screen output to stderr, if console was attached. */ + if (consoleAttached == 1) { + if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) { + OutputDebugString(TEXT("Error calling WriteConsole\r\n")); + } + if (charsWritten == ERROR_NOT_ENOUGH_MEMORY) { + OutputDebugString(TEXT("Insufficient heap memory to write message\r\n")); + } + } +#endif /* ifndef __WINRT__ */ + + SDL_free(tstr); + SDL_stack_free(output); + } +#elif defined(__ANDROID__) + { + char tag[32]; + + SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category)); + __android_log_write(SDL_android_priority[priority], tag, message); + } +#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA) + /* Technically we don't need SDL_VIDEO_DRIVER_COCOA, but that's where this function is defined for now. + */ + extern void SDL_NSLog(const char *text); + { + char *text; + + text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE); + if (text) { + SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message); + SDL_NSLog(text); + SDL_stack_free(text); + return; + } + } +#elif defined(__PSP__) + { + FILE* pFile; + pFile = fopen ("SDL_Log.txt", "a"); + fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message); + fclose (pFile); + } +#endif +#if HAVE_STDIO_H + fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message); +#endif +} + +void +SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata) +{ + if (callback) { + *callback = SDL_log_function; + } + if (userdata) { + *userdata = SDL_log_userdata; + } +} + +void +SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata) +{ + SDL_log_function = callback; + SDL_log_userdata = userdata; +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/atomic/SDL_spinlock.c b/src/atomic/SDL_spinlock.c index ac78729c78acc..b533b33f5b079 100644 --- a/src/atomic/SDL_spinlock.c +++ b/src/atomic/SDL_spinlock.c @@ -1,126 +1,126 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_config.h" - -#if defined(__WIN32__) || defined(__WINRT__) -#include "../core/windows/SDL_windows.h" -#endif - -#include "SDL_atomic.h" -#include "SDL_mutex.h" -#include "SDL_timer.h" - - -/* This function is where all the magic happens... */ -SDL_bool -SDL_AtomicTryLock(SDL_SpinLock *lock) -{ -#if SDL_ATOMIC_DISABLED - /* Terrible terrible damage */ - static SDL_mutex *_spinlock_mutex; - - if (!_spinlock_mutex) { - /* Race condition on first lock... */ - _spinlock_mutex = SDL_CreateMutex(); - } - SDL_LockMutex(_spinlock_mutex); - if (*lock == 0) { - *lock = 1; - SDL_UnlockMutex(_spinlock_mutex); - return SDL_TRUE; - } else { - SDL_UnlockMutex(_spinlock_mutex); - return SDL_FALSE; - } - -#elif defined(_MSC_VER) - SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long)); - return (InterlockedExchange((long*)lock, 1) == 0); - -#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET - return (__sync_lock_test_and_set(lock, 1) == 0); - -#elif defined(__GNUC__) && defined(__arm__) && \ - (defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \ - defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \ - defined(__ARM_ARCH_5TEJ__)) - int result; - __asm__ __volatile__ ( - "swp %0, %1, [%2]\n" - : "=&r,&r" (result) : "r,0" (1), "r,r" (lock) : "memory"); - return (result == 0); - -#elif defined(__GNUC__) && defined(__arm__) - int result; - __asm__ __volatile__ ( - "ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]" - : "=&r" (result) : "r" (1), "r" (lock) : "cc", "memory"); - return (result == 0); - -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - int result; - __asm__ __volatile__( - "lock ; xchgl %0, (%1)\n" - : "=r" (result) : "r" (lock), "0" (1) : "cc", "memory"); - return (result == 0); - -#elif defined(__MACOSX__) || defined(__IPHONEOS__) - /* Maybe used for PowerPC, but the Intel asm or gcc atomics are favored. */ - return OSAtomicCompareAndSwap32Barrier(0, 1, lock); - -#elif HAVE_PTHREAD_SPINLOCK - /* pthread instructions */ - return (pthread_spin_trylock(lock) == 0); - -#else -#error Please implement for your platform. - return SDL_FALSE; -#endif -} - -void -SDL_AtomicLock(SDL_SpinLock *lock) -{ - /* FIXME: Should we have an eventual timeout? */ - while (!SDL_AtomicTryLock(lock)) { - SDL_Delay(0); - } -} - -void -SDL_AtomicUnlock(SDL_SpinLock *lock) -{ -#if defined(_MSC_VER) - _ReadWriteBarrier(); - *lock = 0; - -#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET - __sync_lock_release(lock); - -#elif HAVE_PTHREAD_SPINLOCK - pthread_spin_unlock(lock); - -#else - *lock = 0; -#endif -} - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +#if defined(__WIN32__) || defined(__WINRT__) +#include "../core/windows/SDL_windows.h" +#endif + +#include "SDL_atomic.h" +#include "SDL_mutex.h" +#include "SDL_timer.h" + + +/* This function is where all the magic happens... */ +SDL_bool +SDL_AtomicTryLock(SDL_SpinLock *lock) +{ +#if SDL_ATOMIC_DISABLED + /* Terrible terrible damage */ + static SDL_mutex *_spinlock_mutex; + + if (!_spinlock_mutex) { + /* Race condition on first lock... */ + _spinlock_mutex = SDL_CreateMutex(); + } + SDL_LockMutex(_spinlock_mutex); + if (*lock == 0) { + *lock = 1; + SDL_UnlockMutex(_spinlock_mutex); + return SDL_TRUE; + } else { + SDL_UnlockMutex(_spinlock_mutex); + return SDL_FALSE; + } + +#elif defined(_MSC_VER) + SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long)); + return (InterlockedExchange((long*)lock, 1) == 0); + +#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET + return (__sync_lock_test_and_set(lock, 1) == 0); + +#elif defined(__GNUC__) && defined(__arm__) && \ + (defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \ + defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__)) + int result; + __asm__ __volatile__ ( + "swp %0, %1, [%2]\n" + : "=&r,&r" (result) : "r,0" (1), "r,r" (lock) : "memory"); + return (result == 0); + +#elif defined(__GNUC__) && defined(__arm__) + int result; + __asm__ __volatile__ ( + "ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]" + : "=&r" (result) : "r" (1), "r" (lock) : "cc", "memory"); + return (result == 0); + +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + int result; + __asm__ __volatile__( + "lock ; xchgl %0, (%1)\n" + : "=r" (result) : "r" (lock), "0" (1) : "cc", "memory"); + return (result == 0); + +#elif defined(__MACOSX__) || defined(__IPHONEOS__) + /* Maybe used for PowerPC, but the Intel asm or gcc atomics are favored. */ + return OSAtomicCompareAndSwap32Barrier(0, 1, lock); + +#elif HAVE_PTHREAD_SPINLOCK + /* pthread instructions */ + return (pthread_spin_trylock(lock) == 0); + +#else +#error Please implement for your platform. + return SDL_FALSE; +#endif +} + +void +SDL_AtomicLock(SDL_SpinLock *lock) +{ + /* FIXME: Should we have an eventual timeout? */ + while (!SDL_AtomicTryLock(lock)) { + SDL_Delay(0); + } +} + +void +SDL_AtomicUnlock(SDL_SpinLock *lock) +{ +#if defined(_MSC_VER) + _ReadWriteBarrier(); + *lock = 0; + +#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET + __sync_lock_release(lock); + +#elif HAVE_PTHREAD_SPINLOCK + pthread_spin_unlock(lock); + +#else + *lock = 0; +#endif +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c index e4014f9603e1b..a6792c66758b5 100644 --- a/src/audio/xaudio2/SDL_xaudio2.c +++ b/src/audio/xaudio2/SDL_xaudio2.c @@ -1,543 +1,543 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/* WinRT NOTICE: - - A few changes to SDL's XAudio2 backend were warranted by API - changes to Windows. Many, but not all of these are documented by Microsoft - at: - http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx - - 1. Windows' thread synchronization function, CreateSemaphore, was removed - from WinRT. SDL's semaphore API was substituted instead. - 2. The method calls, IXAudio2::GetDeviceCount and IXAudio2::GetDeviceDetails - were removed from the XAudio2 API. Microsoft is telling developers to - use APIs in Windows::Foundation instead. - For SDL, the missing methods were reimplemented using the APIs Microsoft - said to use. - 3. CoInitialize and CoUninitialize are not available in WinRT. - These calls were removed, as COM will have been initialized earlier, - at least by the call to the WinRT app's main function - (aka 'int main(Platform::Array^)). (DLudwig: - This was my understanding of how WinRT: the 'main' function uses - a tag of [MTAThread], which should initialize COM. My understanding - of COM is somewhat limited, and I may be incorrect here.) - 4. IXAudio2::CreateMasteringVoice changed its integer-based 'DeviceIndex' - argument to a string-based one, 'szDeviceId'. In WinRT, the - string-based argument will be used. -*/ - -#include "SDL_config.h" - -#if SDL_AUDIO_DRIVER_XAUDIO2 - -#include "../../core/windows/SDL_windows.h" -#include "SDL_audio.h" -#include "../SDL_audio_c.h" -#include "../SDL_sysaudio.h" -#include "SDL_assert.h" - -#ifdef __GNUC__ -/* The configure script already did any necessary checking */ -# define SDL_XAUDIO2_HAS_SDK 1 -#elif defined(__WINRT__) -/* WinRT always has access to the .the XAudio 2 SDK */ -# define SDL_XAUDIO2_HAS_SDK -#else -/* XAudio2 exists as of the March 2008 DirectX SDK - The XAudio2 implementation available in the Windows 8 SDK targets Windows 8 and newer. - If you want to build SDL with XAudio2 support you should install the DirectX SDK. - */ -#include -#if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284)) -# pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.") -#else -# define SDL_XAUDIO2_HAS_SDK 1 -#endif -#endif - -#ifdef SDL_XAUDIO2_HAS_SDK - -/* Check to see if we're compiling for XAudio 2.8, or higher. */ -#ifdef WINVER -#if WINVER >= 0x0602 /* Windows 8 SDK or higher? */ -#define SDL_XAUDIO2_WIN8 1 -#endif -#endif - -/* The XAudio header file, when #include'd on WinRT, will only compile in C++ - files, but not C. A few preprocessor-based hacks are defined below in order - to get xaudio2.h to compile in the C/non-C++ file, SDL_xaudio2.c. - */ -#ifdef __WINRT__ -#define uuid(x) -#define DX_BUILD -#endif - -#define INITGUID 1 -#include - -/* Hidden "this" pointer for the audio functions */ -#define _THIS SDL_AudioDevice *this - -#ifdef __WINRT__ -#include "SDL_xaudio2_winrthelpers.h" -#endif - -/* Fixes bug 1210 where some versions of gcc need named parameters */ -#ifdef __GNUC__ -#ifdef THIS -#undef THIS -#endif -#define THIS INTERFACE *p -#ifdef THIS_ -#undef THIS_ -#endif -#define THIS_ INTERFACE *p, -#endif - -struct SDL_PrivateAudioData -{ - IXAudio2 *ixa2; - IXAudio2SourceVoice *source; - IXAudio2MasteringVoice *mastering; - SDL_sem * semaphore; - Uint8 *mixbuf; - int mixlen; - Uint8 *nextbuf; -}; - - -static void -XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) -{ - IXAudio2 *ixa2 = NULL; - UINT32 devcount = 0; - UINT32 i = 0; - - if (iscapture) { - SDL_SetError("XAudio2: capture devices unsupported."); - return; - } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { - SDL_SetError("XAudio2: XAudio2Create() failed at detection."); - return; - } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { - SDL_SetError("XAudio2: IXAudio2::GetDeviceCount() failed."); - IXAudio2_Release(ixa2); - return; - } - - for (i = 0; i < devcount; i++) { - XAUDIO2_DEVICE_DETAILS details; - if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { - char *str = WIN_StringToUTF8(details.DisplayName); - if (str != NULL) { - addfn(str); - SDL_free(str); /* addfn() made a copy of the string. */ - } - } - } - - IXAudio2_Release(ixa2); -} - -static void STDMETHODCALLTYPE -VoiceCBOnBufferEnd(THIS_ void *data) -{ - /* Just signal the SDL audio thread and get out of XAudio2's way. */ - SDL_AudioDevice *this = (SDL_AudioDevice *) data; - SDL_SemPost(this->hidden->semaphore); -} - -static void STDMETHODCALLTYPE -VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error) -{ - /* !!! FIXME: attempt to recover, or mark device disconnected. */ - SDL_assert(0 && "write me!"); -} - -/* no-op callbacks... */ -static void STDMETHODCALLTYPE VoiceCBOnStreamEnd(THIS) {} -static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassStart(THIS_ UINT32 b) {} -static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassEnd(THIS) {} -static void STDMETHODCALLTYPE VoiceCBOnBufferStart(THIS_ void *data) {} -static void STDMETHODCALLTYPE VoiceCBOnLoopEnd(THIS_ void *data) {} - - -static Uint8 * -XAUDIO2_GetDeviceBuf(_THIS) -{ - return this->hidden->nextbuf; -} - -static void -XAUDIO2_PlayDevice(_THIS) -{ - XAUDIO2_BUFFER buffer; - Uint8 *mixbuf = this->hidden->mixbuf; - Uint8 *nextbuf = this->hidden->nextbuf; - const int mixlen = this->hidden->mixlen; - IXAudio2SourceVoice *source = this->hidden->source; - HRESULT result = S_OK; - - if (!this->enabled) { /* shutting down? */ - return; - } - - /* Submit the next filled buffer */ - SDL_zero(buffer); - buffer.AudioBytes = mixlen; - buffer.pAudioData = nextbuf; - buffer.pContext = this; - - if (nextbuf == mixbuf) { - nextbuf += mixlen; - } else { - nextbuf = mixbuf; - } - this->hidden->nextbuf = nextbuf; - - result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL); - if (result == XAUDIO2_E_DEVICE_INVALIDATED) { - /* !!! FIXME: possibly disconnected or temporary lost. Recover? */ - } - - if (result != S_OK) { /* uhoh, panic! */ - IXAudio2SourceVoice_FlushSourceBuffers(source); - this->enabled = 0; - } -} - -static void -XAUDIO2_WaitDevice(_THIS) -{ - if (this->enabled) { - SDL_SemWait(this->hidden->semaphore); - } -} - -static void -XAUDIO2_WaitDone(_THIS) -{ - IXAudio2SourceVoice *source = this->hidden->source; - XAUDIO2_VOICE_STATE state; - SDL_assert(!this->enabled); /* flag that stops playing. */ - IXAudio2SourceVoice_Discontinuity(source); -#if SDL_XAUDIO2_WIN8 - IXAudio2SourceVoice_GetState(source, &state, 0); -#else - IXAudio2SourceVoice_GetState(source, &state); -#endif - while (state.BuffersQueued > 0) { - SDL_SemWait(this->hidden->semaphore); -#if SDL_XAUDIO2_WIN8 - IXAudio2SourceVoice_GetState(source, &state, 0); -#else - IXAudio2SourceVoice_GetState(source, &state); -#endif - } -} - - -static void -XAUDIO2_CloseDevice(_THIS) -{ - if (this->hidden != NULL) { - IXAudio2 *ixa2 = this->hidden->ixa2; - IXAudio2SourceVoice *source = this->hidden->source; - IXAudio2MasteringVoice *mastering = this->hidden->mastering; - - if (source != NULL) { - IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW); - IXAudio2SourceVoice_FlushSourceBuffers(source); - IXAudio2SourceVoice_DestroyVoice(source); - } - if (ixa2 != NULL) { - IXAudio2_StopEngine(ixa2); - } - if (mastering != NULL) { - IXAudio2MasteringVoice_DestroyVoice(mastering); - } - if (ixa2 != NULL) { - IXAudio2_Release(ixa2); - } - SDL_free(this->hidden->mixbuf); - if (this->hidden->semaphore != NULL) { - SDL_DestroySemaphore(this->hidden->semaphore); - } - - SDL_free(this->hidden); - this->hidden = NULL; - } -} - -static int -XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) -{ - HRESULT result = S_OK; - WAVEFORMATEX waveformat; - int valid_format = 0; - SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); - IXAudio2 *ixa2 = NULL; - IXAudio2SourceVoice *source = NULL; -#if defined(SDL_XAUDIO2_WIN8) - LPCWSTR devId = NULL; -#else - UINT32 devId = 0; /* 0 == system default device. */ -#endif - - static IXAudio2VoiceCallbackVtbl callbacks_vtable = { - VoiceCBOnVoiceProcessPassStart, - VoiceCBOnVoiceProcessPassEnd, - VoiceCBOnStreamEnd, - VoiceCBOnBufferStart, - VoiceCBOnBufferEnd, - VoiceCBOnLoopEnd, - VoiceCBOnVoiceError - }; - - static IXAudio2VoiceCallback callbacks = { &callbacks_vtable }; - - if (iscapture) { - return SDL_SetError("XAudio2: capture devices unsupported."); - } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { - return SDL_SetError("XAudio2: XAudio2Create() failed at open."); - } - - /* - XAUDIO2_DEBUG_CONFIGURATION debugConfig; - debugConfig.TraceMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL | XAUDIO2_LOG_FUNC_CALLS | XAUDIO2_LOG_TIMING | XAUDIO2_LOG_LOCKS | XAUDIO2_LOG_MEMORY | XAUDIO2_LOG_STREAMING; - debugConfig.BreakMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS; - debugConfig.LogThreadID = TRUE; - debugConfig.LogFileline = TRUE; - debugConfig.LogFunctionName = TRUE; - debugConfig.LogTiming = TRUE; - ixa2->SetDebugConfiguration(&debugConfig); - */ - -#if ! defined(__WINRT__) - if (devname != NULL) { - UINT32 devcount = 0; - UINT32 i = 0; - - if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { - IXAudio2_Release(ixa2); - return SDL_SetError("XAudio2: IXAudio2_GetDeviceCount() failed."); - } - for (i = 0; i < devcount; i++) { - XAUDIO2_DEVICE_DETAILS details; - if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { - char *str = WIN_StringToUTF8(details.DisplayName); - if (str != NULL) { - const int match = (SDL_strcmp(str, devname) == 0); - SDL_free(str); - if (match) { - devId = i; - break; - } - } - } - } - - if (i == devcount) { - IXAudio2_Release(ixa2); - return SDL_SetError("XAudio2: Requested device not found."); - } - } -#endif - - /* Initialize all variables that we clean on shutdown */ - this->hidden = (struct SDL_PrivateAudioData *) - SDL_malloc((sizeof *this->hidden)); - if (this->hidden == NULL) { - IXAudio2_Release(ixa2); - return SDL_OutOfMemory(); - } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); - - this->hidden->ixa2 = ixa2; - this->hidden->semaphore = SDL_CreateSemaphore(1); - if (this->hidden->semaphore == NULL) { - XAUDIO2_CloseDevice(this); - return SDL_SetError("XAudio2: CreateSemaphore() failed!"); - } - - while ((!valid_format) && (test_format)) { - switch (test_format) { - case AUDIO_U8: - case AUDIO_S16: - case AUDIO_S32: - case AUDIO_F32: - this->spec.format = test_format; - valid_format = 1; - break; - } - test_format = SDL_NextAudioFormat(); - } - - if (!valid_format) { - XAUDIO2_CloseDevice(this); - return SDL_SetError("XAudio2: Unsupported audio format"); - } - - /* Update the fragment size as size in bytes */ - SDL_CalculateAudioSpec(&this->spec); - - /* We feed a Source, it feeds the Mastering, which feeds the device. */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - XAUDIO2_CloseDevice(this); - return SDL_OutOfMemory(); - } - this->hidden->nextbuf = this->hidden->mixbuf; - SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen); - - /* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On - Xbox360, this means 5.1 output, but on Windows, it means "figure out - what the system has." It might be preferable to let XAudio2 blast - stereo output to appropriate surround sound configurations - instead of clamping to 2 channels, even though we'll configure the - Source Voice for whatever number of channels you supply. */ -#if SDL_XAUDIO2_WIN8 - result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering, - XAUDIO2_DEFAULT_CHANNELS, - this->spec.freq, 0, devId, NULL, AudioCategory_GameEffects); -#else - result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering, - XAUDIO2_DEFAULT_CHANNELS, - this->spec.freq, 0, devId, NULL); -#endif - if (result != S_OK) { - XAUDIO2_CloseDevice(this); - return SDL_SetError("XAudio2: Couldn't create mastering voice"); - } - - SDL_zero(waveformat); - if (SDL_AUDIO_ISFLOAT(this->spec.format)) { - waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - } else { - waveformat.wFormatTag = WAVE_FORMAT_PCM; - } - waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format); - waveformat.nChannels = this->spec.channels; - waveformat.nSamplesPerSec = this->spec.freq; - waveformat.nBlockAlign = - waveformat.nChannels * (waveformat.wBitsPerSample / 8); - waveformat.nAvgBytesPerSec = - waveformat.nSamplesPerSec * waveformat.nBlockAlign; - waveformat.cbSize = sizeof(waveformat); - -#ifdef __WINRT__ - // DLudwig: for now, make XAudio2 do sample rate conversion, just to - // get the loopwave test to work. - // - // TODO, WinRT: consider removing WinRT-specific source-voice creation code from SDL_xaudio2.c - result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat, - 0, - 1.0f, &callbacks, NULL, NULL); -#else - result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat, - XAUDIO2_VOICE_NOSRC | - XAUDIO2_VOICE_NOPITCH, - 1.0f, &callbacks, NULL, NULL); - -#endif - if (result != S_OK) { - XAUDIO2_CloseDevice(this); - return SDL_SetError("XAudio2: Couldn't create source voice"); - } - this->hidden->source = source; - - /* Start everything playing! */ - result = IXAudio2_StartEngine(ixa2); - if (result != S_OK) { - XAUDIO2_CloseDevice(this); - return SDL_SetError("XAudio2: Couldn't start engine"); - } - - result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW); - if (result != S_OK) { - XAUDIO2_CloseDevice(this); - return SDL_SetError("XAudio2: Couldn't start source voice"); - } - - return 0; /* good to go. */ -} - -static void -XAUDIO2_Deinitialize(void) -{ -#if defined(__WIN32__) - WIN_CoUninitialize(); -#endif -} - -#endif /* SDL_XAUDIO2_HAS_SDK */ - - -static int -XAUDIO2_Init(SDL_AudioDriverImpl * impl) -{ -#ifndef SDL_XAUDIO2_HAS_SDK - SDL_SetError("XAudio2: SDL was built without XAudio2 support (old DirectX SDK)."); - return 0; /* no XAudio2 support, ever. Update your SDK! */ -#else - /* XAudio2Create() is a macro that uses COM; we don't load the .dll */ - IXAudio2 *ixa2 = NULL; -#if defined(__WIN32__) - // TODO, WinRT: Investigate using CoInitializeEx here - if (FAILED(WIN_CoInitialize())) { - SDL_SetError("XAudio2: CoInitialize() failed"); - return 0; - } -#endif - - if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { -#if defined(__WIN32__) - WIN_CoUninitialize(); -#endif - SDL_SetError("XAudio2: XAudio2Create() failed at initialization"); - return 0; /* not available. */ - } - IXAudio2_Release(ixa2); - - /* Set the function pointers */ - impl->DetectDevices = XAUDIO2_DetectDevices; - impl->OpenDevice = XAUDIO2_OpenDevice; - impl->PlayDevice = XAUDIO2_PlayDevice; - impl->WaitDevice = XAUDIO2_WaitDevice; - impl->WaitDone = XAUDIO2_WaitDone; - impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf; - impl->CloseDevice = XAUDIO2_CloseDevice; - impl->Deinitialize = XAUDIO2_Deinitialize; - - return 1; /* this audio target is available. */ -#endif -} - -AudioBootStrap XAUDIO2_bootstrap = { - "xaudio2", "XAudio2", XAUDIO2_Init, 0 -}; - -#endif /* SDL_AUDIO_DRIVER_XAUDIO2 */ - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* WinRT NOTICE: + + A few changes to SDL's XAudio2 backend were warranted by API + changes to Windows. Many, but not all of these are documented by Microsoft + at: + http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx + + 1. Windows' thread synchronization function, CreateSemaphore, was removed + from WinRT. SDL's semaphore API was substituted instead. + 2. The method calls, IXAudio2::GetDeviceCount and IXAudio2::GetDeviceDetails + were removed from the XAudio2 API. Microsoft is telling developers to + use APIs in Windows::Foundation instead. + For SDL, the missing methods were reimplemented using the APIs Microsoft + said to use. + 3. CoInitialize and CoUninitialize are not available in WinRT. + These calls were removed, as COM will have been initialized earlier, + at least by the call to the WinRT app's main function + (aka 'int main(Platform::Array^)). (DLudwig: + This was my understanding of how WinRT: the 'main' function uses + a tag of [MTAThread], which should initialize COM. My understanding + of COM is somewhat limited, and I may be incorrect here.) + 4. IXAudio2::CreateMasteringVoice changed its integer-based 'DeviceIndex' + argument to a string-based one, 'szDeviceId'. In WinRT, the + string-based argument will be used. +*/ + +#include "SDL_config.h" + +#if SDL_AUDIO_DRIVER_XAUDIO2 + +#include "../../core/windows/SDL_windows.h" +#include "SDL_audio.h" +#include "../SDL_audio_c.h" +#include "../SDL_sysaudio.h" +#include "SDL_assert.h" + +#ifdef __GNUC__ +/* The configure script already did any necessary checking */ +# define SDL_XAUDIO2_HAS_SDK 1 +#elif defined(__WINRT__) +/* WinRT always has access to the .the XAudio 2 SDK */ +# define SDL_XAUDIO2_HAS_SDK +#else +/* XAudio2 exists as of the March 2008 DirectX SDK + The XAudio2 implementation available in the Windows 8 SDK targets Windows 8 and newer. + If you want to build SDL with XAudio2 support you should install the DirectX SDK. + */ +#include +#if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284)) +# pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.") +#else +# define SDL_XAUDIO2_HAS_SDK 1 +#endif +#endif + +#ifdef SDL_XAUDIO2_HAS_SDK + +/* Check to see if we're compiling for XAudio 2.8, or higher. */ +#ifdef WINVER +#if WINVER >= 0x0602 /* Windows 8 SDK or higher? */ +#define SDL_XAUDIO2_WIN8 1 +#endif +#endif + +/* The XAudio header file, when #include'd on WinRT, will only compile in C++ + files, but not C. A few preprocessor-based hacks are defined below in order + to get xaudio2.h to compile in the C/non-C++ file, SDL_xaudio2.c. + */ +#ifdef __WINRT__ +#define uuid(x) +#define DX_BUILD +#endif + +#define INITGUID 1 +#include + +/* Hidden "this" pointer for the audio functions */ +#define _THIS SDL_AudioDevice *this + +#ifdef __WINRT__ +#include "SDL_xaudio2_winrthelpers.h" +#endif + +/* Fixes bug 1210 where some versions of gcc need named parameters */ +#ifdef __GNUC__ +#ifdef THIS +#undef THIS +#endif +#define THIS INTERFACE *p +#ifdef THIS_ +#undef THIS_ +#endif +#define THIS_ INTERFACE *p, +#endif + +struct SDL_PrivateAudioData +{ + IXAudio2 *ixa2; + IXAudio2SourceVoice *source; + IXAudio2MasteringVoice *mastering; + SDL_sem * semaphore; + Uint8 *mixbuf; + int mixlen; + Uint8 *nextbuf; +}; + + +static void +XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +{ + IXAudio2 *ixa2 = NULL; + UINT32 devcount = 0; + UINT32 i = 0; + + if (iscapture) { + SDL_SetError("XAudio2: capture devices unsupported."); + return; + } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { + SDL_SetError("XAudio2: XAudio2Create() failed at detection."); + return; + } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { + SDL_SetError("XAudio2: IXAudio2::GetDeviceCount() failed."); + IXAudio2_Release(ixa2); + return; + } + + for (i = 0; i < devcount; i++) { + XAUDIO2_DEVICE_DETAILS details; + if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { + char *str = WIN_StringToUTF8(details.DisplayName); + if (str != NULL) { + addfn(str); + SDL_free(str); /* addfn() made a copy of the string. */ + } + } + } + + IXAudio2_Release(ixa2); +} + +static void STDMETHODCALLTYPE +VoiceCBOnBufferEnd(THIS_ void *data) +{ + /* Just signal the SDL audio thread and get out of XAudio2's way. */ + SDL_AudioDevice *this = (SDL_AudioDevice *) data; + SDL_SemPost(this->hidden->semaphore); +} + +static void STDMETHODCALLTYPE +VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error) +{ + /* !!! FIXME: attempt to recover, or mark device disconnected. */ + SDL_assert(0 && "write me!"); +} + +/* no-op callbacks... */ +static void STDMETHODCALLTYPE VoiceCBOnStreamEnd(THIS) {} +static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassStart(THIS_ UINT32 b) {} +static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassEnd(THIS) {} +static void STDMETHODCALLTYPE VoiceCBOnBufferStart(THIS_ void *data) {} +static void STDMETHODCALLTYPE VoiceCBOnLoopEnd(THIS_ void *data) {} + + +static Uint8 * +XAUDIO2_GetDeviceBuf(_THIS) +{ + return this->hidden->nextbuf; +} + +static void +XAUDIO2_PlayDevice(_THIS) +{ + XAUDIO2_BUFFER buffer; + Uint8 *mixbuf = this->hidden->mixbuf; + Uint8 *nextbuf = this->hidden->nextbuf; + const int mixlen = this->hidden->mixlen; + IXAudio2SourceVoice *source = this->hidden->source; + HRESULT result = S_OK; + + if (!this->enabled) { /* shutting down? */ + return; + } + + /* Submit the next filled buffer */ + SDL_zero(buffer); + buffer.AudioBytes = mixlen; + buffer.pAudioData = nextbuf; + buffer.pContext = this; + + if (nextbuf == mixbuf) { + nextbuf += mixlen; + } else { + nextbuf = mixbuf; + } + this->hidden->nextbuf = nextbuf; + + result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL); + if (result == XAUDIO2_E_DEVICE_INVALIDATED) { + /* !!! FIXME: possibly disconnected or temporary lost. Recover? */ + } + + if (result != S_OK) { /* uhoh, panic! */ + IXAudio2SourceVoice_FlushSourceBuffers(source); + this->enabled = 0; + } +} + +static void +XAUDIO2_WaitDevice(_THIS) +{ + if (this->enabled) { + SDL_SemWait(this->hidden->semaphore); + } +} + +static void +XAUDIO2_WaitDone(_THIS) +{ + IXAudio2SourceVoice *source = this->hidden->source; + XAUDIO2_VOICE_STATE state; + SDL_assert(!this->enabled); /* flag that stops playing. */ + IXAudio2SourceVoice_Discontinuity(source); +#if SDL_XAUDIO2_WIN8 + IXAudio2SourceVoice_GetState(source, &state, 0); +#else + IXAudio2SourceVoice_GetState(source, &state); +#endif + while (state.BuffersQueued > 0) { + SDL_SemWait(this->hidden->semaphore); +#if SDL_XAUDIO2_WIN8 + IXAudio2SourceVoice_GetState(source, &state, 0); +#else + IXAudio2SourceVoice_GetState(source, &state); +#endif + } +} + + +static void +XAUDIO2_CloseDevice(_THIS) +{ + if (this->hidden != NULL) { + IXAudio2 *ixa2 = this->hidden->ixa2; + IXAudio2SourceVoice *source = this->hidden->source; + IXAudio2MasteringVoice *mastering = this->hidden->mastering; + + if (source != NULL) { + IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(source); + IXAudio2SourceVoice_DestroyVoice(source); + } + if (ixa2 != NULL) { + IXAudio2_StopEngine(ixa2); + } + if (mastering != NULL) { + IXAudio2MasteringVoice_DestroyVoice(mastering); + } + if (ixa2 != NULL) { + IXAudio2_Release(ixa2); + } + SDL_free(this->hidden->mixbuf); + if (this->hidden->semaphore != NULL) { + SDL_DestroySemaphore(this->hidden->semaphore); + } + + SDL_free(this->hidden); + this->hidden = NULL; + } +} + +static int +XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) +{ + HRESULT result = S_OK; + WAVEFORMATEX waveformat; + int valid_format = 0; + SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); + IXAudio2 *ixa2 = NULL; + IXAudio2SourceVoice *source = NULL; +#if defined(SDL_XAUDIO2_WIN8) + LPCWSTR devId = NULL; +#else + UINT32 devId = 0; /* 0 == system default device. */ +#endif + + static IXAudio2VoiceCallbackVtbl callbacks_vtable = { + VoiceCBOnVoiceProcessPassStart, + VoiceCBOnVoiceProcessPassEnd, + VoiceCBOnStreamEnd, + VoiceCBOnBufferStart, + VoiceCBOnBufferEnd, + VoiceCBOnLoopEnd, + VoiceCBOnVoiceError + }; + + static IXAudio2VoiceCallback callbacks = { &callbacks_vtable }; + + if (iscapture) { + return SDL_SetError("XAudio2: capture devices unsupported."); + } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { + return SDL_SetError("XAudio2: XAudio2Create() failed at open."); + } + + /* + XAUDIO2_DEBUG_CONFIGURATION debugConfig; + debugConfig.TraceMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL | XAUDIO2_LOG_FUNC_CALLS | XAUDIO2_LOG_TIMING | XAUDIO2_LOG_LOCKS | XAUDIO2_LOG_MEMORY | XAUDIO2_LOG_STREAMING; + debugConfig.BreakMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS; + debugConfig.LogThreadID = TRUE; + debugConfig.LogFileline = TRUE; + debugConfig.LogFunctionName = TRUE; + debugConfig.LogTiming = TRUE; + ixa2->SetDebugConfiguration(&debugConfig); + */ + +#if ! defined(__WINRT__) + if (devname != NULL) { + UINT32 devcount = 0; + UINT32 i = 0; + + if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { + IXAudio2_Release(ixa2); + return SDL_SetError("XAudio2: IXAudio2_GetDeviceCount() failed."); + } + for (i = 0; i < devcount; i++) { + XAUDIO2_DEVICE_DETAILS details; + if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { + char *str = WIN_StringToUTF8(details.DisplayName); + if (str != NULL) { + const int match = (SDL_strcmp(str, devname) == 0); + SDL_free(str); + if (match) { + devId = i; + break; + } + } + } + } + + if (i == devcount) { + IXAudio2_Release(ixa2); + return SDL_SetError("XAudio2: Requested device not found."); + } + } +#endif + + /* Initialize all variables that we clean on shutdown */ + this->hidden = (struct SDL_PrivateAudioData *) + SDL_malloc((sizeof *this->hidden)); + if (this->hidden == NULL) { + IXAudio2_Release(ixa2); + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + + this->hidden->ixa2 = ixa2; + this->hidden->semaphore = SDL_CreateSemaphore(1); + if (this->hidden->semaphore == NULL) { + XAUDIO2_CloseDevice(this); + return SDL_SetError("XAudio2: CreateSemaphore() failed!"); + } + + while ((!valid_format) && (test_format)) { + switch (test_format) { + case AUDIO_U8: + case AUDIO_S16: + case AUDIO_S32: + case AUDIO_F32: + this->spec.format = test_format; + valid_format = 1; + break; + } + test_format = SDL_NextAudioFormat(); + } + + if (!valid_format) { + XAUDIO2_CloseDevice(this); + return SDL_SetError("XAudio2: Unsupported audio format"); + } + + /* Update the fragment size as size in bytes */ + SDL_CalculateAudioSpec(&this->spec); + + /* We feed a Source, it feeds the Mastering, which feeds the device. */ + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + XAUDIO2_CloseDevice(this); + return SDL_OutOfMemory(); + } + this->hidden->nextbuf = this->hidden->mixbuf; + SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen); + + /* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On + Xbox360, this means 5.1 output, but on Windows, it means "figure out + what the system has." It might be preferable to let XAudio2 blast + stereo output to appropriate surround sound configurations + instead of clamping to 2 channels, even though we'll configure the + Source Voice for whatever number of channels you supply. */ +#if SDL_XAUDIO2_WIN8 + result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering, + XAUDIO2_DEFAULT_CHANNELS, + this->spec.freq, 0, devId, NULL, AudioCategory_GameEffects); +#else + result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering, + XAUDIO2_DEFAULT_CHANNELS, + this->spec.freq, 0, devId, NULL); +#endif + if (result != S_OK) { + XAUDIO2_CloseDevice(this); + return SDL_SetError("XAudio2: Couldn't create mastering voice"); + } + + SDL_zero(waveformat); + if (SDL_AUDIO_ISFLOAT(this->spec.format)) { + waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + } else { + waveformat.wFormatTag = WAVE_FORMAT_PCM; + } + waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format); + waveformat.nChannels = this->spec.channels; + waveformat.nSamplesPerSec = this->spec.freq; + waveformat.nBlockAlign = + waveformat.nChannels * (waveformat.wBitsPerSample / 8); + waveformat.nAvgBytesPerSec = + waveformat.nSamplesPerSec * waveformat.nBlockAlign; + waveformat.cbSize = sizeof(waveformat); + +#ifdef __WINRT__ + // DLudwig: for now, make XAudio2 do sample rate conversion, just to + // get the loopwave test to work. + // + // TODO, WinRT: consider removing WinRT-specific source-voice creation code from SDL_xaudio2.c + result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat, + 0, + 1.0f, &callbacks, NULL, NULL); +#else + result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat, + XAUDIO2_VOICE_NOSRC | + XAUDIO2_VOICE_NOPITCH, + 1.0f, &callbacks, NULL, NULL); + +#endif + if (result != S_OK) { + XAUDIO2_CloseDevice(this); + return SDL_SetError("XAudio2: Couldn't create source voice"); + } + this->hidden->source = source; + + /* Start everything playing! */ + result = IXAudio2_StartEngine(ixa2); + if (result != S_OK) { + XAUDIO2_CloseDevice(this); + return SDL_SetError("XAudio2: Couldn't start engine"); + } + + result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW); + if (result != S_OK) { + XAUDIO2_CloseDevice(this); + return SDL_SetError("XAudio2: Couldn't start source voice"); + } + + return 0; /* good to go. */ +} + +static void +XAUDIO2_Deinitialize(void) +{ +#if defined(__WIN32__) + WIN_CoUninitialize(); +#endif +} + +#endif /* SDL_XAUDIO2_HAS_SDK */ + + +static int +XAUDIO2_Init(SDL_AudioDriverImpl * impl) +{ +#ifndef SDL_XAUDIO2_HAS_SDK + SDL_SetError("XAudio2: SDL was built without XAudio2 support (old DirectX SDK)."); + return 0; /* no XAudio2 support, ever. Update your SDK! */ +#else + /* XAudio2Create() is a macro that uses COM; we don't load the .dll */ + IXAudio2 *ixa2 = NULL; +#if defined(__WIN32__) + // TODO, WinRT: Investigate using CoInitializeEx here + if (FAILED(WIN_CoInitialize())) { + SDL_SetError("XAudio2: CoInitialize() failed"); + return 0; + } +#endif + + if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { +#if defined(__WIN32__) + WIN_CoUninitialize(); +#endif + SDL_SetError("XAudio2: XAudio2Create() failed at initialization"); + return 0; /* not available. */ + } + IXAudio2_Release(ixa2); + + /* Set the function pointers */ + impl->DetectDevices = XAUDIO2_DetectDevices; + impl->OpenDevice = XAUDIO2_OpenDevice; + impl->PlayDevice = XAUDIO2_PlayDevice; + impl->WaitDevice = XAUDIO2_WaitDevice; + impl->WaitDone = XAUDIO2_WaitDone; + impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf; + impl->CloseDevice = XAUDIO2_CloseDevice; + impl->Deinitialize = XAUDIO2_Deinitialize; + + return 1; /* this audio target is available. */ +#endif +} + +AudioBootStrap XAUDIO2_bootstrap = { + "xaudio2", "XAudio2", XAUDIO2_Init, 0 +}; + +#endif /* SDL_AUDIO_DRIVER_XAUDIO2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp index 9c0fe0ed76562..b27ee59b68b42 100644 --- a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp +++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp @@ -1,69 +1,69 @@ - -#include -#include "SDL_xaudio2_winrthelpers.h" - -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP -using Windows::Devices::Enumeration::DeviceClass; -using Windows::Devices::Enumeration::DeviceInformation; -using Windows::Devices::Enumeration::DeviceInformationCollection; -#endif - -extern "C" HRESULT __cdecl IXAudio2_GetDeviceCount(IXAudio2 * ixa2, UINT32 * devcount) -{ -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - // There doesn't seem to be any audio device enumeration on Windows Phone. - // In lieu of this, just treat things as if there is one and only one - // audio device. - *devcount = 1; - return S_OK; -#else - // TODO, WinRT: make xaudio2 device enumeration only happen once, and in the background - auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender); - while (operation->Status != Windows::Foundation::AsyncStatus::Completed) - { - } - - DeviceInformationCollection^ devices = operation->GetResults(); - *devcount = devices->Size; - return S_OK; -#endif -} - -extern "C" HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details) -{ -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - // Windows Phone doesn't seem to have the same device enumeration APIs that - // Windows 8/RT has, or it doesn't have them at all. In lieu of this, - // just treat things as if there is one, and only one, default device. - if (index != 0) - { - return XAUDIO2_E_INVALID_CALL; - } - - if (details) - { - wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), L"default", _TRUNCATE); - wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), L"default", _TRUNCATE); - } - return S_OK; -#else - auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender); - while (operation->Status != Windows::Foundation::AsyncStatus::Completed) - { - } - - DeviceInformationCollection^ devices = operation->GetResults(); - if (index >= devices->Size) - { - return XAUDIO2_E_INVALID_CALL; - } - - DeviceInformation^ d = devices->GetAt(index); - if (details) - { - wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), d->Id->Data(), _TRUNCATE); - wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), d->Name->Data(), _TRUNCATE); - } - return S_OK; -#endif -} + +#include +#include "SDL_xaudio2_winrthelpers.h" + +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP +using Windows::Devices::Enumeration::DeviceClass; +using Windows::Devices::Enumeration::DeviceInformation; +using Windows::Devices::Enumeration::DeviceInformationCollection; +#endif + +extern "C" HRESULT __cdecl IXAudio2_GetDeviceCount(IXAudio2 * ixa2, UINT32 * devcount) +{ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // There doesn't seem to be any audio device enumeration on Windows Phone. + // In lieu of this, just treat things as if there is one and only one + // audio device. + *devcount = 1; + return S_OK; +#else + // TODO, WinRT: make xaudio2 device enumeration only happen once, and in the background + auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender); + while (operation->Status != Windows::Foundation::AsyncStatus::Completed) + { + } + + DeviceInformationCollection^ devices = operation->GetResults(); + *devcount = devices->Size; + return S_OK; +#endif +} + +extern "C" HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details) +{ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // Windows Phone doesn't seem to have the same device enumeration APIs that + // Windows 8/RT has, or it doesn't have them at all. In lieu of this, + // just treat things as if there is one, and only one, default device. + if (index != 0) + { + return XAUDIO2_E_INVALID_CALL; + } + + if (details) + { + wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), L"default", _TRUNCATE); + wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), L"default", _TRUNCATE); + } + return S_OK; +#else + auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender); + while (operation->Status != Windows::Foundation::AsyncStatus::Completed) + { + } + + DeviceInformationCollection^ devices = operation->GetResults(); + if (index >= devices->Size) + { + return XAUDIO2_E_INVALID_CALL; + } + + DeviceInformation^ d = devices->GetAt(index); + if (details) + { + wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), d->Id->Data(), _TRUNCATE); + wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), d->Name->Data(), _TRUNCATE); + } + return S_OK; +#endif +} diff --git a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h index ee5afcd45851d..0beaf8d1f12f4 100644 --- a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h +++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h @@ -1,52 +1,52 @@ - -#pragma once - -// -// Re-implementation of methods removed from XAudio2 (in WinRT): -// - -typedef struct XAUDIO2_DEVICE_DETAILS -{ - WCHAR DeviceID[256]; - WCHAR DisplayName[256]; - /* Other fields exist in the pre-Windows 8 version of this struct, however - they weren't used by SDL, so they weren't added. - */ -} XAUDIO2_DEVICE_DETAILS; - - -#ifdef __cplusplus -extern "C" { -#endif - -HRESULT IXAudio2_GetDeviceCount(IXAudio2 * unused, UINT32 * devcount); -HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details); - -#ifdef __cplusplus -} -#endif - - -// -// C-style macros to call XAudio2's methods in C++: -// -#ifdef __cplusplus -/* -#define IXAudio2_CreateMasteringVoice(A, B, C, D, E, F, G) (A)->CreateMasteringVoice((B), (C), (D), (E), (F), (G)) -#define IXAudio2_CreateSourceVoice(A, B, C, D, E, F, G, H) (A)->CreateSourceVoice((B), (C), (D), (E), (F), (G), (H)) -#define IXAudio2_QueryInterface(A, B, C) (A)->QueryInterface((B), (C)) -#define IXAudio2_Release(A) (A)->Release() -#define IXAudio2_StartEngine(A) (A)->StartEngine() -#define IXAudio2_StopEngine(A) (A)->StopEngine() - -#define IXAudio2MasteringVoice_DestroyVoice(A) (A)->DestroyVoice() - -#define IXAudio2SourceVoice_DestroyVoice(A) (A)->DestroyVoice() -#define IXAudio2SourceVoice_Discontinuity(A) (A)->Discontinuity() -#define IXAudio2SourceVoice_FlushSourceBuffers(A) (A)->FlushSourceBuffers() -#define IXAudio2SourceVoice_GetState(A, B) (A)->GetState((B)) -#define IXAudio2SourceVoice_Start(A, B, C) (A)->Start((B), (C)) -#define IXAudio2SourceVoice_Stop(A, B, C) (A)->Stop((B), (C)) -#define IXAudio2SourceVoice_SubmitSourceBuffer(A, B, C) (A)->SubmitSourceBuffer((B), (C)) -*/ -#endif // ifdef __cplusplus + +#pragma once + +// +// Re-implementation of methods removed from XAudio2 (in WinRT): +// + +typedef struct XAUDIO2_DEVICE_DETAILS +{ + WCHAR DeviceID[256]; + WCHAR DisplayName[256]; + /* Other fields exist in the pre-Windows 8 version of this struct, however + they weren't used by SDL, so they weren't added. + */ +} XAUDIO2_DEVICE_DETAILS; + + +#ifdef __cplusplus +extern "C" { +#endif + +HRESULT IXAudio2_GetDeviceCount(IXAudio2 * unused, UINT32 * devcount); +HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details); + +#ifdef __cplusplus +} +#endif + + +// +// C-style macros to call XAudio2's methods in C++: +// +#ifdef __cplusplus +/* +#define IXAudio2_CreateMasteringVoice(A, B, C, D, E, F, G) (A)->CreateMasteringVoice((B), (C), (D), (E), (F), (G)) +#define IXAudio2_CreateSourceVoice(A, B, C, D, E, F, G, H) (A)->CreateSourceVoice((B), (C), (D), (E), (F), (G), (H)) +#define IXAudio2_QueryInterface(A, B, C) (A)->QueryInterface((B), (C)) +#define IXAudio2_Release(A) (A)->Release() +#define IXAudio2_StartEngine(A) (A)->StartEngine() +#define IXAudio2_StopEngine(A) (A)->StopEngine() + +#define IXAudio2MasteringVoice_DestroyVoice(A) (A)->DestroyVoice() + +#define IXAudio2SourceVoice_DestroyVoice(A) (A)->DestroyVoice() +#define IXAudio2SourceVoice_Discontinuity(A) (A)->Discontinuity() +#define IXAudio2SourceVoice_FlushSourceBuffers(A) (A)->FlushSourceBuffers() +#define IXAudio2SourceVoice_GetState(A, B) (A)->GetState((B)) +#define IXAudio2SourceVoice_Start(A, B, C) (A)->Start((B), (C)) +#define IXAudio2SourceVoice_Stop(A, B, C) (A)->Stop((B), (C)) +#define IXAudio2SourceVoice_SubmitSourceBuffer(A, B, C) (A)->SubmitSourceBuffer((B), (C)) +*/ +#endif // ifdef __cplusplus diff --git a/src/core/winrt/SDL_winrtapp_common.cpp b/src/core/winrt/SDL_winrtapp_common.cpp index 6699e6811e627..fb151f229a21f 100644 --- a/src/core/winrt/SDL_winrtapp_common.cpp +++ b/src/core/winrt/SDL_winrtapp_common.cpp @@ -1,16 +1,16 @@ - -#include -#include "SDL_winrtapp_direct3d.h" -#include "SDL_winrtapp_xaml.h" - -int (*WINRT_SDLAppEntryPoint)(int, char **) = NULL; - + +#include +#include "SDL_winrtapp_direct3d.h" +#include "SDL_winrtapp_xaml.h" + +int (*WINRT_SDLAppEntryPoint)(int, char **) = NULL; + extern "C" DECLSPEC int -SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * xamlBackgroundPanel) -{ - if (xamlBackgroundPanel) { - return SDL_WinRTInitXAMLApp(mainFunction, xamlBackgroundPanel); - } else { - return SDL_WinRTInitNonXAMLApp(mainFunction); - } -} +SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * xamlBackgroundPanel) +{ + if (xamlBackgroundPanel) { + return SDL_WinRTInitXAMLApp(mainFunction, xamlBackgroundPanel); + } else { + return SDL_WinRTInitNonXAMLApp(mainFunction); + } +} diff --git a/src/core/winrt/SDL_winrtapp_common.h b/src/core/winrt/SDL_winrtapp_common.h index 503a785aa690e..d54a8ccdca993 100644 --- a/src/core/winrt/SDL_winrtapp_common.h +++ b/src/core/winrt/SDL_winrtapp_common.h @@ -19,13 +19,13 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "SDL_config.h" - + #ifndef _SDL_winrtapp_common_h -#define _SDL_winrtapp_common_h - -/* A pointer to the app's C-style main() function (which is a different - function than the WinRT app's actual entry point). - */ -extern int (*WINRT_SDLAppEntryPoint)(int, char **); - -#endif // ifndef _SDL_winrtapp_common_h +#define _SDL_winrtapp_common_h + +/* A pointer to the app's C-style main() function (which is a different + function than the WinRT app's actual entry point). + */ +extern int (*WINRT_SDLAppEntryPoint)(int, char **); + +#endif // ifndef _SDL_winrtapp_common_h diff --git a/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp index 3870d77edf066..53c72bc4ec8ee 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp @@ -1,668 +1,668 @@ - -/* Standard C++11 includes */ -#include -#include -#include -using namespace std; - - -/* Windows includes */ -#include "ppltasks.h" -using namespace concurrency; -using namespace Windows::ApplicationModel; -using namespace Windows::ApplicationModel::Core; -using namespace Windows::ApplicationModel::Activation; -using namespace Windows::Devices::Input; -using namespace Windows::Graphics::Display; -using namespace Windows::Foundation; -using namespace Windows::System; -using namespace Windows::UI::Core; -using namespace Windows::UI::Input; - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP -using namespace Windows::Phone::UI::Input; -#endif - - -/* SDL includes */ -extern "C" { -#include "SDL_assert.h" -#include "SDL_events.h" -#include "SDL_hints.h" -#include "SDL_log.h" -#include "SDL_main.h" -#include "SDL_stdinc.h" -#include "SDL_render.h" -#include "../../video/SDL_sysvideo.h" -//#include "../../SDL_hints_c.h" -#include "../../events/SDL_events_c.h" -#include "../../events/SDL_keyboard_c.h" -#include "../../events/SDL_mouse_c.h" -#include "../../events/SDL_windowevents_c.h" -#include "../../render/SDL_sysrender.h" -#include "../windows/SDL_windows.h" -} - -#include "../../video/winrt/SDL_winrtevents_c.h" -#include "../../video/winrt/SDL_winrtvideo_cpp.h" -#include "SDL_winrtapp_common.h" -#include "SDL_winrtapp_direct3d.h" - - -// Compile-time debugging options: -// To enable, uncomment; to disable, comment them out. -//#define LOG_POINTER_EVENTS 1 -//#define LOG_WINDOW_EVENTS 1 -//#define LOG_ORIENTATION_EVENTS 1 - - -// HACK, DLudwig: record a reference to the global, WinRT 'app'/view. -// SDL/WinRT will use this throughout its code. -// -// TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something -// non-global, such as something created inside -// SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside -// SDL_CreateWindow(). -SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr; - -ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource -{ -public: - virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView(); -}; - -IFrameworkView^ SDLApplicationSource::CreateView() -{ - // TODO, WinRT: see if this function (CreateView) can ever get called - // more than once. For now, just prevent it from ever assigning - // SDL_WinRTGlobalApp more than once. - SDL_assert(!SDL_WinRTGlobalApp); - SDL_WinRTApp ^ app = ref new SDL_WinRTApp(); - if (!SDL_WinRTGlobalApp) - { - SDL_WinRTGlobalApp = app; - } - return app; -} - -int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **)) -{ - WINRT_SDLAppEntryPoint = mainFunction; - auto direct3DApplicationSource = ref new SDLApplicationSource(); - CoreApplication::Run(direct3DApplicationSource); - return 0; -} - -static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue) -{ - SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0); - - // Start with no orientation flags, then add each in as they're parsed - // from newValue. - unsigned int orientationFlags = 0; - if (newValue) { - std::istringstream tokenizer(newValue); - while (!tokenizer.eof()) { - std::string orientationName; - std::getline(tokenizer, orientationName, ' '); - if (orientationName == "LandscapeLeft") { - orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped; - } else if (orientationName == "LandscapeRight") { - orientationFlags |= (unsigned int) DisplayOrientations::Landscape; - } else if (orientationName == "Portrait") { - orientationFlags |= (unsigned int) DisplayOrientations::Portrait; - } else if (orientationName == "PortraitUpsideDown") { - orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped; - } - } - } - - // If no valid orientation flags were specified, use a reasonable set of defaults: - if (!orientationFlags) { - // TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s). - orientationFlags = (unsigned int) ( \ - DisplayOrientations::Landscape | - DisplayOrientations::LandscapeFlipped | - DisplayOrientations::Portrait | - DisplayOrientations::PortraitFlipped); - } - - // Set the orientation/rotation preferences. Please note that this does - // not constitute a 100%-certain lock of a given set of possible - // orientations. According to Microsoft's documentation on WinRT [1] - // when a device is not capable of being rotated, Windows may ignore - // the orientation preferences, and stick to what the device is capable of - // displaying. - // - // [1] Documentation on the 'InitialRotationPreference' setting for a - // Windows app's manifest file describes how some orientation/rotation - // preferences may be ignored. See - // http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx - // for details. Microsoft's "Display orientation sample" also gives an - // outline of how Windows treats device rotation - // (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93). - DisplayProperties::AutoRotationPreferences = (DisplayOrientations) orientationFlags; -} - -static void -WINRT_ProcessWindowSizeChange() -{ - // Make the new window size be the one true fullscreen mode. - // This change was initially done, in part, to allow the Direct3D 11.1 - // renderer to receive window-resize events as a device rotates. - // Before, rotating a device from landscape, to portrait, and then - // back to landscape would cause the Direct3D 11.1 swap buffer to - // not get resized appropriately. SDL would, on the rotation from - // landscape to portrait, re-resize the SDL window to it's initial - // size (landscape). On the subsequent rotation, SDL would drop the - // window-resize event as it appeared the SDL window didn't change - // size, and the Direct3D 11.1 renderer wouldn't resize its swap - // chain. - SDL_DisplayMode newDisplayMode; - if (WINRT_CalcDisplayModeUsingNativeWindow(&newDisplayMode) != 0) { - return; - } - - // Make note of the old display mode, and it's old driverdata. - SDL_DisplayMode oldDisplayMode; - SDL_zero(oldDisplayMode); - if (WINRT_GlobalSDLVideoDevice) { - oldDisplayMode = WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode; - } - - // Setup the new display mode in the appropriate spots. - if (WINRT_GlobalSDLVideoDevice) { - // Make a full copy of the display mode for display_modes[0], - // one with with a separately malloced 'driverdata' field. - // SDL_VideoQuit(), if called, will attempt to free the driverdata - // fields in 'desktop_mode' and each entry in the 'display_modes' - // array. - if (WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata) { - // Free the previous mode's memory - SDL_free(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata); - WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata = NULL; - } - if (WINRT_DuplicateDisplayMode(&(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0]), &newDisplayMode) != 0) { - // Uh oh, something went wrong. A malloc call probably failed. - SDL_free(newDisplayMode.driverdata); - return; - } - - // Install 'newDisplayMode' into 'current_mode' and 'desktop_mode'. - WINRT_GlobalSDLVideoDevice->displays[0].current_mode = newDisplayMode; - WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = newDisplayMode; - } - - if (WINRT_GlobalSDLWindow) { - // Send a window-resize event to the rest of SDL, and to apps: - SDL_SendWindowEvent( - WINRT_GlobalSDLWindow, - SDL_WINDOWEVENT_RESIZED, - newDisplayMode.w, - newDisplayMode.h); - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - // HACK: On Windows Phone, make sure that orientation changes from - // Landscape to LandscapeFlipped, Portrait to PortraitFlipped, - // or vice-versa on either of those two, lead to the Direct3D renderer - // getting updated. - const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation; - const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation; - - if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) || - (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) || - (oldOrientation == DisplayOrientations::Portrait && newOrientation == DisplayOrientations::PortraitFlipped) || - (oldOrientation == DisplayOrientations::PortraitFlipped && newOrientation == DisplayOrientations::Portrait)) - { - // One of the reasons this event is getting sent out is because SDL - // will ignore requests to send out SDL_WINDOWEVENT_RESIZED events - // if and when the event size doesn't change (and the Direct3D 11.1 - // renderer doesn't get the memo). - // - // Make sure that the display/window size really didn't change. If - // it did, then a SDL_WINDOWEVENT_SIZE_CHANGED event got sent, and - // the Direct3D 11.1 renderer picked it up, presumably. - if (oldDisplayMode.w == newDisplayMode.w && - oldDisplayMode.h == newDisplayMode.h) - { - SDL_SendWindowEvent( - WINRT_GlobalSDLWindow, - SDL_WINDOWEVENT_SIZE_CHANGED, - newDisplayMode.w, - newDisplayMode.h); - } - } -#endif - } - - // Finally, free the 'driverdata' field of the old 'desktop_mode'. - if (oldDisplayMode.driverdata) { - SDL_free(oldDisplayMode.driverdata); - oldDisplayMode.driverdata = NULL; - } -} - -SDL_WinRTApp::SDL_WinRTApp() : - m_windowClosed(false), - m_windowVisible(true) -{ -} - -void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView) -{ - applicationView->Activated += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnActivated); - - CoreApplication::Suspending += - ref new EventHandler(this, &SDL_WinRTApp::OnSuspending); - - CoreApplication::Resuming += - ref new EventHandler(this, &SDL_WinRTApp::OnResuming); - - CoreApplication::Exiting += - ref new EventHandler(this, &SDL_WinRTApp::OnExiting); - - DisplayProperties::OrientationChanged += - ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged); - - // Register the hint, SDL_HINT_ORIENTATIONS, with SDL. This needs to be - // done before the hint's callback is registered (as of Feb 22, 2013), - // otherwise the hint callback won't get registered. - // - // TODO, WinRT: see if an app's default orientation can be found out via WinRT API(s), then set the initial value of SDL_HINT_ORIENTATIONS accordingly. - //SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight Portrait PortraitUpsideDown"); // DavidL: this is no longer needed (for SDL_AddHintCallback) - SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL); -} - -void SDL_WinRTApp::OnOrientationChanged(Object^ sender) -{ -#if LOG_ORIENTATION_EVENTS==1 - CoreWindow^ window = CoreWindow::GetForCurrentThread(); - if (window) { - SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n", - __FUNCTION__, - (int)DisplayProperties::CurrentOrientation, - (int)DisplayProperties::NativeOrientation, - (int)DisplayProperties::AutoRotationPreferences, - window->Bounds.Width, - window->Bounds.Height); - } else { - SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n", - __FUNCTION__, - (int)DisplayProperties::CurrentOrientation, - (int)DisplayProperties::NativeOrientation, - (int)DisplayProperties::AutoRotationPreferences); - } -#endif - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - // On Windows Phone, treat an orientation change as a change in window size. - // The native window's size doesn't seem to change, however SDL will simulate - // a window size change. - WINRT_ProcessWindowSizeChange(); -#endif -} - -void SDL_WinRTApp::SetWindow(CoreWindow^ window) -{ -#if LOG_WINDOW_EVENTS==1 - SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n", - __FUNCTION__, - (int)DisplayProperties::CurrentOrientation, - (int)DisplayProperties::NativeOrientation, - (int)DisplayProperties::AutoRotationPreferences, - window->Bounds.Width, - window->Bounds.Height); -#endif - - window->SizeChanged += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnWindowSizeChanged); - - window->VisibilityChanged += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnVisibilityChanged); - - window->Closed += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnWindowClosed); - -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP - window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0); -#endif - - window->PointerPressed += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerPressed); - - window->PointerMoved += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerMoved); - - window->PointerReleased += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerReleased); - - window->PointerWheelChanged += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerWheelChanged); - -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP - // Retrieves relative-only mouse movements: - Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnMouseMoved); -#endif - - window->KeyDown += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnKeyDown); - - window->KeyUp += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnKeyUp); - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - HardwareButtons::BackPressed += - ref new EventHandler(this, &SDL_WinRTApp::OnBackButtonPressed); -#endif - -#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps) - // Make sure we know when a user has opened the app's settings pane. - // This is needed in order to display a privacy policy, which needs - // to be done for network-enabled apps, as per Windows Store requirements. - using namespace Windows::UI::ApplicationSettings; - SettingsPane::GetForCurrentView()->CommandsRequested += - ref new TypedEventHandler - (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested); -#endif -} - -void SDL_WinRTApp::Load(Platform::String^ entryPoint) -{ -} - -void SDL_WinRTApp::Run() -{ - SDL_SetMainReady(); - if (WINRT_SDLAppEntryPoint) - { - // TODO, WinRT: pass the C-style main() a reasonably realistic - // representation of command line arguments. - int argc = 0; - char **argv = NULL; - WINRT_SDLAppEntryPoint(argc, argv); - } -} - -void SDL_WinRTApp::PumpEvents() -{ - if (!m_windowClosed) - { - if (m_windowVisible) - { - CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); - } - else - { - CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); - } - } -} - -void SDL_WinRTApp::Uninitialize() -{ -} - -#if WINAPI_FAMILY == WINAPI_FAMILY_APP -void SDL_WinRTApp::OnSettingsPaneCommandsRequested( - Windows::UI::ApplicationSettings::SettingsPane ^p, - Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args) -{ - using namespace Platform; - using namespace Windows::UI::ApplicationSettings; - using namespace Windows::UI::Popups; - - String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy - String ^privacyPolicyLabel = nullptr; // label/link text - const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately - wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion - - // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint): - tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_URL); - if (tmpHintValue && tmpHintValue[0] != '\0') { - // Convert the privacy policy's URL to UCS2: - tmpStr = WIN_UTF8ToString(tmpHintValue); - privacyPolicyURL = ref new String(tmpStr); - SDL_free(tmpStr); - - // Optionally retrieve custom label-text for the link. If this isn't - // available, a default value will be used instead. - tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_LABEL); - if (tmpHintValue && tmpHintValue[0] != '\0') { - tmpStr = WIN_UTF8ToString(tmpHintValue); - privacyPolicyLabel = ref new String(tmpStr); - SDL_free(tmpStr); - } else { - privacyPolicyLabel = ref new String(L"Privacy Policy"); - } - - // Register the link, along with a handler to be called if and when it is - // clicked: - auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel, - ref new UICommandInvokedHandler([=](IUICommand ^) { - Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL)); - })); - args->Request->ApplicationCommands->Append(cmd); - } -} -#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP - -void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args) -{ -#if LOG_WINDOW_EVENTS==1 - SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n", - __FUNCTION__, - args->Size.Width, args->Size.Height, - (int)DisplayProperties::CurrentOrientation, - (int)DisplayProperties::NativeOrientation, - (int)DisplayProperties::AutoRotationPreferences, - (WINRT_GlobalSDLWindow ? "yes" : "no")); -#endif - - WINRT_ProcessWindowSizeChange(); -} - -void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) -{ -#if LOG_WINDOW_EVENTS==1 - SDL_Log("%s, visible?=%s, WINRT_GlobalSDLWindow?=%s\n", - __FUNCTION__, - (args->Visible ? "yes" : "no"), - (WINRT_GlobalSDLWindow ? "yes" : "no")); -#endif - - m_windowVisible = args->Visible; - if (WINRT_GlobalSDLWindow) { - SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid; - - if (args->Visible) { - SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0); - } else { - SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0); - } - - // HACK: Prevent SDL's window-hide handling code, which currently - // triggers a fake window resize (possibly erronously), from - // marking the SDL window's surface as invalid. - // - // A better solution to this probably involves figuring out if the - // fake window resize can be prevented. - WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid; - } -} - -void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) -{ -#if LOG_WINDOW_EVENTS==1 - SDL_Log("%s\n", __FUNCTION__); -#endif - m_windowClosed = true; -} - -void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args) -{ - CoreWindow::GetForCurrentThread()->Activate(); -} - -static int SDLCALL RemoveAppSuspendAndResumeEvents(void * userdata, SDL_Event * event) -{ - if (event->type == SDL_WINDOWEVENT) - { - switch (event->window.event) - { - case SDL_WINDOWEVENT_MINIMIZED: - case SDL_WINDOWEVENT_RESTORED: - // Return 0 to indicate that the event should be removed from the - // event queue: - return 0; - default: - break; - } - } - - // Return 1 to indicate that the event should stay in the event queue: - return 1; -} - -void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args) -{ - // Save app state asynchronously after requesting a deferral. Holding a deferral - // indicates that the application is busy performing suspending operations. Be - // aware that a deferral may not be held indefinitely. After about five seconds, - // the app will be forced to exit. - SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral(); - create_task([this, deferral]() - { - // Send a window-minimized event immediately to observers. - // CoreDispatcher::ProcessEvents, which is the backbone on which - // SDL_WinRTApp::PumpEvents is built, will not return to its caller - // once it sends out a suspend event. Any events posted to SDL's - // event queue won't get received until the WinRT app is resumed. - // SDL_AddEventWatch() may be used to receive app-suspend events on - // WinRT. - // - // In order to prevent app-suspend events from being received twice: - // first via a callback passed to SDL_AddEventWatch, and second via - // SDL's event queue, the event will be sent to SDL, then immediately - // removed from the queue. - if (WINRT_GlobalSDLWindow) - { - SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently) - SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0); - } - - SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND); - SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND); - - deferral->Complete(); - }); -} - -void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args) -{ - SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND); - SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND); - - // Restore any data or state that was unloaded on suspend. By default, data - // and state are persisted when resuming from suspend. Note that this event - // does not occur if the app was previously terminated. - if (WINRT_GlobalSDLWindow) - { - SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently) - - // Remove the app-resume event from the queue, as is done with the - // app-suspend event. - // - // TODO, WinRT: consider posting this event to the queue even though - // its counterpart, the app-suspend event, effectively has to be - // processed immediately. - SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0); - } -} - -void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args) -{ - SDL_SendAppEvent(SDL_APP_TERMINATING); -} - -static void -WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint) -{ - Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint; - SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n", - header, - pt->Position.X, pt->Position.Y, - transformedPoint.X, transformedPoint.Y, - pt->Properties->MouseWheelDelta, - pt->FrameId, - pt->PointerId, - WINRT_GetSDLButtonForPointerPoint(pt)); -} - -void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args) -{ -#if LOG_POINTER_EVENTS - WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); -#endif - - WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); -} - -void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args) -{ -#if LOG_POINTER_EVENTS - WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); -#endif - - WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); -} - -void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args) -{ -#if LOG_POINTER_EVENTS - WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); -#endif - - WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); -} - -void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args) -{ -#if LOG_POINTER_EVENTS - WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); -#endif - - WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); -} - -void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args) -{ - WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args); -} - -void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) -{ - WINRT_ProcessKeyDownEvent(args); -} - -void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) -{ - WINRT_ProcessKeyUpEvent(args); -} - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP -void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args) -{ - SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK); - SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK); - + +/* Standard C++11 includes */ +#include +#include +#include +using namespace std; + + +/* Windows includes */ +#include "ppltasks.h" +using namespace concurrency; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Core; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Devices::Input; +using namespace Windows::Graphics::Display; +using namespace Windows::Foundation; +using namespace Windows::System; +using namespace Windows::UI::Core; +using namespace Windows::UI::Input; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +using namespace Windows::Phone::UI::Input; +#endif + + +/* SDL includes */ +extern "C" { +#include "SDL_assert.h" +#include "SDL_events.h" +#include "SDL_hints.h" +#include "SDL_log.h" +#include "SDL_main.h" +#include "SDL_stdinc.h" +#include "SDL_render.h" +#include "../../video/SDL_sysvideo.h" +//#include "../../SDL_hints_c.h" +#include "../../events/SDL_events_c.h" +#include "../../events/SDL_keyboard_c.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_windowevents_c.h" +#include "../../render/SDL_sysrender.h" +#include "../windows/SDL_windows.h" +} + +#include "../../video/winrt/SDL_winrtevents_c.h" +#include "../../video/winrt/SDL_winrtvideo_cpp.h" +#include "SDL_winrtapp_common.h" +#include "SDL_winrtapp_direct3d.h" + + +// Compile-time debugging options: +// To enable, uncomment; to disable, comment them out. +//#define LOG_POINTER_EVENTS 1 +//#define LOG_WINDOW_EVENTS 1 +//#define LOG_ORIENTATION_EVENTS 1 + + +// HACK, DLudwig: record a reference to the global, WinRT 'app'/view. +// SDL/WinRT will use this throughout its code. +// +// TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something +// non-global, such as something created inside +// SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside +// SDL_CreateWindow(). +SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr; + +ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource +{ +public: + virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView(); +}; + +IFrameworkView^ SDLApplicationSource::CreateView() +{ + // TODO, WinRT: see if this function (CreateView) can ever get called + // more than once. For now, just prevent it from ever assigning + // SDL_WinRTGlobalApp more than once. + SDL_assert(!SDL_WinRTGlobalApp); + SDL_WinRTApp ^ app = ref new SDL_WinRTApp(); + if (!SDL_WinRTGlobalApp) + { + SDL_WinRTGlobalApp = app; + } + return app; +} + +int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **)) +{ + WINRT_SDLAppEntryPoint = mainFunction; + auto direct3DApplicationSource = ref new SDLApplicationSource(); + CoreApplication::Run(direct3DApplicationSource); + return 0; +} + +static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue) +{ + SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0); + + // Start with no orientation flags, then add each in as they're parsed + // from newValue. + unsigned int orientationFlags = 0; + if (newValue) { + std::istringstream tokenizer(newValue); + while (!tokenizer.eof()) { + std::string orientationName; + std::getline(tokenizer, orientationName, ' '); + if (orientationName == "LandscapeLeft") { + orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped; + } else if (orientationName == "LandscapeRight") { + orientationFlags |= (unsigned int) DisplayOrientations::Landscape; + } else if (orientationName == "Portrait") { + orientationFlags |= (unsigned int) DisplayOrientations::Portrait; + } else if (orientationName == "PortraitUpsideDown") { + orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped; + } + } + } + + // If no valid orientation flags were specified, use a reasonable set of defaults: + if (!orientationFlags) { + // TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s). + orientationFlags = (unsigned int) ( \ + DisplayOrientations::Landscape | + DisplayOrientations::LandscapeFlipped | + DisplayOrientations::Portrait | + DisplayOrientations::PortraitFlipped); + } + + // Set the orientation/rotation preferences. Please note that this does + // not constitute a 100%-certain lock of a given set of possible + // orientations. According to Microsoft's documentation on WinRT [1] + // when a device is not capable of being rotated, Windows may ignore + // the orientation preferences, and stick to what the device is capable of + // displaying. + // + // [1] Documentation on the 'InitialRotationPreference' setting for a + // Windows app's manifest file describes how some orientation/rotation + // preferences may be ignored. See + // http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx + // for details. Microsoft's "Display orientation sample" also gives an + // outline of how Windows treats device rotation + // (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93). + DisplayProperties::AutoRotationPreferences = (DisplayOrientations) orientationFlags; +} + +static void +WINRT_ProcessWindowSizeChange() +{ + // Make the new window size be the one true fullscreen mode. + // This change was initially done, in part, to allow the Direct3D 11.1 + // renderer to receive window-resize events as a device rotates. + // Before, rotating a device from landscape, to portrait, and then + // back to landscape would cause the Direct3D 11.1 swap buffer to + // not get resized appropriately. SDL would, on the rotation from + // landscape to portrait, re-resize the SDL window to it's initial + // size (landscape). On the subsequent rotation, SDL would drop the + // window-resize event as it appeared the SDL window didn't change + // size, and the Direct3D 11.1 renderer wouldn't resize its swap + // chain. + SDL_DisplayMode newDisplayMode; + if (WINRT_CalcDisplayModeUsingNativeWindow(&newDisplayMode) != 0) { + return; + } + + // Make note of the old display mode, and it's old driverdata. + SDL_DisplayMode oldDisplayMode; + SDL_zero(oldDisplayMode); + if (WINRT_GlobalSDLVideoDevice) { + oldDisplayMode = WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode; + } + + // Setup the new display mode in the appropriate spots. + if (WINRT_GlobalSDLVideoDevice) { + // Make a full copy of the display mode for display_modes[0], + // one with with a separately malloced 'driverdata' field. + // SDL_VideoQuit(), if called, will attempt to free the driverdata + // fields in 'desktop_mode' and each entry in the 'display_modes' + // array. + if (WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata) { + // Free the previous mode's memory + SDL_free(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata); + WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata = NULL; + } + if (WINRT_DuplicateDisplayMode(&(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0]), &newDisplayMode) != 0) { + // Uh oh, something went wrong. A malloc call probably failed. + SDL_free(newDisplayMode.driverdata); + return; + } + + // Install 'newDisplayMode' into 'current_mode' and 'desktop_mode'. + WINRT_GlobalSDLVideoDevice->displays[0].current_mode = newDisplayMode; + WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = newDisplayMode; + } + + if (WINRT_GlobalSDLWindow) { + // Send a window-resize event to the rest of SDL, and to apps: + SDL_SendWindowEvent( + WINRT_GlobalSDLWindow, + SDL_WINDOWEVENT_RESIZED, + newDisplayMode.w, + newDisplayMode.h); + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // HACK: On Windows Phone, make sure that orientation changes from + // Landscape to LandscapeFlipped, Portrait to PortraitFlipped, + // or vice-versa on either of those two, lead to the Direct3D renderer + // getting updated. + const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation; + const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation; + + if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) || + (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) || + (oldOrientation == DisplayOrientations::Portrait && newOrientation == DisplayOrientations::PortraitFlipped) || + (oldOrientation == DisplayOrientations::PortraitFlipped && newOrientation == DisplayOrientations::Portrait)) + { + // One of the reasons this event is getting sent out is because SDL + // will ignore requests to send out SDL_WINDOWEVENT_RESIZED events + // if and when the event size doesn't change (and the Direct3D 11.1 + // renderer doesn't get the memo). + // + // Make sure that the display/window size really didn't change. If + // it did, then a SDL_WINDOWEVENT_SIZE_CHANGED event got sent, and + // the Direct3D 11.1 renderer picked it up, presumably. + if (oldDisplayMode.w == newDisplayMode.w && + oldDisplayMode.h == newDisplayMode.h) + { + SDL_SendWindowEvent( + WINRT_GlobalSDLWindow, + SDL_WINDOWEVENT_SIZE_CHANGED, + newDisplayMode.w, + newDisplayMode.h); + } + } +#endif + } + + // Finally, free the 'driverdata' field of the old 'desktop_mode'. + if (oldDisplayMode.driverdata) { + SDL_free(oldDisplayMode.driverdata); + oldDisplayMode.driverdata = NULL; + } +} + +SDL_WinRTApp::SDL_WinRTApp() : + m_windowClosed(false), + m_windowVisible(true) +{ +} + +void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView) +{ + applicationView->Activated += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnActivated); + + CoreApplication::Suspending += + ref new EventHandler(this, &SDL_WinRTApp::OnSuspending); + + CoreApplication::Resuming += + ref new EventHandler(this, &SDL_WinRTApp::OnResuming); + + CoreApplication::Exiting += + ref new EventHandler(this, &SDL_WinRTApp::OnExiting); + + DisplayProperties::OrientationChanged += + ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged); + + // Register the hint, SDL_HINT_ORIENTATIONS, with SDL. This needs to be + // done before the hint's callback is registered (as of Feb 22, 2013), + // otherwise the hint callback won't get registered. + // + // TODO, WinRT: see if an app's default orientation can be found out via WinRT API(s), then set the initial value of SDL_HINT_ORIENTATIONS accordingly. + //SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight Portrait PortraitUpsideDown"); // DavidL: this is no longer needed (for SDL_AddHintCallback) + SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL); +} + +void SDL_WinRTApp::OnOrientationChanged(Object^ sender) +{ +#if LOG_ORIENTATION_EVENTS==1 + CoreWindow^ window = CoreWindow::GetForCurrentThread(); + if (window) { + SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n", + __FUNCTION__, + (int)DisplayProperties::CurrentOrientation, + (int)DisplayProperties::NativeOrientation, + (int)DisplayProperties::AutoRotationPreferences, + window->Bounds.Width, + window->Bounds.Height); + } else { + SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n", + __FUNCTION__, + (int)DisplayProperties::CurrentOrientation, + (int)DisplayProperties::NativeOrientation, + (int)DisplayProperties::AutoRotationPreferences); + } +#endif + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // On Windows Phone, treat an orientation change as a change in window size. + // The native window's size doesn't seem to change, however SDL will simulate + // a window size change. + WINRT_ProcessWindowSizeChange(); +#endif +} + +void SDL_WinRTApp::SetWindow(CoreWindow^ window) +{ +#if LOG_WINDOW_EVENTS==1 + SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n", + __FUNCTION__, + (int)DisplayProperties::CurrentOrientation, + (int)DisplayProperties::NativeOrientation, + (int)DisplayProperties::AutoRotationPreferences, + window->Bounds.Width, + window->Bounds.Height); +#endif + + window->SizeChanged += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnWindowSizeChanged); + + window->VisibilityChanged += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnVisibilityChanged); + + window->Closed += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnWindowClosed); + +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0); +#endif + + window->PointerPressed += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerPressed); + + window->PointerMoved += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerMoved); + + window->PointerReleased += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerReleased); + + window->PointerWheelChanged += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerWheelChanged); + +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + // Retrieves relative-only mouse movements: + Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnMouseMoved); +#endif + + window->KeyDown += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnKeyDown); + + window->KeyUp += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnKeyUp); + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + HardwareButtons::BackPressed += + ref new EventHandler(this, &SDL_WinRTApp::OnBackButtonPressed); +#endif + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps) + // Make sure we know when a user has opened the app's settings pane. + // This is needed in order to display a privacy policy, which needs + // to be done for network-enabled apps, as per Windows Store requirements. + using namespace Windows::UI::ApplicationSettings; + SettingsPane::GetForCurrentView()->CommandsRequested += + ref new TypedEventHandler + (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested); +#endif +} + +void SDL_WinRTApp::Load(Platform::String^ entryPoint) +{ +} + +void SDL_WinRTApp::Run() +{ + SDL_SetMainReady(); + if (WINRT_SDLAppEntryPoint) + { + // TODO, WinRT: pass the C-style main() a reasonably realistic + // representation of command line arguments. + int argc = 0; + char **argv = NULL; + WINRT_SDLAppEntryPoint(argc, argv); + } +} + +void SDL_WinRTApp::PumpEvents() +{ + if (!m_windowClosed) + { + if (m_windowVisible) + { + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); + } + else + { + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); + } + } +} + +void SDL_WinRTApp::Uninitialize() +{ +} + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +void SDL_WinRTApp::OnSettingsPaneCommandsRequested( + Windows::UI::ApplicationSettings::SettingsPane ^p, + Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args) +{ + using namespace Platform; + using namespace Windows::UI::ApplicationSettings; + using namespace Windows::UI::Popups; + + String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy + String ^privacyPolicyLabel = nullptr; // label/link text + const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately + wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion + + // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint): + tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_URL); + if (tmpHintValue && tmpHintValue[0] != '\0') { + // Convert the privacy policy's URL to UCS2: + tmpStr = WIN_UTF8ToString(tmpHintValue); + privacyPolicyURL = ref new String(tmpStr); + SDL_free(tmpStr); + + // Optionally retrieve custom label-text for the link. If this isn't + // available, a default value will be used instead. + tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_LABEL); + if (tmpHintValue && tmpHintValue[0] != '\0') { + tmpStr = WIN_UTF8ToString(tmpHintValue); + privacyPolicyLabel = ref new String(tmpStr); + SDL_free(tmpStr); + } else { + privacyPolicyLabel = ref new String(L"Privacy Policy"); + } + + // Register the link, along with a handler to be called if and when it is + // clicked: + auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel, + ref new UICommandInvokedHandler([=](IUICommand ^) { + Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL)); + })); + args->Request->ApplicationCommands->Append(cmd); + } +} +#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP + +void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args) +{ +#if LOG_WINDOW_EVENTS==1 + SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n", + __FUNCTION__, + args->Size.Width, args->Size.Height, + (int)DisplayProperties::CurrentOrientation, + (int)DisplayProperties::NativeOrientation, + (int)DisplayProperties::AutoRotationPreferences, + (WINRT_GlobalSDLWindow ? "yes" : "no")); +#endif + + WINRT_ProcessWindowSizeChange(); +} + +void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) +{ +#if LOG_WINDOW_EVENTS==1 + SDL_Log("%s, visible?=%s, WINRT_GlobalSDLWindow?=%s\n", + __FUNCTION__, + (args->Visible ? "yes" : "no"), + (WINRT_GlobalSDLWindow ? "yes" : "no")); +#endif + + m_windowVisible = args->Visible; + if (WINRT_GlobalSDLWindow) { + SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid; + + if (args->Visible) { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0); + } else { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0); + } + + // HACK: Prevent SDL's window-hide handling code, which currently + // triggers a fake window resize (possibly erronously), from + // marking the SDL window's surface as invalid. + // + // A better solution to this probably involves figuring out if the + // fake window resize can be prevented. + WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid; + } +} + +void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) +{ +#if LOG_WINDOW_EVENTS==1 + SDL_Log("%s\n", __FUNCTION__); +#endif + m_windowClosed = true; +} + +void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args) +{ + CoreWindow::GetForCurrentThread()->Activate(); +} + +static int SDLCALL RemoveAppSuspendAndResumeEvents(void * userdata, SDL_Event * event) +{ + if (event->type == SDL_WINDOWEVENT) + { + switch (event->window.event) + { + case SDL_WINDOWEVENT_MINIMIZED: + case SDL_WINDOWEVENT_RESTORED: + // Return 0 to indicate that the event should be removed from the + // event queue: + return 0; + default: + break; + } + } + + // Return 1 to indicate that the event should stay in the event queue: + return 1; +} + +void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args) +{ + // Save app state asynchronously after requesting a deferral. Holding a deferral + // indicates that the application is busy performing suspending operations. Be + // aware that a deferral may not be held indefinitely. After about five seconds, + // the app will be forced to exit. + SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral(); + create_task([this, deferral]() + { + // Send a window-minimized event immediately to observers. + // CoreDispatcher::ProcessEvents, which is the backbone on which + // SDL_WinRTApp::PumpEvents is built, will not return to its caller + // once it sends out a suspend event. Any events posted to SDL's + // event queue won't get received until the WinRT app is resumed. + // SDL_AddEventWatch() may be used to receive app-suspend events on + // WinRT. + // + // In order to prevent app-suspend events from being received twice: + // first via a callback passed to SDL_AddEventWatch, and second via + // SDL's event queue, the event will be sent to SDL, then immediately + // removed from the queue. + if (WINRT_GlobalSDLWindow) + { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently) + SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0); + } + + SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND); + SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND); + + deferral->Complete(); + }); +} + +void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args) +{ + SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND); + SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND); + + // Restore any data or state that was unloaded on suspend. By default, data + // and state are persisted when resuming from suspend. Note that this event + // does not occur if the app was previously terminated. + if (WINRT_GlobalSDLWindow) + { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently) + + // Remove the app-resume event from the queue, as is done with the + // app-suspend event. + // + // TODO, WinRT: consider posting this event to the queue even though + // its counterpart, the app-suspend event, effectively has to be + // processed immediately. + SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0); + } +} + +void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args) +{ + SDL_SendAppEvent(SDL_APP_TERMINATING); +} + +static void +WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint) +{ + Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint; + SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n", + header, + pt->Position.X, pt->Position.Y, + transformedPoint.X, transformedPoint.Y, + pt->Properties->MouseWheelDelta, + pt->FrameId, + pt->PointerId, + WINRT_GetSDLButtonForPointerPoint(pt)); +} + +void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args) +{ + WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args); +} + +void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) +{ + WINRT_ProcessKeyDownEvent(args); +} + +void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) +{ + WINRT_ProcessKeyUpEvent(args); +} + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args) +{ + SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK); + SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK); + const char *hint = SDL_GetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON); if (hint) { if (*hint == '1') { args->Handled = true; } - } -} -#endif - + } +} +#endif + diff --git a/src/core/winrt/SDL_winrtapp_direct3d.h b/src/core/winrt/SDL_winrtapp_direct3d.h index fcf37a149e13b..07e4a80485eb3 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.h +++ b/src/core/winrt/SDL_winrtapp_direct3d.h @@ -1,58 +1,58 @@ -#pragma once - -#include - -extern int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **)); - -ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFrameworkView -{ -public: - SDL_WinRTApp(); - - // IFrameworkView Methods. - virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView); - virtual void SetWindow(Windows::UI::Core::CoreWindow^ window); - virtual void Load(Platform::String^ entryPoint); - virtual void Run(); - virtual void Uninitialize(); - -internal: - // SDL-specific methods - void PumpEvents(); - -protected: - // Event Handlers. - -#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps) - void OnSettingsPaneCommandsRequested( - Windows::UI::ApplicationSettings::SettingsPane ^p, - Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args); -#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP - - void OnOrientationChanged(Platform::Object^ sender); - void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args); - void OnLogicalDpiChanged(Platform::Object^ sender); - void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args); - void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args); - void OnResuming(Platform::Object^ sender, Platform::Object^ args); - void OnExiting(Platform::Object^ sender, Platform::Object^ args); - void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args); - void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args); - void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); - void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); - void OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); - void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); - void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args); - void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); - void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args); -#endif - -private: - bool m_windowClosed; - bool m_windowVisible; -}; - -extern SDL_WinRTApp ^ SDL_WinRTGlobalApp; +#pragma once + +#include + +extern int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **)); + +ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFrameworkView +{ +public: + SDL_WinRTApp(); + + // IFrameworkView Methods. + virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView); + virtual void SetWindow(Windows::UI::Core::CoreWindow^ window); + virtual void Load(Platform::String^ entryPoint); + virtual void Run(); + virtual void Uninitialize(); + +internal: + // SDL-specific methods + void PumpEvents(); + +protected: + // Event Handlers. + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps) + void OnSettingsPaneCommandsRequested( + Windows::UI::ApplicationSettings::SettingsPane ^p, + Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args); +#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP + + void OnOrientationChanged(Platform::Object^ sender); + void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args); + void OnLogicalDpiChanged(Platform::Object^ sender); + void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args); + void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args); + void OnResuming(Platform::Object^ sender, Platform::Object^ args); + void OnExiting(Platform::Object^ sender, Platform::Object^ args); + void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args); + void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args); + void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + void OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args); + void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); + void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args); +#endif + +private: + bool m_windowClosed; + bool m_windowVisible; +}; + +extern SDL_WinRTApp ^ SDL_WinRTGlobalApp; diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index 73e9846aae498..a5fe56a2d331f 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -1,765 +1,765 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -/* Need this so Linux systems define fseek64o, ftell64o and off64_t */ -#define _LARGEFILE64_SOURCE -#include "SDL_config.h" - -#if defined(__WIN32__) -#include "../core/windows/SDL_windows.h" -#endif - - -/* This file provides a general interface for SDL to read and write - data sources. It can easily be extended to files, memory, etc. -*/ - -#include "SDL_endian.h" -#include "SDL_rwops.h" - -#ifdef __APPLE__ -#include "cocoa/SDL_rwopsbundlesupport.h" -#endif /* __APPLE__ */ - -#ifdef ANDROID -#include "../core/android/SDL_android.h" -#include "SDL_system.h" -#endif - -#ifdef __WIN32__ - -/* Functions to read/write Win32 API file pointers */ - -#ifndef INVALID_SET_FILE_POINTER -#define INVALID_SET_FILE_POINTER 0xFFFFFFFF -#endif - -#define READAHEAD_BUFFER_SIZE 1024 - -static int SDLCALL -windows_file_open(SDL_RWops * context, const char *filename, const char *mode) -{ - UINT old_error_mode; - HANDLE h; - DWORD r_right, w_right; - DWORD must_exist, truncate; - int a_mode; - - if (!context) - return -1; /* failed (invalid call) */ - - context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */ - context->hidden.windowsio.buffer.data = NULL; - context->hidden.windowsio.buffer.size = 0; - context->hidden.windowsio.buffer.left = 0; - - /* "r" = reading, file must exist */ - /* "w" = writing, truncate existing, file may not exist */ - /* "r+"= reading or writing, file must exist */ - /* "a" = writing, append file may not exist */ - /* "a+"= append + read, file may not exist */ - /* "w+" = read, write, truncate. file may not exist */ - - must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0; - truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0; - r_right = (SDL_strchr(mode, '+') != NULL - || must_exist) ? GENERIC_READ : 0; - a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0; - w_right = (a_mode || SDL_strchr(mode, '+') - || truncate) ? GENERIC_WRITE : 0; - - if (!r_right && !w_right) /* inconsistent mode */ - return -1; /* failed (invalid call) */ - - context->hidden.windowsio.buffer.data = - (char *) SDL_malloc(READAHEAD_BUFFER_SIZE); - if (!context->hidden.windowsio.buffer.data) { - return SDL_OutOfMemory(); - } - /* Do not open a dialog box if failure */ - old_error_mode = - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); - - { - LPTSTR tstr = WIN_UTF8ToString(filename); - h = CreateFile(tstr, (w_right | r_right), - (w_right) ? 0 : FILE_SHARE_READ, NULL, - (must_exist | truncate | a_mode), - FILE_ATTRIBUTE_NORMAL, NULL); - SDL_free(tstr); - } - - /* restore old behavior */ - SetErrorMode(old_error_mode); - - if (h == INVALID_HANDLE_VALUE) { - SDL_free(context->hidden.windowsio.buffer.data); - context->hidden.windowsio.buffer.data = NULL; - SDL_SetError("Couldn't open %s", filename); - return -2; /* failed (CreateFile) */ - } - context->hidden.windowsio.h = h; - context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE; - - return 0; /* ok */ -} - -static Sint64 SDLCALL -windows_file_size(SDL_RWops * context) -{ - LARGE_INTEGER size; - - if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) { - return SDL_SetError("windows_file_size: invalid context/file not opened"); - } - - if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) { - return WIN_SetError("windows_file_size"); - } - - return size.QuadPart; -} - -static Sint64 SDLCALL -windows_file_seek(SDL_RWops * context, Sint64 offset, int whence) -{ - DWORD windowswhence; - LARGE_INTEGER windowsoffset; - - if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) { - return SDL_SetError("windows_file_seek: invalid context/file not opened"); - } - - /* FIXME: We may be able to satisfy the seek within buffered data */ - if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) { - offset -= (long)context->hidden.windowsio.buffer.left; - } - context->hidden.windowsio.buffer.left = 0; - - switch (whence) { - case RW_SEEK_SET: - windowswhence = FILE_BEGIN; - break; - case RW_SEEK_CUR: - windowswhence = FILE_CURRENT; - break; - case RW_SEEK_END: - windowswhence = FILE_END; - break; - default: - return SDL_SetError("windows_file_seek: Unknown value for 'whence'"); - } - - windowsoffset.QuadPart = offset; - if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) { - return WIN_SetError("windows_file_seek"); - } - return windowsoffset.QuadPart; -} - -static size_t SDLCALL -windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum) -{ - size_t total_need; - size_t total_read = 0; - size_t read_ahead; - DWORD byte_read; - - total_need = size * maxnum; - - if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE - || !total_need) - return 0; - - if (context->hidden.windowsio.buffer.left > 0) { - void *data = (char *) context->hidden.windowsio.buffer.data + - context->hidden.windowsio.buffer.size - - context->hidden.windowsio.buffer.left; - read_ahead = - SDL_min(total_need, context->hidden.windowsio.buffer.left); - SDL_memcpy(ptr, data, read_ahead); - context->hidden.windowsio.buffer.left -= read_ahead; - - if (read_ahead == total_need) { - return maxnum; - } - ptr = (char *) ptr + read_ahead; - total_need -= read_ahead; - total_read += read_ahead; - } - - if (total_need < READAHEAD_BUFFER_SIZE) { - if (!ReadFile - (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data, - READAHEAD_BUFFER_SIZE, &byte_read, NULL)) { - SDL_Error(SDL_EFREAD); - return 0; - } - read_ahead = SDL_min(total_need, (int) byte_read); - SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead); - context->hidden.windowsio.buffer.size = byte_read; - context->hidden.windowsio.buffer.left = byte_read - read_ahead; - total_read += read_ahead; - } else { - if (!ReadFile - (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) { - SDL_Error(SDL_EFREAD); - return 0; - } - total_read += byte_read; - } - return (total_read / size); -} - -static size_t SDLCALL -windows_file_write(SDL_RWops * context, const void *ptr, size_t size, - size_t num) -{ - - size_t total_bytes; - DWORD byte_written; - size_t nwritten; - - total_bytes = size * num; - - if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE - || total_bytes <= 0 || !size) - return 0; - - if (context->hidden.windowsio.buffer.left) { - SetFilePointer(context->hidden.windowsio.h, - -(LONG)context->hidden.windowsio.buffer.left, NULL, - FILE_CURRENT); - context->hidden.windowsio.buffer.left = 0; - } - - /* if in append mode, we must go to the EOF before write */ - if (context->hidden.windowsio.append) { - if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) == - INVALID_SET_FILE_POINTER) { - SDL_Error(SDL_EFWRITE); - return 0; - } - } - - if (!WriteFile - (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) { - SDL_Error(SDL_EFWRITE); - return 0; - } - - nwritten = byte_written / size; - return nwritten; -} - -static int SDLCALL -windows_file_close(SDL_RWops * context) -{ - - if (context) { - if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) { - CloseHandle(context->hidden.windowsio.h); - context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */ - } - SDL_free(context->hidden.windowsio.buffer.data); - context->hidden.windowsio.buffer.data = NULL; - SDL_FreeRW(context); - } - return (0); -} -#endif /* __WIN32__ */ - -#ifdef HAVE_STDIO_H - -/* Functions to read/write stdio file pointers */ - -static Sint64 SDLCALL -stdio_size(SDL_RWops * context) -{ - Sint64 pos, size; - - pos = SDL_RWseek(context, 0, RW_SEEK_CUR); - if (pos < 0) { - return -1; - } - size = SDL_RWseek(context, 0, RW_SEEK_END); - - SDL_RWseek(context, pos, RW_SEEK_SET); - return size; -} - -static Sint64 SDLCALL -stdio_seek(SDL_RWops * context, Sint64 offset, int whence) -{ -#ifdef HAVE_FSEEKO64 - if (fseeko64(context->hidden.stdio.fp, (off64_t)offset, whence) == 0) { - return ftello64(context->hidden.stdio.fp); - } -#elif defined(HAVE_FSEEKO) - if (fseeko(context->hidden.stdio.fp, (off_t)offset, whence) == 0) { - return ftello(context->hidden.stdio.fp); - } -#elif defined(HAVE__FSEEKI64) - if (_fseeki64(context->hidden.stdio.fp, offset, whence) == 0) { - return _ftelli64(context->hidden.stdio.fp); - } -#else - if (fseek(context->hidden.stdio.fp, offset, whence) == 0) { - return (ftell(context->hidden.stdio.fp)); - } -#endif - return SDL_Error(SDL_EFSEEK); -} - -static size_t SDLCALL -stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum) -{ - size_t nread; - - nread = fread(ptr, size, maxnum, context->hidden.stdio.fp); - if (nread == 0 && ferror(context->hidden.stdio.fp)) { - SDL_Error(SDL_EFREAD); - } - return (nread); -} - -static size_t SDLCALL -stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num) -{ - size_t nwrote; - - nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp); - if (nwrote == 0 && ferror(context->hidden.stdio.fp)) { - SDL_Error(SDL_EFWRITE); - } - return (nwrote); -} - -static int SDLCALL -stdio_close(SDL_RWops * context) -{ - int status = 0; - if (context) { - if (context->hidden.stdio.autoclose) { - /* WARNING: Check the return value here! */ - if (fclose(context->hidden.stdio.fp) != 0) { - status = SDL_Error(SDL_EFWRITE); - } - } - SDL_FreeRW(context); - } - return status; -} -#endif /* !HAVE_STDIO_H */ - -/* Functions to read/write memory pointers */ - -static Sint64 SDLCALL -mem_size(SDL_RWops * context) -{ - return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base); -} - -static Sint64 SDLCALL -mem_seek(SDL_RWops * context, Sint64 offset, int whence) -{ - Uint8 *newpos; - - switch (whence) { - case RW_SEEK_SET: - newpos = context->hidden.mem.base + offset; - break; - case RW_SEEK_CUR: - newpos = context->hidden.mem.here + offset; - break; - case RW_SEEK_END: - newpos = context->hidden.mem.stop + offset; - break; - default: - return SDL_SetError("Unknown value for 'whence'"); - } - if (newpos < context->hidden.mem.base) { - newpos = context->hidden.mem.base; - } - if (newpos > context->hidden.mem.stop) { - newpos = context->hidden.mem.stop; - } - context->hidden.mem.here = newpos; - return (Sint64)(context->hidden.mem.here - context->hidden.mem.base); -} - -static size_t SDLCALL -mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum) -{ - size_t total_bytes; - size_t mem_available; - - total_bytes = (maxnum * size); - if ((maxnum <= 0) || (size <= 0) - || ((total_bytes / maxnum) != (size_t) size)) { - return 0; - } - - mem_available = (context->hidden.mem.stop - context->hidden.mem.here); - if (total_bytes > mem_available) { - total_bytes = mem_available; - } - - SDL_memcpy(ptr, context->hidden.mem.here, total_bytes); - context->hidden.mem.here += total_bytes; - - return (total_bytes / size); -} - -static size_t SDLCALL -mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num) -{ - if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) { - num = (context->hidden.mem.stop - context->hidden.mem.here) / size; - } - SDL_memcpy(context->hidden.mem.here, ptr, num * size); - context->hidden.mem.here += num * size; - return (num); -} - -static size_t SDLCALL -mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num) -{ - SDL_SetError("Can't write to read-only memory"); - return (0); -} - -static int SDLCALL -mem_close(SDL_RWops * context) -{ - if (context) { - SDL_FreeRW(context); - } - return (0); -} - - -/* Functions to create SDL_RWops structures from various data sources */ - -SDL_RWops * -SDL_RWFromFile(const char *file, const char *mode) -{ - SDL_RWops *rwops = NULL; - if (!file || !*file || !mode || !*mode) { - SDL_SetError("SDL_RWFromFile(): No file or no mode specified"); - return NULL; - } -#if defined(ANDROID) -#ifdef HAVE_STDIO_H - /* Try to open the file on the filesystem first */ - if (*file == '/') { - FILE *fp = fopen(file, mode); - if (fp) { - return SDL_RWFromFP(fp, 1); - } - } else { - /* Try opening it from internal storage if it's a relative path */ - char *path; - FILE *fp; - - path = SDL_stack_alloc(char, PATH_MAX); - if (path) { - SDL_snprintf(path, PATH_MAX, "%s/%s", - SDL_AndroidGetInternalStoragePath(), file); - fp = fopen(path, mode); - SDL_stack_free(path); - if (fp) { - return SDL_RWFromFP(fp, 1); - } - } - } -#endif /* HAVE_STDIO_H */ - - /* Try to open the file from the asset system */ - rwops = SDL_AllocRW(); - if (!rwops) - return NULL; /* SDL_SetError already setup by SDL_AllocRW() */ - if (Android_JNI_FileOpen(rwops, file, mode) < 0) { - SDL_FreeRW(rwops); - return NULL; - } - rwops->size = Android_JNI_FileSize; - rwops->seek = Android_JNI_FileSeek; - rwops->read = Android_JNI_FileRead; - rwops->write = Android_JNI_FileWrite; - rwops->close = Android_JNI_FileClose; - rwops->type = SDL_RWOPS_JNIFILE; - -#elif defined(__WIN32__) - rwops = SDL_AllocRW(); - if (!rwops) - return NULL; /* SDL_SetError already setup by SDL_AllocRW() */ - if (windows_file_open(rwops, file, mode) < 0) { - SDL_FreeRW(rwops); - return NULL; - } - rwops->size = windows_file_size; - rwops->seek = windows_file_seek; - rwops->read = windows_file_read; - rwops->write = windows_file_write; - rwops->close = windows_file_close; - rwops->type = SDL_RWOPS_WINFILE; - -#elif HAVE_STDIO_H - { - #ifdef __APPLE__ - FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode); - #elif __WINRT__ - FILE *fp = NULL; - fopen_s(&fp, file, mode); - #else - FILE *fp = fopen(file, mode); - #endif - if (fp == NULL) { - SDL_SetError("Couldn't open %s", file); - } else { - rwops = SDL_RWFromFP(fp, 1); - } - } -#else - SDL_SetError("SDL not compiled with stdio support"); -#endif /* !HAVE_STDIO_H */ - - return (rwops); -} - -#ifdef HAVE_STDIO_H -SDL_RWops * -SDL_RWFromFP(FILE * fp, SDL_bool autoclose) -{ - SDL_RWops *rwops = NULL; - - rwops = SDL_AllocRW(); - if (rwops != NULL) { - rwops->size = stdio_size; - rwops->seek = stdio_seek; - rwops->read = stdio_read; - rwops->write = stdio_write; - rwops->close = stdio_close; - rwops->hidden.stdio.fp = fp; - rwops->hidden.stdio.autoclose = autoclose; - rwops->type = SDL_RWOPS_STDFILE; - } - return (rwops); -} -#else -SDL_RWops * -SDL_RWFromFP(void * fp, SDL_bool autoclose) -{ - SDL_SetError("SDL not compiled with stdio support"); - return NULL; -} -#endif /* HAVE_STDIO_H */ - -SDL_RWops * -SDL_RWFromMem(void *mem, int size) -{ - SDL_RWops *rwops = NULL; - if (!mem) { - SDL_InvalidParamError("mem"); - return (rwops); - } - if (!size) { - SDL_InvalidParamError("size"); - return (rwops); - } - - rwops = SDL_AllocRW(); - if (rwops != NULL) { - rwops->size = mem_size; - rwops->seek = mem_seek; - rwops->read = mem_read; - rwops->write = mem_write; - rwops->close = mem_close; - rwops->hidden.mem.base = (Uint8 *) mem; - rwops->hidden.mem.here = rwops->hidden.mem.base; - rwops->hidden.mem.stop = rwops->hidden.mem.base + size; - rwops->type = SDL_RWOPS_MEMORY; - } - return (rwops); -} - -SDL_RWops * -SDL_RWFromConstMem(const void *mem, int size) -{ - SDL_RWops *rwops = NULL; - if (!mem) { - SDL_InvalidParamError("mem"); - return (rwops); - } - if (!size) { - SDL_InvalidParamError("size"); - return (rwops); - } - - rwops = SDL_AllocRW(); - if (rwops != NULL) { - rwops->size = mem_size; - rwops->seek = mem_seek; - rwops->read = mem_read; - rwops->write = mem_writeconst; - rwops->close = mem_close; - rwops->hidden.mem.base = (Uint8 *) mem; - rwops->hidden.mem.here = rwops->hidden.mem.base; - rwops->hidden.mem.stop = rwops->hidden.mem.base + size; - rwops->type = SDL_RWOPS_MEMORY_RO; - } - return (rwops); -} - -SDL_RWops * -SDL_AllocRW(void) -{ - SDL_RWops *area; - - area = (SDL_RWops *) SDL_malloc(sizeof *area); - if (area == NULL) { - SDL_OutOfMemory(); - } else { - area->type = SDL_RWOPS_UNKNOWN; - } - return (area); -} - -void -SDL_FreeRW(SDL_RWops * area) -{ - SDL_free(area); -} - -/* Functions for dynamically reading and writing endian-specific values */ - -Uint8 -SDL_ReadU8(SDL_RWops * src) -{ - Uint8 value = 0; - - SDL_RWread(src, &value, (sizeof value), 1); - return value; -} - -Uint16 -SDL_ReadLE16(SDL_RWops * src) -{ - Uint16 value = 0; - - SDL_RWread(src, &value, (sizeof value), 1); - return (SDL_SwapLE16(value)); -} - -Uint16 -SDL_ReadBE16(SDL_RWops * src) -{ - Uint16 value = 0; - - SDL_RWread(src, &value, (sizeof value), 1); - return (SDL_SwapBE16(value)); -} - -Uint32 -SDL_ReadLE32(SDL_RWops * src) -{ - Uint32 value = 0; - - SDL_RWread(src, &value, (sizeof value), 1); - return (SDL_SwapLE32(value)); -} - -Uint32 -SDL_ReadBE32(SDL_RWops * src) -{ - Uint32 value = 0; - - SDL_RWread(src, &value, (sizeof value), 1); - return (SDL_SwapBE32(value)); -} - -Uint64 -SDL_ReadLE64(SDL_RWops * src) -{ - Uint64 value = 0; - - SDL_RWread(src, &value, (sizeof value), 1); - return (SDL_SwapLE64(value)); -} - -Uint64 -SDL_ReadBE64(SDL_RWops * src) -{ - Uint64 value = 0; - - SDL_RWread(src, &value, (sizeof value), 1); - return (SDL_SwapBE64(value)); -} - -size_t -SDL_WriteU8(SDL_RWops * dst, Uint8 value) -{ - return (SDL_RWwrite(dst, &value, (sizeof value), 1)); -} - -size_t -SDL_WriteLE16(SDL_RWops * dst, Uint16 value) -{ - value = SDL_SwapLE16(value); - return (SDL_RWwrite(dst, &value, (sizeof value), 1)); -} - -size_t -SDL_WriteBE16(SDL_RWops * dst, Uint16 value) -{ - value = SDL_SwapBE16(value); - return (SDL_RWwrite(dst, &value, (sizeof value), 1)); -} - -size_t -SDL_WriteLE32(SDL_RWops * dst, Uint32 value) -{ - value = SDL_SwapLE32(value); - return (SDL_RWwrite(dst, &value, (sizeof value), 1)); -} - -size_t -SDL_WriteBE32(SDL_RWops * dst, Uint32 value) -{ - value = SDL_SwapBE32(value); - return (SDL_RWwrite(dst, &value, (sizeof value), 1)); -} - -size_t -SDL_WriteLE64(SDL_RWops * dst, Uint64 value) -{ - value = SDL_SwapLE64(value); - return (SDL_RWwrite(dst, &value, (sizeof value), 1)); -} - -size_t -SDL_WriteBE64(SDL_RWops * dst, Uint64 value) -{ - value = SDL_SwapBE64(value); - return (SDL_RWwrite(dst, &value, (sizeof value), 1)); -} - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +/* Need this so Linux systems define fseek64o, ftell64o and off64_t */ +#define _LARGEFILE64_SOURCE +#include "SDL_config.h" + +#if defined(__WIN32__) +#include "../core/windows/SDL_windows.h" +#endif + + +/* This file provides a general interface for SDL to read and write + data sources. It can easily be extended to files, memory, etc. +*/ + +#include "SDL_endian.h" +#include "SDL_rwops.h" + +#ifdef __APPLE__ +#include "cocoa/SDL_rwopsbundlesupport.h" +#endif /* __APPLE__ */ + +#ifdef ANDROID +#include "../core/android/SDL_android.h" +#include "SDL_system.h" +#endif + +#ifdef __WIN32__ + +/* Functions to read/write Win32 API file pointers */ + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER 0xFFFFFFFF +#endif + +#define READAHEAD_BUFFER_SIZE 1024 + +static int SDLCALL +windows_file_open(SDL_RWops * context, const char *filename, const char *mode) +{ + UINT old_error_mode; + HANDLE h; + DWORD r_right, w_right; + DWORD must_exist, truncate; + int a_mode; + + if (!context) + return -1; /* failed (invalid call) */ + + context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */ + context->hidden.windowsio.buffer.data = NULL; + context->hidden.windowsio.buffer.size = 0; + context->hidden.windowsio.buffer.left = 0; + + /* "r" = reading, file must exist */ + /* "w" = writing, truncate existing, file may not exist */ + /* "r+"= reading or writing, file must exist */ + /* "a" = writing, append file may not exist */ + /* "a+"= append + read, file may not exist */ + /* "w+" = read, write, truncate. file may not exist */ + + must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0; + truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0; + r_right = (SDL_strchr(mode, '+') != NULL + || must_exist) ? GENERIC_READ : 0; + a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0; + w_right = (a_mode || SDL_strchr(mode, '+') + || truncate) ? GENERIC_WRITE : 0; + + if (!r_right && !w_right) /* inconsistent mode */ + return -1; /* failed (invalid call) */ + + context->hidden.windowsio.buffer.data = + (char *) SDL_malloc(READAHEAD_BUFFER_SIZE); + if (!context->hidden.windowsio.buffer.data) { + return SDL_OutOfMemory(); + } + /* Do not open a dialog box if failure */ + old_error_mode = + SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + + { + LPTSTR tstr = WIN_UTF8ToString(filename); + h = CreateFile(tstr, (w_right | r_right), + (w_right) ? 0 : FILE_SHARE_READ, NULL, + (must_exist | truncate | a_mode), + FILE_ATTRIBUTE_NORMAL, NULL); + SDL_free(tstr); + } + + /* restore old behavior */ + SetErrorMode(old_error_mode); + + if (h == INVALID_HANDLE_VALUE) { + SDL_free(context->hidden.windowsio.buffer.data); + context->hidden.windowsio.buffer.data = NULL; + SDL_SetError("Couldn't open %s", filename); + return -2; /* failed (CreateFile) */ + } + context->hidden.windowsio.h = h; + context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE; + + return 0; /* ok */ +} + +static Sint64 SDLCALL +windows_file_size(SDL_RWops * context) +{ + LARGE_INTEGER size; + + if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) { + return SDL_SetError("windows_file_size: invalid context/file not opened"); + } + + if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) { + return WIN_SetError("windows_file_size"); + } + + return size.QuadPart; +} + +static Sint64 SDLCALL +windows_file_seek(SDL_RWops * context, Sint64 offset, int whence) +{ + DWORD windowswhence; + LARGE_INTEGER windowsoffset; + + if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) { + return SDL_SetError("windows_file_seek: invalid context/file not opened"); + } + + /* FIXME: We may be able to satisfy the seek within buffered data */ + if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) { + offset -= (long)context->hidden.windowsio.buffer.left; + } + context->hidden.windowsio.buffer.left = 0; + + switch (whence) { + case RW_SEEK_SET: + windowswhence = FILE_BEGIN; + break; + case RW_SEEK_CUR: + windowswhence = FILE_CURRENT; + break; + case RW_SEEK_END: + windowswhence = FILE_END; + break; + default: + return SDL_SetError("windows_file_seek: Unknown value for 'whence'"); + } + + windowsoffset.QuadPart = offset; + if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) { + return WIN_SetError("windows_file_seek"); + } + return windowsoffset.QuadPart; +} + +static size_t SDLCALL +windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum) +{ + size_t total_need; + size_t total_read = 0; + size_t read_ahead; + DWORD byte_read; + + total_need = size * maxnum; + + if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE + || !total_need) + return 0; + + if (context->hidden.windowsio.buffer.left > 0) { + void *data = (char *) context->hidden.windowsio.buffer.data + + context->hidden.windowsio.buffer.size - + context->hidden.windowsio.buffer.left; + read_ahead = + SDL_min(total_need, context->hidden.windowsio.buffer.left); + SDL_memcpy(ptr, data, read_ahead); + context->hidden.windowsio.buffer.left -= read_ahead; + + if (read_ahead == total_need) { + return maxnum; + } + ptr = (char *) ptr + read_ahead; + total_need -= read_ahead; + total_read += read_ahead; + } + + if (total_need < READAHEAD_BUFFER_SIZE) { + if (!ReadFile + (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data, + READAHEAD_BUFFER_SIZE, &byte_read, NULL)) { + SDL_Error(SDL_EFREAD); + return 0; + } + read_ahead = SDL_min(total_need, (int) byte_read); + SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead); + context->hidden.windowsio.buffer.size = byte_read; + context->hidden.windowsio.buffer.left = byte_read - read_ahead; + total_read += read_ahead; + } else { + if (!ReadFile + (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) { + SDL_Error(SDL_EFREAD); + return 0; + } + total_read += byte_read; + } + return (total_read / size); +} + +static size_t SDLCALL +windows_file_write(SDL_RWops * context, const void *ptr, size_t size, + size_t num) +{ + + size_t total_bytes; + DWORD byte_written; + size_t nwritten; + + total_bytes = size * num; + + if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE + || total_bytes <= 0 || !size) + return 0; + + if (context->hidden.windowsio.buffer.left) { + SetFilePointer(context->hidden.windowsio.h, + -(LONG)context->hidden.windowsio.buffer.left, NULL, + FILE_CURRENT); + context->hidden.windowsio.buffer.left = 0; + } + + /* if in append mode, we must go to the EOF before write */ + if (context->hidden.windowsio.append) { + if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) == + INVALID_SET_FILE_POINTER) { + SDL_Error(SDL_EFWRITE); + return 0; + } + } + + if (!WriteFile + (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) { + SDL_Error(SDL_EFWRITE); + return 0; + } + + nwritten = byte_written / size; + return nwritten; +} + +static int SDLCALL +windows_file_close(SDL_RWops * context) +{ + + if (context) { + if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) { + CloseHandle(context->hidden.windowsio.h); + context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */ + } + SDL_free(context->hidden.windowsio.buffer.data); + context->hidden.windowsio.buffer.data = NULL; + SDL_FreeRW(context); + } + return (0); +} +#endif /* __WIN32__ */ + +#ifdef HAVE_STDIO_H + +/* Functions to read/write stdio file pointers */ + +static Sint64 SDLCALL +stdio_size(SDL_RWops * context) +{ + Sint64 pos, size; + + pos = SDL_RWseek(context, 0, RW_SEEK_CUR); + if (pos < 0) { + return -1; + } + size = SDL_RWseek(context, 0, RW_SEEK_END); + + SDL_RWseek(context, pos, RW_SEEK_SET); + return size; +} + +static Sint64 SDLCALL +stdio_seek(SDL_RWops * context, Sint64 offset, int whence) +{ +#ifdef HAVE_FSEEKO64 + if (fseeko64(context->hidden.stdio.fp, (off64_t)offset, whence) == 0) { + return ftello64(context->hidden.stdio.fp); + } +#elif defined(HAVE_FSEEKO) + if (fseeko(context->hidden.stdio.fp, (off_t)offset, whence) == 0) { + return ftello(context->hidden.stdio.fp); + } +#elif defined(HAVE__FSEEKI64) + if (_fseeki64(context->hidden.stdio.fp, offset, whence) == 0) { + return _ftelli64(context->hidden.stdio.fp); + } +#else + if (fseek(context->hidden.stdio.fp, offset, whence) == 0) { + return (ftell(context->hidden.stdio.fp)); + } +#endif + return SDL_Error(SDL_EFSEEK); +} + +static size_t SDLCALL +stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum) +{ + size_t nread; + + nread = fread(ptr, size, maxnum, context->hidden.stdio.fp); + if (nread == 0 && ferror(context->hidden.stdio.fp)) { + SDL_Error(SDL_EFREAD); + } + return (nread); +} + +static size_t SDLCALL +stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num) +{ + size_t nwrote; + + nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp); + if (nwrote == 0 && ferror(context->hidden.stdio.fp)) { + SDL_Error(SDL_EFWRITE); + } + return (nwrote); +} + +static int SDLCALL +stdio_close(SDL_RWops * context) +{ + int status = 0; + if (context) { + if (context->hidden.stdio.autoclose) { + /* WARNING: Check the return value here! */ + if (fclose(context->hidden.stdio.fp) != 0) { + status = SDL_Error(SDL_EFWRITE); + } + } + SDL_FreeRW(context); + } + return status; +} +#endif /* !HAVE_STDIO_H */ + +/* Functions to read/write memory pointers */ + +static Sint64 SDLCALL +mem_size(SDL_RWops * context) +{ + return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base); +} + +static Sint64 SDLCALL +mem_seek(SDL_RWops * context, Sint64 offset, int whence) +{ + Uint8 *newpos; + + switch (whence) { + case RW_SEEK_SET: + newpos = context->hidden.mem.base + offset; + break; + case RW_SEEK_CUR: + newpos = context->hidden.mem.here + offset; + break; + case RW_SEEK_END: + newpos = context->hidden.mem.stop + offset; + break; + default: + return SDL_SetError("Unknown value for 'whence'"); + } + if (newpos < context->hidden.mem.base) { + newpos = context->hidden.mem.base; + } + if (newpos > context->hidden.mem.stop) { + newpos = context->hidden.mem.stop; + } + context->hidden.mem.here = newpos; + return (Sint64)(context->hidden.mem.here - context->hidden.mem.base); +} + +static size_t SDLCALL +mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum) +{ + size_t total_bytes; + size_t mem_available; + + total_bytes = (maxnum * size); + if ((maxnum <= 0) || (size <= 0) + || ((total_bytes / maxnum) != (size_t) size)) { + return 0; + } + + mem_available = (context->hidden.mem.stop - context->hidden.mem.here); + if (total_bytes > mem_available) { + total_bytes = mem_available; + } + + SDL_memcpy(ptr, context->hidden.mem.here, total_bytes); + context->hidden.mem.here += total_bytes; + + return (total_bytes / size); +} + +static size_t SDLCALL +mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num) +{ + if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) { + num = (context->hidden.mem.stop - context->hidden.mem.here) / size; + } + SDL_memcpy(context->hidden.mem.here, ptr, num * size); + context->hidden.mem.here += num * size; + return (num); +} + +static size_t SDLCALL +mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num) +{ + SDL_SetError("Can't write to read-only memory"); + return (0); +} + +static int SDLCALL +mem_close(SDL_RWops * context) +{ + if (context) { + SDL_FreeRW(context); + } + return (0); +} + + +/* Functions to create SDL_RWops structures from various data sources */ + +SDL_RWops * +SDL_RWFromFile(const char *file, const char *mode) +{ + SDL_RWops *rwops = NULL; + if (!file || !*file || !mode || !*mode) { + SDL_SetError("SDL_RWFromFile(): No file or no mode specified"); + return NULL; + } +#if defined(ANDROID) +#ifdef HAVE_STDIO_H + /* Try to open the file on the filesystem first */ + if (*file == '/') { + FILE *fp = fopen(file, mode); + if (fp) { + return SDL_RWFromFP(fp, 1); + } + } else { + /* Try opening it from internal storage if it's a relative path */ + char *path; + FILE *fp; + + path = SDL_stack_alloc(char, PATH_MAX); + if (path) { + SDL_snprintf(path, PATH_MAX, "%s/%s", + SDL_AndroidGetInternalStoragePath(), file); + fp = fopen(path, mode); + SDL_stack_free(path); + if (fp) { + return SDL_RWFromFP(fp, 1); + } + } + } +#endif /* HAVE_STDIO_H */ + + /* Try to open the file from the asset system */ + rwops = SDL_AllocRW(); + if (!rwops) + return NULL; /* SDL_SetError already setup by SDL_AllocRW() */ + if (Android_JNI_FileOpen(rwops, file, mode) < 0) { + SDL_FreeRW(rwops); + return NULL; + } + rwops->size = Android_JNI_FileSize; + rwops->seek = Android_JNI_FileSeek; + rwops->read = Android_JNI_FileRead; + rwops->write = Android_JNI_FileWrite; + rwops->close = Android_JNI_FileClose; + rwops->type = SDL_RWOPS_JNIFILE; + +#elif defined(__WIN32__) + rwops = SDL_AllocRW(); + if (!rwops) + return NULL; /* SDL_SetError already setup by SDL_AllocRW() */ + if (windows_file_open(rwops, file, mode) < 0) { + SDL_FreeRW(rwops); + return NULL; + } + rwops->size = windows_file_size; + rwops->seek = windows_file_seek; + rwops->read = windows_file_read; + rwops->write = windows_file_write; + rwops->close = windows_file_close; + rwops->type = SDL_RWOPS_WINFILE; + +#elif HAVE_STDIO_H + { + #ifdef __APPLE__ + FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode); + #elif __WINRT__ + FILE *fp = NULL; + fopen_s(&fp, file, mode); + #else + FILE *fp = fopen(file, mode); + #endif + if (fp == NULL) { + SDL_SetError("Couldn't open %s", file); + } else { + rwops = SDL_RWFromFP(fp, 1); + } + } +#else + SDL_SetError("SDL not compiled with stdio support"); +#endif /* !HAVE_STDIO_H */ + + return (rwops); +} + +#ifdef HAVE_STDIO_H +SDL_RWops * +SDL_RWFromFP(FILE * fp, SDL_bool autoclose) +{ + SDL_RWops *rwops = NULL; + + rwops = SDL_AllocRW(); + if (rwops != NULL) { + rwops->size = stdio_size; + rwops->seek = stdio_seek; + rwops->read = stdio_read; + rwops->write = stdio_write; + rwops->close = stdio_close; + rwops->hidden.stdio.fp = fp; + rwops->hidden.stdio.autoclose = autoclose; + rwops->type = SDL_RWOPS_STDFILE; + } + return (rwops); +} +#else +SDL_RWops * +SDL_RWFromFP(void * fp, SDL_bool autoclose) +{ + SDL_SetError("SDL not compiled with stdio support"); + return NULL; +} +#endif /* HAVE_STDIO_H */ + +SDL_RWops * +SDL_RWFromMem(void *mem, int size) +{ + SDL_RWops *rwops = NULL; + if (!mem) { + SDL_InvalidParamError("mem"); + return (rwops); + } + if (!size) { + SDL_InvalidParamError("size"); + return (rwops); + } + + rwops = SDL_AllocRW(); + if (rwops != NULL) { + rwops->size = mem_size; + rwops->seek = mem_seek; + rwops->read = mem_read; + rwops->write = mem_write; + rwops->close = mem_close; + rwops->hidden.mem.base = (Uint8 *) mem; + rwops->hidden.mem.here = rwops->hidden.mem.base; + rwops->hidden.mem.stop = rwops->hidden.mem.base + size; + rwops->type = SDL_RWOPS_MEMORY; + } + return (rwops); +} + +SDL_RWops * +SDL_RWFromConstMem(const void *mem, int size) +{ + SDL_RWops *rwops = NULL; + if (!mem) { + SDL_InvalidParamError("mem"); + return (rwops); + } + if (!size) { + SDL_InvalidParamError("size"); + return (rwops); + } + + rwops = SDL_AllocRW(); + if (rwops != NULL) { + rwops->size = mem_size; + rwops->seek = mem_seek; + rwops->read = mem_read; + rwops->write = mem_writeconst; + rwops->close = mem_close; + rwops->hidden.mem.base = (Uint8 *) mem; + rwops->hidden.mem.here = rwops->hidden.mem.base; + rwops->hidden.mem.stop = rwops->hidden.mem.base + size; + rwops->type = SDL_RWOPS_MEMORY_RO; + } + return (rwops); +} + +SDL_RWops * +SDL_AllocRW(void) +{ + SDL_RWops *area; + + area = (SDL_RWops *) SDL_malloc(sizeof *area); + if (area == NULL) { + SDL_OutOfMemory(); + } else { + area->type = SDL_RWOPS_UNKNOWN; + } + return (area); +} + +void +SDL_FreeRW(SDL_RWops * area) +{ + SDL_free(area); +} + +/* Functions for dynamically reading and writing endian-specific values */ + +Uint8 +SDL_ReadU8(SDL_RWops * src) +{ + Uint8 value = 0; + + SDL_RWread(src, &value, (sizeof value), 1); + return value; +} + +Uint16 +SDL_ReadLE16(SDL_RWops * src) +{ + Uint16 value = 0; + + SDL_RWread(src, &value, (sizeof value), 1); + return (SDL_SwapLE16(value)); +} + +Uint16 +SDL_ReadBE16(SDL_RWops * src) +{ + Uint16 value = 0; + + SDL_RWread(src, &value, (sizeof value), 1); + return (SDL_SwapBE16(value)); +} + +Uint32 +SDL_ReadLE32(SDL_RWops * src) +{ + Uint32 value = 0; + + SDL_RWread(src, &value, (sizeof value), 1); + return (SDL_SwapLE32(value)); +} + +Uint32 +SDL_ReadBE32(SDL_RWops * src) +{ + Uint32 value = 0; + + SDL_RWread(src, &value, (sizeof value), 1); + return (SDL_SwapBE32(value)); +} + +Uint64 +SDL_ReadLE64(SDL_RWops * src) +{ + Uint64 value = 0; + + SDL_RWread(src, &value, (sizeof value), 1); + return (SDL_SwapLE64(value)); +} + +Uint64 +SDL_ReadBE64(SDL_RWops * src) +{ + Uint64 value = 0; + + SDL_RWread(src, &value, (sizeof value), 1); + return (SDL_SwapBE64(value)); +} + +size_t +SDL_WriteU8(SDL_RWops * dst, Uint8 value) +{ + return (SDL_RWwrite(dst, &value, (sizeof value), 1)); +} + +size_t +SDL_WriteLE16(SDL_RWops * dst, Uint16 value) +{ + value = SDL_SwapLE16(value); + return (SDL_RWwrite(dst, &value, (sizeof value), 1)); +} + +size_t +SDL_WriteBE16(SDL_RWops * dst, Uint16 value) +{ + value = SDL_SwapBE16(value); + return (SDL_RWwrite(dst, &value, (sizeof value), 1)); +} + +size_t +SDL_WriteLE32(SDL_RWops * dst, Uint32 value) +{ + value = SDL_SwapLE32(value); + return (SDL_RWwrite(dst, &value, (sizeof value), 1)); +} + +size_t +SDL_WriteBE32(SDL_RWops * dst, Uint32 value) +{ + value = SDL_SwapBE32(value); + return (SDL_RWwrite(dst, &value, (sizeof value), 1)); +} + +size_t +SDL_WriteLE64(SDL_RWops * dst, Uint64 value) +{ + value = SDL_SwapLE64(value); + return (SDL_RWwrite(dst, &value, (sizeof value), 1)); +} + +size_t +SDL_WriteBE64(SDL_RWops * dst, Uint64 value) +{ + value = SDL_SwapBE64(value); + return (SDL_RWwrite(dst, &value, (sizeof value), 1)); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/filesystem/winrt/SDL_sysfilesystem.cpp b/src/filesystem/winrt/SDL_sysfilesystem.cpp index 2e9f7e710a8e8..53dbaebe8e661 100644 --- a/src/filesystem/winrt/SDL_sysfilesystem.cpp +++ b/src/filesystem/winrt/SDL_sysfilesystem.cpp @@ -1,154 +1,154 @@ -/* TODO, WinRT: include copyright info in SDL_winrtpaths.cpp - TODO, WinRT: remove the need to compile this with C++/CX (/ZW) extensions, and if possible, without C++ at all -*/ - -#include "SDL_config.h" - -#ifdef __WINRT__ - -extern "C" { -#include "SDL_filesystem.h" -#include "SDL_error.h" -#include "SDL_stdinc.h" -#include "SDL_system.h" -#include "../../core/windows/SDL_windows.h" -} - -#include -#include - -using namespace std; -using namespace Windows::Storage; - -extern "C" const wchar_t * -SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType) -{ - switch (pathType) { - case SDL_WINRT_PATH_INSTALLED_LOCATION: - { - static wstring path; - if (path.empty()) { - path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data(); - } - return path.c_str(); - } - - case SDL_WINRT_PATH_LOCAL_FOLDER: - { - static wstring path; - if (path.empty()) { - path = ApplicationData::Current->LocalFolder->Path->Data(); - } - return path.c_str(); - } - -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP - case SDL_WINRT_PATH_ROAMING_FOLDER: - { - static wstring path; - if (path.empty()) { - path = ApplicationData::Current->RoamingFolder->Path->Data(); - } - return path.c_str(); - } - - case SDL_WINRT_PATH_TEMP_FOLDER: - { - static wstring path; - if (path.empty()) { - path = ApplicationData::Current->TemporaryFolder->Path->Data(); - } - return path.c_str(); - } -#endif - - default: - break; - } - - SDL_Unsupported(); - return NULL; -} - -extern "C" const char * -SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType) -{ - typedef unordered_map UTF8PathMap; - static UTF8PathMap utf8Paths; - - UTF8PathMap::iterator searchResult = utf8Paths.find(pathType); - if (searchResult != utf8Paths.end()) { - return searchResult->second.c_str(); - } - - const wchar_t * ucs2Path = SDL_WinRTGetFSPathUNICODE(pathType); - if (!ucs2Path) { - return NULL; - } - - char * utf8Path = WIN_StringToUTF8(ucs2Path); - utf8Paths[pathType] = utf8Path; - SDL_free(utf8Path); - return utf8Paths[pathType].c_str(); -} - -extern "C" char * -SDL_GetBasePath(void) -{ - const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_INSTALLED_LOCATION); - size_t destPathLen; - char * destPath = NULL; - - if (!srcPath) { - SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError()); - return NULL; - } - - destPathLen = SDL_strlen(srcPath) + 2; - destPath = (char *) SDL_malloc(destPathLen); - if (!destPath) { - SDL_OutOfMemory(); - return NULL; - } - - SDL_snprintf(destPath, destPathLen, "%s\\", srcPath); - return destPath; -} - -extern "C" char * -SDL_GetPrefPath(const char *org, const char *app) -{ - /* WinRT note: The 'SHGetFolderPath' API that is used in Windows 7 and - * earlier is not available on WinRT or Windows Phone. WinRT provides - * a similar API, but SHGetFolderPath can't be called, at least not - * without violating Microsoft's app-store requirements. - */ - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - /* A 'Roaming' folder is not available in Windows Phone 8, however a 'Local' folder is. */ - const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_LOCAL_FOLDER); -#else - /* A 'Roaming' folder is available on Windows 8 and 8.1. Use that. */ - const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_ROAMING_FOLDER); -#endif - - size_t destPathLen; - char * destPath = NULL; - - if (!srcPath) { - SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError()); - return NULL; - } - - destPathLen = SDL_strlen(srcPath) + SDL_strlen(org) + SDL_strlen(app) + 4; - destPath = (char *) SDL_malloc(destPathLen); - if (!destPath) { - SDL_OutOfMemory(); - return NULL; - } - - SDL_snprintf(destPath, destPathLen, "%s\\%s\\%s\\", srcPath, org, app); - return destPath; -} - -#endif /* __WINRT__ */ +/* TODO, WinRT: include copyright info in SDL_winrtpaths.cpp + TODO, WinRT: remove the need to compile this with C++/CX (/ZW) extensions, and if possible, without C++ at all +*/ + +#include "SDL_config.h" + +#ifdef __WINRT__ + +extern "C" { +#include "SDL_filesystem.h" +#include "SDL_error.h" +#include "SDL_stdinc.h" +#include "SDL_system.h" +#include "../../core/windows/SDL_windows.h" +} + +#include +#include + +using namespace std; +using namespace Windows::Storage; + +extern "C" const wchar_t * +SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType) +{ + switch (pathType) { + case SDL_WINRT_PATH_INSTALLED_LOCATION: + { + static wstring path; + if (path.empty()) { + path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data(); + } + return path.c_str(); + } + + case SDL_WINRT_PATH_LOCAL_FOLDER: + { + static wstring path; + if (path.empty()) { + path = ApplicationData::Current->LocalFolder->Path->Data(); + } + return path.c_str(); + } + +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + case SDL_WINRT_PATH_ROAMING_FOLDER: + { + static wstring path; + if (path.empty()) { + path = ApplicationData::Current->RoamingFolder->Path->Data(); + } + return path.c_str(); + } + + case SDL_WINRT_PATH_TEMP_FOLDER: + { + static wstring path; + if (path.empty()) { + path = ApplicationData::Current->TemporaryFolder->Path->Data(); + } + return path.c_str(); + } +#endif + + default: + break; + } + + SDL_Unsupported(); + return NULL; +} + +extern "C" const char * +SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType) +{ + typedef unordered_map UTF8PathMap; + static UTF8PathMap utf8Paths; + + UTF8PathMap::iterator searchResult = utf8Paths.find(pathType); + if (searchResult != utf8Paths.end()) { + return searchResult->second.c_str(); + } + + const wchar_t * ucs2Path = SDL_WinRTGetFSPathUNICODE(pathType); + if (!ucs2Path) { + return NULL; + } + + char * utf8Path = WIN_StringToUTF8(ucs2Path); + utf8Paths[pathType] = utf8Path; + SDL_free(utf8Path); + return utf8Paths[pathType].c_str(); +} + +extern "C" char * +SDL_GetBasePath(void) +{ + const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_INSTALLED_LOCATION); + size_t destPathLen; + char * destPath = NULL; + + if (!srcPath) { + SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError()); + return NULL; + } + + destPathLen = SDL_strlen(srcPath) + 2; + destPath = (char *) SDL_malloc(destPathLen); + if (!destPath) { + SDL_OutOfMemory(); + return NULL; + } + + SDL_snprintf(destPath, destPathLen, "%s\\", srcPath); + return destPath; +} + +extern "C" char * +SDL_GetPrefPath(const char *org, const char *app) +{ + /* WinRT note: The 'SHGetFolderPath' API that is used in Windows 7 and + * earlier is not available on WinRT or Windows Phone. WinRT provides + * a similar API, but SHGetFolderPath can't be called, at least not + * without violating Microsoft's app-store requirements. + */ + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + /* A 'Roaming' folder is not available in Windows Phone 8, however a 'Local' folder is. */ + const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_LOCAL_FOLDER); +#else + /* A 'Roaming' folder is available on Windows 8 and 8.1. Use that. */ + const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_ROAMING_FOLDER); +#endif + + size_t destPathLen; + char * destPath = NULL; + + if (!srcPath) { + SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError()); + return NULL; + } + + destPathLen = SDL_strlen(srcPath) + SDL_strlen(org) + SDL_strlen(app) + 4; + destPath = (char *) SDL_malloc(destPathLen); + if (!destPath) { + SDL_OutOfMemory(); + return NULL; + } + + SDL_snprintf(destPath, destPathLen, "%s\\%s\\%s\\", srcPath, org, app); + return destPath; +} + +#endif /* __WINRT__ */ diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index f739c5706f1f6..f1f469c981d79 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -1,1247 +1,1247 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_config.h" - -/* This is the game controller API for Simple DirectMedia Layer */ - -#include "SDL_events.h" -#include "SDL_assert.h" -#include "SDL_sysjoystick.h" -#include "SDL_hints.h" -#include "SDL_gamecontrollerdb.h" - -#if !SDL_EVENTS_DISABLED -#include "../events/SDL_events_c.h" -#endif -#define ABS(_x) ((_x) < 0 ? -(_x) : (_x)) - - -/* a list of currently opened game controllers */ -static SDL_GameController *SDL_gamecontrollers = NULL; - -/* keep track of the hat and mask value that transforms this hat movement into a button/axis press */ -struct _SDL_HatMapping -{ - int hat; - Uint8 mask; -}; - -#define k_nMaxReverseEntries 20 - -/** - * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask - * MAX 4 hats supported - */ -#define k_nMaxHatEntries 0x3f + 1 - -/* our in memory mapping db between joystick objects and controller mappings */ -struct _SDL_ControllerMapping -{ - SDL_JoystickGUID guid; - const char *name; - - /* mapping of axis/button id to controller version */ - int axes[SDL_CONTROLLER_AXIS_MAX]; - int buttonasaxis[SDL_CONTROLLER_AXIS_MAX]; - - int buttons[SDL_CONTROLLER_BUTTON_MAX]; - int axesasbutton[SDL_CONTROLLER_BUTTON_MAX]; - struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX]; - - /* reverse mapping, joystick indices to buttons */ - SDL_GameControllerAxis raxes[k_nMaxReverseEntries]; - SDL_GameControllerAxis rbuttonasaxis[k_nMaxReverseEntries]; - - SDL_GameControllerButton rbuttons[k_nMaxReverseEntries]; - SDL_GameControllerButton raxesasbutton[k_nMaxReverseEntries]; - SDL_GameControllerButton rhatasbutton[k_nMaxHatEntries]; - -}; - - -/* our hard coded list of mapping support */ -typedef struct _ControllerMapping_t -{ - SDL_JoystickGUID guid; - char *name; - char *mapping; - struct _ControllerMapping_t *next; -} ControllerMapping_t; - -static ControllerMapping_t *s_pSupportedControllers = NULL; -#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) -static ControllerMapping_t *s_pXInputMapping = NULL; -#endif - -/* The SDL game controller structure */ -struct _SDL_GameController -{ - SDL_Joystick *joystick; /* underlying joystick device */ - int ref_count; - Uint8 hatState[4]; /* the current hat state for this controller */ - struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */ - struct _SDL_GameController *next; /* pointer to next game controller we have allocated */ -}; - - -int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value); -int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state); - -/* - * Event filter to fire controller events from joystick ones - */ -int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) -{ - switch( event->type ) - { - case SDL_JOYAXISMOTION: - { - SDL_GameController *controllerlist; - - if ( event->jaxis.axis >= k_nMaxReverseEntries ) break; - - controllerlist = SDL_gamecontrollers; - while ( controllerlist ) - { - if ( controllerlist->joystick->instance_id == event->jaxis.which ) - { - if ( controllerlist->mapping.raxes[event->jaxis.axis] >= 0 ) /* simple axis to axis, send it through */ - { - SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis]; - Sint16 value = event->jaxis.value; - switch (axis) - { - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: - /* Shift it to be 0 - 32767. */ - value = value / 2 + 16384; - default: - break; - } - SDL_PrivateGameControllerAxis( controllerlist, axis, value ); - } - else if ( controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0 ) /* simulate an axis as a button */ - { - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED ); - } - break; - } - controllerlist = controllerlist->next; - } - } - break; - case SDL_JOYBUTTONDOWN: - case SDL_JOYBUTTONUP: - { - SDL_GameController *controllerlist; - - if ( event->jbutton.button >= k_nMaxReverseEntries ) break; - - controllerlist = SDL_gamecontrollers; - while ( controllerlist ) - { - if ( controllerlist->joystick->instance_id == event->jbutton.which ) - { - if ( controllerlist->mapping.rbuttons[event->jbutton.button] >= 0 ) /* simple button as button */ - { - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state ); - } - else if ( controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0 ) /* an button pretending to be an axis */ - { - SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0 ); - } - break; - } - controllerlist = controllerlist->next; - } - } - break; - case SDL_JOYHATMOTION: - { - SDL_GameController *controllerlist; - - if ( event->jhat.hat >= 4 ) break; - - controllerlist = SDL_gamecontrollers; - while ( controllerlist ) - { - if ( controllerlist->joystick->instance_id == event->jhat.which ) - { - Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value; - /* Get list of removed bits (button release) */ - Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame; - /* the hat idx in the high nibble */ - int bHighHat = event->jhat.hat << 4; - - if ( bChanged & SDL_HAT_DOWN ) - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED ); - if ( bChanged & SDL_HAT_UP ) - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED ); - if ( bChanged & SDL_HAT_LEFT ) - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED ); - if ( bChanged & SDL_HAT_RIGHT ) - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED ); - - /* Get list of added bits (button press) */ - bChanged = event->jhat.value ^ bSame; - - if ( bChanged & SDL_HAT_DOWN ) - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED ); - if ( bChanged & SDL_HAT_UP ) - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED ); - if ( bChanged & SDL_HAT_LEFT ) - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED ); - if ( bChanged & SDL_HAT_RIGHT ) - SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED ); - - /* update our state cache */ - controllerlist->hatState[event->jhat.hat] = event->jhat.value; - - break; - } - controllerlist = controllerlist->next; - } - } - break; - case SDL_JOYDEVICEADDED: - { - if ( SDL_IsGameController(event->jdevice.which ) ) - { - SDL_Event deviceevent; - deviceevent.type = SDL_CONTROLLERDEVICEADDED; - deviceevent.cdevice.which = event->jdevice.which; - SDL_PushEvent(&deviceevent); - } - } - break; - case SDL_JOYDEVICEREMOVED: - { - SDL_GameController *controllerlist = SDL_gamecontrollers; - while ( controllerlist ) - { - if ( controllerlist->joystick->instance_id == event->jdevice.which ) - { - SDL_Event deviceevent; - deviceevent.type = SDL_CONTROLLERDEVICEREMOVED; - deviceevent.cdevice.which = event->jdevice.which; - SDL_PushEvent(&deviceevent); - break; - } - controllerlist = controllerlist->next; - } - } - break; - default: - break; - } - - return 1; -} - -/* - * Helper function to scan the mappings database for a controller with the specified GUID - */ -ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid) -{ - ControllerMapping_t *pSupportedController = s_pSupportedControllers; - while ( pSupportedController ) - { - if ( !SDL_memcmp( guid, &pSupportedController->guid, sizeof(*guid) ) ) - { - return pSupportedController; - } - pSupportedController = pSupportedController->next; - } - return NULL; -} - -/* - * Helper function to determine pre-calculated offset to certain joystick mappings - */ -ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) -{ -#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) - if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping ) - { - return s_pXInputMapping; - } - else -#endif - { - SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index ); - return SDL_PrivateGetControllerMappingForGUID(&jGUID); - } -} - -static const char* map_StringForControllerAxis[] = { - "leftx", - "lefty", - "rightx", - "righty", - "lefttrigger", - "righttrigger", - NULL -}; - -/* - * convert a string to its enum equivalent - */ -SDL_GameControllerAxis SDL_GameControllerGetAxisFromString( const char *pchString ) -{ - int entry; - if ( !pchString || !pchString[0] ) - return SDL_CONTROLLER_AXIS_INVALID; - - for ( entry = 0; map_StringForControllerAxis[entry]; ++entry) - { - if ( !SDL_strcasecmp( pchString, map_StringForControllerAxis[entry] ) ) - return entry; - } - return SDL_CONTROLLER_AXIS_INVALID; -} - -/* - * convert an enum to its string equivalent - */ -const char* SDL_GameControllerGetStringForAxis( SDL_GameControllerAxis axis ) -{ - if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) - { - return map_StringForControllerAxis[axis]; - } - return NULL; -} - -static const char* map_StringForControllerButton[] = { - "a", - "b", - "x", - "y", - "back", - "guide", - "start", - "leftstick", - "rightstick", - "leftshoulder", - "rightshoulder", - "dpup", - "dpdown", - "dpleft", - "dpright", - NULL -}; - -/* - * convert a string to its enum equivalent - */ -SDL_GameControllerButton SDL_GameControllerGetButtonFromString( const char *pchString ) -{ - int entry; - if ( !pchString || !pchString[0] ) - return SDL_CONTROLLER_BUTTON_INVALID; - - for ( entry = 0; map_StringForControllerButton[entry]; ++entry) - { - if ( !SDL_strcasecmp( pchString, map_StringForControllerButton[entry] ) ) - return entry; - } - return SDL_CONTROLLER_BUTTON_INVALID; -} - -/* - * convert an enum to its string equivalent - */ -const char* SDL_GameControllerGetStringForButton( SDL_GameControllerButton axis ) -{ - if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) - { - return map_StringForControllerButton[axis]; - } - return NULL; -} - -/* - * given a controller button name and a joystick name update our mapping structure with it - */ -void SDL_PrivateGameControllerParseButton( const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping ) -{ - int iSDLButton = 0; - SDL_GameControllerButton button; - SDL_GameControllerAxis axis; - button = SDL_GameControllerGetButtonFromString( szGameButton ); - axis = SDL_GameControllerGetAxisFromString( szGameButton ); - iSDLButton = SDL_atoi( &szJoystickButton[1] ); - - if ( szJoystickButton[0] == 'a' ) - { - if ( iSDLButton >= k_nMaxReverseEntries ) - { - SDL_SetError("Axis index too large: %d", iSDLButton ); - return; - } - if ( axis != SDL_CONTROLLER_AXIS_INVALID ) - { - pMapping->axes[ axis ] = iSDLButton; - pMapping->raxes[ iSDLButton ] = axis; - } - else if ( button != SDL_CONTROLLER_BUTTON_INVALID ) - { - pMapping->axesasbutton[ button ] = iSDLButton; - pMapping->raxesasbutton[ iSDLButton ] = button; - } - else - { - SDL_assert( !"How did we get here?" ); - } - - } - else if ( szJoystickButton[0] == 'b' ) - { - if ( iSDLButton >= k_nMaxReverseEntries ) - { - SDL_SetError("Button index too large: %d", iSDLButton ); - return; - } - if ( button != SDL_CONTROLLER_BUTTON_INVALID ) - { - pMapping->buttons[ button ] = iSDLButton; - pMapping->rbuttons[ iSDLButton ] = button; - } - else if ( axis != SDL_CONTROLLER_AXIS_INVALID ) - { - pMapping->buttonasaxis[ axis ] = iSDLButton; - pMapping->rbuttonasaxis[ iSDLButton ] = axis; - } - else - { - SDL_assert( !"How did we get here?" ); - } - } - else if ( szJoystickButton[0] == 'h' ) - { - int hat = SDL_atoi( &szJoystickButton[1] ); - int mask = SDL_atoi( &szJoystickButton[3] ); - if (hat >= 4) { - SDL_SetError("Hat index too large: %d", iSDLButton ); - } - - if ( button != SDL_CONTROLLER_BUTTON_INVALID ) - { - int ridx; - pMapping->hatasbutton[ button ].hat = hat; - pMapping->hatasbutton[ button ].mask = mask; - ridx = (hat << 4) | mask; - pMapping->rhatasbutton[ ridx ] = button; - } - else if ( axis != SDL_CONTROLLER_AXIS_INVALID ) - { - SDL_assert( !"Support hat as axis" ); - } - else - { - SDL_assert( !"How did we get here?" ); - } - } -} - - -/* - * given a controller mapping string update our mapping object - */ -static void -SDL_PrivateGameControllerParseControllerConfigString( struct _SDL_ControllerMapping *pMapping, const char *pchString ) -{ - char szGameButton[20]; - char szJoystickButton[20]; - SDL_bool bGameButton = SDL_TRUE; - int i = 0; - const char *pchPos = pchString; - - SDL_memset( szGameButton, 0x0, sizeof(szGameButton) ); - SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) ); - - while ( pchPos && *pchPos ) - { - if ( *pchPos == ':' ) - { - i = 0; - bGameButton = SDL_FALSE; - } - else if ( *pchPos == ' ' ) - { - - } - else if ( *pchPos == ',' ) - { - i = 0; - bGameButton = SDL_TRUE; - SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping ); - SDL_memset( szGameButton, 0x0, sizeof(szGameButton) ); - SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) ); - - } - else if ( bGameButton ) - { - if ( i >= sizeof(szGameButton)) - { - SDL_SetError( "Button name too large: %s", szGameButton ); - return; - } - szGameButton[i] = *pchPos; - i++; - } - else - { - if ( i >= sizeof(szJoystickButton)) - { - SDL_SetError( "Joystick button name too large: %s", szJoystickButton ); - return; - } - szJoystickButton[i] = *pchPos; - i++; - } - pchPos++; - } - - SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping ); - -} - -/* - * Make a new button mapping struct - */ -void SDL_PrivateLoadButtonMapping( struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping ) -{ - int j; - - pMapping->guid = guid; - pMapping->name = pchName; - - /* set all the button mappings to non defaults */ - for ( j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++ ) - { - pMapping->axes[j] = -1; - pMapping->buttonasaxis[j] = -1; - } - for ( j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++ ) - { - pMapping->buttons[j] = -1; - pMapping->axesasbutton[j] = -1; - pMapping->hatasbutton[j].hat = -1; - } - - for ( j = 0; j < k_nMaxReverseEntries; j++ ) - { - pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID; - pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID; - pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID; - pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID; - } - - for (j = 0; j < k_nMaxHatEntries; j++) - { - pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID; - } - - SDL_PrivateGameControllerParseControllerConfigString( pMapping, pchMapping ); -} - - -/* - * grab the guid string from a mapping string - */ -char *SDL_PrivateGetControllerGUIDFromMappingString( const char *pMapping ) -{ - const char *pFirstComma = SDL_strchr( pMapping, ',' ); - if ( pFirstComma ) - { - char *pchGUID = SDL_malloc( pFirstComma - pMapping + 1 ); - if ( !pchGUID ) - { - SDL_OutOfMemory(); - return NULL; - } - SDL_memcpy( pchGUID, pMapping, pFirstComma - pMapping ); - pchGUID[ pFirstComma - pMapping ] = 0; - return pchGUID; - } - return NULL; -} - - -/* - * grab the name string from a mapping string - */ -char *SDL_PrivateGetControllerNameFromMappingString( const char *pMapping ) -{ - const char *pFirstComma, *pSecondComma; - char *pchName; - - pFirstComma = SDL_strchr( pMapping, ',' ); - if ( !pFirstComma ) - return NULL; - - pSecondComma = SDL_strchr( pFirstComma + 1, ',' ); - if ( !pSecondComma ) - return NULL; - - pchName = SDL_malloc( pSecondComma - pFirstComma ); - if ( !pchName ) - { - SDL_OutOfMemory(); - return NULL; - } - SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma ); - pchName[ pSecondComma - pFirstComma - 1 ] = 0; - return pchName; -} - - -/* - * grab the button mapping string from a mapping string - */ -char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping ) -{ - const char *pFirstComma, *pSecondComma; - - pFirstComma = SDL_strchr( pMapping, ',' ); - if ( !pFirstComma ) - return NULL; - - pSecondComma = SDL_strchr( pFirstComma + 1, ',' ); - if ( !pSecondComma ) - return NULL; - - return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */ -} - -void SDL_PrivateGameControllerRefreshMapping( ControllerMapping_t *pControllerMapping ) -{ - SDL_GameController *gamecontrollerlist = SDL_gamecontrollers; - while ( gamecontrollerlist ) - { - if ( !SDL_memcmp( &gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid) ) ) - { - SDL_Event event; - event.type = SDL_CONTROLLERDEVICEREMAPPED; - event.cdevice.which = gamecontrollerlist->joystick->instance_id; - SDL_PushEvent(&event); - - /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */ - SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping); - } - - gamecontrollerlist = gamecontrollerlist->next; - } -} - -/* - * Add or update an entry into the Mappings Database - */ -int -SDL_GameControllerAddMapping( const char *mappingString ) -{ - char *pchGUID; - char *pchName; - char *pchMapping; - SDL_JoystickGUID jGUID; - ControllerMapping_t *pControllerMapping; -#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) - SDL_bool is_xinput_mapping = SDL_FALSE; -#endif - - pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( mappingString ); - if (!pchGUID) { - return -1; - } -#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) - if ( !SDL_strcasecmp( pchGUID, "xinput" ) ) { - is_xinput_mapping = SDL_TRUE; - } -#endif - jGUID = SDL_JoystickGetGUIDFromString(pchGUID); - SDL_free(pchGUID); - - pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID); - - pchName = SDL_PrivateGetControllerNameFromMappingString( mappingString ); - if (!pchName) return -1; - - pchMapping = SDL_PrivateGetControllerMappingFromMappingString( mappingString ); - if (!pchMapping) { - SDL_free( pchName ); - return -1; - } - - if (pControllerMapping) { - /* Update existing mapping */ - SDL_free( pControllerMapping->name ); - pControllerMapping->name = pchName; - SDL_free( pControllerMapping->mapping ); - pControllerMapping->mapping = pchMapping; - /* refresh open controllers */ - SDL_PrivateGameControllerRefreshMapping( pControllerMapping ); - return 0; - } else { - pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) ); - if (!pControllerMapping) { - SDL_free( pchName ); - SDL_free( pchMapping ); - return SDL_OutOfMemory(); - } -#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) - if ( is_xinput_mapping ) - { - s_pXInputMapping = pControllerMapping; - } -#endif - pControllerMapping->guid = jGUID; - pControllerMapping->name = pchName; - pControllerMapping->mapping = pchMapping; - pControllerMapping->next = s_pSupportedControllers; - s_pSupportedControllers = pControllerMapping; - return 1; - } -} - -/* - * Get the mapping string for this GUID - */ -char * -SDL_GameControllerMappingForGUID( SDL_JoystickGUID guid ) -{ - char *pMappingString = NULL; - ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid); - if (mapping) { - char pchGUID[33]; - size_t needed; - SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID)); - /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ - needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; - pMappingString = SDL_malloc( needed ); - SDL_snprintf( pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping ); - } - return pMappingString; -} - -/* - * Get the mapping string for this device - */ -char * -SDL_GameControllerMapping( SDL_GameController * gamecontroller ) -{ - return SDL_GameControllerMappingForGUID( gamecontroller->mapping.guid ); -} - -static void -SDL_GameControllerLoadHints() -{ - const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG); - if ( hint && hint[0] ) { - size_t nchHints = SDL_strlen( hint ); - char *pUserMappings = SDL_malloc( nchHints + 1 ); - char *pTempMappings = pUserMappings; - SDL_memcpy( pUserMappings, hint, nchHints ); - while ( pUserMappings ) { - char *pchNewLine = NULL; - - pchNewLine = SDL_strchr( pUserMappings, '\n' ); - if ( pchNewLine ) - *pchNewLine = '\0'; - - SDL_GameControllerAddMapping( pUserMappings ); - - if ( pchNewLine ) - pUserMappings = pchNewLine + 1; - else - pUserMappings = NULL; - } - SDL_free(pTempMappings); - } -} - -/* - * Initialize the game controller system, mostly load our DB of controller config mappings - */ -int -SDL_GameControllerInit(void) -{ - int i = 0; - const char *pMappingString = NULL; - s_pSupportedControllers = NULL; - pMappingString = s_ControllerMappings[i]; - while ( pMappingString ) - { - SDL_GameControllerAddMapping( pMappingString ); - - i++; - pMappingString = s_ControllerMappings[i]; - } - - /* load in any user supplied config */ - SDL_GameControllerLoadHints(); - - /* watch for joy events and fire controller ones if needed */ - SDL_AddEventWatch( SDL_GameControllerEventWatcher, NULL ); - - return (0); -} - - -/* - * Get the implementation dependent name of a controller - */ -const char * -SDL_GameControllerNameForIndex(int device_index) -{ - ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); - if ( pSupportedController ) - { - return pSupportedController->name; - } - return NULL; -} - - -/* - * Return 1 if the joystick at this device index is a supported controller - */ -SDL_bool -SDL_IsGameController(int device_index) -{ - ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); - if ( pSupportedController ) - { - return SDL_TRUE; - } - - return SDL_FALSE; -} - -/* - * Open a controller for use - the index passed as an argument refers to - * the N'th controller on the system. This index is the value which will - * identify this controller in future controller events. - * - * This function returns a controller identifier, or NULL if an error occurred. - */ -SDL_GameController * -SDL_GameControllerOpen(int device_index) -{ - SDL_GameController *gamecontroller; - SDL_GameController *gamecontrollerlist; - ControllerMapping_t *pSupportedController = NULL; - - if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) { - SDL_SetError("There are %d joysticks available", SDL_NumJoysticks()); - return (NULL); - } - - gamecontrollerlist = SDL_gamecontrollers; - /* If the controller is already open, return it */ - while ( gamecontrollerlist ) - { - if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) { - gamecontroller = gamecontrollerlist; - ++gamecontroller->ref_count; - return (gamecontroller); - } - gamecontrollerlist = gamecontrollerlist->next; - } - - /* Find a controller mapping */ - pSupportedController = SDL_PrivateGetControllerMapping(device_index); - if ( !pSupportedController ) { - SDL_SetError("Couldn't find mapping for device (%d)", device_index ); - return (NULL); - } - - /* Create and initialize the joystick */ - gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller)); - if (gamecontroller == NULL) { - SDL_OutOfMemory(); - return NULL; - } - - SDL_memset(gamecontroller, 0, (sizeof *gamecontroller)); - gamecontroller->joystick = SDL_JoystickOpen(device_index); - if ( !gamecontroller->joystick ) { - SDL_free(gamecontroller); - return NULL; - } - - SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping ); - - /* Add joystick to list */ - ++gamecontroller->ref_count; - /* Link the joystick in the list */ - gamecontroller->next = SDL_gamecontrollers; - SDL_gamecontrollers = gamecontroller; - - SDL_SYS_JoystickUpdate( gamecontroller->joystick ); - - return (gamecontroller); -} - -/* - * Manually pump for controller updates. - */ -void -SDL_GameControllerUpdate(void) -{ - /* Just for API completeness; the joystick API does all the work. */ - SDL_JoystickUpdate(); -} - - -/* - * Get the current state of an axis control on a controller - */ -Sint16 -SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) -{ - if ( !gamecontroller ) - return 0; - - if (gamecontroller->mapping.axes[axis] >= 0 ) - { - Sint16 value = ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) ); - switch (axis) - { - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: - /* Shift it to be 0 - 32767. */ - value = value / 2 + 16384; - default: - break; - } - return value; - } - else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 ) - { - Uint8 value; - value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] ); - if ( value > 0 ) - return 32767; - return 0; - } - return 0; -} - - -/* - * Get the current state of a button on a controller - */ -Uint8 -SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) -{ - if ( !gamecontroller ) - return 0; - - if ( gamecontroller->mapping.buttons[button] >= 0 ) - { - return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) ); - } - else if ( gamecontroller->mapping.axesasbutton[button] >= 0 ) - { - Sint16 value; - value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] ); - if ( ABS(value) > 32768/2 ) - return 1; - return 0; - } - else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 ) - { - Uint8 value; - value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat ); - - if ( value & gamecontroller->mapping.hatasbutton[button].mask ) - return 1; - return 0; - } - - return 0; -} - -/* - * Return if the joystick in question is currently attached to the system, - * \return 0 if not plugged in, 1 if still present. - */ -SDL_bool -SDL_GameControllerGetAttached( SDL_GameController * gamecontroller ) -{ - if ( !gamecontroller ) - return SDL_FALSE; - - return SDL_JoystickGetAttached(gamecontroller->joystick); -} - - -/* - * Get the number of multi-dimensional axis controls on a joystick - */ -const char * -SDL_GameControllerName(SDL_GameController * gamecontroller) -{ - if ( !gamecontroller ) - return NULL; - - return (gamecontroller->mapping.name); -} - - -/* - * Get the joystick for this controller - */ -SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller) -{ - if ( !gamecontroller ) - return NULL; - - return gamecontroller->joystick; -} - -/** - * Get the SDL joystick layer binding for this controller axis mapping - */ -SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) -{ - SDL_GameControllerButtonBind bind; - SDL_memset( &bind, 0x0, sizeof(bind) ); - - if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID ) - return bind; - - if (gamecontroller->mapping.axes[axis] >= 0 ) - { - bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; - bind.value.button = gamecontroller->mapping.axes[axis]; - } - else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 ) - { - bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; - bind.value.button = gamecontroller->mapping.buttonasaxis[axis]; - } - - return bind; -} - - -/** - * Get the SDL joystick layer binding for this controller button mapping - */ -SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) -{ - SDL_GameControllerButtonBind bind; - SDL_memset( &bind, 0x0, sizeof(bind) ); - - if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID ) - return bind; - - if ( gamecontroller->mapping.buttons[button] >= 0 ) - { - bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; - bind.value.button = gamecontroller->mapping.buttons[button]; - } - else if ( gamecontroller->mapping.axesasbutton[button] >= 0 ) - { - bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; - bind.value.axis = gamecontroller->mapping.axesasbutton[button]; - } - else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 ) - { - bind.bindType = SDL_CONTROLLER_BINDTYPE_HAT; - bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat; - bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask; - } - - return bind; -} - - -/* - * Close a joystick previously opened with SDL_JoystickOpen() - */ -void -SDL_GameControllerClose(SDL_GameController * gamecontroller) -{ - SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev; - - if ( !gamecontroller ) - return; - - /* First decrement ref count */ - if (--gamecontroller->ref_count > 0) { - return; - } - - SDL_JoystickClose( gamecontroller->joystick ); - - gamecontrollerlist = SDL_gamecontrollers; - gamecontrollerlistprev = NULL; - while ( gamecontrollerlist ) - { - if (gamecontroller == gamecontrollerlist) - { - if ( gamecontrollerlistprev ) - { - /* unlink this entry */ - gamecontrollerlistprev->next = gamecontrollerlist->next; - } - else - { - SDL_gamecontrollers = gamecontroller->next; - } - - break; - } - gamecontrollerlistprev = gamecontrollerlist; - gamecontrollerlist = gamecontrollerlist->next; - } - - SDL_free(gamecontroller); -} - - -/* - * Quit the controller subsystem - */ -void -SDL_GameControllerQuit(void) -{ - ControllerMapping_t *pControllerMap; - while ( SDL_gamecontrollers ) - { - SDL_gamecontrollers->ref_count = 1; - SDL_GameControllerClose(SDL_gamecontrollers); - } - - while ( s_pSupportedControllers ) - { - pControllerMap = s_pSupportedControllers; - s_pSupportedControllers = s_pSupportedControllers->next; - SDL_free( pControllerMap->name ); - SDL_free( pControllerMap ); - } - - SDL_DelEventWatch( SDL_GameControllerEventWatcher, NULL ); - -} - -/* - * Event filter to transform joystick events into appropriate game controller ones - */ -int -SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value) -{ - int posted; - - /* translate the event, if desired */ - posted = 0; -#if !SDL_EVENTS_DISABLED - if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) { - SDL_Event event; - event.type = SDL_CONTROLLERAXISMOTION; - event.caxis.which = gamecontroller->joystick->instance_id; - event.caxis.axis = axis; - event.caxis.value = value; - posted = SDL_PushEvent(&event) == 1; - } -#endif /* !SDL_EVENTS_DISABLED */ - return (posted); -} - - -/* - * Event filter to transform joystick events into appropriate game controller ones - */ -int -SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state) -{ - int posted; -#if !SDL_EVENTS_DISABLED - SDL_Event event; - - if ( button == SDL_CONTROLLER_BUTTON_INVALID ) - return (0); - - switch (state) { - case SDL_PRESSED: - event.type = SDL_CONTROLLERBUTTONDOWN; - break; - case SDL_RELEASED: - event.type = SDL_CONTROLLERBUTTONUP; - break; - default: - /* Invalid state -- bail */ - return (0); - } -#endif /* !SDL_EVENTS_DISABLED */ - - /* translate the event, if desired */ - posted = 0; -#if !SDL_EVENTS_DISABLED - if (SDL_GetEventState(event.type) == SDL_ENABLE) { - event.cbutton.which = gamecontroller->joystick->instance_id; - event.cbutton.button = button; - event.cbutton.state = state; - posted = SDL_PushEvent(&event) == 1; - } -#endif /* !SDL_EVENTS_DISABLED */ - return (posted); -} - -/* - * Turn off controller events - */ -int -SDL_GameControllerEventState(int state) -{ -#if SDL_EVENTS_DISABLED - return SDL_IGNORE; -#else - const Uint32 event_list[] = { - SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP, - SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED, - }; - unsigned int i; - - switch (state) { - case SDL_QUERY: - state = SDL_IGNORE; - for (i = 0; i < SDL_arraysize(event_list); ++i) { - state = SDL_EventState(event_list[i], SDL_QUERY); - if (state == SDL_ENABLE) { - break; - } - } - break; - default: - for (i = 0; i < SDL_arraysize(event_list); ++i) { - SDL_EventState(event_list[i], state); - } - break; - } - return (state); -#endif /* SDL_EVENTS_DISABLED */ -} - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +/* This is the game controller API for Simple DirectMedia Layer */ + +#include "SDL_events.h" +#include "SDL_assert.h" +#include "SDL_sysjoystick.h" +#include "SDL_hints.h" +#include "SDL_gamecontrollerdb.h" + +#if !SDL_EVENTS_DISABLED +#include "../events/SDL_events_c.h" +#endif +#define ABS(_x) ((_x) < 0 ? -(_x) : (_x)) + + +/* a list of currently opened game controllers */ +static SDL_GameController *SDL_gamecontrollers = NULL; + +/* keep track of the hat and mask value that transforms this hat movement into a button/axis press */ +struct _SDL_HatMapping +{ + int hat; + Uint8 mask; +}; + +#define k_nMaxReverseEntries 20 + +/** + * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask + * MAX 4 hats supported + */ +#define k_nMaxHatEntries 0x3f + 1 + +/* our in memory mapping db between joystick objects and controller mappings */ +struct _SDL_ControllerMapping +{ + SDL_JoystickGUID guid; + const char *name; + + /* mapping of axis/button id to controller version */ + int axes[SDL_CONTROLLER_AXIS_MAX]; + int buttonasaxis[SDL_CONTROLLER_AXIS_MAX]; + + int buttons[SDL_CONTROLLER_BUTTON_MAX]; + int axesasbutton[SDL_CONTROLLER_BUTTON_MAX]; + struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX]; + + /* reverse mapping, joystick indices to buttons */ + SDL_GameControllerAxis raxes[k_nMaxReverseEntries]; + SDL_GameControllerAxis rbuttonasaxis[k_nMaxReverseEntries]; + + SDL_GameControllerButton rbuttons[k_nMaxReverseEntries]; + SDL_GameControllerButton raxesasbutton[k_nMaxReverseEntries]; + SDL_GameControllerButton rhatasbutton[k_nMaxHatEntries]; + +}; + + +/* our hard coded list of mapping support */ +typedef struct _ControllerMapping_t +{ + SDL_JoystickGUID guid; + char *name; + char *mapping; + struct _ControllerMapping_t *next; +} ControllerMapping_t; + +static ControllerMapping_t *s_pSupportedControllers = NULL; +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) +static ControllerMapping_t *s_pXInputMapping = NULL; +#endif + +/* The SDL game controller structure */ +struct _SDL_GameController +{ + SDL_Joystick *joystick; /* underlying joystick device */ + int ref_count; + Uint8 hatState[4]; /* the current hat state for this controller */ + struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */ + struct _SDL_GameController *next; /* pointer to next game controller we have allocated */ +}; + + +int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value); +int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state); + +/* + * Event filter to fire controller events from joystick ones + */ +int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) +{ + switch( event->type ) + { + case SDL_JOYAXISMOTION: + { + SDL_GameController *controllerlist; + + if ( event->jaxis.axis >= k_nMaxReverseEntries ) break; + + controllerlist = SDL_gamecontrollers; + while ( controllerlist ) + { + if ( controllerlist->joystick->instance_id == event->jaxis.which ) + { + if ( controllerlist->mapping.raxes[event->jaxis.axis] >= 0 ) /* simple axis to axis, send it through */ + { + SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis]; + Sint16 value = event->jaxis.value; + switch (axis) + { + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + /* Shift it to be 0 - 32767. */ + value = value / 2 + 16384; + default: + break; + } + SDL_PrivateGameControllerAxis( controllerlist, axis, value ); + } + else if ( controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0 ) /* simulate an axis as a button */ + { + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED ); + } + break; + } + controllerlist = controllerlist->next; + } + } + break; + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + { + SDL_GameController *controllerlist; + + if ( event->jbutton.button >= k_nMaxReverseEntries ) break; + + controllerlist = SDL_gamecontrollers; + while ( controllerlist ) + { + if ( controllerlist->joystick->instance_id == event->jbutton.which ) + { + if ( controllerlist->mapping.rbuttons[event->jbutton.button] >= 0 ) /* simple button as button */ + { + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state ); + } + else if ( controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0 ) /* an button pretending to be an axis */ + { + SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0 ); + } + break; + } + controllerlist = controllerlist->next; + } + } + break; + case SDL_JOYHATMOTION: + { + SDL_GameController *controllerlist; + + if ( event->jhat.hat >= 4 ) break; + + controllerlist = SDL_gamecontrollers; + while ( controllerlist ) + { + if ( controllerlist->joystick->instance_id == event->jhat.which ) + { + Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value; + /* Get list of removed bits (button release) */ + Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame; + /* the hat idx in the high nibble */ + int bHighHat = event->jhat.hat << 4; + + if ( bChanged & SDL_HAT_DOWN ) + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED ); + if ( bChanged & SDL_HAT_UP ) + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED ); + if ( bChanged & SDL_HAT_LEFT ) + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED ); + if ( bChanged & SDL_HAT_RIGHT ) + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED ); + + /* Get list of added bits (button press) */ + bChanged = event->jhat.value ^ bSame; + + if ( bChanged & SDL_HAT_DOWN ) + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED ); + if ( bChanged & SDL_HAT_UP ) + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED ); + if ( bChanged & SDL_HAT_LEFT ) + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED ); + if ( bChanged & SDL_HAT_RIGHT ) + SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED ); + + /* update our state cache */ + controllerlist->hatState[event->jhat.hat] = event->jhat.value; + + break; + } + controllerlist = controllerlist->next; + } + } + break; + case SDL_JOYDEVICEADDED: + { + if ( SDL_IsGameController(event->jdevice.which ) ) + { + SDL_Event deviceevent; + deviceevent.type = SDL_CONTROLLERDEVICEADDED; + deviceevent.cdevice.which = event->jdevice.which; + SDL_PushEvent(&deviceevent); + } + } + break; + case SDL_JOYDEVICEREMOVED: + { + SDL_GameController *controllerlist = SDL_gamecontrollers; + while ( controllerlist ) + { + if ( controllerlist->joystick->instance_id == event->jdevice.which ) + { + SDL_Event deviceevent; + deviceevent.type = SDL_CONTROLLERDEVICEREMOVED; + deviceevent.cdevice.which = event->jdevice.which; + SDL_PushEvent(&deviceevent); + break; + } + controllerlist = controllerlist->next; + } + } + break; + default: + break; + } + + return 1; +} + +/* + * Helper function to scan the mappings database for a controller with the specified GUID + */ +ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid) +{ + ControllerMapping_t *pSupportedController = s_pSupportedControllers; + while ( pSupportedController ) + { + if ( !SDL_memcmp( guid, &pSupportedController->guid, sizeof(*guid) ) ) + { + return pSupportedController; + } + pSupportedController = pSupportedController->next; + } + return NULL; +} + +/* + * Helper function to determine pre-calculated offset to certain joystick mappings + */ +ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) +{ +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) + if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping ) + { + return s_pXInputMapping; + } + else +#endif + { + SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index ); + return SDL_PrivateGetControllerMappingForGUID(&jGUID); + } +} + +static const char* map_StringForControllerAxis[] = { + "leftx", + "lefty", + "rightx", + "righty", + "lefttrigger", + "righttrigger", + NULL +}; + +/* + * convert a string to its enum equivalent + */ +SDL_GameControllerAxis SDL_GameControllerGetAxisFromString( const char *pchString ) +{ + int entry; + if ( !pchString || !pchString[0] ) + return SDL_CONTROLLER_AXIS_INVALID; + + for ( entry = 0; map_StringForControllerAxis[entry]; ++entry) + { + if ( !SDL_strcasecmp( pchString, map_StringForControllerAxis[entry] ) ) + return entry; + } + return SDL_CONTROLLER_AXIS_INVALID; +} + +/* + * convert an enum to its string equivalent + */ +const char* SDL_GameControllerGetStringForAxis( SDL_GameControllerAxis axis ) +{ + if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX) + { + return map_StringForControllerAxis[axis]; + } + return NULL; +} + +static const char* map_StringForControllerButton[] = { + "a", + "b", + "x", + "y", + "back", + "guide", + "start", + "leftstick", + "rightstick", + "leftshoulder", + "rightshoulder", + "dpup", + "dpdown", + "dpleft", + "dpright", + NULL +}; + +/* + * convert a string to its enum equivalent + */ +SDL_GameControllerButton SDL_GameControllerGetButtonFromString( const char *pchString ) +{ + int entry; + if ( !pchString || !pchString[0] ) + return SDL_CONTROLLER_BUTTON_INVALID; + + for ( entry = 0; map_StringForControllerButton[entry]; ++entry) + { + if ( !SDL_strcasecmp( pchString, map_StringForControllerButton[entry] ) ) + return entry; + } + return SDL_CONTROLLER_BUTTON_INVALID; +} + +/* + * convert an enum to its string equivalent + */ +const char* SDL_GameControllerGetStringForButton( SDL_GameControllerButton axis ) +{ + if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX) + { + return map_StringForControllerButton[axis]; + } + return NULL; +} + +/* + * given a controller button name and a joystick name update our mapping structure with it + */ +void SDL_PrivateGameControllerParseButton( const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping ) +{ + int iSDLButton = 0; + SDL_GameControllerButton button; + SDL_GameControllerAxis axis; + button = SDL_GameControllerGetButtonFromString( szGameButton ); + axis = SDL_GameControllerGetAxisFromString( szGameButton ); + iSDLButton = SDL_atoi( &szJoystickButton[1] ); + + if ( szJoystickButton[0] == 'a' ) + { + if ( iSDLButton >= k_nMaxReverseEntries ) + { + SDL_SetError("Axis index too large: %d", iSDLButton ); + return; + } + if ( axis != SDL_CONTROLLER_AXIS_INVALID ) + { + pMapping->axes[ axis ] = iSDLButton; + pMapping->raxes[ iSDLButton ] = axis; + } + else if ( button != SDL_CONTROLLER_BUTTON_INVALID ) + { + pMapping->axesasbutton[ button ] = iSDLButton; + pMapping->raxesasbutton[ iSDLButton ] = button; + } + else + { + SDL_assert( !"How did we get here?" ); + } + + } + else if ( szJoystickButton[0] == 'b' ) + { + if ( iSDLButton >= k_nMaxReverseEntries ) + { + SDL_SetError("Button index too large: %d", iSDLButton ); + return; + } + if ( button != SDL_CONTROLLER_BUTTON_INVALID ) + { + pMapping->buttons[ button ] = iSDLButton; + pMapping->rbuttons[ iSDLButton ] = button; + } + else if ( axis != SDL_CONTROLLER_AXIS_INVALID ) + { + pMapping->buttonasaxis[ axis ] = iSDLButton; + pMapping->rbuttonasaxis[ iSDLButton ] = axis; + } + else + { + SDL_assert( !"How did we get here?" ); + } + } + else if ( szJoystickButton[0] == 'h' ) + { + int hat = SDL_atoi( &szJoystickButton[1] ); + int mask = SDL_atoi( &szJoystickButton[3] ); + if (hat >= 4) { + SDL_SetError("Hat index too large: %d", iSDLButton ); + } + + if ( button != SDL_CONTROLLER_BUTTON_INVALID ) + { + int ridx; + pMapping->hatasbutton[ button ].hat = hat; + pMapping->hatasbutton[ button ].mask = mask; + ridx = (hat << 4) | mask; + pMapping->rhatasbutton[ ridx ] = button; + } + else if ( axis != SDL_CONTROLLER_AXIS_INVALID ) + { + SDL_assert( !"Support hat as axis" ); + } + else + { + SDL_assert( !"How did we get here?" ); + } + } +} + + +/* + * given a controller mapping string update our mapping object + */ +static void +SDL_PrivateGameControllerParseControllerConfigString( struct _SDL_ControllerMapping *pMapping, const char *pchString ) +{ + char szGameButton[20]; + char szJoystickButton[20]; + SDL_bool bGameButton = SDL_TRUE; + int i = 0; + const char *pchPos = pchString; + + SDL_memset( szGameButton, 0x0, sizeof(szGameButton) ); + SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) ); + + while ( pchPos && *pchPos ) + { + if ( *pchPos == ':' ) + { + i = 0; + bGameButton = SDL_FALSE; + } + else if ( *pchPos == ' ' ) + { + + } + else if ( *pchPos == ',' ) + { + i = 0; + bGameButton = SDL_TRUE; + SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping ); + SDL_memset( szGameButton, 0x0, sizeof(szGameButton) ); + SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) ); + + } + else if ( bGameButton ) + { + if ( i >= sizeof(szGameButton)) + { + SDL_SetError( "Button name too large: %s", szGameButton ); + return; + } + szGameButton[i] = *pchPos; + i++; + } + else + { + if ( i >= sizeof(szJoystickButton)) + { + SDL_SetError( "Joystick button name too large: %s", szJoystickButton ); + return; + } + szJoystickButton[i] = *pchPos; + i++; + } + pchPos++; + } + + SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping ); + +} + +/* + * Make a new button mapping struct + */ +void SDL_PrivateLoadButtonMapping( struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping ) +{ + int j; + + pMapping->guid = guid; + pMapping->name = pchName; + + /* set all the button mappings to non defaults */ + for ( j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++ ) + { + pMapping->axes[j] = -1; + pMapping->buttonasaxis[j] = -1; + } + for ( j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++ ) + { + pMapping->buttons[j] = -1; + pMapping->axesasbutton[j] = -1; + pMapping->hatasbutton[j].hat = -1; + } + + for ( j = 0; j < k_nMaxReverseEntries; j++ ) + { + pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID; + pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID; + pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID; + pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID; + } + + for (j = 0; j < k_nMaxHatEntries; j++) + { + pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID; + } + + SDL_PrivateGameControllerParseControllerConfigString( pMapping, pchMapping ); +} + + +/* + * grab the guid string from a mapping string + */ +char *SDL_PrivateGetControllerGUIDFromMappingString( const char *pMapping ) +{ + const char *pFirstComma = SDL_strchr( pMapping, ',' ); + if ( pFirstComma ) + { + char *pchGUID = SDL_malloc( pFirstComma - pMapping + 1 ); + if ( !pchGUID ) + { + SDL_OutOfMemory(); + return NULL; + } + SDL_memcpy( pchGUID, pMapping, pFirstComma - pMapping ); + pchGUID[ pFirstComma - pMapping ] = 0; + return pchGUID; + } + return NULL; +} + + +/* + * grab the name string from a mapping string + */ +char *SDL_PrivateGetControllerNameFromMappingString( const char *pMapping ) +{ + const char *pFirstComma, *pSecondComma; + char *pchName; + + pFirstComma = SDL_strchr( pMapping, ',' ); + if ( !pFirstComma ) + return NULL; + + pSecondComma = SDL_strchr( pFirstComma + 1, ',' ); + if ( !pSecondComma ) + return NULL; + + pchName = SDL_malloc( pSecondComma - pFirstComma ); + if ( !pchName ) + { + SDL_OutOfMemory(); + return NULL; + } + SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma ); + pchName[ pSecondComma - pFirstComma - 1 ] = 0; + return pchName; +} + + +/* + * grab the button mapping string from a mapping string + */ +char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping ) +{ + const char *pFirstComma, *pSecondComma; + + pFirstComma = SDL_strchr( pMapping, ',' ); + if ( !pFirstComma ) + return NULL; + + pSecondComma = SDL_strchr( pFirstComma + 1, ',' ); + if ( !pSecondComma ) + return NULL; + + return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */ +} + +void SDL_PrivateGameControllerRefreshMapping( ControllerMapping_t *pControllerMapping ) +{ + SDL_GameController *gamecontrollerlist = SDL_gamecontrollers; + while ( gamecontrollerlist ) + { + if ( !SDL_memcmp( &gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid) ) ) + { + SDL_Event event; + event.type = SDL_CONTROLLERDEVICEREMAPPED; + event.cdevice.which = gamecontrollerlist->joystick->instance_id; + SDL_PushEvent(&event); + + /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */ + SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping); + } + + gamecontrollerlist = gamecontrollerlist->next; + } +} + +/* + * Add or update an entry into the Mappings Database + */ +int +SDL_GameControllerAddMapping( const char *mappingString ) +{ + char *pchGUID; + char *pchName; + char *pchMapping; + SDL_JoystickGUID jGUID; + ControllerMapping_t *pControllerMapping; +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) + SDL_bool is_xinput_mapping = SDL_FALSE; +#endif + + pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( mappingString ); + if (!pchGUID) { + return -1; + } +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) + if ( !SDL_strcasecmp( pchGUID, "xinput" ) ) { + is_xinput_mapping = SDL_TRUE; + } +#endif + jGUID = SDL_JoystickGetGUIDFromString(pchGUID); + SDL_free(pchGUID); + + pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID); + + pchName = SDL_PrivateGetControllerNameFromMappingString( mappingString ); + if (!pchName) return -1; + + pchMapping = SDL_PrivateGetControllerMappingFromMappingString( mappingString ); + if (!pchMapping) { + SDL_free( pchName ); + return -1; + } + + if (pControllerMapping) { + /* Update existing mapping */ + SDL_free( pControllerMapping->name ); + pControllerMapping->name = pchName; + SDL_free( pControllerMapping->mapping ); + pControllerMapping->mapping = pchMapping; + /* refresh open controllers */ + SDL_PrivateGameControllerRefreshMapping( pControllerMapping ); + return 0; + } else { + pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) ); + if (!pControllerMapping) { + SDL_free( pchName ); + SDL_free( pchMapping ); + return SDL_OutOfMemory(); + } +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) + if ( is_xinput_mapping ) + { + s_pXInputMapping = pControllerMapping; + } +#endif + pControllerMapping->guid = jGUID; + pControllerMapping->name = pchName; + pControllerMapping->mapping = pchMapping; + pControllerMapping->next = s_pSupportedControllers; + s_pSupportedControllers = pControllerMapping; + return 1; + } +} + +/* + * Get the mapping string for this GUID + */ +char * +SDL_GameControllerMappingForGUID( SDL_JoystickGUID guid ) +{ + char *pMappingString = NULL; + ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid); + if (mapping) { + char pchGUID[33]; + size_t needed; + SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID)); + /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ + needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; + pMappingString = SDL_malloc( needed ); + SDL_snprintf( pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping ); + } + return pMappingString; +} + +/* + * Get the mapping string for this device + */ +char * +SDL_GameControllerMapping( SDL_GameController * gamecontroller ) +{ + return SDL_GameControllerMappingForGUID( gamecontroller->mapping.guid ); +} + +static void +SDL_GameControllerLoadHints() +{ + const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG); + if ( hint && hint[0] ) { + size_t nchHints = SDL_strlen( hint ); + char *pUserMappings = SDL_malloc( nchHints + 1 ); + char *pTempMappings = pUserMappings; + SDL_memcpy( pUserMappings, hint, nchHints ); + while ( pUserMappings ) { + char *pchNewLine = NULL; + + pchNewLine = SDL_strchr( pUserMappings, '\n' ); + if ( pchNewLine ) + *pchNewLine = '\0'; + + SDL_GameControllerAddMapping( pUserMappings ); + + if ( pchNewLine ) + pUserMappings = pchNewLine + 1; + else + pUserMappings = NULL; + } + SDL_free(pTempMappings); + } +} + +/* + * Initialize the game controller system, mostly load our DB of controller config mappings + */ +int +SDL_GameControllerInit(void) +{ + int i = 0; + const char *pMappingString = NULL; + s_pSupportedControllers = NULL; + pMappingString = s_ControllerMappings[i]; + while ( pMappingString ) + { + SDL_GameControllerAddMapping( pMappingString ); + + i++; + pMappingString = s_ControllerMappings[i]; + } + + /* load in any user supplied config */ + SDL_GameControllerLoadHints(); + + /* watch for joy events and fire controller ones if needed */ + SDL_AddEventWatch( SDL_GameControllerEventWatcher, NULL ); + + return (0); +} + + +/* + * Get the implementation dependent name of a controller + */ +const char * +SDL_GameControllerNameForIndex(int device_index) +{ + ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); + if ( pSupportedController ) + { + return pSupportedController->name; + } + return NULL; +} + + +/* + * Return 1 if the joystick at this device index is a supported controller + */ +SDL_bool +SDL_IsGameController(int device_index) +{ + ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index); + if ( pSupportedController ) + { + return SDL_TRUE; + } + + return SDL_FALSE; +} + +/* + * Open a controller for use - the index passed as an argument refers to + * the N'th controller on the system. This index is the value which will + * identify this controller in future controller events. + * + * This function returns a controller identifier, or NULL if an error occurred. + */ +SDL_GameController * +SDL_GameControllerOpen(int device_index) +{ + SDL_GameController *gamecontroller; + SDL_GameController *gamecontrollerlist; + ControllerMapping_t *pSupportedController = NULL; + + if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) { + SDL_SetError("There are %d joysticks available", SDL_NumJoysticks()); + return (NULL); + } + + gamecontrollerlist = SDL_gamecontrollers; + /* If the controller is already open, return it */ + while ( gamecontrollerlist ) + { + if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) { + gamecontroller = gamecontrollerlist; + ++gamecontroller->ref_count; + return (gamecontroller); + } + gamecontrollerlist = gamecontrollerlist->next; + } + + /* Find a controller mapping */ + pSupportedController = SDL_PrivateGetControllerMapping(device_index); + if ( !pSupportedController ) { + SDL_SetError("Couldn't find mapping for device (%d)", device_index ); + return (NULL); + } + + /* Create and initialize the joystick */ + gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller)); + if (gamecontroller == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + SDL_memset(gamecontroller, 0, (sizeof *gamecontroller)); + gamecontroller->joystick = SDL_JoystickOpen(device_index); + if ( !gamecontroller->joystick ) { + SDL_free(gamecontroller); + return NULL; + } + + SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping ); + + /* Add joystick to list */ + ++gamecontroller->ref_count; + /* Link the joystick in the list */ + gamecontroller->next = SDL_gamecontrollers; + SDL_gamecontrollers = gamecontroller; + + SDL_SYS_JoystickUpdate( gamecontroller->joystick ); + + return (gamecontroller); +} + +/* + * Manually pump for controller updates. + */ +void +SDL_GameControllerUpdate(void) +{ + /* Just for API completeness; the joystick API does all the work. */ + SDL_JoystickUpdate(); +} + + +/* + * Get the current state of an axis control on a controller + */ +Sint16 +SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) +{ + if ( !gamecontroller ) + return 0; + + if (gamecontroller->mapping.axes[axis] >= 0 ) + { + Sint16 value = ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) ); + switch (axis) + { + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + /* Shift it to be 0 - 32767. */ + value = value / 2 + 16384; + default: + break; + } + return value; + } + else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 ) + { + Uint8 value; + value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] ); + if ( value > 0 ) + return 32767; + return 0; + } + return 0; +} + + +/* + * Get the current state of a button on a controller + */ +Uint8 +SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) +{ + if ( !gamecontroller ) + return 0; + + if ( gamecontroller->mapping.buttons[button] >= 0 ) + { + return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) ); + } + else if ( gamecontroller->mapping.axesasbutton[button] >= 0 ) + { + Sint16 value; + value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] ); + if ( ABS(value) > 32768/2 ) + return 1; + return 0; + } + else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 ) + { + Uint8 value; + value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat ); + + if ( value & gamecontroller->mapping.hatasbutton[button].mask ) + return 1; + return 0; + } + + return 0; +} + +/* + * Return if the joystick in question is currently attached to the system, + * \return 0 if not plugged in, 1 if still present. + */ +SDL_bool +SDL_GameControllerGetAttached( SDL_GameController * gamecontroller ) +{ + if ( !gamecontroller ) + return SDL_FALSE; + + return SDL_JoystickGetAttached(gamecontroller->joystick); +} + + +/* + * Get the number of multi-dimensional axis controls on a joystick + */ +const char * +SDL_GameControllerName(SDL_GameController * gamecontroller) +{ + if ( !gamecontroller ) + return NULL; + + return (gamecontroller->mapping.name); +} + + +/* + * Get the joystick for this controller + */ +SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller) +{ + if ( !gamecontroller ) + return NULL; + + return gamecontroller->joystick; +} + +/** + * Get the SDL joystick layer binding for this controller axis mapping + */ +SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis) +{ + SDL_GameControllerButtonBind bind; + SDL_memset( &bind, 0x0, sizeof(bind) ); + + if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID ) + return bind; + + if (gamecontroller->mapping.axes[axis] >= 0 ) + { + bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; + bind.value.button = gamecontroller->mapping.axes[axis]; + } + else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 ) + { + bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; + bind.value.button = gamecontroller->mapping.buttonasaxis[axis]; + } + + return bind; +} + + +/** + * Get the SDL joystick layer binding for this controller button mapping + */ +SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button) +{ + SDL_GameControllerButtonBind bind; + SDL_memset( &bind, 0x0, sizeof(bind) ); + + if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID ) + return bind; + + if ( gamecontroller->mapping.buttons[button] >= 0 ) + { + bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON; + bind.value.button = gamecontroller->mapping.buttons[button]; + } + else if ( gamecontroller->mapping.axesasbutton[button] >= 0 ) + { + bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS; + bind.value.axis = gamecontroller->mapping.axesasbutton[button]; + } + else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 ) + { + bind.bindType = SDL_CONTROLLER_BINDTYPE_HAT; + bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat; + bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask; + } + + return bind; +} + + +/* + * Close a joystick previously opened with SDL_JoystickOpen() + */ +void +SDL_GameControllerClose(SDL_GameController * gamecontroller) +{ + SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev; + + if ( !gamecontroller ) + return; + + /* First decrement ref count */ + if (--gamecontroller->ref_count > 0) { + return; + } + + SDL_JoystickClose( gamecontroller->joystick ); + + gamecontrollerlist = SDL_gamecontrollers; + gamecontrollerlistprev = NULL; + while ( gamecontrollerlist ) + { + if (gamecontroller == gamecontrollerlist) + { + if ( gamecontrollerlistprev ) + { + /* unlink this entry */ + gamecontrollerlistprev->next = gamecontrollerlist->next; + } + else + { + SDL_gamecontrollers = gamecontroller->next; + } + + break; + } + gamecontrollerlistprev = gamecontrollerlist; + gamecontrollerlist = gamecontrollerlist->next; + } + + SDL_free(gamecontroller); +} + + +/* + * Quit the controller subsystem + */ +void +SDL_GameControllerQuit(void) +{ + ControllerMapping_t *pControllerMap; + while ( SDL_gamecontrollers ) + { + SDL_gamecontrollers->ref_count = 1; + SDL_GameControllerClose(SDL_gamecontrollers); + } + + while ( s_pSupportedControllers ) + { + pControllerMap = s_pSupportedControllers; + s_pSupportedControllers = s_pSupportedControllers->next; + SDL_free( pControllerMap->name ); + SDL_free( pControllerMap ); + } + + SDL_DelEventWatch( SDL_GameControllerEventWatcher, NULL ); + +} + +/* + * Event filter to transform joystick events into appropriate game controller ones + */ +int +SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value) +{ + int posted; + + /* translate the event, if desired */ + posted = 0; +#if !SDL_EVENTS_DISABLED + if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) { + SDL_Event event; + event.type = SDL_CONTROLLERAXISMOTION; + event.caxis.which = gamecontroller->joystick->instance_id; + event.caxis.axis = axis; + event.caxis.value = value; + posted = SDL_PushEvent(&event) == 1; + } +#endif /* !SDL_EVENTS_DISABLED */ + return (posted); +} + + +/* + * Event filter to transform joystick events into appropriate game controller ones + */ +int +SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state) +{ + int posted; +#if !SDL_EVENTS_DISABLED + SDL_Event event; + + if ( button == SDL_CONTROLLER_BUTTON_INVALID ) + return (0); + + switch (state) { + case SDL_PRESSED: + event.type = SDL_CONTROLLERBUTTONDOWN; + break; + case SDL_RELEASED: + event.type = SDL_CONTROLLERBUTTONUP; + break; + default: + /* Invalid state -- bail */ + return (0); + } +#endif /* !SDL_EVENTS_DISABLED */ + + /* translate the event, if desired */ + posted = 0; +#if !SDL_EVENTS_DISABLED + if (SDL_GetEventState(event.type) == SDL_ENABLE) { + event.cbutton.which = gamecontroller->joystick->instance_id; + event.cbutton.button = button; + event.cbutton.state = state; + posted = SDL_PushEvent(&event) == 1; + } +#endif /* !SDL_EVENTS_DISABLED */ + return (posted); +} + +/* + * Turn off controller events + */ +int +SDL_GameControllerEventState(int state) +{ +#if SDL_EVENTS_DISABLED + return SDL_IGNORE; +#else + const Uint32 event_list[] = { + SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP, + SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED, + }; + unsigned int i; + + switch (state) { + case SDL_QUERY: + state = SDL_IGNORE; + for (i = 0; i < SDL_arraysize(event_list); ++i) { + state = SDL_EventState(event_list[i], SDL_QUERY); + if (state == SDL_ENABLE) { + break; + } + } + break; + default: + for (i = 0; i < SDL_arraysize(event_list); ++i) { + SDL_EventState(event_list[i], state); + } + break; + } + return (state); +#endif /* SDL_EVENTS_DISABLED */ +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/main/winrt/SDL_winrt_main_NonXAML.cpp b/src/main/winrt/SDL_winrt_main_NonXAML.cpp index 19eb7b91965eb..088cd6c32607f 100644 --- a/src/main/winrt/SDL_winrt_main_NonXAML.cpp +++ b/src/main/winrt/SDL_winrt_main_NonXAML.cpp @@ -1,56 +1,56 @@ - -#include -#include - -/* At least one file in any SDL/WinRT app appears to require compilation - with C++/CX, otherwise a Windows Metadata file won't get created, and - an APPX0702 build error can appear shortly after linking. - - The following set of preprocessor code forces this file to be compiled - as C++/CX, which appears to cause Visual C++ 2012's build tools to - create this .winmd file, and will help allow builds of SDL/WinRT apps - to proceed without error. - - If other files in an app's project enable C++/CX compilation, then it might - be possible for SDL_winrt_main_NonXAML.cpp to be compiled without /ZW, - for Visual C++'s build tools to create a winmd file, and for the app to - build without APPX0702 errors. In this case, if - SDL_WINRT_METADATA_FILE_AVAILABLE is defined as a C/C++ macro, then - the #error (to force C++/CX compilation) will be disabled. - - Please note that /ZW can be specified on a file-by-file basis. To do this, - right click on the file in Visual C++, click Properties, then change the - setting through the dialog that comes up. -*/ -#ifndef SDL_WINRT_METADATA_FILE_AVAILABLE -#ifndef __cplusplus_winrt -#error SDL_winrt_main_NonXAML.cpp must be compiled with /ZW, otherwise build errors due to missing .winmd files can occur. -#endif -#endif - -/* Prevent MSVC++ from warning about threading models when defining our - custom WinMain. The threading model will instead be set via a direct - call to Windows::Foundation::Initialize (rather than via an attributed - function). - - To note, this warning (C4447) does not seem to come up unless this file - is compiled with C++/CX enabled (via the /ZW compiler flag). -*/ -#ifdef _MSC_VER -#pragma warning(disable:4447) -#endif - -/* Make sure the function to initialize the Windows Runtime gets linked in. */ -#ifdef _MSC_VER -#pragma comment(lib, "runtimeobject.lib") -#endif - -int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) -{ - if (FAILED(Windows::Foundation::Initialize(RO_INIT_MULTITHREADED))) { - return 1; - } - - SDL_WinRTRunApp(SDL_main, NULL); - return 0; -} + +#include +#include + +/* At least one file in any SDL/WinRT app appears to require compilation + with C++/CX, otherwise a Windows Metadata file won't get created, and + an APPX0702 build error can appear shortly after linking. + + The following set of preprocessor code forces this file to be compiled + as C++/CX, which appears to cause Visual C++ 2012's build tools to + create this .winmd file, and will help allow builds of SDL/WinRT apps + to proceed without error. + + If other files in an app's project enable C++/CX compilation, then it might + be possible for SDL_winrt_main_NonXAML.cpp to be compiled without /ZW, + for Visual C++'s build tools to create a winmd file, and for the app to + build without APPX0702 errors. In this case, if + SDL_WINRT_METADATA_FILE_AVAILABLE is defined as a C/C++ macro, then + the #error (to force C++/CX compilation) will be disabled. + + Please note that /ZW can be specified on a file-by-file basis. To do this, + right click on the file in Visual C++, click Properties, then change the + setting through the dialog that comes up. +*/ +#ifndef SDL_WINRT_METADATA_FILE_AVAILABLE +#ifndef __cplusplus_winrt +#error SDL_winrt_main_NonXAML.cpp must be compiled with /ZW, otherwise build errors due to missing .winmd files can occur. +#endif +#endif + +/* Prevent MSVC++ from warning about threading models when defining our + custom WinMain. The threading model will instead be set via a direct + call to Windows::Foundation::Initialize (rather than via an attributed + function). + + To note, this warning (C4447) does not seem to come up unless this file + is compiled with C++/CX enabled (via the /ZW compiler flag). +*/ +#ifdef _MSC_VER +#pragma warning(disable:4447) +#endif + +/* Make sure the function to initialize the Windows Runtime gets linked in. */ +#ifdef _MSC_VER +#pragma comment(lib, "runtimeobject.lib") +#endif + +int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) +{ + if (FAILED(Windows::Foundation::Initialize(RO_INIT_MULTITHREADED))) { + return 1; + } + + SDL_WinRTRunApp(SDL_main, NULL); + return 0; +} diff --git a/src/render/direct3d11/SDL_render_d3d11.cpp b/src/render/direct3d11/SDL_render_d3d11.cpp index 319b5c910af83..58a7ede22de4c 100644 --- a/src/render/direct3d11/SDL_render_d3d11.cpp +++ b/src/render/direct3d11/SDL_render_d3d11.cpp @@ -64,18 +64,18 @@ static const D3D11_FILTER SDL_D3D11_NEAREST_PIXEL_FILTER = D3D11_FILTER_MIN_MAG_ static const D3D11_FILTER SDL_D3D11_LINEAR_FILTER = D3D11_FILTER_MIN_MAG_MIP_LINEAR; /* Vertex shader, common values */ -struct VertexShaderConstants -{ - DirectX::XMFLOAT4X4 model; - DirectX::XMFLOAT4X4 projectionAndView; +struct VertexShaderConstants +{ + DirectX::XMFLOAT4X4 model; + DirectX::XMFLOAT4X4 projectionAndView; }; /* Per-vertex data */ -struct VertexPositionColor -{ - DirectX::XMFLOAT3 pos; - DirectX::XMFLOAT2 tex; - DirectX::XMFLOAT4 color; +struct VertexPositionColor +{ + DirectX::XMFLOAT3 pos; + DirectX::XMFLOAT2 tex; + DirectX::XMFLOAT4 color; }; /* Per-texture data */ @@ -83,7 +83,7 @@ typedef struct { Microsoft::WRL::ComPtr mainTexture; Microsoft::WRL::ComPtr mainTextureResourceView; - Microsoft::WRL::ComPtr mainTextureRenderTargetView; + Microsoft::WRL::ComPtr mainTextureRenderTargetView; SDL_PixelFormat * pixelFormat; Microsoft::WRL::ComPtr stagingTexture; DirectX::XMINT2 lockedTexturePosition; @@ -94,18 +94,18 @@ typedef struct typedef struct { Microsoft::WRL::ComPtr d3dDevice; - Microsoft::WRL::ComPtr d3dContext; - Microsoft::WRL::ComPtr swapChain; - Microsoft::WRL::ComPtr mainRenderTargetView; - Microsoft::WRL::ComPtr currentOffscreenRenderTargetView; - Microsoft::WRL::ComPtr inputLayout; - Microsoft::WRL::ComPtr vertexBuffer; - Microsoft::WRL::ComPtr vertexShader; - Microsoft::WRL::ComPtr texturePixelShader; - Microsoft::WRL::ComPtr colorPixelShader; - Microsoft::WRL::ComPtr blendModeBlend; - Microsoft::WRL::ComPtr blendModeAdd; - Microsoft::WRL::ComPtr blendModeMod; + Microsoft::WRL::ComPtr d3dContext; + Microsoft::WRL::ComPtr swapChain; + Microsoft::WRL::ComPtr mainRenderTargetView; + Microsoft::WRL::ComPtr currentOffscreenRenderTargetView; + Microsoft::WRL::ComPtr inputLayout; + Microsoft::WRL::ComPtr vertexBuffer; + Microsoft::WRL::ComPtr vertexShader; + Microsoft::WRL::ComPtr texturePixelShader; + Microsoft::WRL::ComPtr colorPixelShader; + Microsoft::WRL::ComPtr blendModeBlend; + Microsoft::WRL::ComPtr blendModeAdd; + Microsoft::WRL::ComPtr blendModeMod; Microsoft::WRL::ComPtr nearestPixelSampler; Microsoft::WRL::ComPtr linearSampler; D3D_FEATURE_LEVEL featureLevel; @@ -120,11 +120,11 @@ typedef struct Microsoft::WRL::ComPtr vertexShaderConstants; // Cached renderer properties. - DirectX::XMFLOAT2 windowSizeInDIPs; + DirectX::XMFLOAT2 windowSizeInDIPs; DirectX::XMFLOAT2 renderTargetSize; Windows::Graphics::Display::DisplayOrientations orientation; - // Transform used for display orientation. + // Transform used for display orientation. DirectX::XMFLOAT4X4 orientationTransform3D; } D3D11_RenderData; @@ -134,123 +134,123 @@ typedef struct SDL's shaders are compiled into SDL itself, to simplify distribution. All Direct3D 11.x shaders were compiled with the following: - - fxc /E"main" /T "" /Fo"" "" - - Variables: - - : the type of shader. A table of utilized shader types is - listed below. - - : where to store compiled output - - : where to read shader source code from - - Shader types: - - ps_4_0_level_9_1: Pixel shader for Windows 8+, including Windows RT - - vs_4_0_level_9_1: Vertex shader for Windows 8+, including Windows RT - - ps_4_0_level_9_3: Pixel shader for Windows Phone 8 - - vs_4_0_level_9_3: Vertex shader for Windows Phone 8 - - - Shader object code was converted to a list of DWORDs via the following - *nix style command (available separately from Windows + MSVC): - - hexdump -v -e '6/4 "0x%08.8x, " "\n"' - */ -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP -#define D3D11_USE_SHADER_MODEL_4_0_level_9_3 -#else -#define D3D11_USE_SHADER_MODEL_4_0_level_9_1 -#endif - -/* The texture-rendering pixel shader: - - --- D3D11_PixelShader_Textures.hlsl --- - Texture2D theTexture : register(t0); - SamplerState theSampler : register(s0); - - struct PixelShaderInput - { - float4 pos : SV_POSITION; - float2 tex : TEXCOORD0; - float4 color : COLOR0; - }; - - float4 main(PixelShaderInput input) : SV_TARGET - { - return theTexture.Sample(theSampler, input.tex) * input.color; - } -*/ -#if defined(D3D11_USE_SHADER_MODEL_4_0_level_9_1) -static const DWORD D3D11_PixelShader_Textures[] = { - 0x43425844, 0x6299b59f, 0x155258f2, 0x873ab86a, 0xfcbb6dcd, 0x00000001, - 0x00000330, 0x00000006, 0x00000038, 0x000000c0, 0x0000015c, 0x000001d8, - 0x00000288, 0x000002fc, 0x396e6f41, 0x00000080, 0x00000080, 0xffff0200, - 0x00000058, 0x00000028, 0x00280000, 0x00280000, 0x00280000, 0x00240001, - 0x00280000, 0x00000000, 0xffff0200, 0x0200001f, 0x80000000, 0xb0030000, - 0x0200001f, 0x80000000, 0xb00f0001, 0x0200001f, 0x90000000, 0xa00f0800, - 0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800, 0x03000005, 0x800f0000, - 0x80e40000, 0xb0e40001, 0x02000001, 0x800f0800, 0x80e40000, 0x0000ffff, - 0x52444853, 0x00000094, 0x00000040, 0x00000025, 0x0300005a, 0x00106000, - 0x00000000, 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x03001062, - 0x00101032, 0x00000001, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, - 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x09000045, 0x001000f2, - 0x00000000, 0x00101046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, - 0x00000000, 0x07000038, 0x001020f2, 0x00000000, 0x00100e46, 0x00000000, - 0x00101e46, 0x00000002, 0x0100003e, 0x54415453, 0x00000074, 0x00000003, - 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x00000000, 0x00000000, - 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x46454452, 0x000000a8, - 0x00000000, 0x00000000, 0x00000002, 0x0000001c, 0xffff0400, 0x00000100, - 0x00000072, 0x0000005c, 0x00000003, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000001, 0x00000001, 0x00000067, 0x00000002, 0x00000005, - 0x00000004, 0xffffffff, 0x00000000, 0x00000001, 0x0000000d, 0x53656874, - 0x6c706d61, 0x74007265, 0x65546568, 0x72757478, 0x694d0065, 0x736f7263, - 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, 0x706d6f43, - 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, 0xababab00, - 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, - 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, - 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000065, 0x00000000, - 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, - 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, - 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, - 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 + + fxc /E"main" /T "" /Fo"" "" + + Variables: + - : the type of shader. A table of utilized shader types is + listed below. + - : where to store compiled output + - : where to read shader source code from + + Shader types: + - ps_4_0_level_9_1: Pixel shader for Windows 8+, including Windows RT + - vs_4_0_level_9_1: Vertex shader for Windows 8+, including Windows RT + - ps_4_0_level_9_3: Pixel shader for Windows Phone 8 + - vs_4_0_level_9_3: Vertex shader for Windows Phone 8 + + + Shader object code was converted to a list of DWORDs via the following + *nix style command (available separately from Windows + MSVC): + + hexdump -v -e '6/4 "0x%08.8x, " "\n"' + */ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +#define D3D11_USE_SHADER_MODEL_4_0_level_9_3 +#else +#define D3D11_USE_SHADER_MODEL_4_0_level_9_1 +#endif + +/* The texture-rendering pixel shader: + + --- D3D11_PixelShader_Textures.hlsl --- + Texture2D theTexture : register(t0); + SamplerState theSampler : register(s0); + + struct PixelShaderInput + { + float4 pos : SV_POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; + }; + + float4 main(PixelShaderInput input) : SV_TARGET + { + return theTexture.Sample(theSampler, input.tex) * input.color; + } +*/ +#if defined(D3D11_USE_SHADER_MODEL_4_0_level_9_1) +static const DWORD D3D11_PixelShader_Textures[] = { + 0x43425844, 0x6299b59f, 0x155258f2, 0x873ab86a, 0xfcbb6dcd, 0x00000001, + 0x00000330, 0x00000006, 0x00000038, 0x000000c0, 0x0000015c, 0x000001d8, + 0x00000288, 0x000002fc, 0x396e6f41, 0x00000080, 0x00000080, 0xffff0200, + 0x00000058, 0x00000028, 0x00280000, 0x00280000, 0x00280000, 0x00240001, + 0x00280000, 0x00000000, 0xffff0200, 0x0200001f, 0x80000000, 0xb0030000, + 0x0200001f, 0x80000000, 0xb00f0001, 0x0200001f, 0x90000000, 0xa00f0800, + 0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800, 0x03000005, 0x800f0000, + 0x80e40000, 0xb0e40001, 0x02000001, 0x800f0800, 0x80e40000, 0x0000ffff, + 0x52444853, 0x00000094, 0x00000040, 0x00000025, 0x0300005a, 0x00106000, + 0x00000000, 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x03001062, + 0x00101032, 0x00000001, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, + 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x09000045, 0x001000f2, + 0x00000000, 0x00101046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, + 0x00000000, 0x07000038, 0x001020f2, 0x00000000, 0x00100e46, 0x00000000, + 0x00101e46, 0x00000002, 0x0100003e, 0x54415453, 0x00000074, 0x00000003, + 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x46454452, 0x000000a8, + 0x00000000, 0x00000000, 0x00000002, 0x0000001c, 0xffff0400, 0x00000100, + 0x00000072, 0x0000005c, 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000001, 0x00000067, 0x00000002, 0x00000005, + 0x00000004, 0xffffffff, 0x00000000, 0x00000001, 0x0000000d, 0x53656874, + 0x6c706d61, 0x74007265, 0x65546568, 0x72757478, 0x694d0065, 0x736f7263, + 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, 0x706d6f43, + 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, 0xababab00, + 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, + 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000065, 0x00000000, + 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 }; #elif defined(D3D11_USE_SHADER_MODEL_4_0_level_9_3) static const DWORD D3D11_PixelShader_Textures[] = { - 0x43425844, 0x5876569a, 0x01b6c87e, 0x8447454f, 0xc7f3ef10, 0x00000001, - 0x00000330, 0x00000006, 0x00000038, 0x000000c0, 0x0000015c, 0x000001d8, - 0x00000288, 0x000002fc, 0x396e6f41, 0x00000080, 0x00000080, 0xffff0200, - 0x00000058, 0x00000028, 0x00280000, 0x00280000, 0x00280000, 0x00240001, - 0x00280000, 0x00000000, 0xffff0201, 0x0200001f, 0x80000000, 0xb0030000, - 0x0200001f, 0x80000000, 0xb00f0001, 0x0200001f, 0x90000000, 0xa00f0800, - 0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800, 0x03000005, 0x800f0000, - 0x80e40000, 0xb0e40001, 0x02000001, 0x800f0800, 0x80e40000, 0x0000ffff, - 0x52444853, 0x00000094, 0x00000040, 0x00000025, 0x0300005a, 0x00106000, - 0x00000000, 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x03001062, - 0x00101032, 0x00000001, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, - 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x09000045, 0x001000f2, - 0x00000000, 0x00101046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, - 0x00000000, 0x07000038, 0x001020f2, 0x00000000, 0x00100e46, 0x00000000, - 0x00101e46, 0x00000002, 0x0100003e, 0x54415453, 0x00000074, 0x00000003, - 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x00000000, 0x00000000, - 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x46454452, 0x000000a8, - 0x00000000, 0x00000000, 0x00000002, 0x0000001c, 0xffff0400, 0x00000100, - 0x00000072, 0x0000005c, 0x00000003, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000001, 0x00000001, 0x00000067, 0x00000002, 0x00000005, - 0x00000004, 0xffffffff, 0x00000000, 0x00000001, 0x0000000d, 0x53656874, - 0x6c706d61, 0x74007265, 0x65546568, 0x72757478, 0x694d0065, 0x736f7263, - 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, 0x706d6f43, - 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, 0xababab00, - 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, - 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, - 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000065, 0x00000000, - 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, - 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, - 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, + 0x43425844, 0x5876569a, 0x01b6c87e, 0x8447454f, 0xc7f3ef10, 0x00000001, + 0x00000330, 0x00000006, 0x00000038, 0x000000c0, 0x0000015c, 0x000001d8, + 0x00000288, 0x000002fc, 0x396e6f41, 0x00000080, 0x00000080, 0xffff0200, + 0x00000058, 0x00000028, 0x00280000, 0x00280000, 0x00280000, 0x00240001, + 0x00280000, 0x00000000, 0xffff0201, 0x0200001f, 0x80000000, 0xb0030000, + 0x0200001f, 0x80000000, 0xb00f0001, 0x0200001f, 0x90000000, 0xa00f0800, + 0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800, 0x03000005, 0x800f0000, + 0x80e40000, 0xb0e40001, 0x02000001, 0x800f0800, 0x80e40000, 0x0000ffff, + 0x52444853, 0x00000094, 0x00000040, 0x00000025, 0x0300005a, 0x00106000, + 0x00000000, 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x03001062, + 0x00101032, 0x00000001, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, + 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x09000045, 0x001000f2, + 0x00000000, 0x00101046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, + 0x00000000, 0x07000038, 0x001020f2, 0x00000000, 0x00100e46, 0x00000000, + 0x00101e46, 0x00000002, 0x0100003e, 0x54415453, 0x00000074, 0x00000003, + 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x46454452, 0x000000a8, + 0x00000000, 0x00000000, 0x00000002, 0x0000001c, 0xffff0400, 0x00000100, + 0x00000072, 0x0000005c, 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000001, 0x00000067, 0x00000002, 0x00000005, + 0x00000004, 0xffffffff, 0x00000000, 0x00000001, 0x0000000d, 0x53656874, + 0x6c706d61, 0x74007265, 0x65546568, 0x72757478, 0x694d0065, 0x736f7263, + 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, 0x706d6f43, + 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, 0xababab00, + 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, + 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000065, 0x00000000, + 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 }; #else @@ -260,72 +260,72 @@ static const DWORD D3D11_PixelShader_Textures[] = { /* The color-only-rendering pixel shader: --- D3D11_PixelShader_Colors.hlsl --- - struct PixelShaderInput - { - float4 pos : SV_POSITION; - float2 tex : TEXCOORD0; - float4 color : COLOR0; - }; - - float4 main(PixelShaderInput input) : SV_TARGET - { - return input.color; - } -*/ + struct PixelShaderInput + { + float4 pos : SV_POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; + }; + + float4 main(PixelShaderInput input) : SV_TARGET + { + return input.color; + } +*/ #if defined(D3D11_USE_SHADER_MODEL_4_0_level_9_1) -static const DWORD D3D11_PixelShader_Colors[] = { - 0x43425844, 0xd74c28fe, 0xa1eb8804, 0x269d512a, 0x7699723d, 0x00000001, - 0x00000240, 0x00000006, 0x00000038, 0x00000084, 0x000000c4, 0x00000140, - 0x00000198, 0x0000020c, 0x396e6f41, 0x00000044, 0x00000044, 0xffff0200, - 0x00000020, 0x00000024, 0x00240000, 0x00240000, 0x00240000, 0x00240000, - 0x00240000, 0xffff0200, 0x0200001f, 0x80000000, 0xb00f0001, 0x02000001, - 0x800f0800, 0xb0e40001, 0x0000ffff, 0x52444853, 0x00000038, 0x00000040, - 0x0000000e, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, 0x001020f2, - 0x00000000, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000002, - 0x0100003e, 0x54415453, 0x00000074, 0x00000002, 0x00000000, 0x00000000, - 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x46454452, 0x00000050, 0x00000000, 0x00000000, - 0x00000000, 0x0000001c, 0xffff0400, 0x00000100, 0x0000001c, 0x7263694d, - 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, - 0x6c69706d, 0x39207265, 0x2e30332e, 0x30303239, 0x3336312e, 0xab003438, - 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, - 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, - 0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000065, 0x00000000, - 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, - 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, - 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, - 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 -}; -#elif defined(D3D11_USE_SHADER_MODEL_4_0_level_9_3) -static const DWORD D3D11_PixelShader_Colors[] = { - 0x43425844, 0x93f6ccfc, 0x5f919270, 0x7a11aa4f, 0x9148e931, 0x00000001, - 0x00000240, 0x00000006, 0x00000038, 0x00000084, 0x000000c4, 0x00000140, - 0x00000198, 0x0000020c, 0x396e6f41, 0x00000044, 0x00000044, 0xffff0200, - 0x00000020, 0x00000024, 0x00240000, 0x00240000, 0x00240000, 0x00240000, - 0x00240000, 0xffff0201, 0x0200001f, 0x80000000, 0xb00f0001, 0x02000001, - 0x800f0800, 0xb0e40001, 0x0000ffff, 0x52444853, 0x00000038, 0x00000040, - 0x0000000e, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, 0x001020f2, - 0x00000000, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000002, - 0x0100003e, 0x54415453, 0x00000074, 0x00000002, 0x00000000, 0x00000000, - 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x46454452, 0x00000050, 0x00000000, 0x00000000, - 0x00000000, 0x0000001c, 0xffff0400, 0x00000100, 0x0000001c, 0x7263694d, - 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, - 0x6c69706d, 0x39207265, 0x2e30332e, 0x30303239, 0x3336312e, 0xab003438, - 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, - 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, - 0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000065, 0x00000000, - 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, - 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, - 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, - 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 -}; +static const DWORD D3D11_PixelShader_Colors[] = { + 0x43425844, 0xd74c28fe, 0xa1eb8804, 0x269d512a, 0x7699723d, 0x00000001, + 0x00000240, 0x00000006, 0x00000038, 0x00000084, 0x000000c4, 0x00000140, + 0x00000198, 0x0000020c, 0x396e6f41, 0x00000044, 0x00000044, 0xffff0200, + 0x00000020, 0x00000024, 0x00240000, 0x00240000, 0x00240000, 0x00240000, + 0x00240000, 0xffff0200, 0x0200001f, 0x80000000, 0xb00f0001, 0x02000001, + 0x800f0800, 0xb0e40001, 0x0000ffff, 0x52444853, 0x00000038, 0x00000040, + 0x0000000e, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, 0x001020f2, + 0x00000000, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000002, + 0x0100003e, 0x54415453, 0x00000074, 0x00000002, 0x00000000, 0x00000000, + 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x46454452, 0x00000050, 0x00000000, 0x00000000, + 0x00000000, 0x0000001c, 0xffff0400, 0x00000100, 0x0000001c, 0x7263694d, + 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, + 0x6c69706d, 0x39207265, 0x2e30332e, 0x30303239, 0x3336312e, 0xab003438, + 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, + 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000065, 0x00000000, + 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 +}; +#elif defined(D3D11_USE_SHADER_MODEL_4_0_level_9_3) +static const DWORD D3D11_PixelShader_Colors[] = { + 0x43425844, 0x93f6ccfc, 0x5f919270, 0x7a11aa4f, 0x9148e931, 0x00000001, + 0x00000240, 0x00000006, 0x00000038, 0x00000084, 0x000000c4, 0x00000140, + 0x00000198, 0x0000020c, 0x396e6f41, 0x00000044, 0x00000044, 0xffff0200, + 0x00000020, 0x00000024, 0x00240000, 0x00240000, 0x00240000, 0x00240000, + 0x00240000, 0xffff0201, 0x0200001f, 0x80000000, 0xb00f0001, 0x02000001, + 0x800f0800, 0xb0e40001, 0x0000ffff, 0x52444853, 0x00000038, 0x00000040, + 0x0000000e, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, 0x001020f2, + 0x00000000, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000002, + 0x0100003e, 0x54415453, 0x00000074, 0x00000002, 0x00000000, 0x00000000, + 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x46454452, 0x00000050, 0x00000000, 0x00000000, + 0x00000000, 0x0000001c, 0xffff0400, 0x00000100, 0x0000001c, 0x7263694d, + 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, + 0x6c69706d, 0x39207265, 0x2e30332e, 0x30303239, 0x3336312e, 0xab003438, + 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, + 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000065, 0x00000000, + 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 +}; #else #error "An appropriate 'colors' pixel shader is not defined." #endif @@ -333,170 +333,170 @@ static const DWORD D3D11_PixelShader_Colors[] = { /* The sole vertex shader: --- D3D11_VertexShader.hlsl --- - #pragma pack_matrix( row_major ) - - cbuffer VertexShaderConstants : register(b0) - { - matrix model; - matrix projectionAndView; - }; - - struct VertexShaderInput - { - float3 pos : POSITION; - float2 tex : TEXCOORD0; - float4 color : COLOR0; - }; - - struct VertexShaderOutput - { - float4 pos : SV_POSITION; - float2 tex : TEXCOORD0; - float4 color : COLOR0; - }; - - VertexShaderOutput main(VertexShaderInput input) - { - VertexShaderOutput output; - float4 pos = float4(input.pos, 1.0f); - - // Transform the vertex position into projected space. - pos = mul(pos, model); - pos = mul(pos, projectionAndView); - output.pos = pos; - - // Pass through texture coordinates and color values without transformation - output.tex = input.tex; - output.color = input.color; - - return output; - } + #pragma pack_matrix( row_major ) + + cbuffer VertexShaderConstants : register(b0) + { + matrix model; + matrix projectionAndView; + }; + + struct VertexShaderInput + { + float3 pos : POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; + }; + + struct VertexShaderOutput + { + float4 pos : SV_POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; + }; + + VertexShaderOutput main(VertexShaderInput input) + { + VertexShaderOutput output; + float4 pos = float4(input.pos, 1.0f); + + // Transform the vertex position into projected space. + pos = mul(pos, model); + pos = mul(pos, projectionAndView); + output.pos = pos; + + // Pass through texture coordinates and color values without transformation + output.tex = input.tex; + output.color = input.color; + + return output; + } */ #if defined(D3D11_USE_SHADER_MODEL_4_0_level_9_1) static const DWORD D3D11_VertexShader[] = { - 0x43425844, 0x62dfae5f, 0x3e8bd8df, 0x9ec97127, 0x5044eefb, 0x00000001, - 0x00000598, 0x00000006, 0x00000038, 0x0000016c, 0x00000334, 0x000003b0, - 0x000004b4, 0x00000524, 0x396e6f41, 0x0000012c, 0x0000012c, 0xfffe0200, - 0x000000f8, 0x00000034, 0x00240001, 0x00300000, 0x00300000, 0x00240000, - 0x00300001, 0x00000000, 0x00010008, 0x00000000, 0x00000000, 0xfffe0200, - 0x0200001f, 0x80000005, 0x900f0000, 0x0200001f, 0x80010005, 0x900f0001, - 0x0200001f, 0x80020005, 0x900f0002, 0x03000005, 0x800f0000, 0x90550000, - 0xa0e40002, 0x04000004, 0x800f0000, 0x90000000, 0xa0e40001, 0x80e40000, - 0x04000004, 0x800f0000, 0x90aa0000, 0xa0e40003, 0x80e40000, 0x03000002, - 0x800f0000, 0x80e40000, 0xa0e40004, 0x03000005, 0x800f0001, 0x80550000, - 0xa0e40006, 0x04000004, 0x800f0001, 0x80000000, 0xa0e40005, 0x80e40001, - 0x04000004, 0x800f0001, 0x80aa0000, 0xa0e40007, 0x80e40001, 0x04000004, - 0x800f0000, 0x80ff0000, 0xa0e40008, 0x80e40001, 0x04000004, 0xc0030000, - 0x80ff0000, 0xa0e40000, 0x80e40000, 0x02000001, 0xc00c0000, 0x80e40000, - 0x02000001, 0xe0030000, 0x90e40001, 0x02000001, 0xe00f0001, 0x90e40002, - 0x0000ffff, 0x52444853, 0x000001c0, 0x00010040, 0x00000070, 0x04000059, - 0x00208e46, 0x00000000, 0x00000008, 0x0300005f, 0x00101072, 0x00000000, - 0x0300005f, 0x00101032, 0x00000001, 0x0300005f, 0x001010f2, 0x00000002, - 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x00102032, - 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x02000068, 0x00000002, - 0x08000038, 0x001000f2, 0x00000000, 0x00101556, 0x00000000, 0x00208e46, - 0x00000000, 0x00000001, 0x0a000032, 0x001000f2, 0x00000000, 0x00101006, - 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x00100e46, 0x00000000, - 0x0a000032, 0x001000f2, 0x00000000, 0x00101aa6, 0x00000000, 0x00208e46, - 0x00000000, 0x00000002, 0x00100e46, 0x00000000, 0x08000000, 0x001000f2, - 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000003, - 0x08000038, 0x001000f2, 0x00000001, 0x00100556, 0x00000000, 0x00208e46, - 0x00000000, 0x00000005, 0x0a000032, 0x001000f2, 0x00000001, 0x00100006, - 0x00000000, 0x00208e46, 0x00000000, 0x00000004, 0x00100e46, 0x00000001, - 0x0a000032, 0x001000f2, 0x00000001, 0x00100aa6, 0x00000000, 0x00208e46, - 0x00000000, 0x00000006, 0x00100e46, 0x00000001, 0x0a000032, 0x001020f2, - 0x00000000, 0x00100ff6, 0x00000000, 0x00208e46, 0x00000000, 0x00000007, - 0x00100e46, 0x00000001, 0x05000036, 0x00102032, 0x00000001, 0x00101046, - 0x00000001, 0x05000036, 0x001020f2, 0x00000002, 0x00101e46, 0x00000002, - 0x0100003e, 0x54415453, 0x00000074, 0x0000000b, 0x00000002, 0x00000000, - 0x00000006, 0x00000003, 0x00000000, 0x00000000, 0x00000001, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x46454452, 0x000000fc, 0x00000001, 0x00000054, - 0x00000001, 0x0000001c, 0xfffe0400, 0x00000100, 0x000000c6, 0x0000003c, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, - 0x00000001, 0x74726556, 0x68537865, 0x72656461, 0x736e6f43, 0x746e6174, - 0xabab0073, 0x0000003c, 0x00000002, 0x0000006c, 0x00000080, 0x00000000, - 0x00000000, 0x0000009c, 0x00000000, 0x00000040, 0x00000002, 0x000000a4, - 0x00000000, 0x000000b4, 0x00000040, 0x00000040, 0x00000002, 0x000000a4, - 0x00000000, 0x65646f6d, 0xabab006c, 0x00030002, 0x00040004, 0x00000000, - 0x00000000, 0x6a6f7270, 0x69746365, 0x6e416e6f, 0x65695664, 0x694d0077, - 0x736f7263, 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, - 0x706d6f43, 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, - 0xababab00, 0x4e475349, 0x00000068, 0x00000003, 0x00000008, 0x00000050, - 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000707, 0x00000059, - 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000062, - 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x49534f50, - 0x4e4f4954, 0x58455400, 0x524f4f43, 0x4f430044, 0x00524f4c, 0x4e47534f, - 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, - 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, - 0x00000003, 0x00000001, 0x00000c03, 0x00000065, 0x00000000, 0x00000000, - 0x00000003, 0x00000002, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, + 0x43425844, 0x62dfae5f, 0x3e8bd8df, 0x9ec97127, 0x5044eefb, 0x00000001, + 0x00000598, 0x00000006, 0x00000038, 0x0000016c, 0x00000334, 0x000003b0, + 0x000004b4, 0x00000524, 0x396e6f41, 0x0000012c, 0x0000012c, 0xfffe0200, + 0x000000f8, 0x00000034, 0x00240001, 0x00300000, 0x00300000, 0x00240000, + 0x00300001, 0x00000000, 0x00010008, 0x00000000, 0x00000000, 0xfffe0200, + 0x0200001f, 0x80000005, 0x900f0000, 0x0200001f, 0x80010005, 0x900f0001, + 0x0200001f, 0x80020005, 0x900f0002, 0x03000005, 0x800f0000, 0x90550000, + 0xa0e40002, 0x04000004, 0x800f0000, 0x90000000, 0xa0e40001, 0x80e40000, + 0x04000004, 0x800f0000, 0x90aa0000, 0xa0e40003, 0x80e40000, 0x03000002, + 0x800f0000, 0x80e40000, 0xa0e40004, 0x03000005, 0x800f0001, 0x80550000, + 0xa0e40006, 0x04000004, 0x800f0001, 0x80000000, 0xa0e40005, 0x80e40001, + 0x04000004, 0x800f0001, 0x80aa0000, 0xa0e40007, 0x80e40001, 0x04000004, + 0x800f0000, 0x80ff0000, 0xa0e40008, 0x80e40001, 0x04000004, 0xc0030000, + 0x80ff0000, 0xa0e40000, 0x80e40000, 0x02000001, 0xc00c0000, 0x80e40000, + 0x02000001, 0xe0030000, 0x90e40001, 0x02000001, 0xe00f0001, 0x90e40002, + 0x0000ffff, 0x52444853, 0x000001c0, 0x00010040, 0x00000070, 0x04000059, + 0x00208e46, 0x00000000, 0x00000008, 0x0300005f, 0x00101072, 0x00000000, + 0x0300005f, 0x00101032, 0x00000001, 0x0300005f, 0x001010f2, 0x00000002, + 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x00102032, + 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x02000068, 0x00000002, + 0x08000038, 0x001000f2, 0x00000000, 0x00101556, 0x00000000, 0x00208e46, + 0x00000000, 0x00000001, 0x0a000032, 0x001000f2, 0x00000000, 0x00101006, + 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x00100e46, 0x00000000, + 0x0a000032, 0x001000f2, 0x00000000, 0x00101aa6, 0x00000000, 0x00208e46, + 0x00000000, 0x00000002, 0x00100e46, 0x00000000, 0x08000000, 0x001000f2, + 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000003, + 0x08000038, 0x001000f2, 0x00000001, 0x00100556, 0x00000000, 0x00208e46, + 0x00000000, 0x00000005, 0x0a000032, 0x001000f2, 0x00000001, 0x00100006, + 0x00000000, 0x00208e46, 0x00000000, 0x00000004, 0x00100e46, 0x00000001, + 0x0a000032, 0x001000f2, 0x00000001, 0x00100aa6, 0x00000000, 0x00208e46, + 0x00000000, 0x00000006, 0x00100e46, 0x00000001, 0x0a000032, 0x001020f2, + 0x00000000, 0x00100ff6, 0x00000000, 0x00208e46, 0x00000000, 0x00000007, + 0x00100e46, 0x00000001, 0x05000036, 0x00102032, 0x00000001, 0x00101046, + 0x00000001, 0x05000036, 0x001020f2, 0x00000002, 0x00101e46, 0x00000002, + 0x0100003e, 0x54415453, 0x00000074, 0x0000000b, 0x00000002, 0x00000000, + 0x00000006, 0x00000003, 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x46454452, 0x000000fc, 0x00000001, 0x00000054, + 0x00000001, 0x0000001c, 0xfffe0400, 0x00000100, 0x000000c6, 0x0000003c, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000001, 0x74726556, 0x68537865, 0x72656461, 0x736e6f43, 0x746e6174, + 0xabab0073, 0x0000003c, 0x00000002, 0x0000006c, 0x00000080, 0x00000000, + 0x00000000, 0x0000009c, 0x00000000, 0x00000040, 0x00000002, 0x000000a4, + 0x00000000, 0x000000b4, 0x00000040, 0x00000040, 0x00000002, 0x000000a4, + 0x00000000, 0x65646f6d, 0xabab006c, 0x00030002, 0x00040004, 0x00000000, + 0x00000000, 0x6a6f7270, 0x69746365, 0x6e416e6f, 0x65695664, 0x694d0077, + 0x736f7263, 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, + 0x706d6f43, 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, + 0xababab00, 0x4e475349, 0x00000068, 0x00000003, 0x00000008, 0x00000050, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000707, 0x00000059, + 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000062, + 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x49534f50, + 0x4e4f4954, 0x58455400, 0x524f4f43, 0x4f430044, 0x00524f4c, 0x4e47534f, + 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, + 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, + 0x00000003, 0x00000001, 0x00000c03, 0x00000065, 0x00000000, 0x00000000, + 0x00000003, 0x00000002, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f }; #elif defined(D3D11_USE_SHADER_MODEL_4_0_level_9_3) static const DWORD D3D11_VertexShader[] = { - 0x43425844, 0x01a24e41, 0x696af551, 0x4b2a87d1, 0x82ea03f6, 0x00000001, - 0x00000598, 0x00000006, 0x00000038, 0x0000016c, 0x00000334, 0x000003b0, - 0x000004b4, 0x00000524, 0x396e6f41, 0x0000012c, 0x0000012c, 0xfffe0200, - 0x000000f8, 0x00000034, 0x00240001, 0x00300000, 0x00300000, 0x00240000, - 0x00300001, 0x00000000, 0x00010008, 0x00000000, 0x00000000, 0xfffe0201, - 0x0200001f, 0x80000005, 0x900f0000, 0x0200001f, 0x80010005, 0x900f0001, - 0x0200001f, 0x80020005, 0x900f0002, 0x03000005, 0x800f0000, 0x90550000, - 0xa0e40002, 0x04000004, 0x800f0000, 0x90000000, 0xa0e40001, 0x80e40000, - 0x04000004, 0x800f0000, 0x90aa0000, 0xa0e40003, 0x80e40000, 0x03000002, - 0x800f0000, 0x80e40000, 0xa0e40004, 0x03000005, 0x800f0001, 0x80550000, - 0xa0e40006, 0x04000004, 0x800f0001, 0x80000000, 0xa0e40005, 0x80e40001, - 0x04000004, 0x800f0001, 0x80aa0000, 0xa0e40007, 0x80e40001, 0x04000004, - 0x800f0000, 0x80ff0000, 0xa0e40008, 0x80e40001, 0x04000004, 0xc0030000, - 0x80ff0000, 0xa0e40000, 0x80e40000, 0x02000001, 0xc00c0000, 0x80e40000, - 0x02000001, 0xe0030000, 0x90e40001, 0x02000001, 0xe00f0001, 0x90e40002, - 0x0000ffff, 0x52444853, 0x000001c0, 0x00010040, 0x00000070, 0x04000059, - 0x00208e46, 0x00000000, 0x00000008, 0x0300005f, 0x00101072, 0x00000000, - 0x0300005f, 0x00101032, 0x00000001, 0x0300005f, 0x001010f2, 0x00000002, - 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x00102032, - 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x02000068, 0x00000002, - 0x08000038, 0x001000f2, 0x00000000, 0x00101556, 0x00000000, 0x00208e46, - 0x00000000, 0x00000001, 0x0a000032, 0x001000f2, 0x00000000, 0x00101006, - 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x00100e46, 0x00000000, - 0x0a000032, 0x001000f2, 0x00000000, 0x00101aa6, 0x00000000, 0x00208e46, - 0x00000000, 0x00000002, 0x00100e46, 0x00000000, 0x08000000, 0x001000f2, - 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000003, - 0x08000038, 0x001000f2, 0x00000001, 0x00100556, 0x00000000, 0x00208e46, - 0x00000000, 0x00000005, 0x0a000032, 0x001000f2, 0x00000001, 0x00100006, - 0x00000000, 0x00208e46, 0x00000000, 0x00000004, 0x00100e46, 0x00000001, - 0x0a000032, 0x001000f2, 0x00000001, 0x00100aa6, 0x00000000, 0x00208e46, - 0x00000000, 0x00000006, 0x00100e46, 0x00000001, 0x0a000032, 0x001020f2, - 0x00000000, 0x00100ff6, 0x00000000, 0x00208e46, 0x00000000, 0x00000007, - 0x00100e46, 0x00000001, 0x05000036, 0x00102032, 0x00000001, 0x00101046, - 0x00000001, 0x05000036, 0x001020f2, 0x00000002, 0x00101e46, 0x00000002, - 0x0100003e, 0x54415453, 0x00000074, 0x0000000b, 0x00000002, 0x00000000, - 0x00000006, 0x00000003, 0x00000000, 0x00000000, 0x00000001, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x46454452, 0x000000fc, 0x00000001, 0x00000054, - 0x00000001, 0x0000001c, 0xfffe0400, 0x00000100, 0x000000c6, 0x0000003c, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, - 0x00000001, 0x74726556, 0x68537865, 0x72656461, 0x736e6f43, 0x746e6174, - 0xabab0073, 0x0000003c, 0x00000002, 0x0000006c, 0x00000080, 0x00000000, - 0x00000000, 0x0000009c, 0x00000000, 0x00000040, 0x00000002, 0x000000a4, - 0x00000000, 0x000000b4, 0x00000040, 0x00000040, 0x00000002, 0x000000a4, - 0x00000000, 0x65646f6d, 0xabab006c, 0x00030002, 0x00040004, 0x00000000, - 0x00000000, 0x6a6f7270, 0x69746365, 0x6e416e6f, 0x65695664, 0x694d0077, - 0x736f7263, 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, - 0x706d6f43, 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, - 0xababab00, 0x4e475349, 0x00000068, 0x00000003, 0x00000008, 0x00000050, - 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000707, 0x00000059, - 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000062, - 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x49534f50, - 0x4e4f4954, 0x58455400, 0x524f4f43, 0x4f430044, 0x00524f4c, 0x4e47534f, - 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, - 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, - 0x00000003, 0x00000001, 0x00000c03, 0x00000065, 0x00000000, 0x00000000, - 0x00000003, 0x00000002, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, - 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f + 0x43425844, 0x01a24e41, 0x696af551, 0x4b2a87d1, 0x82ea03f6, 0x00000001, + 0x00000598, 0x00000006, 0x00000038, 0x0000016c, 0x00000334, 0x000003b0, + 0x000004b4, 0x00000524, 0x396e6f41, 0x0000012c, 0x0000012c, 0xfffe0200, + 0x000000f8, 0x00000034, 0x00240001, 0x00300000, 0x00300000, 0x00240000, + 0x00300001, 0x00000000, 0x00010008, 0x00000000, 0x00000000, 0xfffe0201, + 0x0200001f, 0x80000005, 0x900f0000, 0x0200001f, 0x80010005, 0x900f0001, + 0x0200001f, 0x80020005, 0x900f0002, 0x03000005, 0x800f0000, 0x90550000, + 0xa0e40002, 0x04000004, 0x800f0000, 0x90000000, 0xa0e40001, 0x80e40000, + 0x04000004, 0x800f0000, 0x90aa0000, 0xa0e40003, 0x80e40000, 0x03000002, + 0x800f0000, 0x80e40000, 0xa0e40004, 0x03000005, 0x800f0001, 0x80550000, + 0xa0e40006, 0x04000004, 0x800f0001, 0x80000000, 0xa0e40005, 0x80e40001, + 0x04000004, 0x800f0001, 0x80aa0000, 0xa0e40007, 0x80e40001, 0x04000004, + 0x800f0000, 0x80ff0000, 0xa0e40008, 0x80e40001, 0x04000004, 0xc0030000, + 0x80ff0000, 0xa0e40000, 0x80e40000, 0x02000001, 0xc00c0000, 0x80e40000, + 0x02000001, 0xe0030000, 0x90e40001, 0x02000001, 0xe00f0001, 0x90e40002, + 0x0000ffff, 0x52444853, 0x000001c0, 0x00010040, 0x00000070, 0x04000059, + 0x00208e46, 0x00000000, 0x00000008, 0x0300005f, 0x00101072, 0x00000000, + 0x0300005f, 0x00101032, 0x00000001, 0x0300005f, 0x001010f2, 0x00000002, + 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x00102032, + 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x02000068, 0x00000002, + 0x08000038, 0x001000f2, 0x00000000, 0x00101556, 0x00000000, 0x00208e46, + 0x00000000, 0x00000001, 0x0a000032, 0x001000f2, 0x00000000, 0x00101006, + 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x00100e46, 0x00000000, + 0x0a000032, 0x001000f2, 0x00000000, 0x00101aa6, 0x00000000, 0x00208e46, + 0x00000000, 0x00000002, 0x00100e46, 0x00000000, 0x08000000, 0x001000f2, + 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000003, + 0x08000038, 0x001000f2, 0x00000001, 0x00100556, 0x00000000, 0x00208e46, + 0x00000000, 0x00000005, 0x0a000032, 0x001000f2, 0x00000001, 0x00100006, + 0x00000000, 0x00208e46, 0x00000000, 0x00000004, 0x00100e46, 0x00000001, + 0x0a000032, 0x001000f2, 0x00000001, 0x00100aa6, 0x00000000, 0x00208e46, + 0x00000000, 0x00000006, 0x00100e46, 0x00000001, 0x0a000032, 0x001020f2, + 0x00000000, 0x00100ff6, 0x00000000, 0x00208e46, 0x00000000, 0x00000007, + 0x00100e46, 0x00000001, 0x05000036, 0x00102032, 0x00000001, 0x00101046, + 0x00000001, 0x05000036, 0x001020f2, 0x00000002, 0x00101e46, 0x00000002, + 0x0100003e, 0x54415453, 0x00000074, 0x0000000b, 0x00000002, 0x00000000, + 0x00000006, 0x00000003, 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x46454452, 0x000000fc, 0x00000001, 0x00000054, + 0x00000001, 0x0000001c, 0xfffe0400, 0x00000100, 0x000000c6, 0x0000003c, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000001, 0x74726556, 0x68537865, 0x72656461, 0x736e6f43, 0x746e6174, + 0xabab0073, 0x0000003c, 0x00000002, 0x0000006c, 0x00000080, 0x00000000, + 0x00000000, 0x0000009c, 0x00000000, 0x00000040, 0x00000002, 0x000000a4, + 0x00000000, 0x000000b4, 0x00000040, 0x00000040, 0x00000002, 0x000000a4, + 0x00000000, 0x65646f6d, 0xabab006c, 0x00030002, 0x00040004, 0x00000000, + 0x00000000, 0x6a6f7270, 0x69746365, 0x6e416e6f, 0x65695664, 0x694d0077, + 0x736f7263, 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, + 0x706d6f43, 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, + 0xababab00, 0x4e475349, 0x00000068, 0x00000003, 0x00000008, 0x00000050, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000707, 0x00000059, + 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000062, + 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x49534f50, + 0x4e4f4954, 0x58455400, 0x524f4f43, 0x4f430044, 0x00524f4c, 0x4e47534f, + 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, + 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, + 0x00000003, 0x00000001, 0x00000c03, 0x00000065, 0x00000000, 0x00000000, + 0x00000003, 0x00000002, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, + 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f }; #else #error "An appropriate vertex shader is not defined." @@ -576,76 +576,76 @@ DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) { static DXGI_FORMAT SDLPixelFormatToDXGIFormat(Uint32 sdlFormat) { - switch (sdlFormat) { - case SDL_PIXELFORMAT_ARGB8888: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case SDL_PIXELFORMAT_RGB888: - return DXGI_FORMAT_B8G8R8X8_UNORM; - default: - return DXGI_FORMAT_UNKNOWN; - } + switch (sdlFormat) { + case SDL_PIXELFORMAT_ARGB8888: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_RGB888: + return DXGI_FORMAT_B8G8R8X8_UNORM; + default: + return DXGI_FORMAT_UNKNOWN; + } } -SDL_Renderer * -D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) -{ - SDL_Renderer *renderer; - D3D11_RenderData *data; - - renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); - if (!renderer) { - SDL_OutOfMemory(); - return NULL; - } - SDL_zerop(renderer); - - data = new D3D11_RenderData; // Use the C++ 'new' operator to make sure the struct's members initialize using C++ rules - if (!data) { - SDL_OutOfMemory(); - return NULL; - } - data->featureLevel = (D3D_FEATURE_LEVEL) 0; - data->windowSizeInDIPs = XMFLOAT2(0, 0); - data->renderTargetSize = XMFLOAT2(0, 0); - - renderer->WindowEvent = D3D11_WindowEvent; - renderer->CreateTexture = D3D11_CreateTexture; - renderer->UpdateTexture = D3D11_UpdateTexture; - renderer->LockTexture = D3D11_LockTexture; - renderer->UnlockTexture = D3D11_UnlockTexture; - renderer->SetRenderTarget = D3D11_SetRenderTarget; - renderer->UpdateViewport = D3D11_UpdateViewport; - renderer->UpdateClipRect = D3D11_UpdateClipRect; - renderer->RenderClear = D3D11_RenderClear; - renderer->RenderDrawPoints = D3D11_RenderDrawPoints; - renderer->RenderDrawLines = D3D11_RenderDrawLines; - renderer->RenderFillRects = D3D11_RenderFillRects; - renderer->RenderCopy = D3D11_RenderCopy; - renderer->RenderCopyEx = D3D11_RenderCopyEx; - renderer->RenderReadPixels = D3D11_RenderReadPixels; - renderer->RenderPresent = D3D11_RenderPresent; - renderer->DestroyTexture = D3D11_DestroyTexture; - renderer->DestroyRenderer = D3D11_DestroyRenderer; - renderer->info = D3D11_RenderDriver.info; - renderer->driverdata = data; - - // HACK: make sure the SDL_Renderer references the SDL_Window data now, in - // order to give init functions access to the underlying window handle: - renderer->window = window; - - /* Initialize Direct3D resources */ - if (FAILED(D3D11_CreateDeviceResources(renderer))) { - D3D11_DestroyRenderer(renderer); - return NULL; - } - if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) { - D3D11_DestroyRenderer(renderer); - return NULL; - } - - // TODO, WinRT: fill in renderer->info.texture_formats where appropriate - - return renderer; +SDL_Renderer * +D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + SDL_Renderer *renderer; + D3D11_RenderData *data; + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + SDL_zerop(renderer); + + data = new D3D11_RenderData; // Use the C++ 'new' operator to make sure the struct's members initialize using C++ rules + if (!data) { + SDL_OutOfMemory(); + return NULL; + } + data->featureLevel = (D3D_FEATURE_LEVEL) 0; + data->windowSizeInDIPs = XMFLOAT2(0, 0); + data->renderTargetSize = XMFLOAT2(0, 0); + + renderer->WindowEvent = D3D11_WindowEvent; + renderer->CreateTexture = D3D11_CreateTexture; + renderer->UpdateTexture = D3D11_UpdateTexture; + renderer->LockTexture = D3D11_LockTexture; + renderer->UnlockTexture = D3D11_UnlockTexture; + renderer->SetRenderTarget = D3D11_SetRenderTarget; + renderer->UpdateViewport = D3D11_UpdateViewport; + renderer->UpdateClipRect = D3D11_UpdateClipRect; + renderer->RenderClear = D3D11_RenderClear; + renderer->RenderDrawPoints = D3D11_RenderDrawPoints; + renderer->RenderDrawLines = D3D11_RenderDrawLines; + renderer->RenderFillRects = D3D11_RenderFillRects; + renderer->RenderCopy = D3D11_RenderCopy; + renderer->RenderCopyEx = D3D11_RenderCopyEx; + renderer->RenderReadPixels = D3D11_RenderReadPixels; + renderer->RenderPresent = D3D11_RenderPresent; + renderer->DestroyTexture = D3D11_DestroyTexture; + renderer->DestroyRenderer = D3D11_DestroyRenderer; + renderer->info = D3D11_RenderDriver.info; + renderer->driverdata = data; + + // HACK: make sure the SDL_Renderer references the SDL_Window data now, in + // order to give init functions access to the underlying window handle: + renderer->window = window; + + /* Initialize Direct3D resources */ + if (FAILED(D3D11_CreateDeviceResources(renderer))) { + D3D11_DestroyRenderer(renderer); + return NULL; + } + if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) { + D3D11_DestroyRenderer(renderer); + return NULL; + } + + // TODO, WinRT: fill in renderer->info.texture_formats where appropriate + + return renderer; } static void @@ -669,353 +669,353 @@ D3D11_CreateBlendMode(SDL_Renderer * renderer, { D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; HRESULT result = S_OK; - - D3D11_BLEND_DESC blendDesc; - memset(&blendDesc, 0, sizeof(blendDesc)); - blendDesc.AlphaToCoverageEnable = FALSE; - blendDesc.IndependentBlendEnable = FALSE; - blendDesc.RenderTarget[0].BlendEnable = enableBlending; - blendDesc.RenderTarget[0].SrcBlend = srcBlend; - blendDesc.RenderTarget[0].DestBlend = destBlend; - blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[0].SrcBlendAlpha = srcBlendAlpha; - blendDesc.RenderTarget[0].DestBlendAlpha = destBlendAlpha; - blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - result = data->d3dDevice->CreateBlendState(&blendDesc, blendStateOutput); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBlendState", result); - return result; - } - - return S_OK; + + D3D11_BLEND_DESC blendDesc; + memset(&blendDesc, 0, sizeof(blendDesc)); + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = FALSE; + blendDesc.RenderTarget[0].BlendEnable = enableBlending; + blendDesc.RenderTarget[0].SrcBlend = srcBlend; + blendDesc.RenderTarget[0].DestBlend = destBlend; + blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[0].SrcBlendAlpha = srcBlendAlpha; + blendDesc.RenderTarget[0].DestBlendAlpha = destBlendAlpha; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + result = data->d3dDevice->CreateBlendState(&blendDesc, blendStateOutput); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBlendState", result); + return result; + } + + return S_OK; } // Create resources that depend on the device. HRESULT -D3D11_CreateDeviceResources(SDL_Renderer * renderer) -{ - D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; - - // This flag adds support for surfaces with a different color channel ordering - // than the API default. It is required for compatibility with Direct2D. - UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; - - // Make sure Direct3D's debugging feature gets used, if the app requests it. +D3D11_CreateDeviceResources(SDL_Renderer * renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + + // This flag adds support for surfaces with a different color channel ordering + // than the API default. It is required for compatibility with Direct2D. + UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + + // Make sure Direct3D's debugging feature gets used, if the app requests it. const char *hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D11_DEBUG); if (hint) { if (*hint == '1') { creationFlags |= D3D11_CREATE_DEVICE_DEBUG; } - } - - // This array defines the set of DirectX hardware feature levels this app will support. - // Note the ordering should be preserved. - // Don't forget to declare your application's minimum required feature level in its - // description. All applications are assumed to support 9.1 unless otherwise stated. - D3D_FEATURE_LEVEL featureLevels[] = - { - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1 - }; - - // Create the Direct3D 11 API device object and a corresponding context. - ComPtr device; - ComPtr context; - HRESULT result = S_OK; - result = D3D11CreateDevice( - nullptr, // Specify nullptr to use the default adapter. - D3D_DRIVER_TYPE_HARDWARE, - nullptr, - creationFlags, // Set set debug and Direct2D compatibility flags. - featureLevels, // List of feature levels this app can support. - ARRAYSIZE(featureLevels), - D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. - &device, // Returns the Direct3D device created. - &data->featureLevel, // Returns feature level of device created. - &context // Returns the device immediate context. - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", D3D11CreateDevice", result); - return result; - } - - // Get the Direct3D 11.1 API device and context interfaces. - result = device.As(&(data->d3dDevice)); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device to ID3D11Device1", result); - return result; - } - - result = context.As(&data->d3dContext); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext to ID3D11DeviceContext1", result); - return result; - } - - // - // Make note of the maximum texture size - // Max texture sizes are documented on MSDN, at: - // http://msdn.microsoft.com/en-us/library/windows/apps/ff476876.aspx - // - switch (data->d3dDevice->GetFeatureLevel()) { - case D3D_FEATURE_LEVEL_11_1: - case D3D_FEATURE_LEVEL_11_0: - renderer->info.max_texture_width = renderer->info.max_texture_height = 16384; - break; - - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - renderer->info.max_texture_width = renderer->info.max_texture_height = 8192; - break; - - case D3D_FEATURE_LEVEL_9_3: - renderer->info.max_texture_width = renderer->info.max_texture_height = 4096; - break; - - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: - renderer->info.max_texture_width = renderer->info.max_texture_height = 2048; - break; - } - - // - // Load in SDL's one and only vertex shader: - // - result = data->d3dDevice->CreateVertexShader( - D3D11_VertexShader, - sizeof(D3D11_VertexShader), - nullptr, - &data->vertexShader - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateVertexShader", result); - return result; - } - - // - // Create an input layout for SDL's vertex shader: - // - const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - result = data->d3dDevice->CreateInputLayout( - vertexDesc, - ARRAYSIZE(vertexDesc), - D3D11_VertexShader, - sizeof(D3D11_VertexShader), - &data->inputLayout - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateInputLayout", result); - return result; - } - - // - // Load in SDL's pixel shaders - // - - result = data->d3dDevice->CreatePixelShader( - D3D11_PixelShader_Textures, - sizeof(D3D11_PixelShader_Textures), - nullptr, - &data->texturePixelShader - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['textures' shader]", result); - return result; - } - - result = data->d3dDevice->CreatePixelShader( - D3D11_PixelShader_Colors, - sizeof(D3D11_PixelShader_Colors), - nullptr, - &data->colorPixelShader - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['color' shader]", result); - return result; - } - - // - // Setup space to hold vertex shader constants: - // - CD3D11_BUFFER_DESC constantBufferDesc(sizeof(VertexShaderConstants), D3D11_BIND_CONSTANT_BUFFER); - result = data->d3dDevice->CreateBuffer( - &constantBufferDesc, - nullptr, - &data->vertexShaderConstants - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBuffer [vertex shader constants]", result); - return result; - } - - // - // Make sure that the vertex buffer, if already created, gets freed. - // It will be recreated later. - // - data->vertexBuffer = nullptr; - - // - // Create samplers to use when drawing textures: - // - D3D11_SAMPLER_DESC samplerDesc; - samplerDesc.Filter = SDL_D3D11_NEAREST_PIXEL_FILTER; - samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - samplerDesc.MipLODBias = 0.0f; - samplerDesc.MaxAnisotropy = 1; - samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - samplerDesc.BorderColor[0] = 0.0f; - samplerDesc.BorderColor[1] = 0.0f; - samplerDesc.BorderColor[2] = 0.0f; - samplerDesc.BorderColor[3] = 0.0f; - samplerDesc.MinLOD = 0.0f; - samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; - result = data->d3dDevice->CreateSamplerState( - &samplerDesc, - &data->nearestPixelSampler - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateSamplerState [nearest-pixel filter]", result); - return result; - } - - samplerDesc.Filter = SDL_D3D11_LINEAR_FILTER; - result = data->d3dDevice->CreateSamplerState( - &samplerDesc, - &data->linearSampler - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateSamplerState [linear filter]", result); - return result; - } - - // - // Setup Direct3D rasterizer states - // - D3D11_RASTERIZER_DESC rasterDesc; - memset(&rasterDesc, 0, sizeof(rasterDesc)); - rasterDesc.AntialiasedLineEnable = false; - rasterDesc.CullMode = D3D11_CULL_NONE; - rasterDesc.DepthBias = 0; - rasterDesc.DepthBiasClamp = 0.0f; - rasterDesc.DepthClipEnable = true; - rasterDesc.FillMode = D3D11_FILL_SOLID; - rasterDesc.FrontCounterClockwise = false; - rasterDesc.MultisampleEnable = false; - rasterDesc.ScissorEnable = false; - rasterDesc.SlopeScaledDepthBias = 0.0f; - result = data->d3dDevice->CreateRasterizerState(&rasterDesc, &data->mainRasterizer); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRasterizerState [main rasterizer]", result); - return result; - } - - rasterDesc.ScissorEnable = true; - result = data->d3dDevice->CreateRasterizerState(&rasterDesc, &data->clippedRasterizer); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRasterizerState [clipped rasterizer]", result); - return result; - } - - // - // Create blending states: - // - result = D3D11_CreateBlendMode( - renderer, - TRUE, - D3D11_BLEND_SRC_ALPHA, /* srcBlend */ - D3D11_BLEND_INV_SRC_ALPHA, /* destBlend */ - D3D11_BLEND_ONE, /* srcBlendAlpha */ - D3D11_BLEND_INV_SRC_ALPHA, /* destBlendAlpha */ - &data->blendModeBlend); - if (FAILED(result)) { - // D3D11_CreateBlendMode will set the SDL error, if it fails - return result; - } - - result = D3D11_CreateBlendMode( - renderer, - TRUE, - D3D11_BLEND_SRC_ALPHA, /* srcBlend */ - D3D11_BLEND_ONE, /* destBlend */ - D3D11_BLEND_ZERO, /* srcBlendAlpha */ - D3D11_BLEND_ONE, /* destBlendAlpha */ - &data->blendModeAdd); - if (FAILED(result)) { - // D3D11_CreateBlendMode will set the SDL error, if it fails - return result; - } - - result = D3D11_CreateBlendMode( - renderer, - TRUE, - D3D11_BLEND_ZERO, /* srcBlend */ - D3D11_BLEND_SRC_COLOR, /* destBlend */ - D3D11_BLEND_ZERO, /* srcBlendAlpha */ - D3D11_BLEND_ONE, /* destBlendAlpha */ - &data->blendModeMod); - if (FAILED(result)) { - // D3D11_CreateBlendMode will set the SDL error, if it fails - return result; - } - - // - // All done! - // - return S_OK; + } + + // This array defines the set of DirectX hardware feature levels this app will support. + // Note the ordering should be preserved. + // Don't forget to declare your application's minimum required feature level in its + // description. All applications are assumed to support 9.1 unless otherwise stated. + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + + // Create the Direct3D 11 API device object and a corresponding context. + ComPtr device; + ComPtr context; + HRESULT result = S_OK; + result = D3D11CreateDevice( + nullptr, // Specify nullptr to use the default adapter. + D3D_DRIVER_TYPE_HARDWARE, + nullptr, + creationFlags, // Set set debug and Direct2D compatibility flags. + featureLevels, // List of feature levels this app can support. + ARRAYSIZE(featureLevels), + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. + &device, // Returns the Direct3D device created. + &data->featureLevel, // Returns feature level of device created. + &context // Returns the device immediate context. + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", D3D11CreateDevice", result); + return result; + } + + // Get the Direct3D 11.1 API device and context interfaces. + result = device.As(&(data->d3dDevice)); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device to ID3D11Device1", result); + return result; + } + + result = context.As(&data->d3dContext); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext to ID3D11DeviceContext1", result); + return result; + } + + // + // Make note of the maximum texture size + // Max texture sizes are documented on MSDN, at: + // http://msdn.microsoft.com/en-us/library/windows/apps/ff476876.aspx + // + switch (data->d3dDevice->GetFeatureLevel()) { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + renderer->info.max_texture_width = renderer->info.max_texture_height = 16384; + break; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + renderer->info.max_texture_width = renderer->info.max_texture_height = 8192; + break; + + case D3D_FEATURE_LEVEL_9_3: + renderer->info.max_texture_width = renderer->info.max_texture_height = 4096; + break; + + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + renderer->info.max_texture_width = renderer->info.max_texture_height = 2048; + break; + } + + // + // Load in SDL's one and only vertex shader: + // + result = data->d3dDevice->CreateVertexShader( + D3D11_VertexShader, + sizeof(D3D11_VertexShader), + nullptr, + &data->vertexShader + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateVertexShader", result); + return result; + } + + // + // Create an input layout for SDL's vertex shader: + // + const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + result = data->d3dDevice->CreateInputLayout( + vertexDesc, + ARRAYSIZE(vertexDesc), + D3D11_VertexShader, + sizeof(D3D11_VertexShader), + &data->inputLayout + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateInputLayout", result); + return result; + } + + // + // Load in SDL's pixel shaders + // + + result = data->d3dDevice->CreatePixelShader( + D3D11_PixelShader_Textures, + sizeof(D3D11_PixelShader_Textures), + nullptr, + &data->texturePixelShader + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['textures' shader]", result); + return result; + } + + result = data->d3dDevice->CreatePixelShader( + D3D11_PixelShader_Colors, + sizeof(D3D11_PixelShader_Colors), + nullptr, + &data->colorPixelShader + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['color' shader]", result); + return result; + } + + // + // Setup space to hold vertex shader constants: + // + CD3D11_BUFFER_DESC constantBufferDesc(sizeof(VertexShaderConstants), D3D11_BIND_CONSTANT_BUFFER); + result = data->d3dDevice->CreateBuffer( + &constantBufferDesc, + nullptr, + &data->vertexShaderConstants + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBuffer [vertex shader constants]", result); + return result; + } + + // + // Make sure that the vertex buffer, if already created, gets freed. + // It will be recreated later. + // + data->vertexBuffer = nullptr; + + // + // Create samplers to use when drawing textures: + // + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = SDL_D3D11_NEAREST_PIXEL_FILTER; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.MipLODBias = 0.0f; + samplerDesc.MaxAnisotropy = 1; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + samplerDesc.BorderColor[0] = 0.0f; + samplerDesc.BorderColor[1] = 0.0f; + samplerDesc.BorderColor[2] = 0.0f; + samplerDesc.BorderColor[3] = 0.0f; + samplerDesc.MinLOD = 0.0f; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + result = data->d3dDevice->CreateSamplerState( + &samplerDesc, + &data->nearestPixelSampler + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateSamplerState [nearest-pixel filter]", result); + return result; + } + + samplerDesc.Filter = SDL_D3D11_LINEAR_FILTER; + result = data->d3dDevice->CreateSamplerState( + &samplerDesc, + &data->linearSampler + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateSamplerState [linear filter]", result); + return result; + } + + // + // Setup Direct3D rasterizer states + // + D3D11_RASTERIZER_DESC rasterDesc; + memset(&rasterDesc, 0, sizeof(rasterDesc)); + rasterDesc.AntialiasedLineEnable = false; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.DepthBias = 0; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = true; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.FrontCounterClockwise = false; + rasterDesc.MultisampleEnable = false; + rasterDesc.ScissorEnable = false; + rasterDesc.SlopeScaledDepthBias = 0.0f; + result = data->d3dDevice->CreateRasterizerState(&rasterDesc, &data->mainRasterizer); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRasterizerState [main rasterizer]", result); + return result; + } + + rasterDesc.ScissorEnable = true; + result = data->d3dDevice->CreateRasterizerState(&rasterDesc, &data->clippedRasterizer); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRasterizerState [clipped rasterizer]", result); + return result; + } + + // + // Create blending states: + // + result = D3D11_CreateBlendMode( + renderer, + TRUE, + D3D11_BLEND_SRC_ALPHA, /* srcBlend */ + D3D11_BLEND_INV_SRC_ALPHA, /* destBlend */ + D3D11_BLEND_ONE, /* srcBlendAlpha */ + D3D11_BLEND_INV_SRC_ALPHA, /* destBlendAlpha */ + &data->blendModeBlend); + if (FAILED(result)) { + // D3D11_CreateBlendMode will set the SDL error, if it fails + return result; + } + + result = D3D11_CreateBlendMode( + renderer, + TRUE, + D3D11_BLEND_SRC_ALPHA, /* srcBlend */ + D3D11_BLEND_ONE, /* destBlend */ + D3D11_BLEND_ZERO, /* srcBlendAlpha */ + D3D11_BLEND_ONE, /* destBlendAlpha */ + &data->blendModeAdd); + if (FAILED(result)) { + // D3D11_CreateBlendMode will set the SDL error, if it fails + return result; + } + + result = D3D11_CreateBlendMode( + renderer, + TRUE, + D3D11_BLEND_ZERO, /* srcBlend */ + D3D11_BLEND_SRC_COLOR, /* destBlend */ + D3D11_BLEND_ZERO, /* srcBlendAlpha */ + D3D11_BLEND_ONE, /* destBlendAlpha */ + &data->blendModeMod); + if (FAILED(result)) { + // D3D11_CreateBlendMode will set the SDL error, if it fails + return result; + } + + // + // All done! + // + return S_OK; } #ifdef __WINRT__ - -static ABI::Windows::UI::Core::ICoreWindow * -D3D11_GetCoreWindowFromSDLRenderer(SDL_Renderer * renderer) -{ - SDL_Window * sdlWindow = renderer->window; - if ( ! renderer->window ) { - return nullptr; - } - - SDL_SysWMinfo sdlWindowInfo; - SDL_VERSION(&sdlWindowInfo.version); - if ( ! SDL_GetWindowWMInfo(sdlWindow, &sdlWindowInfo) ) { - return nullptr; - } - - if (sdlWindowInfo.subsystem != SDL_SYSWM_WINRT) { - return nullptr; - } - - if ( ! sdlWindowInfo.info.winrt.window ) { - return nullptr; - } - - ABI::Windows::UI::Core::ICoreWindow * coreWindow = nullptr; - if (FAILED(sdlWindowInfo.info.winrt.window->QueryInterface(&coreWindow))) { - return nullptr; - } - - return coreWindow; + +static ABI::Windows::UI::Core::ICoreWindow * +D3D11_GetCoreWindowFromSDLRenderer(SDL_Renderer * renderer) +{ + SDL_Window * sdlWindow = renderer->window; + if ( ! renderer->window ) { + return nullptr; + } + + SDL_SysWMinfo sdlWindowInfo; + SDL_VERSION(&sdlWindowInfo.version); + if ( ! SDL_GetWindowWMInfo(sdlWindow, &sdlWindowInfo) ) { + return nullptr; + } + + if (sdlWindowInfo.subsystem != SDL_SYSWM_WINRT) { + return nullptr; + } + + if ( ! sdlWindowInfo.info.winrt.window ) { + return nullptr; + } + + ABI::Windows::UI::Core::ICoreWindow * coreWindow = nullptr; + if (FAILED(sdlWindowInfo.info.winrt.window->QueryInterface(&coreWindow))) { + return nullptr; + } + + return coreWindow; } // Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels. -static float -D3D11_ConvertDipsToPixels(float dips) -{ - static const float dipsPerInch = 96.0f; - return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer. +static float +D3D11_ConvertDipsToPixels(float dips) +{ + static const float dipsPerInch = 96.0f; + return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer. } #endif @@ -1033,27 +1033,27 @@ D3D11_GetRotationForOrientation(Windows::Graphics::Display::DisplayOrientations // // Windows Phone rotations // - case DisplayOrientations::Landscape: - return DXGI_MODE_ROTATION_ROTATE90; - case DisplayOrientations::Portrait: - return DXGI_MODE_ROTATION_IDENTITY; - case DisplayOrientations::LandscapeFlipped: - return DXGI_MODE_ROTATION_ROTATE270; - case DisplayOrientations::PortraitFlipped: - return DXGI_MODE_ROTATION_ROTATE180; + case DisplayOrientations::Landscape: + return DXGI_MODE_ROTATION_ROTATE90; + case DisplayOrientations::Portrait: + return DXGI_MODE_ROTATION_IDENTITY; + case DisplayOrientations::LandscapeFlipped: + return DXGI_MODE_ROTATION_ROTATE270; + case DisplayOrientations::PortraitFlipped: + return DXGI_MODE_ROTATION_ROTATE180; #else // // Non-Windows-Phone rotations (ex: Windows 8, Windows RT) - // - case DisplayOrientations::Landscape: - return DXGI_MODE_ROTATION_IDENTITY; - case DisplayOrientations::Portrait: - return DXGI_MODE_ROTATION_ROTATE270; - case DisplayOrientations::LandscapeFlipped: - return DXGI_MODE_ROTATION_ROTATE180; - case DisplayOrientations::PortraitFlipped: - return DXGI_MODE_ROTATION_ROTATE90; -#endif // WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // + case DisplayOrientations::Landscape: + return DXGI_MODE_ROTATION_IDENTITY; + case DisplayOrientations::Portrait: + return DXGI_MODE_ROTATION_ROTATE270; + case DisplayOrientations::LandscapeFlipped: + return DXGI_MODE_ROTATION_ROTATE180; + case DisplayOrientations::PortraitFlipped: + return DXGI_MODE_ROTATION_ROTATE90; +#endif // WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP default: return DXGI_MODE_ROTATION_UNSPECIFIED; @@ -1084,9 +1084,9 @@ D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRec outRect->bottom = sdlRect->y + sdlRect->h; break; case DXGI_MODE_ROTATION_ROTATE270: - outRect->left = sdlRect->y; - outRect->right = sdlRect->y + sdlRect->h; - outRect->top = renderer->viewport.w - sdlRect->x - sdlRect->w; + outRect->left = sdlRect->y; + outRect->right = sdlRect->y + sdlRect->h; + outRect->top = renderer->viewport.w - sdlRect->x - sdlRect->w; outRect->bottom = renderer->viewport.w - sdlRect->x; break; case DXGI_MODE_ROTATION_ROTATE180: @@ -1098,7 +1098,7 @@ D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRec case DXGI_MODE_ROTATION_ROTATE90: outRect->left = renderer->viewport.h - sdlRect->y - sdlRect->h; outRect->right = renderer->viewport.h - sdlRect->y; - outRect->top = sdlRect->x; + outRect->top = sdlRect->x; outRect->bottom = sdlRect->x + sdlRect->h; break; default: @@ -1110,24 +1110,24 @@ D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRec // Initialize all resources that change when the window's size changes. // TODO, WinRT: get D3D11_CreateWindowSizeDependentResources working on Win32 -HRESULT -D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) -{ - D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; - HRESULT result = S_OK; - ABI::Windows::UI::Core::ICoreWindow * coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer); - - // Store the window bounds so the next time we get a SizeChanged event we can - // avoid rebuilding everything if the size is identical. - ABI::Windows::Foundation::Rect nativeWindowBounds; - if (coreWindow) { - result = coreWindow->get_Bounds(&nativeWindowBounds); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__", ICoreWindow::get_Bounds [get native-window bounds]", result); - return result; - } - } else { - // TODO, WinRT, XAML: clean up window-bounds code in D3D11_CreateWindowSizeDependentResources +HRESULT +D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + HRESULT result = S_OK; + ABI::Windows::UI::Core::ICoreWindow * coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer); + + // Store the window bounds so the next time we get a SizeChanged event we can + // avoid rebuilding everything if the size is identical. + ABI::Windows::Foundation::Rect nativeWindowBounds; + if (coreWindow) { + result = coreWindow->get_Bounds(&nativeWindowBounds); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__", ICoreWindow::get_Bounds [get native-window bounds]", result); + return result; + } + } else { + // TODO, WinRT, XAML: clean up window-bounds code in D3D11_CreateWindowSizeDependentResources SDL_DisplayMode displayMode; if (SDL_GetDesktopDisplayMode(0, &displayMode) < 0) { SDL_SetError(__FUNCTION__", Get Window Bounds (XAML): Unable to retrieve the native window's size"); @@ -1135,222 +1135,222 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) } nativeWindowBounds.Width = (FLOAT) displayMode.w; - nativeWindowBounds.Height = (FLOAT) displayMode.h; - } - - // TODO, WinRT, XAML: see if window/control sizes are in DIPs, or something else. If something else, then adjust renderer size tracking accordingly. - data->windowSizeInDIPs.x = nativeWindowBounds.Width; - data->windowSizeInDIPs.y = nativeWindowBounds.Height; - - // Calculate the necessary swap chain and render target size in pixels. - float windowWidth = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.x); - float windowHeight = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.y); - - // The width and height of the swap chain must be based on the window's - // landscape-oriented width and height. If the window is in a portrait - // orientation, the dimensions must be reversed. - data->orientation = DisplayProperties::CurrentOrientation; - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - const bool swapDimensions = false; -#else - const bool swapDimensions = D3D11_IsDisplayRotated90Degrees(data->orientation); -#endif - data->renderTargetSize.x = swapDimensions ? windowHeight : windowWidth; - data->renderTargetSize.y = swapDimensions ? windowWidth : windowHeight; - - if(data->swapChain != nullptr) - { - // If the swap chain already exists, resize it. - result = data->swapChain->ResizeBuffers( - 2, // Double-buffered swap chain. - static_cast(data->renderTargetSize.x), - static_cast(data->renderTargetSize.y), - DXGI_FORMAT_B8G8R8A8_UNORM, - 0 - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::ResizeBuffers", result); - return result; - } - } - else - { - const bool usingXAML = (coreWindow == nullptr); - - // Otherwise, create a new one using the same adapter as the existing Direct3D device. - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; - swapChainDesc.Width = static_cast(data->renderTargetSize.x); // Match the size of the window. - swapChainDesc.Height = static_cast(data->renderTargetSize.y); - swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format. - swapChainDesc.Stereo = false; - swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling. - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency. -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed. - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported. -#else - if (usingXAML) { - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - } else { - swapChainDesc.Scaling = DXGI_SCALING_NONE; - } - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect. -#endif - swapChainDesc.Flags = 0; - - ComPtr dxgiDevice; - result = data->d3dDevice.As(&dxgiDevice); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1 to IDXGIDevice1", result); - return result; - } - - ComPtr dxgiAdapter; - result = dxgiDevice->GetAdapter(&dxgiAdapter); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIDevice1::GetAdapter", result); - return result; - } - - ComPtr dxgiFactory; - result = dxgiAdapter->GetParent( - __uuidof(IDXGIFactory2), - &dxgiFactory - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter::GetParent", result); - return result; - } - - if (usingXAML) { - result = dxgiFactory->CreateSwapChainForComposition( - data->d3dDevice.Get(), - &swapChainDesc, - nullptr, - &data->swapChain); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory2::CreateSwapChainForComposition", result); - return result; - } - -#if WINAPI_FAMILY == WINAPI_FAMILY_APP - result = WINRT_GlobalSwapChainBackgroundPanelNative->SetSwapChain(data->swapChain.Get()); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ISwapChainBackgroundPanelNative::SetSwapChain", result); - return result; - } -#else - SDL_SetError(__FUNCTION__ ", XAML support is not yet available for Windows Phone"); - return E_FAIL; -#endif - } else { - IUnknown * coreWindowAsIUnknown = nullptr; - result = coreWindow->QueryInterface(&coreWindowAsIUnknown); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ICoreWindow to IUnknown", result); - return result; - } - - result = dxgiFactory->CreateSwapChainForCoreWindow( - data->d3dDevice.Get(), - coreWindowAsIUnknown, - &swapChainDesc, - nullptr, // Allow on all displays. - &data->swapChain - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory2::CreateSwapChainForCoreWindow", result); - return result; - } - } - - // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and - // ensures that the application will only render after each VSync, minimizing power consumption. - result = dxgiDevice->SetMaximumFrameLatency(1); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIDevice1::SetMaximumFrameLatency", result); - return result; - } - } - -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP - // Set the proper orientation for the swap chain, and generate the - // 3D matrix transformation for rendering to the rotated swap chain. - // - // To note, the call for this, IDXGISwapChain1::SetRotation, is not necessary - // on Windows Phone, nor is it supported there. It's only needed in Windows 8/RT. - DXGI_MODE_ROTATION rotation = D3D11_GetRotationForOrientation(data->orientation); - result = data->swapChain->SetRotation(rotation); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::SetRotation" , result); - return result; - } -#endif - - // Create a render target view of the swap chain back buffer. - ComPtr backBuffer; - result = data->swapChain->GetBuffer( - 0, - __uuidof(ID3D11Texture2D), - &backBuffer - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::GetBuffer [back-buffer]", result); - return result; - } - - result = data->d3dDevice->CreateRenderTargetView( - backBuffer.Get(), - nullptr, - &data->mainRenderTargetView - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRenderTargetView", result); - return result; - } - - if (D3D11_UpdateViewport(renderer) != 0) { - // D3D11_UpdateViewport will set the SDL error if it fails. - return E_FAIL; - } - - return S_OK; + nativeWindowBounds.Height = (FLOAT) displayMode.h; + } + + // TODO, WinRT, XAML: see if window/control sizes are in DIPs, or something else. If something else, then adjust renderer size tracking accordingly. + data->windowSizeInDIPs.x = nativeWindowBounds.Width; + data->windowSizeInDIPs.y = nativeWindowBounds.Height; + + // Calculate the necessary swap chain and render target size in pixels. + float windowWidth = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.x); + float windowHeight = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.y); + + // The width and height of the swap chain must be based on the window's + // landscape-oriented width and height. If the window is in a portrait + // orientation, the dimensions must be reversed. + data->orientation = DisplayProperties::CurrentOrientation; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + const bool swapDimensions = false; +#else + const bool swapDimensions = D3D11_IsDisplayRotated90Degrees(data->orientation); +#endif + data->renderTargetSize.x = swapDimensions ? windowHeight : windowWidth; + data->renderTargetSize.y = swapDimensions ? windowWidth : windowHeight; + + if(data->swapChain != nullptr) + { + // If the swap chain already exists, resize it. + result = data->swapChain->ResizeBuffers( + 2, // Double-buffered swap chain. + static_cast(data->renderTargetSize.x), + static_cast(data->renderTargetSize.y), + DXGI_FORMAT_B8G8R8A8_UNORM, + 0 + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::ResizeBuffers", result); + return result; + } + } + else + { + const bool usingXAML = (coreWindow == nullptr); + + // Otherwise, create a new one using the same adapter as the existing Direct3D device. + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; + swapChainDesc.Width = static_cast(data->renderTargetSize.x); // Match the size of the window. + swapChainDesc.Height = static_cast(data->renderTargetSize.y); + swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format. + swapChainDesc.Stereo = false; + swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling. + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency. +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed. + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported. +#else + if (usingXAML) { + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + } else { + swapChainDesc.Scaling = DXGI_SCALING_NONE; + } + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect. +#endif + swapChainDesc.Flags = 0; + + ComPtr dxgiDevice; + result = data->d3dDevice.As(&dxgiDevice); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1 to IDXGIDevice1", result); + return result; + } + + ComPtr dxgiAdapter; + result = dxgiDevice->GetAdapter(&dxgiAdapter); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIDevice1::GetAdapter", result); + return result; + } + + ComPtr dxgiFactory; + result = dxgiAdapter->GetParent( + __uuidof(IDXGIFactory2), + &dxgiFactory + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter::GetParent", result); + return result; + } + + if (usingXAML) { + result = dxgiFactory->CreateSwapChainForComposition( + data->d3dDevice.Get(), + &swapChainDesc, + nullptr, + &data->swapChain); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory2::CreateSwapChainForComposition", result); + return result; + } + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP + result = WINRT_GlobalSwapChainBackgroundPanelNative->SetSwapChain(data->swapChain.Get()); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ISwapChainBackgroundPanelNative::SetSwapChain", result); + return result; + } +#else + SDL_SetError(__FUNCTION__ ", XAML support is not yet available for Windows Phone"); + return E_FAIL; +#endif + } else { + IUnknown * coreWindowAsIUnknown = nullptr; + result = coreWindow->QueryInterface(&coreWindowAsIUnknown); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ICoreWindow to IUnknown", result); + return result; + } + + result = dxgiFactory->CreateSwapChainForCoreWindow( + data->d3dDevice.Get(), + coreWindowAsIUnknown, + &swapChainDesc, + nullptr, // Allow on all displays. + &data->swapChain + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory2::CreateSwapChainForCoreWindow", result); + return result; + } + } + + // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and + // ensures that the application will only render after each VSync, minimizing power consumption. + result = dxgiDevice->SetMaximumFrameLatency(1); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIDevice1::SetMaximumFrameLatency", result); + return result; + } + } + +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + // Set the proper orientation for the swap chain, and generate the + // 3D matrix transformation for rendering to the rotated swap chain. + // + // To note, the call for this, IDXGISwapChain1::SetRotation, is not necessary + // on Windows Phone, nor is it supported there. It's only needed in Windows 8/RT. + DXGI_MODE_ROTATION rotation = D3D11_GetRotationForOrientation(data->orientation); + result = data->swapChain->SetRotation(rotation); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::SetRotation" , result); + return result; + } +#endif + + // Create a render target view of the swap chain back buffer. + ComPtr backBuffer; + result = data->swapChain->GetBuffer( + 0, + __uuidof(ID3D11Texture2D), + &backBuffer + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::GetBuffer [back-buffer]", result); + return result; + } + + result = data->d3dDevice->CreateRenderTargetView( + backBuffer.Get(), + nullptr, + &data->mainRenderTargetView + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRenderTargetView", result); + return result; + } + + if (D3D11_UpdateViewport(renderer) != 0) { + // D3D11_UpdateViewport will set the SDL error if it fails. + return E_FAIL; + } + + return S_OK; } // This method is called when the window's size changes. -HRESULT -D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer) -{ - D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; - HRESULT result = S_OK; - ABI::Windows::UI::Core::ICoreWindow * coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer); - ABI::Windows::Foundation::Rect coreWindowBounds; - - result = coreWindow->get_Bounds(&coreWindowBounds); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ICoreWindow::get_Bounds [get window bounds]", result); - return result; - } - - if (coreWindowBounds.Width != data->windowSizeInDIPs.x || - coreWindowBounds.Height != data->windowSizeInDIPs.y || - data->orientation != DisplayProperties::CurrentOrientation) - { - ID3D11RenderTargetView* nullViews[] = {nullptr}; - data->d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); - data->mainRenderTargetView = nullptr; - data->d3dContext->Flush(); - result = D3D11_CreateWindowSizeDependentResources(renderer); - if (FAILED(result)) { - /* D3D11_CreateWindowSizeDependentResources will set the SDL error */ - return result; - } - } - - return S_OK; +HRESULT +D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + HRESULT result = S_OK; + ABI::Windows::UI::Core::ICoreWindow * coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer); + ABI::Windows::Foundation::Rect coreWindowBounds; + + result = coreWindow->get_Bounds(&coreWindowBounds); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ICoreWindow::get_Bounds [get window bounds]", result); + return result; + } + + if (coreWindowBounds.Width != data->windowSizeInDIPs.x || + coreWindowBounds.Height != data->windowSizeInDIPs.y || + data->orientation != DisplayProperties::CurrentOrientation) + { + ID3D11RenderTargetView* nullViews[] = {nullptr}; + data->d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr); + data->mainRenderTargetView = nullptr; + data->d3dContext->Flush(); + result = D3D11_CreateWindowSizeDependentResources(renderer); + if (FAILED(result)) { + /* D3D11_CreateWindowSizeDependentResources will set the SDL error */ + return result; + } + } + + return S_OK; } HRESULT @@ -1359,22 +1359,22 @@ D3D11_HandleDeviceLost(SDL_Renderer * renderer) D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; HRESULT result = S_OK; - // Reset these member variables to ensure that D3D11_UpdateForWindowSizeChange recreates all resources. - data->windowSizeInDIPs.x = 0; - data->windowSizeInDIPs.y = 0; - data->swapChain = nullptr; - - result = D3D11_CreateDeviceResources(renderer); - if (FAILED(result)) { - /* D3D11_CreateDeviceResources will set the SDL error */ - return result; - } - - result = D3D11_UpdateForWindowSizeChange(renderer); - if (FAILED(result)) { - /* D3D11_UpdateForWindowSizeChange will set the SDL error */ - return result; - } + // Reset these member variables to ensure that D3D11_UpdateForWindowSizeChange recreates all resources. + data->windowSizeInDIPs.x = 0; + data->windowSizeInDIPs.y = 0; + data->swapChain = nullptr; + + result = D3D11_CreateDeviceResources(renderer); + if (FAILED(result)) { + /* D3D11_CreateDeviceResources will set the SDL error */ + return result; + } + + result = D3D11_UpdateForWindowSizeChange(renderer); + if (FAILED(result)) { + /* D3D11_UpdateForWindowSizeChange will set the SDL error */ + return result; + } return S_OK; } @@ -1382,140 +1382,140 @@ D3D11_HandleDeviceLost(SDL_Renderer * renderer) static void D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) { - //D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; - - if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { - D3D11_UpdateForWindowSizeChange(renderer); + //D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + + if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { + D3D11_UpdateForWindowSizeChange(renderer); } } -static D3D11_FILTER -GetScaleQuality(void) -{ - const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY); - if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) { - return SDL_D3D11_NEAREST_PIXEL_FILTER; - } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ { - return SDL_D3D11_LINEAR_FILTER; - } +static D3D11_FILTER +GetScaleQuality(void) +{ + const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY); + if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) { + return SDL_D3D11_NEAREST_PIXEL_FILTER; + } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ { + return SDL_D3D11_LINEAR_FILTER; + } } -static int -D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) -{ - D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; - D3D11_TextureData *textureData; - HRESULT result; - DXGI_FORMAT textureFormat = SDLPixelFormatToDXGIFormat(texture->format); - if (textureFormat == SDL_PIXELFORMAT_UNKNOWN) { - return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", - __FUNCTION__, texture->format); - } - - textureData = new D3D11_TextureData; - if (!textureData) { - SDL_OutOfMemory(); - return -1; - } - textureData->pixelFormat = SDL_AllocFormat(texture->format); - textureData->lockedTexturePosition = XMINT2(0, 0); - textureData->scaleMode = GetScaleQuality(); - - texture->driverdata = textureData; - - D3D11_TEXTURE2D_DESC textureDesc = {0}; - textureDesc.Width = texture->w; - textureDesc.Height = texture->h; - textureDesc.MipLevels = 1; - textureDesc.ArraySize = 1; - textureDesc.Format = textureFormat; - textureDesc.SampleDesc.Count = 1; - textureDesc.SampleDesc.Quality = 0; - textureDesc.MiscFlags = 0; - - if (texture->access == SDL_TEXTUREACCESS_STREAMING) { - textureDesc.Usage = D3D11_USAGE_DYNAMIC; - textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - } else { - textureDesc.Usage = D3D11_USAGE_DEFAULT; - textureDesc.CPUAccessFlags = 0; - } - - if (texture->access == SDL_TEXTUREACCESS_TARGET) { - textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - } else { - textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - } - -#if 0 - // Fill the texture with a non-black color, for debugging purposes: - const int numPixels = textureDesc.Width * textureDesc.Height; - const int pixelSizeInBytes = textureData->pixelFormat->BytesPerPixel; - std::vector initialTexturePixels(numPixels * pixelSizeInBytes, 0x00); - for (int i = 0; i < (numPixels * pixelSizeInBytes); i += pixelSizeInBytes) { - initialTexturePixels[i+0] = 0xff; - initialTexturePixels[i+1] = 0xff; - initialTexturePixels[i+2] = 0x00; - initialTexturePixels[i+3] = 0xff; - } - D3D11_SUBRESOURCE_DATA initialTextureData = {0}; - initialTextureData.pSysMem = (void *)&(initialTexturePixels[0]); - initialTextureData.SysMemPitch = textureDesc.Width * pixelSizeInBytes; - initialTextureData.SysMemSlicePitch = numPixels * pixelSizeInBytes; -#endif - - result = rendererData->d3dDevice->CreateTexture2D( - &textureDesc, - NULL, // &initialTextureData, - &textureData->mainTexture - ); - if (FAILED(result)) { - D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateTexture2D", result); - return -1; - } - - if (texture->access & SDL_TEXTUREACCESS_TARGET) { - D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; - renderTargetViewDesc.Format = textureDesc.Format; - renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - renderTargetViewDesc.Texture2D.MipSlice = 0; - - result = rendererData->d3dDevice->CreateRenderTargetView( - textureData->mainTexture.Get(), - &renderTargetViewDesc, - &textureData->mainTextureRenderTargetView); - if (FAILED(result)) { - D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRenderTargetView", result); - return -1; - } - } - - D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; - resourceViewDesc.Format = textureDesc.Format; - resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - resourceViewDesc.Texture2D.MostDetailedMip = 0; - resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; - result = rendererData->d3dDevice->CreateShaderResourceView( - textureData->mainTexture.Get(), - &resourceViewDesc, - &textureData->mainTextureResourceView - ); - if (FAILED(result)) { - D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ "ID3D11Device1::CreateShaderResourceView", result); - return -1; - } - - return 0; +static int +D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; + D3D11_TextureData *textureData; + HRESULT result; + DXGI_FORMAT textureFormat = SDLPixelFormatToDXGIFormat(texture->format); + if (textureFormat == SDL_PIXELFORMAT_UNKNOWN) { + return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", + __FUNCTION__, texture->format); + } + + textureData = new D3D11_TextureData; + if (!textureData) { + SDL_OutOfMemory(); + return -1; + } + textureData->pixelFormat = SDL_AllocFormat(texture->format); + textureData->lockedTexturePosition = XMINT2(0, 0); + textureData->scaleMode = GetScaleQuality(); + + texture->driverdata = textureData; + + D3D11_TEXTURE2D_DESC textureDesc = {0}; + textureDesc.Width = texture->w; + textureDesc.Height = texture->h; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = textureFormat; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.MiscFlags = 0; + + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + textureDesc.Usage = D3D11_USAGE_DYNAMIC; + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + } else { + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.CPUAccessFlags = 0; + } + + if (texture->access == SDL_TEXTUREACCESS_TARGET) { + textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + } else { + textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + } + +#if 0 + // Fill the texture with a non-black color, for debugging purposes: + const int numPixels = textureDesc.Width * textureDesc.Height; + const int pixelSizeInBytes = textureData->pixelFormat->BytesPerPixel; + std::vector initialTexturePixels(numPixels * pixelSizeInBytes, 0x00); + for (int i = 0; i < (numPixels * pixelSizeInBytes); i += pixelSizeInBytes) { + initialTexturePixels[i+0] = 0xff; + initialTexturePixels[i+1] = 0xff; + initialTexturePixels[i+2] = 0x00; + initialTexturePixels[i+3] = 0xff; + } + D3D11_SUBRESOURCE_DATA initialTextureData = {0}; + initialTextureData.pSysMem = (void *)&(initialTexturePixels[0]); + initialTextureData.SysMemPitch = textureDesc.Width * pixelSizeInBytes; + initialTextureData.SysMemSlicePitch = numPixels * pixelSizeInBytes; +#endif + + result = rendererData->d3dDevice->CreateTexture2D( + &textureDesc, + NULL, // &initialTextureData, + &textureData->mainTexture + ); + if (FAILED(result)) { + D3D11_DestroyTexture(renderer, texture); + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateTexture2D", result); + return -1; + } + + if (texture->access & SDL_TEXTUREACCESS_TARGET) { + D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; + renderTargetViewDesc.Format = textureDesc.Format; + renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + renderTargetViewDesc.Texture2D.MipSlice = 0; + + result = rendererData->d3dDevice->CreateRenderTargetView( + textureData->mainTexture.Get(), + &renderTargetViewDesc, + &textureData->mainTextureRenderTargetView); + if (FAILED(result)) { + D3D11_DestroyTexture(renderer, texture); + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRenderTargetView", result); + return -1; + } + } + + D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; + resourceViewDesc.Format = textureDesc.Format; + resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + resourceViewDesc.Texture2D.MostDetailedMip = 0; + resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; + result = rendererData->d3dDevice->CreateShaderResourceView( + textureData->mainTexture.Get(), + &resourceViewDesc, + &textureData->mainTextureResourceView + ); + if (FAILED(result)) { + D3D11_DestroyTexture(renderer, texture); + WIN_SetErrorFromHRESULT(__FUNCTION__ "ID3D11Device1::CreateShaderResourceView", result); + return -1; + } + + return 0; } static void D3D11_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) { - D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; + D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; if (textureData) { if (textureData->pixelFormat) { @@ -1533,27 +1533,27 @@ D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, const void * srcPixels, int srcPitch) { - // Lock the texture, retrieving a buffer to write pixel data to: - void * destPixels = NULL; - int destPitch = 0; - if (D3D11_LockTexture(renderer, texture, rect, &destPixels, &destPitch) != 0) { - // An error is already set. Attach some info to it, then return to - // the caller. - std::string errorMessage = string(__FUNCTION__ ", Lock Texture Failed: ") + SDL_GetError(); - return SDL_SetError(errorMessage.c_str()); - } - - // Copy pixel data to the locked texture's memory: - for (int y = 0; y < rect->h; ++y) { - memcpy( - ((Uint8 *)destPixels) + (destPitch * y), - ((Uint8 *)srcPixels) + (srcPitch * y), - srcPitch - ); - } - - // Commit the texture's memory back to Direct3D: - D3D11_UnlockTexture(renderer, texture); + // Lock the texture, retrieving a buffer to write pixel data to: + void * destPixels = NULL; + int destPitch = 0; + if (D3D11_LockTexture(renderer, texture, rect, &destPixels, &destPitch) != 0) { + // An error is already set. Attach some info to it, then return to + // the caller. + std::string errorMessage = string(__FUNCTION__ ", Lock Texture Failed: ") + SDL_GetError(); + return SDL_SetError(errorMessage.c_str()); + } + + // Copy pixel data to the locked texture's memory: + for (int y = 0; y < rect->h; ++y) { + memcpy( + ((Uint8 *)destPixels) + (destPitch * y), + ((Uint8 *)srcPixels) + (srcPitch * y), + srcPitch + ); + } + + // Commit the texture's memory back to Direct3D: + D3D11_UnlockTexture(renderer, texture); // Return to the caller: return 0; @@ -1564,9 +1564,9 @@ D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, void **pixels, int *pitch) { D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; - D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; - HRESULT result = S_OK; - + D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; + HRESULT result = S_OK; + if (textureData->stagingTexture) { return SDL_SetError("texture is already locked"); } @@ -1596,18 +1596,18 @@ D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, } // Get a write-only pointer to data in the staging texture: - D3D11_MAPPED_SUBRESOURCE textureMemory = {0}; - result = rendererData->d3dContext->Map( - textureData->stagingTexture.Get(), - D3D11CalcSubresource(0, 0, 0), - D3D11_MAP_WRITE, - 0, - &textureMemory - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [map staging texture]", result); - textureData->stagingTexture = nullptr; - return -1; + D3D11_MAPPED_SUBRESOURCE textureMemory = {0}; + result = rendererData->d3dContext->Map( + textureData->stagingTexture.Get(), + D3D11CalcSubresource(0, 0, 0), + D3D11_MAP_WRITE, + 0, + &textureMemory + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [map staging texture]", result); + textureData->stagingTexture = nullptr; + return -1; } // Make note of where the staging texture will be written to (on a @@ -1649,24 +1649,24 @@ D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) } static int -D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) -{ - D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; - - if (texture == NULL) { - rendererData->currentOffscreenRenderTargetView = nullptr; - return 0; - } - - D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; - - if (!textureData->mainTextureRenderTargetView) { - return SDL_SetError("specified texture is not a render target"); - } - - rendererData->currentOffscreenRenderTargetView = textureData->mainTextureRenderTargetView; - - return 0; +D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; + + if (texture == NULL) { + rendererData->currentOffscreenRenderTargetView = nullptr; + return 0; + } + + D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; + + if (!textureData->mainTextureRenderTargetView) { + return SDL_SetError("specified texture is not a render target"); + } + + rendererData->currentOffscreenRenderTargetView = textureData->mainTextureRenderTargetView; + + return 0; } static int @@ -1686,34 +1686,34 @@ D3D11_UpdateViewport(SDL_Renderer * renderer) // default coordinate system) so rotations will be done in the opposite // direction of the DXGI_MODE_ROTATION enumeration. DirectX::XMMATRIX projection; - switch (D3D11_GetRotationForOrientation(data->orientation)) - { - case DXGI_MODE_ROTATION_IDENTITY: - projection = XMMatrixIdentity(); - break; - case DXGI_MODE_ROTATION_ROTATE270: - projection = XMMatrixRotationZ(XM_PIDIV2); - break; - case DXGI_MODE_ROTATION_ROTATE180: - projection = XMMatrixRotationZ(XM_PI); - break; - case DXGI_MODE_ROTATION_ROTATE90: - projection = XMMatrixRotationZ(-XM_PIDIV2); - break; - default: - return SDL_SetError("An unknown DisplayOrientation is being used"); - } - - // - // Update the view matrix - // - float viewportWidth = (float) renderer->viewport.w; - float viewportHeight = (float) renderer->viewport.h; - DirectX::XMMATRIX view = XMMatrixMultiply( - XMMatrixScaling(2.0f / viewportWidth, 2.0f / viewportHeight, 1.0f), - XMMatrixMultiply( - XMMatrixTranslation(-1, -1, 0), - XMMatrixRotationX(XM_PI) + switch (D3D11_GetRotationForOrientation(data->orientation)) + { + case DXGI_MODE_ROTATION_IDENTITY: + projection = XMMatrixIdentity(); + break; + case DXGI_MODE_ROTATION_ROTATE270: + projection = XMMatrixRotationZ(XM_PIDIV2); + break; + case DXGI_MODE_ROTATION_ROTATE180: + projection = XMMatrixRotationZ(XM_PI); + break; + case DXGI_MODE_ROTATION_ROTATE90: + projection = XMMatrixRotationZ(-XM_PIDIV2); + break; + default: + return SDL_SetError("An unknown DisplayOrientation is being used"); + } + + // + // Update the view matrix + // + float viewportWidth = (float) renderer->viewport.w; + float viewportHeight = (float) renderer->viewport.h; + DirectX::XMMATRIX view = XMMatrixMultiply( + XMMatrixScaling(2.0f / viewportWidth, 2.0f / viewportHeight, 1.0f), + XMMatrixMultiply( + XMMatrixTranslation(-1, -1, 0), + XMMatrixRotationX(XM_PI) )); // @@ -1737,39 +1737,39 @@ D3D11_UpdateViewport(SDL_Renderer * renderer) // a landscape mode, for all Windows 8/RT devices, or a portrait mode, // for Windows Phone devices. // - SDL_FRect orientationAlignedViewport; - const bool swapDimensions = D3D11_IsDisplayRotated90Degrees(data->orientation); - if (swapDimensions) { - orientationAlignedViewport.x = (float) renderer->viewport.y; - orientationAlignedViewport.y = (float) renderer->viewport.x; - orientationAlignedViewport.w = (float) renderer->viewport.h; - orientationAlignedViewport.h = (float) renderer->viewport.w; - } else { - orientationAlignedViewport.x = (float) renderer->viewport.x; - orientationAlignedViewport.y = (float) renderer->viewport.y; - orientationAlignedViewport.w = (float) renderer->viewport.w; - orientationAlignedViewport.h = (float) renderer->viewport.h; - } - // TODO, WinRT: get custom viewports working with non-Landscape modes (Portrait, PortraitFlipped, and LandscapeFlipped) - - D3D11_VIEWPORT viewport; - memset(&viewport, 0, sizeof(viewport)); - viewport.TopLeftX = orientationAlignedViewport.x; - viewport.TopLeftY = orientationAlignedViewport.y; - viewport.Width = orientationAlignedViewport.w; - viewport.Height = orientationAlignedViewport.h; - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; + SDL_FRect orientationAlignedViewport; + const bool swapDimensions = D3D11_IsDisplayRotated90Degrees(data->orientation); + if (swapDimensions) { + orientationAlignedViewport.x = (float) renderer->viewport.y; + orientationAlignedViewport.y = (float) renderer->viewport.x; + orientationAlignedViewport.w = (float) renderer->viewport.h; + orientationAlignedViewport.h = (float) renderer->viewport.w; + } else { + orientationAlignedViewport.x = (float) renderer->viewport.x; + orientationAlignedViewport.y = (float) renderer->viewport.y; + orientationAlignedViewport.w = (float) renderer->viewport.w; + orientationAlignedViewport.h = (float) renderer->viewport.h; + } + // TODO, WinRT: get custom viewports working with non-Landscape modes (Portrait, PortraitFlipped, and LandscapeFlipped) + + D3D11_VIEWPORT viewport; + memset(&viewport, 0, sizeof(viewport)); + viewport.TopLeftX = orientationAlignedViewport.x; + viewport.TopLeftY = orientationAlignedViewport.y; + viewport.Width = orientationAlignedViewport.w; + viewport.Height = orientationAlignedViewport.h; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; data->d3dContext->RSSetViewports(1, &viewport); #if 0 - SDL_Log("%s, oav={%.0f,%.0f,%.0f,%.0f}, rend={%.0f,%.0f}\n", - __FUNCTION__, - orientationAlignedViewport.x, - orientationAlignedViewport.y, - orientationAlignedViewport.w, - orientationAlignedViewport.h, - data->renderTargetSize.x, + SDL_Log("%s, oav={%.0f,%.0f,%.0f,%.0f}, rend={%.0f,%.0f}\n", + __FUNCTION__, + orientationAlignedViewport.x, + orientationAlignedViewport.y, + orientationAlignedViewport.w, + orientationAlignedViewport.h, + data->renderTargetSize.x, data->renderTargetSize.y); #endif @@ -1796,32 +1796,32 @@ D3D11_UpdateClipRect(SDL_Renderer * renderer) return 0; } -static ComPtr & -D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer) -{ - D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; - if (data->currentOffscreenRenderTargetView) { - return data->currentOffscreenRenderTargetView; - } else { - return data->mainRenderTargetView; - } +static ComPtr & +D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + if (data->currentOffscreenRenderTargetView) { + return data->currentOffscreenRenderTargetView; + } else { + return data->mainRenderTargetView; + } } -static int -D3D11_RenderClear(SDL_Renderer * renderer) -{ - D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; - const float colorRGBA[] = { - (renderer->r / 255.0f), - (renderer->g / 255.0f), - (renderer->b / 255.0f), - (renderer->a / 255.0f) - }; - data->d3dContext->ClearRenderTargetView( - D3D11_GetCurrentRenderTargetView(renderer).Get(), - colorRGBA - ); - return 0; +static int +D3D11_RenderClear(SDL_Renderer * renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + const float colorRGBA[] = { + (renderer->r / 255.0f), + (renderer->g / 255.0f), + (renderer->b / 255.0f), + (renderer->a / 255.0f) + }; + data->d3dContext->ClearRenderTargetView( + D3D11_GetCurrentRenderTargetView(renderer).Get(), + colorRGBA + ); + return 0; } static int @@ -1839,45 +1839,45 @@ D3D11_UpdateVertexBuffer(SDL_Renderer *renderer, } if (vertexBufferDesc.ByteWidth >= dataSizeInBytes) { - D3D11_MAPPED_SUBRESOURCE mappedResource; - ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE)); - result = rendererData->d3dContext->Map(rendererData->vertexBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [vertex buffer]", result); - return -1; - } - memcpy(mappedResource.pData, vertexData, dataSizeInBytes); - rendererData->d3dContext->Unmap(rendererData->vertexBuffer.Get(), 0); - } else { - vertexBufferDesc.ByteWidth = dataSizeInBytes; - vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; - vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - - D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; - vertexBufferData.pSysMem = vertexData; - vertexBufferData.SysMemPitch = 0; - vertexBufferData.SysMemSlicePitch = 0; - - result = rendererData->d3dDevice->CreateBuffer( - &vertexBufferDesc, - &vertexBufferData, - &rendererData->vertexBuffer - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBuffer [vertex buffer]", result); - return -1; - } - } - - UINT stride = sizeof(VertexPositionColor); - UINT offset = 0; - rendererData->d3dContext->IASetVertexBuffers( - 0, - 1, - rendererData->vertexBuffer.GetAddressOf(), - &stride, - &offset + D3D11_MAPPED_SUBRESOURCE mappedResource; + ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE)); + result = rendererData->d3dContext->Map(rendererData->vertexBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [vertex buffer]", result); + return -1; + } + memcpy(mappedResource.pData, vertexData, dataSizeInBytes); + rendererData->d3dContext->Unmap(rendererData->vertexBuffer.Get(), 0); + } else { + vertexBufferDesc.ByteWidth = dataSizeInBytes; + vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + D3D11_SUBRESOURCE_DATA vertexBufferData = {0}; + vertexBufferData.pSysMem = vertexData; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + + result = rendererData->d3dDevice->CreateBuffer( + &vertexBufferDesc, + &vertexBufferData, + &rendererData->vertexBuffer + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBuffer [vertex buffer]", result); + return -1; + } + } + + UINT stride = sizeof(VertexPositionColor); + UINT offset = 0; + rendererData->d3dContext->IASetVertexBuffers( + 0, + 1, + rendererData->vertexBuffer.GetAddressOf(), + &stride, + &offset ); return 0; @@ -1888,32 +1888,32 @@ D3D11_RenderStartDrawOp(SDL_Renderer * renderer) { D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; - rendererData->d3dContext->OMSetRenderTargets( - 1, - D3D11_GetCurrentRenderTargetView(renderer).GetAddressOf(), - nullptr - ); -} - -static void -D3D11_RenderSetBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) -{ - D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; - switch (blendMode) { - case SDL_BLENDMODE_BLEND: - rendererData->d3dContext->OMSetBlendState(rendererData->blendModeBlend.Get(), 0, 0xFFFFFFFF); + rendererData->d3dContext->OMSetRenderTargets( + 1, + D3D11_GetCurrentRenderTargetView(renderer).GetAddressOf(), + nullptr + ); +} + +static void +D3D11_RenderSetBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + rendererData->d3dContext->OMSetBlendState(rendererData->blendModeBlend.Get(), 0, 0xFFFFFFFF); break; - case SDL_BLENDMODE_ADD: - rendererData->d3dContext->OMSetBlendState(rendererData->blendModeAdd.Get(), 0, 0xFFFFFFFF); + case SDL_BLENDMODE_ADD: + rendererData->d3dContext->OMSetBlendState(rendererData->blendModeAdd.Get(), 0, 0xFFFFFFFF); break; - case SDL_BLENDMODE_MOD: - rendererData->d3dContext->OMSetBlendState(rendererData->blendModeMod.Get(), 0, 0xFFFFFFFF); + case SDL_BLENDMODE_MOD: + rendererData->d3dContext->OMSetBlendState(rendererData->blendModeMod.Get(), 0, 0xFFFFFFFF); break; case SDL_BLENDMODE_NONE: - rendererData->d3dContext->OMSetBlendState(NULL, 0, 0xFFFFFFFF); - break; - } -} + rendererData->d3dContext->OMSetBlendState(NULL, 0, 0xFFFFFFFF); + break; + } +} static void D3D11_SetPixelShader(SDL_Renderer * renderer, @@ -1921,10 +1921,10 @@ D3D11_SetPixelShader(SDL_Renderer * renderer, ID3D11ShaderResourceView * shaderResource, ID3D11SamplerState * sampler) { - D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; - rendererData->d3dContext->PSSetShader(shader, nullptr, 0); - rendererData->d3dContext->PSSetShaderResources(0, 1, &shaderResource); - rendererData->d3dContext->PSSetSamplers(0, 1, &sampler); + D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; + rendererData->d3dContext->PSSetShader(shader, nullptr, 0); + rendererData->d3dContext->PSSetShaderResources(0, 1, &shaderResource); + rendererData->d3dContext->PSSetSamplers(0, 1, &sampler); } static void @@ -1933,25 +1933,25 @@ D3D11_RenderFinishDrawOp(SDL_Renderer * renderer, UINT vertexCount) { D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; - - rendererData->d3dContext->UpdateSubresource( - rendererData->vertexShaderConstants.Get(), - 0, - NULL, - &rendererData->vertexShaderConstantsData, - 0, - 0 - ); - - rendererData->d3dContext->IASetPrimitiveTopology(primitiveTopology); - rendererData->d3dContext->IASetInputLayout(rendererData->inputLayout.Get()); - rendererData->d3dContext->VSSetShader(rendererData->vertexShader.Get(), nullptr, 0); - rendererData->d3dContext->VSSetConstantBuffers(0, 1, rendererData->vertexShaderConstants.GetAddressOf()); - if (SDL_RectEmpty(&(renderer->clip_rect))) { - rendererData->d3dContext->RSSetState(rendererData->mainRasterizer.Get()); - } else { - rendererData->d3dContext->RSSetState(rendererData->clippedRasterizer.Get()); - } + + rendererData->d3dContext->UpdateSubresource( + rendererData->vertexShaderConstants.Get(), + 0, + NULL, + &rendererData->vertexShaderConstantsData, + 0, + 0 + ); + + rendererData->d3dContext->IASetPrimitiveTopology(primitiveTopology); + rendererData->d3dContext->IASetInputLayout(rendererData->inputLayout.Get()); + rendererData->d3dContext->VSSetShader(rendererData->vertexShader.Get(), nullptr, 0); + rendererData->d3dContext->VSSetConstantBuffers(0, 1, rendererData->vertexShaderConstants.GetAddressOf()); + if (SDL_RectEmpty(&(renderer->clip_rect))) { + rendererData->d3dContext->RSSetState(rendererData->mainRasterizer.Get()); + } else { + rendererData->d3dContext->RSSetState(rendererData->clippedRasterizer.Get()); + } rendererData->d3dContext->Draw(vertexCount, 0); } @@ -1968,25 +1968,25 @@ D3D11_RenderDrawPoints(SDL_Renderer * renderer, a = (float)(renderer->a / 255.0f); VertexPositionColor * vertices = SDL_stack_alloc(VertexPositionColor, count); - for (int i = 0; i < min(count, 128); ++i) { - const VertexPositionColor v = {XMFLOAT3(points[i].x, points[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}; - vertices[i] = v; - } - - D3D11_RenderStartDrawOp(renderer); - D3D11_RenderSetBlendMode(renderer, renderer->blendMode); - if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) { - SDL_stack_free(vertices); - return -1; - } - - D3D11_SetPixelShader( - renderer, - rendererData->colorPixelShader.Get(), - nullptr, - nullptr); - - D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, count); + for (int i = 0; i < min(count, 128); ++i) { + const VertexPositionColor v = {XMFLOAT3(points[i].x, points[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}; + vertices[i] = v; + } + + D3D11_RenderStartDrawOp(renderer); + D3D11_RenderSetBlendMode(renderer, renderer->blendMode); + if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) { + SDL_stack_free(vertices); + return -1; + } + + D3D11_SetPixelShader( + renderer, + rendererData->colorPixelShader.Get(), + nullptr, + nullptr); + + D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, count); SDL_stack_free(vertices); return 0; } @@ -2004,25 +2004,25 @@ D3D11_RenderDrawLines(SDL_Renderer * renderer, a = (float)(renderer->a / 255.0f); VertexPositionColor * vertices = SDL_stack_alloc(VertexPositionColor, count); - for (int i = 0; i < count; ++i) { - const VertexPositionColor v = {XMFLOAT3(points[i].x, points[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}; - vertices[i] = v; - } - - D3D11_RenderStartDrawOp(renderer); - D3D11_RenderSetBlendMode(renderer, renderer->blendMode); - if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) { - SDL_stack_free(vertices); - return -1; - } - - D3D11_SetPixelShader( - renderer, - rendererData->colorPixelShader.Get(), - nullptr, - nullptr); - - D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, count); + for (int i = 0; i < count; ++i) { + const VertexPositionColor v = {XMFLOAT3(points[i].x, points[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}; + vertices[i] = v; + } + + D3D11_RenderStartDrawOp(renderer); + D3D11_RenderSetBlendMode(renderer, renderer->blendMode); + if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) { + SDL_stack_free(vertices); + return -1; + } + + D3D11_SetPixelShader( + renderer, + rendererData->colorPixelShader.Get(), + nullptr, + nullptr); + + D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, count); SDL_stack_free(vertices); return 0; } @@ -2052,40 +2052,40 @@ D3D11_RenderFillRects(SDL_Renderer * renderer, #define rects _rects #endif - for (int i = 0; i < count; ++i) { - D3D11_RenderStartDrawOp(renderer); - D3D11_RenderSetBlendMode(renderer, renderer->blendMode); - -#if 0 - // Set colors for the test pattern: - a = 1.0f; - switch (i) { - case 0: r = 1.0f; g = 1.0f; b = 0.0f; break; - case 1: r = 1.0f; g = 0.0f; b = 0.0f; break; - case 2: r = 0.0f; g = 1.0f; b = 0.0f; break; - case 3: r = 0.0f; g = 0.0f; b = 1.0f; break; - case 4: r = 1.0f; g = 1.0f; b = 1.0f; break; - } -#endif - - VertexPositionColor vertices[] = { - {XMFLOAT3(rects[i].x, rects[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(rects[i].x, rects[i].y + rects[i].h, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(rects[i].x + rects[i].w, rects[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(rects[i].x + rects[i].w, rects[i].y + rects[i].h, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}, - }; - if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { - return -1; - } - - D3D11_SetPixelShader( - renderer, - rendererData->colorPixelShader.Get(), - nullptr, - nullptr); - - D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor)); - } + for (int i = 0; i < count; ++i) { + D3D11_RenderStartDrawOp(renderer); + D3D11_RenderSetBlendMode(renderer, renderer->blendMode); + +#if 0 + // Set colors for the test pattern: + a = 1.0f; + switch (i) { + case 0: r = 1.0f; g = 1.0f; b = 0.0f; break; + case 1: r = 1.0f; g = 0.0f; b = 0.0f; break; + case 2: r = 0.0f; g = 1.0f; b = 0.0f; break; + case 3: r = 0.0f; g = 0.0f; b = 1.0f; break; + case 4: r = 1.0f; g = 1.0f; b = 1.0f; break; + } +#endif + + VertexPositionColor vertices[] = { + {XMFLOAT3(rects[i].x, rects[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(rects[i].x, rects[i].y + rects[i].h, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(rects[i].x + rects[i].w, rects[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(rects[i].x + rects[i].w, rects[i].y + rects[i].h, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}, + }; + if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { + return -1; + } + + D3D11_SetPixelShader( + renderer, + rendererData->colorPixelShader.Get(), + nullptr, + nullptr); + + D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor)); + } return 0; } @@ -2116,9 +2116,9 @@ D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, D3D11_RenderStartDrawOp(renderer); D3D11_RenderSetBlendMode(renderer, texture->blendMode); - float minu = (float) srcrect->x / texture->w; - float maxu = (float) (srcrect->x + srcrect->w) / texture->w; - float minv = (float) srcrect->y / texture->h; + float minu = (float) srcrect->x / texture->w; + float maxu = (float) (srcrect->x + srcrect->w) / texture->w; + float minv = (float) srcrect->y / texture->h; float maxv = (float) (srcrect->y + srcrect->h) / texture->h; float r = 1.0f; @@ -2133,25 +2133,25 @@ D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) { a = (float)(texture->a / 255.0f); } - - VertexPositionColor vertices[] = { - {XMFLOAT3(dstrect->x, dstrect->y, 0.0f), XMFLOAT2(minu, minv), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(dstrect->x, dstrect->y + dstrect->h, 0.0f), XMFLOAT2(minu, maxv), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(dstrect->x + dstrect->w, dstrect->y, 0.0f), XMFLOAT2(maxu, minv), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(dstrect->x + dstrect->w, dstrect->y + dstrect->h, 0.0f), XMFLOAT2(maxu, maxv), XMFLOAT4(r, g, b, a)}, - }; - if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { - return -1; - } - - ID3D11SamplerState *textureSampler = D3D11_RenderGetSampler(renderer, texture); - D3D11_SetPixelShader( - renderer, - rendererData->texturePixelShader.Get(), - textureData->mainTextureResourceView.Get(), - textureSampler); - - D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor)); + + VertexPositionColor vertices[] = { + {XMFLOAT3(dstrect->x, dstrect->y, 0.0f), XMFLOAT2(minu, minv), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(dstrect->x, dstrect->y + dstrect->h, 0.0f), XMFLOAT2(minu, maxv), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(dstrect->x + dstrect->w, dstrect->y, 0.0f), XMFLOAT2(maxu, minv), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(dstrect->x + dstrect->w, dstrect->y + dstrect->h, 0.0f), XMFLOAT2(maxu, maxv), XMFLOAT4(r, g, b, a)}, + }; + if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { + return -1; + } + + ID3D11SamplerState *textureSampler = D3D11_RenderGetSampler(renderer, texture); + D3D11_SetPixelShader( + renderer, + rendererData->texturePixelShader.Get(), + textureData->mainTextureResourceView.Get(), + textureSampler); + + D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor)); return 0; } @@ -2167,9 +2167,9 @@ D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, D3D11_RenderStartDrawOp(renderer); D3D11_RenderSetBlendMode(renderer, texture->blendMode); - float minu = (float) srcrect->x / texture->w; - float maxu = (float) (srcrect->x + srcrect->w) / texture->w; - float minv = (float) srcrect->y / texture->h; + float minu = (float) srcrect->x / texture->w; + float maxu = (float) (srcrect->x + srcrect->w) / texture->w; + float minv = (float) srcrect->y / texture->h; float maxv = (float) (srcrect->y + srcrect->h) / texture->h; float r = 1.0f; @@ -2204,31 +2204,31 @@ D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, XMMatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0) )); - const float minx = -center->x; - const float maxx = dstrect->w - center->x; - const float miny = -center->y; - const float maxy = dstrect->h - center->y; - - VertexPositionColor vertices[] = { - {XMFLOAT3(minx, miny, 0.0f), XMFLOAT2(minu, minv), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(minx, maxy, 0.0f), XMFLOAT2(minu, maxv), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(maxx, miny, 0.0f), XMFLOAT2(maxu, minv), XMFLOAT4(r, g, b, a)}, - {XMFLOAT3(maxx, maxy, 0.0f), XMFLOAT2(maxu, maxv), XMFLOAT4(r, g, b, a)}, - }; - if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { - return -1; - } - - ID3D11SamplerState *textureSampler = D3D11_RenderGetSampler(renderer, texture); - D3D11_SetPixelShader( - renderer, - rendererData->texturePixelShader.Get(), - textureData->mainTextureResourceView.Get(), - textureSampler); - - D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor)); - - rendererData->vertexShaderConstantsData.model = oldModelMatrix; + const float minx = -center->x; + const float maxx = dstrect->w - center->x; + const float miny = -center->y; + const float maxy = dstrect->h - center->y; + + VertexPositionColor vertices[] = { + {XMFLOAT3(minx, miny, 0.0f), XMFLOAT2(minu, minv), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(minx, maxy, 0.0f), XMFLOAT2(minu, maxv), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(maxx, miny, 0.0f), XMFLOAT2(maxu, minv), XMFLOAT4(r, g, b, a)}, + {XMFLOAT3(maxx, maxy, 0.0f), XMFLOAT2(maxu, maxv), XMFLOAT4(r, g, b, a)}, + }; + if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { + return -1; + } + + ID3D11SamplerState *textureSampler = D3D11_RenderGetSampler(renderer, texture); + D3D11_SetPixelShader( + renderer, + rendererData->texturePixelShader.Get(), + textureData->mainTextureResourceView.Get(), + textureSampler); + + D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor)); + + rendererData->vertexShaderConstantsData.model = oldModelMatrix; return 0; } @@ -2241,15 +2241,15 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, HRESULT result = S_OK; // Retrieve a pointer to the back buffer: - ComPtr backBuffer; - result = data->swapChain->GetBuffer( - 0, - __uuidof(ID3D11Texture2D), - &backBuffer - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::GetBuffer [get back buffer]", result); - return -1; + ComPtr backBuffer; + result = data->swapChain->GetBuffer( + 0, + __uuidof(ID3D11Texture2D), + &backBuffer + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::GetBuffer [get back buffer]", result); + return -1; } // Create a staging texture to copy the screen's data to: @@ -2308,29 +2308,29 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, // Copy the data into the desired buffer, converting pixels to the // desired format at the same time: - if (SDL_ConvertPixels( - rect->w, rect->h, - DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format), - textureMemory.pData, - textureMemory.RowPitch, - format, - pixels, - pitch) != 0) - { - // When SDL_ConvertPixels fails, it'll have already set the format. - // Get the error message, and attach some extra data to it. - std::string errorMessage = string(__FUNCTION__ ", Convert Pixels failed: ") + SDL_GetError(); - return SDL_SetError(errorMessage.c_str()); - } - - // Unmap the texture: - data->d3dContext->Unmap( - stagingTexture.Get(), - D3D11CalcSubresource(0, 0, 0)); - - // All done. The staging texture will be cleaned up in it's container - // ComPtr<>'s destructor. - return 0; + if (SDL_ConvertPixels( + rect->w, rect->h, + DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format), + textureMemory.pData, + textureMemory.RowPitch, + format, + pixels, + pitch) != 0) + { + // When SDL_ConvertPixels fails, it'll have already set the format. + // Get the error message, and attach some extra data to it. + std::string errorMessage = string(__FUNCTION__ ", Convert Pixels failed: ") + SDL_GetError(); + return SDL_SetError(errorMessage.c_str()); + } + + // Unmap the texture: + data->d3dContext->Unmap( + stagingTexture.Get(), + D3D11CalcSubresource(0, 0, 0)); + + // All done. The staging texture will be cleaned up in it's container + // ComPtr<>'s destructor. + return 0; } static void @@ -2338,46 +2338,46 @@ D3D11_RenderPresent(SDL_Renderer * renderer) { D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - // The first argument instructs DXGI to block until VSync, putting the application - // to sleep until the next VSync. This ensures we don't waste any cycles rendering - // frames that will never be displayed to the screen. - HRESULT hr = data->swapChain->Present(1, 0); -#else - // The application may optionally specify "dirty" or "scroll" - // rects to improve efficiency in certain scenarios. - // This option is not available on Windows Phone 8, to note. - DXGI_PRESENT_PARAMETERS parameters = {0}; - parameters.DirtyRectsCount = 0; - parameters.pDirtyRects = nullptr; - parameters.pScrollRect = nullptr; - parameters.pScrollOffset = nullptr; - - // The first argument instructs DXGI to block until VSync, putting the application - // to sleep until the next VSync. This ensures we don't waste any cycles rendering - // frames that will never be displayed to the screen. - HRESULT hr = data->swapChain->Present1(1, 0, ¶meters); -#endif - - // Discard the contents of the render target. - // This is a valid operation only when the existing contents will be entirely - // overwritten. If dirty or scroll rects are used, this call should be removed. - data->d3dContext->DiscardView(data->mainRenderTargetView.Get()); - - // If the device was removed either by a disconnect or a driver upgrade, we - // must recreate all device resources. - // - // TODO, WinRT: consider throwing an exception if D3D11_RenderPresent fails, especially if there is a way to salvedge debug info from users' machines - if (hr == DXGI_ERROR_DEVICE_REMOVED) - { - hr = D3D11_HandleDeviceLost(renderer); - if (FAILED(hr)) { - /* D3D11_HandleDeviceLost will set the SDL error */ - } - } - else - { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::DiscardView", hr); +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // The first argument instructs DXGI to block until VSync, putting the application + // to sleep until the next VSync. This ensures we don't waste any cycles rendering + // frames that will never be displayed to the screen. + HRESULT hr = data->swapChain->Present(1, 0); +#else + // The application may optionally specify "dirty" or "scroll" + // rects to improve efficiency in certain scenarios. + // This option is not available on Windows Phone 8, to note. + DXGI_PRESENT_PARAMETERS parameters = {0}; + parameters.DirtyRectsCount = 0; + parameters.pDirtyRects = nullptr; + parameters.pScrollRect = nullptr; + parameters.pScrollOffset = nullptr; + + // The first argument instructs DXGI to block until VSync, putting the application + // to sleep until the next VSync. This ensures we don't waste any cycles rendering + // frames that will never be displayed to the screen. + HRESULT hr = data->swapChain->Present1(1, 0, ¶meters); +#endif + + // Discard the contents of the render target. + // This is a valid operation only when the existing contents will be entirely + // overwritten. If dirty or scroll rects are used, this call should be removed. + data->d3dContext->DiscardView(data->mainRenderTargetView.Get()); + + // If the device was removed either by a disconnect or a driver upgrade, we + // must recreate all device resources. + // + // TODO, WinRT: consider throwing an exception if D3D11_RenderPresent fails, especially if there is a way to salvedge debug info from users' machines + if (hr == DXGI_ERROR_DEVICE_REMOVED) + { + hr = D3D11_HandleDeviceLost(renderer); + if (FAILED(hr)) { + /* D3D11_HandleDeviceLost will set the SDL error */ + } + } + else + { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::DiscardView", hr); } } diff --git a/src/thread/stdcpp/SDL_systhread.cpp b/src/thread/stdcpp/SDL_systhread.cpp index 6e043b4171534..24df914c774fc 100644 --- a/src/thread/stdcpp/SDL_systhread.cpp +++ b/src/thread/stdcpp/SDL_systhread.cpp @@ -151,17 +151,17 @@ SDL_SYS_DetachThread(SDL_Thread * thread) } extern "C" -SDL_TLSData * -SDL_SYS_GetTLSData() -{ - return SDL_Generic_GetTLSData(); -} - -extern "C" -int -SDL_SYS_SetTLSData(SDL_TLSData *data) -{ - return SDL_Generic_SetTLSData(data); +SDL_TLSData * +SDL_SYS_GetTLSData() +{ + return SDL_Generic_GetTLSData(); +} + +extern "C" +int +SDL_SYS_SetTLSData(SDL_TLSData *data) +{ + return SDL_Generic_SetTLSData(data); } /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/timer/windows/SDL_systimer.c b/src/timer/windows/SDL_systimer.c index a3055218cc112..4680d4aa726ba 100644 --- a/src/timer/windows/SDL_systimer.c +++ b/src/timer/windows/SDL_systimer.c @@ -170,17 +170,17 @@ SDL_GetPerformanceFrequency(void) return frequency.QuadPart; } -#ifdef __WINRT__ -static void -Sleep(DWORD timeout) -{ - static HANDLE mutex = 0; - if ( ! mutex ) - { - mutex = CreateEventEx(0, 0, 0, EVENT_ALL_ACCESS); - } - WaitForSingleObjectEx(mutex, timeout, FALSE); -} +#ifdef __WINRT__ +static void +Sleep(DWORD timeout) +{ + static HANDLE mutex = 0; + if ( ! mutex ) + { + mutex = CreateEventEx(0, 0, 0, EVENT_ALL_ACCESS); + } + WaitForSingleObjectEx(mutex, timeout, FALSE); +} #endif void diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 397942d550eec..a72fe11681bc2 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -1,401 +1,401 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_config.h" - -#ifndef _SDL_sysvideo_h -#define _SDL_sysvideo_h - -#include "SDL_messagebox.h" -#include "SDL_shape.h" -#include "SDL_thread.h" - -/* The SDL video driver */ - -typedef struct SDL_WindowShaper SDL_WindowShaper; -typedef struct SDL_ShapeDriver SDL_ShapeDriver; -typedef struct SDL_VideoDisplay SDL_VideoDisplay; -typedef struct SDL_VideoDevice SDL_VideoDevice; - -/* Define the SDL window-shaper structure */ -struct SDL_WindowShaper -{ - /* The window associated with the shaper */ - SDL_Window *window; - - /* The user's specified coordinates for the window, for once we give it a shape. */ - Uint32 userx,usery; - - /* The parameters for shape calculation. */ - SDL_WindowShapeMode mode; - - /* Has this window been assigned a shape? */ - SDL_bool hasshape; - - void *driverdata; -}; - -/* Define the SDL shape driver structure */ -struct SDL_ShapeDriver -{ - SDL_WindowShaper *(*CreateShaper)(SDL_Window * window); - int (*SetWindowShape)(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode); - int (*ResizeWindowShape)(SDL_Window *window); -}; - -typedef struct SDL_WindowUserData -{ - char *name; - void *data; - struct SDL_WindowUserData *next; -} SDL_WindowUserData; - -/* Define the SDL window structure, corresponding to toplevel windows */ -struct SDL_Window -{ - const void *magic; - Uint32 id; - char *title; - SDL_Surface *icon; - int x, y; - int w, h; - int min_w, min_h; - int max_w, max_h; - Uint32 flags; - - /* Stored position and size for windowed mode */ - SDL_Rect windowed; - - SDL_DisplayMode fullscreen_mode; - - float brightness; - Uint16 *gamma; - Uint16 *saved_gamma; /* (just offset into gamma) */ - - SDL_Surface *surface; - SDL_bool surface_valid; - - SDL_WindowShaper *shaper; - - SDL_WindowUserData *data; - - void *driverdata; - - SDL_Window *prev; - SDL_Window *next; -}; -#define FULLSCREEN_VISIBLE(W) \ - (((W)->flags & SDL_WINDOW_FULLSCREEN) && \ - ((W)->flags & SDL_WINDOW_SHOWN) && \ - !((W)->flags & SDL_WINDOW_MINIMIZED)) - -/* - * Define the SDL display structure This corresponds to physical monitors - * attached to the system. - */ -struct SDL_VideoDisplay -{ - char *name; - int max_display_modes; - int num_display_modes; - SDL_DisplayMode *display_modes; - SDL_DisplayMode desktop_mode; - SDL_DisplayMode current_mode; - - SDL_Window *fullscreen_window; - - SDL_VideoDevice *device; - - void *driverdata; -}; - -/* Forward declaration */ -struct SDL_SysWMinfo; - -/* Define the SDL video driver structure */ -#define _THIS SDL_VideoDevice *_this - -struct SDL_VideoDevice -{ - /* * * */ - /* The name of this video driver */ - const char *name; - - /* * * */ - /* Initialization/Query functions */ - - /* - * Initialize the native video subsystem, filling in the list of - * displays for this driver, returning 0 or -1 if there's an error. - */ - int (*VideoInit) (_THIS); - - /* - * Reverse the effects VideoInit() -- called if VideoInit() fails or - * if the application is shutting down the video subsystem. - */ - void (*VideoQuit) (_THIS); - - /* * * */ - /* - * Display functions - */ - - /* - * Get the bounds of a display - */ - int (*GetDisplayBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); - - /* - * Get a list of the available display modes for a display. - */ - void (*GetDisplayModes) (_THIS, SDL_VideoDisplay * display); - - /* - * Setting the display mode is independent of creating windows, so - * when the display mode is changed, all existing windows should have - * their data updated accordingly, including the display surfaces - * associated with them. - */ - int (*SetDisplayMode) (_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); - - /* * * */ - /* - * Window functions - */ - int (*CreateWindow) (_THIS, SDL_Window * window); - int (*CreateWindowFrom) (_THIS, SDL_Window * window, const void *data); - void (*SetWindowTitle) (_THIS, SDL_Window * window); - void (*SetWindowIcon) (_THIS, SDL_Window * window, SDL_Surface * icon); - void (*SetWindowPosition) (_THIS, SDL_Window * window); - void (*SetWindowSize) (_THIS, SDL_Window * window); - void (*SetWindowMinimumSize) (_THIS, SDL_Window * window); - void (*SetWindowMaximumSize) (_THIS, SDL_Window * window); - void (*ShowWindow) (_THIS, SDL_Window * window); - void (*HideWindow) (_THIS, SDL_Window * window); - void (*RaiseWindow) (_THIS, SDL_Window * window); - void (*MaximizeWindow) (_THIS, SDL_Window * window); - void (*MinimizeWindow) (_THIS, SDL_Window * window); - void (*RestoreWindow) (_THIS, SDL_Window * window); - void (*SetWindowBordered) (_THIS, SDL_Window * window, SDL_bool bordered); - void (*SetWindowFullscreen) (_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); - int (*SetWindowGammaRamp) (_THIS, SDL_Window * window, const Uint16 * ramp); - int (*GetWindowGammaRamp) (_THIS, SDL_Window * window, Uint16 * ramp); - void (*SetWindowGrab) (_THIS, SDL_Window * window, SDL_bool grabbed); - void (*DestroyWindow) (_THIS, SDL_Window * window); - int (*CreateWindowFramebuffer) (_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch); - int (*UpdateWindowFramebuffer) (_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects); - void (*DestroyWindowFramebuffer) (_THIS, SDL_Window * window); - void (*OnWindowEnter) (_THIS, SDL_Window * window); - - /* * * */ - /* - * Shaped-window functions - */ - SDL_ShapeDriver shape_driver; - - /* Get some platform dependent window information */ - SDL_bool(*GetWindowWMInfo) (_THIS, SDL_Window * window, - struct SDL_SysWMinfo * info); - - /* * * */ - /* - * OpenGL support - */ - int (*GL_LoadLibrary) (_THIS, const char *path); - void *(*GL_GetProcAddress) (_THIS, const char *proc); - void (*GL_UnloadLibrary) (_THIS); - SDL_GLContext(*GL_CreateContext) (_THIS, SDL_Window * window); - int (*GL_MakeCurrent) (_THIS, SDL_Window * window, SDL_GLContext context); - void (*GL_GetDrawableSize) (_THIS, SDL_Window * window, int *w, int *h); - int (*GL_SetSwapInterval) (_THIS, int interval); - int (*GL_GetSwapInterval) (_THIS); - void (*GL_SwapWindow) (_THIS, SDL_Window * window); - void (*GL_DeleteContext) (_THIS, SDL_GLContext context); - - /* * * */ - /* - * Event manager functions - */ - void (*PumpEvents) (_THIS); - - /* Suspend the screensaver */ - void (*SuspendScreenSaver) (_THIS); - - /* Text input */ - void (*StartTextInput) (_THIS); - void (*StopTextInput) (_THIS); - void (*SetTextInputRect) (_THIS, SDL_Rect *rect); - - /* Screen keyboard */ - SDL_bool (*HasScreenKeyboardSupport) (_THIS); - void (*ShowScreenKeyboard) (_THIS, SDL_Window *window); - void (*HideScreenKeyboard) (_THIS, SDL_Window *window); - SDL_bool (*IsScreenKeyboardShown) (_THIS, SDL_Window *window); - - /* Clipboard */ - int (*SetClipboardText) (_THIS, const char *text); - char * (*GetClipboardText) (_THIS); - SDL_bool (*HasClipboardText) (_THIS); - - /* MessageBox */ - int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid); - - /* * * */ - /* Data common to all drivers */ - SDL_bool suspend_screensaver; - int num_displays; - SDL_VideoDisplay *displays; - SDL_Window *windows; - Uint8 window_magic; - Uint32 next_object_id; - char * clipboard_text; - - /* * * */ - /* Data used by the GL drivers */ - struct - { - int red_size; - int green_size; - int blue_size; - int alpha_size; - int depth_size; - int buffer_size; - int stencil_size; - int double_buffer; - int accum_red_size; - int accum_green_size; - int accum_blue_size; - int accum_alpha_size; - int stereo; - int multisamplebuffers; - int multisamplesamples; - int accelerated; - int major_version; - int minor_version; - int flags; - int profile_mask; - int share_with_current_context; - int framebuffer_srgb_capable; - int retained_backing; - int driver_loaded; - char driver_path[256]; - void *dll_handle; - } gl_config; - - /* * * */ - /* Cache current GL context; don't call the OS when it hasn't changed. */ - /* We have the global pointers here so Cocoa continues to work the way - it always has, and the thread-local storage for the general case. - */ - SDL_Window *current_glwin; - SDL_GLContext current_glctx; - SDL_TLSID current_glwin_tls; - SDL_TLSID current_glctx_tls; - - /* * * */ - /* Data private to this driver */ - void *driverdata; - struct SDL_GLDriverData *gl_data; - -#if SDL_VIDEO_OPENGL_EGL - struct SDL_EGL_VideoData *egl_data; -#endif - -#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 - struct SDL_PrivateGLESData *gles_data; -#endif - - /* * * */ - /* The function used to dispose of this structure */ - void (*free) (_THIS); -}; - -typedef struct VideoBootStrap -{ - const char *name; - const char *desc; - int (*available) (void); - SDL_VideoDevice *(*create) (int devindex); -} VideoBootStrap; - -#if SDL_VIDEO_DRIVER_COCOA -extern VideoBootStrap COCOA_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_X11 -extern VideoBootStrap X11_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_DIRECTFB -extern VideoBootStrap DirectFB_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_WINDOWS -extern VideoBootStrap WINDOWS_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_WINRT -extern VideoBootStrap WINRT_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_HAIKU -extern VideoBootStrap HAIKU_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_PANDORA -extern VideoBootStrap PND_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_UIKIT -extern VideoBootStrap UIKIT_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_ANDROID -extern VideoBootStrap Android_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_PSP -extern VideoBootStrap PSP_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_RPI -extern VideoBootStrap RPI_bootstrap; -#endif -#if SDL_VIDEO_DRIVER_DUMMY -extern VideoBootStrap DUMMY_bootstrap; -#endif - -extern SDL_VideoDevice *SDL_GetVideoDevice(void); -extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode); -extern int SDL_AddVideoDisplay(const SDL_VideoDisplay * display); -extern SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode * mode); -extern SDL_VideoDisplay *SDL_GetDisplayForWindow(SDL_Window *window); -extern void *SDL_GetDisplayDriverData( int displayIndex ); - -extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); - -extern void SDL_OnWindowShown(SDL_Window * window); -extern void SDL_OnWindowHidden(SDL_Window * window); -extern void SDL_OnWindowResized(SDL_Window * window); -extern void SDL_OnWindowMinimized(SDL_Window * window); -extern void SDL_OnWindowRestored(SDL_Window * window); -extern void SDL_OnWindowEnter(SDL_Window * window); -extern void SDL_OnWindowLeave(SDL_Window * window); -extern void SDL_OnWindowFocusGained(SDL_Window * window); -extern void SDL_OnWindowFocusLost(SDL_Window * window); -extern void SDL_UpdateWindowGrab(SDL_Window * window); -extern SDL_Window * SDL_GetFocusWindow(void); - -extern SDL_bool SDL_ShouldAllowTopmost(void); - -#endif /* _SDL_sysvideo_h */ - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +#ifndef _SDL_sysvideo_h +#define _SDL_sysvideo_h + +#include "SDL_messagebox.h" +#include "SDL_shape.h" +#include "SDL_thread.h" + +/* The SDL video driver */ + +typedef struct SDL_WindowShaper SDL_WindowShaper; +typedef struct SDL_ShapeDriver SDL_ShapeDriver; +typedef struct SDL_VideoDisplay SDL_VideoDisplay; +typedef struct SDL_VideoDevice SDL_VideoDevice; + +/* Define the SDL window-shaper structure */ +struct SDL_WindowShaper +{ + /* The window associated with the shaper */ + SDL_Window *window; + + /* The user's specified coordinates for the window, for once we give it a shape. */ + Uint32 userx,usery; + + /* The parameters for shape calculation. */ + SDL_WindowShapeMode mode; + + /* Has this window been assigned a shape? */ + SDL_bool hasshape; + + void *driverdata; +}; + +/* Define the SDL shape driver structure */ +struct SDL_ShapeDriver +{ + SDL_WindowShaper *(*CreateShaper)(SDL_Window * window); + int (*SetWindowShape)(SDL_WindowShaper *shaper,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode); + int (*ResizeWindowShape)(SDL_Window *window); +}; + +typedef struct SDL_WindowUserData +{ + char *name; + void *data; + struct SDL_WindowUserData *next; +} SDL_WindowUserData; + +/* Define the SDL window structure, corresponding to toplevel windows */ +struct SDL_Window +{ + const void *magic; + Uint32 id; + char *title; + SDL_Surface *icon; + int x, y; + int w, h; + int min_w, min_h; + int max_w, max_h; + Uint32 flags; + + /* Stored position and size for windowed mode */ + SDL_Rect windowed; + + SDL_DisplayMode fullscreen_mode; + + float brightness; + Uint16 *gamma; + Uint16 *saved_gamma; /* (just offset into gamma) */ + + SDL_Surface *surface; + SDL_bool surface_valid; + + SDL_WindowShaper *shaper; + + SDL_WindowUserData *data; + + void *driverdata; + + SDL_Window *prev; + SDL_Window *next; +}; +#define FULLSCREEN_VISIBLE(W) \ + (((W)->flags & SDL_WINDOW_FULLSCREEN) && \ + ((W)->flags & SDL_WINDOW_SHOWN) && \ + !((W)->flags & SDL_WINDOW_MINIMIZED)) + +/* + * Define the SDL display structure This corresponds to physical monitors + * attached to the system. + */ +struct SDL_VideoDisplay +{ + char *name; + int max_display_modes; + int num_display_modes; + SDL_DisplayMode *display_modes; + SDL_DisplayMode desktop_mode; + SDL_DisplayMode current_mode; + + SDL_Window *fullscreen_window; + + SDL_VideoDevice *device; + + void *driverdata; +}; + +/* Forward declaration */ +struct SDL_SysWMinfo; + +/* Define the SDL video driver structure */ +#define _THIS SDL_VideoDevice *_this + +struct SDL_VideoDevice +{ + /* * * */ + /* The name of this video driver */ + const char *name; + + /* * * */ + /* Initialization/Query functions */ + + /* + * Initialize the native video subsystem, filling in the list of + * displays for this driver, returning 0 or -1 if there's an error. + */ + int (*VideoInit) (_THIS); + + /* + * Reverse the effects VideoInit() -- called if VideoInit() fails or + * if the application is shutting down the video subsystem. + */ + void (*VideoQuit) (_THIS); + + /* * * */ + /* + * Display functions + */ + + /* + * Get the bounds of a display + */ + int (*GetDisplayBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); + + /* + * Get a list of the available display modes for a display. + */ + void (*GetDisplayModes) (_THIS, SDL_VideoDisplay * display); + + /* + * Setting the display mode is independent of creating windows, so + * when the display mode is changed, all existing windows should have + * their data updated accordingly, including the display surfaces + * associated with them. + */ + int (*SetDisplayMode) (_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); + + /* * * */ + /* + * Window functions + */ + int (*CreateWindow) (_THIS, SDL_Window * window); + int (*CreateWindowFrom) (_THIS, SDL_Window * window, const void *data); + void (*SetWindowTitle) (_THIS, SDL_Window * window); + void (*SetWindowIcon) (_THIS, SDL_Window * window, SDL_Surface * icon); + void (*SetWindowPosition) (_THIS, SDL_Window * window); + void (*SetWindowSize) (_THIS, SDL_Window * window); + void (*SetWindowMinimumSize) (_THIS, SDL_Window * window); + void (*SetWindowMaximumSize) (_THIS, SDL_Window * window); + void (*ShowWindow) (_THIS, SDL_Window * window); + void (*HideWindow) (_THIS, SDL_Window * window); + void (*RaiseWindow) (_THIS, SDL_Window * window); + void (*MaximizeWindow) (_THIS, SDL_Window * window); + void (*MinimizeWindow) (_THIS, SDL_Window * window); + void (*RestoreWindow) (_THIS, SDL_Window * window); + void (*SetWindowBordered) (_THIS, SDL_Window * window, SDL_bool bordered); + void (*SetWindowFullscreen) (_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); + int (*SetWindowGammaRamp) (_THIS, SDL_Window * window, const Uint16 * ramp); + int (*GetWindowGammaRamp) (_THIS, SDL_Window * window, Uint16 * ramp); + void (*SetWindowGrab) (_THIS, SDL_Window * window, SDL_bool grabbed); + void (*DestroyWindow) (_THIS, SDL_Window * window); + int (*CreateWindowFramebuffer) (_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch); + int (*UpdateWindowFramebuffer) (_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects); + void (*DestroyWindowFramebuffer) (_THIS, SDL_Window * window); + void (*OnWindowEnter) (_THIS, SDL_Window * window); + + /* * * */ + /* + * Shaped-window functions + */ + SDL_ShapeDriver shape_driver; + + /* Get some platform dependent window information */ + SDL_bool(*GetWindowWMInfo) (_THIS, SDL_Window * window, + struct SDL_SysWMinfo * info); + + /* * * */ + /* + * OpenGL support + */ + int (*GL_LoadLibrary) (_THIS, const char *path); + void *(*GL_GetProcAddress) (_THIS, const char *proc); + void (*GL_UnloadLibrary) (_THIS); + SDL_GLContext(*GL_CreateContext) (_THIS, SDL_Window * window); + int (*GL_MakeCurrent) (_THIS, SDL_Window * window, SDL_GLContext context); + void (*GL_GetDrawableSize) (_THIS, SDL_Window * window, int *w, int *h); + int (*GL_SetSwapInterval) (_THIS, int interval); + int (*GL_GetSwapInterval) (_THIS); + void (*GL_SwapWindow) (_THIS, SDL_Window * window); + void (*GL_DeleteContext) (_THIS, SDL_GLContext context); + + /* * * */ + /* + * Event manager functions + */ + void (*PumpEvents) (_THIS); + + /* Suspend the screensaver */ + void (*SuspendScreenSaver) (_THIS); + + /* Text input */ + void (*StartTextInput) (_THIS); + void (*StopTextInput) (_THIS); + void (*SetTextInputRect) (_THIS, SDL_Rect *rect); + + /* Screen keyboard */ + SDL_bool (*HasScreenKeyboardSupport) (_THIS); + void (*ShowScreenKeyboard) (_THIS, SDL_Window *window); + void (*HideScreenKeyboard) (_THIS, SDL_Window *window); + SDL_bool (*IsScreenKeyboardShown) (_THIS, SDL_Window *window); + + /* Clipboard */ + int (*SetClipboardText) (_THIS, const char *text); + char * (*GetClipboardText) (_THIS); + SDL_bool (*HasClipboardText) (_THIS); + + /* MessageBox */ + int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid); + + /* * * */ + /* Data common to all drivers */ + SDL_bool suspend_screensaver; + int num_displays; + SDL_VideoDisplay *displays; + SDL_Window *windows; + Uint8 window_magic; + Uint32 next_object_id; + char * clipboard_text; + + /* * * */ + /* Data used by the GL drivers */ + struct + { + int red_size; + int green_size; + int blue_size; + int alpha_size; + int depth_size; + int buffer_size; + int stencil_size; + int double_buffer; + int accum_red_size; + int accum_green_size; + int accum_blue_size; + int accum_alpha_size; + int stereo; + int multisamplebuffers; + int multisamplesamples; + int accelerated; + int major_version; + int minor_version; + int flags; + int profile_mask; + int share_with_current_context; + int framebuffer_srgb_capable; + int retained_backing; + int driver_loaded; + char driver_path[256]; + void *dll_handle; + } gl_config; + + /* * * */ + /* Cache current GL context; don't call the OS when it hasn't changed. */ + /* We have the global pointers here so Cocoa continues to work the way + it always has, and the thread-local storage for the general case. + */ + SDL_Window *current_glwin; + SDL_GLContext current_glctx; + SDL_TLSID current_glwin_tls; + SDL_TLSID current_glctx_tls; + + /* * * */ + /* Data private to this driver */ + void *driverdata; + struct SDL_GLDriverData *gl_data; + +#if SDL_VIDEO_OPENGL_EGL + struct SDL_EGL_VideoData *egl_data; +#endif + +#if SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 + struct SDL_PrivateGLESData *gles_data; +#endif + + /* * * */ + /* The function used to dispose of this structure */ + void (*free) (_THIS); +}; + +typedef struct VideoBootStrap +{ + const char *name; + const char *desc; + int (*available) (void); + SDL_VideoDevice *(*create) (int devindex); +} VideoBootStrap; + +#if SDL_VIDEO_DRIVER_COCOA +extern VideoBootStrap COCOA_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_X11 +extern VideoBootStrap X11_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_DIRECTFB +extern VideoBootStrap DirectFB_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_WINDOWS +extern VideoBootStrap WINDOWS_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_WINRT +extern VideoBootStrap WINRT_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_HAIKU +extern VideoBootStrap HAIKU_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_PANDORA +extern VideoBootStrap PND_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_UIKIT +extern VideoBootStrap UIKIT_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_ANDROID +extern VideoBootStrap Android_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_PSP +extern VideoBootStrap PSP_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_RPI +extern VideoBootStrap RPI_bootstrap; +#endif +#if SDL_VIDEO_DRIVER_DUMMY +extern VideoBootStrap DUMMY_bootstrap; +#endif + +extern SDL_VideoDevice *SDL_GetVideoDevice(void); +extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode); +extern int SDL_AddVideoDisplay(const SDL_VideoDisplay * display); +extern SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode * mode); +extern SDL_VideoDisplay *SDL_GetDisplayForWindow(SDL_Window *window); +extern void *SDL_GetDisplayDriverData( int displayIndex ); + +extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); + +extern void SDL_OnWindowShown(SDL_Window * window); +extern void SDL_OnWindowHidden(SDL_Window * window); +extern void SDL_OnWindowResized(SDL_Window * window); +extern void SDL_OnWindowMinimized(SDL_Window * window); +extern void SDL_OnWindowRestored(SDL_Window * window); +extern void SDL_OnWindowEnter(SDL_Window * window); +extern void SDL_OnWindowLeave(SDL_Window * window); +extern void SDL_OnWindowFocusGained(SDL_Window * window); +extern void SDL_OnWindowFocusLost(SDL_Window * window); +extern void SDL_UpdateWindowGrab(SDL_Window * window); +extern SDL_Window * SDL_GetFocusWindow(void); + +extern SDL_bool SDL_ShouldAllowTopmost(void); + +#endif /* _SDL_sysvideo_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index c265a77e64654..a05914eaaa833 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1,3293 +1,3293 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_config.h" - -/* The high-level video driver subsystem */ - -#include "SDL.h" -#include "SDL_video.h" -#include "SDL_sysvideo.h" -#include "SDL_blit.h" -#include "SDL_pixels_c.h" -#include "SDL_rect_c.h" -#include "../events/SDL_events_c.h" -#include "../timer/SDL_timer_c.h" - -#if SDL_VIDEO_OPENGL -#include "SDL_opengl.h" -#endif /* SDL_VIDEO_OPENGL */ - -#if SDL_VIDEO_OPENGL_ES -#include "SDL_opengles.h" -#endif /* SDL_VIDEO_OPENGL_ES */ - -/* GL and GLES2 headers conflict on Linux 32 bits */ -#if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL -#include "SDL_opengles2.h" -#endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */ - -#include "SDL_syswm.h" - -/* On Windows, windows.h defines CreateWindow */ -#ifdef CreateWindow -#undef CreateWindow -#endif - -/* Available video drivers */ -static VideoBootStrap *bootstrap[] = { -#if SDL_VIDEO_DRIVER_COCOA - &COCOA_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_X11 - &X11_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_DIRECTFB - &DirectFB_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_WINDOWS - &WINDOWS_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_WINRT - &WINRT_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_HAIKU - &HAIKU_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_PANDORA - &PND_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_UIKIT - &UIKIT_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_ANDROID - &Android_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_PSP - &PSP_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_RPI - &RPI_bootstrap, -#endif -#if SDL_VIDEO_DRIVER_DUMMY - &DUMMY_bootstrap, -#endif - NULL -}; - -static SDL_VideoDevice *_this = NULL; - -#define CHECK_WINDOW_MAGIC(window, retval) \ - if (!_this) { \ - SDL_UninitializedVideo(); \ - return retval; \ - } \ - if (!window || window->magic != &_this->window_magic) { \ - SDL_SetError("Invalid window"); \ - return retval; \ - } - -#define CHECK_DISPLAY_INDEX(displayIndex, retval) \ - if (!_this) { \ - SDL_UninitializedVideo(); \ - return retval; \ - } \ - if (displayIndex < 0 || displayIndex >= _this->num_displays) { \ - SDL_SetError("displayIndex must be in the range 0 - %d", \ - _this->num_displays - 1); \ - return retval; \ - } - - -#ifdef __MACOSX__ -/* Support for Mac OS X fullscreen spaces */ -extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window); -extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state); -#endif - - -/* Support for framebuffer emulation using an accelerated renderer */ - -#define SDL_WINDOWTEXTUREDATA "_SDL_WindowTextureData" - -typedef struct { - SDL_Renderer *renderer; - SDL_Texture *texture; - void *pixels; - int pitch; - int bytes_per_pixel; -} SDL_WindowTextureData; - -static SDL_bool -ShouldUseTextureFramebuffer() -{ - const char *hint; - - /* If there's no native framebuffer support then there's no option */ - if (!_this->CreateWindowFramebuffer) { - return SDL_TRUE; - } - - /* If the user has specified a software renderer we can't use a - texture framebuffer, or renderer creation will go recursive. - */ - hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER); - if (hint && SDL_strcasecmp(hint, "software") == 0) { - return SDL_FALSE; - } - - /* See if the user or application wants a specific behavior */ - hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); - if (hint) { - if (*hint == '0') { - return SDL_FALSE; - } else { - return SDL_TRUE; - } - } - - /* Each platform has different performance characteristics */ -#if defined(__WIN32__) - /* GDI BitBlt() is way faster than Direct3D dynamic textures right now. - */ - return SDL_FALSE; - -#elif defined(__MACOSX__) - /* Mac OS X uses OpenGL as the native fast path */ - return SDL_TRUE; - -#elif defined(__LINUX__) - /* Properly configured OpenGL drivers are faster than MIT-SHM */ -#if SDL_VIDEO_OPENGL - /* Ugh, find a way to cache this value! */ - { - SDL_Window *window; - SDL_GLContext context; - SDL_bool hasAcceleratedOpenGL = SDL_FALSE; - - window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN); - if (window) { - context = SDL_GL_CreateContext(window); - if (context) { - const GLubyte *(APIENTRY * glGetStringFunc) (GLenum); - const char *vendor = NULL; - - glGetStringFunc = SDL_GL_GetProcAddress("glGetString"); - if (glGetStringFunc) { - vendor = (const char *) glGetStringFunc(GL_VENDOR); - } - /* Add more vendors here at will... */ - if (vendor && - (SDL_strstr(vendor, "ATI Technologies") || - SDL_strstr(vendor, "NVIDIA"))) { - hasAcceleratedOpenGL = SDL_TRUE; - } - SDL_GL_DeleteContext(context); - } - SDL_DestroyWindow(window); - } - return hasAcceleratedOpenGL; - } -#elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 - /* Let's be optimistic about this! */ - return SDL_TRUE; -#else - return SDL_FALSE; -#endif - -#else - /* Play it safe, assume that if there is a framebuffer driver that it's - optimized for the current platform. - */ - return SDL_FALSE; -#endif -} - -static int -SDL_CreateWindowTexture(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) -{ - SDL_WindowTextureData *data; - SDL_RendererInfo info; - Uint32 i; - - data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); - if (!data) { - SDL_Renderer *renderer = NULL; - SDL_RendererInfo info; - int i; - const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); - - /* Check to see if there's a specific driver requested */ - if (hint && *hint != '0' && *hint != '1' && - SDL_strcasecmp(hint, "software") != 0) { - for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { - SDL_GetRenderDriverInfo(i, &info); - if (SDL_strcasecmp(info.name, hint) == 0) { - renderer = SDL_CreateRenderer(window, i, 0); - break; - } - } - } - - if (!renderer) { - for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { - SDL_GetRenderDriverInfo(i, &info); - if (SDL_strcmp(info.name, "software") != 0) { - renderer = SDL_CreateRenderer(window, i, 0); - if (renderer) { - break; - } - } - } - } - if (!renderer) { - return SDL_SetError("No hardware accelerated renderers available"); - } - - /* Create the data after we successfully create the renderer (bug #1116) */ - data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data)); - if (!data) { - SDL_DestroyRenderer(renderer); - return SDL_OutOfMemory(); - } - SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data); - - data->renderer = renderer; - } - - /* Free any old texture and pixel data */ - if (data->texture) { - SDL_DestroyTexture(data->texture); - data->texture = NULL; - } - SDL_free(data->pixels); - data->pixels = NULL; - - if (SDL_GetRendererInfo(data->renderer, &info) < 0) { - return -1; - } - - /* Find the first format without an alpha channel */ - *format = info.texture_formats[0]; - for (i = 0; i < info.num_texture_formats; ++i) { - if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) && - !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) { - *format = info.texture_formats[i]; - break; - } - } - - data->texture = SDL_CreateTexture(data->renderer, *format, - SDL_TEXTUREACCESS_STREAMING, - window->w, window->h); - if (!data->texture) { - return -1; - } - - /* Create framebuffer data */ - data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format); - data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3); - data->pixels = SDL_malloc(window->h * data->pitch); - if (!data->pixels) { - return SDL_OutOfMemory(); - } - - *pixels = data->pixels; - *pitch = data->pitch; - - /* Make sure we're not double-scaling the viewport */ - SDL_RenderSetViewport(data->renderer, NULL); - - return 0; -} - -static int -SDL_UpdateWindowTexture(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects) -{ - SDL_WindowTextureData *data; - SDL_Rect rect; - void *src; - - data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); - if (!data || !data->texture) { - return SDL_SetError("No window texture data"); - } - - /* Update a single rect that contains subrects for best DMA performance */ - if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) { - src = (void *)((Uint8 *)data->pixels + - rect.y * data->pitch + - rect.x * data->bytes_per_pixel); - if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) { - return -1; - } - - if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) { - return -1; - } - - SDL_RenderPresent(data->renderer); - } - return 0; -} - -static void -SDL_DestroyWindowTexture(_THIS, SDL_Window * window) -{ - SDL_WindowTextureData *data; - - data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL); - if (!data) { - return; - } - if (data->texture) { - SDL_DestroyTexture(data->texture); - } - if (data->renderer) { - SDL_DestroyRenderer(data->renderer); - } - SDL_free(data->pixels); - SDL_free(data); -} - - -static int -cmpmodes(const void *A, const void *B) -{ - const SDL_DisplayMode *a = (const SDL_DisplayMode *) A; - const SDL_DisplayMode *b = (const SDL_DisplayMode *) B; - if (a == b) { - return 0; - } else if (a->w != b->w) { - return b->w - a->w; - } else if (a->h != b->h) { - return b->h - a->h; - } else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) { - return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format); - } else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) { - return SDL_PIXELLAYOUT(b->format) - SDL_PIXELLAYOUT(a->format); - } else if (a->refresh_rate != b->refresh_rate) { - return b->refresh_rate - a->refresh_rate; - } - return 0; -} - -static int -SDL_UninitializedVideo() -{ - return SDL_SetError("Video subsystem has not been initialized"); -} - -int -SDL_GetNumVideoDrivers(void) -{ - return SDL_arraysize(bootstrap) - 1; -} - -const char * -SDL_GetVideoDriver(int index) -{ - if (index >= 0 && index < SDL_GetNumVideoDrivers()) { - return bootstrap[index]->name; - } - return NULL; -} - -/* - * Initialize the video and event subsystems -- determine native pixel format - */ -int -SDL_VideoInit(const char *driver_name) -{ - SDL_VideoDevice *video; - int index; - int i; - - /* Check to make sure we don't overwrite '_this' */ - if (_this != NULL) { - SDL_VideoQuit(); - } - -#if !SDL_TIMERS_DISABLED - SDL_InitTicks(); -#endif - - /* Start the event loop */ - if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 || - SDL_KeyboardInit() < 0 || - SDL_MouseInit() < 0 || - SDL_TouchInit() < 0) { - return -1; - } - - /* Select the proper video driver */ - index = 0; - video = NULL; - if (driver_name == NULL) { - driver_name = SDL_getenv("SDL_VIDEODRIVER"); - } - if (driver_name != NULL) { - for (i = 0; bootstrap[i]; ++i) { - if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) { - video = bootstrap[i]->create(index); - break; - } - } - } else { - for (i = 0; bootstrap[i]; ++i) { - if (bootstrap[i]->available()) { - video = bootstrap[i]->create(index); - if (video != NULL) { - break; - } - } - } - } - if (video == NULL) { - if (driver_name) { - return SDL_SetError("%s not available", driver_name); - } - return SDL_SetError("No available video device"); - } - _this = video; - _this->name = bootstrap[i]->name; - _this->next_object_id = 1; - - - /* Set some very sane GL defaults */ - _this->gl_config.driver_loaded = 0; - _this->gl_config.dll_handle = NULL; - _this->gl_config.red_size = 3; - _this->gl_config.green_size = 3; - _this->gl_config.blue_size = 2; - _this->gl_config.alpha_size = 0; - _this->gl_config.buffer_size = 0; - _this->gl_config.depth_size = 16; - _this->gl_config.stencil_size = 0; - _this->gl_config.double_buffer = 1; - _this->gl_config.accum_red_size = 0; - _this->gl_config.accum_green_size = 0; - _this->gl_config.accum_blue_size = 0; - _this->gl_config.accum_alpha_size = 0; - _this->gl_config.stereo = 0; - _this->gl_config.multisamplebuffers = 0; - _this->gl_config.multisamplesamples = 0; - _this->gl_config.retained_backing = 1; - _this->gl_config.accelerated = -1; /* accelerated or not, both are fine */ - _this->gl_config.profile_mask = 0; -#if SDL_VIDEO_OPENGL - _this->gl_config.major_version = 2; - _this->gl_config.minor_version = 1; -#elif SDL_VIDEO_OPENGL_ES2 - _this->gl_config.major_version = 2; - _this->gl_config.minor_version = 0; - _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; -#elif SDL_VIDEO_OPENGL_ES - _this->gl_config.major_version = 1; - _this->gl_config.minor_version = 1; - _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; -#endif - _this->gl_config.flags = 0; - - _this->gl_config.share_with_current_context = 0; - - _this->current_glwin_tls = SDL_TLSCreate(); - _this->current_glctx_tls = SDL_TLSCreate(); - - /* Initialize the video subsystem */ - if (_this->VideoInit(_this) < 0) { - SDL_VideoQuit(); - return -1; - } - - /* Make sure some displays were added */ - if (_this->num_displays == 0) { - SDL_VideoQuit(); - return SDL_SetError("The video driver did not add any displays"); - } - - /* Add the renderer framebuffer emulation if desired */ - if (ShouldUseTextureFramebuffer()) { - _this->CreateWindowFramebuffer = SDL_CreateWindowTexture; - _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture; - _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture; - } - - /* If we don't use a screen keyboard, turn on text input by default, - otherwise programs that expect to get text events without enabling - UNICODE input won't get any events. - - Actually, come to think of it, you needed to call SDL_EnableUNICODE(1) - in SDL 1.2 before you got text input events. Hmm... - */ - if (!SDL_HasScreenKeyboardSupport()) { - SDL_StartTextInput(); - } - - /* We're ready to go! */ - return 0; -} - -const char * -SDL_GetCurrentVideoDriver() -{ - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - return _this->name; -} - -SDL_VideoDevice * -SDL_GetVideoDevice(void) -{ - return _this; -} - -int -SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode) -{ - SDL_VideoDisplay display; - - SDL_zero(display); - if (desktop_mode) { - display.desktop_mode = *desktop_mode; - } - display.current_mode = display.desktop_mode; - - return SDL_AddVideoDisplay(&display); -} - -int -SDL_AddVideoDisplay(const SDL_VideoDisplay * display) -{ - SDL_VideoDisplay *displays; - int index = -1; - - displays = - SDL_realloc(_this->displays, - (_this->num_displays + 1) * sizeof(*displays)); - if (displays) { - index = _this->num_displays++; - displays[index] = *display; - displays[index].device = _this; - _this->displays = displays; - - if (display->name) { - displays[index].name = SDL_strdup(display->name); - } else { - char name[32]; - - SDL_itoa(index, name, 10); - displays[index].name = SDL_strdup(name); - } - } else { - SDL_OutOfMemory(); - } - return index; -} - -int -SDL_GetNumVideoDisplays(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return 0; - } - return _this->num_displays; -} - -static int -SDL_GetIndexOfDisplay(SDL_VideoDisplay *display) -{ - int displayIndex; - - for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) { - if (display == &_this->displays[displayIndex]) { - return displayIndex; - } - } - - /* Couldn't find the display, just use index 0 */ - return 0; -} - -void * -SDL_GetDisplayDriverData( int displayIndex ) -{ - CHECK_DISPLAY_INDEX( displayIndex, NULL ); - - return _this->displays[displayIndex].driverdata; -} - -const char * -SDL_GetDisplayName(int displayIndex) -{ - CHECK_DISPLAY_INDEX(displayIndex, NULL); - - return _this->displays[displayIndex].name; -} - -int -SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect) -{ - CHECK_DISPLAY_INDEX(displayIndex, -1); - - if (rect) { - SDL_VideoDisplay *display = &_this->displays[displayIndex]; - - if (_this->GetDisplayBounds) { - if (_this->GetDisplayBounds(_this, display, rect) == 0) { - return 0; - } - } - - /* Assume that the displays are left to right */ - if (displayIndex == 0) { - rect->x = 0; - rect->y = 0; - } else { - SDL_GetDisplayBounds(displayIndex-1, rect); - rect->x += rect->w; - } - rect->w = display->current_mode.w; - rect->h = display->current_mode.h; - } - return 0; -} - -SDL_bool -SDL_AddDisplayMode(SDL_VideoDisplay * display, const SDL_DisplayMode * mode) -{ - SDL_DisplayMode *modes; - int i, nmodes; - - /* Make sure we don't already have the mode in the list */ - modes = display->display_modes; - nmodes = display->num_display_modes; - for (i = 0; i < nmodes; ++i) { - if (cmpmodes(mode, &modes[i]) == 0) { - return SDL_FALSE; - } - } - - /* Go ahead and add the new mode */ - if (nmodes == display->max_display_modes) { - modes = - SDL_realloc(modes, - (display->max_display_modes + 32) * sizeof(*modes)); - if (!modes) { - return SDL_FALSE; - } - display->display_modes = modes; - display->max_display_modes += 32; - } - modes[nmodes] = *mode; - display->num_display_modes++; - - /* Re-sort video modes */ - SDL_qsort(display->display_modes, display->num_display_modes, - sizeof(SDL_DisplayMode), cmpmodes); - - return SDL_TRUE; -} - -static int -SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display) -{ - if (!display->num_display_modes && _this->GetDisplayModes) { - _this->GetDisplayModes(_this, display); - SDL_qsort(display->display_modes, display->num_display_modes, - sizeof(SDL_DisplayMode), cmpmodes); - } - return display->num_display_modes; -} - -int -SDL_GetNumDisplayModes(int displayIndex) -{ - CHECK_DISPLAY_INDEX(displayIndex, -1); - - return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]); -} - -int -SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode) -{ - SDL_VideoDisplay *display; - - CHECK_DISPLAY_INDEX(displayIndex, -1); - - display = &_this->displays[displayIndex]; - if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) { - return SDL_SetError("index must be in the range of 0 - %d", - SDL_GetNumDisplayModesForDisplay(display) - 1); - } - if (mode) { - *mode = display->display_modes[index]; - } - return 0; -} - -int -SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode) -{ - SDL_VideoDisplay *display; - - CHECK_DISPLAY_INDEX(displayIndex, -1); - - display = &_this->displays[displayIndex]; - if (mode) { - *mode = display->desktop_mode; - } - return 0; -} - -int -SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode) -{ - SDL_VideoDisplay *display; - - CHECK_DISPLAY_INDEX(displayIndex, -1); - - display = &_this->displays[displayIndex]; - if (mode) { - *mode = display->current_mode; - } - return 0; -} - -static SDL_DisplayMode * -SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display, - const SDL_DisplayMode * mode, - SDL_DisplayMode * closest) -{ - Uint32 target_format; - int target_refresh_rate; - int i; - SDL_DisplayMode *current, *match; - - if (!mode || !closest) { - SDL_SetError("Missing desired mode or closest mode parameter"); - return NULL; - } - - /* Default to the desktop format */ - if (mode->format) { - target_format = mode->format; - } else { - target_format = display->desktop_mode.format; - } - - /* Default to the desktop refresh rate */ - if (mode->refresh_rate) { - target_refresh_rate = mode->refresh_rate; - } else { - target_refresh_rate = display->desktop_mode.refresh_rate; - } - - match = NULL; - for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) { - current = &display->display_modes[i]; - - if (current->w && (current->w < mode->w)) { - /* Out of sorted modes large enough here */ - break; - } - if (current->h && (current->h < mode->h)) { - if (current->w && (current->w == mode->w)) { - /* Out of sorted modes large enough here */ - break; - } - /* Wider, but not tall enough, due to a different - aspect ratio. This mode must be skipped, but closer - modes may still follow. */ - continue; - } - if (!match || current->w < match->w || current->h < match->h) { - match = current; - continue; - } - if (current->format != match->format) { - /* Sorted highest depth to lowest */ - if (current->format == target_format || - (SDL_BITSPERPIXEL(current->format) >= - SDL_BITSPERPIXEL(target_format) - && SDL_PIXELTYPE(current->format) == - SDL_PIXELTYPE(target_format))) { - match = current; - } - continue; - } - if (current->refresh_rate != match->refresh_rate) { - /* Sorted highest refresh to lowest */ - if (current->refresh_rate >= target_refresh_rate) { - match = current; - } - } - } - if (match) { - if (match->format) { - closest->format = match->format; - } else { - closest->format = mode->format; - } - if (match->w && match->h) { - closest->w = match->w; - closest->h = match->h; - } else { - closest->w = mode->w; - closest->h = mode->h; - } - if (match->refresh_rate) { - closest->refresh_rate = match->refresh_rate; - } else { - closest->refresh_rate = mode->refresh_rate; - } - closest->driverdata = match->driverdata; - - /* - * Pick some reasonable defaults if the app and driver don't - * care - */ - if (!closest->format) { - closest->format = SDL_PIXELFORMAT_RGB888; - } - if (!closest->w) { - closest->w = 640; - } - if (!closest->h) { - closest->h = 480; - } - return closest; - } - return NULL; -} - -SDL_DisplayMode * -SDL_GetClosestDisplayMode(int displayIndex, - const SDL_DisplayMode * mode, - SDL_DisplayMode * closest) -{ - SDL_VideoDisplay *display; - - CHECK_DISPLAY_INDEX(displayIndex, NULL); - - display = &_this->displays[displayIndex]; - return SDL_GetClosestDisplayModeForDisplay(display, mode, closest); -} - -static int -SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode) -{ - SDL_DisplayMode display_mode; - SDL_DisplayMode current_mode; - - if (mode) { - display_mode = *mode; - - /* Default to the current mode */ - if (!display_mode.format) { - display_mode.format = display->current_mode.format; - } - if (!display_mode.w) { - display_mode.w = display->current_mode.w; - } - if (!display_mode.h) { - display_mode.h = display->current_mode.h; - } - if (!display_mode.refresh_rate) { - display_mode.refresh_rate = display->current_mode.refresh_rate; - } - - /* Get a good video mode, the closest one possible */ - if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) { - return SDL_SetError("No video mode large enough for %dx%d", - display_mode.w, display_mode.h); - } - } else { - display_mode = display->desktop_mode; - } - - /* See if there's anything left to do */ - current_mode = display->current_mode; - if (SDL_memcmp(&display_mode, ¤t_mode, sizeof(display_mode)) == 0) { - return 0; - } - - /* Actually change the display mode */ - if (!_this->SetDisplayMode) { - return SDL_SetError("Video driver doesn't support changing display mode"); - } - if (_this->SetDisplayMode(_this, display, &display_mode) < 0) { - return -1; - } - display->current_mode = display_mode; - return 0; -} - -int -SDL_GetWindowDisplayIndex(SDL_Window * window) -{ - int displayIndex; - int i, dist; - int closest = -1; - int closest_dist = 0x7FFFFFFF; - SDL_Point center; - SDL_Point delta; - SDL_Rect rect; - - CHECK_WINDOW_MAGIC(window, -1); - - if (SDL_WINDOWPOS_ISUNDEFINED(window->x) || - SDL_WINDOWPOS_ISCENTERED(window->x)) { - displayIndex = (window->x & 0xFFFF); - if (displayIndex >= _this->num_displays) { - displayIndex = 0; - } - return displayIndex; - } - if (SDL_WINDOWPOS_ISUNDEFINED(window->y) || - SDL_WINDOWPOS_ISCENTERED(window->y)) { - displayIndex = (window->y & 0xFFFF); - if (displayIndex >= _this->num_displays) { - displayIndex = 0; - } - return displayIndex; - } - - /* Find the display containing the window */ - for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = &_this->displays[i]; - - if (display->fullscreen_window == window) { - return i; - } - } - center.x = window->x + window->w / 2; - center.y = window->y + window->h / 2; - for (i = 0; i < _this->num_displays; ++i) { - SDL_GetDisplayBounds(i, &rect); - if (SDL_EnclosePoints(¢er, 1, &rect, NULL)) { - return i; - } - - delta.x = center.x - (rect.x + rect.w / 2); - delta.y = center.y - (rect.y + rect.h / 2); - dist = (delta.x*delta.x + delta.y*delta.y); - if (dist < closest_dist) { - closest = i; - closest_dist = dist; - } - } - if (closest < 0) { - SDL_SetError("Couldn't find any displays"); - } - return closest; -} - -SDL_VideoDisplay * -SDL_GetDisplayForWindow(SDL_Window *window) -{ - int displayIndex = SDL_GetWindowDisplayIndex(window); - if (displayIndex >= 0) { - return &_this->displays[displayIndex]; - } else { - return NULL; - } -} - -int -SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode) -{ - CHECK_WINDOW_MAGIC(window, -1); - - if (mode) { - window->fullscreen_mode = *mode; - } else { - SDL_zero(window->fullscreen_mode); - } - return 0; -} - -int -SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode) -{ - SDL_DisplayMode fullscreen_mode; - SDL_VideoDisplay *display; - - if (!mode) { - return SDL_InvalidParamError("mode"); - } - - CHECK_WINDOW_MAGIC(window, -1); - - fullscreen_mode = window->fullscreen_mode; - if (!fullscreen_mode.w) { - fullscreen_mode.w = window->w; - } - if (!fullscreen_mode.h) { - fullscreen_mode.h = window->h; - } - - display = SDL_GetDisplayForWindow(window); - - /* if in desktop size mode, just return the size of the desktop */ - if ( ( window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP ) == SDL_WINDOW_FULLSCREEN_DESKTOP ) - { - fullscreen_mode = display->desktop_mode; - } - else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window), - &fullscreen_mode, - &fullscreen_mode)) { - return SDL_SetError("Couldn't find display mode match"); - } - - if (mode) { - *mode = fullscreen_mode; - } - return 0; -} - -Uint32 -SDL_GetWindowPixelFormat(SDL_Window * window) -{ - SDL_VideoDisplay *display; - - CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN); - - display = SDL_GetDisplayForWindow(window); - return display->current_mode.format; -} - -static void -SDL_RestoreMousePosition(SDL_Window *window) -{ - int x, y; - - if (window == SDL_GetMouseFocus()) { - SDL_GetMouseState(&x, &y); - SDL_WarpMouseInWindow(window, x, y); - } -} - -static void -SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) -{ - SDL_VideoDisplay *display; - SDL_Window *other; - -#ifdef __MACOSX__ - if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) { - return; - } -#endif - - display = SDL_GetDisplayForWindow(window); - - if (fullscreen) { - /* Hide any other fullscreen windows */ - if (display->fullscreen_window && - display->fullscreen_window != window) { - SDL_MinimizeWindow(display->fullscreen_window); - } - } - - /* See if anything needs to be done now */ - if ((display->fullscreen_window == window) == fullscreen) { - return; - } - - /* See if there are any fullscreen windows */ - for (other = _this->windows; other; other = other->next) { - SDL_bool setDisplayMode = SDL_FALSE; - - if (other == window) { - setDisplayMode = fullscreen; - } else if (FULLSCREEN_VISIBLE(other) && - SDL_GetDisplayForWindow(other) == display) { - setDisplayMode = SDL_TRUE; - } - - if (setDisplayMode) { - SDL_DisplayMode fullscreen_mode; - - if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) { - SDL_bool resized = SDL_TRUE; - - if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) { - resized = SDL_FALSE; - } - - /* only do the mode change if we want exclusive fullscreen */ - if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { - SDL_SetDisplayModeForDisplay(display, &fullscreen_mode); - } else { - SDL_SetDisplayModeForDisplay(display, NULL); - } - - if (_this->SetWindowFullscreen) { - _this->SetWindowFullscreen(_this, other, display, SDL_TRUE); - } - display->fullscreen_window = other; - - /* Generate a mode change event here */ - if (resized) { - SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED, - fullscreen_mode.w, fullscreen_mode.h); - } else { - SDL_OnWindowResized(other); - } - - SDL_RestoreMousePosition(other); - return; - } - } - } - - /* Nope, restore the desktop mode */ - SDL_SetDisplayModeForDisplay(display, NULL); - - if (_this->SetWindowFullscreen) { - _this->SetWindowFullscreen(_this, window, display, SDL_FALSE); - } - display->fullscreen_window = NULL; - - /* Generate a mode change event here */ - SDL_OnWindowResized(window); - - /* Restore the cursor position */ - SDL_RestoreMousePosition(window); -} - -#define CREATE_FLAGS \ - (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI) - -static void -SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags) -{ - window->windowed.x = window->x; - window->windowed.y = window->y; - window->windowed.w = window->w; - window->windowed.h = window->h; - - if (flags & SDL_WINDOW_MAXIMIZED) { - SDL_MaximizeWindow(window); - } - if (flags & SDL_WINDOW_MINIMIZED) { - SDL_MinimizeWindow(window); - } - if (flags & SDL_WINDOW_FULLSCREEN) { - SDL_SetWindowFullscreen(window, flags); - } - if (flags & SDL_WINDOW_INPUT_GRABBED) { - SDL_SetWindowGrab(window, SDL_TRUE); - } - if (!(flags & SDL_WINDOW_HIDDEN)) { - SDL_ShowWindow(window); - } -} - -SDL_Window * -SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) -{ - SDL_Window *window; - const char *hint; - - if (!_this) { - /* Initialize the video system if needed */ - if (SDL_VideoInit(NULL) < 0) { - return NULL; - } - } - - /* Some platforms can't create zero-sized windows */ - if (w < 1) { - w = 1; - } - if (h < 1) { - h = 1; - } - - /* Some platforms have OpenGL enabled by default */ -#if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ - flags |= SDL_WINDOW_OPENGL; -#endif - if (flags & SDL_WINDOW_OPENGL) { - if (!_this->GL_CreateContext) { - SDL_SetError("No OpenGL support in video driver"); - return NULL; - } - if (SDL_GL_LoadLibrary(NULL) < 0) { - return NULL; - } - } - - /* Unless the user has specified the high-DPI disabling hint, respect the - * SDL_WINDOW_ALLOW_HIGHDPI flag. - */ - if (flags & SDL_WINDOW_ALLOW_HIGHDPI) { - hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED); - if (hint && SDL_atoi(hint) > 0) { - flags &= ~SDL_WINDOW_ALLOW_HIGHDPI; - } - } - - window = (SDL_Window *)SDL_calloc(1, sizeof(*window)); - if (!window) { - SDL_OutOfMemory(); - return NULL; - } - window->magic = &_this->window_magic; - window->id = _this->next_object_id++; - window->x = x; - window->y = y; - window->w = w; - window->h = h; - if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) || - SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - int displayIndex; - SDL_Rect bounds; - - displayIndex = SDL_GetIndexOfDisplay(display); - SDL_GetDisplayBounds(displayIndex, &bounds); - if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) { - window->x = bounds.x + (bounds.w - w) / 2; - } - if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) { - window->y = bounds.y + (bounds.h - h) / 2; - } - } - window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); - window->brightness = 1.0f; - window->next = _this->windows; - - if (_this->windows) { - _this->windows->prev = window; - } - _this->windows = window; - - if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) { - SDL_DestroyWindow(window); - return NULL; - } - - if (title) { - SDL_SetWindowTitle(window, title); - } - SDL_FinishWindowCreation(window, flags); - - /* If the window was created fullscreen, make sure the mode code matches */ - SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)); - - return window; -} - -SDL_Window * -SDL_CreateWindowFrom(const void *data) -{ - SDL_Window *window; - - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - window = (SDL_Window *)SDL_calloc(1, sizeof(*window)); - if (!window) { - SDL_OutOfMemory(); - return NULL; - } - window->magic = &_this->window_magic; - window->id = _this->next_object_id++; - window->flags = SDL_WINDOW_FOREIGN; - window->brightness = 1.0f; - window->next = _this->windows; - if (_this->windows) { - _this->windows->prev = window; - } - _this->windows = window; - - if (!_this->CreateWindowFrom || - _this->CreateWindowFrom(_this, window, data) < 0) { - SDL_DestroyWindow(window); - return NULL; - } - return window; -} - -int -SDL_RecreateWindow(SDL_Window * window, Uint32 flags) -{ - char *title = window->title; - SDL_Surface *icon = window->icon; - - if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) { - return SDL_SetError("No OpenGL support in video driver"); - } - - if (window->flags & SDL_WINDOW_FOREIGN) { - /* Can't destroy and re-create foreign windows, hrm */ - flags |= SDL_WINDOW_FOREIGN; - } else { - flags &= ~SDL_WINDOW_FOREIGN; - } - - /* Restore video mode, etc. */ - SDL_HideWindow(window); - - /* Tear down the old native window */ - if (window->surface) { - window->surface->flags &= ~SDL_DONTFREE; - SDL_FreeSurface(window->surface); - } - if (_this->DestroyWindowFramebuffer) { - _this->DestroyWindowFramebuffer(_this, window); - } - if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) { - _this->DestroyWindow(_this, window); - } - - if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) { - if (flags & SDL_WINDOW_OPENGL) { - if (SDL_GL_LoadLibrary(NULL) < 0) { - return -1; - } - } else { - SDL_GL_UnloadLibrary(); - } - } - - window->title = NULL; - window->icon = NULL; - window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); - - if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) { - if (_this->CreateWindow(_this, window) < 0) { - if (flags & SDL_WINDOW_OPENGL) { - SDL_GL_UnloadLibrary(); - } - return -1; - } - } - - if (title) { - SDL_SetWindowTitle(window, title); - SDL_free(title); - } - if (icon) { - SDL_SetWindowIcon(window, icon); - SDL_FreeSurface(icon); - } - SDL_FinishWindowCreation(window, flags); - - return 0; -} - -Uint32 -SDL_GetWindowID(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, 0); - - return window->id; -} - -SDL_Window * -SDL_GetWindowFromID(Uint32 id) -{ - SDL_Window *window; - - if (!_this) { - return NULL; - } - for (window = _this->windows; window; window = window->next) { - if (window->id == id) { - return window; - } - } - return NULL; -} - -Uint32 -SDL_GetWindowFlags(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, 0); - - return window->flags; -} - -void -SDL_SetWindowTitle(SDL_Window * window, const char *title) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (title == window->title) { - return; - } - SDL_free(window->title); - if (title && *title) { - window->title = SDL_strdup(title); - } else { - window->title = NULL; - } - - if (_this->SetWindowTitle) { - _this->SetWindowTitle(_this, window); - } -} - -const char * -SDL_GetWindowTitle(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, ""); - - return window->title ? window->title : ""; -} - -void -SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (!icon) { - return; - } - - SDL_FreeSurface(window->icon); - - /* Convert the icon into ARGB8888 */ - window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0); - if (!window->icon) { - return; - } - - if (_this->SetWindowIcon) { - _this->SetWindowIcon(_this, window, window->icon); - } -} - -void* -SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata) -{ - SDL_WindowUserData *prev, *data; - - CHECK_WINDOW_MAGIC(window, NULL); - - /* Input validation */ - if (name == NULL || name[0] == '\0') { - SDL_InvalidParamError("name"); - return NULL; - } - - /* See if the named data already exists */ - prev = NULL; - for (data = window->data; data; prev = data, data = data->next) { - if (data->name && SDL_strcmp(data->name, name) == 0) { - void *last_value = data->data; - - if (userdata) { - /* Set the new value */ - data->data = userdata; - } else { - /* Delete this value */ - if (prev) { - prev->next = data->next; - } else { - window->data = data->next; - } - SDL_free(data->name); - SDL_free(data); - } - return last_value; - } - } - - /* Add new data to the window */ - if (userdata) { - data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data)); - data->name = SDL_strdup(name); - data->data = userdata; - data->next = window->data; - window->data = data; - } - return NULL; -} - -void * -SDL_GetWindowData(SDL_Window * window, const char *name) -{ - SDL_WindowUserData *data; - - CHECK_WINDOW_MAGIC(window, NULL); - - /* Input validation */ - if (name == NULL || name[0] == '\0') { - SDL_InvalidParamError("name"); - return NULL; - } - - for (data = window->data; data; data = data->next) { - if (data->name && SDL_strcmp(data->name, name) == 0) { - return data->data; - } - } - return NULL; -} - -void -SDL_SetWindowPosition(SDL_Window * window, int x, int y) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - int displayIndex; - SDL_Rect bounds; - - displayIndex = SDL_GetIndexOfDisplay(display); - SDL_GetDisplayBounds(displayIndex, &bounds); - if (SDL_WINDOWPOS_ISCENTERED(x)) { - x = bounds.x + (bounds.w - window->w) / 2; - } - if (SDL_WINDOWPOS_ISCENTERED(y)) { - y = bounds.y + (bounds.h - window->h) / 2; - } - } - - if ((window->flags & SDL_WINDOW_FULLSCREEN)) { - if (!SDL_WINDOWPOS_ISUNDEFINED(x)) { - window->windowed.x = x; - } - if (!SDL_WINDOWPOS_ISUNDEFINED(y)) { - window->windowed.y = y; - } - } else { - if (!SDL_WINDOWPOS_ISUNDEFINED(x)) { - window->x = x; - } - if (!SDL_WINDOWPOS_ISUNDEFINED(y)) { - window->y = y; - } - - if (_this->SetWindowPosition) { - _this->SetWindowPosition(_this, window); - } - SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y); - } -} - -void -SDL_GetWindowPosition(SDL_Window * window, int *x, int *y) -{ - CHECK_WINDOW_MAGIC(window, ); - - /* Fullscreen windows are always at their display's origin */ - if (window->flags & SDL_WINDOW_FULLSCREEN) { - if (x) { - *x = 0; - } - if (y) { - *y = 0; - } - } else { - if (x) { - *x = window->x; - } - if (y) { - *y = window->y; - } - } -} - -void -SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered) -{ - CHECK_WINDOW_MAGIC(window, ); - if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { - const int want = (bordered != SDL_FALSE); /* normalize the flag. */ - const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0); - if ((want != have) && (_this->SetWindowBordered)) { - if (want) { - window->flags &= ~SDL_WINDOW_BORDERLESS; - } else { - window->flags |= SDL_WINDOW_BORDERLESS; - } - _this->SetWindowBordered(_this, window, (SDL_bool) want); - } - } -} - -void -SDL_SetWindowSize(SDL_Window * window, int w, int h) -{ - CHECK_WINDOW_MAGIC(window, ); - if (w <= 0) { - SDL_InvalidParamError("w"); - return; - } - if (h <= 0) { - SDL_InvalidParamError("h"); - return; - } - - /* Make sure we don't exceed any window size limits */ - if (window->min_w && w < window->min_w) - { - w = window->min_w; - } - if (window->max_w && w > window->max_w) - { - w = window->max_w; - } - if (window->min_h && h < window->min_h) - { - h = window->min_h; - } - if (window->max_h && h > window->max_h) - { - h = window->max_h; - } - - /* FIXME: Should this change fullscreen modes? */ - if (window->flags & SDL_WINDOW_FULLSCREEN) { - window->windowed.w = w; - window->windowed.h = h; - } else { - window->w = w; - window->h = h; - if (_this->SetWindowSize) { - _this->SetWindowSize(_this, window); - } - if (window->w == w && window->h == h) { - /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */ - SDL_OnWindowResized(window); - } - } -} - -void -SDL_GetWindowSize(SDL_Window * window, int *w, int *h) -{ - CHECK_WINDOW_MAGIC(window, ); - if (w) { - *w = window->w; - } - if (h) { - *h = window->h; - } -} - -void -SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h) -{ - CHECK_WINDOW_MAGIC(window, ); - if (min_w <= 0) { - SDL_InvalidParamError("min_w"); - return; - } - if (min_h <= 0) { - SDL_InvalidParamError("min_h"); - return; - } - - if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { - window->min_w = min_w; - window->min_h = min_h; - if (_this->SetWindowMinimumSize) { - _this->SetWindowMinimumSize(_this, window); - } - /* Ensure that window is not smaller than minimal size */ - SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h)); - } -} - -void -SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h) -{ - CHECK_WINDOW_MAGIC(window, ); - if (min_w) { - *min_w = window->min_w; - } - if (min_h) { - *min_h = window->min_h; - } -} - -void -SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h) -{ - CHECK_WINDOW_MAGIC(window, ); - if (max_w <= 0) { - SDL_InvalidParamError("max_w"); - return; - } - if (max_h <= 0) { - SDL_InvalidParamError("max_h"); - return; - } - - if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { - window->max_w = max_w; - window->max_h = max_h; - if (_this->SetWindowMaximumSize) { - _this->SetWindowMaximumSize(_this, window); - } - /* Ensure that window is not larger than maximal size */ - SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h)); - } -} - -void -SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h) -{ - CHECK_WINDOW_MAGIC(window, ); - if (max_w) { - *max_w = window->max_w; - } - if (max_h) { - *max_h = window->max_h; - } -} - -void -SDL_ShowWindow(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (window->flags & SDL_WINDOW_SHOWN) { - return; - } - - if (_this->ShowWindow) { - _this->ShowWindow(_this, window); - } - SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0); -} - -void -SDL_HideWindow(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (!(window->flags & SDL_WINDOW_SHOWN)) { - return; - } - - SDL_UpdateFullscreenMode(window, SDL_FALSE); - - if (_this->HideWindow) { - _this->HideWindow(_this, window); - } - SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0); -} - -void -SDL_RaiseWindow(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (!(window->flags & SDL_WINDOW_SHOWN)) { - return; - } - if (_this->RaiseWindow) { - _this->RaiseWindow(_this, window); - } -} - -void -SDL_MaximizeWindow(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (window->flags & SDL_WINDOW_MAXIMIZED) { - return; - } - - /* !!! FIXME: should this check if the window is resizable? */ - - if (_this->MaximizeWindow) { - _this->MaximizeWindow(_this, window); - } -} - -void -SDL_MinimizeWindow(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (window->flags & SDL_WINDOW_MINIMIZED) { - return; - } - - SDL_UpdateFullscreenMode(window, SDL_FALSE); - - if (_this->MinimizeWindow) { - _this->MinimizeWindow(_this, window); - } -} - -void -SDL_RestoreWindow(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) { - return; - } - - if (_this->RestoreWindow) { - _this->RestoreWindow(_this, window); - } -} - -#define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN ) -int -SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags) -{ - CHECK_WINDOW_MAGIC(window, -1); - - flags &= FULLSCREEN_MASK; - - if ( flags == (window->flags & FULLSCREEN_MASK) ) { - return 0; - } - - /* clear the previous flags and OR in the new ones */ - window->flags &= ~FULLSCREEN_MASK; - window->flags |= flags; - - SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)); - - return 0; -} - -static SDL_Surface * -SDL_CreateWindowFramebuffer(SDL_Window * window) -{ - Uint32 format; - void *pixels; - int pitch; - int bpp; - Uint32 Rmask, Gmask, Bmask, Amask; - - if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) { - return NULL; - } - - if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) { - return NULL; - } - - if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { - return NULL; - } - - return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask); -} - -SDL_Surface * -SDL_GetWindowSurface(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, NULL); - - if (!window->surface_valid) { - if (window->surface) { - window->surface->flags &= ~SDL_DONTFREE; - SDL_FreeSurface(window->surface); - } - window->surface = SDL_CreateWindowFramebuffer(window); - if (window->surface) { - window->surface_valid = SDL_TRUE; - window->surface->flags |= SDL_DONTFREE; - } - } - return window->surface; -} - -int -SDL_UpdateWindowSurface(SDL_Window * window) -{ - SDL_Rect full_rect; - - CHECK_WINDOW_MAGIC(window, -1); - - full_rect.x = 0; - full_rect.y = 0; - full_rect.w = window->w; - full_rect.h = window->h; - return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1); -} - -int -SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects, - int numrects) -{ - CHECK_WINDOW_MAGIC(window, -1); - - if (!window->surface_valid) { - return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface"); - } - - return _this->UpdateWindowFramebuffer(_this, window, rects, numrects); -} - -int -SDL_SetWindowBrightness(SDL_Window * window, float brightness) -{ - Uint16 ramp[256]; - int status; - - CHECK_WINDOW_MAGIC(window, -1); - - SDL_CalculateGammaRamp(brightness, ramp); - status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp); - if (status == 0) { - window->brightness = brightness; - } - return status; -} - -float -SDL_GetWindowBrightness(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, 1.0f); - - return window->brightness; -} - -int -SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red, - const Uint16 * green, - const Uint16 * blue) -{ - CHECK_WINDOW_MAGIC(window, -1); - - if (!_this->SetWindowGammaRamp) { - return SDL_Unsupported(); - } - - if (!window->gamma) { - if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) { - return -1; - } - } - - if (red) { - SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16)); - } - if (green) { - SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16)); - } - if (blue) { - SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16)); - } - if (window->flags & SDL_WINDOW_INPUT_FOCUS) { - return _this->SetWindowGammaRamp(_this, window, window->gamma); - } else { - return 0; - } -} - -int -SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red, - Uint16 * green, - Uint16 * blue) -{ - CHECK_WINDOW_MAGIC(window, -1); - - if (!window->gamma) { - int i; - - window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16)); - if (!window->gamma) { - return SDL_OutOfMemory(); - } - window->saved_gamma = window->gamma + 3*256; - - if (_this->GetWindowGammaRamp) { - if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) { - return -1; - } - } else { - /* Create an identity gamma ramp */ - for (i = 0; i < 256; ++i) { - Uint16 value = (Uint16)((i << 8) | i); - - window->gamma[0*256+i] = value; - window->gamma[1*256+i] = value; - window->gamma[2*256+i] = value; - } - } - SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16)); - } - - if (red) { - SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16)); - } - if (green) { - SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16)); - } - if (blue) { - SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16)); - } - return 0; -} - -void -SDL_UpdateWindowGrab(SDL_Window * window) -{ - if (_this->SetWindowGrab) { - SDL_bool grabbed; - if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && - (window->flags & SDL_WINDOW_INPUT_FOCUS)) { - grabbed = SDL_TRUE; - } else { - grabbed = SDL_FALSE; - } - _this->SetWindowGrab(_this, window, grabbed); - } -} - -void -SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) { - return; - } - if (grabbed) { - window->flags |= SDL_WINDOW_INPUT_GRABBED; - } else { - window->flags &= ~SDL_WINDOW_INPUT_GRABBED; - } - SDL_UpdateWindowGrab(window); -} - -SDL_bool -SDL_GetWindowGrab(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, SDL_FALSE); - - return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0); -} - -void -SDL_OnWindowShown(SDL_Window * window) -{ - SDL_OnWindowRestored(window); -} - -void -SDL_OnWindowHidden(SDL_Window * window) -{ - SDL_UpdateFullscreenMode(window, SDL_FALSE); -} - -void -SDL_OnWindowResized(SDL_Window * window) -{ - window->surface_valid = SDL_FALSE; - SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h); -} - -void -SDL_OnWindowMinimized(SDL_Window * window) -{ - SDL_UpdateFullscreenMode(window, SDL_FALSE); -} - -void -SDL_OnWindowRestored(SDL_Window * window) -{ - SDL_RaiseWindow(window); - - if (FULLSCREEN_VISIBLE(window)) { - SDL_UpdateFullscreenMode(window, SDL_TRUE); - } -} - -void -SDL_OnWindowEnter(SDL_Window * window) -{ - if (_this->OnWindowEnter) { - _this->OnWindowEnter(_this, window); - } -} - -void -SDL_OnWindowLeave(SDL_Window * window) -{ -} - -void -SDL_OnWindowFocusGained(SDL_Window * window) -{ - SDL_Mouse *mouse = SDL_GetMouse(); - - if (window->gamma && _this->SetWindowGammaRamp) { - _this->SetWindowGammaRamp(_this, window, window->gamma); - } - - if (mouse && mouse->relative_mode) { - SDL_SetMouseFocus(window); - SDL_WarpMouseInWindow(window, window->w/2, window->h/2); - } - - SDL_UpdateWindowGrab(window); -} - -static SDL_bool -ShouldMinimizeOnFocusLoss(SDL_Window * window) -{ - const char *hint; - - if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { - return SDL_FALSE; - } - -#ifdef __MACOSX__ - if (Cocoa_IsWindowInFullscreenSpace(window)) { - return SDL_FALSE; - } -#endif - - hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS); - if (hint) { - if (*hint == '0') { - return SDL_FALSE; - } else { - return SDL_TRUE; - } - } - - return SDL_TRUE; -} - -void -SDL_OnWindowFocusLost(SDL_Window * window) -{ - if (window->gamma && _this->SetWindowGammaRamp) { - _this->SetWindowGammaRamp(_this, window, window->saved_gamma); - } - - SDL_UpdateWindowGrab(window); - - if (ShouldMinimizeOnFocusLoss(window)) { - SDL_MinimizeWindow(window); - } -} - -SDL_Window * -SDL_GetFocusWindow(void) -{ - SDL_Window *window; - - if (!_this) { - return NULL; - } - for (window = _this->windows; window; window = window->next) { - if (window->flags & SDL_WINDOW_INPUT_FOCUS) { - return window; - } - } - return NULL; -} - -void -SDL_DestroyWindow(SDL_Window * window) -{ - SDL_VideoDisplay *display; - - CHECK_WINDOW_MAGIC(window, ); - - /* Restore video mode, etc. */ - SDL_HideWindow(window); - - /* Make sure this window no longer has focus */ - if (SDL_GetKeyboardFocus() == window) { - SDL_SetKeyboardFocus(NULL); - } - if (SDL_GetMouseFocus() == window) { - SDL_SetMouseFocus(NULL); - } - - /* make no context current if this is the current context window. */ - if (window->flags & SDL_WINDOW_OPENGL) { - if (_this->current_glwin == window) { - SDL_GL_MakeCurrent(window, NULL); - } - } - - if (window->surface) { - window->surface->flags &= ~SDL_DONTFREE; - SDL_FreeSurface(window->surface); - } - if (_this->DestroyWindowFramebuffer) { - _this->DestroyWindowFramebuffer(_this, window); - } - if (_this->DestroyWindow) { - _this->DestroyWindow(_this, window); - } - if (window->flags & SDL_WINDOW_OPENGL) { - SDL_GL_UnloadLibrary(); - } - - display = SDL_GetDisplayForWindow(window); - if (display->fullscreen_window == window) { - display->fullscreen_window = NULL; - } - - /* Now invalidate magic */ - window->magic = NULL; - - /* Free memory associated with the window */ - SDL_free(window->title); - SDL_FreeSurface(window->icon); - SDL_free(window->gamma); - while (window->data) { - SDL_WindowUserData *data = window->data; - - window->data = data->next; - SDL_free(data->name); - SDL_free(data); - } - - /* Unlink the window from the list */ - if (window->next) { - window->next->prev = window->prev; - } - if (window->prev) { - window->prev->next = window->next; - } else { - _this->windows = window->next; - } - - SDL_free(window); -} - -SDL_bool -SDL_IsScreenSaverEnabled() -{ - if (!_this) { - return SDL_TRUE; - } - return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE; -} - -void -SDL_EnableScreenSaver() -{ - if (!_this) { - return; - } - if (!_this->suspend_screensaver) { - return; - } - _this->suspend_screensaver = SDL_FALSE; - if (_this->SuspendScreenSaver) { - _this->SuspendScreenSaver(_this); - } -} - -void -SDL_DisableScreenSaver() -{ - if (!_this) { - return; - } - if (_this->suspend_screensaver) { - return; - } - _this->suspend_screensaver = SDL_TRUE; - if (_this->SuspendScreenSaver) { - _this->SuspendScreenSaver(_this); - } -} - -void -SDL_VideoQuit(void) -{ - int i, j; - - if (!_this) { - return; - } - - /* Halt event processing before doing anything else */ - SDL_TouchQuit(); - SDL_MouseQuit(); - SDL_KeyboardQuit(); - SDL_QuitSubSystem(SDL_INIT_EVENTS); - - SDL_EnableScreenSaver(); - - /* Clean up the system video */ - while (_this->windows) { - SDL_DestroyWindow(_this->windows); - } - _this->VideoQuit(_this); - - for (i = 0; i < _this->num_displays; ++i) { - SDL_VideoDisplay *display = &_this->displays[i]; - for (j = display->num_display_modes; j--;) { - SDL_free(display->display_modes[j].driverdata); - display->display_modes[j].driverdata = NULL; - } - SDL_free(display->display_modes); - display->display_modes = NULL; - SDL_free(display->desktop_mode.driverdata); - display->desktop_mode.driverdata = NULL; - SDL_free(display->driverdata); - display->driverdata = NULL; - } - if (_this->displays) { - for (i = 0; i < _this->num_displays; ++i) { - SDL_free(_this->displays[i].name); - } - SDL_free(_this->displays); - _this->displays = NULL; - _this->num_displays = 0; - } - SDL_free(_this->clipboard_text); - _this->clipboard_text = NULL; - _this->free(_this); - _this = NULL; -} - -int -SDL_GL_LoadLibrary(const char *path) -{ - int retval; - - if (!_this) { - return SDL_UninitializedVideo(); - } - if (_this->gl_config.driver_loaded) { - if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) { - return SDL_SetError("OpenGL library already loaded"); - } - retval = 0; - } else { - if (!_this->GL_LoadLibrary) { - return SDL_SetError("No dynamic GL support in video driver"); - } - retval = _this->GL_LoadLibrary(_this, path); - } - if (retval == 0) { - ++_this->gl_config.driver_loaded; - } else { - if (_this->GL_UnloadLibrary) { - _this->GL_UnloadLibrary(_this); - } - } - return (retval); -} - -void * -SDL_GL_GetProcAddress(const char *proc) -{ - void *func; - - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - func = NULL; - if (_this->GL_GetProcAddress) { - if (_this->gl_config.driver_loaded) { - func = _this->GL_GetProcAddress(_this, proc); - } else { - SDL_SetError("No GL driver has been loaded"); - } - } else { - SDL_SetError("No dynamic GL support in video driver"); - } - return func; -} - -void -SDL_GL_UnloadLibrary(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return; - } - if (_this->gl_config.driver_loaded > 0) { - if (--_this->gl_config.driver_loaded > 0) { - return; - } - if (_this->GL_UnloadLibrary) { - _this->GL_UnloadLibrary(_this); - } - } -} - -static SDL_INLINE SDL_bool -isAtLeastGL3(const char *verstr) -{ - return ( verstr && (SDL_atoi(verstr) >= 3) ); -} - -SDL_bool -SDL_GL_ExtensionSupported(const char *extension) -{ -#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 - const GLubyte *(APIENTRY * glGetStringFunc) (GLenum); - const char *extensions; - const char *start; - const char *where, *terminator; - - /* Extension names should not have spaces. */ - where = SDL_strchr(extension, ' '); - if (where || *extension == '\0') { - return SDL_FALSE; - } - /* See if there's an environment variable override */ - start = SDL_getenv(extension); - if (start && *start == '0') { - return SDL_FALSE; - } - - /* Lookup the available extensions */ - - glGetStringFunc = SDL_GL_GetProcAddress("glGetString"); - if (!glGetStringFunc) { - return SDL_FALSE; - } - - if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) { - const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint); - void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params); - GLint num_exts = 0; - GLint i; - - glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi"); - glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv"); - if ((!glGetStringiFunc) || (!glGetIntegervFunc)) { - return SDL_FALSE; - } - - #ifndef GL_NUM_EXTENSIONS - #define GL_NUM_EXTENSIONS 0x821D - #endif - glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts); - for (i = 0; i < num_exts; i++) { - const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i); - if (SDL_strcmp(thisext, extension) == 0) { - return SDL_TRUE; - } - } - - return SDL_FALSE; - } - - /* Try the old way with glGetString(GL_EXTENSIONS) ... */ - - extensions = (const char *) glGetStringFunc(GL_EXTENSIONS); - if (!extensions) { - return SDL_FALSE; - } - /* - * It takes a bit of care to be fool-proof about parsing the OpenGL - * extensions string. Don't be fooled by sub-strings, etc. - */ - - start = extensions; - - for (;;) { - where = SDL_strstr(start, extension); - if (!where) - break; - - terminator = where + SDL_strlen(extension); - if (where == start || *(where - 1) == ' ') - if (*terminator == ' ' || *terminator == '\0') - return SDL_TRUE; - - start = terminator; - } - return SDL_FALSE; -#else - return SDL_FALSE; -#endif -} - -int -SDL_GL_SetAttribute(SDL_GLattr attr, int value) -{ -#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 - int retval; - - if (!_this) { - return SDL_UninitializedVideo(); - } - retval = 0; - switch (attr) { - case SDL_GL_RED_SIZE: - _this->gl_config.red_size = value; - break; - case SDL_GL_GREEN_SIZE: - _this->gl_config.green_size = value; - break; - case SDL_GL_BLUE_SIZE: - _this->gl_config.blue_size = value; - break; - case SDL_GL_ALPHA_SIZE: - _this->gl_config.alpha_size = value; - break; - case SDL_GL_DOUBLEBUFFER: - _this->gl_config.double_buffer = value; - break; - case SDL_GL_BUFFER_SIZE: - _this->gl_config.buffer_size = value; - break; - case SDL_GL_DEPTH_SIZE: - _this->gl_config.depth_size = value; - break; - case SDL_GL_STENCIL_SIZE: - _this->gl_config.stencil_size = value; - break; - case SDL_GL_ACCUM_RED_SIZE: - _this->gl_config.accum_red_size = value; - break; - case SDL_GL_ACCUM_GREEN_SIZE: - _this->gl_config.accum_green_size = value; - break; - case SDL_GL_ACCUM_BLUE_SIZE: - _this->gl_config.accum_blue_size = value; - break; - case SDL_GL_ACCUM_ALPHA_SIZE: - _this->gl_config.accum_alpha_size = value; - break; - case SDL_GL_STEREO: - _this->gl_config.stereo = value; - break; - case SDL_GL_MULTISAMPLEBUFFERS: - _this->gl_config.multisamplebuffers = value; - break; - case SDL_GL_MULTISAMPLESAMPLES: - _this->gl_config.multisamplesamples = value; - break; - case SDL_GL_ACCELERATED_VISUAL: - _this->gl_config.accelerated = value; - break; - case SDL_GL_RETAINED_BACKING: - _this->gl_config.retained_backing = value; - break; - case SDL_GL_CONTEXT_MAJOR_VERSION: - _this->gl_config.major_version = value; - break; - case SDL_GL_CONTEXT_MINOR_VERSION: - _this->gl_config.minor_version = value; - break; - case SDL_GL_CONTEXT_EGL: - /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */ - if (value != 0) { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - } else { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); - }; - break; - case SDL_GL_CONTEXT_FLAGS: - if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG | - SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG | - SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG | - SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) { - retval = SDL_SetError("Unknown OpenGL context flag %d", value); - break; - } - _this->gl_config.flags = value; - break; - case SDL_GL_CONTEXT_PROFILE_MASK: - if( value != 0 && - value != SDL_GL_CONTEXT_PROFILE_CORE && - value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY && - value != SDL_GL_CONTEXT_PROFILE_ES ) { - retval = SDL_SetError("Unknown OpenGL context profile %d", value); - break; - } - _this->gl_config.profile_mask = value; - break; - case SDL_GL_SHARE_WITH_CURRENT_CONTEXT: - _this->gl_config.share_with_current_context = value; - break; - case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE: - _this->gl_config.framebuffer_srgb_capable = value; - break; - default: - retval = SDL_SetError("Unknown OpenGL attribute"); - break; - } - return retval; -#else - return SDL_Unsupported(); -#endif /* SDL_VIDEO_OPENGL */ -} - -int -SDL_GL_GetAttribute(SDL_GLattr attr, int *value) -{ -#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 - void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params); - GLenum(APIENTRY * glGetErrorFunc) (void); - GLenum attrib = 0; - GLenum error = 0; - - glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv"); - if (!glGetIntegervFunc) { - return -1; - } - - glGetErrorFunc = SDL_GL_GetProcAddress("glGetError"); - if (!glGetErrorFunc) { - return -1; - } - - /* Clear value in any case */ - *value = 0; - - switch (attr) { - case SDL_GL_RED_SIZE: - attrib = GL_RED_BITS; - break; - case SDL_GL_BLUE_SIZE: - attrib = GL_BLUE_BITS; - break; - case SDL_GL_GREEN_SIZE: - attrib = GL_GREEN_BITS; - break; - case SDL_GL_ALPHA_SIZE: - attrib = GL_ALPHA_BITS; - break; - case SDL_GL_DOUBLEBUFFER: -#if SDL_VIDEO_OPENGL - attrib = GL_DOUBLEBUFFER; - break; -#else - /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER */ - /* parameter which switches double buffer to single buffer. OpenGL ES */ - /* SDL driver must set proper value after initialization */ - *value = _this->gl_config.double_buffer; - return 0; -#endif - case SDL_GL_DEPTH_SIZE: - attrib = GL_DEPTH_BITS; - break; - case SDL_GL_STENCIL_SIZE: - attrib = GL_STENCIL_BITS; - break; -#if SDL_VIDEO_OPENGL - case SDL_GL_ACCUM_RED_SIZE: - attrib = GL_ACCUM_RED_BITS; - break; - case SDL_GL_ACCUM_GREEN_SIZE: - attrib = GL_ACCUM_GREEN_BITS; - break; - case SDL_GL_ACCUM_BLUE_SIZE: - attrib = GL_ACCUM_BLUE_BITS; - break; - case SDL_GL_ACCUM_ALPHA_SIZE: - attrib = GL_ACCUM_ALPHA_BITS; - break; - case SDL_GL_STEREO: - attrib = GL_STEREO; - break; -#else - case SDL_GL_ACCUM_RED_SIZE: - case SDL_GL_ACCUM_GREEN_SIZE: - case SDL_GL_ACCUM_BLUE_SIZE: - case SDL_GL_ACCUM_ALPHA_SIZE: - case SDL_GL_STEREO: - /* none of these are supported in OpenGL ES */ - *value = 0; - return 0; -#endif - case SDL_GL_MULTISAMPLEBUFFERS: -#if SDL_VIDEO_OPENGL - attrib = GL_SAMPLE_BUFFERS_ARB; -#else - attrib = GL_SAMPLE_BUFFERS; -#endif - break; - case SDL_GL_MULTISAMPLESAMPLES: -#if SDL_VIDEO_OPENGL - attrib = GL_SAMPLES_ARB; -#else - attrib = GL_SAMPLES; -#endif - break; - case SDL_GL_BUFFER_SIZE: - { - GLint bits = 0; - GLint component; - - /* - * there doesn't seem to be a single flag in OpenGL - * for this! - */ - glGetIntegervFunc(GL_RED_BITS, &component); - bits += component; - glGetIntegervFunc(GL_GREEN_BITS, &component); - bits += component; - glGetIntegervFunc(GL_BLUE_BITS, &component); - bits += component; - glGetIntegervFunc(GL_ALPHA_BITS, &component); - bits += component; - - *value = bits; - return 0; - } - case SDL_GL_ACCELERATED_VISUAL: - { - /* FIXME: How do we get this information? */ - *value = (_this->gl_config.accelerated != 0); - return 0; - } - case SDL_GL_RETAINED_BACKING: - { - *value = _this->gl_config.retained_backing; - return 0; - } - case SDL_GL_CONTEXT_MAJOR_VERSION: - { - *value = _this->gl_config.major_version; - return 0; - } - case SDL_GL_CONTEXT_MINOR_VERSION: - { - *value = _this->gl_config.minor_version; - return 0; - } - case SDL_GL_CONTEXT_EGL: - /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */ - { - if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { - *value = 1; - } - else { - *value = 0; - } - return 0; - } - case SDL_GL_CONTEXT_FLAGS: - { - *value = _this->gl_config.flags; - return 0; - } - case SDL_GL_CONTEXT_PROFILE_MASK: - { - *value = _this->gl_config.profile_mask; - return 0; - } - case SDL_GL_SHARE_WITH_CURRENT_CONTEXT: - { - *value = _this->gl_config.share_with_current_context; - return 0; - } - case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE: - { - *value = _this->gl_config.framebuffer_srgb_capable; - return 0; - } - default: - return SDL_SetError("Unknown OpenGL attribute"); - } - - glGetIntegervFunc(attrib, (GLint *) value); - error = glGetErrorFunc(); - if (error != GL_NO_ERROR) { - if (error == GL_INVALID_ENUM) { - return SDL_SetError("OpenGL error: GL_INVALID_ENUM"); - } else if (error == GL_INVALID_VALUE) { - return SDL_SetError("OpenGL error: GL_INVALID_VALUE"); - } - return SDL_SetError("OpenGL error: %08X", error); - } - return 0; -#else - return SDL_Unsupported(); -#endif /* SDL_VIDEO_OPENGL */ -} - -SDL_GLContext -SDL_GL_CreateContext(SDL_Window * window) -{ - SDL_GLContext ctx = NULL; - CHECK_WINDOW_MAGIC(window, NULL); - - if (!(window->flags & SDL_WINDOW_OPENGL)) { - SDL_SetError("The specified window isn't an OpenGL window"); - return NULL; - } - - ctx = _this->GL_CreateContext(_this, window); - - /* Creating a context is assumed to make it current in the SDL driver. */ - if (ctx) { - _this->current_glwin = window; - _this->current_glctx = ctx; - SDL_TLSSet(_this->current_glwin_tls, window, NULL); - SDL_TLSSet(_this->current_glctx_tls, ctx, NULL); - } - return ctx; -} - -int -SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx) -{ - int retval; - - if (window == SDL_GL_GetCurrentWindow() && - ctx == SDL_GL_GetCurrentContext()) { - /* We're already current. */ - return 0; - } - - if (!ctx) { - window = NULL; - } else { - CHECK_WINDOW_MAGIC(window, -1); - - if (!(window->flags & SDL_WINDOW_OPENGL)) { - return SDL_SetError("The specified window isn't an OpenGL window"); - } - } - - retval = _this->GL_MakeCurrent(_this, window, ctx); - if (retval == 0) { - _this->current_glwin = window; - _this->current_glctx = ctx; - SDL_TLSSet(_this->current_glwin_tls, window, NULL); - SDL_TLSSet(_this->current_glctx_tls, ctx, NULL); - } - return retval; -} - -SDL_Window * -SDL_GL_GetCurrentWindow(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls); -} - -SDL_GLContext -SDL_GL_GetCurrentContext(void) -{ - if (!_this) { - SDL_UninitializedVideo(); - return NULL; - } - return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls); -} - -void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (_this->GL_GetDrawableSize) { - _this->GL_GetDrawableSize(_this, window, w, h); - } else { - SDL_GetWindowSize(window, w, h); - } -} - -int -SDL_GL_SetSwapInterval(int interval) -{ - if (!_this) { - return SDL_UninitializedVideo(); - } else if (SDL_GL_GetCurrentContext() == NULL) { - return SDL_SetError("No OpenGL context has been made current"); - } else if (_this->GL_SetSwapInterval) { - return _this->GL_SetSwapInterval(_this, interval); - } else { - return SDL_SetError("Setting the swap interval is not supported"); - } -} - -int -SDL_GL_GetSwapInterval(void) -{ - if (!_this) { - return 0; - } else if (SDL_GL_GetCurrentContext() == NULL) { - return 0; - } else if (_this->GL_GetSwapInterval) { - return _this->GL_GetSwapInterval(_this); - } else { - return 0; - } -} - -void -SDL_GL_SwapWindow(SDL_Window * window) -{ - CHECK_WINDOW_MAGIC(window, ); - - if (!(window->flags & SDL_WINDOW_OPENGL)) { - SDL_SetError("The specified window isn't an OpenGL window"); - return; - } - - if (SDL_GL_GetCurrentWindow() != window) { - SDL_SetError("The specified window has not been made current"); - return; - } - - _this->GL_SwapWindow(_this, window); -} - -void -SDL_GL_DeleteContext(SDL_GLContext context) -{ - if (!_this || !context) { - return; - } - - if (SDL_GL_GetCurrentContext() == context) { - SDL_GL_MakeCurrent(NULL, NULL); - } - - _this->GL_DeleteContext(_this, context); -} - -#if 0 /* FIXME */ -/* - * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags - * & 2 for alpha channel. - */ -static void -CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags) -{ - int x, y; - Uint32 colorkey; -#define SET_MASKBIT(icon, x, y, mask) \ - mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8))) - - colorkey = icon->format->colorkey; - switch (icon->format->BytesPerPixel) { - case 1: - { - Uint8 *pixels; - for (y = 0; y < icon->h; ++y) { - pixels = (Uint8 *) icon->pixels + y * icon->pitch; - for (x = 0; x < icon->w; ++x) { - if (*pixels++ == colorkey) { - SET_MASKBIT(icon, x, y, mask); - } - } - } - } - break; - - case 2: - { - Uint16 *pixels; - for (y = 0; y < icon->h; ++y) { - pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2; - for (x = 0; x < icon->w; ++x) { - if ((flags & 1) && *pixels == colorkey) { - SET_MASKBIT(icon, x, y, mask); - } else if ((flags & 2) - && (*pixels & icon->format->Amask) == 0) { - SET_MASKBIT(icon, x, y, mask); - } - pixels++; - } - } - } - break; - - case 4: - { - Uint32 *pixels; - for (y = 0; y < icon->h; ++y) { - pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4; - for (x = 0; x < icon->w; ++x) { - if ((flags & 1) && *pixels == colorkey) { - SET_MASKBIT(icon, x, y, mask); - } else if ((flags & 2) - && (*pixels & icon->format->Amask) == 0) { - SET_MASKBIT(icon, x, y, mask); - } - pixels++; - } - } - } - break; - } -} - -/* - * Sets the window manager icon for the display window. - */ -void -SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask) -{ - if (icon && _this->SetIcon) { - /* Generate a mask if necessary, and create the icon! */ - if (mask == NULL) { - int mask_len = icon->h * (icon->w + 7) / 8; - int flags = 0; - mask = (Uint8 *) SDL_malloc(mask_len); - if (mask == NULL) { - return; - } - SDL_memset(mask, ~0, mask_len); - if (icon->flags & SDL_SRCCOLORKEY) - flags |= 1; - if (icon->flags & SDL_SRCALPHA) - flags |= 2; - if (flags) { - CreateMaskFromColorKeyOrAlpha(icon, mask, flags); - } - _this->SetIcon(_this, icon, mask); - SDL_free(mask); - } else { - _this->SetIcon(_this, icon, mask); - } - } -} -#endif - -SDL_bool -SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info) -{ - CHECK_WINDOW_MAGIC(window, SDL_FALSE); - - if (!info) { - return SDL_FALSE; - } - info->subsystem = SDL_SYSWM_UNKNOWN; - - if (!_this->GetWindowWMInfo) { - return SDL_FALSE; - } - return (_this->GetWindowWMInfo(_this, window, info)); -} - -void -SDL_StartTextInput(void) -{ - SDL_Window *window; - - /* First, enable text events */ - SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE); - SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE); - - /* Then show the on-screen keyboard, if any */ - window = SDL_GetFocusWindow(); - if (window && _this && _this->ShowScreenKeyboard) { - _this->ShowScreenKeyboard(_this, window); - } - - /* Finally start the text input system */ - if (_this && _this->StartTextInput) { - _this->StartTextInput(_this); - } -} - -SDL_bool -SDL_IsTextInputActive(void) -{ - return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE); -} - -void -SDL_StopTextInput(void) -{ - SDL_Window *window; - - /* Stop the text input system */ - if (_this && _this->StopTextInput) { - _this->StopTextInput(_this); - } - - /* Hide the on-screen keyboard, if any */ - window = SDL_GetFocusWindow(); - if (window && _this && _this->HideScreenKeyboard) { - _this->HideScreenKeyboard(_this, window); - } - - /* Finally disable text events */ - SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE); - SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE); -} - -void -SDL_SetTextInputRect(SDL_Rect *rect) -{ - if (_this && _this->SetTextInputRect) { - _this->SetTextInputRect(_this, rect); - } -} - -SDL_bool -SDL_HasScreenKeyboardSupport(void) -{ - if (_this && _this->HasScreenKeyboardSupport) { - return _this->HasScreenKeyboardSupport(_this); - } - return SDL_FALSE; -} - -SDL_bool -SDL_IsScreenKeyboardShown(SDL_Window *window) -{ - if (window && _this && _this->IsScreenKeyboardShown) { - return _this->IsScreenKeyboardShown(_this, window); - } - return SDL_FALSE; -} - -#if SDL_VIDEO_DRIVER_WINDOWS -#include "windows/SDL_windowsmessagebox.h" -#endif -#if SDL_VIDEO_DRIVER_COCOA -#include "cocoa/SDL_cocoamessagebox.h" -#endif -#if SDL_VIDEO_DRIVER_UIKIT -#include "uikit/SDL_uikitmessagebox.h" -#endif -#if SDL_VIDEO_DRIVER_X11 -#include "x11/SDL_x11messagebox.h" -#endif - -static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype) -{ - SDL_SysWMinfo info; - SDL_Window *window = messageboxdata->window; - - if (!window) { - return SDL_TRUE; - } - - SDL_VERSION(&info.version); - if (!SDL_GetWindowWMInfo(window, &info)) { - return SDL_TRUE; - } else { - return (info.subsystem == drivertype); - } -} - -int -SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) -{ - int dummybutton; - int retval = -1; - SDL_bool relative_mode; - int show_cursor_prev; - - if (!messageboxdata) { - return SDL_InvalidParamError("messageboxdata"); - } - - relative_mode = SDL_GetRelativeMouseMode(); - SDL_SetRelativeMouseMode(SDL_FALSE); - show_cursor_prev = SDL_ShowCursor(1); - - if (!buttonid) { - buttonid = &dummybutton; - } - - if (_this && _this->ShowMessageBox) { - retval = _this->ShowMessageBox(_this, messageboxdata, buttonid); - } - - /* It's completely fine to call this function before video is initialized */ -#if SDL_VIDEO_DRIVER_WINDOWS - if (retval == -1 && - SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) && - WIN_ShowMessageBox(messageboxdata, buttonid) == 0) { - retval = 0; - } -#endif -#if SDL_VIDEO_DRIVER_COCOA - if (retval == -1 && - SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) && - Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) { - retval = 0; - } -#endif -#if SDL_VIDEO_DRIVER_UIKIT - if (retval == -1 && - SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) && - UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) { - retval = 0; - } -#endif -#if SDL_VIDEO_DRIVER_X11 - if (retval == -1 && - SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) && - X11_ShowMessageBox(messageboxdata, buttonid) == 0) { - retval = 0; - } -#endif - if (retval == -1) { - SDL_SetError("No message system available"); - } - - SDL_ShowCursor(show_cursor_prev); - SDL_SetRelativeMouseMode(relative_mode); - - return retval; -} - -int -SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window) -{ - SDL_MessageBoxData data; - SDL_MessageBoxButtonData button; - - SDL_zero(data); - data.flags = flags; - data.title = title; - data.message = message; - data.numbuttons = 1; - data.buttons = &button; - data.window = window; - - SDL_zero(button); - button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; - button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT; - button.text = "OK"; - - return SDL_ShowMessageBox(&data, NULL); -} - -SDL_bool -SDL_ShouldAllowTopmost(void) -{ - const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST); - if (hint) { - if (*hint == '0') { - return SDL_FALSE; - } else { - return SDL_TRUE; - } - } - return SDL_TRUE; -} - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +/* The high-level video driver subsystem */ + +#include "SDL.h" +#include "SDL_video.h" +#include "SDL_sysvideo.h" +#include "SDL_blit.h" +#include "SDL_pixels_c.h" +#include "SDL_rect_c.h" +#include "../events/SDL_events_c.h" +#include "../timer/SDL_timer_c.h" + +#if SDL_VIDEO_OPENGL +#include "SDL_opengl.h" +#endif /* SDL_VIDEO_OPENGL */ + +#if SDL_VIDEO_OPENGL_ES +#include "SDL_opengles.h" +#endif /* SDL_VIDEO_OPENGL_ES */ + +/* GL and GLES2 headers conflict on Linux 32 bits */ +#if SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL +#include "SDL_opengles2.h" +#endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */ + +#include "SDL_syswm.h" + +/* On Windows, windows.h defines CreateWindow */ +#ifdef CreateWindow +#undef CreateWindow +#endif + +/* Available video drivers */ +static VideoBootStrap *bootstrap[] = { +#if SDL_VIDEO_DRIVER_COCOA + &COCOA_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_X11 + &X11_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_DIRECTFB + &DirectFB_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_WINDOWS + &WINDOWS_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_WINRT + &WINRT_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_HAIKU + &HAIKU_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_PANDORA + &PND_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_UIKIT + &UIKIT_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_ANDROID + &Android_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_PSP + &PSP_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_RPI + &RPI_bootstrap, +#endif +#if SDL_VIDEO_DRIVER_DUMMY + &DUMMY_bootstrap, +#endif + NULL +}; + +static SDL_VideoDevice *_this = NULL; + +#define CHECK_WINDOW_MAGIC(window, retval) \ + if (!_this) { \ + SDL_UninitializedVideo(); \ + return retval; \ + } \ + if (!window || window->magic != &_this->window_magic) { \ + SDL_SetError("Invalid window"); \ + return retval; \ + } + +#define CHECK_DISPLAY_INDEX(displayIndex, retval) \ + if (!_this) { \ + SDL_UninitializedVideo(); \ + return retval; \ + } \ + if (displayIndex < 0 || displayIndex >= _this->num_displays) { \ + SDL_SetError("displayIndex must be in the range 0 - %d", \ + _this->num_displays - 1); \ + return retval; \ + } + + +#ifdef __MACOSX__ +/* Support for Mac OS X fullscreen spaces */ +extern SDL_bool Cocoa_IsWindowInFullscreenSpace(SDL_Window * window); +extern SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state); +#endif + + +/* Support for framebuffer emulation using an accelerated renderer */ + +#define SDL_WINDOWTEXTUREDATA "_SDL_WindowTextureData" + +typedef struct { + SDL_Renderer *renderer; + SDL_Texture *texture; + void *pixels; + int pitch; + int bytes_per_pixel; +} SDL_WindowTextureData; + +static SDL_bool +ShouldUseTextureFramebuffer() +{ + const char *hint; + + /* If there's no native framebuffer support then there's no option */ + if (!_this->CreateWindowFramebuffer) { + return SDL_TRUE; + } + + /* If the user has specified a software renderer we can't use a + texture framebuffer, or renderer creation will go recursive. + */ + hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER); + if (hint && SDL_strcasecmp(hint, "software") == 0) { + return SDL_FALSE; + } + + /* See if the user or application wants a specific behavior */ + hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); + if (hint) { + if (*hint == '0') { + return SDL_FALSE; + } else { + return SDL_TRUE; + } + } + + /* Each platform has different performance characteristics */ +#if defined(__WIN32__) + /* GDI BitBlt() is way faster than Direct3D dynamic textures right now. + */ + return SDL_FALSE; + +#elif defined(__MACOSX__) + /* Mac OS X uses OpenGL as the native fast path */ + return SDL_TRUE; + +#elif defined(__LINUX__) + /* Properly configured OpenGL drivers are faster than MIT-SHM */ +#if SDL_VIDEO_OPENGL + /* Ugh, find a way to cache this value! */ + { + SDL_Window *window; + SDL_GLContext context; + SDL_bool hasAcceleratedOpenGL = SDL_FALSE; + + window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN); + if (window) { + context = SDL_GL_CreateContext(window); + if (context) { + const GLubyte *(APIENTRY * glGetStringFunc) (GLenum); + const char *vendor = NULL; + + glGetStringFunc = SDL_GL_GetProcAddress("glGetString"); + if (glGetStringFunc) { + vendor = (const char *) glGetStringFunc(GL_VENDOR); + } + /* Add more vendors here at will... */ + if (vendor && + (SDL_strstr(vendor, "ATI Technologies") || + SDL_strstr(vendor, "NVIDIA"))) { + hasAcceleratedOpenGL = SDL_TRUE; + } + SDL_GL_DeleteContext(context); + } + SDL_DestroyWindow(window); + } + return hasAcceleratedOpenGL; + } +#elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 + /* Let's be optimistic about this! */ + return SDL_TRUE; +#else + return SDL_FALSE; +#endif + +#else + /* Play it safe, assume that if there is a framebuffer driver that it's + optimized for the current platform. + */ + return SDL_FALSE; +#endif +} + +static int +SDL_CreateWindowTexture(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) +{ + SDL_WindowTextureData *data; + SDL_RendererInfo info; + Uint32 i; + + data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); + if (!data) { + SDL_Renderer *renderer = NULL; + SDL_RendererInfo info; + int i; + const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); + + /* Check to see if there's a specific driver requested */ + if (hint && *hint != '0' && *hint != '1' && + SDL_strcasecmp(hint, "software") != 0) { + for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { + SDL_GetRenderDriverInfo(i, &info); + if (SDL_strcasecmp(info.name, hint) == 0) { + renderer = SDL_CreateRenderer(window, i, 0); + break; + } + } + } + + if (!renderer) { + for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { + SDL_GetRenderDriverInfo(i, &info); + if (SDL_strcmp(info.name, "software") != 0) { + renderer = SDL_CreateRenderer(window, i, 0); + if (renderer) { + break; + } + } + } + } + if (!renderer) { + return SDL_SetError("No hardware accelerated renderers available"); + } + + /* Create the data after we successfully create the renderer (bug #1116) */ + data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data)); + if (!data) { + SDL_DestroyRenderer(renderer); + return SDL_OutOfMemory(); + } + SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data); + + data->renderer = renderer; + } + + /* Free any old texture and pixel data */ + if (data->texture) { + SDL_DestroyTexture(data->texture); + data->texture = NULL; + } + SDL_free(data->pixels); + data->pixels = NULL; + + if (SDL_GetRendererInfo(data->renderer, &info) < 0) { + return -1; + } + + /* Find the first format without an alpha channel */ + *format = info.texture_formats[0]; + for (i = 0; i < info.num_texture_formats; ++i) { + if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) && + !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) { + *format = info.texture_formats[i]; + break; + } + } + + data->texture = SDL_CreateTexture(data->renderer, *format, + SDL_TEXTUREACCESS_STREAMING, + window->w, window->h); + if (!data->texture) { + return -1; + } + + /* Create framebuffer data */ + data->bytes_per_pixel = SDL_BYTESPERPIXEL(*format); + data->pitch = (((window->w * data->bytes_per_pixel) + 3) & ~3); + data->pixels = SDL_malloc(window->h * data->pitch); + if (!data->pixels) { + return SDL_OutOfMemory(); + } + + *pixels = data->pixels; + *pitch = data->pitch; + + /* Make sure we're not double-scaling the viewport */ + SDL_RenderSetViewport(data->renderer, NULL); + + return 0; +} + +static int +SDL_UpdateWindowTexture(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects) +{ + SDL_WindowTextureData *data; + SDL_Rect rect; + void *src; + + data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); + if (!data || !data->texture) { + return SDL_SetError("No window texture data"); + } + + /* Update a single rect that contains subrects for best DMA performance */ + if (SDL_GetSpanEnclosingRect(window->w, window->h, numrects, rects, &rect)) { + src = (void *)((Uint8 *)data->pixels + + rect.y * data->pitch + + rect.x * data->bytes_per_pixel); + if (SDL_UpdateTexture(data->texture, &rect, src, data->pitch) < 0) { + return -1; + } + + if (SDL_RenderCopy(data->renderer, data->texture, NULL, NULL) < 0) { + return -1; + } + + SDL_RenderPresent(data->renderer); + } + return 0; +} + +static void +SDL_DestroyWindowTexture(_THIS, SDL_Window * window) +{ + SDL_WindowTextureData *data; + + data = SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, NULL); + if (!data) { + return; + } + if (data->texture) { + SDL_DestroyTexture(data->texture); + } + if (data->renderer) { + SDL_DestroyRenderer(data->renderer); + } + SDL_free(data->pixels); + SDL_free(data); +} + + +static int +cmpmodes(const void *A, const void *B) +{ + const SDL_DisplayMode *a = (const SDL_DisplayMode *) A; + const SDL_DisplayMode *b = (const SDL_DisplayMode *) B; + if (a == b) { + return 0; + } else if (a->w != b->w) { + return b->w - a->w; + } else if (a->h != b->h) { + return b->h - a->h; + } else if (SDL_BITSPERPIXEL(a->format) != SDL_BITSPERPIXEL(b->format)) { + return SDL_BITSPERPIXEL(b->format) - SDL_BITSPERPIXEL(a->format); + } else if (SDL_PIXELLAYOUT(a->format) != SDL_PIXELLAYOUT(b->format)) { + return SDL_PIXELLAYOUT(b->format) - SDL_PIXELLAYOUT(a->format); + } else if (a->refresh_rate != b->refresh_rate) { + return b->refresh_rate - a->refresh_rate; + } + return 0; +} + +static int +SDL_UninitializedVideo() +{ + return SDL_SetError("Video subsystem has not been initialized"); +} + +int +SDL_GetNumVideoDrivers(void) +{ + return SDL_arraysize(bootstrap) - 1; +} + +const char * +SDL_GetVideoDriver(int index) +{ + if (index >= 0 && index < SDL_GetNumVideoDrivers()) { + return bootstrap[index]->name; + } + return NULL; +} + +/* + * Initialize the video and event subsystems -- determine native pixel format + */ +int +SDL_VideoInit(const char *driver_name) +{ + SDL_VideoDevice *video; + int index; + int i; + + /* Check to make sure we don't overwrite '_this' */ + if (_this != NULL) { + SDL_VideoQuit(); + } + +#if !SDL_TIMERS_DISABLED + SDL_InitTicks(); +#endif + + /* Start the event loop */ + if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0 || + SDL_KeyboardInit() < 0 || + SDL_MouseInit() < 0 || + SDL_TouchInit() < 0) { + return -1; + } + + /* Select the proper video driver */ + index = 0; + video = NULL; + if (driver_name == NULL) { + driver_name = SDL_getenv("SDL_VIDEODRIVER"); + } + if (driver_name != NULL) { + for (i = 0; bootstrap[i]; ++i) { + if (SDL_strncasecmp(bootstrap[i]->name, driver_name, SDL_strlen(driver_name)) == 0) { + video = bootstrap[i]->create(index); + break; + } + } + } else { + for (i = 0; bootstrap[i]; ++i) { + if (bootstrap[i]->available()) { + video = bootstrap[i]->create(index); + if (video != NULL) { + break; + } + } + } + } + if (video == NULL) { + if (driver_name) { + return SDL_SetError("%s not available", driver_name); + } + return SDL_SetError("No available video device"); + } + _this = video; + _this->name = bootstrap[i]->name; + _this->next_object_id = 1; + + + /* Set some very sane GL defaults */ + _this->gl_config.driver_loaded = 0; + _this->gl_config.dll_handle = NULL; + _this->gl_config.red_size = 3; + _this->gl_config.green_size = 3; + _this->gl_config.blue_size = 2; + _this->gl_config.alpha_size = 0; + _this->gl_config.buffer_size = 0; + _this->gl_config.depth_size = 16; + _this->gl_config.stencil_size = 0; + _this->gl_config.double_buffer = 1; + _this->gl_config.accum_red_size = 0; + _this->gl_config.accum_green_size = 0; + _this->gl_config.accum_blue_size = 0; + _this->gl_config.accum_alpha_size = 0; + _this->gl_config.stereo = 0; + _this->gl_config.multisamplebuffers = 0; + _this->gl_config.multisamplesamples = 0; + _this->gl_config.retained_backing = 1; + _this->gl_config.accelerated = -1; /* accelerated or not, both are fine */ + _this->gl_config.profile_mask = 0; +#if SDL_VIDEO_OPENGL + _this->gl_config.major_version = 2; + _this->gl_config.minor_version = 1; +#elif SDL_VIDEO_OPENGL_ES2 + _this->gl_config.major_version = 2; + _this->gl_config.minor_version = 0; + _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; +#elif SDL_VIDEO_OPENGL_ES + _this->gl_config.major_version = 1; + _this->gl_config.minor_version = 1; + _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; +#endif + _this->gl_config.flags = 0; + + _this->gl_config.share_with_current_context = 0; + + _this->current_glwin_tls = SDL_TLSCreate(); + _this->current_glctx_tls = SDL_TLSCreate(); + + /* Initialize the video subsystem */ + if (_this->VideoInit(_this) < 0) { + SDL_VideoQuit(); + return -1; + } + + /* Make sure some displays were added */ + if (_this->num_displays == 0) { + SDL_VideoQuit(); + return SDL_SetError("The video driver did not add any displays"); + } + + /* Add the renderer framebuffer emulation if desired */ + if (ShouldUseTextureFramebuffer()) { + _this->CreateWindowFramebuffer = SDL_CreateWindowTexture; + _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture; + _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture; + } + + /* If we don't use a screen keyboard, turn on text input by default, + otherwise programs that expect to get text events without enabling + UNICODE input won't get any events. + + Actually, come to think of it, you needed to call SDL_EnableUNICODE(1) + in SDL 1.2 before you got text input events. Hmm... + */ + if (!SDL_HasScreenKeyboardSupport()) { + SDL_StartTextInput(); + } + + /* We're ready to go! */ + return 0; +} + +const char * +SDL_GetCurrentVideoDriver() +{ + if (!_this) { + SDL_UninitializedVideo(); + return NULL; + } + return _this->name; +} + +SDL_VideoDevice * +SDL_GetVideoDevice(void) +{ + return _this; +} + +int +SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode) +{ + SDL_VideoDisplay display; + + SDL_zero(display); + if (desktop_mode) { + display.desktop_mode = *desktop_mode; + } + display.current_mode = display.desktop_mode; + + return SDL_AddVideoDisplay(&display); +} + +int +SDL_AddVideoDisplay(const SDL_VideoDisplay * display) +{ + SDL_VideoDisplay *displays; + int index = -1; + + displays = + SDL_realloc(_this->displays, + (_this->num_displays + 1) * sizeof(*displays)); + if (displays) { + index = _this->num_displays++; + displays[index] = *display; + displays[index].device = _this; + _this->displays = displays; + + if (display->name) { + displays[index].name = SDL_strdup(display->name); + } else { + char name[32]; + + SDL_itoa(index, name, 10); + displays[index].name = SDL_strdup(name); + } + } else { + SDL_OutOfMemory(); + } + return index; +} + +int +SDL_GetNumVideoDisplays(void) +{ + if (!_this) { + SDL_UninitializedVideo(); + return 0; + } + return _this->num_displays; +} + +static int +SDL_GetIndexOfDisplay(SDL_VideoDisplay *display) +{ + int displayIndex; + + for (displayIndex = 0; displayIndex < _this->num_displays; ++displayIndex) { + if (display == &_this->displays[displayIndex]) { + return displayIndex; + } + } + + /* Couldn't find the display, just use index 0 */ + return 0; +} + +void * +SDL_GetDisplayDriverData( int displayIndex ) +{ + CHECK_DISPLAY_INDEX( displayIndex, NULL ); + + return _this->displays[displayIndex].driverdata; +} + +const char * +SDL_GetDisplayName(int displayIndex) +{ + CHECK_DISPLAY_INDEX(displayIndex, NULL); + + return _this->displays[displayIndex].name; +} + +int +SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect) +{ + CHECK_DISPLAY_INDEX(displayIndex, -1); + + if (rect) { + SDL_VideoDisplay *display = &_this->displays[displayIndex]; + + if (_this->GetDisplayBounds) { + if (_this->GetDisplayBounds(_this, display, rect) == 0) { + return 0; + } + } + + /* Assume that the displays are left to right */ + if (displayIndex == 0) { + rect->x = 0; + rect->y = 0; + } else { + SDL_GetDisplayBounds(displayIndex-1, rect); + rect->x += rect->w; + } + rect->w = display->current_mode.w; + rect->h = display->current_mode.h; + } + return 0; +} + +SDL_bool +SDL_AddDisplayMode(SDL_VideoDisplay * display, const SDL_DisplayMode * mode) +{ + SDL_DisplayMode *modes; + int i, nmodes; + + /* Make sure we don't already have the mode in the list */ + modes = display->display_modes; + nmodes = display->num_display_modes; + for (i = 0; i < nmodes; ++i) { + if (cmpmodes(mode, &modes[i]) == 0) { + return SDL_FALSE; + } + } + + /* Go ahead and add the new mode */ + if (nmodes == display->max_display_modes) { + modes = + SDL_realloc(modes, + (display->max_display_modes + 32) * sizeof(*modes)); + if (!modes) { + return SDL_FALSE; + } + display->display_modes = modes; + display->max_display_modes += 32; + } + modes[nmodes] = *mode; + display->num_display_modes++; + + /* Re-sort video modes */ + SDL_qsort(display->display_modes, display->num_display_modes, + sizeof(SDL_DisplayMode), cmpmodes); + + return SDL_TRUE; +} + +static int +SDL_GetNumDisplayModesForDisplay(SDL_VideoDisplay * display) +{ + if (!display->num_display_modes && _this->GetDisplayModes) { + _this->GetDisplayModes(_this, display); + SDL_qsort(display->display_modes, display->num_display_modes, + sizeof(SDL_DisplayMode), cmpmodes); + } + return display->num_display_modes; +} + +int +SDL_GetNumDisplayModes(int displayIndex) +{ + CHECK_DISPLAY_INDEX(displayIndex, -1); + + return SDL_GetNumDisplayModesForDisplay(&_this->displays[displayIndex]); +} + +int +SDL_GetDisplayMode(int displayIndex, int index, SDL_DisplayMode * mode) +{ + SDL_VideoDisplay *display; + + CHECK_DISPLAY_INDEX(displayIndex, -1); + + display = &_this->displays[displayIndex]; + if (index < 0 || index >= SDL_GetNumDisplayModesForDisplay(display)) { + return SDL_SetError("index must be in the range of 0 - %d", + SDL_GetNumDisplayModesForDisplay(display) - 1); + } + if (mode) { + *mode = display->display_modes[index]; + } + return 0; +} + +int +SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode) +{ + SDL_VideoDisplay *display; + + CHECK_DISPLAY_INDEX(displayIndex, -1); + + display = &_this->displays[displayIndex]; + if (mode) { + *mode = display->desktop_mode; + } + return 0; +} + +int +SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode) +{ + SDL_VideoDisplay *display; + + CHECK_DISPLAY_INDEX(displayIndex, -1); + + display = &_this->displays[displayIndex]; + if (mode) { + *mode = display->current_mode; + } + return 0; +} + +static SDL_DisplayMode * +SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display, + const SDL_DisplayMode * mode, + SDL_DisplayMode * closest) +{ + Uint32 target_format; + int target_refresh_rate; + int i; + SDL_DisplayMode *current, *match; + + if (!mode || !closest) { + SDL_SetError("Missing desired mode or closest mode parameter"); + return NULL; + } + + /* Default to the desktop format */ + if (mode->format) { + target_format = mode->format; + } else { + target_format = display->desktop_mode.format; + } + + /* Default to the desktop refresh rate */ + if (mode->refresh_rate) { + target_refresh_rate = mode->refresh_rate; + } else { + target_refresh_rate = display->desktop_mode.refresh_rate; + } + + match = NULL; + for (i = 0; i < SDL_GetNumDisplayModesForDisplay(display); ++i) { + current = &display->display_modes[i]; + + if (current->w && (current->w < mode->w)) { + /* Out of sorted modes large enough here */ + break; + } + if (current->h && (current->h < mode->h)) { + if (current->w && (current->w == mode->w)) { + /* Out of sorted modes large enough here */ + break; + } + /* Wider, but not tall enough, due to a different + aspect ratio. This mode must be skipped, but closer + modes may still follow. */ + continue; + } + if (!match || current->w < match->w || current->h < match->h) { + match = current; + continue; + } + if (current->format != match->format) { + /* Sorted highest depth to lowest */ + if (current->format == target_format || + (SDL_BITSPERPIXEL(current->format) >= + SDL_BITSPERPIXEL(target_format) + && SDL_PIXELTYPE(current->format) == + SDL_PIXELTYPE(target_format))) { + match = current; + } + continue; + } + if (current->refresh_rate != match->refresh_rate) { + /* Sorted highest refresh to lowest */ + if (current->refresh_rate >= target_refresh_rate) { + match = current; + } + } + } + if (match) { + if (match->format) { + closest->format = match->format; + } else { + closest->format = mode->format; + } + if (match->w && match->h) { + closest->w = match->w; + closest->h = match->h; + } else { + closest->w = mode->w; + closest->h = mode->h; + } + if (match->refresh_rate) { + closest->refresh_rate = match->refresh_rate; + } else { + closest->refresh_rate = mode->refresh_rate; + } + closest->driverdata = match->driverdata; + + /* + * Pick some reasonable defaults if the app and driver don't + * care + */ + if (!closest->format) { + closest->format = SDL_PIXELFORMAT_RGB888; + } + if (!closest->w) { + closest->w = 640; + } + if (!closest->h) { + closest->h = 480; + } + return closest; + } + return NULL; +} + +SDL_DisplayMode * +SDL_GetClosestDisplayMode(int displayIndex, + const SDL_DisplayMode * mode, + SDL_DisplayMode * closest) +{ + SDL_VideoDisplay *display; + + CHECK_DISPLAY_INDEX(displayIndex, NULL); + + display = &_this->displays[displayIndex]; + return SDL_GetClosestDisplayModeForDisplay(display, mode, closest); +} + +static int +SDL_SetDisplayModeForDisplay(SDL_VideoDisplay * display, const SDL_DisplayMode * mode) +{ + SDL_DisplayMode display_mode; + SDL_DisplayMode current_mode; + + if (mode) { + display_mode = *mode; + + /* Default to the current mode */ + if (!display_mode.format) { + display_mode.format = display->current_mode.format; + } + if (!display_mode.w) { + display_mode.w = display->current_mode.w; + } + if (!display_mode.h) { + display_mode.h = display->current_mode.h; + } + if (!display_mode.refresh_rate) { + display_mode.refresh_rate = display->current_mode.refresh_rate; + } + + /* Get a good video mode, the closest one possible */ + if (!SDL_GetClosestDisplayModeForDisplay(display, &display_mode, &display_mode)) { + return SDL_SetError("No video mode large enough for %dx%d", + display_mode.w, display_mode.h); + } + } else { + display_mode = display->desktop_mode; + } + + /* See if there's anything left to do */ + current_mode = display->current_mode; + if (SDL_memcmp(&display_mode, ¤t_mode, sizeof(display_mode)) == 0) { + return 0; + } + + /* Actually change the display mode */ + if (!_this->SetDisplayMode) { + return SDL_SetError("Video driver doesn't support changing display mode"); + } + if (_this->SetDisplayMode(_this, display, &display_mode) < 0) { + return -1; + } + display->current_mode = display_mode; + return 0; +} + +int +SDL_GetWindowDisplayIndex(SDL_Window * window) +{ + int displayIndex; + int i, dist; + int closest = -1; + int closest_dist = 0x7FFFFFFF; + SDL_Point center; + SDL_Point delta; + SDL_Rect rect; + + CHECK_WINDOW_MAGIC(window, -1); + + if (SDL_WINDOWPOS_ISUNDEFINED(window->x) || + SDL_WINDOWPOS_ISCENTERED(window->x)) { + displayIndex = (window->x & 0xFFFF); + if (displayIndex >= _this->num_displays) { + displayIndex = 0; + } + return displayIndex; + } + if (SDL_WINDOWPOS_ISUNDEFINED(window->y) || + SDL_WINDOWPOS_ISCENTERED(window->y)) { + displayIndex = (window->y & 0xFFFF); + if (displayIndex >= _this->num_displays) { + displayIndex = 0; + } + return displayIndex; + } + + /* Find the display containing the window */ + for (i = 0; i < _this->num_displays; ++i) { + SDL_VideoDisplay *display = &_this->displays[i]; + + if (display->fullscreen_window == window) { + return i; + } + } + center.x = window->x + window->w / 2; + center.y = window->y + window->h / 2; + for (i = 0; i < _this->num_displays; ++i) { + SDL_GetDisplayBounds(i, &rect); + if (SDL_EnclosePoints(¢er, 1, &rect, NULL)) { + return i; + } + + delta.x = center.x - (rect.x + rect.w / 2); + delta.y = center.y - (rect.y + rect.h / 2); + dist = (delta.x*delta.x + delta.y*delta.y); + if (dist < closest_dist) { + closest = i; + closest_dist = dist; + } + } + if (closest < 0) { + SDL_SetError("Couldn't find any displays"); + } + return closest; +} + +SDL_VideoDisplay * +SDL_GetDisplayForWindow(SDL_Window *window) +{ + int displayIndex = SDL_GetWindowDisplayIndex(window); + if (displayIndex >= 0) { + return &_this->displays[displayIndex]; + } else { + return NULL; + } +} + +int +SDL_SetWindowDisplayMode(SDL_Window * window, const SDL_DisplayMode * mode) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (mode) { + window->fullscreen_mode = *mode; + } else { + SDL_zero(window->fullscreen_mode); + } + return 0; +} + +int +SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode) +{ + SDL_DisplayMode fullscreen_mode; + SDL_VideoDisplay *display; + + if (!mode) { + return SDL_InvalidParamError("mode"); + } + + CHECK_WINDOW_MAGIC(window, -1); + + fullscreen_mode = window->fullscreen_mode; + if (!fullscreen_mode.w) { + fullscreen_mode.w = window->w; + } + if (!fullscreen_mode.h) { + fullscreen_mode.h = window->h; + } + + display = SDL_GetDisplayForWindow(window); + + /* if in desktop size mode, just return the size of the desktop */ + if ( ( window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP ) == SDL_WINDOW_FULLSCREEN_DESKTOP ) + { + fullscreen_mode = display->desktop_mode; + } + else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window), + &fullscreen_mode, + &fullscreen_mode)) { + return SDL_SetError("Couldn't find display mode match"); + } + + if (mode) { + *mode = fullscreen_mode; + } + return 0; +} + +Uint32 +SDL_GetWindowPixelFormat(SDL_Window * window) +{ + SDL_VideoDisplay *display; + + CHECK_WINDOW_MAGIC(window, SDL_PIXELFORMAT_UNKNOWN); + + display = SDL_GetDisplayForWindow(window); + return display->current_mode.format; +} + +static void +SDL_RestoreMousePosition(SDL_Window *window) +{ + int x, y; + + if (window == SDL_GetMouseFocus()) { + SDL_GetMouseState(&x, &y); + SDL_WarpMouseInWindow(window, x, y); + } +} + +static void +SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) +{ + SDL_VideoDisplay *display; + SDL_Window *other; + +#ifdef __MACOSX__ + if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) { + return; + } +#endif + + display = SDL_GetDisplayForWindow(window); + + if (fullscreen) { + /* Hide any other fullscreen windows */ + if (display->fullscreen_window && + display->fullscreen_window != window) { + SDL_MinimizeWindow(display->fullscreen_window); + } + } + + /* See if anything needs to be done now */ + if ((display->fullscreen_window == window) == fullscreen) { + return; + } + + /* See if there are any fullscreen windows */ + for (other = _this->windows; other; other = other->next) { + SDL_bool setDisplayMode = SDL_FALSE; + + if (other == window) { + setDisplayMode = fullscreen; + } else if (FULLSCREEN_VISIBLE(other) && + SDL_GetDisplayForWindow(other) == display) { + setDisplayMode = SDL_TRUE; + } + + if (setDisplayMode) { + SDL_DisplayMode fullscreen_mode; + + if (SDL_GetWindowDisplayMode(other, &fullscreen_mode) == 0) { + SDL_bool resized = SDL_TRUE; + + if (other->w == fullscreen_mode.w && other->h == fullscreen_mode.h) { + resized = SDL_FALSE; + } + + /* only do the mode change if we want exclusive fullscreen */ + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { + SDL_SetDisplayModeForDisplay(display, &fullscreen_mode); + } else { + SDL_SetDisplayModeForDisplay(display, NULL); + } + + if (_this->SetWindowFullscreen) { + _this->SetWindowFullscreen(_this, other, display, SDL_TRUE); + } + display->fullscreen_window = other; + + /* Generate a mode change event here */ + if (resized) { + SDL_SendWindowEvent(other, SDL_WINDOWEVENT_RESIZED, + fullscreen_mode.w, fullscreen_mode.h); + } else { + SDL_OnWindowResized(other); + } + + SDL_RestoreMousePosition(other); + return; + } + } + } + + /* Nope, restore the desktop mode */ + SDL_SetDisplayModeForDisplay(display, NULL); + + if (_this->SetWindowFullscreen) { + _this->SetWindowFullscreen(_this, window, display, SDL_FALSE); + } + display->fullscreen_window = NULL; + + /* Generate a mode change event here */ + SDL_OnWindowResized(window); + + /* Restore the cursor position */ + SDL_RestoreMousePosition(window); +} + +#define CREATE_FLAGS \ + (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI) + +static void +SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags) +{ + window->windowed.x = window->x; + window->windowed.y = window->y; + window->windowed.w = window->w; + window->windowed.h = window->h; + + if (flags & SDL_WINDOW_MAXIMIZED) { + SDL_MaximizeWindow(window); + } + if (flags & SDL_WINDOW_MINIMIZED) { + SDL_MinimizeWindow(window); + } + if (flags & SDL_WINDOW_FULLSCREEN) { + SDL_SetWindowFullscreen(window, flags); + } + if (flags & SDL_WINDOW_INPUT_GRABBED) { + SDL_SetWindowGrab(window, SDL_TRUE); + } + if (!(flags & SDL_WINDOW_HIDDEN)) { + SDL_ShowWindow(window); + } +} + +SDL_Window * +SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) +{ + SDL_Window *window; + const char *hint; + + if (!_this) { + /* Initialize the video system if needed */ + if (SDL_VideoInit(NULL) < 0) { + return NULL; + } + } + + /* Some platforms can't create zero-sized windows */ + if (w < 1) { + w = 1; + } + if (h < 1) { + h = 1; + } + + /* Some platforms have OpenGL enabled by default */ +#if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ + flags |= SDL_WINDOW_OPENGL; +#endif + if (flags & SDL_WINDOW_OPENGL) { + if (!_this->GL_CreateContext) { + SDL_SetError("No OpenGL support in video driver"); + return NULL; + } + if (SDL_GL_LoadLibrary(NULL) < 0) { + return NULL; + } + } + + /* Unless the user has specified the high-DPI disabling hint, respect the + * SDL_WINDOW_ALLOW_HIGHDPI flag. + */ + if (flags & SDL_WINDOW_ALLOW_HIGHDPI) { + hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED); + if (hint && SDL_atoi(hint) > 0) { + flags &= ~SDL_WINDOW_ALLOW_HIGHDPI; + } + } + + window = (SDL_Window *)SDL_calloc(1, sizeof(*window)); + if (!window) { + SDL_OutOfMemory(); + return NULL; + } + window->magic = &_this->window_magic; + window->id = _this->next_object_id++; + window->x = x; + window->y = y; + window->w = w; + window->h = h; + if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISUNDEFINED(y) || + SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { + SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); + int displayIndex; + SDL_Rect bounds; + + displayIndex = SDL_GetIndexOfDisplay(display); + SDL_GetDisplayBounds(displayIndex, &bounds); + if (SDL_WINDOWPOS_ISUNDEFINED(x) || SDL_WINDOWPOS_ISCENTERED(x)) { + window->x = bounds.x + (bounds.w - w) / 2; + } + if (SDL_WINDOWPOS_ISUNDEFINED(y) || SDL_WINDOWPOS_ISCENTERED(y)) { + window->y = bounds.y + (bounds.h - h) / 2; + } + } + window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); + window->brightness = 1.0f; + window->next = _this->windows; + + if (_this->windows) { + _this->windows->prev = window; + } + _this->windows = window; + + if (_this->CreateWindow && _this->CreateWindow(_this, window) < 0) { + SDL_DestroyWindow(window); + return NULL; + } + + if (title) { + SDL_SetWindowTitle(window, title); + } + SDL_FinishWindowCreation(window, flags); + + /* If the window was created fullscreen, make sure the mode code matches */ + SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)); + + return window; +} + +SDL_Window * +SDL_CreateWindowFrom(const void *data) +{ + SDL_Window *window; + + if (!_this) { + SDL_UninitializedVideo(); + return NULL; + } + window = (SDL_Window *)SDL_calloc(1, sizeof(*window)); + if (!window) { + SDL_OutOfMemory(); + return NULL; + } + window->magic = &_this->window_magic; + window->id = _this->next_object_id++; + window->flags = SDL_WINDOW_FOREIGN; + window->brightness = 1.0f; + window->next = _this->windows; + if (_this->windows) { + _this->windows->prev = window; + } + _this->windows = window; + + if (!_this->CreateWindowFrom || + _this->CreateWindowFrom(_this, window, data) < 0) { + SDL_DestroyWindow(window); + return NULL; + } + return window; +} + +int +SDL_RecreateWindow(SDL_Window * window, Uint32 flags) +{ + char *title = window->title; + SDL_Surface *icon = window->icon; + + if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) { + return SDL_SetError("No OpenGL support in video driver"); + } + + if (window->flags & SDL_WINDOW_FOREIGN) { + /* Can't destroy and re-create foreign windows, hrm */ + flags |= SDL_WINDOW_FOREIGN; + } else { + flags &= ~SDL_WINDOW_FOREIGN; + } + + /* Restore video mode, etc. */ + SDL_HideWindow(window); + + /* Tear down the old native window */ + if (window->surface) { + window->surface->flags &= ~SDL_DONTFREE; + SDL_FreeSurface(window->surface); + } + if (_this->DestroyWindowFramebuffer) { + _this->DestroyWindowFramebuffer(_this, window); + } + if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) { + _this->DestroyWindow(_this, window); + } + + if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) { + if (flags & SDL_WINDOW_OPENGL) { + if (SDL_GL_LoadLibrary(NULL) < 0) { + return -1; + } + } else { + SDL_GL_UnloadLibrary(); + } + } + + window->title = NULL; + window->icon = NULL; + window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); + + if (_this->CreateWindow && !(flags & SDL_WINDOW_FOREIGN)) { + if (_this->CreateWindow(_this, window) < 0) { + if (flags & SDL_WINDOW_OPENGL) { + SDL_GL_UnloadLibrary(); + } + return -1; + } + } + + if (title) { + SDL_SetWindowTitle(window, title); + SDL_free(title); + } + if (icon) { + SDL_SetWindowIcon(window, icon); + SDL_FreeSurface(icon); + } + SDL_FinishWindowCreation(window, flags); + + return 0; +} + +Uint32 +SDL_GetWindowID(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, 0); + + return window->id; +} + +SDL_Window * +SDL_GetWindowFromID(Uint32 id) +{ + SDL_Window *window; + + if (!_this) { + return NULL; + } + for (window = _this->windows; window; window = window->next) { + if (window->id == id) { + return window; + } + } + return NULL; +} + +Uint32 +SDL_GetWindowFlags(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, 0); + + return window->flags; +} + +void +SDL_SetWindowTitle(SDL_Window * window, const char *title) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (title == window->title) { + return; + } + SDL_free(window->title); + if (title && *title) { + window->title = SDL_strdup(title); + } else { + window->title = NULL; + } + + if (_this->SetWindowTitle) { + _this->SetWindowTitle(_this, window); + } +} + +const char * +SDL_GetWindowTitle(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, ""); + + return window->title ? window->title : ""; +} + +void +SDL_SetWindowIcon(SDL_Window * window, SDL_Surface * icon) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (!icon) { + return; + } + + SDL_FreeSurface(window->icon); + + /* Convert the icon into ARGB8888 */ + window->icon = SDL_ConvertSurfaceFormat(icon, SDL_PIXELFORMAT_ARGB8888, 0); + if (!window->icon) { + return; + } + + if (_this->SetWindowIcon) { + _this->SetWindowIcon(_this, window, window->icon); + } +} + +void* +SDL_SetWindowData(SDL_Window * window, const char *name, void *userdata) +{ + SDL_WindowUserData *prev, *data; + + CHECK_WINDOW_MAGIC(window, NULL); + + /* Input validation */ + if (name == NULL || name[0] == '\0') { + SDL_InvalidParamError("name"); + return NULL; + } + + /* See if the named data already exists */ + prev = NULL; + for (data = window->data; data; prev = data, data = data->next) { + if (data->name && SDL_strcmp(data->name, name) == 0) { + void *last_value = data->data; + + if (userdata) { + /* Set the new value */ + data->data = userdata; + } else { + /* Delete this value */ + if (prev) { + prev->next = data->next; + } else { + window->data = data->next; + } + SDL_free(data->name); + SDL_free(data); + } + return last_value; + } + } + + /* Add new data to the window */ + if (userdata) { + data = (SDL_WindowUserData *)SDL_malloc(sizeof(*data)); + data->name = SDL_strdup(name); + data->data = userdata; + data->next = window->data; + window->data = data; + } + return NULL; +} + +void * +SDL_GetWindowData(SDL_Window * window, const char *name) +{ + SDL_WindowUserData *data; + + CHECK_WINDOW_MAGIC(window, NULL); + + /* Input validation */ + if (name == NULL || name[0] == '\0') { + SDL_InvalidParamError("name"); + return NULL; + } + + for (data = window->data; data; data = data->next) { + if (data->name && SDL_strcmp(data->name, name) == 0) { + return data->data; + } + } + return NULL; +} + +void +SDL_SetWindowPosition(SDL_Window * window, int x, int y) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { + SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); + int displayIndex; + SDL_Rect bounds; + + displayIndex = SDL_GetIndexOfDisplay(display); + SDL_GetDisplayBounds(displayIndex, &bounds); + if (SDL_WINDOWPOS_ISCENTERED(x)) { + x = bounds.x + (bounds.w - window->w) / 2; + } + if (SDL_WINDOWPOS_ISCENTERED(y)) { + y = bounds.y + (bounds.h - window->h) / 2; + } + } + + if ((window->flags & SDL_WINDOW_FULLSCREEN)) { + if (!SDL_WINDOWPOS_ISUNDEFINED(x)) { + window->windowed.x = x; + } + if (!SDL_WINDOWPOS_ISUNDEFINED(y)) { + window->windowed.y = y; + } + } else { + if (!SDL_WINDOWPOS_ISUNDEFINED(x)) { + window->x = x; + } + if (!SDL_WINDOWPOS_ISUNDEFINED(y)) { + window->y = y; + } + + if (_this->SetWindowPosition) { + _this->SetWindowPosition(_this, window); + } + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y); + } +} + +void +SDL_GetWindowPosition(SDL_Window * window, int *x, int *y) +{ + CHECK_WINDOW_MAGIC(window, ); + + /* Fullscreen windows are always at their display's origin */ + if (window->flags & SDL_WINDOW_FULLSCREEN) { + if (x) { + *x = 0; + } + if (y) { + *y = 0; + } + } else { + if (x) { + *x = window->x; + } + if (y) { + *y = window->y; + } + } +} + +void +SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered) +{ + CHECK_WINDOW_MAGIC(window, ); + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + const int want = (bordered != SDL_FALSE); /* normalize the flag. */ + const int have = ((window->flags & SDL_WINDOW_BORDERLESS) == 0); + if ((want != have) && (_this->SetWindowBordered)) { + if (want) { + window->flags &= ~SDL_WINDOW_BORDERLESS; + } else { + window->flags |= SDL_WINDOW_BORDERLESS; + } + _this->SetWindowBordered(_this, window, (SDL_bool) want); + } + } +} + +void +SDL_SetWindowSize(SDL_Window * window, int w, int h) +{ + CHECK_WINDOW_MAGIC(window, ); + if (w <= 0) { + SDL_InvalidParamError("w"); + return; + } + if (h <= 0) { + SDL_InvalidParamError("h"); + return; + } + + /* Make sure we don't exceed any window size limits */ + if (window->min_w && w < window->min_w) + { + w = window->min_w; + } + if (window->max_w && w > window->max_w) + { + w = window->max_w; + } + if (window->min_h && h < window->min_h) + { + h = window->min_h; + } + if (window->max_h && h > window->max_h) + { + h = window->max_h; + } + + /* FIXME: Should this change fullscreen modes? */ + if (window->flags & SDL_WINDOW_FULLSCREEN) { + window->windowed.w = w; + window->windowed.h = h; + } else { + window->w = w; + window->h = h; + if (_this->SetWindowSize) { + _this->SetWindowSize(_this, window); + } + if (window->w == w && window->h == h) { + /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */ + SDL_OnWindowResized(window); + } + } +} + +void +SDL_GetWindowSize(SDL_Window * window, int *w, int *h) +{ + CHECK_WINDOW_MAGIC(window, ); + if (w) { + *w = window->w; + } + if (h) { + *h = window->h; + } +} + +void +SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h) +{ + CHECK_WINDOW_MAGIC(window, ); + if (min_w <= 0) { + SDL_InvalidParamError("min_w"); + return; + } + if (min_h <= 0) { + SDL_InvalidParamError("min_h"); + return; + } + + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + window->min_w = min_w; + window->min_h = min_h; + if (_this->SetWindowMinimumSize) { + _this->SetWindowMinimumSize(_this, window); + } + /* Ensure that window is not smaller than minimal size */ + SDL_SetWindowSize(window, SDL_max(window->w, window->min_w), SDL_max(window->h, window->min_h)); + } +} + +void +SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h) +{ + CHECK_WINDOW_MAGIC(window, ); + if (min_w) { + *min_w = window->min_w; + } + if (min_h) { + *min_h = window->min_h; + } +} + +void +SDL_SetWindowMaximumSize(SDL_Window * window, int max_w, int max_h) +{ + CHECK_WINDOW_MAGIC(window, ); + if (max_w <= 0) { + SDL_InvalidParamError("max_w"); + return; + } + if (max_h <= 0) { + SDL_InvalidParamError("max_h"); + return; + } + + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + window->max_w = max_w; + window->max_h = max_h; + if (_this->SetWindowMaximumSize) { + _this->SetWindowMaximumSize(_this, window); + } + /* Ensure that window is not larger than maximal size */ + SDL_SetWindowSize(window, SDL_min(window->w, window->max_w), SDL_min(window->h, window->max_h)); + } +} + +void +SDL_GetWindowMaximumSize(SDL_Window * window, int *max_w, int *max_h) +{ + CHECK_WINDOW_MAGIC(window, ); + if (max_w) { + *max_w = window->max_w; + } + if (max_h) { + *max_h = window->max_h; + } +} + +void +SDL_ShowWindow(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (window->flags & SDL_WINDOW_SHOWN) { + return; + } + + if (_this->ShowWindow) { + _this->ShowWindow(_this, window); + } + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0); +} + +void +SDL_HideWindow(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (!(window->flags & SDL_WINDOW_SHOWN)) { + return; + } + + SDL_UpdateFullscreenMode(window, SDL_FALSE); + + if (_this->HideWindow) { + _this->HideWindow(_this, window); + } + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIDDEN, 0, 0); +} + +void +SDL_RaiseWindow(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (!(window->flags & SDL_WINDOW_SHOWN)) { + return; + } + if (_this->RaiseWindow) { + _this->RaiseWindow(_this, window); + } +} + +void +SDL_MaximizeWindow(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (window->flags & SDL_WINDOW_MAXIMIZED) { + return; + } + + /* !!! FIXME: should this check if the window is resizable? */ + + if (_this->MaximizeWindow) { + _this->MaximizeWindow(_this, window); + } +} + +void +SDL_MinimizeWindow(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (window->flags & SDL_WINDOW_MINIMIZED) { + return; + } + + SDL_UpdateFullscreenMode(window, SDL_FALSE); + + if (_this->MinimizeWindow) { + _this->MinimizeWindow(_this, window); + } +} + +void +SDL_RestoreWindow(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (!(window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED))) { + return; + } + + if (_this->RestoreWindow) { + _this->RestoreWindow(_this, window); + } +} + +#define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN ) +int +SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags) +{ + CHECK_WINDOW_MAGIC(window, -1); + + flags &= FULLSCREEN_MASK; + + if ( flags == (window->flags & FULLSCREEN_MASK) ) { + return 0; + } + + /* clear the previous flags and OR in the new ones */ + window->flags &= ~FULLSCREEN_MASK; + window->flags |= flags; + + SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)); + + return 0; +} + +static SDL_Surface * +SDL_CreateWindowFramebuffer(SDL_Window * window) +{ + Uint32 format; + void *pixels; + int pitch; + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) { + return NULL; + } + + if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) { + return NULL; + } + + if (!SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + return NULL; + } + + return SDL_CreateRGBSurfaceFrom(pixels, window->w, window->h, bpp, pitch, Rmask, Gmask, Bmask, Amask); +} + +SDL_Surface * +SDL_GetWindowSurface(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, NULL); + + if (!window->surface_valid) { + if (window->surface) { + window->surface->flags &= ~SDL_DONTFREE; + SDL_FreeSurface(window->surface); + } + window->surface = SDL_CreateWindowFramebuffer(window); + if (window->surface) { + window->surface_valid = SDL_TRUE; + window->surface->flags |= SDL_DONTFREE; + } + } + return window->surface; +} + +int +SDL_UpdateWindowSurface(SDL_Window * window) +{ + SDL_Rect full_rect; + + CHECK_WINDOW_MAGIC(window, -1); + + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = window->w; + full_rect.h = window->h; + return SDL_UpdateWindowSurfaceRects(window, &full_rect, 1); +} + +int +SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects, + int numrects) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (!window->surface_valid) { + return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface"); + } + + return _this->UpdateWindowFramebuffer(_this, window, rects, numrects); +} + +int +SDL_SetWindowBrightness(SDL_Window * window, float brightness) +{ + Uint16 ramp[256]; + int status; + + CHECK_WINDOW_MAGIC(window, -1); + + SDL_CalculateGammaRamp(brightness, ramp); + status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp); + if (status == 0) { + window->brightness = brightness; + } + return status; +} + +float +SDL_GetWindowBrightness(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, 1.0f); + + return window->brightness; +} + +int +SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red, + const Uint16 * green, + const Uint16 * blue) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (!_this->SetWindowGammaRamp) { + return SDL_Unsupported(); + } + + if (!window->gamma) { + if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) { + return -1; + } + } + + if (red) { + SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16)); + } + if (green) { + SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16)); + } + if (blue) { + SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16)); + } + if (window->flags & SDL_WINDOW_INPUT_FOCUS) { + return _this->SetWindowGammaRamp(_this, window, window->gamma); + } else { + return 0; + } +} + +int +SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red, + Uint16 * green, + Uint16 * blue) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (!window->gamma) { + int i; + + window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16)); + if (!window->gamma) { + return SDL_OutOfMemory(); + } + window->saved_gamma = window->gamma + 3*256; + + if (_this->GetWindowGammaRamp) { + if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) { + return -1; + } + } else { + /* Create an identity gamma ramp */ + for (i = 0; i < 256; ++i) { + Uint16 value = (Uint16)((i << 8) | i); + + window->gamma[0*256+i] = value; + window->gamma[1*256+i] = value; + window->gamma[2*256+i] = value; + } + } + SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16)); + } + + if (red) { + SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16)); + } + if (green) { + SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16)); + } + if (blue) { + SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16)); + } + return 0; +} + +void +SDL_UpdateWindowGrab(SDL_Window * window) +{ + if (_this->SetWindowGrab) { + SDL_bool grabbed; + if ((window->flags & SDL_WINDOW_INPUT_GRABBED) && + (window->flags & SDL_WINDOW_INPUT_FOCUS)) { + grabbed = SDL_TRUE; + } else { + grabbed = SDL_FALSE; + } + _this->SetWindowGrab(_this, window, grabbed); + } +} + +void +SDL_SetWindowGrab(SDL_Window * window, SDL_bool grabbed) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (!!grabbed == !!(window->flags & SDL_WINDOW_INPUT_GRABBED)) { + return; + } + if (grabbed) { + window->flags |= SDL_WINDOW_INPUT_GRABBED; + } else { + window->flags &= ~SDL_WINDOW_INPUT_GRABBED; + } + SDL_UpdateWindowGrab(window); +} + +SDL_bool +SDL_GetWindowGrab(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, SDL_FALSE); + + return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0); +} + +void +SDL_OnWindowShown(SDL_Window * window) +{ + SDL_OnWindowRestored(window); +} + +void +SDL_OnWindowHidden(SDL_Window * window) +{ + SDL_UpdateFullscreenMode(window, SDL_FALSE); +} + +void +SDL_OnWindowResized(SDL_Window * window) +{ + window->surface_valid = SDL_FALSE; + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SIZE_CHANGED, window->w, window->h); +} + +void +SDL_OnWindowMinimized(SDL_Window * window) +{ + SDL_UpdateFullscreenMode(window, SDL_FALSE); +} + +void +SDL_OnWindowRestored(SDL_Window * window) +{ + SDL_RaiseWindow(window); + + if (FULLSCREEN_VISIBLE(window)) { + SDL_UpdateFullscreenMode(window, SDL_TRUE); + } +} + +void +SDL_OnWindowEnter(SDL_Window * window) +{ + if (_this->OnWindowEnter) { + _this->OnWindowEnter(_this, window); + } +} + +void +SDL_OnWindowLeave(SDL_Window * window) +{ +} + +void +SDL_OnWindowFocusGained(SDL_Window * window) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (window->gamma && _this->SetWindowGammaRamp) { + _this->SetWindowGammaRamp(_this, window, window->gamma); + } + + if (mouse && mouse->relative_mode) { + SDL_SetMouseFocus(window); + SDL_WarpMouseInWindow(window, window->w/2, window->h/2); + } + + SDL_UpdateWindowGrab(window); +} + +static SDL_bool +ShouldMinimizeOnFocusLoss(SDL_Window * window) +{ + const char *hint; + + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + return SDL_FALSE; + } + +#ifdef __MACOSX__ + if (Cocoa_IsWindowInFullscreenSpace(window)) { + return SDL_FALSE; + } +#endif + + hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS); + if (hint) { + if (*hint == '0') { + return SDL_FALSE; + } else { + return SDL_TRUE; + } + } + + return SDL_TRUE; +} + +void +SDL_OnWindowFocusLost(SDL_Window * window) +{ + if (window->gamma && _this->SetWindowGammaRamp) { + _this->SetWindowGammaRamp(_this, window, window->saved_gamma); + } + + SDL_UpdateWindowGrab(window); + + if (ShouldMinimizeOnFocusLoss(window)) { + SDL_MinimizeWindow(window); + } +} + +SDL_Window * +SDL_GetFocusWindow(void) +{ + SDL_Window *window; + + if (!_this) { + return NULL; + } + for (window = _this->windows; window; window = window->next) { + if (window->flags & SDL_WINDOW_INPUT_FOCUS) { + return window; + } + } + return NULL; +} + +void +SDL_DestroyWindow(SDL_Window * window) +{ + SDL_VideoDisplay *display; + + CHECK_WINDOW_MAGIC(window, ); + + /* Restore video mode, etc. */ + SDL_HideWindow(window); + + /* Make sure this window no longer has focus */ + if (SDL_GetKeyboardFocus() == window) { + SDL_SetKeyboardFocus(NULL); + } + if (SDL_GetMouseFocus() == window) { + SDL_SetMouseFocus(NULL); + } + + /* make no context current if this is the current context window. */ + if (window->flags & SDL_WINDOW_OPENGL) { + if (_this->current_glwin == window) { + SDL_GL_MakeCurrent(window, NULL); + } + } + + if (window->surface) { + window->surface->flags &= ~SDL_DONTFREE; + SDL_FreeSurface(window->surface); + } + if (_this->DestroyWindowFramebuffer) { + _this->DestroyWindowFramebuffer(_this, window); + } + if (_this->DestroyWindow) { + _this->DestroyWindow(_this, window); + } + if (window->flags & SDL_WINDOW_OPENGL) { + SDL_GL_UnloadLibrary(); + } + + display = SDL_GetDisplayForWindow(window); + if (display->fullscreen_window == window) { + display->fullscreen_window = NULL; + } + + /* Now invalidate magic */ + window->magic = NULL; + + /* Free memory associated with the window */ + SDL_free(window->title); + SDL_FreeSurface(window->icon); + SDL_free(window->gamma); + while (window->data) { + SDL_WindowUserData *data = window->data; + + window->data = data->next; + SDL_free(data->name); + SDL_free(data); + } + + /* Unlink the window from the list */ + if (window->next) { + window->next->prev = window->prev; + } + if (window->prev) { + window->prev->next = window->next; + } else { + _this->windows = window->next; + } + + SDL_free(window); +} + +SDL_bool +SDL_IsScreenSaverEnabled() +{ + if (!_this) { + return SDL_TRUE; + } + return _this->suspend_screensaver ? SDL_FALSE : SDL_TRUE; +} + +void +SDL_EnableScreenSaver() +{ + if (!_this) { + return; + } + if (!_this->suspend_screensaver) { + return; + } + _this->suspend_screensaver = SDL_FALSE; + if (_this->SuspendScreenSaver) { + _this->SuspendScreenSaver(_this); + } +} + +void +SDL_DisableScreenSaver() +{ + if (!_this) { + return; + } + if (_this->suspend_screensaver) { + return; + } + _this->suspend_screensaver = SDL_TRUE; + if (_this->SuspendScreenSaver) { + _this->SuspendScreenSaver(_this); + } +} + +void +SDL_VideoQuit(void) +{ + int i, j; + + if (!_this) { + return; + } + + /* Halt event processing before doing anything else */ + SDL_TouchQuit(); + SDL_MouseQuit(); + SDL_KeyboardQuit(); + SDL_QuitSubSystem(SDL_INIT_EVENTS); + + SDL_EnableScreenSaver(); + + /* Clean up the system video */ + while (_this->windows) { + SDL_DestroyWindow(_this->windows); + } + _this->VideoQuit(_this); + + for (i = 0; i < _this->num_displays; ++i) { + SDL_VideoDisplay *display = &_this->displays[i]; + for (j = display->num_display_modes; j--;) { + SDL_free(display->display_modes[j].driverdata); + display->display_modes[j].driverdata = NULL; + } + SDL_free(display->display_modes); + display->display_modes = NULL; + SDL_free(display->desktop_mode.driverdata); + display->desktop_mode.driverdata = NULL; + SDL_free(display->driverdata); + display->driverdata = NULL; + } + if (_this->displays) { + for (i = 0; i < _this->num_displays; ++i) { + SDL_free(_this->displays[i].name); + } + SDL_free(_this->displays); + _this->displays = NULL; + _this->num_displays = 0; + } + SDL_free(_this->clipboard_text); + _this->clipboard_text = NULL; + _this->free(_this); + _this = NULL; +} + +int +SDL_GL_LoadLibrary(const char *path) +{ + int retval; + + if (!_this) { + return SDL_UninitializedVideo(); + } + if (_this->gl_config.driver_loaded) { + if (path && SDL_strcmp(path, _this->gl_config.driver_path) != 0) { + return SDL_SetError("OpenGL library already loaded"); + } + retval = 0; + } else { + if (!_this->GL_LoadLibrary) { + return SDL_SetError("No dynamic GL support in video driver"); + } + retval = _this->GL_LoadLibrary(_this, path); + } + if (retval == 0) { + ++_this->gl_config.driver_loaded; + } else { + if (_this->GL_UnloadLibrary) { + _this->GL_UnloadLibrary(_this); + } + } + return (retval); +} + +void * +SDL_GL_GetProcAddress(const char *proc) +{ + void *func; + + if (!_this) { + SDL_UninitializedVideo(); + return NULL; + } + func = NULL; + if (_this->GL_GetProcAddress) { + if (_this->gl_config.driver_loaded) { + func = _this->GL_GetProcAddress(_this, proc); + } else { + SDL_SetError("No GL driver has been loaded"); + } + } else { + SDL_SetError("No dynamic GL support in video driver"); + } + return func; +} + +void +SDL_GL_UnloadLibrary(void) +{ + if (!_this) { + SDL_UninitializedVideo(); + return; + } + if (_this->gl_config.driver_loaded > 0) { + if (--_this->gl_config.driver_loaded > 0) { + return; + } + if (_this->GL_UnloadLibrary) { + _this->GL_UnloadLibrary(_this); + } + } +} + +static SDL_INLINE SDL_bool +isAtLeastGL3(const char *verstr) +{ + return ( verstr && (SDL_atoi(verstr) >= 3) ); +} + +SDL_bool +SDL_GL_ExtensionSupported(const char *extension) +{ +#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 + const GLubyte *(APIENTRY * glGetStringFunc) (GLenum); + const char *extensions; + const char *start; + const char *where, *terminator; + + /* Extension names should not have spaces. */ + where = SDL_strchr(extension, ' '); + if (where || *extension == '\0') { + return SDL_FALSE; + } + /* See if there's an environment variable override */ + start = SDL_getenv(extension); + if (start && *start == '0') { + return SDL_FALSE; + } + + /* Lookup the available extensions */ + + glGetStringFunc = SDL_GL_GetProcAddress("glGetString"); + if (!glGetStringFunc) { + return SDL_FALSE; + } + + if (isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) { + const GLubyte *(APIENTRY * glGetStringiFunc) (GLenum, GLuint); + void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params); + GLint num_exts = 0; + GLint i; + + glGetStringiFunc = SDL_GL_GetProcAddress("glGetStringi"); + glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv"); + if ((!glGetStringiFunc) || (!glGetIntegervFunc)) { + return SDL_FALSE; + } + + #ifndef GL_NUM_EXTENSIONS + #define GL_NUM_EXTENSIONS 0x821D + #endif + glGetIntegervFunc(GL_NUM_EXTENSIONS, &num_exts); + for (i = 0; i < num_exts; i++) { + const char *thisext = (const char *) glGetStringiFunc(GL_EXTENSIONS, i); + if (SDL_strcmp(thisext, extension) == 0) { + return SDL_TRUE; + } + } + + return SDL_FALSE; + } + + /* Try the old way with glGetString(GL_EXTENSIONS) ... */ + + extensions = (const char *) glGetStringFunc(GL_EXTENSIONS); + if (!extensions) { + return SDL_FALSE; + } + /* + * It takes a bit of care to be fool-proof about parsing the OpenGL + * extensions string. Don't be fooled by sub-strings, etc. + */ + + start = extensions; + + for (;;) { + where = SDL_strstr(start, extension); + if (!where) + break; + + terminator = where + SDL_strlen(extension); + if (where == start || *(where - 1) == ' ') + if (*terminator == ' ' || *terminator == '\0') + return SDL_TRUE; + + start = terminator; + } + return SDL_FALSE; +#else + return SDL_FALSE; +#endif +} + +int +SDL_GL_SetAttribute(SDL_GLattr attr, int value) +{ +#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 + int retval; + + if (!_this) { + return SDL_UninitializedVideo(); + } + retval = 0; + switch (attr) { + case SDL_GL_RED_SIZE: + _this->gl_config.red_size = value; + break; + case SDL_GL_GREEN_SIZE: + _this->gl_config.green_size = value; + break; + case SDL_GL_BLUE_SIZE: + _this->gl_config.blue_size = value; + break; + case SDL_GL_ALPHA_SIZE: + _this->gl_config.alpha_size = value; + break; + case SDL_GL_DOUBLEBUFFER: + _this->gl_config.double_buffer = value; + break; + case SDL_GL_BUFFER_SIZE: + _this->gl_config.buffer_size = value; + break; + case SDL_GL_DEPTH_SIZE: + _this->gl_config.depth_size = value; + break; + case SDL_GL_STENCIL_SIZE: + _this->gl_config.stencil_size = value; + break; + case SDL_GL_ACCUM_RED_SIZE: + _this->gl_config.accum_red_size = value; + break; + case SDL_GL_ACCUM_GREEN_SIZE: + _this->gl_config.accum_green_size = value; + break; + case SDL_GL_ACCUM_BLUE_SIZE: + _this->gl_config.accum_blue_size = value; + break; + case SDL_GL_ACCUM_ALPHA_SIZE: + _this->gl_config.accum_alpha_size = value; + break; + case SDL_GL_STEREO: + _this->gl_config.stereo = value; + break; + case SDL_GL_MULTISAMPLEBUFFERS: + _this->gl_config.multisamplebuffers = value; + break; + case SDL_GL_MULTISAMPLESAMPLES: + _this->gl_config.multisamplesamples = value; + break; + case SDL_GL_ACCELERATED_VISUAL: + _this->gl_config.accelerated = value; + break; + case SDL_GL_RETAINED_BACKING: + _this->gl_config.retained_backing = value; + break; + case SDL_GL_CONTEXT_MAJOR_VERSION: + _this->gl_config.major_version = value; + break; + case SDL_GL_CONTEXT_MINOR_VERSION: + _this->gl_config.minor_version = value; + break; + case SDL_GL_CONTEXT_EGL: + /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */ + if (value != 0) { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + } else { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); + }; + break; + case SDL_GL_CONTEXT_FLAGS: + if( value & ~(SDL_GL_CONTEXT_DEBUG_FLAG | + SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG | + SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG | + SDL_GL_CONTEXT_RESET_ISOLATION_FLAG) ) { + retval = SDL_SetError("Unknown OpenGL context flag %d", value); + break; + } + _this->gl_config.flags = value; + break; + case SDL_GL_CONTEXT_PROFILE_MASK: + if( value != 0 && + value != SDL_GL_CONTEXT_PROFILE_CORE && + value != SDL_GL_CONTEXT_PROFILE_COMPATIBILITY && + value != SDL_GL_CONTEXT_PROFILE_ES ) { + retval = SDL_SetError("Unknown OpenGL context profile %d", value); + break; + } + _this->gl_config.profile_mask = value; + break; + case SDL_GL_SHARE_WITH_CURRENT_CONTEXT: + _this->gl_config.share_with_current_context = value; + break; + case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE: + _this->gl_config.framebuffer_srgb_capable = value; + break; + default: + retval = SDL_SetError("Unknown OpenGL attribute"); + break; + } + return retval; +#else + return SDL_Unsupported(); +#endif /* SDL_VIDEO_OPENGL */ +} + +int +SDL_GL_GetAttribute(SDL_GLattr attr, int *value) +{ +#if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 + void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params); + GLenum(APIENTRY * glGetErrorFunc) (void); + GLenum attrib = 0; + GLenum error = 0; + + glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv"); + if (!glGetIntegervFunc) { + return -1; + } + + glGetErrorFunc = SDL_GL_GetProcAddress("glGetError"); + if (!glGetErrorFunc) { + return -1; + } + + /* Clear value in any case */ + *value = 0; + + switch (attr) { + case SDL_GL_RED_SIZE: + attrib = GL_RED_BITS; + break; + case SDL_GL_BLUE_SIZE: + attrib = GL_BLUE_BITS; + break; + case SDL_GL_GREEN_SIZE: + attrib = GL_GREEN_BITS; + break; + case SDL_GL_ALPHA_SIZE: + attrib = GL_ALPHA_BITS; + break; + case SDL_GL_DOUBLEBUFFER: +#if SDL_VIDEO_OPENGL + attrib = GL_DOUBLEBUFFER; + break; +#else + /* OpenGL ES 1.0 and above specifications have EGL_SINGLE_BUFFER */ + /* parameter which switches double buffer to single buffer. OpenGL ES */ + /* SDL driver must set proper value after initialization */ + *value = _this->gl_config.double_buffer; + return 0; +#endif + case SDL_GL_DEPTH_SIZE: + attrib = GL_DEPTH_BITS; + break; + case SDL_GL_STENCIL_SIZE: + attrib = GL_STENCIL_BITS; + break; +#if SDL_VIDEO_OPENGL + case SDL_GL_ACCUM_RED_SIZE: + attrib = GL_ACCUM_RED_BITS; + break; + case SDL_GL_ACCUM_GREEN_SIZE: + attrib = GL_ACCUM_GREEN_BITS; + break; + case SDL_GL_ACCUM_BLUE_SIZE: + attrib = GL_ACCUM_BLUE_BITS; + break; + case SDL_GL_ACCUM_ALPHA_SIZE: + attrib = GL_ACCUM_ALPHA_BITS; + break; + case SDL_GL_STEREO: + attrib = GL_STEREO; + break; +#else + case SDL_GL_ACCUM_RED_SIZE: + case SDL_GL_ACCUM_GREEN_SIZE: + case SDL_GL_ACCUM_BLUE_SIZE: + case SDL_GL_ACCUM_ALPHA_SIZE: + case SDL_GL_STEREO: + /* none of these are supported in OpenGL ES */ + *value = 0; + return 0; +#endif + case SDL_GL_MULTISAMPLEBUFFERS: +#if SDL_VIDEO_OPENGL + attrib = GL_SAMPLE_BUFFERS_ARB; +#else + attrib = GL_SAMPLE_BUFFERS; +#endif + break; + case SDL_GL_MULTISAMPLESAMPLES: +#if SDL_VIDEO_OPENGL + attrib = GL_SAMPLES_ARB; +#else + attrib = GL_SAMPLES; +#endif + break; + case SDL_GL_BUFFER_SIZE: + { + GLint bits = 0; + GLint component; + + /* + * there doesn't seem to be a single flag in OpenGL + * for this! + */ + glGetIntegervFunc(GL_RED_BITS, &component); + bits += component; + glGetIntegervFunc(GL_GREEN_BITS, &component); + bits += component; + glGetIntegervFunc(GL_BLUE_BITS, &component); + bits += component; + glGetIntegervFunc(GL_ALPHA_BITS, &component); + bits += component; + + *value = bits; + return 0; + } + case SDL_GL_ACCELERATED_VISUAL: + { + /* FIXME: How do we get this information? */ + *value = (_this->gl_config.accelerated != 0); + return 0; + } + case SDL_GL_RETAINED_BACKING: + { + *value = _this->gl_config.retained_backing; + return 0; + } + case SDL_GL_CONTEXT_MAJOR_VERSION: + { + *value = _this->gl_config.major_version; + return 0; + } + case SDL_GL_CONTEXT_MINOR_VERSION: + { + *value = _this->gl_config.minor_version; + return 0; + } + case SDL_GL_CONTEXT_EGL: + /* FIXME: SDL_GL_CONTEXT_EGL to be deprecated in SDL 2.1 */ + { + if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { + *value = 1; + } + else { + *value = 0; + } + return 0; + } + case SDL_GL_CONTEXT_FLAGS: + { + *value = _this->gl_config.flags; + return 0; + } + case SDL_GL_CONTEXT_PROFILE_MASK: + { + *value = _this->gl_config.profile_mask; + return 0; + } + case SDL_GL_SHARE_WITH_CURRENT_CONTEXT: + { + *value = _this->gl_config.share_with_current_context; + return 0; + } + case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE: + { + *value = _this->gl_config.framebuffer_srgb_capable; + return 0; + } + default: + return SDL_SetError("Unknown OpenGL attribute"); + } + + glGetIntegervFunc(attrib, (GLint *) value); + error = glGetErrorFunc(); + if (error != GL_NO_ERROR) { + if (error == GL_INVALID_ENUM) { + return SDL_SetError("OpenGL error: GL_INVALID_ENUM"); + } else if (error == GL_INVALID_VALUE) { + return SDL_SetError("OpenGL error: GL_INVALID_VALUE"); + } + return SDL_SetError("OpenGL error: %08X", error); + } + return 0; +#else + return SDL_Unsupported(); +#endif /* SDL_VIDEO_OPENGL */ +} + +SDL_GLContext +SDL_GL_CreateContext(SDL_Window * window) +{ + SDL_GLContext ctx = NULL; + CHECK_WINDOW_MAGIC(window, NULL); + + if (!(window->flags & SDL_WINDOW_OPENGL)) { + SDL_SetError("The specified window isn't an OpenGL window"); + return NULL; + } + + ctx = _this->GL_CreateContext(_this, window); + + /* Creating a context is assumed to make it current in the SDL driver. */ + if (ctx) { + _this->current_glwin = window; + _this->current_glctx = ctx; + SDL_TLSSet(_this->current_glwin_tls, window, NULL); + SDL_TLSSet(_this->current_glctx_tls, ctx, NULL); + } + return ctx; +} + +int +SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx) +{ + int retval; + + if (window == SDL_GL_GetCurrentWindow() && + ctx == SDL_GL_GetCurrentContext()) { + /* We're already current. */ + return 0; + } + + if (!ctx) { + window = NULL; + } else { + CHECK_WINDOW_MAGIC(window, -1); + + if (!(window->flags & SDL_WINDOW_OPENGL)) { + return SDL_SetError("The specified window isn't an OpenGL window"); + } + } + + retval = _this->GL_MakeCurrent(_this, window, ctx); + if (retval == 0) { + _this->current_glwin = window; + _this->current_glctx = ctx; + SDL_TLSSet(_this->current_glwin_tls, window, NULL); + SDL_TLSSet(_this->current_glctx_tls, ctx, NULL); + } + return retval; +} + +SDL_Window * +SDL_GL_GetCurrentWindow(void) +{ + if (!_this) { + SDL_UninitializedVideo(); + return NULL; + } + return (SDL_Window *)SDL_TLSGet(_this->current_glwin_tls); +} + +SDL_GLContext +SDL_GL_GetCurrentContext(void) +{ + if (!_this) { + SDL_UninitializedVideo(); + return NULL; + } + return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls); +} + +void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (_this->GL_GetDrawableSize) { + _this->GL_GetDrawableSize(_this, window, w, h); + } else { + SDL_GetWindowSize(window, w, h); + } +} + +int +SDL_GL_SetSwapInterval(int interval) +{ + if (!_this) { + return SDL_UninitializedVideo(); + } else if (SDL_GL_GetCurrentContext() == NULL) { + return SDL_SetError("No OpenGL context has been made current"); + } else if (_this->GL_SetSwapInterval) { + return _this->GL_SetSwapInterval(_this, interval); + } else { + return SDL_SetError("Setting the swap interval is not supported"); + } +} + +int +SDL_GL_GetSwapInterval(void) +{ + if (!_this) { + return 0; + } else if (SDL_GL_GetCurrentContext() == NULL) { + return 0; + } else if (_this->GL_GetSwapInterval) { + return _this->GL_GetSwapInterval(_this); + } else { + return 0; + } +} + +void +SDL_GL_SwapWindow(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, ); + + if (!(window->flags & SDL_WINDOW_OPENGL)) { + SDL_SetError("The specified window isn't an OpenGL window"); + return; + } + + if (SDL_GL_GetCurrentWindow() != window) { + SDL_SetError("The specified window has not been made current"); + return; + } + + _this->GL_SwapWindow(_this, window); +} + +void +SDL_GL_DeleteContext(SDL_GLContext context) +{ + if (!_this || !context) { + return; + } + + if (SDL_GL_GetCurrentContext() == context) { + SDL_GL_MakeCurrent(NULL, NULL); + } + + _this->GL_DeleteContext(_this, context); +} + +#if 0 /* FIXME */ +/* + * Utility function used by SDL_WM_SetIcon(); flags & 1 for color key, flags + * & 2 for alpha channel. + */ +static void +CreateMaskFromColorKeyOrAlpha(SDL_Surface * icon, Uint8 * mask, int flags) +{ + int x, y; + Uint32 colorkey; +#define SET_MASKBIT(icon, x, y, mask) \ + mask[(y*((icon->w+7)/8))+(x/8)] &= ~(0x01<<(7-(x%8))) + + colorkey = icon->format->colorkey; + switch (icon->format->BytesPerPixel) { + case 1: + { + Uint8 *pixels; + for (y = 0; y < icon->h; ++y) { + pixels = (Uint8 *) icon->pixels + y * icon->pitch; + for (x = 0; x < icon->w; ++x) { + if (*pixels++ == colorkey) { + SET_MASKBIT(icon, x, y, mask); + } + } + } + } + break; + + case 2: + { + Uint16 *pixels; + for (y = 0; y < icon->h; ++y) { + pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2; + for (x = 0; x < icon->w; ++x) { + if ((flags & 1) && *pixels == colorkey) { + SET_MASKBIT(icon, x, y, mask); + } else if ((flags & 2) + && (*pixels & icon->format->Amask) == 0) { + SET_MASKBIT(icon, x, y, mask); + } + pixels++; + } + } + } + break; + + case 4: + { + Uint32 *pixels; + for (y = 0; y < icon->h; ++y) { + pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4; + for (x = 0; x < icon->w; ++x) { + if ((flags & 1) && *pixels == colorkey) { + SET_MASKBIT(icon, x, y, mask); + } else if ((flags & 2) + && (*pixels & icon->format->Amask) == 0) { + SET_MASKBIT(icon, x, y, mask); + } + pixels++; + } + } + } + break; + } +} + +/* + * Sets the window manager icon for the display window. + */ +void +SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask) +{ + if (icon && _this->SetIcon) { + /* Generate a mask if necessary, and create the icon! */ + if (mask == NULL) { + int mask_len = icon->h * (icon->w + 7) / 8; + int flags = 0; + mask = (Uint8 *) SDL_malloc(mask_len); + if (mask == NULL) { + return; + } + SDL_memset(mask, ~0, mask_len); + if (icon->flags & SDL_SRCCOLORKEY) + flags |= 1; + if (icon->flags & SDL_SRCALPHA) + flags |= 2; + if (flags) { + CreateMaskFromColorKeyOrAlpha(icon, mask, flags); + } + _this->SetIcon(_this, icon, mask); + SDL_free(mask); + } else { + _this->SetIcon(_this, icon, mask); + } + } +} +#endif + +SDL_bool +SDL_GetWindowWMInfo(SDL_Window * window, struct SDL_SysWMinfo *info) +{ + CHECK_WINDOW_MAGIC(window, SDL_FALSE); + + if (!info) { + return SDL_FALSE; + } + info->subsystem = SDL_SYSWM_UNKNOWN; + + if (!_this->GetWindowWMInfo) { + return SDL_FALSE; + } + return (_this->GetWindowWMInfo(_this, window, info)); +} + +void +SDL_StartTextInput(void) +{ + SDL_Window *window; + + /* First, enable text events */ + SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE); + SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE); + + /* Then show the on-screen keyboard, if any */ + window = SDL_GetFocusWindow(); + if (window && _this && _this->ShowScreenKeyboard) { + _this->ShowScreenKeyboard(_this, window); + } + + /* Finally start the text input system */ + if (_this && _this->StartTextInput) { + _this->StartTextInput(_this); + } +} + +SDL_bool +SDL_IsTextInputActive(void) +{ + return (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE); +} + +void +SDL_StopTextInput(void) +{ + SDL_Window *window; + + /* Stop the text input system */ + if (_this && _this->StopTextInput) { + _this->StopTextInput(_this); + } + + /* Hide the on-screen keyboard, if any */ + window = SDL_GetFocusWindow(); + if (window && _this && _this->HideScreenKeyboard) { + _this->HideScreenKeyboard(_this, window); + } + + /* Finally disable text events */ + SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE); + SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE); +} + +void +SDL_SetTextInputRect(SDL_Rect *rect) +{ + if (_this && _this->SetTextInputRect) { + _this->SetTextInputRect(_this, rect); + } +} + +SDL_bool +SDL_HasScreenKeyboardSupport(void) +{ + if (_this && _this->HasScreenKeyboardSupport) { + return _this->HasScreenKeyboardSupport(_this); + } + return SDL_FALSE; +} + +SDL_bool +SDL_IsScreenKeyboardShown(SDL_Window *window) +{ + if (window && _this && _this->IsScreenKeyboardShown) { + return _this->IsScreenKeyboardShown(_this, window); + } + return SDL_FALSE; +} + +#if SDL_VIDEO_DRIVER_WINDOWS +#include "windows/SDL_windowsmessagebox.h" +#endif +#if SDL_VIDEO_DRIVER_COCOA +#include "cocoa/SDL_cocoamessagebox.h" +#endif +#if SDL_VIDEO_DRIVER_UIKIT +#include "uikit/SDL_uikitmessagebox.h" +#endif +#if SDL_VIDEO_DRIVER_X11 +#include "x11/SDL_x11messagebox.h" +#endif + +static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype) +{ + SDL_SysWMinfo info; + SDL_Window *window = messageboxdata->window; + + if (!window) { + return SDL_TRUE; + } + + SDL_VERSION(&info.version); + if (!SDL_GetWindowWMInfo(window, &info)) { + return SDL_TRUE; + } else { + return (info.subsystem == drivertype); + } +} + +int +SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ + int dummybutton; + int retval = -1; + SDL_bool relative_mode; + int show_cursor_prev; + + if (!messageboxdata) { + return SDL_InvalidParamError("messageboxdata"); + } + + relative_mode = SDL_GetRelativeMouseMode(); + SDL_SetRelativeMouseMode(SDL_FALSE); + show_cursor_prev = SDL_ShowCursor(1); + + if (!buttonid) { + buttonid = &dummybutton; + } + + if (_this && _this->ShowMessageBox) { + retval = _this->ShowMessageBox(_this, messageboxdata, buttonid); + } + + /* It's completely fine to call this function before video is initialized */ +#if SDL_VIDEO_DRIVER_WINDOWS + if (retval == -1 && + SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WINDOWS) && + WIN_ShowMessageBox(messageboxdata, buttonid) == 0) { + retval = 0; + } +#endif +#if SDL_VIDEO_DRIVER_COCOA + if (retval == -1 && + SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_COCOA) && + Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) { + retval = 0; + } +#endif +#if SDL_VIDEO_DRIVER_UIKIT + if (retval == -1 && + SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_UIKIT) && + UIKit_ShowMessageBox(messageboxdata, buttonid) == 0) { + retval = 0; + } +#endif +#if SDL_VIDEO_DRIVER_X11 + if (retval == -1 && + SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) && + X11_ShowMessageBox(messageboxdata, buttonid) == 0) { + retval = 0; + } +#endif + if (retval == -1) { + SDL_SetError("No message system available"); + } + + SDL_ShowCursor(show_cursor_prev); + SDL_SetRelativeMouseMode(relative_mode); + + return retval; +} + +int +SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window) +{ + SDL_MessageBoxData data; + SDL_MessageBoxButtonData button; + + SDL_zero(data); + data.flags = flags; + data.title = title; + data.message = message; + data.numbuttons = 1; + data.buttons = &button; + data.window = window; + + SDL_zero(button); + button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; + button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT; + button.text = "OK"; + + return SDL_ShowMessageBox(&data, NULL); +} + +SDL_bool +SDL_ShouldAllowTopmost(void) +{ + const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST); + if (hint) { + if (*hint == '0') { + return SDL_FALSE; + } else { + return SDL_TRUE; + } + } + return SDL_TRUE; +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtevents.cpp b/src/video/winrt/SDL_winrtevents.cpp index 021ad406c17dc..112c3d49409cd 100644 --- a/src/video/winrt/SDL_winrtevents.cpp +++ b/src/video/winrt/SDL_winrtevents.cpp @@ -22,15 +22,15 @@ #if SDL_VIDEO_DRIVER_WINRT -/* - * Windows includes: - */ -#include -using namespace Windows::UI::Core; -using Windows::UI::Core::CoreCursor; - -/* - * SDL includes: +/* + * Windows includes: + */ +#include +using namespace Windows::UI::Core; +using Windows::UI::Core::CoreCursor; + +/* + * SDL includes: */ #include "SDL_winrtevents_c.h" #include "../../core/winrt/SDL_winrtapp_common.h" @@ -63,89 +63,89 @@ WINRT_PumpEvents(_THIS) /* XAML Thread management */ - -enum SDL_XAMLAppThreadState -{ - ThreadState_NotLaunched = 0, - ThreadState_Running, - ThreadState_Yielding + +enum SDL_XAMLAppThreadState +{ + ThreadState_NotLaunched = 0, + ThreadState_Running, + ThreadState_Yielding }; -static SDL_XAMLAppThreadState _threadState = ThreadState_NotLaunched; -static SDL_Thread * _XAMLThread = nullptr; -static SDL_mutex * _mutex = nullptr; -static SDL_cond * _cond = nullptr; - -static void -WINRT_YieldXAMLThread() -{ - SDL_LockMutex(_mutex); - SDL_assert(_threadState == ThreadState_Running); - _threadState = ThreadState_Yielding; - SDL_UnlockMutex(_mutex); - - SDL_CondSignal(_cond); - - SDL_LockMutex(_mutex); - while (_threadState != ThreadState_Running) { - SDL_CondWait(_cond, _mutex); - } - SDL_UnlockMutex(_mutex); -} - -static int -WINRT_XAMLThreadMain(void * userdata) -{ - // TODO, WinRT: pass the C-style main() a reasonably realistic - // representation of command line arguments. - int argc = 0; - char **argv = NULL; - return WINRT_SDLAppEntryPoint(argc, argv); -} - -void -WINRT_CycleXAMLThread() -{ - switch (_threadState) { - case ThreadState_NotLaunched: - { - _cond = SDL_CreateCond(); - - _mutex = SDL_CreateMutex(); - _threadState = ThreadState_Running; - _XAMLThread = SDL_CreateThread(WINRT_XAMLThreadMain, "SDL/XAML App Thread", nullptr); - - SDL_LockMutex(_mutex); - while (_threadState != ThreadState_Yielding) { - SDL_CondWait(_cond, _mutex); - } - SDL_UnlockMutex(_mutex); - - break; - } - - case ThreadState_Running: - { - SDL_assert(false); - break; - } - - case ThreadState_Yielding: - { - SDL_LockMutex(_mutex); - SDL_assert(_threadState == ThreadState_Yielding); - _threadState = ThreadState_Running; - SDL_UnlockMutex(_mutex); - - SDL_CondSignal(_cond); - - SDL_LockMutex(_mutex); - while (_threadState != ThreadState_Yielding) { - SDL_CondWait(_cond, _mutex); - } - SDL_UnlockMutex(_mutex); - } - } +static SDL_XAMLAppThreadState _threadState = ThreadState_NotLaunched; +static SDL_Thread * _XAMLThread = nullptr; +static SDL_mutex * _mutex = nullptr; +static SDL_cond * _cond = nullptr; + +static void +WINRT_YieldXAMLThread() +{ + SDL_LockMutex(_mutex); + SDL_assert(_threadState == ThreadState_Running); + _threadState = ThreadState_Yielding; + SDL_UnlockMutex(_mutex); + + SDL_CondSignal(_cond); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Running) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); +} + +static int +WINRT_XAMLThreadMain(void * userdata) +{ + // TODO, WinRT: pass the C-style main() a reasonably realistic + // representation of command line arguments. + int argc = 0; + char **argv = NULL; + return WINRT_SDLAppEntryPoint(argc, argv); +} + +void +WINRT_CycleXAMLThread() +{ + switch (_threadState) { + case ThreadState_NotLaunched: + { + _cond = SDL_CreateCond(); + + _mutex = SDL_CreateMutex(); + _threadState = ThreadState_Running; + _XAMLThread = SDL_CreateThread(WINRT_XAMLThreadMain, "SDL/XAML App Thread", nullptr); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Yielding) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); + + break; + } + + case ThreadState_Running: + { + SDL_assert(false); + break; + } + + case ThreadState_Yielding: + { + SDL_LockMutex(_mutex); + SDL_assert(_threadState == ThreadState_Yielding); + _threadState = ThreadState_Running; + SDL_UnlockMutex(_mutex); + + SDL_CondSignal(_cond); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Yielding) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); + } + } } #endif /* SDL_VIDEO_DRIVER_WINRT */ diff --git a/src/video/winrt/SDL_winrtevents_c.h b/src/video/winrt/SDL_winrtevents_c.h index a6ae7a2c6ac7f..ba5105f3f3a39 100644 --- a/src/video/winrt/SDL_winrtevents_c.h +++ b/src/video/winrt/SDL_winrtevents_c.h @@ -46,9 +46,9 @@ extern void WINRT_PumpEvents(_THIS); #ifdef __cplusplus_winrt /* Pointers (Mice, Touch, etc.) */ -typedef enum { - NormalizeZeroToOne, - TransformToSDLWindowSize +typedef enum { + NormalizeZeroToOne, + TransformToSDLWindowSize } WINRT_CursorNormalizationType; extern Windows::Foundation::Point WINRT_TransformCursorPosition(SDL_Window * window, Windows::Foundation::Point rawPosition, diff --git a/src/video/winrt/SDL_winrtkeyboard.cpp b/src/video/winrt/SDL_winrtkeyboard.cpp index a68b6d50cbe8b..cb5f57dd7ed41 100644 --- a/src/video/winrt/SDL_winrtkeyboard.cpp +++ b/src/video/winrt/SDL_winrtkeyboard.cpp @@ -1,301 +1,301 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ #include "SDL_config.h" - -#if SDL_VIDEO_DRIVER_WINRT - -/* Standard C++11 includes */ -#include - - -/* Windows-specific includes */ -#include -#include - - -/* SDL-specific includes */ -#include -#include "SDL_winrtevents_c.h" - -extern "C" { -#include "../../events/scancodes_windows.h" -#include "../../events/SDL_keyboard_c.h" -} - - -static SDL_Scancode WinRT_Official_Keycodes[] = { - SDL_SCANCODE_UNKNOWN, // VirtualKey.None -- 0 - SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftButton -- 1 - SDL_SCANCODE_UNKNOWN, // VirtualKey.RightButton -- 2 - SDL_SCANCODE_CANCEL, // VirtualKey.Cancel -- 3 - SDL_SCANCODE_UNKNOWN, // VirtualKey.MiddleButton -- 4 - SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton1 -- 5 - SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton2 -- 6 - SDL_SCANCODE_UNKNOWN, // -- 7 - SDL_SCANCODE_BACKSPACE, // VirtualKey.Back -- 8 - SDL_SCANCODE_TAB, // VirtualKey.Tab -- 9 - SDL_SCANCODE_UNKNOWN, // -- 10 - SDL_SCANCODE_UNKNOWN, // -- 11 - SDL_SCANCODE_CLEAR, // VirtualKey.Clear -- 12 - SDL_SCANCODE_RETURN, // VirtualKey.Enter -- 13 - SDL_SCANCODE_UNKNOWN, // -- 14 - SDL_SCANCODE_UNKNOWN, // -- 15 - SDL_SCANCODE_LSHIFT, // VirtualKey.Shift -- 16 - SDL_SCANCODE_LCTRL, // VirtualKey.Control -- 17 - SDL_SCANCODE_MENU, // VirtualKey.Menu -- 18 - SDL_SCANCODE_PAUSE, // VirtualKey.Pause -- 19 - SDL_SCANCODE_CAPSLOCK, // VirtualKey.CapitalLock -- 20 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Kana or VirtualKey.Hangul -- 21 - SDL_SCANCODE_UNKNOWN, // -- 22 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Junja -- 23 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Final -- 24 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Hanja or VirtualKey.Kanji -- 25 - SDL_SCANCODE_UNKNOWN, // -- 26 - SDL_SCANCODE_ESCAPE, // VirtualKey.Escape -- 27 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Convert -- 28 - SDL_SCANCODE_UNKNOWN, // VirtualKey.NonConvert -- 29 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Accept -- 30 - SDL_SCANCODE_UNKNOWN, // VirtualKey.ModeChange -- 31 (maybe SDL_SCANCODE_MODE ?) - SDL_SCANCODE_SPACE, // VirtualKey.Space -- 32 - SDL_SCANCODE_PAGEUP, // VirtualKey.PageUp -- 33 - SDL_SCANCODE_PAGEDOWN, // VirtualKey.PageDown -- 34 - SDL_SCANCODE_END, // VirtualKey.End -- 35 - SDL_SCANCODE_HOME, // VirtualKey.Home -- 36 - SDL_SCANCODE_LEFT, // VirtualKey.Left -- 37 - SDL_SCANCODE_UP, // VirtualKey.Up -- 38 - SDL_SCANCODE_RIGHT, // VirtualKey.Right -- 39 - SDL_SCANCODE_DOWN, // VirtualKey.Down -- 40 - SDL_SCANCODE_SELECT, // VirtualKey.Select -- 41 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Print -- 42 (maybe SDL_SCANCODE_PRINTSCREEN ?) - SDL_SCANCODE_EXECUTE, // VirtualKey.Execute -- 43 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Snapshot -- 44 - SDL_SCANCODE_INSERT, // VirtualKey.Insert -- 45 - SDL_SCANCODE_DELETE, // VirtualKey.Delete -- 46 - SDL_SCANCODE_HELP, // VirtualKey.Help -- 47 - SDL_SCANCODE_0, // VirtualKey.Number0 -- 48 - SDL_SCANCODE_1, // VirtualKey.Number1 -- 49 - SDL_SCANCODE_2, // VirtualKey.Number2 -- 50 - SDL_SCANCODE_3, // VirtualKey.Number3 -- 51 - SDL_SCANCODE_4, // VirtualKey.Number4 -- 52 - SDL_SCANCODE_5, // VirtualKey.Number5 -- 53 - SDL_SCANCODE_6, // VirtualKey.Number6 -- 54 - SDL_SCANCODE_7, // VirtualKey.Number7 -- 55 - SDL_SCANCODE_8, // VirtualKey.Number8 -- 56 - SDL_SCANCODE_9, // VirtualKey.Number9 -- 57 - SDL_SCANCODE_UNKNOWN, // -- 58 - SDL_SCANCODE_UNKNOWN, // -- 59 - SDL_SCANCODE_UNKNOWN, // -- 60 - SDL_SCANCODE_UNKNOWN, // -- 61 - SDL_SCANCODE_UNKNOWN, // -- 62 - SDL_SCANCODE_UNKNOWN, // -- 63 - SDL_SCANCODE_UNKNOWN, // -- 64 - SDL_SCANCODE_A, // VirtualKey.A -- 65 - SDL_SCANCODE_B, // VirtualKey.B -- 66 - SDL_SCANCODE_C, // VirtualKey.C -- 67 - SDL_SCANCODE_D, // VirtualKey.D -- 68 - SDL_SCANCODE_E, // VirtualKey.E -- 69 - SDL_SCANCODE_F, // VirtualKey.F -- 70 - SDL_SCANCODE_G, // VirtualKey.G -- 71 - SDL_SCANCODE_H, // VirtualKey.H -- 72 - SDL_SCANCODE_I, // VirtualKey.I -- 73 - SDL_SCANCODE_J, // VirtualKey.J -- 74 - SDL_SCANCODE_K, // VirtualKey.K -- 75 - SDL_SCANCODE_L, // VirtualKey.L -- 76 - SDL_SCANCODE_M, // VirtualKey.M -- 77 - SDL_SCANCODE_N, // VirtualKey.N -- 78 - SDL_SCANCODE_O, // VirtualKey.O -- 79 - SDL_SCANCODE_P, // VirtualKey.P -- 80 - SDL_SCANCODE_Q, // VirtualKey.Q -- 81 - SDL_SCANCODE_R, // VirtualKey.R -- 82 - SDL_SCANCODE_S, // VirtualKey.S -- 83 - SDL_SCANCODE_T, // VirtualKey.T -- 84 - SDL_SCANCODE_U, // VirtualKey.U -- 85 - SDL_SCANCODE_V, // VirtualKey.V -- 86 - SDL_SCANCODE_W, // VirtualKey.W -- 87 - SDL_SCANCODE_X, // VirtualKey.X -- 88 - SDL_SCANCODE_Y, // VirtualKey.Y -- 89 - SDL_SCANCODE_Z, // VirtualKey.Z -- 90 - SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftWindows -- 91 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_LGUI ?) - SDL_SCANCODE_UNKNOWN, // VirtualKey.RightWindows -- 92 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_RGUI ?) - SDL_SCANCODE_APPLICATION, // VirtualKey.Application -- 93 - SDL_SCANCODE_UNKNOWN, // -- 94 - SDL_SCANCODE_SLEEP, // VirtualKey.Sleep -- 95 - SDL_SCANCODE_KP_0, // VirtualKey.NumberPad0 -- 96 - SDL_SCANCODE_KP_1, // VirtualKey.NumberPad1 -- 97 - SDL_SCANCODE_KP_2, // VirtualKey.NumberPad2 -- 98 - SDL_SCANCODE_KP_3, // VirtualKey.NumberPad3 -- 99 - SDL_SCANCODE_KP_4, // VirtualKey.NumberPad4 -- 100 - SDL_SCANCODE_KP_5, // VirtualKey.NumberPad5 -- 101 - SDL_SCANCODE_KP_6, // VirtualKey.NumberPad6 -- 102 - SDL_SCANCODE_KP_7, // VirtualKey.NumberPad7 -- 103 - SDL_SCANCODE_KP_8, // VirtualKey.NumberPad8 -- 104 - SDL_SCANCODE_KP_9, // VirtualKey.NumberPad9 -- 105 - SDL_SCANCODE_KP_MULTIPLY, // VirtualKey.Multiply -- 106 - SDL_SCANCODE_KP_PLUS, // VirtualKey.Add -- 107 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Separator -- 108 - SDL_SCANCODE_KP_MINUS, // VirtualKey.Subtract -- 109 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Decimal -- 110 (maybe SDL_SCANCODE_DECIMALSEPARATOR, SDL_SCANCODE_KP_DECIMAL, or SDL_SCANCODE_KP_PERIOD ?) - SDL_SCANCODE_KP_DIVIDE, // VirtualKey.Divide -- 111 - SDL_SCANCODE_F1, // VirtualKey.F1 -- 112 - SDL_SCANCODE_F2, // VirtualKey.F2 -- 113 - SDL_SCANCODE_F3, // VirtualKey.F3 -- 114 - SDL_SCANCODE_F4, // VirtualKey.F4 -- 115 - SDL_SCANCODE_F5, // VirtualKey.F5 -- 116 - SDL_SCANCODE_F6, // VirtualKey.F6 -- 117 - SDL_SCANCODE_F7, // VirtualKey.F7 -- 118 - SDL_SCANCODE_F8, // VirtualKey.F8 -- 119 - SDL_SCANCODE_F9, // VirtualKey.F9 -- 120 - SDL_SCANCODE_F10, // VirtualKey.F10 -- 121 - SDL_SCANCODE_F11, // VirtualKey.F11 -- 122 - SDL_SCANCODE_F12, // VirtualKey.F12 -- 123 - SDL_SCANCODE_F13, // VirtualKey.F13 -- 124 - SDL_SCANCODE_F14, // VirtualKey.F14 -- 125 - SDL_SCANCODE_F15, // VirtualKey.F15 -- 126 - SDL_SCANCODE_F16, // VirtualKey.F16 -- 127 - SDL_SCANCODE_F17, // VirtualKey.F17 -- 128 - SDL_SCANCODE_F18, // VirtualKey.F18 -- 129 - SDL_SCANCODE_F19, // VirtualKey.F19 -- 130 - SDL_SCANCODE_F20, // VirtualKey.F20 -- 131 - SDL_SCANCODE_F21, // VirtualKey.F21 -- 132 - SDL_SCANCODE_F22, // VirtualKey.F22 -- 133 - SDL_SCANCODE_F23, // VirtualKey.F23 -- 134 - SDL_SCANCODE_F24, // VirtualKey.F24 -- 135 - SDL_SCANCODE_UNKNOWN, // -- 136 - SDL_SCANCODE_UNKNOWN, // -- 137 - SDL_SCANCODE_UNKNOWN, // -- 138 - SDL_SCANCODE_UNKNOWN, // -- 139 - SDL_SCANCODE_UNKNOWN, // -- 140 - SDL_SCANCODE_UNKNOWN, // -- 141 - SDL_SCANCODE_UNKNOWN, // -- 142 - SDL_SCANCODE_UNKNOWN, // -- 143 - SDL_SCANCODE_NUMLOCKCLEAR, // VirtualKey.NumberKeyLock -- 144 - SDL_SCANCODE_SCROLLLOCK, // VirtualKey.Scroll -- 145 - SDL_SCANCODE_UNKNOWN, // -- 146 - SDL_SCANCODE_UNKNOWN, // -- 147 - SDL_SCANCODE_UNKNOWN, // -- 148 - SDL_SCANCODE_UNKNOWN, // -- 149 - SDL_SCANCODE_UNKNOWN, // -- 150 - SDL_SCANCODE_UNKNOWN, // -- 151 - SDL_SCANCODE_UNKNOWN, // -- 152 - SDL_SCANCODE_UNKNOWN, // -- 153 - SDL_SCANCODE_UNKNOWN, // -- 154 - SDL_SCANCODE_UNKNOWN, // -- 155 - SDL_SCANCODE_UNKNOWN, // -- 156 - SDL_SCANCODE_UNKNOWN, // -- 157 - SDL_SCANCODE_UNKNOWN, // -- 158 - SDL_SCANCODE_UNKNOWN, // -- 159 - SDL_SCANCODE_LSHIFT, // VirtualKey.LeftShift -- 160 - SDL_SCANCODE_RSHIFT, // VirtualKey.RightShift -- 161 - SDL_SCANCODE_LCTRL, // VirtualKey.LeftControl -- 162 - SDL_SCANCODE_RCTRL, // VirtualKey.RightControl -- 163 - SDL_SCANCODE_MENU, // VirtualKey.LeftMenu -- 164 - SDL_SCANCODE_MENU, // VirtualKey.RightMenu -- 165 -}; - -static std::unordered_map WinRT_Unofficial_Keycodes; - -static SDL_Scancode -TranslateKeycode(int keycode) -{ - if (WinRT_Unofficial_Keycodes.empty()) { - /* Set up a table of undocumented (by Microsoft), WinRT-specific, - key codes: */ - // TODO, WinRT: move content declarations of WinRT_Unofficial_Keycodes into a C++11 initializer list, when possible - WinRT_Unofficial_Keycodes[220] = SDL_SCANCODE_GRAVE; - WinRT_Unofficial_Keycodes[222] = SDL_SCANCODE_BACKSLASH; - } - - /* Try to get a documented, WinRT, 'VirtualKey' first (as documented at - http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.virtualkey.aspx ). - If that fails, fall back to a Win32 virtual key. - */ - // TODO, WinRT: try filling out the WinRT keycode table as much as possible, using the Win32 table for interpretation hints - //SDL_Log("WinRT TranslateKeycode, keycode=%d\n", (int)keycode); - SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; - if (keycode < SDL_arraysize(WinRT_Official_Keycodes)) { - scancode = WinRT_Official_Keycodes[keycode]; - } - if (scancode == SDL_SCANCODE_UNKNOWN) { - if (WinRT_Unofficial_Keycodes.find(keycode) != WinRT_Unofficial_Keycodes.end()) { - scancode = WinRT_Unofficial_Keycodes[keycode]; - } - } - if (scancode == SDL_SCANCODE_UNKNOWN) { - if (keycode < SDL_arraysize(windows_scancode_table)) { - scancode = windows_scancode_table[keycode]; - } - } - if (scancode == SDL_SCANCODE_UNKNOWN) { - SDL_Log("WinRT TranslateKeycode, unknown keycode=%d\n", (int)keycode); - } - return scancode; -} - -void -WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args) -{ - SDL_Scancode sdlScancode = TranslateKeycode((int)args->VirtualKey); -#if 0 - SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode); - SDL_Log("key down, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, native scan code=%d, was down?=%s, vkey=%d, sdl scan code=%d (%s), sdl key code=%d (%s)\n", - (args->Handled ? "1" : "0"), - (args->KeyStatus.IsExtendedKey ? "1" : "0"), - (args->KeyStatus.IsKeyReleased ? "1" : "0"), - (args->KeyStatus.IsMenuKeyDown ? "1" : "0"), - args->KeyStatus.RepeatCount, - args->KeyStatus.ScanCode, - (args->KeyStatus.WasKeyDown ? "1" : "0"), - args->VirtualKey, - sdlScancode, - SDL_GetScancodeName(sdlScancode), - keycode, - SDL_GetKeyName(keycode)); - //args->Handled = true; - //VirtualKey vkey = args->VirtualKey; -#endif - SDL_SendKeyboardKey(SDL_PRESSED, sdlScancode); -} - -void -WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args) -{ - SDL_Scancode sdlScancode = TranslateKeycode((int)args->VirtualKey); -#if 0 - SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode); - SDL_Log("key up, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, native scan code=%d, was down?=%s, vkey=%d, sdl scan code=%d (%s), sdl key code=%d (%s)\n", - (args->Handled ? "1" : "0"), - (args->KeyStatus.IsExtendedKey ? "1" : "0"), - (args->KeyStatus.IsKeyReleased ? "1" : "0"), - (args->KeyStatus.IsMenuKeyDown ? "1" : "0"), - args->KeyStatus.RepeatCount, - args->KeyStatus.ScanCode, - (args->KeyStatus.WasKeyDown ? "1" : "0"), - args->VirtualKey, - sdlScancode, - SDL_GetScancodeName(sdlScancode), - keycode, - SDL_GetKeyName(keycode)); - //args->Handled = true; -#endif - SDL_SendKeyboardKey(SDL_RELEASED, sdlScancode); -} - -#endif // SDL_VIDEO_DRIVER_WINRT + +#if SDL_VIDEO_DRIVER_WINRT + +/* Standard C++11 includes */ +#include + + +/* Windows-specific includes */ +#include +#include + + +/* SDL-specific includes */ +#include +#include "SDL_winrtevents_c.h" + +extern "C" { +#include "../../events/scancodes_windows.h" +#include "../../events/SDL_keyboard_c.h" +} + + +static SDL_Scancode WinRT_Official_Keycodes[] = { + SDL_SCANCODE_UNKNOWN, // VirtualKey.None -- 0 + SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftButton -- 1 + SDL_SCANCODE_UNKNOWN, // VirtualKey.RightButton -- 2 + SDL_SCANCODE_CANCEL, // VirtualKey.Cancel -- 3 + SDL_SCANCODE_UNKNOWN, // VirtualKey.MiddleButton -- 4 + SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton1 -- 5 + SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton2 -- 6 + SDL_SCANCODE_UNKNOWN, // -- 7 + SDL_SCANCODE_BACKSPACE, // VirtualKey.Back -- 8 + SDL_SCANCODE_TAB, // VirtualKey.Tab -- 9 + SDL_SCANCODE_UNKNOWN, // -- 10 + SDL_SCANCODE_UNKNOWN, // -- 11 + SDL_SCANCODE_CLEAR, // VirtualKey.Clear -- 12 + SDL_SCANCODE_RETURN, // VirtualKey.Enter -- 13 + SDL_SCANCODE_UNKNOWN, // -- 14 + SDL_SCANCODE_UNKNOWN, // -- 15 + SDL_SCANCODE_LSHIFT, // VirtualKey.Shift -- 16 + SDL_SCANCODE_LCTRL, // VirtualKey.Control -- 17 + SDL_SCANCODE_MENU, // VirtualKey.Menu -- 18 + SDL_SCANCODE_PAUSE, // VirtualKey.Pause -- 19 + SDL_SCANCODE_CAPSLOCK, // VirtualKey.CapitalLock -- 20 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Kana or VirtualKey.Hangul -- 21 + SDL_SCANCODE_UNKNOWN, // -- 22 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Junja -- 23 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Final -- 24 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Hanja or VirtualKey.Kanji -- 25 + SDL_SCANCODE_UNKNOWN, // -- 26 + SDL_SCANCODE_ESCAPE, // VirtualKey.Escape -- 27 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Convert -- 28 + SDL_SCANCODE_UNKNOWN, // VirtualKey.NonConvert -- 29 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Accept -- 30 + SDL_SCANCODE_UNKNOWN, // VirtualKey.ModeChange -- 31 (maybe SDL_SCANCODE_MODE ?) + SDL_SCANCODE_SPACE, // VirtualKey.Space -- 32 + SDL_SCANCODE_PAGEUP, // VirtualKey.PageUp -- 33 + SDL_SCANCODE_PAGEDOWN, // VirtualKey.PageDown -- 34 + SDL_SCANCODE_END, // VirtualKey.End -- 35 + SDL_SCANCODE_HOME, // VirtualKey.Home -- 36 + SDL_SCANCODE_LEFT, // VirtualKey.Left -- 37 + SDL_SCANCODE_UP, // VirtualKey.Up -- 38 + SDL_SCANCODE_RIGHT, // VirtualKey.Right -- 39 + SDL_SCANCODE_DOWN, // VirtualKey.Down -- 40 + SDL_SCANCODE_SELECT, // VirtualKey.Select -- 41 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Print -- 42 (maybe SDL_SCANCODE_PRINTSCREEN ?) + SDL_SCANCODE_EXECUTE, // VirtualKey.Execute -- 43 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Snapshot -- 44 + SDL_SCANCODE_INSERT, // VirtualKey.Insert -- 45 + SDL_SCANCODE_DELETE, // VirtualKey.Delete -- 46 + SDL_SCANCODE_HELP, // VirtualKey.Help -- 47 + SDL_SCANCODE_0, // VirtualKey.Number0 -- 48 + SDL_SCANCODE_1, // VirtualKey.Number1 -- 49 + SDL_SCANCODE_2, // VirtualKey.Number2 -- 50 + SDL_SCANCODE_3, // VirtualKey.Number3 -- 51 + SDL_SCANCODE_4, // VirtualKey.Number4 -- 52 + SDL_SCANCODE_5, // VirtualKey.Number5 -- 53 + SDL_SCANCODE_6, // VirtualKey.Number6 -- 54 + SDL_SCANCODE_7, // VirtualKey.Number7 -- 55 + SDL_SCANCODE_8, // VirtualKey.Number8 -- 56 + SDL_SCANCODE_9, // VirtualKey.Number9 -- 57 + SDL_SCANCODE_UNKNOWN, // -- 58 + SDL_SCANCODE_UNKNOWN, // -- 59 + SDL_SCANCODE_UNKNOWN, // -- 60 + SDL_SCANCODE_UNKNOWN, // -- 61 + SDL_SCANCODE_UNKNOWN, // -- 62 + SDL_SCANCODE_UNKNOWN, // -- 63 + SDL_SCANCODE_UNKNOWN, // -- 64 + SDL_SCANCODE_A, // VirtualKey.A -- 65 + SDL_SCANCODE_B, // VirtualKey.B -- 66 + SDL_SCANCODE_C, // VirtualKey.C -- 67 + SDL_SCANCODE_D, // VirtualKey.D -- 68 + SDL_SCANCODE_E, // VirtualKey.E -- 69 + SDL_SCANCODE_F, // VirtualKey.F -- 70 + SDL_SCANCODE_G, // VirtualKey.G -- 71 + SDL_SCANCODE_H, // VirtualKey.H -- 72 + SDL_SCANCODE_I, // VirtualKey.I -- 73 + SDL_SCANCODE_J, // VirtualKey.J -- 74 + SDL_SCANCODE_K, // VirtualKey.K -- 75 + SDL_SCANCODE_L, // VirtualKey.L -- 76 + SDL_SCANCODE_M, // VirtualKey.M -- 77 + SDL_SCANCODE_N, // VirtualKey.N -- 78 + SDL_SCANCODE_O, // VirtualKey.O -- 79 + SDL_SCANCODE_P, // VirtualKey.P -- 80 + SDL_SCANCODE_Q, // VirtualKey.Q -- 81 + SDL_SCANCODE_R, // VirtualKey.R -- 82 + SDL_SCANCODE_S, // VirtualKey.S -- 83 + SDL_SCANCODE_T, // VirtualKey.T -- 84 + SDL_SCANCODE_U, // VirtualKey.U -- 85 + SDL_SCANCODE_V, // VirtualKey.V -- 86 + SDL_SCANCODE_W, // VirtualKey.W -- 87 + SDL_SCANCODE_X, // VirtualKey.X -- 88 + SDL_SCANCODE_Y, // VirtualKey.Y -- 89 + SDL_SCANCODE_Z, // VirtualKey.Z -- 90 + SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftWindows -- 91 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_LGUI ?) + SDL_SCANCODE_UNKNOWN, // VirtualKey.RightWindows -- 92 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_RGUI ?) + SDL_SCANCODE_APPLICATION, // VirtualKey.Application -- 93 + SDL_SCANCODE_UNKNOWN, // -- 94 + SDL_SCANCODE_SLEEP, // VirtualKey.Sleep -- 95 + SDL_SCANCODE_KP_0, // VirtualKey.NumberPad0 -- 96 + SDL_SCANCODE_KP_1, // VirtualKey.NumberPad1 -- 97 + SDL_SCANCODE_KP_2, // VirtualKey.NumberPad2 -- 98 + SDL_SCANCODE_KP_3, // VirtualKey.NumberPad3 -- 99 + SDL_SCANCODE_KP_4, // VirtualKey.NumberPad4 -- 100 + SDL_SCANCODE_KP_5, // VirtualKey.NumberPad5 -- 101 + SDL_SCANCODE_KP_6, // VirtualKey.NumberPad6 -- 102 + SDL_SCANCODE_KP_7, // VirtualKey.NumberPad7 -- 103 + SDL_SCANCODE_KP_8, // VirtualKey.NumberPad8 -- 104 + SDL_SCANCODE_KP_9, // VirtualKey.NumberPad9 -- 105 + SDL_SCANCODE_KP_MULTIPLY, // VirtualKey.Multiply -- 106 + SDL_SCANCODE_KP_PLUS, // VirtualKey.Add -- 107 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Separator -- 108 + SDL_SCANCODE_KP_MINUS, // VirtualKey.Subtract -- 109 + SDL_SCANCODE_UNKNOWN, // VirtualKey.Decimal -- 110 (maybe SDL_SCANCODE_DECIMALSEPARATOR, SDL_SCANCODE_KP_DECIMAL, or SDL_SCANCODE_KP_PERIOD ?) + SDL_SCANCODE_KP_DIVIDE, // VirtualKey.Divide -- 111 + SDL_SCANCODE_F1, // VirtualKey.F1 -- 112 + SDL_SCANCODE_F2, // VirtualKey.F2 -- 113 + SDL_SCANCODE_F3, // VirtualKey.F3 -- 114 + SDL_SCANCODE_F4, // VirtualKey.F4 -- 115 + SDL_SCANCODE_F5, // VirtualKey.F5 -- 116 + SDL_SCANCODE_F6, // VirtualKey.F6 -- 117 + SDL_SCANCODE_F7, // VirtualKey.F7 -- 118 + SDL_SCANCODE_F8, // VirtualKey.F8 -- 119 + SDL_SCANCODE_F9, // VirtualKey.F9 -- 120 + SDL_SCANCODE_F10, // VirtualKey.F10 -- 121 + SDL_SCANCODE_F11, // VirtualKey.F11 -- 122 + SDL_SCANCODE_F12, // VirtualKey.F12 -- 123 + SDL_SCANCODE_F13, // VirtualKey.F13 -- 124 + SDL_SCANCODE_F14, // VirtualKey.F14 -- 125 + SDL_SCANCODE_F15, // VirtualKey.F15 -- 126 + SDL_SCANCODE_F16, // VirtualKey.F16 -- 127 + SDL_SCANCODE_F17, // VirtualKey.F17 -- 128 + SDL_SCANCODE_F18, // VirtualKey.F18 -- 129 + SDL_SCANCODE_F19, // VirtualKey.F19 -- 130 + SDL_SCANCODE_F20, // VirtualKey.F20 -- 131 + SDL_SCANCODE_F21, // VirtualKey.F21 -- 132 + SDL_SCANCODE_F22, // VirtualKey.F22 -- 133 + SDL_SCANCODE_F23, // VirtualKey.F23 -- 134 + SDL_SCANCODE_F24, // VirtualKey.F24 -- 135 + SDL_SCANCODE_UNKNOWN, // -- 136 + SDL_SCANCODE_UNKNOWN, // -- 137 + SDL_SCANCODE_UNKNOWN, // -- 138 + SDL_SCANCODE_UNKNOWN, // -- 139 + SDL_SCANCODE_UNKNOWN, // -- 140 + SDL_SCANCODE_UNKNOWN, // -- 141 + SDL_SCANCODE_UNKNOWN, // -- 142 + SDL_SCANCODE_UNKNOWN, // -- 143 + SDL_SCANCODE_NUMLOCKCLEAR, // VirtualKey.NumberKeyLock -- 144 + SDL_SCANCODE_SCROLLLOCK, // VirtualKey.Scroll -- 145 + SDL_SCANCODE_UNKNOWN, // -- 146 + SDL_SCANCODE_UNKNOWN, // -- 147 + SDL_SCANCODE_UNKNOWN, // -- 148 + SDL_SCANCODE_UNKNOWN, // -- 149 + SDL_SCANCODE_UNKNOWN, // -- 150 + SDL_SCANCODE_UNKNOWN, // -- 151 + SDL_SCANCODE_UNKNOWN, // -- 152 + SDL_SCANCODE_UNKNOWN, // -- 153 + SDL_SCANCODE_UNKNOWN, // -- 154 + SDL_SCANCODE_UNKNOWN, // -- 155 + SDL_SCANCODE_UNKNOWN, // -- 156 + SDL_SCANCODE_UNKNOWN, // -- 157 + SDL_SCANCODE_UNKNOWN, // -- 158 + SDL_SCANCODE_UNKNOWN, // -- 159 + SDL_SCANCODE_LSHIFT, // VirtualKey.LeftShift -- 160 + SDL_SCANCODE_RSHIFT, // VirtualKey.RightShift -- 161 + SDL_SCANCODE_LCTRL, // VirtualKey.LeftControl -- 162 + SDL_SCANCODE_RCTRL, // VirtualKey.RightControl -- 163 + SDL_SCANCODE_MENU, // VirtualKey.LeftMenu -- 164 + SDL_SCANCODE_MENU, // VirtualKey.RightMenu -- 165 +}; + +static std::unordered_map WinRT_Unofficial_Keycodes; + +static SDL_Scancode +TranslateKeycode(int keycode) +{ + if (WinRT_Unofficial_Keycodes.empty()) { + /* Set up a table of undocumented (by Microsoft), WinRT-specific, + key codes: */ + // TODO, WinRT: move content declarations of WinRT_Unofficial_Keycodes into a C++11 initializer list, when possible + WinRT_Unofficial_Keycodes[220] = SDL_SCANCODE_GRAVE; + WinRT_Unofficial_Keycodes[222] = SDL_SCANCODE_BACKSLASH; + } + + /* Try to get a documented, WinRT, 'VirtualKey' first (as documented at + http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.virtualkey.aspx ). + If that fails, fall back to a Win32 virtual key. + */ + // TODO, WinRT: try filling out the WinRT keycode table as much as possible, using the Win32 table for interpretation hints + //SDL_Log("WinRT TranslateKeycode, keycode=%d\n", (int)keycode); + SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; + if (keycode < SDL_arraysize(WinRT_Official_Keycodes)) { + scancode = WinRT_Official_Keycodes[keycode]; + } + if (scancode == SDL_SCANCODE_UNKNOWN) { + if (WinRT_Unofficial_Keycodes.find(keycode) != WinRT_Unofficial_Keycodes.end()) { + scancode = WinRT_Unofficial_Keycodes[keycode]; + } + } + if (scancode == SDL_SCANCODE_UNKNOWN) { + if (keycode < SDL_arraysize(windows_scancode_table)) { + scancode = windows_scancode_table[keycode]; + } + } + if (scancode == SDL_SCANCODE_UNKNOWN) { + SDL_Log("WinRT TranslateKeycode, unknown keycode=%d\n", (int)keycode); + } + return scancode; +} + +void +WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args) +{ + SDL_Scancode sdlScancode = TranslateKeycode((int)args->VirtualKey); +#if 0 + SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode); + SDL_Log("key down, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, native scan code=%d, was down?=%s, vkey=%d, sdl scan code=%d (%s), sdl key code=%d (%s)\n", + (args->Handled ? "1" : "0"), + (args->KeyStatus.IsExtendedKey ? "1" : "0"), + (args->KeyStatus.IsKeyReleased ? "1" : "0"), + (args->KeyStatus.IsMenuKeyDown ? "1" : "0"), + args->KeyStatus.RepeatCount, + args->KeyStatus.ScanCode, + (args->KeyStatus.WasKeyDown ? "1" : "0"), + args->VirtualKey, + sdlScancode, + SDL_GetScancodeName(sdlScancode), + keycode, + SDL_GetKeyName(keycode)); + //args->Handled = true; + //VirtualKey vkey = args->VirtualKey; +#endif + SDL_SendKeyboardKey(SDL_PRESSED, sdlScancode); +} + +void +WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args) +{ + SDL_Scancode sdlScancode = TranslateKeycode((int)args->VirtualKey); +#if 0 + SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode); + SDL_Log("key up, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, native scan code=%d, was down?=%s, vkey=%d, sdl scan code=%d (%s), sdl key code=%d (%s)\n", + (args->Handled ? "1" : "0"), + (args->KeyStatus.IsExtendedKey ? "1" : "0"), + (args->KeyStatus.IsKeyReleased ? "1" : "0"), + (args->KeyStatus.IsMenuKeyDown ? "1" : "0"), + args->KeyStatus.RepeatCount, + args->KeyStatus.ScanCode, + (args->KeyStatus.WasKeyDown ? "1" : "0"), + args->VirtualKey, + sdlScancode, + SDL_GetScancodeName(sdlScancode), + keycode, + SDL_GetKeyName(keycode)); + //args->Handled = true; +#endif + SDL_SendKeyboardKey(SDL_RELEASED, sdlScancode); +} + +#endif // SDL_VIDEO_DRIVER_WINRT diff --git a/src/video/winrt/SDL_winrtmouse.cpp b/src/video/winrt/SDL_winrtmouse.cpp index c2605e47f1328..3e896f7f0a005 100644 --- a/src/video/winrt/SDL_winrtmouse.cpp +++ b/src/video/winrt/SDL_winrtmouse.cpp @@ -1,166 +1,166 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2012 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "SDL_config.h" - -#if SDL_VIDEO_DRIVER_WINRT - -/* - * Windows includes: - */ -#include -using namespace Windows::UI::Core; -using Windows::UI::Core::CoreCursor; - -/* - * SDL includes: - */ -extern "C" { -#include "SDL_assert.h" -#include "../../events/SDL_mouse_c.h" -#include "../../events/SDL_touch_c.h" -#include "../SDL_sysvideo.h" -#include "SDL_events.h" -#include "SDL_log.h" -} - -#include "../../core/winrt/SDL_winrtapp_direct3d.h" -#include "SDL_winrtvideo_cpp.h" -#include "SDL_winrtmouse_c.h" - - -extern "C" SDL_bool WINRT_UsingRelativeMouseMode = SDL_FALSE; - - -static SDL_Cursor * -WINRT_CreateSystemCursor(SDL_SystemCursor id) -{ - SDL_Cursor *cursor; - CoreCursorType cursorType = CoreCursorType::Arrow; - - switch(id) - { - default: - SDL_assert(0); - return NULL; - case SDL_SYSTEM_CURSOR_ARROW: cursorType = CoreCursorType::Arrow; break; - case SDL_SYSTEM_CURSOR_IBEAM: cursorType = CoreCursorType::IBeam; break; - case SDL_SYSTEM_CURSOR_WAIT: cursorType = CoreCursorType::Wait; break; - case SDL_SYSTEM_CURSOR_CROSSHAIR: cursorType = CoreCursorType::Cross; break; - case SDL_SYSTEM_CURSOR_WAITARROW: cursorType = CoreCursorType::Wait; break; - case SDL_SYSTEM_CURSOR_SIZENWSE: cursorType = CoreCursorType::SizeNorthwestSoutheast; break; - case SDL_SYSTEM_CURSOR_SIZENESW: cursorType = CoreCursorType::SizeNortheastSouthwest; break; - case SDL_SYSTEM_CURSOR_SIZEWE: cursorType = CoreCursorType::SizeWestEast; break; - case SDL_SYSTEM_CURSOR_SIZENS: cursorType = CoreCursorType::SizeNorthSouth; break; - case SDL_SYSTEM_CURSOR_SIZEALL: cursorType = CoreCursorType::SizeAll; break; - case SDL_SYSTEM_CURSOR_NO: cursorType = CoreCursorType::UniversalNo; break; - case SDL_SYSTEM_CURSOR_HAND: cursorType = CoreCursorType::Hand; break; - } - - cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor)); - if (cursor) { - /* Create a pointer to a COM reference to a cursor. The extra - pointer is used (on top of the COM reference) to allow the cursor - to be referenced by the SDL_cursor's driverdata field, which is - a void pointer. - */ - CoreCursor ^* theCursor = new CoreCursor^(nullptr); - *theCursor = ref new CoreCursor(cursorType, 0); - cursor->driverdata = (void *) theCursor; - } else { - SDL_OutOfMemory(); - } - - return cursor; -} - -static SDL_Cursor * -WINRT_CreateDefaultCursor() -{ - return WINRT_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); -} - -static void -WINRT_FreeCursor(SDL_Cursor * cursor) -{ - if (cursor->driverdata) { - CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata; - *theCursor = nullptr; // Release the COM reference to the CoreCursor - delete theCursor; // Delete the pointer to the COM reference - } - SDL_free(cursor); -} - -static int -WINRT_ShowCursor(SDL_Cursor * cursor) -{ - // TODO, WinRT, XAML: make WINRT_ShowCursor work when XAML support is enabled. - if ( ! CoreWindow::GetForCurrentThread()) { - return 0; - } - - if (cursor) { - CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata; - CoreWindow::GetForCurrentThread()->PointerCursor = *theCursor; - } else { - CoreWindow::GetForCurrentThread()->PointerCursor = nullptr; - } - return 0; -} - -static int -WINRT_SetRelativeMouseMode(SDL_bool enabled) -{ - WINRT_UsingRelativeMouseMode = enabled; - return 0; -} - -void -WINRT_InitMouse(_THIS) -{ - SDL_Mouse *mouse = SDL_GetMouse(); - - /* DLudwig, Dec 3, 2012: WinRT does not currently provide APIs for - the following features, AFAIK: - - custom cursors (multiple system cursors are, however, available) - - programmatically moveable cursors - */ - -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP - //mouse->CreateCursor = WINRT_CreateCursor; - mouse->CreateSystemCursor = WINRT_CreateSystemCursor; - mouse->ShowCursor = WINRT_ShowCursor; - mouse->FreeCursor = WINRT_FreeCursor; - //mouse->WarpMouse = WINRT_WarpMouse; - mouse->SetRelativeMouseMode = WINRT_SetRelativeMouseMode; - - SDL_SetDefaultCursor(WINRT_CreateDefaultCursor()); -#endif -} - -void -WINRT_QuitMouse(_THIS) -{ -} - -#endif /* SDL_VIDEO_DRIVER_WINRT */ - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SDL_config.h" + +#if SDL_VIDEO_DRIVER_WINRT + +/* + * Windows includes: + */ +#include +using namespace Windows::UI::Core; +using Windows::UI::Core::CoreCursor; + +/* + * SDL includes: + */ +extern "C" { +#include "SDL_assert.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_touch_c.h" +#include "../SDL_sysvideo.h" +#include "SDL_events.h" +#include "SDL_log.h" +} + +#include "../../core/winrt/SDL_winrtapp_direct3d.h" +#include "SDL_winrtvideo_cpp.h" +#include "SDL_winrtmouse_c.h" + + +extern "C" SDL_bool WINRT_UsingRelativeMouseMode = SDL_FALSE; + + +static SDL_Cursor * +WINRT_CreateSystemCursor(SDL_SystemCursor id) +{ + SDL_Cursor *cursor; + CoreCursorType cursorType = CoreCursorType::Arrow; + + switch(id) + { + default: + SDL_assert(0); + return NULL; + case SDL_SYSTEM_CURSOR_ARROW: cursorType = CoreCursorType::Arrow; break; + case SDL_SYSTEM_CURSOR_IBEAM: cursorType = CoreCursorType::IBeam; break; + case SDL_SYSTEM_CURSOR_WAIT: cursorType = CoreCursorType::Wait; break; + case SDL_SYSTEM_CURSOR_CROSSHAIR: cursorType = CoreCursorType::Cross; break; + case SDL_SYSTEM_CURSOR_WAITARROW: cursorType = CoreCursorType::Wait; break; + case SDL_SYSTEM_CURSOR_SIZENWSE: cursorType = CoreCursorType::SizeNorthwestSoutheast; break; + case SDL_SYSTEM_CURSOR_SIZENESW: cursorType = CoreCursorType::SizeNortheastSouthwest; break; + case SDL_SYSTEM_CURSOR_SIZEWE: cursorType = CoreCursorType::SizeWestEast; break; + case SDL_SYSTEM_CURSOR_SIZENS: cursorType = CoreCursorType::SizeNorthSouth; break; + case SDL_SYSTEM_CURSOR_SIZEALL: cursorType = CoreCursorType::SizeAll; break; + case SDL_SYSTEM_CURSOR_NO: cursorType = CoreCursorType::UniversalNo; break; + case SDL_SYSTEM_CURSOR_HAND: cursorType = CoreCursorType::Hand; break; + } + + cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor)); + if (cursor) { + /* Create a pointer to a COM reference to a cursor. The extra + pointer is used (on top of the COM reference) to allow the cursor + to be referenced by the SDL_cursor's driverdata field, which is + a void pointer. + */ + CoreCursor ^* theCursor = new CoreCursor^(nullptr); + *theCursor = ref new CoreCursor(cursorType, 0); + cursor->driverdata = (void *) theCursor; + } else { + SDL_OutOfMemory(); + } + + return cursor; +} + +static SDL_Cursor * +WINRT_CreateDefaultCursor() +{ + return WINRT_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); +} + +static void +WINRT_FreeCursor(SDL_Cursor * cursor) +{ + if (cursor->driverdata) { + CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata; + *theCursor = nullptr; // Release the COM reference to the CoreCursor + delete theCursor; // Delete the pointer to the COM reference + } + SDL_free(cursor); +} + +static int +WINRT_ShowCursor(SDL_Cursor * cursor) +{ + // TODO, WinRT, XAML: make WINRT_ShowCursor work when XAML support is enabled. + if ( ! CoreWindow::GetForCurrentThread()) { + return 0; + } + + if (cursor) { + CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata; + CoreWindow::GetForCurrentThread()->PointerCursor = *theCursor; + } else { + CoreWindow::GetForCurrentThread()->PointerCursor = nullptr; + } + return 0; +} + +static int +WINRT_SetRelativeMouseMode(SDL_bool enabled) +{ + WINRT_UsingRelativeMouseMode = enabled; + return 0; +} + +void +WINRT_InitMouse(_THIS) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + /* DLudwig, Dec 3, 2012: WinRT does not currently provide APIs for + the following features, AFAIK: + - custom cursors (multiple system cursors are, however, available) + - programmatically moveable cursors + */ + +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + //mouse->CreateCursor = WINRT_CreateCursor; + mouse->CreateSystemCursor = WINRT_CreateSystemCursor; + mouse->ShowCursor = WINRT_ShowCursor; + mouse->FreeCursor = WINRT_FreeCursor; + //mouse->WarpMouse = WINRT_WarpMouse; + mouse->SetRelativeMouseMode = WINRT_SetRelativeMouseMode; + + SDL_SetDefaultCursor(WINRT_CreateDefaultCursor()); +#endif +} + +void +WINRT_QuitMouse(_THIS) +{ +} + +#endif /* SDL_VIDEO_DRIVER_WINRT */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtopengles.cpp b/src/video/winrt/SDL_winrtopengles.cpp index f6cdeaec66ce1..1229eb9bfcd86 100644 --- a/src/video/winrt/SDL_winrtopengles.cpp +++ b/src/video/winrt/SDL_winrtopengles.cpp @@ -1,50 +1,50 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_config.h" - -// TODO: WinRT, make this file compile via C code - -#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL - -/* EGL implementation of SDL OpenGL support */ - -#include "SDL_winrtvideo_cpp.h" -extern "C" { -#include "SDL_winrtopengles.h" -} - -#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((NativeDisplayType) -3) - -extern "C" int -WINRT_GLES_LoadLibrary(_THIS, const char *path) { - return SDL_EGL_LoadLibrary(_this, path, EGL_D3D11_ONLY_DISPLAY_ANGLE); -} - -extern "C" { -SDL_EGL_CreateContext_impl(WINRT) -SDL_EGL_SwapWindow_impl(WINRT) -SDL_EGL_MakeCurrent_impl(WINRT) -} - -#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */ - -/* vi: set ts=4 sw=4 expandtab: */ - +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +// TODO: WinRT, make this file compile via C code + +#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL + +/* EGL implementation of SDL OpenGL support */ + +#include "SDL_winrtvideo_cpp.h" +extern "C" { +#include "SDL_winrtopengles.h" +} + +#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((NativeDisplayType) -3) + +extern "C" int +WINRT_GLES_LoadLibrary(_THIS, const char *path) { + return SDL_EGL_LoadLibrary(_this, path, EGL_D3D11_ONLY_DISPLAY_ANGLE); +} + +extern "C" { +SDL_EGL_CreateContext_impl(WINRT) +SDL_EGL_SwapWindow_impl(WINRT) +SDL_EGL_MakeCurrent_impl(WINRT) +} + +#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/winrt/SDL_winrtopengles.h b/src/video/winrt/SDL_winrtopengles.h index 4ac3cfe239173..193e0333f6914 100644 --- a/src/video/winrt/SDL_winrtopengles.h +++ b/src/video/winrt/SDL_winrtopengles.h @@ -1,48 +1,48 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ -#include "SDL_config.h" - -#ifndef _SDL_winrtopengles_h -#define _SDL_winrtopengles_h - -#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL - -#include "../SDL_sysvideo.h" -#include "../SDL_egl_c.h" - -/* OpenGLES functions */ -#define WINRT_GLES_GetAttribute SDL_EGL_GetAttribute -#define WINRT_GLES_GetProcAddress SDL_EGL_GetProcAddress -#define WINRT_GLES_UnloadLibrary SDL_EGL_UnloadLibrary -#define WINRT_GLES_SetSwapInterval SDL_EGL_SetSwapInterval -#define WINRT_GLES_GetSwapInterval SDL_EGL_GetSwapInterval -#define WINRT_GLES_DeleteContext SDL_EGL_DeleteContext - -extern int WINRT_GLES_LoadLibrary(_THIS, const char *path); -extern SDL_GLContext WINRT_GLES_CreateContext(_THIS, SDL_Window * window); -extern void WINRT_GLES_SwapWindow(_THIS, SDL_Window * window); -extern int WINRT_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); - -#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */ - -#endif /* _SDL_winrtopengles_h */ - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +#ifndef _SDL_winrtopengles_h +#define _SDL_winrtopengles_h + +#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL + +#include "../SDL_sysvideo.h" +#include "../SDL_egl_c.h" + +/* OpenGLES functions */ +#define WINRT_GLES_GetAttribute SDL_EGL_GetAttribute +#define WINRT_GLES_GetProcAddress SDL_EGL_GetProcAddress +#define WINRT_GLES_UnloadLibrary SDL_EGL_UnloadLibrary +#define WINRT_GLES_SetSwapInterval SDL_EGL_SetSwapInterval +#define WINRT_GLES_GetSwapInterval SDL_EGL_GetSwapInterval +#define WINRT_GLES_DeleteContext SDL_EGL_DeleteContext + +extern int WINRT_GLES_LoadLibrary(_THIS, const char *path); +extern SDL_GLContext WINRT_GLES_CreateContext(_THIS, SDL_Window * window); +extern void WINRT_GLES_SwapWindow(_THIS, SDL_Window * window); +extern int WINRT_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); + +#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */ + +#endif /* _SDL_winrtopengles_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtpointerinput.cpp b/src/video/winrt/SDL_winrtpointerinput.cpp index bb1a771f96f21..13dd5b621528b 100644 --- a/src/video/winrt/SDL_winrtpointerinput.cpp +++ b/src/video/winrt/SDL_winrtpointerinput.cpp @@ -17,7 +17,7 @@ 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. -*/ +*/ #include "SDL_config.h" #if SDL_VIDEO_DRIVER_WINRT @@ -32,363 +32,363 @@ extern "C" { #include "../SDL_sysvideo.h" #include "../../events/SDL_events_c.h" -#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_mouse_c.h" #include "../../events/SDL_touch_c.h" } - -/* File-specific globals: */ -static SDL_TouchID WINRT_TouchID = 1; -static unsigned int WINRT_LeftFingerDown = 0; - - -void -WINRT_InitTouch(_THIS) -{ - SDL_AddTouch(WINRT_TouchID, ""); -} - - -// -// Applies necessary geometric transformations to raw cursor positions: -// -Windows::Foundation::Point -WINRT_TransformCursorPosition(SDL_Window * window, - Windows::Foundation::Point rawPosition, - WINRT_CursorNormalizationType normalization) -{ - using namespace Windows::UI::Core; - using namespace Windows::Graphics::Display; - - if (!window) { - return rawPosition; - } - - SDL_WindowData * windowData = (SDL_WindowData *) window->driverdata; - if (windowData->coreWindow == nullptr) { - // For some reason, the window isn't associated with a CoreWindow. - // This might end up being the case as XAML support is extended. - // For now, if there's no CoreWindow attached to the SDL_Window, - // don't do any transforms. - - // TODO, WinRT: make sure touch input coordinate ranges are correct when using XAML support - return rawPosition; - } - - // The CoreWindow can only be accessed on certain thread(s). - SDL_assert(CoreWindow::GetForCurrentThread() != nullptr); - - CoreWindow ^ nativeWindow = windowData->coreWindow.Get(); - Windows::Foundation::Point outputPosition; - - // Compute coordinates normalized from 0..1. - // If the coordinates need to be sized to the SDL window, - // we'll do that after. -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP - outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width; - outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height; -#else - switch (DisplayProperties::CurrentOrientation) - { - case DisplayOrientations::Portrait: - outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width; - outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height; - break; - case DisplayOrientations::PortraitFlipped: - outputPosition.X = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width); - outputPosition.Y = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height); - break; - case DisplayOrientations::Landscape: - outputPosition.X = rawPosition.Y / nativeWindow->Bounds.Height; - outputPosition.Y = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width); - break; - case DisplayOrientations::LandscapeFlipped: - outputPosition.X = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height); - outputPosition.Y = rawPosition.X / nativeWindow->Bounds.Width; - break; - default: - break; - } -#endif - - if (normalization == TransformToSDLWindowSize) { - outputPosition.X *= ((float32) window->w); - outputPosition.Y *= ((float32) window->h); - } - - return outputPosition; -} - -static inline int -_lround(float arg) -{ - if (arg >= 0.0f) { - return (int)floor(arg + 0.5f); - } else { - return (int)ceil(arg - 0.5f); - } -} - -Uint8 -WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt) -{ - using namespace Windows::UI::Input; - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - return SDL_BUTTON_LEFT; -#else - switch (pt->Properties->PointerUpdateKind) - { - case PointerUpdateKind::LeftButtonPressed: - case PointerUpdateKind::LeftButtonReleased: - return SDL_BUTTON_LEFT; - - case PointerUpdateKind::RightButtonPressed: - case PointerUpdateKind::RightButtonReleased: - return SDL_BUTTON_RIGHT; - - case PointerUpdateKind::MiddleButtonPressed: - case PointerUpdateKind::MiddleButtonReleased: - return SDL_BUTTON_MIDDLE; - - case PointerUpdateKind::XButton1Pressed: - case PointerUpdateKind::XButton1Released: - return SDL_BUTTON_X1; - - case PointerUpdateKind::XButton2Pressed: - case PointerUpdateKind::XButton2Released: - return SDL_BUTTON_X2; - - default: - break; - } -#endif - - return 0; -} - -//const char * -//WINRT_ConvertPointerUpdateKindToString(Windows::UI::Input::PointerUpdateKind kind) -//{ -// using namespace Windows::UI::Input; -// -// switch (kind) -// { -// case PointerUpdateKind::Other: -// return "Other"; -// case PointerUpdateKind::LeftButtonPressed: -// return "LeftButtonPressed"; -// case PointerUpdateKind::LeftButtonReleased: -// return "LeftButtonReleased"; -// case PointerUpdateKind::RightButtonPressed: -// return "RightButtonPressed"; -// case PointerUpdateKind::RightButtonReleased: -// return "RightButtonReleased"; -// case PointerUpdateKind::MiddleButtonPressed: -// return "MiddleButtonPressed"; -// case PointerUpdateKind::MiddleButtonReleased: -// return "MiddleButtonReleased"; -// case PointerUpdateKind::XButton1Pressed: -// return "XButton1Pressed"; -// case PointerUpdateKind::XButton1Released: -// return "XButton1Released"; -// case PointerUpdateKind::XButton2Pressed: -// return "XButton2Pressed"; -// case PointerUpdateKind::XButton2Released: -// return "XButton2Released"; -// } -// -// return ""; -//} - -static bool -WINRT_IsTouchEvent(Windows::UI::Input::PointerPoint ^pointerPoint) -{ -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - return true; -#else - using namespace Windows::Devices::Input; - switch (pointerPoint->PointerDevice->PointerDeviceType) { - case PointerDeviceType::Touch: - case PointerDeviceType::Pen: - return true; - default: - return false; - } -#endif -} - -void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) -{ - if (!window) { - return; - } - - Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); - - if ( ! WINRT_IsTouchEvent(pointerPoint)) { - SDL_SendMouseButton(window, 0, SDL_PRESSED, button); - } else { - Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); - Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize); - - if (!WINRT_LeftFingerDown) { - if (button) { - SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); - SDL_SendMouseButton(window, 0, SDL_PRESSED, button); - } - - WINRT_LeftFingerDown = pointerPoint->PointerId; - } - - SDL_SendTouch( - WINRT_TouchID, - (SDL_FingerID) pointerPoint->PointerId, - SDL_TRUE, - normalizedPoint.X, - normalizedPoint.Y, - pointerPoint->Properties->Pressure); - } + +/* File-specific globals: */ +static SDL_TouchID WINRT_TouchID = 1; +static unsigned int WINRT_LeftFingerDown = 0; + + +void +WINRT_InitTouch(_THIS) +{ + SDL_AddTouch(WINRT_TouchID, ""); +} + + +// +// Applies necessary geometric transformations to raw cursor positions: +// +Windows::Foundation::Point +WINRT_TransformCursorPosition(SDL_Window * window, + Windows::Foundation::Point rawPosition, + WINRT_CursorNormalizationType normalization) +{ + using namespace Windows::UI::Core; + using namespace Windows::Graphics::Display; + + if (!window) { + return rawPosition; + } + + SDL_WindowData * windowData = (SDL_WindowData *) window->driverdata; + if (windowData->coreWindow == nullptr) { + // For some reason, the window isn't associated with a CoreWindow. + // This might end up being the case as XAML support is extended. + // For now, if there's no CoreWindow attached to the SDL_Window, + // don't do any transforms. + + // TODO, WinRT: make sure touch input coordinate ranges are correct when using XAML support + return rawPosition; + } + + // The CoreWindow can only be accessed on certain thread(s). + SDL_assert(CoreWindow::GetForCurrentThread() != nullptr); + + CoreWindow ^ nativeWindow = windowData->coreWindow.Get(); + Windows::Foundation::Point outputPosition; + + // Compute coordinates normalized from 0..1. + // If the coordinates need to be sized to the SDL window, + // we'll do that after. +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width; + outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height; +#else + switch (DisplayProperties::CurrentOrientation) + { + case DisplayOrientations::Portrait: + outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width; + outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height; + break; + case DisplayOrientations::PortraitFlipped: + outputPosition.X = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width); + outputPosition.Y = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height); + break; + case DisplayOrientations::Landscape: + outputPosition.X = rawPosition.Y / nativeWindow->Bounds.Height; + outputPosition.Y = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width); + break; + case DisplayOrientations::LandscapeFlipped: + outputPosition.X = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height); + outputPosition.Y = rawPosition.X / nativeWindow->Bounds.Width; + break; + default: + break; + } +#endif + + if (normalization == TransformToSDLWindowSize) { + outputPosition.X *= ((float32) window->w); + outputPosition.Y *= ((float32) window->h); + } + + return outputPosition; +} + +static inline int +_lround(float arg) +{ + if (arg >= 0.0f) { + return (int)floor(arg + 0.5f); + } else { + return (int)ceil(arg - 0.5f); + } +} + +Uint8 +WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt) +{ + using namespace Windows::UI::Input; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + return SDL_BUTTON_LEFT; +#else + switch (pt->Properties->PointerUpdateKind) + { + case PointerUpdateKind::LeftButtonPressed: + case PointerUpdateKind::LeftButtonReleased: + return SDL_BUTTON_LEFT; + + case PointerUpdateKind::RightButtonPressed: + case PointerUpdateKind::RightButtonReleased: + return SDL_BUTTON_RIGHT; + + case PointerUpdateKind::MiddleButtonPressed: + case PointerUpdateKind::MiddleButtonReleased: + return SDL_BUTTON_MIDDLE; + + case PointerUpdateKind::XButton1Pressed: + case PointerUpdateKind::XButton1Released: + return SDL_BUTTON_X1; + + case PointerUpdateKind::XButton2Pressed: + case PointerUpdateKind::XButton2Released: + return SDL_BUTTON_X2; + + default: + break; + } +#endif + + return 0; } - -void -WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) -{ - if (!window || WINRT_UsingRelativeMouseMode) { - return; - } - - Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); - Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize); - - if ( ! WINRT_IsTouchEvent(pointerPoint)) { - SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); - } else if (pointerPoint->PointerId == WINRT_LeftFingerDown) { - if (pointerPoint->PointerId == WINRT_LeftFingerDown) { - SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); - } - - SDL_SendTouchMotion( - WINRT_TouchID, - (SDL_FingerID) pointerPoint->PointerId, - normalizedPoint.X, - normalizedPoint.Y, - pointerPoint->Properties->Pressure); - } -} - -void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) -{ - if (!window) { - return; - } - - Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); - - if (!WINRT_IsTouchEvent(pointerPoint)) { - SDL_SendMouseButton(window, 0, SDL_RELEASED, button); - } else { - Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); - - if (WINRT_LeftFingerDown == pointerPoint->PointerId) { - if (button) { - SDL_SendMouseButton(window, 0, SDL_RELEASED, button); - } - WINRT_LeftFingerDown = 0; - } - - SDL_SendTouch( - WINRT_TouchID, - (SDL_FingerID) pointerPoint->PointerId, - SDL_FALSE, - normalizedPoint.X, - normalizedPoint.Y, - pointerPoint->Properties->Pressure); - } -} - -void -WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) -{ - if (!window) { - return; - } - - // FIXME: This may need to accumulate deltas up to WHEEL_DELTA - short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA; - SDL_SendMouseWheel(window, 0, 0, motion); -} - -void -WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args) -{ - if (!window || !WINRT_UsingRelativeMouseMode) { - return; - } - - // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows - // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs' - // MouseDelta field often reports very large values. More information - // on this can be found at the following pages on MSDN: - // - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8 - // - https://connect.microsoft.com/VisualStudio/Feedback/details/756515 - // - // The values do not appear to be as large when running on some systems, - // most notably a Surface RT. Furthermore, the values returned by - // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved - // method, do not ever appear to be large, even when MouseEventArgs' - // MouseDelta is reporting to the contrary. - // - // On systems with the large-values behavior, it appears that the values - // get reported as if the screen's size is 65536 units in both the X and Y - // dimensions. This can be viewed by using Windows' now-private, "Raw Input" - // APIs. (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.) - // - // MSDN's documentation on MouseEventArgs' MouseDelta field (at - // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ), - // does not seem to indicate (to me) that its values should be so large. It - // says that its values should be a "change in screen location". I could - // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see: - // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ), - // indicates that these values are in DIPs, which is the same unit used - // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint - // property. See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx - // for details.) - // - // To note, PointerMoved events are sent a 'RawPosition' value (via the - // CurrentPoint property in MouseEventArgs), however these do not seem - // to exhibit the same large-value behavior. - // - // The values passed via PointerMoved events can't always be used for relative - // mouse motion, unfortunately. Its values are bound to the cursor's position, - // which stops when it hits one of the screen's edges. This can be a problem in - // first person shooters, whereby it is normal for mouse motion to travel far - // along any one axis for a period of time. MouseMoved events do not have the - // screen-bounding limitation, and can be used regardless of where the system's - // cursor is. - // - // One possible workaround would be to programmatically set the cursor's - // position to the screen's center (when SDL's relative mouse mode is enabled), - // however WinRT does not yet seem to have the ability to set the cursor's - // position via a public API. Win32 did this via an API call, SetCursorPos, - // however WinRT makes this function be private. Apps that use it won't get - // approved for distribution in the Windows Store. I've yet to be able to find - // a suitable, store-friendly counterpart for WinRT. - // - // There may be some room for a workaround whereby OnPointerMoved's values - // are compared to the values from OnMouseMoved in order to detect - // when this bug is active. A suitable transformation could then be made to - // OnMouseMoved's values. For now, however, the system-reported values are sent - // to SDL with minimal transformation: from native screen coordinates (in DIPs) - // to SDL window coordinates. - // - const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y); - const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs, TransformToSDLWindowSize); - SDL_SendMouseMotion( - window, - 0, - 1, - _lround(mouseDeltaInSDLWindowCoords.X), - _lround(mouseDeltaInSDLWindowCoords.Y)); + +//const char * +//WINRT_ConvertPointerUpdateKindToString(Windows::UI::Input::PointerUpdateKind kind) +//{ +// using namespace Windows::UI::Input; +// +// switch (kind) +// { +// case PointerUpdateKind::Other: +// return "Other"; +// case PointerUpdateKind::LeftButtonPressed: +// return "LeftButtonPressed"; +// case PointerUpdateKind::LeftButtonReleased: +// return "LeftButtonReleased"; +// case PointerUpdateKind::RightButtonPressed: +// return "RightButtonPressed"; +// case PointerUpdateKind::RightButtonReleased: +// return "RightButtonReleased"; +// case PointerUpdateKind::MiddleButtonPressed: +// return "MiddleButtonPressed"; +// case PointerUpdateKind::MiddleButtonReleased: +// return "MiddleButtonReleased"; +// case PointerUpdateKind::XButton1Pressed: +// return "XButton1Pressed"; +// case PointerUpdateKind::XButton1Released: +// return "XButton1Released"; +// case PointerUpdateKind::XButton2Pressed: +// return "XButton2Pressed"; +// case PointerUpdateKind::XButton2Released: +// return "XButton2Released"; +// } +// +// return ""; +//} + +static bool +WINRT_IsTouchEvent(Windows::UI::Input::PointerPoint ^pointerPoint) +{ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + return true; +#else + using namespace Windows::Devices::Input; + switch (pointerPoint->PointerDevice->PointerDeviceType) { + case PointerDeviceType::Touch: + case PointerDeviceType::Pen: + return true; + default: + return false; + } +#endif +} + +void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); + + if ( ! WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendMouseButton(window, 0, SDL_PRESSED, button); + } else { + Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); + Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize); + + if (!WINRT_LeftFingerDown) { + if (button) { + SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); + SDL_SendMouseButton(window, 0, SDL_PRESSED, button); + } + + WINRT_LeftFingerDown = pointerPoint->PointerId; + } + + SDL_SendTouch( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + SDL_TRUE, + normalizedPoint.X, + normalizedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +void +WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window || WINRT_UsingRelativeMouseMode) { + return; + } + + Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); + Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize); + + if ( ! WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); + } else if (pointerPoint->PointerId == WINRT_LeftFingerDown) { + if (pointerPoint->PointerId == WINRT_LeftFingerDown) { + SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); + } + + SDL_SendTouchMotion( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + normalizedPoint.X, + normalizedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); + + if (!WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendMouseButton(window, 0, SDL_RELEASED, button); + } else { + Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); + + if (WINRT_LeftFingerDown == pointerPoint->PointerId) { + if (button) { + SDL_SendMouseButton(window, 0, SDL_RELEASED, button); + } + WINRT_LeftFingerDown = 0; + } + + SDL_SendTouch( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + SDL_FALSE, + normalizedPoint.X, + normalizedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +void +WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + // FIXME: This may need to accumulate deltas up to WHEEL_DELTA + short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA; + SDL_SendMouseWheel(window, 0, 0, motion); +} + +void +WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args) +{ + if (!window || !WINRT_UsingRelativeMouseMode) { + return; + } + + // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows + // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs' + // MouseDelta field often reports very large values. More information + // on this can be found at the following pages on MSDN: + // - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8 + // - https://connect.microsoft.com/VisualStudio/Feedback/details/756515 + // + // The values do not appear to be as large when running on some systems, + // most notably a Surface RT. Furthermore, the values returned by + // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved + // method, do not ever appear to be large, even when MouseEventArgs' + // MouseDelta is reporting to the contrary. + // + // On systems with the large-values behavior, it appears that the values + // get reported as if the screen's size is 65536 units in both the X and Y + // dimensions. This can be viewed by using Windows' now-private, "Raw Input" + // APIs. (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.) + // + // MSDN's documentation on MouseEventArgs' MouseDelta field (at + // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ), + // does not seem to indicate (to me) that its values should be so large. It + // says that its values should be a "change in screen location". I could + // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see: + // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ), + // indicates that these values are in DIPs, which is the same unit used + // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint + // property. See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx + // for details.) + // + // To note, PointerMoved events are sent a 'RawPosition' value (via the + // CurrentPoint property in MouseEventArgs), however these do not seem + // to exhibit the same large-value behavior. + // + // The values passed via PointerMoved events can't always be used for relative + // mouse motion, unfortunately. Its values are bound to the cursor's position, + // which stops when it hits one of the screen's edges. This can be a problem in + // first person shooters, whereby it is normal for mouse motion to travel far + // along any one axis for a period of time. MouseMoved events do not have the + // screen-bounding limitation, and can be used regardless of where the system's + // cursor is. + // + // One possible workaround would be to programmatically set the cursor's + // position to the screen's center (when SDL's relative mouse mode is enabled), + // however WinRT does not yet seem to have the ability to set the cursor's + // position via a public API. Win32 did this via an API call, SetCursorPos, + // however WinRT makes this function be private. Apps that use it won't get + // approved for distribution in the Windows Store. I've yet to be able to find + // a suitable, store-friendly counterpart for WinRT. + // + // There may be some room for a workaround whereby OnPointerMoved's values + // are compared to the values from OnMouseMoved in order to detect + // when this bug is active. A suitable transformation could then be made to + // OnMouseMoved's values. For now, however, the system-reported values are sent + // to SDL with minimal transformation: from native screen coordinates (in DIPs) + // to SDL window coordinates. + // + const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y); + const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs, TransformToSDLWindowSize); + SDL_SendMouseMotion( + window, + 0, + 1, + _lround(mouseDeltaInSDLWindowCoords.X), + _lround(mouseDeltaInSDLWindowCoords.Y)); } #endif // SDL_VIDEO_DRIVER_WINRT diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index d5f4679609e8a..30dffcf085513 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -113,14 +113,14 @@ WINRT_CreateDevice(int devindex) device->PumpEvents = WINRT_PumpEvents; device->GetWindowWMInfo = WINRT_GetWindowWMInfo; #ifdef SDL_VIDEO_OPENGL_EGL - device->GL_LoadLibrary = WINRT_GLES_LoadLibrary; - device->GL_GetProcAddress = WINRT_GLES_GetProcAddress; - device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary; - device->GL_CreateContext = WINRT_GLES_CreateContext; - device->GL_MakeCurrent = WINRT_GLES_MakeCurrent; - device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval; - device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval; - device->GL_SwapWindow = WINRT_GLES_SwapWindow; + device->GL_LoadLibrary = WINRT_GLES_LoadLibrary; + device->GL_GetProcAddress = WINRT_GLES_GetProcAddress; + device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary; + device->GL_CreateContext = WINRT_GLES_CreateContext; + device->GL_MakeCurrent = WINRT_GLES_MakeCurrent; + device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval; + device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval; + device->GL_SwapWindow = WINRT_GLES_SwapWindow; device->GL_DeleteContext = WINRT_GLES_DeleteContext; #endif device->free = WINRT_DeleteDevice; @@ -351,7 +351,7 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) /* For now, treat WinRT apps as if they always have focus. TODO, WinRT: try tracking keyboard and mouse focus state with respect to snapped apps */ - SDL_SetMouseFocus(window); + SDL_SetMouseFocus(window); SDL_SetKeyboardFocus(window); /* Make sure the WinRT app's IFramworkView can post events on diff --git a/src/video/winrt/SDL_winrtvideo_cpp.h b/src/video/winrt/SDL_winrtvideo_cpp.h index 0c2cb115408de..0a8de6455e5fe 100644 --- a/src/video/winrt/SDL_winrtvideo_cpp.h +++ b/src/video/winrt/SDL_winrtvideo_cpp.h @@ -44,36 +44,36 @@ extern SDL_Window * WINRT_GlobalSDLWindow; /* The global, WinRT, video device. */ extern SDL_VideoDevice * WINRT_GlobalSDLVideoDevice; -/* Creates a display mode for Plain Direct3D (non-XAML) apps, using the lone, native window's settings. - - Pass in an allocated SDL_DisplayMode field to store the data in. - - This function will return 0 on success, -1 on failure. - - If this function succeeds, be sure to call SDL_free on the - SDL_DisplayMode's driverdata field. -*/ -extern int WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode); - -/* Duplicates a display mode, copying over driverdata as necessary */ -extern int WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src); - -/* Display mode internals */ -typedef struct -{ - Windows::Graphics::Display::DisplayOrientations currentOrientation; +/* Creates a display mode for Plain Direct3D (non-XAML) apps, using the lone, native window's settings. + + Pass in an allocated SDL_DisplayMode field to store the data in. + + This function will return 0 on success, -1 on failure. + + If this function succeeds, be sure to call SDL_free on the + SDL_DisplayMode's driverdata field. +*/ +extern int WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode); + +/* Duplicates a display mode, copying over driverdata as necessary */ +extern int WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src); + +/* Display mode internals */ +typedef struct +{ + Windows::Graphics::Display::DisplayOrientations currentOrientation; } SDL_DisplayModeData; #ifdef __cplusplus_winrt /* Internal window data */ -struct SDL_WindowData -{ - SDL_Window *sdlWindow; - Platform::Agile coreWindow; -#ifdef SDL_VIDEO_OPENGL_EGL - EGLSurface egl_surface; -#endif +struct SDL_WindowData +{ + SDL_Window *sdlWindow; + Platform::Agile coreWindow; +#ifdef SDL_VIDEO_OPENGL_EGL + EGLSurface egl_surface; +#endif }; #endif // ifdef __cplusplus_winrt diff --git a/test/loopwave.c b/test/loopwave.c index 403d16c53194e..210465a2b6cd3 100644 --- a/test/loopwave.c +++ b/test/loopwave.c @@ -1,144 +1,144 @@ -/* - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely. -*/ - -/* Program to load a wave file and loop playing it using SDL sound */ - -/* loopwaves.c is much more robust in handling WAVE files -- - This is only for simple WAVEs -*/ -#include "SDL_config.h" - -#include -#include - -#if HAVE_SIGNAL_H -#include -#endif - -#include "SDL.h" -#include "SDL_audio.h" - -struct -{ - SDL_AudioSpec spec; - Uint8 *sound; /* Pointer to wave data */ - Uint32 soundlen; /* Length of wave data */ - int soundpos; /* Current play position */ -} wave; - - -/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ -static void -quit(int rc) -{ - SDL_Quit(); - exit(rc); -} - - -void SDLCALL -fillerup(void *unused, Uint8 * stream, int len) -{ - Uint8 *waveptr; - int waveleft; - - /* Set up the pointers */ - waveptr = wave.sound + wave.soundpos; - waveleft = wave.soundlen - wave.soundpos; - - /* Go! */ - while (waveleft <= len) { - SDL_memcpy(stream, waveptr, waveleft); - stream += waveleft; - len -= waveleft; - waveptr = wave.sound; - waveleft = wave.soundlen; - wave.soundpos = 0; - } - SDL_memcpy(stream, waveptr, len); - wave.soundpos += len; -} - -static int done = 0; -void -poked(int sig) -{ - done = 1; -} - -int -main(int argc, char *argv[]) -{ - int i; - char filename[4096]; - - /* Enable standard application logging */ - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); - - /* Load the SDL library */ - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); - return (1); - } - - if (argc >= 1) { - SDL_strlcpy(filename, argv[1], sizeof(filename)); - } else { - SDL_strlcpy(filename, "sample.wav", sizeof(filename)); - } - /* Load the wave file into memory */ - if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", argv[1], SDL_GetError()); - quit(1); - } - - wave.spec.callback = fillerup; -#if HAVE_SIGNAL_H - /* Set the signals */ -#ifdef SIGHUP - signal(SIGHUP, poked); -#endif - signal(SIGINT, poked); -#ifdef SIGQUIT - signal(SIGQUIT, poked); -#endif - signal(SIGTERM, poked); -#endif /* HAVE_SIGNAL_H */ - - /* Show the list of available drivers */ - SDL_Log("Available audio drivers:"); - for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) { - SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); - } - - /* Initialize fillerup() variables */ - if (SDL_OpenAudio(&wave.spec, NULL) < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError()); - SDL_FreeWAV(wave.sound); - quit(2); - } - - SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); - - /* Let the audio run */ - SDL_PauseAudio(0); - while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)) - SDL_Delay(1000); - - /* Clean up on signal */ - SDL_CloseAudio(); - SDL_FreeWAV(wave.sound); - SDL_Quit(); - return (0); -} - -/* vi: set ts=4 sw=4 expandtab: */ +/* + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ + +/* Program to load a wave file and loop playing it using SDL sound */ + +/* loopwaves.c is much more robust in handling WAVE files -- + This is only for simple WAVEs +*/ +#include "SDL_config.h" + +#include +#include + +#if HAVE_SIGNAL_H +#include +#endif + +#include "SDL.h" +#include "SDL_audio.h" + +struct +{ + SDL_AudioSpec spec; + Uint8 *sound; /* Pointer to wave data */ + Uint32 soundlen; /* Length of wave data */ + int soundpos; /* Current play position */ +} wave; + + +/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ +static void +quit(int rc) +{ + SDL_Quit(); + exit(rc); +} + + +void SDLCALL +fillerup(void *unused, Uint8 * stream, int len) +{ + Uint8 *waveptr; + int waveleft; + + /* Set up the pointers */ + waveptr = wave.sound + wave.soundpos; + waveleft = wave.soundlen - wave.soundpos; + + /* Go! */ + while (waveleft <= len) { + SDL_memcpy(stream, waveptr, waveleft); + stream += waveleft; + len -= waveleft; + waveptr = wave.sound; + waveleft = wave.soundlen; + wave.soundpos = 0; + } + SDL_memcpy(stream, waveptr, len); + wave.soundpos += len; +} + +static int done = 0; +void +poked(int sig) +{ + done = 1; +} + +int +main(int argc, char *argv[]) +{ + int i; + char filename[4096]; + + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + /* Load the SDL library */ + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + return (1); + } + + if (argc >= 1) { + SDL_strlcpy(filename, argv[1], sizeof(filename)); + } else { + SDL_strlcpy(filename, "sample.wav", sizeof(filename)); + } + /* Load the wave file into memory */ + if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", argv[1], SDL_GetError()); + quit(1); + } + + wave.spec.callback = fillerup; +#if HAVE_SIGNAL_H + /* Set the signals */ +#ifdef SIGHUP + signal(SIGHUP, poked); +#endif + signal(SIGINT, poked); +#ifdef SIGQUIT + signal(SIGQUIT, poked); +#endif + signal(SIGTERM, poked); +#endif /* HAVE_SIGNAL_H */ + + /* Show the list of available drivers */ + SDL_Log("Available audio drivers:"); + for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) { + SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); + } + + /* Initialize fillerup() variables */ + if (SDL_OpenAudio(&wave.spec, NULL) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError()); + SDL_FreeWAV(wave.sound); + quit(2); + } + + SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + + /* Let the audio run */ + SDL_PauseAudio(0); + while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)) + SDL_Delay(1000); + + /* Clean up on signal */ + SDL_CloseAudio(); + SDL_FreeWAV(wave.sound); + SDL_Quit(); + return (0); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/test/testthread.c b/test/testthread.c index c5ce2d5a8e962..ed9f1f182f42b 100644 --- a/test/testthread.c +++ b/test/testthread.c @@ -1,99 +1,99 @@ -/* - Copyright (C) 1997-2013 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely. -*/ - -/* Simple test of the SDL threading code */ - -#include -#include -#include - -#include "SDL.h" -#include "SDL_thread.h" - -static SDL_TLSID tls; -static int alive = 0; - -/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ -static void -quit(int rc) -{ - SDL_Quit(); - exit(rc); -} - -int SDLCALL -ThreadFunc(void *data) -{ - SDL_TLSSet(tls, "baby thread", NULL); - SDL_Log("Started thread %s: My thread id is %lu, thread data = %s\n", - (char *) data, SDL_ThreadID(), (const char *)SDL_TLSGet(tls)); - while (alive) { - SDL_Log("Thread '%s' is alive!\n", (char *) data); - SDL_Delay(1 * 1000); - } - SDL_Log("Thread '%s' exiting!\n", (char *) data); - return (0); -} - -static void -killed(int sig) -{ - SDL_Log("Killed with SIGTERM, waiting 5 seconds to exit\n"); - SDL_Delay(5 * 1000); - alive = 0; - quit(0); -} - -int -main(int argc, char *argv[]) -{ - SDL_Thread *thread; - - /* Enable standard application logging */ - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); - - /* Load the SDL library */ - if (SDL_Init(0) < 0) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); - return (1); - } - - tls = SDL_TLSCreate(); - SDL_assert(tls); - SDL_TLSSet(tls, "main thread", NULL); - SDL_Log("Main thread data initially: %s\n", (const char *)SDL_TLSGet(tls)); - - alive = 1; - thread = SDL_CreateThread(ThreadFunc, "One", "#1"); - if (thread == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); - quit(1); - } - SDL_Delay(5 * 1000); - SDL_Log("Waiting for thread #1\n"); - alive = 0; - SDL_WaitThread(thread, NULL); - - SDL_Log("Main thread data finally: %s\n", (const char *)SDL_TLSGet(tls)); - - alive = 1; - signal(SIGTERM, killed); - thread = SDL_CreateThread(ThreadFunc, "Two", "#2"); - if (thread == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); - quit(1); - } - raise(SIGTERM); - - SDL_Quit(); /* Never reached */ - return (0); /* Never reached */ -} +/* + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ + +/* Simple test of the SDL threading code */ + +#include +#include +#include + +#include "SDL.h" +#include "SDL_thread.h" + +static SDL_TLSID tls; +static int alive = 0; + +/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ +static void +quit(int rc) +{ + SDL_Quit(); + exit(rc); +} + +int SDLCALL +ThreadFunc(void *data) +{ + SDL_TLSSet(tls, "baby thread", NULL); + SDL_Log("Started thread %s: My thread id is %lu, thread data = %s\n", + (char *) data, SDL_ThreadID(), (const char *)SDL_TLSGet(tls)); + while (alive) { + SDL_Log("Thread '%s' is alive!\n", (char *) data); + SDL_Delay(1 * 1000); + } + SDL_Log("Thread '%s' exiting!\n", (char *) data); + return (0); +} + +static void +killed(int sig) +{ + SDL_Log("Killed with SIGTERM, waiting 5 seconds to exit\n"); + SDL_Delay(5 * 1000); + alive = 0; + quit(0); +} + +int +main(int argc, char *argv[]) +{ + SDL_Thread *thread; + + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + /* Load the SDL library */ + if (SDL_Init(0) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + return (1); + } + + tls = SDL_TLSCreate(); + SDL_assert(tls); + SDL_TLSSet(tls, "main thread", NULL); + SDL_Log("Main thread data initially: %s\n", (const char *)SDL_TLSGet(tls)); + + alive = 1; + thread = SDL_CreateThread(ThreadFunc, "One", "#1"); + if (thread == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); + quit(1); + } + SDL_Delay(5 * 1000); + SDL_Log("Waiting for thread #1\n"); + alive = 0; + SDL_WaitThread(thread, NULL); + + SDL_Log("Main thread data finally: %s\n", (const char *)SDL_TLSGet(tls)); + + alive = 1; + signal(SIGTERM, killed); + thread = SDL_CreateThread(ThreadFunc, "Two", "#2"); + if (thread == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create thread: %s\n", SDL_GetError()); + quit(1); + } + raise(SIGTERM); + + SDL_Quit(); /* Never reached */ + return (0); /* Never reached */ +}