diff --git a/Dockerfile b/Dockerfile index 38286b4..ec76d73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,12 @@ RUN apt-get update && \ WORKDIR /tmp COPY .config/dotnet-tools.json .config/dotnet-tools.json COPY SDL3-CS/SDL3-CS.csproj SDL3-CS/SDL3-CS.csproj + +# .NET 8 installed using the distro package does not support the android workload. +# Since the project is only used for reference purposes, we'll retarget it to a single framework. +# See: https://github.com/dotnet/core/discussions/9258#discussioncomment-9548857 +RUN sed -i 's/net8.0<\/TargetFramework>/' SDL3-CS/SDL3-CS.csproj + RUN dotnet tool restore && \ dotnet restore --ucr SDL3-CS/SDL3-CS.csproj @@ -16,4 +22,4 @@ RUN echo '#!/bin/bash' >> entrypoint.sh && \ echo 'python3 SDL3-CS/generate_bindings.py "$@"' >> entrypoint.sh && \ chmod +x entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file +ENTRYPOINT ["/entrypoint.sh"] diff --git a/External/SDL b/External/SDL index e027b85..6fa6297 160000 --- a/External/SDL +++ b/External/SDL @@ -1 +1 @@ -Subproject commit e027b85cc457556071cbb2f3f1bcf8803c1bc001 +Subproject commit 6fa6297441e387abdc565daa44a04e07acd55624 diff --git a/SDL3-CS.Tests.iOS/SDL3-CS.Tests.iOS.csproj b/SDL3-CS.Tests.iOS/SDL3-CS.Tests.iOS.csproj index db14f90..31c6e93 100644 --- a/SDL3-CS.Tests.iOS/SDL3-CS.Tests.iOS.csproj +++ b/SDL3-CS.Tests.iOS/SDL3-CS.Tests.iOS.csproj @@ -8,6 +8,7 @@ true 13.0 true + iPhone Developer diff --git a/SDL3-CS.Tests/Program.cs b/SDL3-CS.Tests/Program.cs index 8e44865..acfa9bb 100644 --- a/SDL3-CS.Tests/Program.cs +++ b/SDL3-CS.Tests/Program.cs @@ -32,6 +32,8 @@ namespace SDL.Tests window.Setup(); window.Create(); + printWindows(); + const SDL_Keymod state = SDL_Keymod.SDL_KMOD_CAPS | SDL_Keymod.SDL_KMOD_ALT; SDL_SetModState(state); Debug.Assert(SDL_GetModState() == state); @@ -64,5 +66,17 @@ namespace SDL.Tests } } } + + private static unsafe void printWindows() + { + using var windows = SDL_GetWindows(); + if (windows == null) + return; + + for (int i = 0; i < windows.Count; i++) + { + Console.WriteLine($"Window {i} title: {SDL_GetWindowTitle(windows[i])}"); + } + } } } diff --git a/SDL3-CS/SDL3-CS.csproj b/SDL3-CS/SDL3-CS.csproj index b3ef941..4f627a6 100644 --- a/SDL3-CS/SDL3-CS.csproj +++ b/SDL3-CS/SDL3-CS.csproj @@ -7,6 +7,7 @@ enable true $(NoWarn);SYSLIB1054;CA1401 + $(DefineConstants);JETBRAINS_ANNOTATIONS diff --git a/SDL3-CS/SDL3/ClangSharp/SDL_audio.g.cs b/SDL3-CS/SDL3/ClangSharp/SDL_audio.g.cs index de63476..6a38aa0 100644 --- a/SDL3-CS/SDL3/ClangSharp/SDL_audio.g.cs +++ b/SDL3-CS/SDL3/ClangSharp/SDL_audio.g.cs @@ -87,6 +87,14 @@ namespace SDL [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, [NativeTypeName("const SDL_AudioSpec *")] SDL_AudioSpec* spec); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: NativeTypeName("bool")] + public static extern SDLBool SDL_IsAudioDevicePhysical(SDL_AudioDeviceID devid); + + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: NativeTypeName("bool")] + public static extern SDLBool SDL_IsAudioDevicePlayback(SDL_AudioDeviceID devid); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: NativeTypeName("bool")] public static extern SDLBool SDL_PauseAudioDevice(SDL_AudioDeviceID dev); diff --git a/SDL3-CS/SDL3/ClangSharp/SDL_dialog.g.cs b/SDL3-CS/SDL3/ClangSharp/SDL_dialog.g.cs index 7109c6b..8c09112 100644 --- a/SDL3-CS/SDL3/ClangSharp/SDL_dialog.g.cs +++ b/SDL3-CS/SDL3/ClangSharp/SDL_dialog.g.cs @@ -37,6 +37,13 @@ namespace SDL public byte* pattern; } + public enum SDL_FileDialogType + { + SDL_FILEDIALOG_OPENFILE, + SDL_FILEDIALOG_SAVEFILE, + SDL_FILEDIALOG_OPENFOLDER, + } + public static unsafe partial class SDL3 { [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] @@ -47,5 +54,32 @@ namespace SDL [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void SDL_ShowOpenFolderDialog([NativeTypeName("SDL_DialogFileCallback")] delegate* unmanaged[Cdecl] callback, [NativeTypeName("void*")] IntPtr userdata, SDL_Window* window, [NativeTypeName("const char *")] byte* default_location, [NativeTypeName("bool")] SDLBool allow_many); + + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void SDL_ShowFileDialogWithProperties(SDL_FileDialogType type, [NativeTypeName("SDL_DialogFileCallback")] delegate* unmanaged[Cdecl] callback, [NativeTypeName("void*")] IntPtr userdata, SDL_PropertiesID props); + + [NativeTypeName("#define SDL_PROP_FILE_DIALOG_FILTERS_POINTER \"SDL.filedialog.filters\"")] + public static ReadOnlySpan SDL_PROP_FILE_DIALOG_FILTERS_POINTER => "SDL.filedialog.filters"u8; + + [NativeTypeName("#define SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER \"SDL.filedialog.nfilters\"")] + public static ReadOnlySpan SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER => "SDL.filedialog.nfilters"u8; + + [NativeTypeName("#define SDL_PROP_FILE_DIALOG_WINDOW_POINTER \"SDL.filedialog.window\"")] + public static ReadOnlySpan SDL_PROP_FILE_DIALOG_WINDOW_POINTER => "SDL.filedialog.window"u8; + + [NativeTypeName("#define SDL_PROP_FILE_DIALOG_LOCATION_STRING \"SDL.filedialog.location\"")] + public static ReadOnlySpan SDL_PROP_FILE_DIALOG_LOCATION_STRING => "SDL.filedialog.location"u8; + + [NativeTypeName("#define SDL_PROP_FILE_DIALOG_MANY_BOOLEAN \"SDL.filedialog.many\"")] + public static ReadOnlySpan SDL_PROP_FILE_DIALOG_MANY_BOOLEAN => "SDL.filedialog.many"u8; + + [NativeTypeName("#define SDL_PROP_FILE_DIALOG_TITLE_STRING \"SDL.filedialog.title\"")] + public static ReadOnlySpan SDL_PROP_FILE_DIALOG_TITLE_STRING => "SDL.filedialog.title"u8; + + [NativeTypeName("#define SDL_PROP_FILE_DIALOG_ACCEPT_STRING \"SDL.filedialog.accept\"")] + public static ReadOnlySpan SDL_PROP_FILE_DIALOG_ACCEPT_STRING => "SDL.filedialog.accept"u8; + + [NativeTypeName("#define SDL_PROP_FILE_DIALOG_CANCEL_STRING \"SDL.filedialog.cancel\"")] + public static ReadOnlySpan SDL_PROP_FILE_DIALOG_CANCEL_STRING => "SDL.filedialog.cancel"u8; } } diff --git a/SDL3-CS/SDL3/ClangSharp/SDL_events.g.cs b/SDL3-CS/SDL3/ClangSharp/SDL_events.g.cs index 99b24ba..dcc7559 100644 --- a/SDL3-CS/SDL3/ClangSharp/SDL_events.g.cs +++ b/SDL3-CS/SDL3/ClangSharp/SDL_events.g.cs @@ -711,6 +711,19 @@ namespace SDL public SDL_CameraID which; } + public partial struct SDL_RenderEvent + { + public SDL_EventType type; + + [NativeTypeName("Uint32")] + public uint reserved; + + [NativeTypeName("Uint64")] + public ulong timestamp; + + public SDL_WindowID windowID; + } + public partial struct SDL_TouchFingerEvent { public SDL_EventType type; @@ -1064,6 +1077,9 @@ namespace SDL [FieldOffset(0)] public SDL_PenAxisEvent paxis; + [FieldOffset(0)] + public SDL_RenderEvent render; + [FieldOffset(0)] public SDL_DropEvent drop; diff --git a/SDL3-CS/SDL3/ClangSharp/SDL_filesystem.g.cs b/SDL3-CS/SDL3/ClangSharp/SDL_filesystem.g.cs index 2806487..4faaf1e 100644 --- a/SDL3-CS/SDL3/ClangSharp/SDL_filesystem.g.cs +++ b/SDL3-CS/SDL3/ClangSharp/SDL_filesystem.g.cs @@ -115,6 +115,10 @@ namespace SDL [return: NativeTypeName("char **")] public static extern byte** SDL_GlobDirectory([NativeTypeName("const char *")] byte* path, [NativeTypeName("const char *")] byte* pattern, SDL_GlobFlags flags, int* count); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetCurrentDirectory", ExactSpelling = true)] + [return: NativeTypeName("char *")] + public static extern byte* Unsafe_SDL_GetCurrentDirectory(); + [NativeTypeName("#define SDL_GLOB_CASEINSENSITIVE (1u << 0)")] public const uint SDL_GLOB_CASEINSENSITIVE = (1U << 0); } diff --git a/SDL3-CS/SDL3/ClangSharp/SDL_gpu.g.cs b/SDL3-CS/SDL3/ClangSharp/SDL_gpu.g.cs index 2eb4d23..5b95a15 100644 --- a/SDL3-CS/SDL3/ClangSharp/SDL_gpu.g.cs +++ b/SDL3-CS/SDL3/ClangSharp/SDL_gpu.g.cs @@ -1335,6 +1335,10 @@ namespace SDL [return: NativeTypeName("bool")] public static extern SDLBool SDL_SetGPUSwapchainParameters(SDL_GPUDevice* device, SDL_Window* window, SDL_GPUSwapchainComposition swapchain_composition, SDL_GPUPresentMode present_mode); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: NativeTypeName("bool")] + public static extern SDLBool SDL_SetGPUAllowedFramesInFlight(SDL_GPUDevice* device, [NativeTypeName("Uint32")] uint allowed_frames_in_flight); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern SDL_GPUTextureFormat SDL_GetGPUSwapchainTextureFormat(SDL_GPUDevice* device, SDL_Window* window); @@ -1342,6 +1346,14 @@ namespace SDL [return: NativeTypeName("bool")] public static extern SDLBool SDL_AcquireGPUSwapchainTexture(SDL_GPUCommandBuffer* command_buffer, SDL_Window* window, SDL_GPUTexture** swapchain_texture, [NativeTypeName("Uint32 *")] uint* swapchain_texture_width, [NativeTypeName("Uint32 *")] uint* swapchain_texture_height); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: NativeTypeName("bool")] + public static extern SDLBool SDL_WaitForGPUSwapchain(SDL_GPUDevice* device, SDL_Window* window); + + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: NativeTypeName("bool")] + public static extern SDLBool SDL_WaitAndAcquireGPUSwapchainTexture(SDL_GPUCommandBuffer* command_buffer, SDL_Window* window, SDL_GPUTexture** swapchain_texture, [NativeTypeName("Uint32 *")] uint* swapchain_texture_width, [NativeTypeName("Uint32 *")] uint* swapchain_texture_height); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: NativeTypeName("bool")] public static extern SDLBool SDL_SubmitGPUCommandBuffer(SDL_GPUCommandBuffer* command_buffer); diff --git a/SDL3-CS/SDL3/ClangSharp/SDL_hints.g.cs b/SDL3-CS/SDL3/ClangSharp/SDL_hints.g.cs index fed523f..e93d3ef 100644 --- a/SDL3-CS/SDL3/ClangSharp/SDL_hints.g.cs +++ b/SDL3-CS/SDL3/ClangSharp/SDL_hints.g.cs @@ -97,6 +97,12 @@ namespace SDL [NativeTypeName("#define SDL_HINT_AUDIO_ALSA_DEFAULT_DEVICE \"SDL_AUDIO_ALSA_DEFAULT_DEVICE\"")] public static ReadOnlySpan SDL_HINT_AUDIO_ALSA_DEFAULT_DEVICE => "SDL_AUDIO_ALSA_DEFAULT_DEVICE"u8; + [NativeTypeName("#define SDL_HINT_AUDIO_ALSA_DEFAULT_PLAYBACK_DEVICE \"SDL_AUDIO_ALSA_DEFAULT_PLAYBACK_DEVICE\"")] + public static ReadOnlySpan SDL_HINT_AUDIO_ALSA_DEFAULT_PLAYBACK_DEVICE => "SDL_AUDIO_ALSA_DEFAULT_PLAYBACK_DEVICE"u8; + + [NativeTypeName("#define SDL_HINT_AUDIO_ALSA_DEFAULT_RECORDING_DEVICE \"SDL_AUDIO_ALSA_DEFAULT_RECORDING_DEVICE\"")] + public static ReadOnlySpan SDL_HINT_AUDIO_ALSA_DEFAULT_RECORDING_DEVICE => "SDL_AUDIO_ALSA_DEFAULT_RECORDING_DEVICE"u8; + [NativeTypeName("#define SDL_HINT_AUDIO_CATEGORY \"SDL_AUDIO_CATEGORY\"")] public static ReadOnlySpan SDL_HINT_AUDIO_CATEGORY => "SDL_AUDIO_CATEGORY"u8; @@ -334,6 +340,9 @@ namespace SDL [NativeTypeName("#define SDL_HINT_JOYSTICK_HIDAPI_STEAM \"SDL_JOYSTICK_HIDAPI_STEAM\"")] public static ReadOnlySpan SDL_HINT_JOYSTICK_HIDAPI_STEAM => "SDL_JOYSTICK_HIDAPI_STEAM"u8; + [NativeTypeName("#define SDL_HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED \"SDL_JOYSTICK_HIDAPI_STEAM_HOME_LED\"")] + public static ReadOnlySpan SDL_HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED => "SDL_JOYSTICK_HIDAPI_STEAM_HOME_LED"u8; + [NativeTypeName("#define SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK \"SDL_JOYSTICK_HIDAPI_STEAMDECK\"")] public static ReadOnlySpan SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK => "SDL_JOYSTICK_HIDAPI_STEAMDECK"u8; @@ -460,6 +469,9 @@ namespace SDL [NativeTypeName("#define SDL_HINT_MOUSE_DOUBLE_CLICK_TIME \"SDL_MOUSE_DOUBLE_CLICK_TIME\"")] public static ReadOnlySpan SDL_HINT_MOUSE_DOUBLE_CLICK_TIME => "SDL_MOUSE_DOUBLE_CLICK_TIME"u8; + [NativeTypeName("#define SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR \"SDL_MOUSE_DEFAULT_SYSTEM_CURSOR\"")] + public static ReadOnlySpan SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR => "SDL_MOUSE_DEFAULT_SYSTEM_CURSOR"u8; + [NativeTypeName("#define SDL_HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE \"SDL_MOUSE_EMULATE_WARP_WITH_RELATIVE\"")] public static ReadOnlySpan SDL_HINT_MOUSE_EMULATE_WARP_WITH_RELATIVE => "SDL_MOUSE_EMULATE_WARP_WITH_RELATIVE"u8; diff --git a/SDL3-CS/SDL3/ClangSharp/SDL_init.g.cs b/SDL3-CS/SDL3/ClangSharp/SDL_init.g.cs index 058bf20..8a1b196 100644 --- a/SDL3-CS/SDL3/ClangSharp/SDL_init.g.cs +++ b/SDL3-CS/SDL3/ClangSharp/SDL_init.g.cs @@ -54,6 +54,14 @@ namespace SDL [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] public static extern void SDL_Quit(); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: NativeTypeName("bool")] + public static extern SDLBool SDL_IsMainThread(); + + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: NativeTypeName("bool")] + public static extern SDLBool SDL_RunOnMainThread([NativeTypeName("SDL_MainThreadCallback")] delegate* unmanaged[Cdecl] callback, [NativeTypeName("void*")] IntPtr userdata, [NativeTypeName("bool")] SDLBool wait_complete); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: NativeTypeName("bool")] public static extern SDLBool SDL_SetAppMetadata([NativeTypeName("const char *")] byte* appname, [NativeTypeName("const char *")] byte* appversion, [NativeTypeName("const char *")] byte* appidentifier); diff --git a/SDL3-CS/SDL3/ClangSharp/SDL_render.g.cs b/SDL3-CS/SDL3/ClangSharp/SDL_render.g.cs index 3f00a6d..0d477d8 100644 --- a/SDL3-CS/SDL3/ClangSharp/SDL_render.g.cs +++ b/SDL3-CS/SDL3/ClangSharp/SDL_render.g.cs @@ -344,6 +344,10 @@ namespace SDL [return: NativeTypeName("bool")] public static extern SDLBool SDL_RenderTextureRotated(SDL_Renderer* renderer, SDL_Texture* texture, [NativeTypeName("const SDL_FRect *")] SDL_FRect* srcrect, [NativeTypeName("const SDL_FRect *")] SDL_FRect* dstrect, double angle, [NativeTypeName("const SDL_FPoint *")] SDL_FPoint* center, SDL_FlipMode flip); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + [return: NativeTypeName("bool")] + public static extern SDLBool SDL_RenderTextureAffine(SDL_Renderer* renderer, SDL_Texture* texture, [NativeTypeName("const SDL_FRect *")] SDL_FRect* srcrect, [NativeTypeName("const SDL_FPoint *")] SDL_FPoint* origin, [NativeTypeName("const SDL_FPoint *")] SDL_FPoint* right, [NativeTypeName("const SDL_FPoint *")] SDL_FPoint* down); + [DllImport("SDL3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] [return: NativeTypeName("bool")] public static extern SDLBool SDL_RenderTextureTiled(SDL_Renderer* renderer, SDL_Texture* texture, [NativeTypeName("const SDL_FRect *")] SDL_FRect* srcrect, float scale, [NativeTypeName("const SDL_FRect *")] SDL_FRect* dstrect); diff --git a/SDL3-CS/SDL3/SDL_video.cs b/SDL3-CS/SDL3/SDL_video.cs index 0b952ab..2641bb6 100644 --- a/SDL3-CS/SDL3/SDL_video.cs +++ b/SDL3-CS/SDL3/SDL_video.cs @@ -107,11 +107,11 @@ namespace SDL } [MustDisposeResource] - public static unsafe SDLPointerArray? SDL_GetWindows() + public static unsafe SDLOpaquePointerArray? SDL_GetWindows() { int count; var array = SDL_GetWindows(&count); - return SDLArray.Create(array, count); + return SDLArray.CreateOpaque(array, count); } } } diff --git a/SDL3-CS/SDLArray.cs b/SDL3-CS/SDLArray.cs index 91f1d60..1494025 100644 --- a/SDL3-CS/SDLArray.cs +++ b/SDL3-CS/SDLArray.cs @@ -63,5 +63,15 @@ namespace SDL return new SDLPointerArray(array, count); } + + [MustDisposeResource] + internal static SDLOpaquePointerArray? CreateOpaque(T** array, int count) + where T : unmanaged + { + if (array == null) + return null; + + return new SDLOpaquePointerArray(array, count); + } } } diff --git a/SDL3-CS/SDLOpaquePointerArray.cs b/SDL3-CS/SDLOpaquePointerArray.cs new file mode 100644 index 0000000..4123e91 --- /dev/null +++ b/SDL3-CS/SDLOpaquePointerArray.cs @@ -0,0 +1,46 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Diagnostics; +using JetBrains.Annotations; + +namespace SDL +{ + [MustDisposeResource] + public sealed unsafe class SDLOpaquePointerArray : IDisposable + where T : unmanaged + { + private readonly T** array; + public readonly int Count; + private bool isDisposed; + + internal SDLOpaquePointerArray(T** array, int count) + { + this.array = array; + Count = count; + } + + public T* this[int index] + { + get + { + ObjectDisposedException.ThrowIf(isDisposed, this); + ArgumentOutOfRangeException.ThrowIfNegative(index); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); + Debug.Assert(array[index] != null); + return array[index]; + } + } + + public void Dispose() + { + if (isDisposed) + return; + + isDisposed = true; + + SDL3.SDL_free(array); + } + } +}