Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62639fdf88 | ||
|
|
b3cdeb942a | ||
|
|
a296c40867 | ||
|
|
f896e26f59 | ||
|
|
d19b010d4e | ||
|
|
14aa5cf762 | ||
|
|
69255b870d | ||
|
|
a4de176e1c | ||
|
|
9b36a76ee6 | ||
|
|
a75bf983e5 | ||
|
|
6f774908fe | ||
|
|
a35639c7b5 | ||
|
|
db3ee5d62b | ||
|
|
08a547e077 | ||
|
|
b428c1834f | ||
|
|
5813d0ec0a | ||
|
|
4194879df1 | ||
|
|
9918d6cb5e | ||
|
|
19988c5faa | ||
|
|
7773157fae | ||
|
|
9bf86a2db3 | ||
|
|
edb81cf84a | ||
|
|
9257df24b5 | ||
|
|
97b0b13147 | ||
|
|
7e78636e8e |
No files matched your search
+2
-2
@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
|
||||
endif()
|
||||
|
||||
# See docs/release_checklist.md
|
||||
project(SDL3 LANGUAGES C VERSION "3.3.4")
|
||||
project(SDL3 LANGUAGES C VERSION "3.3.5")
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
set(SDL3_MAINPROJECT ON)
|
||||
@@ -393,7 +393,7 @@ cmake_dependent_option(SDL_SHARED "Build a shared version of the library" ${SDL_
|
||||
cmake_dependent_option(SDL_STATIC "Build a static version of the library" ${SDL_STATIC_DEFAULT} ${SDL_STATIC_AVAILABLE} OFF)
|
||||
option(SDL_TEST_LIBRARY "Build the SDL3_test library" ON)
|
||||
|
||||
dep_option(SDL_TESTS "Build the test directory" OFF SDL_TEST_LIBRARY OFF)
|
||||
dep_option(SDL_TESTS "Build the test directory" ${SDL3_MAINPROJECT} SDL_TEST_LIBRARY OFF)
|
||||
dep_option(SDL_INSTALL_TESTS "Install test-cases" OFF "SDL_INSTALL;NOT SDL_FRAMEWORK" OFF)
|
||||
dep_option(SDL_TESTS_LINK_SHARED "link tests to shared SDL library" "${SDL_SHARED}" "SDL_SHARED;SDL_STATIC" "${SDL_SHARED}")
|
||||
set(SDL_TESTS_TIMEOUT_MULTIPLIER "1" CACHE STRING "Timeout multiplier to account for really slow machines")
|
||||
|
||||
+54
-2
@@ -8,43 +8,95 @@ This is a list of major changes in SDL's version history.
|
||||
General:
|
||||
* Added SDL_CreateAnimatedCursor() to create animated color cursors
|
||||
* Added SDL_SetWindowProgressState(), SDL_SetWindowProgressValue(), SDL_GetWindowProgressState(), and SDL_GetWindowProgressValue() to show progress in the window's taskbar icon on Windows and Linux
|
||||
* Added SDL_GetGPUDeviceProperties() to get the properties of an SDL GPU device
|
||||
* Added GPU device creation properties to enable the GPU API on older hardware if you're not using these features:
|
||||
- SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN
|
||||
- SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN
|
||||
- SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN
|
||||
- SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN
|
||||
- SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN
|
||||
* Added SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER to enable configuring Vulkan features when creating a GPU device
|
||||
* Added SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION_BOOLEAN to allow requiring Vulkan hardware acceleration when creating a GPU device
|
||||
* Added SDL_GetGPUDeviceProperties() to query information from a GPU device:
|
||||
- SDL_PROP_GPU_DEVICE_NAME_STRING
|
||||
- SDL_PROP_GPU_DEVICE_DRIVER_NAME_STRING
|
||||
- SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING
|
||||
- SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING
|
||||
* Added SDL_GetPixelFormatFromGPUTextureFormat() and SDL_GetGPUTextureFormatFromPixelFormat()
|
||||
* Added SDL_CreateGPURenderer() and SDL_GetGPURendererDevice() to create a 2D renderer for use with GPU rendering.
|
||||
* Added SDL_CreateGPURenderState(), SDL_SetGPURenderStateFragmentUniforms(), SDL_SetGPURenderState(), and SDL_DestroyGPURenderState() to use fragment shaders with a GPU 2D renderer
|
||||
* Added SDL_PROP_TEXTURE_CREATE_GPU_TEXTURE_POINTER to create a 2D texture from an existing GPU texture
|
||||
* Added SDL_PROP_TEXTURE_GPU_TEXTURE_POINTER to get the GPU texture from a 2D texture when using the GPU 2D renderer
|
||||
* Added support for YUV textures and HDR colorspaces to the GPU 2D renderer
|
||||
* Added support for textures with palettes, and SDL_GetTexturePalette() and SDL_SetTexturePalette() to interact with them
|
||||
* Added SDL_RenderTexture9GridTiled() to do tiled instead of stretched 9-grid texture rendering
|
||||
* Added SDL_GetDefaultTextureScaleMode() and SDL_SetDefaultTextureScaleMode() to set the texture scale mode for new textures
|
||||
* Added SDL_GetRenderTextureAddressMode() and SDL_SetRenderTextureAddressMode() to change the texture addressing mode
|
||||
* Added SDL_TEXTURE_ADDRESS_WRAP to allow wrapping of textures if the renderer has SDL_PROP_RENDERER_TEXTURE_WRAPPING_BOOLEAN set
|
||||
* The default YUV colorspace is BT.601 limited range, for compatibility with SDL2
|
||||
* Added SDL_SCALEMODE_PIXELART as an improved scaling algorithm for pixel art without introducing blurring
|
||||
* Added SDL_FLIP_HORIZONTAL_AND_VERTICAL to flip a surface both horizontally and vertically
|
||||
* Added SDL_LoadPNG(), SDL_LoadPNG_IO(), SDL_SavePNG(), and SDL_SavePNG_IO() to load and save PNG images
|
||||
* Added SDL_LoadSurface() and SDL_LoadSurface_IO() to detect BMP and PNG formats and load them as surfaces
|
||||
* Added SDL_PROP_SURFACE_ROTATION_FLOAT to indicate the rotation needed to display camera images upright
|
||||
* Added SDL_RotateSurface() to create a rotated copy of a surface
|
||||
* SDL_EVENT_WINDOW_EXPOSED now sets data1 to true if it is sent during live resizing
|
||||
* Added SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, which is sent when the usable desktop bounds change
|
||||
* Added SDL_EVENT_SCREEN_KEYBOARD_SHOWN, which is sent when the on-screen keyboard has been shown
|
||||
* Added SDL_EVENT_SCREEN_KEYBOARD_HIDDEN, which is sent when the on-screen keyboard has been hidden
|
||||
* Added pinch gesture events: SDL_EVENT_PINCH_BEGIN, SDL_EVENT_PINCH_UPDATE, SDL_EVENT_PINCH_END
|
||||
* SDL_EVENT_AUDIO_DEVICE_ADDED will be sent during initialization for each audio device
|
||||
* SDL_GetCameraPermissionState() returns SDL_CameraPermissionState instead of int
|
||||
* Added SDL_PutAudioStreamDataNoCopy() to do more efficient audio stream processing in some cases
|
||||
* Added SDL_PutAudioStreamPlanarData() to add planar audio data instead of interleaved data to an audio stream
|
||||
* Added SDL_HINT_AUDIO_DEVICE_RAW_STREAM to signal that the OS shouldn't do further audio processing, useful for applications that handle noise canceling, etc.
|
||||
* Added SDL_PROP_AUDIOSTREAM_AUTO_CLEANUP_BOOLEAN to allow streams that persist beyond the audio subsystem lifetime.
|
||||
* Added enhanced support for 8BitDo controllers
|
||||
* Added enhanced support for FlyDigi controllers
|
||||
* Added enhanced support for Hand Held Legend SInput controllers
|
||||
* Added support for wired Nintendo Switch 2 controllers when built with libusb
|
||||
* Added SDL_hid_get_properties() to associate SDL properties with HID devices
|
||||
* Added SDL_PROP_HIDAPI_LIBUSB_DEVICE_HANDLE_POINTER to query the libusb handle from an SDL_hid_device, if it's been opened with libusb
|
||||
* Added SDL_SetRelativeMouseTransform() to add custom mouse input transformation
|
||||
* Added SDL_GetPenDeviceType() to determine whether a pen is on the screen or on a separate touchpad
|
||||
* SDL_HINT_MAIN_CALLBACK_RATE may be set to a floating point callback rate
|
||||
* Added SDL_GetEventDescription() to get an English description of an event, suitable for logging
|
||||
* Added SDL_PROP_IOSTREAM_MEMORY_FREE_FUNC_POINTER to allow custom freeing of the memory used by SDL_IOFromMem() and SDL_IOFromConstMem()
|
||||
* Added SDL_PROP_PROCESS_CREATE_WORKING_DIRECTORY_STRING to set the working directory for new processes
|
||||
* Added verbose log output when the DEBUG_INVOCATION environment variable is set to "1"
|
||||
* Added SDL_AddAtomicU32()
|
||||
* Added SDL_GetSystemPageSize() to get the system page size
|
||||
* Added SDL_ALIGNED() to signal that data should have a specific alignment
|
||||
|
||||
Windows:
|
||||
* Added SDL_HINT_RENDER_DIRECT3D11_WARP to enable D3D11 software rasterization
|
||||
* Using SDL_InsertGPUDebugLabel(), SDL_PushGPUDebugGroup(), and SDL_PopGPUDebugGroup() requires WinPixEventRuntime.dll to be in your PATH or in the same directory as your executable
|
||||
* Added SDL_PROP_DISPLAY_WINDOWS_HMONITOR_POINTER so you can query the HMONITOR associated with a display
|
||||
* SDL_HINT_AUDIO_DEVICE_STREAM_ROLE is used by the WASAPI audio driver to set the audio stream category
|
||||
* Added SDL_HINT_AUDIO_DEVICE_RAW_STREAM to signal whether the OS audio driver should do additional signal processing
|
||||
* Added SDL_HINT_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS to allow disabling some system hotkeys when in raw input mode
|
||||
* SDL_HINT_WINDOWS_GAMEINPUT is disabled by default
|
||||
|
||||
macOS:
|
||||
* Added SDL_HINT_MAC_PRESS_AND_HOLD to control whether holding down a key will repeat the pressed key or open the accents menu
|
||||
|
||||
Linux:
|
||||
* Added atomic support for KMSDRM
|
||||
* Added SDL_HINT_KMSDRM_ATOMIC to control whether KMSDRM will use atomic functionality
|
||||
* Added SDL_PROP_DISPLAY_WAYLAND_WL_OUTPUT_POINTER so you can query the wl_output associated with a display
|
||||
|
||||
Emscripten:
|
||||
* Added SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT for applications that don't want to be fullscreen, but would like to fill the window
|
||||
* Added SDL_WINDOW_FILL_DOCUMENT to indicate that windows expand to fill the whole browser window
|
||||
* Added SDL_SetWindowFillDocument() to change whether windows expand to fill the whole browser window
|
||||
* Added SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING to allow setting the SDL canvas ID, and SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING to query it on existing windows
|
||||
* Added SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING to specify where keyboard input is bound, and SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING to query it on existing windows
|
||||
|
||||
iOS:
|
||||
* SDL now supports window scenes, fixing the warning "CLIENT OF UIKIT REQUIRES UPDATE"
|
||||
* Added SDL_PROP_WINDOW_CREATE_WINDOWSCENE_POINTER to specify the window scene for a window
|
||||
|
||||
visionOS:
|
||||
* The default refresh rate has been increased to 90Hz
|
||||
* SDL_SetWindowSize() changes the size of the window on Vision Pro headsets
|
||||
|
||||
PlayStation 2:
|
||||
* Added the following hints to control the display parameters: SDL_HINT_PS2_GS_WIDTH, SDL_HINT_PS2_GS_HEIGHT, SDL_HINT_PS2_GS_PROGRESSIVE, SDL_HINT_PS2_GS_MODE
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.3.4</string>
|
||||
<string>3.3.5</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>SDLX</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.3.4</string>
|
||||
<string>3.3.5</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -3145,8 +3145,8 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DEPLOYMENT_POSTPROCESSING = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 305.0.0;
|
||||
DYLIB_CURRENT_VERSION = 305.0.0;
|
||||
DYLIB_COMPATIBILITY_VERSION = 306.0.0;
|
||||
DYLIB_CURRENT_VERSION = 306.0.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_ALTIVEC_EXTENSIONS = YES;
|
||||
@@ -3181,7 +3181,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.3.4;
|
||||
MARKETING_VERSION = 3.3.5;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
PRODUCT_NAME = SDL3;
|
||||
@@ -3211,8 +3211,8 @@
|
||||
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 305.0.0;
|
||||
DYLIB_CURRENT_VERSION = 305.0.0;
|
||||
DYLIB_COMPATIBILITY_VERSION = 306.0.0;
|
||||
DYLIB_CURRENT_VERSION = 306.0.0;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
@@ -3244,7 +3244,7 @@
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
MARKETING_VERSION = 3.3.4;
|
||||
MARKETING_VERSION = 3.3.5;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Title SDL 3.3.4
|
||||
Title SDL 3.3.5
|
||||
Version 1
|
||||
Description SDL Library for macOS (http://www.libsdl.org)
|
||||
DefaultLocation /Library/Frameworks
|
||||
|
||||
@@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||
private static final String TAG = "SDL";
|
||||
private static final int SDL_MAJOR_VERSION = 3;
|
||||
private static final int SDL_MINOR_VERSION = 3;
|
||||
private static final int SDL_MICRO_VERSION = 4;
|
||||
private static final int SDL_MICRO_VERSION = 5;
|
||||
/*
|
||||
// Display InputType.SOURCE/CLASS of events and devices
|
||||
//
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main include header for the SDL library, version 3.3.4
|
||||
* Main include header for the SDL library, version 3.3.5
|
||||
*
|
||||
* It is almost always best to include just this one header instead of
|
||||
* picking out individual headers included here. There are exceptions to
|
||||
|
||||
@@ -577,6 +577,15 @@ extern SDL_DECLSPEC SDL_AudioDeviceID * SDLCALL SDL_GetAudioRecordingDevices(int
|
||||
/**
|
||||
* Get the human-readable name of a specific audio device.
|
||||
*
|
||||
* **WARNING**: this function will work with SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK
|
||||
* and SDL_AUDIO_DEVICE_DEFAULT_RECORDING, returning the current default
|
||||
* physical devices' names. However, as the default device may change at any
|
||||
* time, it is likely better to show a generic name to the user, like "System
|
||||
* default audio device" or perhaps "default [currently %s]". Do not store
|
||||
* this name to disk to reidentify the device in a later run of the program,
|
||||
* as the default might change in general, and the string will be the name of
|
||||
* a specific device and not the abstract system default.
|
||||
*
|
||||
* \param devid the instance ID of the device to query.
|
||||
* \returns the name of the audio device, or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
|
||||
@@ -2361,7 +2361,7 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties(
|
||||
* When no such structure is provided, SDL will use Vulkan API version 1.0 and
|
||||
* a minimal set of features. The requested API version influences how the
|
||||
* feature_list is processed by SDL. When requesting API version 1.0, the
|
||||
* feature_list is ignored. Only the vulkan_10_phyisical_device_features and
|
||||
* feature_list is ignored. Only the vulkan_10_physical_device_features and
|
||||
* the extension lists are used. When requesting API version 1.1, the
|
||||
* feature_list is scanned for feature structures introduced in Vulkan 1.1.
|
||||
* When requesting Vulkan 1.2 or higher, the feature_list is additionally
|
||||
|
||||
@@ -787,32 +787,6 @@ extern "C" {
|
||||
*/
|
||||
#define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT"
|
||||
|
||||
/**
|
||||
* Dictate that windows on Emscripten will fill the whole browser window.
|
||||
*
|
||||
* When enabled, the canvas element fills the entire document. Resize events
|
||||
* will be generated as the browser window is resized, as that will adjust the
|
||||
* canvas size as well. The canvas will cover anything else on the page,
|
||||
* including any controls provided by Emscripten in its generated HTML file
|
||||
* (in fact, any elements on the page that aren't the canvas will be moved
|
||||
* into a hidden `div` element).
|
||||
*
|
||||
* Often times this is desirable for a browser-based game, but it means
|
||||
* several things that we expect of an SDL window on other platforms might not
|
||||
* work as expected, such as minimum window sizes and aspect ratios.
|
||||
*
|
||||
* This hint overrides SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN
|
||||
* properties when creating an SDL window.
|
||||
*
|
||||
* This hint only applies to the Emscripten platform.
|
||||
*
|
||||
* This hint can be set at any time (before creating the window, or to toggle
|
||||
* its state later). Only one window can fill the document at a time.
|
||||
*
|
||||
* \since This hint is available since SDL 3.4.0.
|
||||
*/
|
||||
#define SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT "SDL_EMSCRIPTEN_FILL_DOCUMENT"
|
||||
|
||||
/**
|
||||
* A variable that controls whether the on-screen keyboard should be shown
|
||||
* when text input is active.
|
||||
|
||||
@@ -203,10 +203,10 @@ typedef Uint32 SDL_MouseButtonFlags;
|
||||
* \sa SDL_SetRelativeMouseTransform
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_MouseMotionTransformCallback)(
|
||||
void *userdata,
|
||||
Uint64 timestamp,
|
||||
SDL_Window *window,
|
||||
SDL_MouseID mouseID,
|
||||
void *userdata,
|
||||
Uint64 timestamp,
|
||||
SDL_Window *window,
|
||||
SDL_MouseID mouseID,
|
||||
float *x, float *y
|
||||
);
|
||||
|
||||
|
||||
@@ -241,9 +241,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
|
||||
* left edge of the image, if this surface is being used as a cursor.
|
||||
* - `SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER`: the hotspot pixel offset from the
|
||||
* top edge of the image, if this surface is being used as a cursor.
|
||||
* - `SDL_PROP_SURFACE_ROTATION_NUMBER`: the number of degrees a surface's
|
||||
* data is meant to be rotated clockwise to make the image right-side up.
|
||||
* Default 0. This is used by the camera API, if a mobile device is oriented
|
||||
* - `SDL_PROP_SURFACE_ROTATION_FLOAT`: the number of degrees a surface's data
|
||||
* is meant to be rotated clockwise to make the image right-side up. Default
|
||||
* 0. This is used by the camera API, if a mobile device is oriented
|
||||
* differently than what its camera provides (i.e. - the camera always
|
||||
* provides portrait images but the phone is being held in landscape
|
||||
* orientation). Since SDL 3.4.0.
|
||||
@@ -263,7 +263,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac
|
||||
#define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap"
|
||||
#define SDL_PROP_SURFACE_HOTSPOT_X_NUMBER "SDL.surface.hotspot.x"
|
||||
#define SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER "SDL.surface.hotspot.y"
|
||||
#define SDL_PROP_SURFACE_ROTATION_NUMBER "SDL.surface.rotation"
|
||||
#define SDL_PROP_SURFACE_ROTATION_FLOAT "SDL.surface.rotation"
|
||||
|
||||
/**
|
||||
* Set the colorspace used by a surface.
|
||||
@@ -1027,6 +1027,14 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipM
|
||||
* larger than the original, with the background filled in with the colorkey,
|
||||
* if available, or RGBA 255/255/255/0 if not.
|
||||
*
|
||||
* If `surface` has the SDL_PROP_SURFACE_ROTATION_FLOAT property set on it,
|
||||
* the new copy will have the adjusted value set: if the rotation property is
|
||||
* 90 and `angle` was 30, the new surface will have a property value of 60
|
||||
* (that is: to be upright vs gravity, this surface needs to rotate 60 more
|
||||
* degrees). However, note that further rotations on the new surface in this
|
||||
* example will produce unexpected results, since the image will have resized
|
||||
* and padded to accommodate the not-90 degree angle.
|
||||
*
|
||||
* \param surface the surface to rotate.
|
||||
* \param angle the rotation angle, in degrees.
|
||||
* \returns a rotated copy of the surface or NULL on failure; call
|
||||
|
||||
@@ -62,7 +62,7 @@ extern "C" {
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MICRO_VERSION 4
|
||||
#define SDL_MICRO_VERSION 5
|
||||
|
||||
/**
|
||||
* This macro turns the version numbers into a numeric value.
|
||||
|
||||
+33
-14
@@ -215,6 +215,7 @@ typedef Uint64 SDL_WindowFlags;
|
||||
#define SDL_WINDOW_TOOLTIP SDL_UINT64_C(0x0000000000040000) /**< window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window */
|
||||
#define SDL_WINDOW_POPUP_MENU SDL_UINT64_C(0x0000000000080000) /**< window should be treated as a popup menu, requires a parent window */
|
||||
#define SDL_WINDOW_KEYBOARD_GRABBED SDL_UINT64_C(0x0000000000100000) /**< window has grabbed keyboard input */
|
||||
#define SDL_WINDOW_FILL_DOCUMENT SDL_UINT64_C(0x0000000000200000) /**< window is in fill-document mode (Emscripten only), since SDL 3.4.0 */
|
||||
#define SDL_WINDOW_VULKAN SDL_UINT64_C(0x0000000010000000) /**< window usable for Vulkan surface */
|
||||
#define SDL_WINDOW_METAL SDL_UINT64_C(0x0000000020000000) /**< window usable for Metal view */
|
||||
#define SDL_WINDOW_TRANSPARENT SDL_UINT64_C(0x0000000040000000) /**< window with transparent buffer */
|
||||
@@ -1370,15 +1371,6 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren
|
||||
*
|
||||
* - `SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING`: the id given to the
|
||||
* canvas element. This should start with a '#' sign
|
||||
* - `SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN`: true to make
|
||||
* the canvas element fill the entire document. Resize events will be
|
||||
* generated as the browser window is resized, as that will adjust the
|
||||
* canvas size as well. The canvas will cover anything else on the page,
|
||||
* including any controls provided by Emscripten in its generated HTML file.
|
||||
* Often times this is desirable for a browser-based game, but it means
|
||||
* several things that we expect of an SDL window on other platforms might
|
||||
* not work as expected, such as minimum window sizes and aspect ratios.
|
||||
* Default false.
|
||||
* - `SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING`: override the
|
||||
* binding element for keyboard inputs for this canvas. The variable can be
|
||||
* one of:
|
||||
@@ -1453,7 +1445,6 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowWithProperties(SDL_Prop
|
||||
#define SDL_PROP_WINDOW_CREATE_WIN32_PIXEL_FORMAT_HWND_POINTER "SDL.window.create.win32.pixel_format_hwnd"
|
||||
#define SDL_PROP_WINDOW_CREATE_X11_WINDOW_NUMBER "SDL.window.create.x11.window"
|
||||
#define SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_CANVAS_ID_STRING "SDL.window.create.emscripten.canvas_id"
|
||||
#define SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN "SDL.window.create.emscripten.fill_document"
|
||||
#define SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING "SDL.window.create.emscripten.keyboard_element"
|
||||
|
||||
/**
|
||||
@@ -1623,9 +1614,6 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowParent(SDL_Window *window)
|
||||
*
|
||||
* - `SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING`: the id the canvas element
|
||||
* will have
|
||||
* - `SDL_PROP_WINDOW_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN`: true if the canvas is
|
||||
* set to consume the entire browser window, bypassing some SDL window
|
||||
* functionality.
|
||||
* - `SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING`: the keyboard
|
||||
* element that associates keyboard events to this window
|
||||
*
|
||||
@@ -1675,7 +1663,6 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetWindowProperties(SDL_Window
|
||||
#define SDL_PROP_WINDOW_X11_SCREEN_NUMBER "SDL.window.x11.screen"
|
||||
#define SDL_PROP_WINDOW_X11_WINDOW_NUMBER "SDL.window.x11.window"
|
||||
#define SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING "SDL.window.emscripten.canvas_id"
|
||||
#define SDL_PROP_WINDOW_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN "SDL.window.emscripten.fill_document"
|
||||
#define SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING "SDL.window.emscripten.keyboard_element"
|
||||
|
||||
/**
|
||||
@@ -1694,6 +1681,7 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetWindowProperties(SDL_Window
|
||||
* \sa SDL_MinimizeWindow
|
||||
* \sa SDL_SetWindowFullscreen
|
||||
* \sa SDL_SetWindowMouseGrab
|
||||
* \sa SDL_SetWindowFillDocument
|
||||
* \sa SDL_ShowWindow
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_WindowFlags SDLCALL SDL_GetWindowFlags(SDL_Window *window);
|
||||
@@ -2163,6 +2151,37 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowResizable(SDL_Window *window, bool
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowAlwaysOnTop(SDL_Window *window, bool on_top);
|
||||
|
||||
/**
|
||||
* Set the window to fill the current document space (Emscripten only).
|
||||
*
|
||||
* This will add or remove the window's `SDL_WINDOW_FILL_DOCUMENT` flag.
|
||||
*
|
||||
* Currently this flag only applies to the Emscripten target.
|
||||
*
|
||||
* When enabled, the canvas element fills the entire document. Resize events
|
||||
* will be generated as the browser window is resized, as that will adjust the
|
||||
* canvas size as well. The canvas will cover anything else on the page,
|
||||
* including any controls provided by Emscripten in its generated HTML file
|
||||
* (in fact, any elements on the page that aren't the canvas will be moved
|
||||
* into a hidden `div` element).
|
||||
*
|
||||
* Often times this is desirable for a browser-based game, but it means
|
||||
* several things that we expect of an SDL window on other platforms might not
|
||||
* work as expected, such as minimum window sizes and aspect ratios.
|
||||
*
|
||||
* \param window the window of which to change the fill-document state.
|
||||
* \param fill true to set the window to fill the document, false to disable.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_GetWindowFlags
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowFillDocument(SDL_Window *window, bool fill);
|
||||
|
||||
/**
|
||||
* Show a window.
|
||||
*
|
||||
|
||||
@@ -1579,6 +1579,14 @@ const char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid)
|
||||
// remains valid (in case the device is unplugged at the wrong moment), we hold the
|
||||
// subsystem_rwlock while we copy the string.
|
||||
SDL_LockRWLockForReading(current_audio.subsystem_rwlock);
|
||||
|
||||
// Allow default device IDs to be used, just return the current default physical device's name.
|
||||
if (devid == SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK) {
|
||||
devid = current_audio.default_playback_device_id;
|
||||
} else if (devid == SDL_AUDIO_DEVICE_DEFAULT_RECORDING) {
|
||||
devid = current_audio.default_recording_device_id;
|
||||
}
|
||||
|
||||
SDL_FindInHashTable(islogical ? current_audio.device_hash_logical : current_audio.device_hash_physical, (const void *) (uintptr_t) devid, &vdev);
|
||||
if (!vdev) {
|
||||
SDL_SetError("Invalid audio device instance ID");
|
||||
|
||||
@@ -150,7 +150,7 @@ static size_t GetFrameBufLen(const SDL_CameraSpec *spec)
|
||||
return wxh * SDL_BYTESPERPIXEL(fmt);
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult ZombieAcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult ZombieAcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
const SDL_CameraSpec *spec = &device->actual_spec;
|
||||
|
||||
@@ -832,7 +832,7 @@ bool SDL_CameraThreadIterate(SDL_Camera *device)
|
||||
SDL_Surface *output_surface = NULL;
|
||||
SurfaceList *slist = NULL;
|
||||
Uint64 timestampNS = 0;
|
||||
int rotation = 0;
|
||||
float rotation = 0.0f;
|
||||
|
||||
// AcquireFrame SHOULD NOT BLOCK, as we are holding a lock right now. Block in WaitDevice instead!
|
||||
const SDL_CameraFrameResult rc = device->AcquireFrame(device, device->acquire_surface, ×tampNS, &rotation);
|
||||
@@ -929,7 +929,7 @@ bool SDL_CameraThreadIterate(SDL_Camera *device)
|
||||
acquired->pixels = NULL;
|
||||
acquired->pitch = 0;
|
||||
|
||||
SDL_SetNumberProperty(SDL_GetSurfaceProperties(output_surface), SDL_PROP_SURFACE_ROTATION_NUMBER, rotation);
|
||||
SDL_SetFloatProperty(SDL_GetSurfaceProperties(output_surface), SDL_PROP_SURFACE_ROTATION_FLOAT, rotation);
|
||||
|
||||
// make the filled output surface available to the app.
|
||||
SDL_LockMutex(device->lock);
|
||||
|
||||
@@ -99,7 +99,7 @@ struct SDL_Camera
|
||||
|
||||
// These are, initially, set from camera_driver, but we might swap them out with Zombie versions on disconnect/failure.
|
||||
bool (*WaitDevice)(SDL_Camera *device);
|
||||
SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation);
|
||||
SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation);
|
||||
void (*ReleaseFrame)(SDL_Camera *device, SDL_Surface *frame);
|
||||
|
||||
// All supported formats/dimensions for this device.
|
||||
@@ -178,7 +178,7 @@ typedef struct SDL_CameraDriverImpl
|
||||
bool (*OpenDevice)(SDL_Camera *device, const SDL_CameraSpec *spec);
|
||||
void (*CloseDevice)(SDL_Camera *device);
|
||||
bool (*WaitDevice)(SDL_Camera *device);
|
||||
SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation); // set frame->pixels, frame->pitch, *timestampNS, and *rotation!
|
||||
SDL_CameraFrameResult (*AcquireFrame)(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation); // set frame->pixels, frame->pitch, *timestampNS, and *rotation!
|
||||
void (*ReleaseFrame)(SDL_Camera *device, SDL_Surface *frame); // Reclaim frame->pixels and frame->pitch!
|
||||
void (*FreeDeviceHandle)(SDL_Camera *device); // SDL is done with this device; free the handle from SDL_AddCamera()
|
||||
void (*Deinitialize)(void);
|
||||
|
||||
@@ -296,7 +296,7 @@ static bool ANDROIDCAMERA_WaitDevice(SDL_Camera *device)
|
||||
return true; // this isn't used atm, since we run our own thread via onImageAvailable callbacks.
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult ANDROIDCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult ANDROIDCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
SDL_CameraFrameResult result = SDL_CAMERA_FRAME_READY;
|
||||
media_status_t res;
|
||||
@@ -380,7 +380,7 @@ static SDL_CameraFrameResult ANDROIDCAMERA_AcquireFrame(SDL_Camera *device, SDL_
|
||||
dev_rotation = -dev_rotation; // we want to subtract this value, instead of add, if back-facing.
|
||||
}
|
||||
|
||||
*rotation = dev_rotation + device->hidden->rotation; // current phone orientation, static camera orientation in relation to phone.
|
||||
*rotation = (float) (dev_rotation + device->hidden->rotation); // current phone orientation, static camera orientation in relation to phone.
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ static bool COREMEDIA_WaitDevice(SDL_Camera *device)
|
||||
return true; // this isn't used atm, since we run our own thread out of Grand Central Dispatch.
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult COREMEDIA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult COREMEDIA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
SDL_CameraFrameResult result = SDL_CAMERA_FRAME_READY;
|
||||
SDLPrivateCameraData *hidden = (__bridge SDLPrivateCameraData *) device->hidden;
|
||||
@@ -243,21 +243,21 @@ static SDL_CameraFrameResult COREMEDIA_AcquireFrame(SDL_Camera *device, SDL_Surf
|
||||
// there is probably math for this, but this is easy to slap into a table.
|
||||
// rotation = rotations[uiorientation-1][devorientation-1];
|
||||
if (device->position == SDL_CAMERA_POSITION_BACK_FACING) {
|
||||
static const int back_rotations[4][4] = {
|
||||
static const Uint16 back_rotations[4][4] = {
|
||||
{ 90, 90, 90, 90 }, // ui portrait
|
||||
{ 270, 270, 270, 270 }, // ui portait upside down
|
||||
{ 0, 0, 0, 0 }, // ui landscape left
|
||||
{ 180, 180, 180, 180 } // ui landscape right
|
||||
};
|
||||
*rotation = back_rotations[ui_orientation - 1][device_orientation - 1];
|
||||
*rotation = (float) back_rotations[ui_orientation - 1][device_orientation - 1];
|
||||
} else {
|
||||
static const int front_rotations[4][4] = {
|
||||
static const Uint16 front_rotations[4][4] = {
|
||||
{ 90, 90, 270, 270 }, // ui portrait
|
||||
{ 270, 270, 90, 90 }, // ui portait upside down
|
||||
{ 0, 0, 180, 180 }, // ui landscape left
|
||||
{ 180, 180, 0, 0 } // ui landscape right
|
||||
};
|
||||
*rotation = front_rotations[ui_orientation - 1][device_orientation - 1];
|
||||
*rotation = (float) front_rotations[ui_orientation - 1][device_orientation - 1];
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -320,10 +320,37 @@ static bool COREMEDIA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec *spec)
|
||||
|
||||
const float FRAMERATE_EPSILON = 0.01f;
|
||||
for (AVFrameRateRange *framerate in format.videoSupportedFrameRateRanges) {
|
||||
if (rate > (framerate.minFrameRate - FRAMERATE_EPSILON) &&
|
||||
rate < (framerate.maxFrameRate + FRAMERATE_EPSILON)) {
|
||||
spec_format = format;
|
||||
break;
|
||||
// Check if the requested rate is within the supported range
|
||||
if (rate >= (framerate.minFrameRate - FRAMERATE_EPSILON) &&
|
||||
rate <= (framerate.maxFrameRate + FRAMERATE_EPSILON)) {
|
||||
|
||||
// Prefer formats with narrower frame rate ranges that are closer to our target
|
||||
// This helps avoid formats that support a wide range (like 10-60 FPS)
|
||||
// when we want a specific rate (like 30 FPS)
|
||||
bool should_select = false;
|
||||
if (spec_format == nil) {
|
||||
should_select = true;
|
||||
} else {
|
||||
AVFrameRateRange *current_range = spec_format.videoSupportedFrameRateRanges.firstObject;
|
||||
float current_range_width = current_range.maxFrameRate - current_range.minFrameRate;
|
||||
float new_range_width = framerate.maxFrameRate - framerate.minFrameRate;
|
||||
|
||||
// Prefer formats with narrower ranges, or if ranges are similar, prefer closer to target
|
||||
if (new_range_width < current_range_width) {
|
||||
should_select = true;
|
||||
} else if (SDL_fabsf(new_range_width - current_range_width) < 0.1f) {
|
||||
// Similar range width, prefer the one closer to our target rate
|
||||
float current_distance = SDL_fabsf(rate - current_range.minFrameRate);
|
||||
float new_distance = SDL_fabsf(rate - framerate.minFrameRate);
|
||||
if (new_distance < current_distance) {
|
||||
should_select = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (should_select) {
|
||||
spec_format = format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,6 +366,22 @@ static bool COREMEDIA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec *spec)
|
||||
}
|
||||
|
||||
avdevice.activeFormat = spec_format;
|
||||
|
||||
// Try to set the frame duration to enforce the requested frame rate
|
||||
const float frameRate = (float)spec->framerate_numerator / spec->framerate_denominator;
|
||||
const CMTime frameDuration = CMTimeMake(1, (int32_t)frameRate);
|
||||
|
||||
// Check if the device supports setting frame duration
|
||||
if ([avdevice respondsToSelector:@selector(setActiveVideoMinFrameDuration:)] &&
|
||||
[avdevice respondsToSelector:@selector(setActiveVideoMaxFrameDuration:)]) {
|
||||
@try {
|
||||
avdevice.activeVideoMinFrameDuration = frameDuration;
|
||||
avdevice.activeVideoMaxFrameDuration = frameDuration;
|
||||
} @catch (NSException *exception) {
|
||||
// Some devices don't support setting frame duration, that's okay
|
||||
}
|
||||
}
|
||||
|
||||
[avdevice unlockForConfiguration];
|
||||
|
||||
AVCaptureSession *session = [[AVCaptureSession alloc] init];
|
||||
@@ -394,6 +437,15 @@ static bool COREMEDIA_OpenDevice(SDL_Camera *device, const SDL_CameraSpec *spec)
|
||||
}
|
||||
[session addOutput:output];
|
||||
|
||||
// Try to set the frame rate on the connection
|
||||
AVCaptureConnection *connection = [output connectionWithMediaType:AVMediaTypeVideo];
|
||||
if (connection && connection.isVideoMinFrameDurationSupported) {
|
||||
connection.videoMinFrameDuration = frameDuration;
|
||||
if (connection.isVideoMaxFrameDurationSupported) {
|
||||
connection.videoMaxFrameDuration = frameDuration;
|
||||
}
|
||||
}
|
||||
|
||||
[session commitConfiguration];
|
||||
|
||||
SDLPrivateCameraData *hidden = [[SDLPrivateCameraData alloc] init];
|
||||
|
||||
@@ -38,7 +38,7 @@ static bool DUMMYCAMERA_WaitDevice(SDL_Camera *device)
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult DUMMYCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult DUMMYCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return SDL_CAMERA_FRAME_ERROR;
|
||||
|
||||
@@ -39,7 +39,7 @@ static bool EMSCRIPTENCAMERA_WaitDevice(SDL_Camera *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult EMSCRIPTENCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult EMSCRIPTENCAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
void *rgba = SDL_malloc(device->actual_spec.width * device->actual_spec.height * 4);
|
||||
if (!rgba) {
|
||||
|
||||
@@ -430,7 +430,7 @@ static void SDLCALL CleanupIMFMediaBuffer(void *userdata, void *value)
|
||||
SDL_free(objs);
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
SDL_assert(device->hidden->current_sample != NULL);
|
||||
|
||||
@@ -562,7 +562,7 @@ static SDL_CameraFrameResult MEDIAFOUNDATION_CopyFrame(SDL_Surface *frame, const
|
||||
return SDL_CAMERA_FRAME_READY;
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult MEDIAFOUNDATION_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
SDL_assert(device->hidden->current_sample != NULL);
|
||||
|
||||
|
||||
@@ -577,7 +577,7 @@ static bool PIPEWIRECAMERA_WaitDevice(SDL_Camera *device)
|
||||
return true;
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult PIPEWIRECAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult PIPEWIRECAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
struct pw_buffer *b;
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ static bool V4L2_WaitDevice(SDL_Camera *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult V4L2_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
const int fd = device->hidden->fd;
|
||||
const io_method io = device->hidden->io;
|
||||
@@ -801,7 +801,7 @@ static void MaybeAddDevice(const char *path)
|
||||
const int stepw = (int) frmsizeenum.stepwise.step_width;
|
||||
const int steph = (int) frmsizeenum.stepwise.step_height;
|
||||
for (int w = minw; w <= maxw; w += stepw) {
|
||||
for (int h = minh; w <= maxh; w += steph) {
|
||||
for (int h = minh; h <= maxh; h += steph) {
|
||||
#if DEBUG_CAMERA
|
||||
SDL_Log("CAMERA: * Has %s size %dx%d", (frmsizeenum.type == V4L2_FRMSIZE_TYPE_STEPWISE) ? "stepwise" : "continuous", w, h);
|
||||
#endif
|
||||
|
||||
@@ -190,7 +190,7 @@ static bool VITACAMERA_WaitDevice(SDL_Camera *device)
|
||||
return true;
|
||||
}
|
||||
|
||||
static SDL_CameraFrameResult VITACAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, int *rotation)
|
||||
static SDL_CameraFrameResult VITACAMERA_AcquireFrame(SDL_Camera *device, SDL_Surface *frame, Uint64 *timestampNS, float *rotation)
|
||||
{
|
||||
SceCameraRead read = {0};
|
||||
read.size = sizeof(SceCameraRead);
|
||||
|
||||
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,3,4,0
|
||||
PRODUCTVERSION 3,3,4,0
|
||||
FILEVERSION 3,3,5,0
|
||||
PRODUCTVERSION 3,3,5,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS 0x40004L
|
||||
@@ -23,12 +23,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "\0"
|
||||
VALUE "FileDescription", "SDL\0"
|
||||
VALUE "FileVersion", "3, 3, 4, 0\0"
|
||||
VALUE "FileVersion", "3, 3, 5, 0\0"
|
||||
VALUE "InternalName", "SDL\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2025 Sam Lantinga\0"
|
||||
VALUE "OriginalFilename", "SDL3.dll\0"
|
||||
VALUE "ProductName", "Simple DirectMedia Layer\0"
|
||||
VALUE "ProductVersion", "3, 3, 4, 0\0"
|
||||
VALUE "ProductVersion", "3, 3, 5, 0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -1270,6 +1270,7 @@ SDL3_0.0.0 {
|
||||
SDL_RotateSurface;
|
||||
SDL_LoadSurface_IO;
|
||||
SDL_LoadSurface;
|
||||
SDL_SetWindowFillDocument;
|
||||
# extra symbols go here (don't modify this line)
|
||||
local: *;
|
||||
};
|
||||
@@ -1296,3 +1296,4 @@
|
||||
#define SDL_RotateSurface SDL_RotateSurface_REAL
|
||||
#define SDL_LoadSurface_IO SDL_LoadSurface_IO_REAL
|
||||
#define SDL_LoadSurface SDL_LoadSurface_REAL
|
||||
#define SDL_SetWindowFillDocument SDL_SetWindowFillDocument_REAL
|
||||
@@ -1304,3 +1304,4 @@ SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateAnimatedCursor,(SDL_CursorFrameInfo *a,int
|
||||
SDL_DYNAPI_PROC(SDL_Surface*,SDL_RotateSurface,(SDL_Surface *a,float b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadSurface_IO,(SDL_IOStream *a,bool b),(a,b),return)
|
||||
SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadSurface,(const char *a),(a),return)
|
||||
SDL_DYNAPI_PROC(bool,SDL_SetWindowFillDocument,(SDL_Window *a,bool b),(a,b),return)
|
||||
@@ -1238,16 +1238,8 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
|
||||
SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, SDL_RendererEventWatch, renderer);
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_EMSCRIPTEN // don't change vsync on Emscripten unless explicitly requested; we already set this with a mainloop, and a 0 default causes problems here.
|
||||
if (SDL_HasProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER)) {
|
||||
const int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0);
|
||||
SDL_SetRenderVSync(renderer, vsync);
|
||||
}
|
||||
#else // everything else defaults to no vsync if not requested.
|
||||
const int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0);
|
||||
int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0);
|
||||
SDL_SetRenderVSync(renderer, vsync);
|
||||
#endif
|
||||
|
||||
SDL_CalculateSimulatedVSyncInterval(renderer, window);
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_RENDER,
|
||||
|
||||
@@ -1787,10 +1787,10 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
|
||||
}
|
||||
}
|
||||
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32); // SDL_PIXELFORMAT_ARGB8888 on little endian systems
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX32);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX32);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8);
|
||||
|
||||
@@ -1933,7 +1933,7 @@ static bool GL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_Pr
|
||||
|
||||
// RGBA32 is always supported with OpenGL
|
||||
if (bgra_supported) {
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32); // SDL_PIXELFORMAT_ARGB8888 on little endian systems
|
||||
}
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32);
|
||||
|
||||
|
||||
@@ -2430,10 +2430,10 @@ static bool GLES2_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
|
||||
data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer);
|
||||
data->window_framebuffer = (GLuint)window_framebuffer;
|
||||
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32); // SDL_PIXELFORMAT_ARGB8888 on little endian systems
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX32);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX32);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8);
|
||||
#ifdef SDL_HAVE_YUV
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12);
|
||||
|
||||
@@ -395,9 +395,11 @@ static bool VULKAN_UpdateTextureInternal(VULKAN_RenderData *rendererData, VkImag
|
||||
static SDL_PixelFormat VULKAN_VkFormatToSDLPixelFormat(VkFormat vkFormat)
|
||||
{
|
||||
switch (vkFormat) {
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
return SDL_PIXELFORMAT_ARGB8888;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
return SDL_PIXELFORMAT_RGBA32;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
return SDL_PIXELFORMAT_BGRA32;
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
|
||||
return SDL_PIXELFORMAT_ABGR8888;
|
||||
case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
|
||||
return SDL_PIXELFORMAT_ABGR2101010;
|
||||
@@ -430,8 +432,12 @@ static VkDeviceSize VULKAN_GetBytesPerPixel(VkFormat vkFormat, int plane)
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16_UNORM:
|
||||
return 4;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT:
|
||||
@@ -454,16 +460,23 @@ static VkFormat SDLPixelFormatToVkTextureFormat(Uint32 format, Uint32 output_col
|
||||
return VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
case SDL_PIXELFORMAT_ABGR2101010:
|
||||
return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
|
||||
case SDL_PIXELFORMAT_ARGB8888:
|
||||
if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
|
||||
return VK_FORMAT_B8G8R8A8_SRGB;
|
||||
}
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
case SDL_PIXELFORMAT_ABGR8888:
|
||||
case SDL_PIXELFORMAT_RGBA32:
|
||||
if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
|
||||
return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
}
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case SDL_PIXELFORMAT_BGRA32:
|
||||
if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
|
||||
return VK_FORMAT_B8G8R8A8_SRGB;
|
||||
}
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
case SDL_PIXELFORMAT_ABGR8888:
|
||||
if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
|
||||
return VK_FORMAT_A8B8G8R8_SRGB_PACK32;
|
||||
}
|
||||
return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||
#endif
|
||||
case SDL_PIXELFORMAT_INDEX8:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
case SDL_PIXELFORMAT_YUY2:
|
||||
@@ -4553,8 +4566,11 @@ static bool VULKAN_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SD
|
||||
VULKAN_InvalidateCachedState(renderer);
|
||||
|
||||
renderer->name = VULKAN_RenderDriver.name;
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32); // SDL_PIXELFORMAT_ARGB8888 on little endian systems
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32);
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888);
|
||||
#endif
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT);
|
||||
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8);
|
||||
|
||||
@@ -137,13 +137,14 @@ static bool STEAM_EnumerateStorageDirectory(void *userdata, const char *path, SD
|
||||
}
|
||||
fname = file + dirlen;
|
||||
} else {
|
||||
// Make sure this is a top-level file
|
||||
if (SDL_strchr(file, '/') != NULL) {
|
||||
continue;
|
||||
}
|
||||
fname = file;
|
||||
}
|
||||
|
||||
// Make sure this is a file in the current directory
|
||||
if (SDL_strchr(fname, '/') != NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (callback(callback_userdata, dirname, fname)) {
|
||||
case SDL_ENUM_SUCCESS:
|
||||
done = true;
|
||||
|
||||
@@ -2497,6 +2497,15 @@ SDL_AppResult SDLTest_CommonEventMainCallbacks(SDLTest_CommonState *state, const
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_D:
|
||||
if (withControl) {
|
||||
/* Ctrl-D toggle fill-document */
|
||||
SDL_Window *window = SDL_GetWindowFromEvent(event);
|
||||
if (window) {
|
||||
SDL_SetWindowFillDocument(window, !((SDL_GetWindowFlags(window) & SDL_WINDOW_FILL_DOCUMENT) != 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_P:
|
||||
if (withAlt) {
|
||||
/* Alt-P cycle through progress states */
|
||||
|
||||
+2
-2
@@ -1107,8 +1107,8 @@ SDL_GLContext SDL_EGL_CreateContext(SDL_VideoDevice *_this, EGLSurface egl_surfa
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The default swap interval is 1, according to the spec
|
||||
_this->egl_data->egl_swapinterval = 1;
|
||||
// The default swap interval is 1, according to the spec, but SDL3's policy is to default vsync to off by default.
|
||||
_this->egl_data->egl_swapinterval = 0;
|
||||
|
||||
if (!SDL_EGL_MakeCurrent(_this, egl_surface, (SDL_GLContext)egl_context)) {
|
||||
// Delete the context
|
||||
|
||||
@@ -2198,6 +2198,14 @@ SDL_Surface *SDL_RotateSurface(SDL_Surface *surface, float angle)
|
||||
SDL_DestroySurface(convert);
|
||||
}
|
||||
}
|
||||
|
||||
if (rotated) {
|
||||
if (SDL_HasProperty(surface->props, SDL_PROP_SURFACE_ROTATION_FLOAT)) {
|
||||
const float rotation = (SDL_GetNumberProperty(surface->props, SDL_PROP_SURFACE_ROTATION_FLOAT, 0) - angle);
|
||||
SDL_SetFloatProperty(SDL_GetSurfaceProperties(rotated), SDL_PROP_SURFACE_ROTATION_FLOAT, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
return rotated;
|
||||
}
|
||||
|
||||
|
||||
@@ -312,6 +312,7 @@ struct SDL_VideoDevice
|
||||
bool (*FlashWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
bool (*ApplyWindowProgress)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*SetWindowFocusable)(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
|
||||
bool (*SetWindowFillDocument)(SDL_VideoDevice *_this, SDL_Window *window, bool fill);
|
||||
bool (*SyncWindow)(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
bool (*ReconfigureWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_WindowFlags flags);
|
||||
|
||||
|
||||
+24
-1
@@ -2199,7 +2199,7 @@ SDL_PixelFormat SDL_GetWindowPixelFormat(SDL_Window *window)
|
||||
}
|
||||
|
||||
#define CREATE_FLAGS \
|
||||
(SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_TRANSPARENT | SDL_WINDOW_NOT_FOCUSABLE)
|
||||
(SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_TRANSPARENT | SDL_WINDOW_NOT_FOCUSABLE | SDL_WINDOW_FILL_DOCUMENT)
|
||||
|
||||
static SDL_INLINE bool IsAcceptingDragAndDrop(void)
|
||||
{
|
||||
@@ -2557,6 +2557,10 @@ SDL_Window *SDL_CreateWindowWithProperties(SDL_PropertiesID props)
|
||||
window->external_graphics_context = external_graphics_context;
|
||||
window->constrain_popup = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN, true);
|
||||
|
||||
if (!_this->SetWindowFillDocument) {
|
||||
window->flags &= ~SDL_WINDOW_FILL_DOCUMENT; // not an error, just unsupported here, so remove the flag.
|
||||
}
|
||||
|
||||
if (_this->windows) {
|
||||
_this->windows->prev = window;
|
||||
}
|
||||
@@ -3914,6 +3918,25 @@ bool SDL_SetWindowFocusable(SDL_Window *window, bool focusable)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_SetWindowFillDocument(SDL_Window *window, bool fill)
|
||||
{
|
||||
CHECK_WINDOW_MAGIC(window, false);
|
||||
|
||||
const bool want = (fill != false); // normalize the flag.
|
||||
const bool have = ((window->flags & SDL_WINDOW_FILL_DOCUMENT) != 0);
|
||||
if ((want != have) && (_this->SetWindowFillDocument)) {
|
||||
if (!_this->SetWindowFillDocument(_this, window, want)) {
|
||||
return false;
|
||||
} else if (want) {
|
||||
window->flags |= SDL_WINDOW_FILL_DOCUMENT;
|
||||
} else {
|
||||
window->flags &= ~SDL_WINDOW_FILL_DOCUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDL_UpdateWindowGrab(SDL_Window *window)
|
||||
{
|
||||
bool keyboard_grabbed, mouse_grabbed;
|
||||
|
||||
@@ -50,6 +50,7 @@ static SDL_FullscreenResult Emscripten_SetWindowFullscreen(SDL_VideoDevice *_thi
|
||||
static void Emscripten_PumpEvents(SDL_VideoDevice *_this);
|
||||
static void Emscripten_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
static bool Emscripten_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
|
||||
static bool Emscripten_SetWindowFillDocument(SDL_VideoDevice *_this, SDL_Window *window, bool fill);
|
||||
|
||||
SDL_Window *Emscripten_fill_document_window = NULL;
|
||||
|
||||
@@ -58,11 +59,8 @@ static int pending_swap_interval = -1;
|
||||
|
||||
// Emscripten driver bootstrap functions
|
||||
|
||||
static void SDLCALL Emscripten_FillDocHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint);
|
||||
|
||||
static void Emscripten_DeleteDevice(SDL_VideoDevice *device)
|
||||
{
|
||||
SDL_RemoveHintCallback(SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT, Emscripten_FillDocHintChanged, device);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
@@ -177,6 +175,7 @@ static SDL_VideoDevice *Emscripten_CreateDevice(void)
|
||||
device->GetWindowSizeInPixels = Emscripten_GetWindowSizeInPixels;
|
||||
device->DestroyWindow = Emscripten_DestroyWindow;
|
||||
device->SetWindowFullscreen = Emscripten_SetWindowFullscreen;
|
||||
device->SetWindowFillDocument = Emscripten_SetWindowFillDocument;
|
||||
|
||||
device->CreateWindowFramebuffer = Emscripten_CreateWindowFramebuffer;
|
||||
device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer;
|
||||
@@ -197,8 +196,6 @@ static SDL_VideoDevice *Emscripten_CreateDevice(void)
|
||||
Emscripten_ListenSystemTheme();
|
||||
device->system_theme = Emscripten_GetSystemTheme();
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT, Emscripten_FillDocHintChanged, device);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
@@ -463,14 +460,16 @@ EMSCRIPTEN_KEEPALIVE void requestFullscreenThroughSDL(SDL_Window *window)
|
||||
SDL_SetWindowFullscreen(window, true);
|
||||
}
|
||||
|
||||
static void Emscripten_SetWindowFillDocState(SDL_Window *window, bool enable)
|
||||
static bool Emscripten_SetWindowFillDocument(SDL_VideoDevice *_this, SDL_Window *window, bool fill)
|
||||
{
|
||||
SDL_WindowData *wdata = window->internal;
|
||||
|
||||
SDL_assert(!Emscripten_fill_document_window || !enable); // one at a time, sorry.
|
||||
if (fill && Emscripten_fill_document_window && (Emscripten_fill_document_window != window)) {
|
||||
return SDL_SetError("Only one fill-document window allowed at a time.");
|
||||
}
|
||||
|
||||
// fill_document takes up the entire page and resizes as the browser window resizes.
|
||||
if (enable) {
|
||||
if (fill) {
|
||||
Emscripten_fill_document_window = window;
|
||||
|
||||
const int w = MAIN_THREAD_EM_ASM_INT({ return window.innerWidth; });
|
||||
@@ -558,20 +557,8 @@ static void Emscripten_SetWindowFillDocState(SDL_Window *window, bool enable)
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, wdata->non_fill_document_width, wdata->non_fill_document_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SDLCALL Emscripten_FillDocHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
const bool enabled = SDL_GetStringBoolean(hint, false);
|
||||
if (Emscripten_fill_document_window && !enabled) {
|
||||
Emscripten_SetWindowFillDocState(Emscripten_fill_document_window, false);
|
||||
} else if (!Emscripten_fill_document_window && enabled) {
|
||||
/// there's currently only ever one canvas, but if this changes later, we can choose the one with keyboard focus or something.
|
||||
SDL_VideoDevice *device = (SDL_VideoDevice *) userdata;
|
||||
if (device && device->windows) { // take first window in the list for now.
|
||||
Emscripten_SetWindowFillDocState(device->windows, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
|
||||
@@ -580,6 +567,12 @@ static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
double css_w, css_h;
|
||||
const char *selector;
|
||||
|
||||
bool fill_document = ((window->flags & SDL_WINDOW_FILL_DOCUMENT) != 0);
|
||||
if (fill_document && Emscripten_fill_document_window) {
|
||||
fill_document = false; // only one allowed at a time.
|
||||
window->flags &= ~SDL_WINDOW_FILL_DOCUMENT; // !!! FIXME: should this fail instead?
|
||||
}
|
||||
|
||||
// Allocate window internal data
|
||||
wdata = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData));
|
||||
if (!wdata) {
|
||||
@@ -598,15 +591,6 @@ static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
}
|
||||
wdata->keyboard_element = SDL_strdup(selector);
|
||||
|
||||
bool fill_document;
|
||||
if (Emscripten_fill_document_window) {
|
||||
fill_document = false; // only one allowed at a time.
|
||||
} else if (SDL_GetHint(SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT)) {
|
||||
fill_document = SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_FILL_DOCUMENT, false);
|
||||
} else {
|
||||
fill_document = SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN, false);
|
||||
}
|
||||
|
||||
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
|
||||
wdata->pixel_ratio = emscripten_get_device_pixel_ratio();
|
||||
} else {
|
||||
@@ -629,7 +613,7 @@ static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
|
||||
wdata->non_fill_document_width = window->w;
|
||||
wdata->non_fill_document_height = window->h;
|
||||
Emscripten_SetWindowFillDocState(window, fill_document);
|
||||
Emscripten_SetWindowFillDocument(_this, window, fill_document);
|
||||
|
||||
// One window, it always has focus
|
||||
SDL_SetMouseFocus(window);
|
||||
@@ -647,7 +631,6 @@ static bool Emscripten_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
// Ensure various things are added to the window's properties
|
||||
SDL_SetStringProperty(window->props, SDL_PROP_WINDOW_EMSCRIPTEN_CANVAS_ID_STRING, wdata->canvas_id);
|
||||
SDL_SetStringProperty(window->props, SDL_PROP_WINDOW_EMSCRIPTEN_KEYBOARD_ELEMENT_STRING, wdata->keyboard_element);
|
||||
SDL_SetBooleanProperty(window->props, SDL_PROP_WINDOW_EMSCRIPTEN_FILL_DOCUMENT_BOOLEAN, fill_document);
|
||||
|
||||
// Window has been successfully created
|
||||
return true;
|
||||
@@ -695,9 +678,7 @@ static void Emscripten_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data;
|
||||
|
||||
if (Emscripten_fill_document_window == window) {
|
||||
Emscripten_SetWindowFillDocState(window, false);
|
||||
}
|
||||
Emscripten_SetWindowFillDocument(_this, window, false);
|
||||
|
||||
if (window->internal) {
|
||||
data = window->internal;
|
||||
@@ -812,6 +793,11 @@ static bool Emscripten_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
// Pass PNG data to JavaScript
|
||||
MAIN_THREAD_EM_ASM({
|
||||
var pngData = HEAPU8.subarray($0, $0 + $1);
|
||||
if (pngData.buffer instanceof SharedArrayBuffer) {
|
||||
// explicitly create a copy
|
||||
pngData = new Uint8Array(pngData);
|
||||
}
|
||||
|
||||
var blob = new Blob([pngData], {type: 'image/png'});
|
||||
var url = URL.createObjectURL(blob);
|
||||
|
||||
|
||||
@@ -1011,13 +1011,10 @@ static int XLookupStringAsUTF8(XKeyEvent *event_struct, char *buffer_return, int
|
||||
return result;
|
||||
}
|
||||
|
||||
SDL_WindowData *X11_FindWindow(SDL_VideoDevice *_this, Window window)
|
||||
SDL_WindowData *X11_FindWindow(SDL_VideoData *videodata, Window window)
|
||||
{
|
||||
const SDL_VideoData *videodata = _this->internal;
|
||||
int i;
|
||||
|
||||
if (videodata && videodata->windowlist) {
|
||||
for (i = 0; i < videodata->numwindows; ++i) {
|
||||
for (int i = 0; i < videodata->numwindows; ++i) {
|
||||
if ((videodata->windowlist[i] != NULL) &&
|
||||
(videodata->windowlist[i]->xwindow == window)) {
|
||||
return videodata->windowlist[i];
|
||||
@@ -1341,7 +1338,7 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
|
||||
// xsettings internally filters events for the windows it watches
|
||||
X11_HandleXsettingsEvent(_this, xevent);
|
||||
|
||||
data = X11_FindWindow(_this, xevent->xany.window);
|
||||
data = X11_FindWindow(videodata, xevent->xany.window);
|
||||
|
||||
if (!data) {
|
||||
// The window for KeymapNotify, etc events is 0
|
||||
|
||||
@@ -33,7 +33,7 @@ extern Uint64 X11_GetEventTimestamp(unsigned long time);
|
||||
extern void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_KeyboardID keyboardID, XEvent *xevent);
|
||||
extern void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, float x, float y, unsigned long time);
|
||||
extern void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, unsigned long time);
|
||||
extern SDL_WindowData *X11_FindWindow(SDL_VideoDevice *_this, Window window);
|
||||
extern SDL_WindowData *X11_FindWindow(SDL_VideoData *videodata, Window window);
|
||||
extern bool X11_ProcessHitTest(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y, bool force_new_result);
|
||||
extern bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y);
|
||||
extern bool X11_IsWheelEvent(int button, int *xticks, int *yticks);
|
||||
|
||||
@@ -130,27 +130,14 @@ static bool xinput2_version_atleast(const int version, const int wantmajor, cons
|
||||
return version >= ((wantmajor * 1000) + wantminor);
|
||||
}
|
||||
|
||||
// !!! FIXME: isn't this just X11_FindWindow?
|
||||
static SDL_WindowData *xinput2_get_sdlwindowdata(SDL_VideoData *videodata, Window window)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < videodata->numwindows; i++) {
|
||||
SDL_WindowData *d = videodata->windowlist[i];
|
||||
if (d->xwindow == window) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_Window *xinput2_get_sdlwindow(SDL_VideoData *videodata, Window window)
|
||||
{
|
||||
const SDL_WindowData *windowdata = xinput2_get_sdlwindowdata(videodata, window);
|
||||
const SDL_WindowData *windowdata = X11_FindWindow(videodata, window);
|
||||
return windowdata ? windowdata->window : NULL;
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO
|
||||
static void xinput2_reset_scrollable_valuators(SDL_VideoData *videodata)
|
||||
static void xinput2_reset_scrollable_valuators()
|
||||
{
|
||||
for (int i = 0; i < scrollable_device_count; ++i) {
|
||||
for (int j = 0; j < scrollable_devices[i].scroll_info_count; ++j) {
|
||||
@@ -519,7 +506,7 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
|
||||
// Handle pen proximity enter/leave
|
||||
if (proev->what == XIPropertyModified && proev->property == videodata->atoms.pen_atom_wacom_serial_ids) {
|
||||
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
|
||||
SDL_WindowData *windowdata = X11_FindWindow(_this, xev->event);
|
||||
SDL_WindowData *windowdata = X11_FindWindow(videodata, xev->event);
|
||||
X11_NotifyPenProximityChange(_this, windowdata ? windowdata->window : NULL, proev->deviceid);
|
||||
}
|
||||
} break;
|
||||
@@ -546,7 +533,7 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
|
||||
case XI_KeyRelease:
|
||||
{
|
||||
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
|
||||
SDL_WindowData *windowdata = X11_FindWindow(_this, xev->event);
|
||||
SDL_WindowData *windowdata = X11_FindWindow(videodata, xev->event);
|
||||
XEvent xevent;
|
||||
|
||||
if (xev->deviceid != xev->sourceid) {
|
||||
@@ -615,7 +602,7 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
|
||||
}
|
||||
} else if (!pointer_emulated) {
|
||||
// Otherwise assume a regular mouse
|
||||
SDL_WindowData *windowdata = xinput2_get_sdlwindowdata(videodata, xev->event);
|
||||
SDL_WindowData *windowdata = X11_FindWindow(videodata, xev->event);
|
||||
int x_ticks = 0, y_ticks = 0;
|
||||
|
||||
// Slave pointer devices don't have button remapping applied automatically, so do it manually.
|
||||
@@ -643,7 +630,7 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO
|
||||
case XI_Enter:
|
||||
xinput2_reset_scrollable_valuators(videodata);
|
||||
xinput2_reset_scrollable_valuators();
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
+19
-4
@@ -102,6 +102,21 @@ define_property(TARGET PROPERTY SDL_NONINTERACTIVE BRIEF_DOCS "If true, target i
|
||||
define_property(TARGET PROPERTY SDL_NONINTERACTIVE_ARGUMENTS BRIEF_DOCS "Argument(s) to run executable in non-interactive mode." FULL_DOCS "Argument(s) to run executable in non-interactive mode.")
|
||||
define_property(TARGET PROPERTY SDL_NONINTERACTIVE_TIMEOUT BRIEF_DOCS "Timeout for noninteractive executable." FULL_DOCS "Timeout for noninteractive executable.")
|
||||
|
||||
if(HAVE_X11)
|
||||
find_package(X11 QUIET)
|
||||
if(NOT TARGET X11::X11)
|
||||
set(HAVE_X11 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_WAYLAND)
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(PkgWaylandClient QUIET IMPORTED_TARGET wayland-client)
|
||||
if(NOT TARGET PkgConfig::PkgWaylandClient)
|
||||
set(HAVE_WAYLAND OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(add_sdl_test_executable TARGET)
|
||||
cmake_parse_arguments(AST "BUILD_DEPENDENT;NONINTERACTIVE;NEEDS_RESOURCES;TESTUTILS;THREADS;MAIN_CALLBACKS;NOTRACKMEM" "" "DEPENDS;DISABLE_THREADS_ARGS;NONINTERACTIVE_TIMEOUT;NONINTERACTIVE_ARGS;INSTALLED_ARGS;SOURCES" ${ARGN})
|
||||
if(AST_UNPARSED_ARGUMENTS)
|
||||
@@ -338,15 +353,15 @@ elseif(HAVE_X11 OR HAVE_WAYLAND)
|
||||
add_sdl_test_executable(testnative BUILD_DEPENDENT NEEDS_RESOURCES TESTUTILS SOURCES testnative.c)
|
||||
if(HAVE_X11)
|
||||
target_sources(testnative PRIVATE testnativex11.c)
|
||||
target_link_libraries(testnative PRIVATE X11)
|
||||
target_link_libraries(testnative PRIVATE X11::X11)
|
||||
endif()
|
||||
if(HAVE_WAYLAND)
|
||||
set_property(SOURCE ${SDL3_BINARY_DIR}/wayland-generated-protocols/xdg-shell-protocol.c PROPERTY GENERATED 1)
|
||||
target_sources(testnative PRIVATE testnativewayland.c ${SDL3_BINARY_DIR}/wayland-generated-protocols/xdg-shell-protocol.c)
|
||||
target_sources(testnative PRIVATE testnativewayland.c "${SDL3_BINARY_DIR}/wayland-generated-protocols/xdg-shell-protocol.c")
|
||||
|
||||
# Needed to silence the documentation warning in the generated header file
|
||||
target_compile_options(testnative PRIVATE -Wno-documentation-unknown-command)
|
||||
target_link_libraries(testnative PRIVATE wayland-client)
|
||||
target_link_libraries(testnative PRIVATE PkgConfig::PkgWaylandClient)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
@@ -452,7 +467,7 @@ if (HAVE_WAYLAND)
|
||||
add_sdl_test_executable(testwaylandcustom NEEDS_RESOURCES SOURCES testwaylandcustom.c ${SDL3_BINARY_DIR}/wayland-generated-protocols/xdg-shell-protocol.c)
|
||||
# Needed to silence the documentation warning in the generated header file
|
||||
target_compile_options(testwaylandcustom PRIVATE -Wno-documentation-unknown-command)
|
||||
target_link_libraries(testwaylandcustom PRIVATE wayland-client)
|
||||
target_link_libraries(testwaylandcustom PRIVATE PkgConfig::PkgWaylandClient)
|
||||
endif()
|
||||
|
||||
check_c_compiler_flag(-Wformat-overflow HAVE_WFORMAT_OVERFLOW)
|
||||
|
||||
@@ -109,6 +109,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
|
||||
}
|
||||
|
||||
SDL_Log("Using audio driver: %s", SDL_GetCurrentAudioDriver());
|
||||
SDL_Log("Current audio device name: %s", SDL_GetAudioDeviceName(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK));
|
||||
|
||||
stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &wave.spec, NULL, NULL);
|
||||
if (!stream) {
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
#include <SDL3/SDL_test.h>
|
||||
#include "testautomation_suites.h"
|
||||
|
||||
static bool test_double_isfinite(double d)
|
||||
{
|
||||
union {
|
||||
Uint64 u64;
|
||||
double d;
|
||||
} d_u;
|
||||
d_u.d = d;
|
||||
return (d_u.u64 & 0x7ff0000000000000ULL) != 0x7ff0000000000000ULL;
|
||||
}
|
||||
|
||||
/* ================= Test Case Implementation ================== */
|
||||
|
||||
/* Fixture */
|
||||
@@ -1147,11 +1157,11 @@ static int SDLCALL audio_resampleLoss(void *arg)
|
||||
SDL_DestroyAudioStream(stream);
|
||||
SDL_free(buf_out);
|
||||
signal_to_noise = 10 * SDL_log10(sum_squared_value / sum_squared_error); /* decibel */
|
||||
SDLTest_AssertCheck(ISFINITE(sum_squared_value), "Sum of squared target should be finite.");
|
||||
SDLTest_AssertCheck(ISFINITE(sum_squared_error), "Sum of squared error should be finite.");
|
||||
SDLTest_AssertCheck(test_double_isfinite(sum_squared_value), "Sum of squared target should be finite.");
|
||||
SDLTest_AssertCheck(test_double_isfinite(sum_squared_error), "Sum of squared error should be finite.");
|
||||
/* Infinity is theoretically possible when there is very little to no noise */
|
||||
SDLTest_AssertCheck(!ISNAN(signal_to_noise), "Signal-to-noise ratio should not be NaN.");
|
||||
SDLTest_AssertCheck(ISFINITE(max_error), "Maximum conversion error should be finite.");
|
||||
SDLTest_AssertCheck(test_double_isfinite(max_error), "Maximum conversion error should be finite.");
|
||||
SDLTest_AssertCheck(signal_to_noise >= spec->signal_to_noise, "Conversion signal-to-noise ratio %f dB should be no less than %f dB.",
|
||||
signal_to_noise, spec->signal_to_noise);
|
||||
SDLTest_AssertCheck(max_error <= spec->max_error, "Maximum conversion error %f should be no more than %f.",
|
||||
@@ -1440,11 +1450,11 @@ static int SDLCALL audio_formatChange(void *arg)
|
||||
}
|
||||
|
||||
signal_to_noise = 10 * SDL_log10(sum_squared_value / sum_squared_error); /* decibel */
|
||||
SDLTest_AssertCheck(ISFINITE(sum_squared_value), "Sum of squared target should be finite.");
|
||||
SDLTest_AssertCheck(ISFINITE(sum_squared_error), "Sum of squared error should be finite.");
|
||||
SDLTest_AssertCheck(test_double_isfinite(sum_squared_value), "Sum of squared target should be finite.");
|
||||
SDLTest_AssertCheck(test_double_isfinite(sum_squared_error), "Sum of squared error should be finite.");
|
||||
/* Infinity is theoretically possible when there is very little to no noise */
|
||||
SDLTest_AssertCheck(!ISNAN(signal_to_noise), "Signal-to-noise ratio should not be NaN.");
|
||||
SDLTest_AssertCheck(ISFINITE(max_error), "Maximum conversion error should be finite.");
|
||||
SDLTest_AssertCheck(test_double_isfinite(max_error), "Maximum conversion error should be finite.");
|
||||
SDLTest_AssertCheck(signal_to_noise >= target_signal_to_noise, "Conversion signal-to-noise ratio %f dB should be no less than %f dB.",
|
||||
signal_to_noise, target_signal_to_noise);
|
||||
SDLTest_AssertCheck(max_error <= target_max_error, "Maximum conversion error %f should be no more than %f.",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#define ISFINITE(X) isfinite((float)(X))
|
||||
#define ISINF(X) isinf((float)(X))
|
||||
#define ISNAN(X) isnan((float)(X))
|
||||
|
||||
|
||||
+1
-1
@@ -364,7 +364,7 @@ SDL_AppResult SDL_AppIterate(void *appstate)
|
||||
// device might be rotated to a different one (like an iPhone providing portrait images even if you hold
|
||||
// the phone in landscape mode). The rotation is how far to rotate the image clockwise to put it right-side
|
||||
// up, for how the user would expect it to be for how they are holding the device.
|
||||
const int rotation = (int) SDL_GetNumberProperty(SDL_GetSurfaceProperties(frame_current), SDL_PROP_SURFACE_ROTATION_NUMBER, 0);
|
||||
const float rotation = SDL_GetFloatProperty(SDL_GetSurfaceProperties(frame_current), SDL_PROP_SURFACE_ROTATION_FLOAT, 0.0f);
|
||||
SDL_GetRenderOutputSize(renderer, &win_w, &win_h);
|
||||
d.x = ((win_w - texture->w) / 2.0f);
|
||||
d.y = ((win_h - texture->h) / 2.0f);
|
||||
|
||||
Reference in new issue
Block a user