diff --git a/Nu/Nu.Gaia/Gaia.fs b/Nu/Nu.Gaia/Gaia.fs
index 081ca026b9..82462bcbb9 100644
--- a/Nu/Nu.Gaia/Gaia.fs
+++ b/Nu/Nu.Gaia/Gaia.fs
@@ -1276,7 +1276,11 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1920,1080 Split
""""""
""""""
""""""
- """"""|]
+ """"""
+ """"""
+ """"""
+ """"""
+ """"""|]
|> Array.append (File.ReadAllLines fsprojFilePath)
let fsprojNugetPaths =
fsprojFileLines
@@ -3273,7 +3277,10 @@ DockSpace ID=0x7C6B3D9B Window=0xA87D555D Pos=0,0 Size=1920,1080 Split
"#r \"Magick.NET-Q8-AnyCPU.dll\"\n" +
"#r \"OpenGL.Net.dll\"\n" +
"#r \"Pfim.dll\"\n" +
- "#r \"SDL2-CS.dll\"\n" +
+ "#r \"SDL3-CS.dll\"\n" +
+ "#r \"SDL3_image-CS.dll\"\n" +
+ "#r \"SDL3_mixer-CS.dll\"\n" +
+ "#r \"SDL3_ttf-CS.dll\"\n" +
"#r \"TiledSharp.dll\"\n" +
"#r \"Twizzle.ImGui-Bundle.NET.dll\"\n" +
"#r \"Prime.dll\"\n" +
diff --git a/Nu/Nu.Gaia/Nu.Gaia.fsproj b/Nu/Nu.Gaia/Nu.Gaia.fsproj
index 82a8093efb..ac4522d923 100644
--- a/Nu/Nu.Gaia/Nu.Gaia.fsproj
+++ b/Nu/Nu.Gaia/Nu.Gaia.fsproj
@@ -62,9 +62,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Nu/Nu.Pipe/Nu.Pipe.fsproj b/Nu/Nu.Pipe/Nu.Pipe.fsproj
index aa387fae1a..f8814a69f2 100644
--- a/Nu/Nu.Pipe/Nu.Pipe.fsproj
+++ b/Nu/Nu.Pipe/Nu.Pipe.fsproj
@@ -53,9 +53,6 @@
..\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Nu/Nu.Template.ImSim.Empty/Nu.Template.ImSim.Empty.fsproj b/Nu/Nu.Template.ImSim.Empty/Nu.Template.ImSim.Empty.fsproj
index c59ed61945..bd919e3a55 100644
--- a/Nu/Nu.Template.ImSim.Empty/Nu.Template.ImSim.Empty.fsproj
+++ b/Nu/Nu.Template.ImSim.Empty/Nu.Template.ImSim.Empty.fsproj
@@ -66,9 +66,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Nu/Nu.Template.ImSim.Game/Nu.Template.ImSim.Game.fsproj b/Nu/Nu.Template.ImSim.Game/Nu.Template.ImSim.Game.fsproj
index eaae74f05d..8889a302e1 100644
--- a/Nu/Nu.Template.ImSim.Game/Nu.Template.ImSim.Game.fsproj
+++ b/Nu/Nu.Template.ImSim.Game/Nu.Template.ImSim.Game.fsproj
@@ -69,9 +69,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Nu/Nu.Template.Mmcc.Empty/Nu.Template.Mmcc.Empty.fsproj b/Nu/Nu.Template.Mmcc.Empty/Nu.Template.Mmcc.Empty.fsproj
index 73fca2ca5e..3001f7deb3 100644
--- a/Nu/Nu.Template.Mmcc.Empty/Nu.Template.Mmcc.Empty.fsproj
+++ b/Nu/Nu.Template.Mmcc.Empty/Nu.Template.Mmcc.Empty.fsproj
@@ -66,9 +66,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Nu/Nu.Template.Mmcc.Game/Nu.Template.Mmcc.Game.fsproj b/Nu/Nu.Template.Mmcc.Game/Nu.Template.Mmcc.Game.fsproj
index af5e3747e7..e7dccf5516 100644
--- a/Nu/Nu.Template.Mmcc.Game/Nu.Template.Mmcc.Game.fsproj
+++ b/Nu/Nu.Template.Mmcc.Game/Nu.Template.Mmcc.Game.fsproj
@@ -70,9 +70,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Nu/Nu.Tests/Nu.Tests.fsproj b/Nu/Nu.Tests/Nu.Tests.fsproj
index 8969e48698..73636b52d6 100644
--- a/Nu/Nu.Tests/Nu.Tests.fsproj
+++ b/Nu/Nu.Tests/Nu.Tests.fsproj
@@ -71,9 +71,6 @@
..\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Nu/Nu/Audio/AudioPlayer.fs b/Nu/Nu/Audio/AudioPlayer.fs
index 861acf3807..2fda678855 100644
--- a/Nu/Nu/Audio/AudioPlayer.fs
+++ b/Nu/Nu/Audio/AudioPlayer.fs
@@ -8,7 +8,8 @@ namespace Nu
open System
open System.Collections.Generic
open System.IO
-open SDL2
+open FSharp.NativeInterop
+open SDL
open Prime
/// Describes a sound.
@@ -54,11 +55,6 @@ type AudioMessage =
| StopSongMessage
| ReloadAudioAssetsMessage
-/// An audio asset used by the audio system.
-type internal AudioAsset =
- | WavAsset of nativeint
- | MusAsset of nativeint
-
/// The audio player. Represents the audio subsystem of Nu generally.
type AudioPlayer =
@@ -81,10 +77,10 @@ type AudioPlayer =
abstract EnqueueMessage : message : AudioMessage -> unit
/// Get the current optionally-playing song.
- abstract SongOpt : SongDescriptor option
+ abstract SongOpt : SongDescriptor option // TODO: We can support multiple tracks for multiple songs.
/// Get the current song's position or 0.0 if one isn't playing.
- abstract SongPosition : double
+ abstract SongPosition : GameTime
/// Get the current song's volume or 0.0f if one isn't playing.
abstract SongVolume : single
@@ -114,7 +110,7 @@ type [] StubAudioPlayer =
member audioPlayer.ClearMessages () = ()
member audioPlayer.EnqueueMessage _ = ()
member audioPlayer.SongOpt = None
- member audioPlayer.SongPosition = 0.0
+ member audioPlayer.SongPosition = GameTime.zero
member audioPlayer.SongVolume = 0.0f
member audioPlayer.SongFadingIn = false
member audioPlayer.SongFadingOut = false
@@ -127,57 +123,34 @@ type [] StubAudioPlayer =
/// The SDL implementation of AudioPlayer.
type [] SdlAudioPlayer =
private
- { AudioContext : unit // audio context, interestingly, is global. Good luck encapsulating that!
- AudioPackages : Packages
+ { AudioMixer : MIX_Mixer nativeptr
+ SoundTrack : MIX_Track nativeptr // One track for all sounds for now. We can add more tracks later.
+ SongTrack : MIX_Track nativeptr // One track for all songs for now. We can add more tracks later.
+ SongTrackPropertiesId : SDL_PropertiesID // reused instance across PlayTrack calls.
+ AudioPackages : Packages
mutable AudioMessages : AudioMessage List
mutable MasterAudioVolume : single
mutable MasterSoundVolume : single
mutable MasterSongVolume : single
- mutable SongOpt : (SongDescriptor * nativeint) option }
-
- static member private tryFreeAudioAsset (audioAsset : AudioAsset) (audioPlayer : SdlAudioPlayer) =
- match audioAsset with
- | WavAsset wav ->
- match audioPlayer.SongOpt with
- | Some (_, wavPlaying) ->
- let freeing = wav <> wavPlaying
- if freeing then SDL_mixer.Mix_FreeChunk wav
- freeing
- | None ->
- SDL_mixer.Mix_FreeChunk wav
- true
- | MusAsset mus ->
- match audioPlayer.SongOpt with
- | Some (_, musPlaying) ->
- let freeing = mus <> musPlaying
- if freeing then SDL_mixer.Mix_FreeMusic mus
- freeing
- | None ->
- SDL_mixer.Mix_FreeMusic mus
- true
-
- static member private haltAudio () =
- SDL_mixer.Mix_HaltMusic () |> ignore
- let (_, _, _, channelCount) = SDL_mixer.Mix_QuerySpec ()
- for i in [0 .. channelCount - 1] do
- SDL_mixer.Mix_HaltChannel i |> ignore
-
- static member private tryLoadAudioAsset (asset : Asset) =
+ mutable SongOpt : (SongDescriptor * MIX_Audio nativeptr) option }
+
+ static member private haltAudio audioPlayer =
+ if not (SDL3_mixer.MIX_StopAllTracks (audioPlayer.AudioMixer, 0L)) then
+ Log.error ("Could not halt audio due to '" + SDL3.SDL_GetError () + "'.")
+
+ static member private tryLoadAudioAsset (asset : Asset) audioPlayer =
+ // Set predecode to true: https://github.com/libsdl-org/SDL_mixer/issues/662#issuecomment-2626072254
+ // "There's also the need to decode the data in advance because some formats are expensive to decode
+ // and can't be done just in time to feed the audio device. I'm operating under the assumption that for
+ // the most part games want the minimum possible latency so will be feeding the output small chunks at a high rate."
match PathF.GetExtensionLower asset.FilePath with
- | SoundExtension _ ->
- let wavOpt = SDL_mixer.Mix_LoadWAV asset.FilePath
- if wavOpt <> IntPtr.Zero then Some (WavAsset wavOpt)
- else
- let errorMsg = SDL.SDL_GetError ()
- Log.info ("Could not load wav '" + asset.FilePath + "' due to '" + errorMsg + "'.")
- None
- | SongExtension _ ->
- let musOpt = SDL_mixer.Mix_LoadMUS asset.FilePath
- if musOpt <> IntPtr.Zero then Some (MusAsset musOpt)
- else
- let errorMsg = SDL.SDL_GetError ()
- Log.info ("Could not load song asset '" + asset.FilePath + "' due to '" + errorMsg + "'.")
+ | SoundExtension _ | SongExtension _ ->
+ let musOpt = SDL3_mixer.MIX_LoadAudio (audioPlayer.AudioMixer, asset.FilePath, true)
+ if NativePtr.isNullPtr musOpt then
+ let errorMsg = SDL3.SDL_GetError ()
+ Log.info ("Could not load sound or song asset '" + asset.FilePath + "' due to '" + errorMsg + "'.")
None
+ else Some musOpt
| _ -> None
static member private tryLoadAudioPackage packageName audioPlayer =
@@ -210,12 +183,9 @@ type [] SdlAudioPlayer =
then assetsToFree.Add (asset, audioAsset)
else assetsToKeep.Add (assetName, (lastWriteTime, asset, audioAsset))
- // attempt to free assets
- for assetEntry in assetsToFree do
- let asset = assetEntry.Key
- let audioAsset = assetEntry.Value
- if not (SdlAudioPlayer.tryFreeAudioAsset audioAsset audioPlayer) then
- assetsToKeep.Add (asset.FilePath, (DateTimeOffset.MinValue.DateTime, asset, audioAsset))
+ // free assets
+ for asset in assetsToFree do
+ SDL3_mixer.MIX_DestroyAudio asset.Value // Audio assets are reference counted. If a track is still using it, the actual deallocation will happen when the track stops using it.
// categorize assets to load
let assetsToLoad = HashSet ()
@@ -226,7 +196,7 @@ type [] SdlAudioPlayer =
// load assets
let assetsLoaded = Dictionary ()
for asset in assetsToLoad do
- match SdlAudioPlayer.tryLoadAudioAsset asset with
+ match SdlAudioPlayer.tryLoadAudioAsset asset audioPlayer with
| Some audioAsset ->
let lastWriteTime =
try DateTimeOffset (File.GetLastWriteTime asset.FilePath)
@@ -255,75 +225,57 @@ type [] SdlAudioPlayer =
| None -> None
static member private playSong songDescriptor audioPlayer =
- let song = songDescriptor.Song
- match SdlAudioPlayer.tryGetAudioAsset song audioPlayer with
- | Some audioAsset ->
- match audioAsset with
- | WavAsset _ ->
- Log.info ("Cannot play wav file as song '" + scstring song + "'.")
- | MusAsset musAsset ->
- let loops = match songDescriptor.RepeatLimitOpt with Some repeatLimit -> max 0 (int repeatLimit) | None -> -1
- SDL_mixer.Mix_HaltMusic () |> ignore // NOTE: have to stop current song in case it is still fading out, causing the next song not to play.
- SDL_mixer.Mix_VolumeMusic (int (songDescriptor.Volume * audioPlayer.MasterAudioVolume * audioPlayer.MasterSongVolume * single SDL_mixer.MIX_MAX_VOLUME)) |> ignore
- match SDL_mixer.Mix_FadeInMusicPos (musAsset, loops, int (max Constants.Audio.FadeInSecondsMin songDescriptor.FadeInTime.Seconds * 1000.0), double songDescriptor.StartTime.Seconds) with
- | -1 ->
- // HACK: start time exceeded length of track, so starting over.
- SDL_mixer.Mix_FadeInMusicPos (musAsset, loops, int (max Constants.Audio.FadeInSecondsMin songDescriptor.FadeInTime.Seconds * 1000.0), 0.0) |> ignore
- | _ -> ()
- audioPlayer.SongOpt <- Some (songDescriptor, musAsset)
- | None ->
- Log.info ("PlaySongMessage failed due to unloadable assets for '" + scstring song + "'.")
+ if songDescriptor.Volume > 0.0f then
+ let song = songDescriptor.Song
+ match SdlAudioPlayer.tryGetAudioAsset song audioPlayer with
+ | Some audioAsset ->
+ let loops = match songDescriptor.RepeatLimitOpt with Some repeatLimit -> max 0L (int64 repeatLimit) | None -> -1L
+ SDL3_mixer.MIX_SetTrackAudio (audioPlayer.SongTrack, audioAsset) |> ignore
+ SDL3_mixer.MIX_SetTrackGain (audioPlayer.SongTrack, songDescriptor.Volume * audioPlayer.MasterAudioVolume * audioPlayer.MasterSongVolume) |> ignore
+ SDL3.SDL_SetNumberProperty (audioPlayer.SongTrackPropertiesId, SDL3_mixer.MIX_PROP_PLAY_LOOPS_NUMBER, loops) |> ignore
+ SDL3.SDL_SetNumberProperty (audioPlayer.SongTrackPropertiesId, SDL3_mixer.MIX_PROP_PLAY_FADE_IN_MILLISECONDS_NUMBER, int64 (max Constants.Audio.FadeInSecondsMin songDescriptor.FadeInTime.Seconds * 1000.0)) |> ignore
+ SDL3.SDL_SetNumberProperty (audioPlayer.SongTrackPropertiesId, SDL3_mixer.MIX_PROP_PLAY_START_MILLISECOND_NUMBER, int64 (songDescriptor.StartTime.Seconds * 1000.0)) |> ignore
+ if not (SDL3_mixer.MIX_PlayTrack (audioPlayer.SongTrack, audioPlayer.SongTrackPropertiesId)) then
+ Log.info ("Could not play song asset '" + scstring song + "' due to '" + SDL3.SDL_GetError () + "'.")
+ audioPlayer.SongOpt <- Some (songDescriptor, audioAsset)
+ | None ->
+ Log.info ("PlaySongMessage failed due to unloadable assets for '" + scstring song + "'.")
static member private handleLoadAudioPackage packageName audioPlayer =
SdlAudioPlayer.tryLoadAudioPackage packageName audioPlayer
static member private handleUnloadAudioPackage packageName audioPlayer =
- match Dictionary.tryFind packageName audioPlayer.AudioPackages with
+ match Dictionary.tryFind packageName audioPlayer.AudioPackages with
| Some package ->
- // all sounds / music must be halted because one of them might be playing during unload
- // (which is very bad according to the API docs).
- SdlAudioPlayer.haltAudio ()
for asset in package.Assets do
- match __c asset.Value with
- | WavAsset wavAsset -> SDL_mixer.Mix_FreeChunk wavAsset
- | MusAsset musAsset -> SDL_mixer.Mix_FreeMusic musAsset
+ SDL3_mixer.MIX_DestroyAudio (__c asset.Value)
audioPlayer.AudioPackages.Remove packageName |> ignore
| None -> ()
static member private handlePlaySound (soundDescriptor : SoundDescriptor) audioPlayer =
if soundDescriptor.Volume > 0.0f then
- let sound = soundDescriptor.Sound
- match SdlAudioPlayer.tryGetAudioAsset sound audioPlayer with
+ match SdlAudioPlayer.tryGetAudioAsset soundDescriptor.Sound audioPlayer with
| Some audioAsset ->
- match audioAsset with
- | WavAsset wavAsset ->
- let channel = SDL_mixer.Mix_PlayChannel (-1, wavAsset, 0)
- if channel > -1 then
- SDL_mixer.Mix_Volume (channel, int (soundDescriptor.Volume * audioPlayer.MasterSoundVolume * single SDL_mixer.MIX_MAX_VOLUME)) |> ignore
- let pan = soundDescriptor.Panning |> max -1.0f |> min 1.0f
- let left = byte (255.0f * (1.0f - max 0.0f pan))
- let right = byte (255.0f * (1.0f + min 0.0f pan))
- SDL_mixer.Mix_SetPanning (channel, left, right) |> ignore
- let distance = soundDescriptor.Distance |> max 0.0f |> min 1.0f |> (*) 255.0f |> byte
- SDL_mixer.Mix_SetDistance (channel, distance) |> ignore
- | MusAsset _ -> Log.info ("Cannot play song asset as sound '" + scstring sound + "'.")
+ SDL3_mixer.MIX_SetTrackAudio (audioPlayer.SoundTrack, audioAsset) |> ignore
+ SDL3_mixer.MIX_SetTrackGain (audioPlayer.SoundTrack, soundDescriptor.Volume * audioPlayer.MasterAudioVolume * audioPlayer.MasterSoundVolume) |> ignore
+ let pan = soundDescriptor.Panning |> max -1.0f |> min 1.0f // TODO: support 3D sound via SetTrack3DPosition. It is not optimal to force stereo for surround sound setups.
+ let mutable stereoGains = MIX_StereoGains (left = 1.0f - max 0.0f pan, right = 1.0f + min 0.0f pan)
+ SDL3_mixer.MIX_SetTrackStereo (audioPlayer.SoundTrack, &&stereoGains) |> ignore
+ // TODO: Distance is not supported with stereo gains! We need to use 3D sound.
+ SDL3_mixer.MIX_PlayTrack (audioPlayer.SoundTrack, Unchecked.defaultof) |> ignore
| None ->
- Log.info ("PlaySoundMessage failed due to unloadable assets for '" + scstring sound + "'.")
+ Log.info ("PlaySoundMessage failed due to unloadable assets for '" + scstring soundDescriptor.Sound + "'.")
static member private handlePlaySong songDescriptor audioPlayer =
SdlAudioPlayer.playSong songDescriptor audioPlayer
- static member private handleFadeOutSong (fadeOutTime : GameTime) =
- if SDL_mixer.Mix_PlayingMusic () = 1 then
- if fadeOutTime <> GameTime.zero &&
- SDL_mixer.Mix_FadingMusic () <> SDL_mixer.Mix_Fading.MIX_FADING_OUT then
- SDL_mixer.Mix_FadeOutMusic (int (fadeOutTime.Seconds * 1000.0)) |> ignore
- else
- SDL_mixer.Mix_HaltMusic () |> ignore
+ static member private handleFadeOutSong (fadeOutTime : GameTime) audioPlayer =
+ if not (SDL3_mixer.MIX_StopTrack (audioPlayer.SongTrack, SDL3_mixer.MIX_TrackFramesToMS (audioPlayer.SongTrack, int64 (fadeOutTime.Seconds * 1000.0)))) then
+ Log.info ("Could not fade out song due to '" + SDL3.SDL_GetError () + "'.")
- static member private handleStopSong =
- if SDL_mixer.Mix_PlayingMusic () = 1 then
- SDL_mixer.Mix_HaltMusic () |> ignore
+ static member private handleStopSong audioPlayer =
+ if not (SDL3_mixer.MIX_StopTrack (audioPlayer.SongTrack, 0)) then
+ Log.info ("Could not stop song due to '" + SDL3.SDL_GetError () + "'.")
static member private handleReloadAudioAssets audioPlayer =
for packageName in audioPlayer.AudioPackages |> Seq.map (fun entry -> entry.Key) |> Array.ofSeq do
@@ -336,8 +288,8 @@ type [] SdlAudioPlayer =
| PlaySoundMessage soundDescriptor -> SdlAudioPlayer.handlePlaySound soundDescriptor audioPlayer
| PlaySongMessage songDescriptor -> SdlAudioPlayer.handlePlaySong songDescriptor audioPlayer
| SetSongVolumeMessage volume -> SdlAudioPlayer.setSongVolume volume audioPlayer
- | FadeOutSongMessage fadeOutTime -> SdlAudioPlayer.handleFadeOutSong fadeOutTime
- | StopSongMessage -> SdlAudioPlayer.handleStopSong
+ | FadeOutSongMessage fadeOutTime -> SdlAudioPlayer.handleFadeOutSong fadeOutTime audioPlayer
+ | StopSongMessage -> SdlAudioPlayer.handleStopSong audioPlayer
| ReloadAudioAssetsMessage -> SdlAudioPlayer.handleReloadAudioAssets audioPlayer
static member private handleAudioMessages audioMessages audioPlayer =
@@ -346,33 +298,48 @@ type [] SdlAudioPlayer =
static member private updateSongVolume audioPlayer =
match audioPlayer.SongOpt with
- | Some (currentSong, _) -> SDL_mixer.Mix_VolumeMusic (int (currentSong.Volume * audioPlayer.MasterAudioVolume * audioPlayer.MasterSongVolume * single SDL_mixer.MIX_MAX_VOLUME)) |> ignore
+ | Some (currentSong, _) -> SDL3_mixer.MIX_SetTrackGain (audioPlayer.SongTrack, currentSong.Volume * audioPlayer.MasterAudioVolume * audioPlayer.MasterSongVolume) |> ignore
| None -> ()
static member private setSongVolume volume audioPlayer =
match audioPlayer.SongOpt with
| Some (currentSong, musPlaying) ->
if currentSong.Volume <> volume then
- SDL_mixer.Mix_VolumeMusic (int (volume * audioPlayer.MasterAudioVolume * audioPlayer.MasterSongVolume * single SDL_mixer.MIX_MAX_VOLUME)) |> ignore
+ SDL3_mixer.MIX_SetTrackGain (audioPlayer.SongTrack, volume * audioPlayer.MasterAudioVolume * audioPlayer.MasterSongVolume) |> ignore
audioPlayer.SongOpt <- Some ({ currentSong with Volume = volume }, musPlaying)
| None -> ()
static member private updateSong audioPlayer =
- if SDL_mixer.Mix_PlayingMusic () = 0 then
+ if not (SDL3_mixer.MIX_TrackPlaying audioPlayer.SongTrack) then
audioPlayer.SongOpt <- None
- static member private getSongFadingIn () =
- SDL_mixer.Mix_FadingMusic () = SDL_mixer.Mix_Fading.MIX_FADING_IN
+ static member private getSongFadingIn audioPlayer =
+ SDL3_mixer.MIX_GetTrackFadeFrames audioPlayer.SongTrack > 0L
- static member private getSongFadingOut () =
- SDL_mixer.Mix_FadingMusic () = SDL_mixer.Mix_Fading.MIX_FADING_OUT
+ static member private getSongFadingOut audioPlayer =
+ SDL3_mixer.MIX_GetTrackFadeFrames audioPlayer.SongTrack < 0L
/// Make an SdlAudioPlayer.
static member make () =
- if SDL.SDL_WasInit SDL.SDL_INIT_AUDIO = 0u then
+ if SDL3.SDL_WasInit SDL_InitFlags.SDL_INIT_AUDIO = LanguagePrimitives.EnumOfValue 0u then
failwith "Cannot create an AudioPlayer without SDL audio initialized."
+ let mixer = SDL3_mixer.MIX_CreateMixerDevice (SDL3.SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NativePtr.nullPtr)
+ if NativePtr.isNullPtr mixer then
+ Log.info ("Mixer could not initialize audio due to '" + SDL3.SDL_GetError () + "'.")
+ let soundTrack = SDL3_mixer.MIX_CreateTrack mixer
+ if NativePtr.isNullPtr soundTrack then
+ Log.info ("Sound track could not be created due to '" + SDL3.SDL_GetError () + "'.")
+ let songTrack = SDL3_mixer.MIX_CreateTrack mixer
+ if NativePtr.isNullPtr songTrack then
+ Log.info ("Song track could not be created due to '" + SDL3.SDL_GetError () + "'.")
+ let props = SDL3.SDL_CreateProperties ()
+ if props = Unchecked.defaultof<_> then
+ Log.info ("SDL properties could not be created due to '" + SDL3.SDL_GetError () + "'.")
let audioPlayer =
- { AudioContext = ()
+ { AudioMixer = mixer
+ SoundTrack = soundTrack
+ SongTrack = songTrack
+ SongTrackPropertiesId = props
AudioPackages = dictPlus StringComparer.Ordinal []
AudioMessages = List ()
MasterAudioVolume = Constants.Audio.MasterAudioVolumeDefault
@@ -415,8 +382,8 @@ type [] SdlAudioPlayer =
member audioPlayer.SongPosition =
match audioPlayer.SongOpt with
- | Some (_, musAsset) -> ignore musAsset; failwithnie () // SDL_mixer.Mix_GetMusicPosition musAsset
- | None -> failwithnie () // 0.0
+ | Some (_, musAsset) -> SDL3_mixer.MIX_AudioFramesToMS (musAsset, SDL3_mixer.MIX_GetTrackPlaybackPosition audioPlayer.SongTrack) |> double |> (*) 0.001 |> GameTime.ofSeconds
+ | None -> GameTime.zero
member audioPlayer.SongVolume =
match audioPlayer.SongOpt with
@@ -424,18 +391,19 @@ type [] SdlAudioPlayer =
| None -> 0.0f
member audioPlayer.SongFadingIn =
- SdlAudioPlayer.getSongFadingIn ()
+ SdlAudioPlayer.getSongFadingIn audioPlayer
member audioPlayer.SongFadingOut =
- SdlAudioPlayer.getSongFadingOut ()
+ SdlAudioPlayer.getSongFadingOut audioPlayer
member audioPlayer.Play audioMessages =
SdlAudioPlayer.handleAudioMessages audioMessages audioPlayer
SdlAudioPlayer.updateSong audioPlayer
member audioPlayer.CleanUp () =
- SdlAudioPlayer.haltAudio ()
+ SDL3_mixer.MIX_DestroyMixer audioPlayer.AudioMixer // also destroys tracks
let audioPackages = audioPlayer.AudioPackages |> Seq.map (fun entry -> entry.Value)
let audioAssets = audioPackages |> Seq.map (fun package -> package.Assets.Values) |> Seq.concat
- for (_, _, audioAsset) in audioAssets do SdlAudioPlayer.tryFreeAudioAsset audioAsset audioPlayer |> ignore
- audioPlayer.AudioPackages.Clear ()
\ No newline at end of file
+ for (_, _, audioAsset) in audioAssets do SDL3_mixer.MIX_DestroyAudio audioAsset
+ audioPlayer.AudioPackages.Clear ()
+ SDL3.SDL_DestroyProperties audioPlayer.SongTrackPropertiesId
\ No newline at end of file
diff --git a/Nu/Nu/Core/Constants.fs b/Nu/Nu/Core/Constants.fs
index e10d95cd35..1e46972835 100644
--- a/Nu/Nu/Core/Constants.fs
+++ b/Nu/Nu/Core/Constants.fs
@@ -10,7 +10,7 @@ open System.Collections.Frozen
open System.Configuration
open System.Diagnostics
open System.Numerics
-open SDL2
+open SDL
open Prime
open Nu
@@ -45,7 +45,7 @@ module OpenGL =
let [] VersionMajor = 4
let [] VersionMinor = 6
- let [] Profile = SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE
+ let [] Profile = SDL3.SDL_GL_CONTEXT_PROFILE_CORE
let [] GlslVersionPragma = "#version " + string VersionMajor + string VersionMinor + "0" + " core"
let [] TextureImageUnitsRequired = 32
let [] mutable HlDebug = match ConfigurationManager.AppSettings.["HlDebug"] with null -> false | value -> scvalue value
@@ -346,7 +346,7 @@ module Render =
let [] RefractiveIndexDefault = 1.0f
let [] ClearCoatDefault = 1.0f
let [] ClearCoatRoughnessDefault = 1.0f
- let [] FontSizeDefault = 14
+ let [] FontSizeDefault = 14.0f
let [] Body3dSegmentRenderMagnitudeMax = 48.0f
let [] Body3dSegmentRenderDistanceMax = 40.0f
let [] Body3dRenderDistanceMax = 32.0f
@@ -361,8 +361,6 @@ module Audio =
let [] SongVolumeDefault = 1.0f
let [] FadeOutTimeDefault = GameTime.ofSeconds 0.5
let [] SongResumptionMax = GameTime.ofSeconds 90.0 // HACK: prevents songs from starting over too often due to hack in SdlAudioPlayer.playSong.
- let [] Frequency = 44100
- let [] BufferSize = 1024
let [] FadeInSecondsMin = 0.1 // NOTE: Mix_FadeInMusicPos seems to sometimes cause audio 'popping' when starting a song, so a minimum fade is used instead.
[]
diff --git a/Nu/Nu/Cursor/CursorClient.fs b/Nu/Nu/Cursor/CursorClient.fs
index 03076a068e..a7770cc7bf 100644
--- a/Nu/Nu/Cursor/CursorClient.fs
+++ b/Nu/Nu/Cursor/CursorClient.fs
@@ -2,25 +2,54 @@
open System
open System.Collections.Generic
open System.IO
-open SDL2
+open FSharp.NativeInterop
+open SDL
open Prime
open Nu
/// The type of a system cursor.
type CursorType =
+ /// Default cursor. Usually an arrow.
| DefaultCursor
- | ArrowCursor
- | IBeamCursor
+ /// Text selection. Usually an I-beam.
+ | TextCursor
+ /// Wait. Usually an hourglass or watch or spinning ball.
| WaitCursor
+ /// Crosshair.
| CrosshairCursor
- | WaitArrowCursor
- | SizeNwseCursor
- | SizeNeswCursor
- | SizeWestEastCursor
- | SizeNorthSouthCursor
- | SizeAllCursor
- | NoCursor
- | HandCursor
+ /// Program is busy but still interactive. Usually it's WaitCursor with an arrow.
+ | ProgressCursor
+ /// Double arrow pointing northwest and southeast.
+ | ResizeNwseCursor
+ /// Double arrow pointing northeast and southwest.
+ | ResizeNeswCursor
+ /// Double arrow pointing west and east.
+ | ResizeEastWestCursor
+ /// Double arrow pointing north and south.
+ | ResizeNorthSouthCursor
+ /// Four pointed arrow pointing north, south, east, and west.
+ | MoveCursor
+ /// Not permitted. Usually a slashed circle or crossbones.
+ | NotAllowedCursor
+ /// Pointer that indicates a link. Usually a pointing hand.
+ | PointerCursor
+ /// Window resize top-left. This may be a single arrow or a double arrow like ResizeNwseCursor.
+ | ResizeNorthWestCursor
+ /// Window resize top. This may be a single arrow or a double arrow like ResizeNorthSouthCursor.
+ | ResizeNorthCursor
+ /// Window resize top-right. This may be a single arrow or a double arrow like ResizeNeswCursor.
+ | ResizeNorthEastCursor
+ /// Window resize right. This may be a single arrow or a double arrow like ResizeEastWestCursor.
+ | ResizeEastCursor
+ /// Window resize bottom-right. This may be a single arrow or a double arrow like ResizeNwseCursor.
+ | ResizeSouthEastCursor
+ /// Window resize bottom. This may be a single arrow or a double arrow like ResizeNorthSouthCursor.
+ | ResizeSouthCursor
+ /// Window resize bottom-left. This may be a single arrow or a double arrow like ResizeNeswCursor.
+ | ResizeSouthWestCursor
+ /// Window resize left. This may be a single arrow or a double arrow like ResizeEastWestCursor.
+ | ResizeWestCursor
+ /// User-defined cursor loaded from a cursor asset.
| UserDefinedCursor of AssetTag : Cursor AssetTag
/// Instructs the system cursor display behavior.
@@ -62,8 +91,8 @@ type [] StubCursorClient =
/// The SDL implementation of CursorClient.
type [] SdlCursorClient =
private
- { SystemCursors : Dictionary
- CursorPackages : Packages
+ { SystemCursors : Dictionary
+ CursorPackages : Packages
mutable CursorType : CursorType }
/// Make an SdlCursorClient.
@@ -75,30 +104,21 @@ type [] SdlCursorClient =
static member private tryLoadCursorAsset (asset : Asset) =
match PathF.GetExtensionLower asset.FilePath with
| CursorExtension _ ->
- let surface = SDL_image.IMG_Load asset.FilePath
- if surface <> 0n then
-
- // load hotspot from .cur file. NOTE: SDL3 reads cursor hotspots as SDLSurface properties
- // (https://github.com/libsdl-org/SDL_image/pull/519/files), however SDL2 does not do that. Therefore,
- // we have to read the hotspot properties manually.
- // NOTE: reference for .cur file format here - https://www.daubnet.com/en/file-format-cur
- use fileStream = new FileStream (asset.FilePath, FileMode.Open, FileAccess.Read, FileShare.None, 0) // 0 = disable buffering
- use binaryReader = new BinaryReader (fileStream)
- fileStream.Seek (10, SeekOrigin.Begin) |> ignore
- let hotspotX = binaryReader.ReadUInt16 () // hotspotX of first cursor is bytes 10 to 11 (little endian)
- let hotspotY = binaryReader.ReadUInt16 () // hotspotY of first cursor is bytes 12 to 13 (little endian)
-
- // create cursor and free the surface that the cursor copied from
- let cursor = SDL.SDL_CreateColorCursor (surface, int hotspotX, int hotspotY)
- SDL.SDL_FreeSurface surface
- if cursor <> 0n
+ let surface = SDL3_image.IMG_Load asset.FilePath
+ if not (NativePtr.isNullPtr surface) then
+
+ // create cursor. hotspot parameters (0, 0) here are overridden by the surface properties
+ // SDL_PROP_SURFACE_HOTSPOT_X_NUMBER and SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER set by Image.Load
+ let cursor = SDL3.SDL_CreateColorCursor (surface, 0, 0)
+ SDL3.SDL_DestroySurface surface // the cursor stores a copy of the frame data, the surface can be destroyed here
+ if not (NativePtr.isNullPtr cursor)
then Some cursor
else
- Log.warn ("Could not create cursor for '" + asset.FilePath + "' due to: '" + SDL.SDL_GetError ())
+ Log.warn ("Could not create cursor for '" + asset.FilePath + "' due to: '" + SDL3.SDL_GetError ())
None
else
- Log.warn ("Could not load cursor for '" + asset.FilePath + "' due to: '" + SDL.SDL_GetError ())
+ Log.warn ("Could not load cursor for '" + asset.FilePath + "' due to: '" + SDL3.SDL_GetError ())
None
| _ -> None
@@ -125,7 +145,7 @@ type [] SdlCursorClient =
with exn -> Log.info ("Asset file write time read error due to: " + scstring exn); DateTimeOffset.MinValue.DateTime
if lastWriteTime = lastWriteTime'
then assetsToKeep.Add assetName |> ignore
- else SDL.SDL_FreeCursor cursor
+ else SDL3.SDL_DestroyCursor cursor
// load newly found assets that are not kept
for asset in assetsCollected do
@@ -152,46 +172,48 @@ type [] SdlCursorClient =
| Some package -> package.Assets |> Dictionary.tryFind assetTag.AssetName |> Option.map __c
| None -> None
- static member private setSystemCursor (systemCursor : SDL.SDL_SystemCursor) cursorClient =
+ static member private setSystemCursor (systemCursor : SDL_SystemCursor) cursorClient =
match Dictionary.tryFind systemCursor cursorClient.SystemCursors with
- | Some cursor -> SDL.SDL_SetCursor cursor
+ | Some cursor -> SDL3.SDL_SetCursor cursor
| None ->
- let cursor = SDL.SDL_CreateSystemCursor systemCursor
- if cursor <> nativeint 0 then
+ let cursor = SDL3.SDL_CreateSystemCursor systemCursor
+ if not (NativePtr.isNullPtr cursor) then
cursorClient.SystemCursors.[systemCursor] <- cursor
- SDL.SDL_SetCursor cursor
- else Log.warn ("Failed to create system cursor '" + scstring systemCursor + "' due to: " + SDL.SDL_GetError ())
+ SDL3.SDL_SetCursor cursor
+ else Log.warn ("Failed to create system cursor '" + scstring systemCursor + "' due to: " + SDL3.SDL_GetError ()); true
static member private getCursorType cursorClient =
cursorClient.CursorType
static member private setCursorType cursorType (cursorClient : SdlCursorClient) =
match cursorType with
- | DefaultCursor -> SDL.SDL_SetCursor (SDL.SDL_GetDefaultCursor ())
- | ArrowCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW cursorClient
- | IBeamCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_IBEAM cursorClient
- | WaitCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_WAIT cursorClient
- | CrosshairCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_CROSSHAIR cursorClient
- | WaitArrowCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_WAITARROW cursorClient
- | SizeNwseCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENWSE cursorClient
- | SizeNeswCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENESW cursorClient
- | SizeWestEastCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEWE cursorClient
- | SizeNorthSouthCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENS cursorClient
- | SizeAllCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEALL cursorClient
- | NoCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_NO cursorClient
- | HandCursor -> SdlCursorClient.setSystemCursor SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_HAND cursorClient
+ | DefaultCursor -> SDL3.SDL_SetCursor (SDL3.SDL_GetDefaultCursor ()) // is a shared system cursor instance of SDL_SystemCursor.SDL_SYSTEM_CURSOR_DEFAULT unless SDL is initialized with the SDL_HINT_MOUSE_DEFAULT_SYSTEM_CURSOR hint, which we don't use
+ | TextCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_TEXT cursorClient
+ | WaitCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_WAIT cursorClient
+ | CrosshairCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_CROSSHAIR cursorClient
+ | ProgressCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_PROGRESS cursorClient
+ | ResizeNwseCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_NWSE_RESIZE cursorClient
+ | ResizeNeswCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_NESW_RESIZE cursorClient
+ | ResizeEastWestCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_EW_RESIZE cursorClient
+ | ResizeNorthSouthCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_NS_RESIZE cursorClient
+ | MoveCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_MOVE cursorClient
+ | NotAllowedCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_NOT_ALLOWED cursorClient
+ | PointerCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_POINTER cursorClient
+ | ResizeNorthWestCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_NW_RESIZE cursorClient
+ | ResizeNorthCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_N_RESIZE cursorClient
+ | ResizeNorthEastCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_NE_RESIZE cursorClient
+ | ResizeEastCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_E_RESIZE cursorClient
+ | ResizeSouthEastCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_SE_RESIZE cursorClient
+ | ResizeSouthCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_S_RESIZE cursorClient
+ | ResizeSouthWestCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_SW_RESIZE cursorClient
+ | ResizeWestCursor -> SdlCursorClient.setSystemCursor SDL_SystemCursor.SDL_SYSTEM_CURSOR_W_RESIZE cursorClient
| UserDefinedCursor assetTag ->
match SdlCursorClient.tryGetCursorAsset assetTag cursorClient with
- | Some cursor -> SDL.SDL_SetCursor cursor
- | None -> Log.info ("UserDefinedCursor message failed due to unloadable assets for '" + scstring assetTag + "'.")
+ | Some cursor -> SDL3.SDL_SetCursor cursor
+ | None -> Log.warn ("UserDefinedCursor message failed due to unloadable assets for '" + scstring assetTag + "'."); true
+ |> fun result -> if not result then Log.warn ("Failed to set cursor type '" + scstring cursorType + "' due to: " + SDL3.SDL_GetError ())
cursorClient.CursorType <- cursorType
- static member private getCursorVisible =
- SDL.SDL_ShowCursor SDL.SDL_QUERY = SDL.SDL_ENABLE
-
- static member private setCursorVisible visible =
- SDL.SDL_ShowCursor (if visible then SDL.SDL_ENABLE else SDL.SDL_DISABLE) |> ignore
-
interface CursorClient with
member cursorClient.CursorType
@@ -199,8 +221,10 @@ type [] SdlCursorClient =
and set value = SdlCursorClient.setCursorType value cursorClient
member cursorClient.CursorVisible
- with get () = SdlCursorClient.getCursorVisible
- and set value = SdlCursorClient.setCursorVisible value
+ with get () = SDL3.SDL_CursorVisible ()
+ and set value =
+ if not (if value then SDL3.SDL_ShowCursor () else SDL3.SDL_HideCursor ()) then
+ Log.warn ("Failed to set cursor visibility to '" + scstring value + "' due to: " + SDL3.SDL_GetError ())
member cursorClient.LoadCursorPackage packageName =
SdlCursorClient.tryLoadCursorPackage packageName cursorClient
@@ -208,13 +232,13 @@ type [] SdlCursorClient =
member cursorClient.UnloadCursorPackage packageName =
match Dictionary.tryFind packageName cursorClient.CursorPackages with
| Some package ->
- for asset in package.Assets do SDL.SDL_FreeCursor (__c asset.Value)
+ for asset in package.Assets do SDL3.SDL_DestroyCursor (__c asset.Value)
cursorClient.CursorPackages.Remove packageName |> ignore
| None -> ()
member cursorClient.ReloadCursorAssets () =
for systemCursor in cursorClient.SystemCursors.Values do
- SDL.SDL_FreeCursor systemCursor
+ SDL3.SDL_DestroyCursor systemCursor
cursorClient.SystemCursors.Clear ()
for packageName in cursorClient.CursorPackages |> Seq.map (fun entry -> entry.Key) |> Array.ofSeq do
SdlCursorClient.tryLoadCursorPackage packageName cursorClient
@@ -222,7 +246,7 @@ type [] SdlCursorClient =
member cursorClient.CleanUp () =
for systemCursor in cursorClient.SystemCursors.Values do
- SDL.SDL_FreeCursor systemCursor
+ SDL3.SDL_DestroyCursor systemCursor
for package in cursorClient.CursorPackages.Values do
for (_, _, cursor) in package.Assets.Values do
- SDL.SDL_FreeCursor cursor
\ No newline at end of file
+ SDL3.SDL_DestroyCursor cursor
\ No newline at end of file
diff --git a/Nu/Nu/Effects/EffectDescriptor.fs b/Nu/Nu/Effects/EffectDescriptor.fs
index dfbf8c3c3d..01586cc880 100644
--- a/Nu/Nu/Effects/EffectDescriptor.fs
+++ b/Nu/Nu/Effects/EffectDescriptor.fs
@@ -194,7 +194,7 @@ and Content =
| Nil // first to make default value when missing
| StaticSprite of Image : Resource * Aspects : Aspect array * Content : Content
| AnimatedSprite of Image : Resource * CelSize : Vector2i * CelCount : int * CelRun : int * CelDelay : GameTime * Playback : Playback * Aspects : Aspect array * Content : Content
- | TextSprite of Font : Resource * Text : string * FontSizing : int option * FontStyling : FontStyle Set * Aspects : Aspect array * Content : Content
+ | TextSprite of Font : Resource * Text : string * FontSizing : single option * FontStyling : FontStyle Set * Aspects : Aspect array * Content : Content
| Billboard of Albedo : Resource * Roughness : Resource * Metallic : Resource * AmbientOcclusion : Resource * Emission : Resource * Normal : Resource * HeightMap : Resource * TwoSided : bool * Clipped : bool * Aspects : Aspect array * Content : Content
| StaticModel of Resource : Resource * Clipped : bool * Aspects : Aspect array * Content : Content
| Light3d of LightType : LightType * Aspects : Aspect array * Content : Content
diff --git a/Nu/Nu/ImGui/ImGui.fs b/Nu/Nu/ImGui/ImGui.fs
index ee6477622f..16265b0f46 100644
--- a/Nu/Nu/ImGui/ImGui.fs
+++ b/Nu/Nu/ImGui/ImGui.fs
@@ -25,8 +25,8 @@ type ImGui (stub : bool, displaySize : Vector2i) =
static let mutable Font = Unchecked.defaultof
static let mutable MouseLeftIdInternal = 0L
- let charsPressed =
- List ()
+ let inputs =
+ List ()
let context =
ImGui.CreateContext ()
@@ -89,8 +89,8 @@ type ImGui (stub : bool, displaySize : Vector2i) =
let io = ImGui.GetIO ()
io.MouseWheel <- io.MouseWheel + change
- member this.HandleKeyChar (keyChar : char) =
- charsPressed.Add keyChar
+ member this.HandleTextInput (input : string) =
+ inputs.Add input
member this.BeginFrame deltaTime =
if not stub then
@@ -108,9 +108,9 @@ type ImGui (stub : bool, displaySize : Vector2i) =
member this.InputFrame () =
let io = ImGui.GetIO ()
- for c in charsPressed do
- io.AddInputCharacter (uint32 c)
- charsPressed.Clear ()
+ for i in inputs do
+ io.AddInputCharactersUTF8 i
+ inputs.Clear ()
member this.RenderFrame () =
if not stub then ImGui.Render ()
diff --git a/Nu/Nu/Nu.fsproj b/Nu/Nu/Nu.fsproj
index ff314b5418..85ce6c5a73 100644
--- a/Nu/Nu/Nu.fsproj
+++ b/Nu/Nu/Nu.fsproj
@@ -65,7 +65,6 @@
-
@@ -141,66 +140,6 @@
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
-
- PreserveNewest
- False
-
PreserveNewest
False
@@ -233,9 +172,6 @@
..\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
@@ -250,6 +186,10 @@
+
+
+
+
diff --git a/Nu/Nu/OpenGL/OpenGL.Hl.fs b/Nu/Nu/OpenGL/OpenGL.Hl.fs
index f0e5edc6a4..5e4bb6726f 100644
--- a/Nu/Nu/OpenGL/OpenGL.Hl.fs
+++ b/Nu/Nu/OpenGL/OpenGL.Hl.fs
@@ -15,7 +15,8 @@ open System
open System.Runtime.InteropServices
open System.Numerics
open System.Text
-open SDL2
+open FSharp.NativeInterop
+open SDL
open Prime
open Nu
@@ -133,10 +134,10 @@ module Hl =
let CreateSglContextInitial window =
Log.info "Initializing OpenGL 4.6..."
Gl.Initialize ()
- let glContext = SDL.SDL_GL_CreateContext window
+ let glContext = SDL3.SDL_GL_CreateContext window
let swapInterval = if Constants.Render.Vsync then 1 else 0
- SDL.SDL_GL_SetSwapInterval swapInterval |> ignore
- if SDL.SDL_GL_MakeCurrent (window, glContext) <> 0 then Log.error "Could not make OpenGL context current when required."
+ SDL3.SDL_GL_SetSwapInterval swapInterval |> ignore
+ if not (SDL3.SDL_GL_MakeCurrent (window, glContext)) then Log.error "Could not make OpenGL context current when required."
Gl.BindAPI ()
let vendorName = Gl.GetString StringName.Vendor
let versionStr = Gl.GetString StringName.Version
@@ -149,17 +150,17 @@ module Hl =
/// Create a SDL OpenGL context with the given window that shares the current context. Originating thread must wait
/// on the given WaitOnce object before continuing processing.
let CreateSglContextSharedWithCurrentContext (window, sharedContext) =
- if SDL.SDL_GL_MakeCurrent (window, sharedContext) <> 0 then Log.error "Could not make OpenGL context current when required."
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1) |> ignore
- let glContext = SDL.SDL_GL_CreateContext window
- if SDL.SDL_GL_MakeCurrent (window, glContext) <> 0 then Log.error "Could not make OpenGL context current when required."
+ if not (SDL3.SDL_GL_MakeCurrent (window, sharedContext)) then Log.error "Could not make OpenGL context current when required."
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1) |> ignore
+ let glContext = SDL3.SDL_GL_CreateContext window
+ if not (SDL3.SDL_GL_MakeCurrent (window, glContext)) then Log.error "Could not make OpenGL context current when required."
Gl.BindAPI ()
glContext
/// Delete an SDL-created OpenGL context.
let DestroySglContext (glContext, sglWindow) =
- if SDL.SDL_GL_MakeCurrent (sglWindow, IntPtr.Zero) <> 0 then Log.error "Could not clear OpenGL context current when desired."
- SDL.SDL_GL_DeleteContext glContext
+ if not (SDL3.SDL_GL_MakeCurrent (sglWindow, NativePtr.nullPtr)) then Log.error "Could not clear OpenGL context current when desired."
+ if not (SDL3.SDL_GL_DestroyContext glContext) then Log.error "Failed to destroy OpenGL context when desired."
/// Initialize OpenGL context once created.
let InitContext attach =
diff --git a/Nu/Nu/OpenGL/OpenGL.Texture.fs b/Nu/Nu/OpenGL/OpenGL.Texture.fs
index e4a0b0556e..9cd6ce376d 100644
--- a/Nu/Nu/OpenGL/OpenGL.Texture.fs
+++ b/Nu/Nu/OpenGL/OpenGL.Texture.fs
@@ -13,7 +13,8 @@ open System.IO
open System.Numerics
open System.Runtime.InteropServices
open System.Threading
-open SDL2
+open FSharp.NativeInterop
+open SDL
open Pfim
open Prime
open Nu
@@ -391,21 +392,20 @@ module Texture =
Some (TextureDataNative (metadata, scan0, { new IDisposable with member this.Dispose () = bitmap.UnlockBits data; bitmap.Dispose () })) // NOTE: calling UnlockBits explicitly since I can't figure out if Dispose does.
with _ -> None
| _ -> None
-
+
// attempt to load data as any format supported by SDL_image on any device
else
- let format = SDL.SDL_PIXELFORMAT_ARGB8888 // seems to be the right format on Ubuntu...
- let unconvertedPtr = SDL_image.IMG_Load filePath
- if unconvertedPtr <> nativeint 0 then
- let unconverted = Marshal.PtrToStructure unconvertedPtr
+ let format = SDL_PixelFormat.SDL_PIXELFORMAT_ARGB8888 // seems to be the right format on Ubuntu...
+ let unconvertedPtr = SDL3_image.IMG_Load filePath
+ if not (NativePtr.isNullPtr unconvertedPtr) then
+ let unconverted = NativePtr.toByRef unconvertedPtr
let metadata = TextureMetadata.make unconverted.w unconverted.h
- let unconvertedFormat = Marshal.PtrToStructure unconverted.format
- if unconvertedFormat.format <> format then
- let convertedPtr = SDL.SDL_ConvertSurfaceFormat (unconvertedPtr, format, 0u)
- let converted = Marshal.PtrToStructure convertedPtr
- SDL.SDL_FreeSurface unconvertedPtr // no longer need this
- Some (TextureDataNative (metadata, converted.pixels, { new IDisposable with member this.Dispose () = SDL.SDL_FreeSurface convertedPtr }))
- else Some (TextureDataNative (metadata, unconverted.pixels, { new IDisposable with member this.Dispose () = SDL.SDL_FreeSurface unconvertedPtr }))
+ if unconverted.format <> format then
+ let convertedPtr = SDL3.SDL_ConvertSurface (unconvertedPtr, format)
+ let converted = NativePtr.toByRef convertedPtr
+ SDL3.SDL_DestroySurface unconvertedPtr // no longer need this
+ Some (TextureDataNative (metadata, converted.pixels, { new IDisposable with member this.Dispose () = SDL3.SDL_DestroySurface convertedPtr }))
+ else Some (TextureDataNative (metadata, unconverted.pixels, { new IDisposable with member this.Dispose () = SDL3.SDL_DestroySurface unconvertedPtr }))
else None
else None
diff --git a/Nu/Nu/Render/Renderer2d.fs b/Nu/Nu/Render/Renderer2d.fs
index 3d93381101..9f563d1091 100644
--- a/Nu/Nu/Render/Renderer2d.fs
+++ b/Nu/Nu/Render/Renderer2d.fs
@@ -9,8 +9,8 @@ open System
open System.Collections.Generic
open System.IO
open System.Numerics
-open System.Runtime.InteropServices
-open SDL2
+open FSharp.NativeInterop
+open SDL
open TiledSharp
open Prime
@@ -31,7 +31,7 @@ type [] TextValue =
mutable ClipOpt : Box2 voption
mutable Text : string
mutable Font : Font AssetTag
- mutable FontSizing : int option
+ mutable FontSizing : single option
mutable FontStyling : FontStyle Set
mutable Color : Color
mutable Justification : Justification
@@ -95,7 +95,7 @@ type TextDescriptor =
ClipOpt : Box2 voption
Text : string
Font : Font AssetTag
- FontSizing : int option
+ FontSizing : single option
FontStyling : FontStyle Set
Color : Color
Justification : Justification
@@ -207,7 +207,7 @@ type [] GlRenderer2d =
match renderAsset with
| RawAsset -> ()
| TextureAsset texture -> texture.Destroy ()
- | FontAsset (_, font) -> SDL_ttf.TTF_CloseFont font
+ | FontAsset (_, font) -> SDL3_ttf.TTF_CloseFont font
| CubeMapAsset _ -> ()
| StaticModelAsset _ -> ()
| AnimatedModelAsset _ -> ()
@@ -233,15 +233,15 @@ type [] GlRenderer2d =
let fontSizeDefault =
if fileFirstNameLength >= 3 then
let fontSizeText = fileFirstName.Substring (fileFirstNameLength - 3, 3)
- match Int32.TryParse fontSizeText with
+ match Single.TryParse fontSizeText with
| (true, fontSize) -> fontSize
| (false, _) -> Constants.Render.FontSizeDefault
else Constants.Render.FontSizeDefault
- let fontSize = fontSizeDefault * renderer.Viewport.DisplayScalar
- let fontOpt = SDL_ttf.TTF_OpenFont (asset.FilePath, fontSize)
- if fontOpt <> IntPtr.Zero
+ let fontSize = fontSizeDefault * single renderer.Viewport.DisplayScalar
+ let fontOpt = SDL3_ttf.TTF_OpenFont (asset.FilePath, fontSize)
+ if fontOpt <> NativePtr.nullPtr
then Some (FontAsset (fontSizeDefault, fontOpt))
- else Log.info ("Could not load font due to '" + SDL_ttf.TTF_GetError () + "'."); None
+ else Log.info ("Could not load font due to '" + SDL3.SDL_GetError () + "'."); None
| _ -> None
static member private tryLoadRenderPackage packageName renderer =
@@ -618,6 +618,7 @@ type [] GlRenderer2d =
// fin
tileIndex <- inc tileIndex
tileMin.X <- tileMin.X + tileSize.X
+
else Log.infoOnce ("TileLayerDescriptor failed due to unloadable or non-texture assets for one or more of '" + scstring tileAssets + "'.")
/// Render Spine skeleton.
@@ -658,7 +659,7 @@ type [] GlRenderer2d =
clipOpt : Box2 voption inref,
text : string,
font : Font AssetTag,
- fontSizing : int option,
+ fontSizing : single option,
fontStyling : FontStyle Set,
color : Color inref,
justification : Justification,
@@ -702,8 +703,8 @@ type [] GlRenderer2d =
// determine font size
let fontSize =
match fontSizing with
- | Some fontSize -> fontSize * renderer.Viewport.DisplayScalar
- | None -> fontSizeDefault * renderer.Viewport.DisplayScalar
+ | Some fontSize -> fontSize * single renderer.Viewport.DisplayScalar
+ | None -> fontSizeDefault * single renderer.Viewport.DisplayScalar
// attempt to find or create text texture
// NOTE: because of the hacky way the caret is shown, texture is recreated every blink on / off.
@@ -713,48 +714,47 @@ type [] GlRenderer2d =
| (false, _) ->
// gather rendering resources
- let (offset, textSurface, textSurfacePtr) =
+ let (offset, textSurfacePtr) =
// create sdl color
- let mutable colorSdl = SDL.SDL_Color ()
+ let mutable colorSdl = SDL_Color ()
colorSdl.r <- color.R8
colorSdl.g <- color.G8
colorSdl.b <- color.B8
colorSdl.a <- color.A8
// attempt to configure sdl font size
- if SDL_ttf.TTF_SetFontSize (font, fontSize) <> 0 then
- let error = SDL_ttf.TTF_GetError ()
+ if not (SDL3_ttf.TTF_SetFontSize (font, fontSize)) then
+ let error = SDL3.SDL_GetError ()
Log.infoOnce ("Failed to set font size for font '" + scstring font + "' due to: " + error)
- SDL_ttf.TTF_SetFontSize (font, fontSizeDefault * renderer.Viewport.DisplayScalar) |> ignore
+ SDL3_ttf.TTF_SetFontSize (font, fontSizeDefault * single renderer.Viewport.DisplayScalar) |> ignore
// configure sdl font style
let styleSdl =
if fontStyling.Count > 0 then // OPTIMIZATION: avoid set queries where possible.
- (if fontStyling.Contains Bold then SDL_ttf.TTF_STYLE_BOLD else 0) |||
- (if fontStyling.Contains Italic then SDL_ttf.TTF_STYLE_ITALIC else 0) |||
- (if fontStyling.Contains Underline then SDL_ttf.TTF_STYLE_UNDERLINE else 0) |||
- (if fontStyling.Contains Strikethrough then SDL_ttf.TTF_STYLE_STRIKETHROUGH else 0)
- else 0
- SDL_ttf.TTF_SetFontStyle (font, styleSdl)
+ (if fontStyling.Contains Bold then TTF_FontStyleFlags.TTF_STYLE_BOLD else TTF_FontStyleFlags.TTF_STYLE_NORMAL) |||
+ (if fontStyling.Contains Italic then TTF_FontStyleFlags.TTF_STYLE_ITALIC else TTF_FontStyleFlags.TTF_STYLE_NORMAL) |||
+ (if fontStyling.Contains Underline then TTF_FontStyleFlags.TTF_STYLE_UNDERLINE else TTF_FontStyleFlags.TTF_STYLE_NORMAL) |||
+ (if fontStyling.Contains Strikethrough then TTF_FontStyleFlags.TTF_STYLE_STRIKETHROUGH else TTF_FontStyleFlags.TTF_STYLE_NORMAL)
+ else TTF_FontStyleFlags.TTF_STYLE_NORMAL
+ SDL3_ttf.TTF_SetFontStyle (font, styleSdl)
// render text to surface
match justification with
| Unjustified wrapped ->
let textSurfacePtr =
if wrapped
- then SDL_ttf.TTF_RenderUNICODE_Blended_Wrapped (font, text, colorSdl, uint32 size.X)
- else SDL_ttf.TTF_RenderUNICODE_Blended (font, text, colorSdl)
- let textSurface = Marshal.PtrToStructure textSurfacePtr
+ then SDL3_ttf.TTF_RenderText_Blended_Wrapped (font, text, 0un, colorSdl, int size.X)
+ else SDL3_ttf.TTF_RenderText_Blended (font, text, 0un, colorSdl)
+ let textSurface = NativePtr.toByRef textSurfacePtr
let textSurfaceHeight = single textSurface.h
let offsetY = size.Y - textSurfaceHeight
- (v2 0.0f offsetY, textSurface, textSurfacePtr)
+ (v2 0.0f offsetY, textSurfacePtr)
| Justified (h, v) ->
let mutable width = 0
let mutable height = 0
- SDL_ttf.TTF_SizeUNICODE (font, text, &width, &height) |> ignore
- let textSurfacePtr = SDL_ttf.TTF_RenderUNICODE_Blended (font, text, colorSdl)
- let textSurface = Marshal.PtrToStructure textSurfacePtr
+ SDL3_ttf.TTF_GetStringSize (font, text, 0un, &&width, &&height) |> ignore
+ let textSurfacePtr = SDL3_ttf.TTF_RenderText_Blended (font, text, 0un, colorSdl)
let offsetX =
match h with
| JustifyLeft -> 0.0f
@@ -766,13 +766,14 @@ type [] GlRenderer2d =
| JustifyMiddle -> floor ((size.Y - single height) * 0.5f)
| JustifyBottom -> 0.0f
let offset = v2 offsetX offsetY
- (offset, textSurface, textSurfacePtr)
+ (offset, textSurfacePtr)
// render only when a valid surface was created
- if textSurfacePtr <> IntPtr.Zero then
+ if not (NativePtr.isNullPtr textSurfacePtr) then
+ let textSurface = NativePtr.toByRef textSurfacePtr
// construct mvp matrix
- let textSurfaceWidth = textSurface.pitch / 4
+ let textSurfaceWidth = textSurface.pitch / 4 // NOTE: textSurface.w may be an innacurate representation of texture width in SDL2_ttf versions beyond v2.0.15 because... I don't know why.
let textSurfaceHeight = textSurface.h
let translation = (position + offset).V3
let scale = v3 (single textSurfaceWidth) (single textSurfaceHeight) 1.0f
@@ -800,8 +801,8 @@ type [] GlRenderer2d =
let textTexture = OpenGL.Texture.EagerTexture { TextureMetadata = textTextureMetadata; TextureId = textTextureId }
OpenGL.Hl.Assert ()
- // free sdl surface
- SDL.SDL_FreeSurface textSurfacePtr
+ // destroy sdl surface
+ SDL3.SDL_DestroySurface textSurfacePtr
// register texture for reuse
renderer.TextTextures.Add (textTextureKey, (ref true, (textSurfaceWidth, textSurfaceHeight, modelViewProjection, textTexture)))
diff --git a/Nu/Nu/Render/Renderer3d.fs b/Nu/Nu/Render/Renderer3d.fs
index 55a0f1298c..b0d8b869e4 100644
--- a/Nu/Nu/Render/Renderer3d.fs
+++ b/Nu/Nu/Render/Renderer3d.fs
@@ -11,7 +11,8 @@ open System.Collections.Generic
open System.IO
open System.Numerics
open System.Runtime.InteropServices
-open SDL2
+open FSharp.NativeInterop
+open SDL
open Prime
/// A layer from which a 3d terrain's material is composed.
@@ -1434,7 +1435,7 @@ type [] GlRenderer3d =
match renderAsset with
| RawAsset -> () // nothing to do
| TextureAsset texture -> texture.Destroy ()
- | FontAsset (_, font) -> SDL_ttf.TTF_CloseFont font
+ | FontAsset (_, font) -> SDL3_ttf.TTF_CloseFont font
| CubeMapAsset (_, cubeMap, _) -> cubeMap.Destroy ()
| StaticModelAsset (_, model) -> OpenGL.PhysicallyBased.DestroyPhysicallyBasedModel model
| AnimatedModelAsset model -> OpenGL.PhysicallyBased.DestroyPhysicallyBasedModel model
@@ -4747,12 +4748,11 @@ type [] GlRenderer3d =
static member make glContext window geometryViewport windowViewport =
// start lazy texture server
- let sglWindow = match window with SglWindow sglWindow -> sglWindow.SglWindow
- if SDL.SDL_GL_MakeCurrent (sglWindow, IntPtr.Zero) <> 0 then Log.error "Could not clear OpenGL context current when desired."
+ if not (SDL3.SDL_GL_MakeCurrent (window, NativePtr.nullPtr)) then Log.error "Could not clear OpenGL context current when desired."
let lazyTextureQueues = ConcurrentDictionary HashIdentity.Reference
- let textureServer = OpenGL.Texture.TextureServer (lazyTextureQueues, glContext, sglWindow)
+ let textureServer = OpenGL.Texture.TextureServer (lazyTextureQueues, glContext, window)
textureServer.Start ()
- if SDL.SDL_GL_MakeCurrent (sglWindow, glContext) <> 0 then Log.error "Could not make OpenGL context current when required."
+ if not (SDL3.SDL_GL_MakeCurrent (window, glContext)) then Log.error "Could not make OpenGL context current when required."
OpenGL.Hl.Assert ()
// create cube map vao
diff --git a/Nu/Nu/Render/RendererPrelude.fs b/Nu/Nu/Render/RendererPrelude.fs
index 0898049a51..74fc74aacf 100644
--- a/Nu/Nu/Render/RendererPrelude.fs
+++ b/Nu/Nu/Render/RendererPrelude.fs
@@ -8,6 +8,7 @@ namespace Nu
open System
open System.Numerics
open Prime
+open SDL
/// The blend mode of a sprite.
type [] Blend =
@@ -129,7 +130,7 @@ type [] RenderPass =
type RenderAsset =
| RawAsset
| TextureAsset of Texture : OpenGL.Texture.Texture
- | FontAsset of FontSizeDefault : int * Font : nativeint
+ | FontAsset of FontSizeDefault : single * Font : TTF_Font nativeptr
| CubeMapAsset of FilePaths : OpenGL.CubeMap.CubeMapKey * CubeMap : OpenGL.Texture.Texture * IrradianceAndEnvironmentMapOptRef : (OpenGL.Texture.Texture * OpenGL.Texture.Texture) option ref
| StaticModelAsset of UserDefined : bool * StaticModel : OpenGL.PhysicallyBased.PhysicallyBasedModel
| AnimatedModelAsset of AnimatedModel : OpenGL.PhysicallyBased.PhysicallyBasedModel
\ No newline at end of file
diff --git a/Nu/Nu/Render/RendererProcess.fs b/Nu/Nu/Render/RendererProcess.fs
index a19d771c9c..e27178a3b6 100644
--- a/Nu/Nu/Render/RendererProcess.fs
+++ b/Nu/Nu/Render/RendererProcess.fs
@@ -10,7 +10,7 @@ open System.Collections.Concurrent
open System.Collections.Generic
open System.Numerics
open System.Threading
-open SDL2
+open SDL
open ImGuiNET
open Prime
@@ -20,7 +20,7 @@ type RendererProcess =
interface
/// Start the rendering process.
- abstract Start : ImFontAtlasPtr -> Window option -> Viewport -> Viewport -> unit
+ abstract Start : ImFontAtlasPtr -> SDL_Window nativeptr option -> Viewport -> Viewport -> unit
/// The current configuration of the 3d renderer.
abstract Renderer3dConfig : Renderer3dConfig
@@ -67,11 +67,11 @@ type RendererInline () =
let mutable started = false
let mutable terminated = false
- let mutable windowOpt = Option.None
+ let mutable windowOpt = Option.None
let mutable messages3d = List ()
let mutable messages2d = List ()
let mutable messagesImGui = List ()
- let mutable dependenciesOpt = Option.None
+ let mutable dependenciesOpt = Option.None
let assetTextureRequests = ConcurrentDictionary HashIdentity.Structural
let assetTextureOpts = ConcurrentDictionary HashIdentity.Structural
@@ -91,7 +91,7 @@ type RendererInline () =
| Some window ->
// create gl context
- let glContext = match window with SglWindow window -> OpenGL.Hl.CreateSglContextInitial window.SglWindow
+ let glContext = OpenGL.Hl.CreateSglContextInitial window
OpenGL.Hl.Assert ()
// initialize gl context
@@ -204,7 +204,7 @@ type RendererInline () =
member ri.RequestSwap () =
match windowOpt with
- | Some (SglWindow window) -> SDL.SDL_GL_SwapWindow window.SglWindow
+ | Some window -> SDL3.SDL_GL_SwapWindow window |> ignore
| None -> ()
member ri.Terminate () =
@@ -226,7 +226,7 @@ type RendererInline () =
// clean up gl
dependenciesOpt <- None
match windowOpt with
- | Some (SglWindow window) -> OpenGL.Hl.DestroySglContext (glContext, window.SglWindow)
+ | Some window -> OpenGL.Hl.DestroySglContext (glContext, window)
| None -> ()
// fin
@@ -374,7 +374,7 @@ type RendererThread () =
member private rt.Run fonts window geometryViewport windowViewport =
// create gl context
- let glContext = match window with SglWindow window -> OpenGL.Hl.CreateSglContextInitial window.SglWindow
+ let glContext = OpenGL.Hl.CreateSglContextInitial window
OpenGL.Hl.Assert ()
// initialize gl context
@@ -445,7 +445,7 @@ type RendererThread () =
swapRequestAcknowledged <- true
// swap
- match window with SglWindow window -> SDL.SDL_GL_SwapWindow window.SglWindow
+ SDL3.SDL_GL_SwapWindow window |> ignore
// clean up 3d
renderer3d.CleanUp ()
@@ -460,7 +460,7 @@ type RendererThread () =
OpenGL.Hl.Assert ()
// clean up gl
- OpenGL.Hl.DestroySglContext (glContext, match window with SglWindow window -> window.SglWindow)
+ OpenGL.Hl.DestroySglContext (glContext, window)
interface RendererProcess with
diff --git a/Nu/Nu/SDL2.dll b/Nu/Nu/SDL2.dll
deleted file mode 100644
index e26bcb1c3b..0000000000
Binary files a/Nu/Nu/SDL2.dll and /dev/null differ
diff --git a/Nu/Nu/SDL2_image.dll b/Nu/Nu/SDL2_image.dll
deleted file mode 100644
index d90de2a301..0000000000
Binary files a/Nu/Nu/SDL2_image.dll and /dev/null differ
diff --git a/Nu/Nu/SDL2_mixer.dll b/Nu/Nu/SDL2_mixer.dll
deleted file mode 100644
index 5e4fef32f9..0000000000
Binary files a/Nu/Nu/SDL2_mixer.dll and /dev/null differ
diff --git a/Nu/Nu/SDL2_ttf.dll b/Nu/Nu/SDL2_ttf.dll
deleted file mode 100644
index dbbf385119..0000000000
Binary files a/Nu/Nu/SDL2_ttf.dll and /dev/null differ
diff --git a/Nu/Nu/Scripts/GenerateDependencyGraph.fsx b/Nu/Nu/Scripts/GenerateDependencyGraph.fsx
index 22130b24f1..3782e93411 100644
--- a/Nu/Nu/Scripts/GenerateDependencyGraph.fsx
+++ b/Nu/Nu/Scripts/GenerateDependencyGraph.fsx
@@ -2,6 +2,7 @@
#r "FSharp.Compiler.Service"
#r "nuget: MSBuild.StructuredLogger"
#r "nuget: GiGraph.Dot, 4.1.0"
+#r "nuget: Prime"
open System
open System.IO
diff --git a/Nu/Nu/Scripts/GenerateInputBindings.fsx b/Nu/Nu/Scripts/GenerateInputBindings.fsx
index d61a67b58c..6f3bb99c6b 100644
--- a/Nu/Nu/Scripts/GenerateInputBindings.fsx
+++ b/Nu/Nu/Scripts/GenerateInputBindings.fsx
@@ -4,32 +4,14 @@
// Nu Game Engine is licensed under the Nu Game Engine Noncommercial License.
// See https://github.com/bryanedds/Nu/blob/master/License.md.
-#I __SOURCE_DIRECTORY__
-#r "nuget: Aether.Physics2D, 2.2.0"
-#r "nuget: Box2D.NET, 3.1.1.557"
-#r "nuget: BCnEncoder.Net, 2.2.1"
-#r "nuget: DotRecast.Recast.Toolset, 2026.1.1"
-#r "nuget: JoltPhysicsSharp, 2.19.5"
-#r "nuget: Magick.NET-Q8-AnyCpu, 14.10.3"
-#r "nuget: Pfim, 0.11.4"
-#r "nuget: Prime, 11.4.1"
-#r "nuget: System.Configuration.ConfigurationManager, 10.0.1"
-#r "nuget: System.Drawing.Common, 10.0.1"
-#r "nuget: Twizzle.ImGui-Bundle.NET, 1.91.5.2"
-#r "../../../Nu/Nu.Dependencies/AssimpNet/netstandard2.1/AssimpNet.dll"
-#r "../../../Nu/Nu.Dependencies/BulletSharpPInvoke/netstandard2.1/BulletSharp.dll"
-#r "../../../Nu/Nu.Dependencies/OpenGL.NET/lib/netcoreapp2.2/OpenGL.Net.dll"
-#r "../../../Nu/Nu.Dependencies/SDL2-CS/netstandard2.0/SDL2-CS.dll"
-#r "../../../Nu/Nu.Dependencies/TiledSharp/lib/netstandard2.0/TiledSharp.dll"
-#r "../../../Nu/Nu.Math/bin/Debug/netstandard2.1/Nu.Math.dll"
-#r "../../../Nu/Nu/bin/Debug/net10.0/Nu.dll"
+#r "nuget: Prime"
+#r "nuget: ppy.SDL3-CS"
open System
-open System.Text.RegularExpressions
-open System.Linq
open System.IO
+open System.Text.RegularExpressions
open Prime
-open SDL2
+open SDL
// this function was copied and converted from - https://stackoverflow.com/a/46095771
let upperCaseToPascalCase (original : string) =
@@ -43,39 +25,17 @@ let upperCaseToPascalCase (original : string) =
// replace white spaces with undescore, then replace all invalid chars with empty string
invalidCharsRgx.Replace(whiteSpace.Replace(original, "_"), "")
// split by underscores
- |> (fun (str : string) -> str.Split ([|'_'|], StringSplitOptions.RemoveEmptyEntries))
+ |> fun str -> str.Split ([|'_'|], StringSplitOptions.RemoveEmptyEntries)
// set first letter to uppercase
- |> (fun (strs : string array) -> strs.Select(fun w -> startsWithLowerCaseChar.Replace (w, fun m -> m.Value.ToUpperInvariant ())))
+ |> Array.map (fun w -> startsWithLowerCaseChar.Replace (w, _.Value.ToUpperInvariant()))
// replace second and all following upper case letters to lower if there is no next lower (ABC -> Abc)
- |> (fun (strs : string seq) -> strs.Select (fun w -> firstCharFollowedByUpperCasesOnly.Replace (w, fun m -> m.Value.ToLowerInvariant ())))
+ |> Array.map (fun w -> firstCharFollowedByUpperCasesOnly.Replace (w, _.Value.ToLowerInvariant()))
// set upper case the first lower case following a number (Ab9cd -> Ab9Cd)
- |> (fun (strs : string seq) -> strs.Select(fun w -> lowerCaseNextToNumber.Replace (w, fun m -> m.Value.ToUpperInvariant ())))
+ |> Array.map (fun w -> lowerCaseNextToNumber.Replace (w, _.Value.ToUpperInvariant()))
// lower second and next upper case letters except the last if it follows by any lower (ABcDEf -> AbcDef)
- |> (fun (strs : string seq) -> strs.Select(fun w -> upperCaseInside.Replace (w, fun m -> m.Value.ToLowerInvariant ())))
+ |> Array.map (fun w -> upperCaseInside.Replace (w, _.Value.ToLowerInvariant()))
String.Concat pascalCase
-let enumEntries (ty : Type) =
- ty.GetEnumNames ()
- |> enumerable
- |> Seq.map (fun (name : string) ->
- let name = name.Replace ("SDL_SCANCODE_", "")
- let firstChar = name.[0] // NOTE: elided bounds check because I presume no case where this is possible
- if firstChar >= '0' && firstChar <= '9'
- then "Num" + name
- else name)
- |> flip Seq.zip (ty.GetEnumValues () |> enumerable)
- |> Seq.filter (fun (name, _) -> name <> "SDL_NUM_SCANCODES")
- |> Seq.map (mapFst (fun (name : string) -> name.Replace ("RETURN", "ENTER"))) // NOTE: ImGui calls this the 'enter' key, so I choose that.
- |> Seq.map (mapFst upperCaseToPascalCase)
- |> List.ofSeq
-
-let enumEntryToCode (entryName : string, entryValue : int) =
- " | " + entryName + " = " + scstring entryValue
-
-let enumEntriesToCode entries =
- let codes = List.map enumEntryToCode entries
- String.Join ("\n", codes)
-
let generateBindingsCode codesStr =
"// Nu Game Engine.\n" +
"// Required Notice:\n" +
@@ -83,12 +43,12 @@ let generateBindingsCode codesStr =
"// Nu Game Engine is licensed under the Nu Game Engine Noncommercial License.\n" +
"// See https://github.com/bryanedds/Nu/blob/master/License.md.\n" +
"\n" +
- "//*****************************************************************************************//\n" +
- "// //\n" +
- "// NOTE: This code is GENERATED by 'GenerateInputBindings.fsx' and then manually modified! //\n" +
- "// Do NOT edit this code by hand! //\n" +
- "// //\n" +
- "//*****************************************************************************************//\n" +
+ "//*********************************************************************************************//\n" +
+ "// //\n" +
+ "// NOTE: This code is GENERATED by 'Scripts/GenerateInputBindings.fsx' as this is a one-to-one //\n" +
+ "// correspondence to SDL3.SDL_Scancode with cleaner names. Do NOT edit this code by hand! //\n" +
+ "// //\n" +
+ "//*********************************************************************************************//\n" +
"\n" +
"namespace Nu\n" +
"open System\n" +
@@ -97,11 +57,32 @@ let generateBindingsCode codesStr =
"type KeyboardKey =\n" +
codesStr
-do
- Directory.SetCurrentDirectory (__SOURCE_DIRECTORY__ + "/../bin/Debug")
- let code =
- typeof |>
- enumEntries |>
- enumEntriesToCode |>
- generateBindingsCode
- File.WriteAllText ("../../Sdl/SdlInputBindings.fs", code)
\ No newline at end of file
+let code =
+ Enum.GetValues ()
+ |> Array.filter (function SDL_Scancode.SDL_SCANCODE_COUNT | SDL_Scancode.SDL_SCANCODE_RESERVED -> false | _ -> true)
+ |> Array.map (fun value ->
+ let name =
+ match value with
+ | SDL_Scancode.SDL_SCANCODE_0 -> "Num0"
+ | SDL_Scancode.SDL_SCANCODE_1 -> "Num1"
+ | SDL_Scancode.SDL_SCANCODE_2 -> "Num2"
+ | SDL_Scancode.SDL_SCANCODE_3 -> "Num3"
+ | SDL_Scancode.SDL_SCANCODE_4 -> "Num4"
+ | SDL_Scancode.SDL_SCANCODE_5 -> "Num5"
+ | SDL_Scancode.SDL_SCANCODE_6 -> "Num6"
+ | SDL_Scancode.SDL_SCANCODE_7 -> "Num7"
+ | SDL_Scancode.SDL_SCANCODE_8 -> "Num8"
+ | SDL_Scancode.SDL_SCANCODE_9 -> "Num9"
+ | SDL_Scancode.SDL_SCANCODE_RETURN -> "Enter" // NOTE: ImGui calls this the 'enter' key, so I choose that.
+ | SDL_Scancode.SDL_SCANCODE_RETURN2 -> "Enter2"
+ | SDL_Scancode.SDL_SCANCODE_NONUSHASH -> "NonUsHash"
+ | SDL_Scancode.SDL_SCANCODE_NONUSBACKSLASH -> "NonUsBackslash"
+ | _ ->
+ let name = (string value).Replace ("SDL_SCANCODE_", "")
+ let name = Regex.Replace (name, "LEFT|RIGHT|UP|DOWN|LOCK|SCREEN|GUI|SHIFT|CTRL|ALT|BRACE|BRACKET|PAREN|SEL|SEPARATOR|MINUS|UNIT|REQ", "_$0")
+ let name = Regex.Replace (name, "MEM|EQUALS|END|DBL|VERTICAL|CURRENCY|CLEAR|ALT|LOCK", "$0_")
+ upperCaseToPascalCase name
+ " | " + name + " = " + string (int value))
+ |> String.concat "\n"
+ |> generateBindingsCode
+File.WriteAllText (__SOURCE_DIRECTORY__ + "/../Sdl/SdlInputBindings.fs", code)
\ No newline at end of file
diff --git a/Nu/Nu/Sdl/Sdl.fs b/Nu/Nu/Sdl/Sdl.fs
index b18b8d85a2..0102f9404e 100644
--- a/Nu/Nu/Sdl/Sdl.fs
+++ b/Nu/Nu/Sdl/Sdl.fs
@@ -9,30 +9,23 @@ open System
open System.Collections.Generic
open System.Numerics
open System.Runtime.InteropServices
-open SDL2
+open FSharp.NativeInterop
+open SDL
open Prime
-/// A window for rendering in SDL OpenGL.
-type [] SglWindow =
- { SglWindow : nativeint }
-
-/// A window for rendering.
-type [] Window =
- | SglWindow of SglWindow
-
/// Describes the initial configuration of a window created via SDL.
type SdlWindowConfig =
{ WindowTitle : string
WindowX : int
WindowY : int
- WindowFlags : SDL.SDL_WindowFlags }
+ WindowFlags : SDL_WindowFlags }
/// A default SdlWindowConfig.
static member val defaultConfig =
{ WindowTitle = "Nu Game"
- WindowX = SDL.SDL_WINDOWPOS_UNDEFINED
- WindowY = SDL.SDL_WINDOWPOS_UNDEFINED
- WindowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN ||| SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE ||| SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL }
+ WindowX = int SDL3.SDL_WINDOWPOS_UNDEFINED
+ WindowY = int SDL3.SDL_WINDOWPOS_UNDEFINED
+ WindowFlags = SDL_WindowFlags.SDL_WINDOW_RESIZABLE ||| SDL_WindowFlags.SDL_WINDOW_OPENGL }
/// Describes the general configuration of SDL.
type [] SdlConfig =
@@ -51,13 +44,13 @@ module SdlEvents =
/// like Windows from eco-hanging the application when it sees user input not getting processed in a timely
/// fashion.
let poll () =
- let mutable polledEvent = SDL2.SDL.SDL_Event ()
- while SDL2.SDL.SDL_PollEvent &polledEvent <> 0 do
+ let mutable polledEvent = SDL_Event ()
+ while (SDL3.SDL_PollEvent &&polledEvent : bool) do
PolledEvents.Enqueue polledEvent
/// Attempt to consume an SDL event. Usually only the engine should call this, but there might be cases where the
/// user needs to utilize it to cancel a long-running process or something.
- let tryConsume (event : SDL2.SDL.SDL_Event outref) =
+ let tryConsume (event : SDL_Event outref) =
PolledEvents.TryDequeue &event
[]
@@ -66,7 +59,7 @@ module SdlDeps =
/// The dependencies needed to initialize SDL.
type [] SdlDeps =
private
- { WindowOpt : Window option
+ { WindowOpt : SDL_Window nativeptr option
Config : SdlConfig
Destroy : unit -> unit }
@@ -88,53 +81,63 @@ module SdlDeps =
let getConfig sdlDeps =
sdlDeps.Config
+ /// Get the desktop display mode.
+ let getDesktopDisplayMode () =
+ let display = SDL3.SDL_GetPrimaryDisplay ()
+ let displayMode = SDL3.SDL_GetDesktopDisplayMode display
+ if NativePtr.isNullPtr displayMode then
+ Log.error ("Failed to get desktop display mode: " + SDL3.SDL_GetError ())
+ Unchecked.defaultof<_>
+ else NativePtr.read displayMode
+
/// Attempt to set the window's full screen state.
let trySetWindowFullScreen fullScreen sdlDeps =
match sdlDeps.WindowOpt with
- | Some (SglWindow window) ->
+ | Some window ->
// get a snapshot of whether screen was full
- let (width, height) = (ref 0, ref 0)
- SDL.SDL_GetWindowSize (window.SglWindow, width, height) |> ignore
- let mutable displayMode = Unchecked.defaultof<_>
- SDL.SDL_GetDesktopDisplayMode (0, &displayMode) |> ignore
- let wasFullScreen = width.Value = displayMode.w || height.Value = displayMode.h
+ let mutable width, height = 0, 0
+ SDL3.SDL_GetWindowSize (window, &&width, &&height) |> ignore
+ let displayMode = getDesktopDisplayMode ()
+ let wasFullScreen = width = displayMode.w || height = displayMode.h
// change full screen status via flags
- let flags = if fullScreen then uint SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP else 0u
- SDL.SDL_SetWindowFullscreen (window.SglWindow, flags) |> ignore
+ SDL3.SDL_SetWindowFullscreen (window, fullScreen) |> ignore
// when changing from full screen, set window to windowed size and make sure its title bar is visible
if wasFullScreen && not fullScreen then
let windowSizeWindowed = Constants.Render.DisplayVirtualResolution * 2
- SDL.SDL_RestoreWindow window.SglWindow
- SDL.SDL_SetWindowSize (window.SglWindow, windowSizeWindowed.X, windowSizeWindowed.Y)
- SDL.SDL_SetWindowPosition (window.SglWindow, 100, 100)
+ SDL3.SDL_RestoreWindow window |> ignore
+ SDL3.SDL_SetWindowSize (window, windowSizeWindowed.X, windowSizeWindowed.Y) |> ignore
+ SDL3.SDL_SetWindowPosition (window, 100, 100) |> ignore
- | _ -> ()
+ | None -> ()
sdlDeps
/// Attempt to initalize an SDL module.
let internal attemptPerformSdlInit create destroy =
let initResult = create ()
- let error = SDL.SDL_GetError ()
- if initResult = 0
+ let error = SDL3.SDL_GetError ()
+ if initResult
then Right ((), destroy)
else Left error
/// Attempt to initalize an SDL resource.
let internal tryMakeSdlResource create destroy =
let resource = create ()
- if resource <> IntPtr.Zero
- then Right (resource, destroy)
- else Left ("SDL2# resource creation failed due to '" + SDL.SDL_GetError () + "'.")
+ if NativePtr.isNullPtr resource
+ then Left ("SDL3# resource creation failed due to '" + SDL3.SDL_GetError () + "'.")
+ else Right (resource, destroy)
/// Attempt to initalize a global SDL resource.
let internal tryMakeSdlGlobalResource create destroy =
- let resource = create ()
- if resource = 0
+ let resource : SDLBool = create ()
+ if SDLBool.op_Implicit resource
then Right ((), destroy)
- else Left ("SDL2# global resource creation failed due to '" + SDL.SDL_GetError () + "'.")
+ else Left ("SDL3# global resource creation failed due to '" + SDL3.SDL_GetError () + "'.")
+
+ type private LogOutputDelegate =
+ delegate of nativeint * int * SDL_LogPriority * nativeptr -> unit
/// Attempt to make an SdlDeps instance.
let tryMake sdlConfig accompanied (windowSize : Vector2i) =
@@ -142,88 +145,76 @@ module SdlDeps =
(fun () ->
// setup SDL logging
- SDL.SDL_LogSetOutputFunction
- ((fun _ category priority message ->
+ SDL3.SDL_SetLogOutputFunction
+ (Marshal.GetFunctionPointerForDelegate(fun _ category priority message ->
+ let message = SDL3.PtrToStringUTF8 message
match priority with
- | SDL.SDL_LogPriority.SDL_LOG_PRIORITY_VERBOSE
- | SDL.SDL_LogPriority.SDL_LOG_PRIORITY_DEBUG
- | SDL.SDL_LogPriority.SDL_LOG_PRIORITY_INFO -> Log.info (Marshal.PtrToStringUTF8 message + " (Category " + string category + ")")
- | SDL.SDL_LogPriority.SDL_LOG_PRIORITY_WARN -> Log.warn (Marshal.PtrToStringUTF8 message + " (Category " + string category + ")")
- | SDL.SDL_LogPriority.SDL_LOG_PRIORITY_ERROR -> Log.error (Marshal.PtrToStringUTF8 message + " (Category " + string category + ")")
- | SDL.SDL_LogPriority.SDL_LOG_PRIORITY_CRITICAL -> Log.fail (Marshal.PtrToStringUTF8 message + " (Category " + string category + ")")
+ | SDL_LogPriority.SDL_LOG_PRIORITY_VERBOSE
+ | SDL_LogPriority.SDL_LOG_PRIORITY_DEBUG
+ | SDL_LogPriority.SDL_LOG_PRIORITY_INFO -> Log.info (message + " (Category " + string category + ")")
+ | SDL_LogPriority.SDL_LOG_PRIORITY_WARN -> Log.warn (message + " (Category " + string category + ")")
+ | SDL_LogPriority.SDL_LOG_PRIORITY_ERROR -> Log.error (message + " (Category " + string category + ")")
+ | SDL_LogPriority.SDL_LOG_PRIORITY_CRITICAL -> Log.fail (message + " (Category " + string category + ")")
| _ -> ()),
- nativeint 0)
+ 0n)
// attempt to initialize sdl
- Log.info "Initializing SDL 2..."
- SDL.SDL_SetHint ("SDL_WINDOWS_DPI_AWARENESS", "permonitorv2") |> ignore
- SDL.SDL_SetHint (SDL.SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1") |> ignore
+ Log.info "Initializing SDL 3..."
+ SDL3.SDL_SetHint (SDL3.SDL_HINT_WINDOWS_CLOSE_ON_ALT_F4, "0") |> ignore
let initConfig =
- SDL.SDL_INIT_TIMER |||
- SDL.SDL_INIT_AUDIO |||
- SDL.SDL_INIT_VIDEO |||
- SDL.SDL_INIT_JOYSTICK |||
- SDL.SDL_INIT_HAPTIC |||
- SDL.SDL_INIT_GAMECONTROLLER |||
- SDL.SDL_INIT_EVENTS
- let result = SDL.SDL_Init initConfig
-
- // verify initialization
- if result = 0 then
- let mutable sdlVersion = Unchecked.defaultof<_>
- SDL.SDL_GetVersion &sdlVersion
- Log.info ("Initialized SDL " + string sdlVersion.major + "." + string sdlVersion.minor + "." + string sdlVersion.patch + ".")
- result)
-
- (fun () -> SDL.SDL_Quit ()) with
+ SDL_InitFlags.SDL_INIT_AUDIO |||
+ SDL_InitFlags.SDL_INIT_VIDEO |||
+ SDL_InitFlags.SDL_INIT_JOYSTICK |||
+ SDL_InitFlags.SDL_INIT_HAPTIC |||
+ SDL_InitFlags.SDL_INIT_GAMEPAD |||
+ SDL_InitFlags.SDL_INIT_EVENTS
+ SDL3.SDL_Init initConfig)
+
+ (fun () -> SDL3.SDL_Quit ()) with
| Left error -> Left error
| Right ((), destroy) ->
match tryMakeSdlResource
(fun () ->
-
+
// create window
let windowConfig = sdlConfig.WindowConfig
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_ACCELERATED_VISUAL, 1) |> ignore
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, Constants.OpenGL.VersionMajor) |> ignore
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, Constants.OpenGL.VersionMinor) |> ignore
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, Constants.OpenGL.Profile) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_ACCELERATED_VISUAL, 1) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_CONTEXT_MAJOR_VERSION, Constants.OpenGL.VersionMajor) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_CONTEXT_MINOR_VERSION, Constants.OpenGL.VersionMinor) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_CONTEXT_PROFILE_MASK, Constants.OpenGL.Profile) |> ignore
#if DEBUG
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_CONTEXT_FLAGS, int SDL.SDL_GLcontext.SDL_GL_CONTEXT_DEBUG_FLAG) |> ignore
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_CONTEXT_FLAGS, int SDL.SDL_GLcontext.SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_CONTEXT_FLAGS, int SDL_GLContextFlag.SDL_GL_CONTEXT_DEBUG_FLAG) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_CONTEXT_FLAGS, int SDL_GLContextFlag.SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG) |> ignore
#endif
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1) |> ignore
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_DEPTH_SIZE, 24) |> ignore
- SDL.SDL_GL_SetAttribute (SDL.SDL_GLattr.SDL_GL_STENCIL_SIZE, 8) |> ignore
- let window = SDL.SDL_CreateWindow (windowConfig.WindowTitle, windowConfig.WindowX, windowConfig.WindowY, windowSize.X, windowSize.Y, windowConfig.WindowFlags)
-
- // set to full screen when window taking up entire screen and unaccompanied
- let mutable displayMode = Unchecked.defaultof<_>
- SDL.SDL_GetDesktopDisplayMode (0, &displayMode) |> ignore
- if (windowSize.X = displayMode.w || windowSize.Y = displayMode.h) && not accompanied then
- SDL.SDL_SetWindowFullscreen (window, uint SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_DOUBLEBUFFER, 1) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_DEPTH_SIZE, 24) |> ignore
+ SDL3.SDL_GL_SetAttribute (SDL_GLAttr.SDL_GL_STENCIL_SIZE, 8) |> ignore
+ let window = SDL3.SDL_CreateWindow (windowConfig.WindowTitle, windowSize.X, windowSize.Y, windowConfig.WindowFlags)
+ if not (NativePtr.isNullPtr window) then
+ SDL3.SDL_StartTextInput window |> ignore // TODO: This would activate an IME! We need this for receiving text input events at all, but we should only show an IME when the a text input field is focused.
+ SDL3.SDL_SetWindowPosition (window, windowConfig.WindowX, windowConfig.WindowY) |> ignore
+
+ // set to full screen when window taking up entire screen and unaccompanied
+ let mutable displayMode = getDesktopDisplayMode ()
+ if (windowSize.X = displayMode.w || windowSize.Y = displayMode.h) && not accompanied then
+ SDL3.SDL_SetWindowFullscreen (window, true) |> ignore
window)
- (fun window -> SDL.SDL_DestroyWindow window; destroy ()) with
+ (fun window -> SDL3.SDL_DestroyWindow window; destroy ()) with
| Left error -> Left error
| Right (window, destroy) ->
- match tryMakeSdlGlobalResource
- (fun () -> SDL_ttf.TTF_Init ())
- (fun () -> SDL_ttf.TTF_Quit (); destroy window) with
+ match tryMakeSdlGlobalResource SDL3_ttf.TTF_Init (fun () -> SDL3_ttf.TTF_Quit (); destroy window) with
| Left error -> Left error
| Right ((), destroy) ->
- match tryMakeSdlGlobalResource
- (fun () -> SDL_mixer.Mix_Init (enum 0))
- (fun () -> SDL_mixer.Mix_Quit (); destroy ()) with
+ match tryMakeSdlGlobalResource SDL3_mixer.MIX_Init (fun () -> SDL3_mixer.MIX_Quit (); destroy ()) with
| Left error -> Left error
| Right ((), destroy) ->
- match tryMakeSdlGlobalResource
- (fun () -> SDL_mixer.Mix_OpenAudio (Constants.Audio.Frequency, SDL_mixer.MIX_DEFAULT_FORMAT, SDL_mixer.MIX_DEFAULT_CHANNELS, Constants.Audio.BufferSize))
- (fun () -> SDL_mixer.Mix_CloseAudio (); destroy ()) with
- | Left error -> Left error
- | Right ((), destroy) ->
- GamepadState.init ()
- let context = SglWindow { SglWindow = window }
- Right { WindowOpt = Some context; Config = sdlConfig; Destroy = destroy }
+ let versionToString version =
+ let version = version ()
+ $"{SDL3.SDL_VERSIONNUM_MAJOR version}.{SDL3.SDL_VERSIONNUM_MINOR version}.{SDL3.SDL_VERSIONNUM_MICRO version}"
+ Log.info $"Initialized SDL {versionToString SDL3.SDL_GetVersion}, SDL_ttf {versionToString SDL3_ttf.TTF_Version}, SDL_mixer {versionToString SDL3_mixer.MIX_Version}, SDL_image {versionToString SDL3_image.IMG_Version}."
+ GamepadState.init ()
+ Right { WindowOpt = Some window; Config = sdlConfig; Destroy = destroy }
/// The dependencies needed to initialize SDL.
type SdlDeps = SdlDeps.SdlDeps
\ No newline at end of file
diff --git a/Nu/Nu/Sdl/SdlInput.fs b/Nu/Nu/Sdl/SdlInput.fs
index 5672a91eb7..676afb146d 100644
--- a/Nu/Nu/Sdl/SdlInput.fs
+++ b/Nu/Nu/Sdl/SdlInput.fs
@@ -7,8 +7,8 @@
namespace Nu
open System
open System.Numerics
-open System.Runtime.InteropServices
-open SDL2
+open FSharp.NativeInterop
+open SDL
open Prime
/// Describes a mouse button.
@@ -81,6 +81,7 @@ type GamepadDirection =
| DirectionCentered
/// Describes a gamepad button.
+// TODO: The actual button and the button name should be decoupled! See https://wiki.libsdl.org/SDL3/SDL_GamepadButton#remarks
type GamepadButton =
| ButtonA
| ButtonB
@@ -95,36 +96,45 @@ type GamepadButton =
[]
module internal MouseState =
- let mutable private MouseButtonStatePrevious = 0u
- let mutable private MouseButtonStateCurrent = 0u
+ let mutable private MouseButtonStatePrevious : SDL_MouseButtonFlags = LanguagePrimitives.EnumOfValue 0u
+ let mutable private MouseButtonStateCurrent : SDL_MouseButtonFlags = LanguagePrimitives.EnumOfValue 0u
let mutable internal MouseScrollStatePrevious = 0.0f
let mutable internal MouseScrollStateCurrent = 0.0f
/// Convert a MouseButton to SDL's representation.
let internal toSdlButton mouseButton =
match mouseButton with
- | MouseLeft -> SDL.SDL_BUTTON_LEFT
- | MouseMiddle -> SDL.SDL_BUTTON_MIDDLE
- | MouseRight -> SDL.SDL_BUTTON_RIGHT
- | MouseX1 -> SDL.SDL_BUTTON_X1
- | MouseX2 -> SDL.SDL_BUTTON_X2
+ | MouseLeft -> SDLButton.SDL_BUTTON_LEFT
+ | MouseMiddle -> SDLButton.SDL_BUTTON_MIDDLE
+ | MouseRight -> SDLButton.SDL_BUTTON_RIGHT
+ | MouseX1 -> SDLButton.SDL_BUTTON_X1
+ | MouseX2 -> SDLButton.SDL_BUTTON_X2
/// Convert SDL's representation of a mouse button to a MouseButton.
let internal toNuButton mouseButton =
match mouseButton with
- | SDL.SDL_BUTTON_LEFT -> MouseLeft
- | SDL.SDL_BUTTON_MIDDLE -> MouseMiddle
- | SDL.SDL_BUTTON_RIGHT -> MouseRight
- | SDL.SDL_BUTTON_X1 -> MouseX1
- | SDL.SDL_BUTTON_X2 -> MouseX2
+ | SDLButton.SDL_BUTTON_LEFT -> MouseLeft
+ | SDLButton.SDL_BUTTON_MIDDLE -> MouseMiddle
+ | SDLButton.SDL_BUTTON_RIGHT -> MouseRight
+ | SDLButton.SDL_BUTTON_X1 -> MouseX1
+ | SDLButton.SDL_BUTTON_X2 -> MouseX2
| _ -> failwith "Invalid SDL mouse button."
+ /// Convert a MouseButton to SDL's representation.
+ let private toSdlButtonFlags mouseButton =
+ match mouseButton with
+ | MouseLeft -> SDL_MouseButtonFlags.SDL_BUTTON_LMASK
+ | MouseMiddle -> SDL_MouseButtonFlags.SDL_BUTTON_MMASK
+ | MouseRight -> SDL_MouseButtonFlags.SDL_BUTTON_RMASK
+ | MouseX1 -> SDL_MouseButtonFlags.SDL_BUTTON_X1MASK
+ | MouseX2 -> SDL_MouseButtonFlags.SDL_BUTTON_X2MASK
+
/// Update the current mouse state from SDL.
let internal update () =
// update button state
MouseButtonStatePrevious <- MouseButtonStateCurrent
- let (sdlMouseButtonState, _, _) = SDL.SDL_GetMouseState ()
+ let sdlMouseButtonState = SDL3.SDL_GetMouseState (NativePtr.nullPtr, NativePtr.nullPtr)
MouseButtonStateCurrent <- sdlMouseButtonState
// update scroll state
@@ -132,8 +142,9 @@ module internal MouseState =
/// Get the position of the mouse.
let internal getPosition () =
- let (_, x, y) = SDL.SDL_GetMouseState ()
- v2 (single x) (single y)
+ let mutable x, y = 0.0f, 0.0f
+ SDL3.SDL_GetMouseState (&&x, &&y) |> ignore
+ v2 x y
/// Get the scroll of the mouse.
let internal getScroll () =
@@ -141,9 +152,8 @@ module internal MouseState =
/// Check that the given mouse button is down.
let internal isButtonDown mouseButton =
- let sdlMouseButton = toSdlButton mouseButton
- let sdlMouseButtonMask = SDL.SDL_BUTTON sdlMouseButton
- MouseButtonStateCurrent &&& sdlMouseButtonMask <> 0u
+ let sdlMouseButton = toSdlButtonFlags mouseButton
+ MouseButtonStateCurrent &&& sdlMouseButton <> LanguagePrimitives.EnumOfValue 0u
/// Check that the given mouse button is up.
let internal isButtonUp mouseButton =
@@ -151,17 +161,15 @@ module internal MouseState =
/// Check that the given mouse button was just pressed.
let internal isButtonPressed mouseButton =
- let sdlMouseButton = toSdlButton mouseButton
- let sdlMouseButtonMask = SDL.SDL_BUTTON sdlMouseButton
- (MouseButtonStatePrevious &&& sdlMouseButtonMask = 0u) &&
- (MouseButtonStateCurrent &&& sdlMouseButtonMask <> 0u)
+ let sdlMouseButton = toSdlButtonFlags mouseButton
+ (MouseButtonStatePrevious &&& sdlMouseButton = LanguagePrimitives.EnumOfValue 0u) &&
+ (MouseButtonStateCurrent &&& sdlMouseButton <> LanguagePrimitives.EnumOfValue 0u)
/// Check that the given mouse button was just released.
let internal isButtonReleased mouseButton =
- let sdlMouseButton = toSdlButton mouseButton
- let sdlMouseButtonMask = SDL.SDL_BUTTON sdlMouseButton
- (MouseButtonStatePrevious &&& sdlMouseButtonMask <> 0u) &&
- (MouseButtonStateCurrent &&& sdlMouseButtonMask = 0u)
+ let sdlMouseButton = toSdlButtonFlags mouseButton
+ (MouseButtonStatePrevious &&& sdlMouseButton <> LanguagePrimitives.EnumOfValue 0u) &&
+ (MouseButtonStateCurrent &&& sdlMouseButton = LanguagePrimitives.EnumOfValue 0u)
/// Get how much the mouse has just scrolled.
let internal getScrolled () =
@@ -178,50 +186,55 @@ module internal MouseState =
/// Exposes the ongoing state of the keyboard.
[]
module internal KeyboardState =
-
- let mutable private KeyboardStatePreviousOpt = None
- let mutable private KeyboardStateCurrentOpt = None
+
+ let mutable private keysCount = 0
+ let mutable private KeyboardStatePrevious = Array.empty
+ let mutable private KeyboardStateCurrent = Array.empty
/// Update the current keyboard state from SDL.
let internal update () =
- let mutable keysCount = 0
- let keyboardStatePtr = SDL.SDL_GetKeyboardState &keysCount
- let keyboardState = Array.zeroCreate keysCount
- Marshal.Copy(keyboardStatePtr, keyboardState, 0, keysCount)
- KeyboardStatePreviousOpt <- KeyboardStateCurrentOpt
- KeyboardStateCurrentOpt <- Some keyboardState
+ // move keyboard state current to previous
+ if KeyboardStatePrevious.Length <> KeyboardStateCurrent.Length
+ then KeyboardStatePrevious <- Array.copy KeyboardStateCurrent
+ else KeyboardStateCurrent.CopyTo (KeyboardStatePrevious.AsSpan ())
+
+ // get current keyboard state
+ let oldKeysCount = keysCount
+ let keyboardStatePtr = SDL3.SDL_GetKeyboardState &&keysCount
+ if oldKeysCount <> keysCount then KeyboardStateCurrent <- Array.zeroCreate keysCount
+ Span(NativePtr.toVoidPtr keyboardStatePtr, keysCount).CopyTo (KeyboardStateCurrent.AsSpan ())
/// Check that the given keyboard key is down.
let internal isKeyDown (key : KeyboardKey) =
- match KeyboardStateCurrentOpt with
- | Some keyboardState -> keyboardState.[int key] = byte 1
- | None -> false
+ match KeyboardStateCurrent with
+ | [||] -> false
+ | keyboardState -> keyboardState.[int key]
/// Check that the given keyboard key is up.
let internal isKeyUp (key : KeyboardKey) =
- match KeyboardStateCurrentOpt with
- | Some keyboardState -> keyboardState.[int key] = byte 0
- | None -> false
+ match KeyboardStateCurrent with
+ | [||] -> false
+ | keyboardState -> not keyboardState.[int key]
/// Check that the given keyboard key was just pressed.
let internal isKeyPressed key =
- match KeyboardStateCurrentOpt with
- | Some keyboardState ->
- keyboardState.[int key] = byte 1 &&
- match KeyboardStatePreviousOpt with
- | Some keyboardState -> keyboardState.[int key] = byte 0
- | None -> false
- | None -> false
+ match KeyboardStateCurrent with
+ | [||] -> false
+ | keyboardState ->
+ keyboardState.[int key] &&
+ match KeyboardStatePrevious with
+ | [||] -> false
+ | keyboardState -> not keyboardState.[int key]
/// Check that the given keyboard key was just released.
let internal isKeyReleased key =
- match KeyboardStateCurrentOpt with
- | Some keyboardState ->
- keyboardState.[int key] = byte 0 &&
- match KeyboardStatePreviousOpt with
- | Some keyboardState -> keyboardState.[int key] = byte 1
- | None -> false
- | None -> false
+ match KeyboardStateCurrent with
+ | [||] -> false
+ | keyboardState ->
+ not keyboardState.[int key] &&
+ match KeyboardStatePrevious with
+ | [||] -> false
+ | keyboardState -> keyboardState.[int key]
/// Check that either enter key is down.
let internal isEnterDown () =
@@ -245,7 +258,7 @@ module internal KeyboardState =
/// Check that either ctrl key is down.
let internal isCtrlDown () =
- int (SDL.SDL_GetModState ()) &&& int SDL.SDL_Keymod.KMOD_CTRL <> 0
+ SDL3.SDL_GetModState () &&& SDL_Keymod.SDL_KMOD_CTRL <> SDL_Keymod.SDL_KMOD_NONE
/// Check that both ctrl keys are up.
let internal isCtrlUp () =
@@ -253,7 +266,7 @@ module internal KeyboardState =
/// Check that either alt key is down.
let internal isAltDown () =
- int (SDL.SDL_GetModState ()) &&& int SDL.SDL_Keymod.KMOD_ALT <> 0
+ SDL3.SDL_GetModState () &&& SDL_Keymod.SDL_KMOD_ALT <> SDL_Keymod.SDL_KMOD_NONE
/// Check that both alt keys are up.
let internal isAltUp () =
@@ -261,7 +274,7 @@ module internal KeyboardState =
/// Check that either shift key is down.
let internal isShiftDown () =
- int (SDL.SDL_GetModState ()) &&& int SDL.SDL_Keymod.KMOD_SHIFT <> 0
+ SDL3.SDL_GetModState () &&& SDL_Keymod.SDL_KMOD_SHIFT <> SDL_Keymod.SDL_KMOD_NONE
/// Check that both shift keys are up.
let internal isShiftUp () =
@@ -275,16 +288,9 @@ module GamepadState =
/// Initialize gamepad state.
let internal init () =
- let indices = SDL.SDL_NumJoysticks ()
- Joysticks <-
- Array.map (fun joystick ->
- // NOTE: we don't have a matching call to SDL.SDL_JoystickClose, but it may not be necessary
- SDL.SDL_JoystickOpen joystick)
- [|0 .. indices|]
-
- /// Check that an SDL gamepad button is supported.
- let internal isSdlButtonSupported button =
- button < 8
+ use joysticks = SDL3.SDL_GetJoysticks ()
+ // NOTE: we don't have a matching call to SDL3.SDL_CloseJoystick, but it may not be necessary
+ Joysticks <- Array.init joysticks.Count (fun i -> SDL3.SDL_OpenJoystick joysticks.[i])
/// Get the number of open gamepad.
let internal getGamepadCount () =
@@ -293,74 +299,74 @@ module GamepadState =
/// Convert an SDL joystick axis to a GamepadAxis.
let internal toNuAxis axis =
match axis with
- | SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX -> StickLeftX
- | SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY -> StickLeftY
- | SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX -> StickRightX
- | SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY -> StickRightY
- | SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT -> TriggerLeft
- | SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT -> TriggerRight
+ | SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTX -> StickLeftX
+ | SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTY -> StickLeftY
+ | SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTX -> StickRightX
+ | SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTY -> StickRightY
+ | SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFT_TRIGGER -> TriggerLeft
+ | SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHT_TRIGGER -> TriggerRight
| _ -> failwith "Invalid SDL joystick axis."
/// Convert a GamepadAxis to SDL's representation.
let internal toSdlAxis axis =
match axis with
- | StickLeftX -> SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX
- | StickLeftY -> SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY
- | StickRightX -> SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX
- | StickRightY -> SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY
- | TriggerLeft -> SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT
- | TriggerRight -> SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT
+ | StickLeftX -> SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTX
+ | StickLeftY -> SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTY
+ | StickRightX -> SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTX
+ | StickRightY -> SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTY
+ | TriggerLeft -> SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFT_TRIGGER
+ | TriggerRight -> SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHT_TRIGGER
/// Convert a GamepadButton to SDL's representation.
let internal toSdlButton gamepadButton =
match gamepadButton with
- | ButtonA -> 0
- | ButtonB -> 1
- | ButtonX -> 2
- | ButtonY -> 3
- | ButtonL -> 4
- | ButtonR -> 5
- | ButtonSelect -> 6
- | ButtonStart -> 7
-
- /// Convert SDL's representation of a joystick button to a GamepadButton.
- let internal toNuButton gamepadButton =
+ | ButtonA -> SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH
+ | ButtonB -> SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST
+ | ButtonX -> SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST
+ | ButtonY -> SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH
+ | ButtonL -> SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER
+ | ButtonR -> SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER
+ | ButtonSelect -> SDL_GamepadButton.SDL_GAMEPAD_BUTTON_BACK
+ | ButtonStart -> SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START
+
+ /// Try to convert SDL's representation of a joystick button to a GamepadButton.
+ let internal tryToNuButton gamepadButton =
match gamepadButton with
- | 0 -> ButtonA
- | 1 -> ButtonB
- | 2 -> ButtonX
- | 3 -> ButtonY
- | 4 -> ButtonL
- | 5 -> ButtonR
- | 6 -> ButtonSelect
- | 7 -> ButtonStart
- | _ -> failwith "Invalid SDL joystick button."
+ | SDL_GamepadButton.SDL_GAMEPAD_BUTTON_SOUTH -> Some ButtonA
+ | SDL_GamepadButton.SDL_GAMEPAD_BUTTON_EAST -> Some ButtonB
+ | SDL_GamepadButton.SDL_GAMEPAD_BUTTON_WEST -> Some ButtonX
+ | SDL_GamepadButton.SDL_GAMEPAD_BUTTON_NORTH -> Some ButtonY
+ | SDL_GamepadButton.SDL_GAMEPAD_BUTTON_LEFT_SHOULDER -> Some ButtonL
+ | SDL_GamepadButton.SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER -> Some ButtonR
+ | SDL_GamepadButton.SDL_GAMEPAD_BUTTON_BACK -> Some ButtonSelect
+ | SDL_GamepadButton.SDL_GAMEPAD_BUTTON_START -> Some ButtonStart
+ | _ -> None
/// Convert a GamepadDirection to SDL's representation.
let internal toSdlDirection gamepadDirection =
match gamepadDirection with
- | DirectionUp -> SDL.SDL_HAT_UP
- | DirectionUpLeft -> SDL.SDL_HAT_LEFTUP
- | DirectionLeft -> SDL.SDL_HAT_LEFT
- | DirectionDownLeft -> SDL.SDL_HAT_LEFTDOWN
- | DirectionDown -> SDL.SDL_HAT_DOWN
- | DirectionDownRight -> SDL.SDL_HAT_RIGHTDOWN
- | DirectionRight -> SDL.SDL_HAT_RIGHT
- | DirectionUpRight -> SDL.SDL_HAT_RIGHTUP
- | DirectionCentered -> SDL.SDL_HAT_CENTERED
+ | DirectionUp -> SDL3.SDL_HAT_UP
+ | DirectionUpLeft -> SDL3.SDL_HAT_LEFTUP
+ | DirectionLeft -> SDL3.SDL_HAT_LEFT
+ | DirectionDownLeft -> SDL3.SDL_HAT_LEFTDOWN
+ | DirectionDown -> SDL3.SDL_HAT_DOWN
+ | DirectionDownRight -> SDL3.SDL_HAT_RIGHTDOWN
+ | DirectionRight -> SDL3.SDL_HAT_RIGHT
+ | DirectionUpRight -> SDL3.SDL_HAT_RIGHTUP
+ | DirectionCentered -> SDL3.SDL_HAT_CENTERED
/// Convert SDL's representation of a hat direction to a GamepadDirection.
let internal toNuDirection gamepadDirection =
- match gamepadDirection with
- | SDL.SDL_HAT_UP -> DirectionUp
- | SDL.SDL_HAT_LEFTUP -> DirectionUpLeft
- | SDL.SDL_HAT_LEFT -> DirectionLeft
- | SDL.SDL_HAT_LEFTDOWN -> DirectionDownLeft
- | SDL.SDL_HAT_DOWN -> DirectionDown
- | SDL.SDL_HAT_RIGHTDOWN -> DirectionDownRight
- | SDL.SDL_HAT_RIGHT -> DirectionRight
- | SDL.SDL_HAT_RIGHTUP -> DirectionUpRight
- | SDL.SDL_HAT_CENTERED -> DirectionCentered
+ match uint32 gamepadDirection with
+ | SDL3.SDL_HAT_UP -> DirectionUp
+ | SDL3.SDL_HAT_LEFTUP -> DirectionUpLeft
+ | SDL3.SDL_HAT_LEFT -> DirectionLeft
+ | SDL3.SDL_HAT_LEFTDOWN -> DirectionDownLeft
+ | SDL3.SDL_HAT_DOWN -> DirectionDown
+ | SDL3.SDL_HAT_RIGHTDOWN -> DirectionDownRight
+ | SDL3.SDL_HAT_RIGHT -> DirectionRight
+ | SDL3.SDL_HAT_RIGHTUP -> DirectionUpRight
+ | SDL3.SDL_HAT_CENTERED -> DirectionCentered
| _ -> failwith "Invalid SDL hat direction."
/// Convert an SDL joystick axis value to a float in the range -1.0f to 1.0f.
@@ -373,8 +379,8 @@ module GamepadState =
let internal getStickLeft index =
match Array.tryItem index Joysticks with
| Some joystick ->
- let x = SDL.SDL_GameControllerGetAxis (joystick, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX)
- let y = SDL.SDL_GameControllerGetAxis (joystick, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY)
+ let x = SDL3.SDL_GetJoystickAxis (joystick, int SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTX)
+ let y = SDL3.SDL_GetJoystickAxis (joystick, int SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFTY)
v2 (toNuAxisValue x) (toNuAxisValue y)
| None -> v2Zero
@@ -382,8 +388,8 @@ module GamepadState =
let internal getStickRight index =
match Array.tryItem index Joysticks with
| Some joystick ->
- let x = SDL.SDL_GameControllerGetAxis (joystick, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTX)
- let y = SDL.SDL_GameControllerGetAxis (joystick, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_RIGHTY)
+ let x = SDL3.SDL_GetJoystickAxis (joystick, int SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTX)
+ let y = SDL3.SDL_GetJoystickAxis (joystick, int SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHTY)
v2 (toNuAxisValue x) (toNuAxisValue y)
| None -> v2Zero
@@ -391,7 +397,7 @@ module GamepadState =
let internal getTriggerLeft index =
match Array.tryItem index Joysticks with
| Some joystick ->
- let value = SDL.SDL_GameControllerGetAxis (joystick, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT)
+ let value = SDL3.SDL_GetJoystickAxis (joystick, int SDL_GamepadAxis.SDL_GAMEPAD_AXIS_LEFT_TRIGGER)
toNuAxisValue value
| None -> 0.0f
@@ -399,15 +405,15 @@ module GamepadState =
let internal getTriggerRight index =
match Array.tryItem index Joysticks with
| Some joystick ->
- let value = SDL.SDL_GameControllerGetAxis (joystick, SDL.SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
+ let value = SDL3.SDL_GetJoystickAxis (joystick, int SDL_GamepadAxis.SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)
toNuAxisValue value
| None -> 0.0f
/// Get the given gamepad's current direction.
let internal getDirection index =
match Array.tryItem index Joysticks with
- | Some joystick ->
- let hat = SDL.SDL_JoystickGetHat (joystick, 0)
+ | Some gamepad ->
+ let hat = SDL3.SDL_GetJoystickHat (gamepad, 0)
toNuDirection hat
| None -> DirectionCentered
@@ -415,5 +421,5 @@ module GamepadState =
let internal isButtonDown index button =
let sdlButton = toSdlButton button
match Array.tryItem index Joysticks with
- | Some joystick -> SDL.SDL_JoystickGetButton (joystick, sdlButton) = byte 1
+ | Some joystick -> SDL3.SDL_GetJoystickButton (joystick, int sdlButton)
| None -> false
\ No newline at end of file
diff --git a/Nu/Nu/Sdl/SdlInputBindings.fs b/Nu/Nu/Sdl/SdlInputBindings.fs
index f123cae2b1..f3d48521ac 100644
--- a/Nu/Nu/Sdl/SdlInputBindings.fs
+++ b/Nu/Nu/Sdl/SdlInputBindings.fs
@@ -4,12 +4,12 @@
// Nu Game Engine is licensed under the Nu Game Engine Noncommercial License.
// See https://github.com/bryanedds/Nu/blob/master/License.md.
-//*****************************************************************************************//
-// //
-// NOTE: This code is GENERATED by 'GenerateInputBindings.fsx' and then manually modified! //
-// Do NOT edit this code by hand! //
-// //
-//*****************************************************************************************//
+//*********************************************************************************************//
+// //
+// NOTE: This code is GENERATED by 'Scripts/GenerateInputBindings.fsx' as this is a one-to-one //
+// correspondence to SDL3.SDL_Scancode with cleaner names. Do NOT edit this code by hand! //
+// //
+//*********************************************************************************************//
namespace Nu
open System
@@ -173,14 +173,14 @@ type KeyboardKey =
| Out = 160
| Oper = 161
| ClearAgain = 162
- | Crsel = 163
- | Exsel = 164
+ | CrSel = 163
+ | ExSel = 164
| Kp00 = 176
| Kp000 = 177
| ThousandsSeparator = 178
| DecimalSeparator = 179
| CurrencyUnit = 180
- | CurrencySubunit = 181
+ | CurrencySubUnit = 181
| KpLeftParen = 182
| KpRightParen = 183
| KpLeftBrace = 184
@@ -230,32 +230,36 @@ type KeyboardKey =
| RAlt = 230
| RGui = 231
| Mode = 257
- | AudioNext = 258
- | AudioPrev = 259
- | AudioStop = 260
- | AudioPlay = 261
- | AudioMute = 262
- | MediaSelect = 263
- | Www = 264
- | Mail = 265
- | Calculator = 266
- | Computer = 267
- | AcSearch = 268
- | AcHome = 269
- | AcBack = 270
- | AcForward = 271
- | AcStop = 272
- | AcRefresh = 273
- | AcBookmarks = 274
- | BrightnessDown = 275
- | BrightnessUp = 276
- | DisplaySwitch = 277
- | KbdIllumToggle = 278
- | KbdIllumDown = 279
- | KbdIllumUp = 280
- | Eject = 281
- | Sleep = 282
- | App1 = 283
- | App2 = 284
- | AudioRewind = 285
- | AudioFastForward = 286
\ No newline at end of file
+ | Sleep = 258
+ | Wake = 259
+ | ChannelIncrement = 260
+ | ChannelDecrement = 261
+ | MediaPlay = 262
+ | MediaPause = 263
+ | MediaRecord = 264
+ | MediaFastForward = 265
+ | MediaRewind = 266
+ | MediaNextTrack = 267
+ | MediaPreviousTrack = 268
+ | MediaStop = 269
+ | MediaEject = 270
+ | MediaPlayPause = 271
+ | MediaSelect = 272
+ | AcNew = 273
+ | AcOpen = 274
+ | AcClose = 275
+ | AcExit = 276
+ | AcSave = 277
+ | AcPrint = 278
+ | AcProperties = 279
+ | AcSearch = 280
+ | AcHome = 281
+ | AcBack = 282
+ | AcForward = 283
+ | AcStop = 284
+ | AcRefresh = 285
+ | AcBookmarks = 286
+ | SoftLeft = 287
+ | SoftRight = 288
+ | Call = 289
+ | EndCall = 290
\ No newline at end of file
diff --git a/Nu/Nu/Sdl/SdlInterop.fs b/Nu/Nu/Sdl/SdlInterop.fs
deleted file mode 100644
index 9421b8a3c0..0000000000
--- a/Nu/Nu/Sdl/SdlInterop.fs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Nu Game Engine.
-// Required Notice:
-// Copyright (C) Bryan Edds.
-// Nu Game Engine is licensed under the Nu Game Engine Noncommercial License.
-// See https://github.com/bryanedds/Nu/blob/master/License.md.
-
-namespace SDL2
-open System
-open System.Runtime.InteropServices
-
-[]
-module SDL =
-
- // Missing in SDL2#? https://wiki.libsdl.org/SDL2/SDL_GetDefaultCursor?
- []
- extern nativeint SDL_GetDefaultCursor ()
\ No newline at end of file
diff --git a/Nu/Nu/World/World.fs b/Nu/Nu/World/World.fs
index 0822b8e1f1..c2b295e711 100644
--- a/Nu/Nu/World/World.fs
+++ b/Nu/Nu/World/World.fs
@@ -12,7 +12,7 @@ open System.Diagnostics.Tracing
open System.Numerics
open System.Reflection
open System.Threading
-open SDL2
+open SDL
open Prime
/// GC event listener. Currently just logs whenever an object larger than 85k is allocated to notify user of possible
@@ -396,7 +396,7 @@ module WorldModule4 =
assemblyName.Name <> "Prime" &&
assemblyName.Name <> "Nu" &&
assemblyName.Name <> "netstandard" &&
- assemblyName.Name <> "SDL2-CS"
+ not (assemblyName.Name.StartsWith "ppy.SDL3")
let pluginAssembly = plugin.GetType().Assembly
let pluginAssembliesReferenced = Reflection.loadReferencedAssembliesTransitively pluginAssemblyNamePredicate pluginAssembly
let pluginAssemblies = Array.cons pluginAssembly pluginAssembliesReferenced
@@ -446,7 +446,7 @@ module WorldModule4 =
for package in initialPackages do
rendererProcess.EnqueueMessage3d (LoadRenderPackage3d package)
let audioPlayer =
- if SDL.SDL_WasInit SDL.SDL_INIT_AUDIO <> 0u
+ if SDL3.SDL_WasInit SDL_InitFlags.SDL_INIT_AUDIO <> LanguagePrimitives.EnumOfValue 0u
then SdlAudioPlayer.make () :> AudioPlayer
else StubAudioPlayer.make () :> AudioPlayer
for package in initialPackages do
diff --git a/Nu/Nu/World/WorldEvents.fs b/Nu/Nu/World/WorldEvents.fs
index b01d22749f..b89a2a3357 100644
--- a/Nu/Nu/World/WorldEvents.fs
+++ b/Nu/Nu/World/WorldEvents.fs
@@ -63,9 +63,9 @@ type GamepadButtonData =
{ GamepadButton : GamepadButton
Down : bool }
-/// The data for a text input event.
+/// The data for a text input event for one character that may be represented as multiple Unicode code points for non-English languages.
type TextInputData =
- { TextInput : char }
+ { TextInput : string }
/// The data for a text edit event.
type TextEditData =
@@ -342,19 +342,19 @@ module Events =
let KeyboardKeyUpEvent = stoa "KeyboardKey/Up/Event"
/// Raised when a gamepad axis is changed.
- let GamepadAxisChangeEvent axis (index : int) = rtoa [|"Gamepad"; GamepadAxis.toEventName axis + string index + "Change"; "Event"|]
+ let GamepadAxisChangeEvent axis (index : uint) = rtoa [|"Gamepad"; GamepadAxis.toEventName axis + string index + "Change"; "Event"|]
/// Raised when a gamepad direction is changed.
- let GamepadDirectionChangeEvent (index : int) = rtoa [|"Gamepad"; "Direction" + string index + "Change"; "Event"|]
+ let GamepadDirectionChangeEvent (index : uint) = rtoa [|"Gamepad"; "Direction" + string index + "Change"; "Event"|]
/// Raised when a gamepad button is pressed or released.
- let GamepadButtonChangeEvent (index : int) = rtoa [|"Gamepad"; "Button" + string index + "Change"; "Event"|]
+ let GamepadButtonChangeEvent (index : uint) = rtoa [|"Gamepad"; "Button" + string index + "Change"; "Event"|]
/// Raised when a gamepad direction is pressed.
- let GamepadButtonDownEvent (index : int) = rtoa [|"Gamepad"; "Button" + string index + "Down"; "Event"|]
+ let GamepadButtonDownEvent (index : uint) = rtoa [|"Gamepad"; "Button" + string index + "Down"; "Event"|]
/// Raised when a gamepad direction is released.
- let GamepadButtonUpEvent (index : int) = rtoa [|"Gamepad"; "Button" + string index + "Up"; "Event"|]
+ let GamepadButtonUpEvent (index : uint) = rtoa [|"Gamepad"; "Button" + string index + "Up"; "Event"|]
/// Raised when text input is received from the OS.
let TextInputEvent = stoa "TextInput/Event"
diff --git a/Nu/Nu/World/WorldFacets.fs b/Nu/Nu/World/WorldFacets.fs
index 861c88eff2..7550d74bfd 100644
--- a/Nu/Nu/World/WorldFacets.fs
+++ b/Nu/Nu/World/WorldFacets.fs
@@ -71,7 +71,7 @@ type StaticSpriteFacet () =
override this.Render (_, entity, world) =
let mutable transform = entity.GetTransform world
let staticImage = entity.GetStaticImage world
- let insetOpt = match entity.GetInsetOpt world with Some inset -> ValueSome inset | None -> ValueNone
+ let insetOpt = entity.GetInsetOpt world |> Option.toValueOption
let clipOpt = entity.GetClipOpt world |> Option.toValueOption
let color = entity.GetColor world
let blend = entity.GetBlend world
@@ -152,7 +152,7 @@ type AnimatedSpriteFacet () =
override this.Render (_, entity, world) =
let mutable transform = entity.GetTransform world
let animationSheet = entity.GetAnimationSheet world
- let insetOpt = match getSpriteInsetOpt entity world with Some inset -> ValueSome inset | None -> ValueNone
+ let insetOpt = getSpriteInsetOpt entity world |> Option.toValueOption
let clipOpt = entity.GetClipOpt world |> Option.toValueOption
let color = entity.GetColor world
let blend = entity.GetBlend world
@@ -423,8 +423,8 @@ module TextFacetExtensions =
member this.GetFont world : Font AssetTag = this.Get (nameof this.Font) world
member this.SetFont (value : Font AssetTag) world = this.Set (nameof this.Font) value world
member this.Font = lens (nameof this.Font) this this.GetFont this.SetFont
- member this.GetFontSizing world : int option = this.Get (nameof this.FontSizing) world
- member this.SetFontSizing (value : int option) world = this.Set (nameof this.FontSizing) value world
+ member this.GetFontSizing world : single option = this.Get (nameof this.FontSizing) world
+ member this.SetFontSizing (value : single option) world = this.Set (nameof this.FontSizing) value world
member this.FontSizing = lens (nameof this.FontSizing) this this.GetFontSizing this.SetFontSizing
member this.GetFontStyling world : FontStyle Set = this.Get (nameof this.FontStyling) world
member this.SetFontStyling (value : FontStyle Set) world = this.Set (nameof this.FontStyling) value world
@@ -869,9 +869,9 @@ type FillBarFacet () =
define Entity.ColorDisabled Constants.Gui.ColorDisabledDefault
define Entity.Fill 0.0f
define Entity.FillInset 0.0f
- define Entity.FillColor (Color (1.0f, 0.0f, 0.0f, 1.0f))
+ define Entity.FillColor Color.Red
define Entity.FillImage Assets.Default.White
- define Entity.BorderColor (Color (1.0f, 1.0f, 1.0f, 1.0f))
+ define Entity.BorderColor Color.White
define Entity.BorderImage Assets.Default.Border]
override this.Render (_, entity, world) =
diff --git a/Nu/Nu/World/WorldInput.fs b/Nu/Nu/World/WorldInput.fs
index bffcc63200..755ae62345 100644
--- a/Nu/Nu/World/WorldInput.fs
+++ b/Nu/Nu/World/WorldInput.fs
@@ -201,11 +201,6 @@ module WorldInputModule =
ignore (world : World)
KeyboardState.isShiftUp ()
- /// Check that an SDL gamepad button is supported.
- static member isSdlButtonSupported button world =
- ignore (world : World)
- GamepadState.isSdlButtonSupported button
-
/// Get the number of open gamepad.
static member getGamepadCount world =
ignore (world : World)
@@ -226,10 +221,10 @@ module WorldInputModule =
ignore (world : World)
GamepadState.toSdlButton gamepadButton
- /// Convert SDL's representation of a joystick button to a GamepadButton.
- static member toNuButton gamepadButton world =
+ /// Try to convert SDL's representation of a joystick button to a GamepadButton.
+ static member tryToNuButton gamepadButton world =
ignore (world : World)
- GamepadState.toNuButton gamepadButton
+ GamepadState.tryToNuButton gamepadButton
/// Convert a GamepadDirection to SDL's representation.
static member toSdlDirection gamepadDirection world =
diff --git a/Nu/Nu/World/WorldModule2.fs b/Nu/Nu/World/WorldModule2.fs
index b6e1339b79..1cc1c94f34 100644
--- a/Nu/Nu/World/WorldModule2.fs
+++ b/Nu/Nu/World/WorldModule2.fs
@@ -11,7 +11,7 @@ open System.Diagnostics
open System.IO
open System.Numerics
open System.Threading
-open SDL2
+open SDL
open ImGuiNET
open Prime
@@ -1097,55 +1097,54 @@ module WorldModule2 =
| KeyboardKey.LShift -> [ImGuiKey.LeftShift; ImGuiKey.ModShift]
| KeyboardKey.RShift -> [ImGuiKey.RightShift; ImGuiKey.ModShift]
| _ ->
- if int keyboardKey >= int KeyboardKey.Num1 && int keyboardKey <= int KeyboardKey.Num9 then int ImGuiKey._1 + (int keyboardKey - int KeyboardKey.Num1) |> enum |> List.singleton
- elif int keyboardKey >= int KeyboardKey.A && int keyboardKey <= int KeyboardKey.Z then int ImGuiKey.A + (int keyboardKey - int KeyboardKey.A) |> enum |> List.singleton
- elif int keyboardKey >= int KeyboardKey.F1 && int keyboardKey <= int KeyboardKey.F12 then int ImGuiKey.F1 + (int keyboardKey - int KeyboardKey.F1) |> enum |> List.singleton
+ if keyboardKey >= KeyboardKey.Num1 && keyboardKey <= KeyboardKey.Num9 then ImGuiKey._1 + (keyboardKey - KeyboardKey.Num1 |> LanguagePrimitives.EnumToValue |> LanguagePrimitives.EnumOfValue) |> List.singleton
+ elif keyboardKey >= KeyboardKey.A && keyboardKey <= KeyboardKey.Z then ImGuiKey.A + (keyboardKey - KeyboardKey.A |> LanguagePrimitives.EnumToValue |> LanguagePrimitives.EnumOfValue) |> List.singleton
+ elif keyboardKey >= KeyboardKey.F1 && keyboardKey <= KeyboardKey.F12 then ImGuiKey.F1 + (keyboardKey - KeyboardKey.F1 |> LanguagePrimitives.EnumToValue |> LanguagePrimitives.EnumOfValue) |> List.singleton
else []
- static member private processInput2 (evt : SDL.SDL_Event) (world : World) =
- match evt.``type`` with
- | SDL.SDL_EventType.SDL_QUIT ->
+ static member private processInput2 (evt : SDL_Event) (world : World) =
+ match evt.Type with
+ | SDL_EventType.SDL_EVENT_QUIT ->
if world.Accompanied then
let eventTrace = EventTrace.debug "World" "processInput2" "ExitRequest" EventTrace.empty
World.publishPlus () Nu.Game.Handle.ExitRequestEvent eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_WINDOWEVENT ->
- if evt.window.windowEvent = SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED then
-
- // ensure window size is a factor of display virtual resolution, going to full screen otherwise
- let windowSize = World.getWindowSize world
- let windowScalar =
- max (single windowSize.X / single Constants.Render.DisplayVirtualResolution.X |> ceil |> int |> max 1)
- (single windowSize.Y / single Constants.Render.DisplayVirtualResolution.Y |> ceil |> int |> max 1)
- let windowSize' = windowScalar * Constants.Render.DisplayVirtualResolution
- World.trySetWindowSize windowSize' world
- let windowSize'' = World.getWindowSize world
- if windowSize''.X < windowSize'.X || windowSize''.Y < windowSize'.Y then
- World.trySetWindowFullScreen true world
-
- // synchronize display virtual scalar
- let windowSize'' = World.getWindowSize world
- let xScalar = windowSize''.X / Constants.Render.DisplayVirtualResolution.X
- let yScalar = windowSize''.Y / Constants.Render.DisplayVirtualResolution.Y
- Globals.Render.DisplayScalar <- min xScalar yScalar
-
- // synchronize view ports
- World.synchronizeViewports world
-
- | SDL.SDL_EventType.SDL_MOUSEMOTION ->
+ | SDL_EventType.SDL_EVENT_WINDOW_RESIZED ->
+
+ // ensure window size is a factor of display virtual resolution, going to full screen otherwise
+ let windowSize = World.getWindowSize world
+ let windowScalar =
+ max (single windowSize.X / single Constants.Render.DisplayVirtualResolution.X |> ceil |> int |> max 1)
+ (single windowSize.Y / single Constants.Render.DisplayVirtualResolution.Y |> ceil |> int |> max 1)
+ let windowSize' = windowScalar * Constants.Render.DisplayVirtualResolution
+ World.trySetWindowSize windowSize' world
+ let windowSize'' = World.getWindowSize world
+ if windowSize''.X < windowSize'.X || windowSize''.Y < windowSize'.Y then
+ World.trySetWindowFullScreen true world
+
+ // synchronize display virtual scalar
+ let windowSize'' = World.getWindowSize world
+ let xScalar = windowSize''.X / Constants.Render.DisplayVirtualResolution.X
+ let yScalar = windowSize''.Y / Constants.Render.DisplayVirtualResolution.Y
+ Globals.Render.DisplayScalar <- min xScalar yScalar
+
+ // synchronize view ports
+ World.synchronizeViewports world
+
+ | SDL_EventType.SDL_EVENT_MOUSE_MOTION ->
let io = ImGui.GetIO ()
let boundsMin = world.WindowViewport.Bounds.Min
- io.AddMousePosEvent (single (evt.button.x - boundsMin.X), single (evt.button.y - boundsMin.Y))
+ io.AddMousePosEvent (evt.button.x - single boundsMin.X, evt.button.y - single boundsMin.Y)
let mousePosition = v2 (single evt.button.x) (single evt.button.y)
if World.isMouseButtonDown MouseLeft world then
let eventTrace = EventTrace.debug "World" "processInput2" "MouseDrag" EventTrace.empty
World.publishPlus { MouseMoveData.Position = mousePosition } Nu.Game.Handle.MouseDragEvent eventTrace Nu.Game.Handle true true world
let eventTrace = EventTrace.debug "World" "processInput2" "MouseMove" EventTrace.empty
World.publishPlus { MouseMoveData.Position = mousePosition } Nu.Game.Handle.MouseMoveEvent eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN ->
+ | SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN ->
let io = ImGui.GetIO ()
- let mouseButton = World.toNuMouseButton (uint32 evt.button.button)
+ let mouseButton = World.toNuMouseButton evt.button.Button
io.AddMouseButtonEvent (World.toImGuiMouseButton mouseButton, true)
- if not (io.WantCaptureMouseGlobal) then
+ if not io.WantCaptureMouseGlobal then
let mousePosition = World.getMousePosition world
let mouseButtonDownEvent = stoa ("Mouse/" + MouseButton.toEventName mouseButton + "/Down/Event/" + Constants.Engine.GameName)
let mouseButtonChangeEvent = stoa ("Mouse/" + MouseButton.toEventName mouseButton + "/Change/Event/" + Constants.Engine.GameName)
@@ -1154,13 +1153,12 @@ module WorldModule2 =
World.publishPlus eventData mouseButtonDownEvent eventTrace Nu.Game.Handle true true world
let eventTrace = EventTrace.debug "World" "processInput2" "MouseButtonChange" EventTrace.empty
World.publishPlus eventData mouseButtonChangeEvent eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_MOUSEBUTTONUP ->
+ | SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP ->
let io = ImGui.GetIO ()
- let mouseButton = World.toNuMouseButton (uint32 evt.button.button)
+ let mouseButton = World.toNuMouseButton evt.button.Button
io.AddMouseButtonEvent (World.toImGuiMouseButton mouseButton, false)
- if not (io.WantCaptureMouseGlobal) then
+ if not io.WantCaptureMouseGlobal then
let mousePosition = World.getMousePosition world
- let mouseButton = World.toNuMouseButton (uint32 evt.button.button)
let mouseButtonUpEvent = stoa ("Mouse/" + MouseButton.toEventName mouseButton + "/Up/Event/" + Constants.Engine.GameName)
let mouseButtonChangeEvent = stoa ("Mouse/" + MouseButton.toEventName mouseButton + "/Change/Event/" + Constants.Engine.GameName)
let eventData = { Position = mousePosition; Button = mouseButton; Down = false }
@@ -1168,82 +1166,84 @@ module WorldModule2 =
World.publishPlus eventData mouseButtonUpEvent eventTrace Nu.Game.Handle true true world
let eventTrace = EventTrace.debug "World" "processInput2" "MouseButtonChange" EventTrace.empty
World.publishPlus eventData mouseButtonChangeEvent eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_MOUSEWHEEL ->
+ | SDL_EventType.SDL_EVENT_MOUSE_WHEEL ->
let imGui = World.getImGui world
- if evt.wheel.preciseY <> 0.0f then
- let flipped = evt.wheel.direction = uint SDL.SDL_MouseWheelDirection.SDL_MOUSEWHEEL_FLIPPED
- let travel = evt.wheel.preciseY * if flipped then -1.0f else 1.0f
+ if evt.wheel.y <> 0.0f then
+ let flipped = evt.wheel.direction = SDL_MouseWheelDirection.SDL_MOUSEWHEEL_FLIPPED
+ let travel = evt.wheel.y * if flipped then -1.0f else 1.0f
MouseState.MouseScrollStateCurrent <- MouseState.MouseScrollStateCurrent + travel
imGui.HandleMouseScrollChange travel
let eventData = { Travel = travel }
let eventTrace = EventTrace.debug "World" "processInput2" "MouseScroll" EventTrace.empty
World.publishPlus eventData Nu.Game.Handle.MouseScrollEvent eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_TEXTINPUT ->
+ | SDL_EventType.SDL_EVENT_TEXT_INPUT ->
let io = ImGui.GetIO ()
let imGui = World.getImGui world
- let textInput = char evt.text.text.FixedElementField
- imGui.HandleKeyChar textInput
- if not (io.WantCaptureKeyboardGlobal) then
+ let textInput = evt.text.GetText ()
+ imGui.HandleTextInput textInput
+ if not io.WantCaptureKeyboardGlobal then
let eventData = { TextInput = textInput }
let eventTrace = EventTrace.debug "World" "processInput2" "TextInput" EventTrace.empty
World.publishPlus eventData Nu.Game.Handle.TextInputEvent eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_KEYDOWN ->
+ | SDL_EventType.SDL_EVENT_KEY_DOWN ->
let io = ImGui.GetIO ()
- let keyboard = evt.key
- let key = keyboard.keysym
- let keyboardKey = key.scancode |> int |> enum
+ let key = evt.key
+ let keyboardKey = key.scancode |> LanguagePrimitives.EnumToValue |> LanguagePrimitives.EnumOfValue
for imGuiKey in World.toImGuiKeys keyboardKey do
io.AddKeyEvent (imGuiKey, true)
if not (io.WantCaptureKeyboardGlobal) then
- let eventData = { KeyboardKey = keyboardKey; Repeated = keyboard.repeat <> byte 0; Down = true }
+ let eventData = { KeyboardKey = keyboardKey; Repeated = key.repeat; Down = true }
let eventTrace = EventTrace.debug "World" "processInput2" "KeyboardKeyDown" EventTrace.empty
World.publishPlus eventData Nu.Game.Handle.KeyboardKeyDownEvent eventTrace Nu.Game.Handle true true world
let eventTrace = EventTrace.debug "World" "processInput2" "KeyboardKeyChange" EventTrace.empty
World.publishPlus eventData Nu.Game.Handle.KeyboardKeyChangeEvent eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_KEYUP ->
+ | SDL_EventType.SDL_EVENT_KEY_UP ->
let io = ImGui.GetIO ()
- let keyboard = evt.key
- let key = keyboard.keysym
- let keyboardKey = key.scancode |> int |> enum
+ let key = evt.key
+ let keyboardKey = key.scancode |> LanguagePrimitives.EnumToValue |> LanguagePrimitives.EnumOfValue
for imGuiKey in World.toImGuiKeys keyboardKey do
io.AddKeyEvent (imGuiKey, false)
if not (io.WantCaptureKeyboardGlobal) then
- let eventData = { KeyboardKey = key.scancode |> int |> enum; Repeated = keyboard.repeat <> byte 0; Down = false }
+ let eventData = { KeyboardKey = keyboardKey; Repeated = key.repeat; Down = false }
let eventTrace = EventTrace.debug "World" "processInput2" "KeyboardKeyUp" EventTrace.empty
World.publishPlus eventData Nu.Game.Handle.KeyboardKeyUpEvent eventTrace Nu.Game.Handle true true world
let eventTrace = EventTrace.debug "World" "processInput2" "KeyboardKeyChange" EventTrace.empty
World.publishPlus eventData Nu.Game.Handle.KeyboardKeyChangeEvent eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_JOYAXISMOTION ->
- let index = evt.jaxis.which
- let axis = evt.jaxis.axis |> int |> enum
- let value = evt.jaxis.axisValue
+ | SDL_EventType.SDL_EVENT_JOYSTICK_AXIS_MOTION ->
+ let index = evt.jaxis.which |> LanguagePrimitives.EnumToValue
+ let axis = evt.jaxis.axis |> int |> enum
+ let value = evt.jaxis.value
let eventData = { GamepadAxis = GamepadState.toNuAxisValue value }
let eventTrace = EventTrace.debug "World" "processInput2" "GamepadAxisChange" EventTrace.empty
World.publishPlus eventData (Nu.Game.Handle.GamepadAxisChangeEvent (GamepadState.toNuAxis axis) index) eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_JOYHATMOTION ->
- let index = evt.jhat.which
- let direction = evt.jhat.hatValue
+ | SDL_EventType.SDL_EVENT_JOYSTICK_HAT_MOTION ->
+ let index = evt.jhat.which |> LanguagePrimitives.EnumToValue
+ let direction = evt.jhat.value
let eventData = { GamepadDirection = GamepadState.toNuDirection direction }
let eventTrace = EventTrace.debug "World" "processInput2" "GamepadDirectionChange" EventTrace.empty
World.publishPlus eventData (Nu.Game.Handle.GamepadDirectionChangeEvent index) eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_JOYBUTTONDOWN ->
- let index = evt.jbutton.which
- let button = int evt.jbutton.button
- if GamepadState.isSdlButtonSupported button then
- let eventData = { GamepadButton = GamepadState.toNuButton button; Down = true }
+ | SDL_EventType.SDL_EVENT_JOYSTICK_BUTTON_DOWN ->
+ let index = evt.jbutton.which |> LanguagePrimitives.EnumToValue
+ let button = evt.jbutton.button |> int |> enum
+ match GamepadState.tryToNuButton button with
+ | Some button ->
+ let eventData = { GamepadButton = button; Down = true }
let eventTrace = EventTrace.debug "World" "processInput2" "GamepadButtonDown" EventTrace.empty
World.publishPlus eventData (Nu.Game.Handle.GamepadButtonDownEvent index) eventTrace Nu.Game.Handle true true world
let eventTrace = EventTrace.debug "World" "processInput2" "GamepadButtonChange" EventTrace.empty
World.publishPlus eventData (Nu.Game.Handle.GamepadButtonChangeEvent index) eventTrace Nu.Game.Handle true true world
- | SDL.SDL_EventType.SDL_JOYBUTTONUP ->
- let index = evt.jbutton.which
- let button = int evt.jbutton.button
- if GamepadState.isSdlButtonSupported button then
- let eventData = { GamepadButton = GamepadState.toNuButton button; Down = true }
+ | None -> ()
+ | SDL_EventType.SDL_EVENT_JOYSTICK_BUTTON_UP ->
+ let index = evt.jbutton.which |> LanguagePrimitives.EnumToValue
+ let button = evt.jbutton.button |> int |> enum
+ match GamepadState.tryToNuButton button with
+ | Some button ->
+ let eventData = { GamepadButton = button; Down = true }
let eventTrace = EventTrace.debug "World" "processInput2" "GamepadButtonUp" EventTrace.empty
World.publishPlus eventData (Nu.Game.Handle.GamepadButtonUpEvent index) eventTrace Nu.Game.Handle true true world
let eventTrace = EventTrace.debug "World" "processInput2" "GamepadButtonChange" EventTrace.empty
World.publishPlus eventData (Nu.Game.Handle.GamepadButtonChangeEvent index) eventTrace Nu.Game.Handle true true world
+ | None -> ()
| _ -> ()
static member private processIntegrationMessage integrationMessage (world : World) =
@@ -1894,7 +1894,7 @@ module WorldModule2 =
WorldModuleInternal2.HashSet3dShadowCached.Clear ()
static member private processInput (world : World) =
- if SDL.SDL_WasInit SDL.SDL_INIT_TIMER <> 0u then
+ if SDL3.SDL_WasInit SDL_InitFlags.SDL_INIT_EVENTS <> LanguagePrimitives.EnumOfValue 0u then
SdlEvents.poll ()
MouseState.update ()
KeyboardState.update ()
@@ -2034,7 +2034,7 @@ module WorldModule2 =
// process audio
world.Timers.AudioTimer.Restart ()
- if SDL.SDL_WasInit SDL.SDL_INIT_AUDIO <> 0u then
+ if SDL3.SDL_WasInit SDL_InitFlags.SDL_INIT_AUDIO <> LanguagePrimitives.EnumOfValue 0u then
let audioPlayer = World.getAudioPlayer world
let audioMessages = audioPlayer.PopMessages ()
audioPlayer.Play audioMessages
diff --git a/Nu/Nu/World/WorldPrelude.fs b/Nu/Nu/World/WorldPrelude.fs
index c812e44444..7e408d6e2a 100644
--- a/Nu/Nu/World/WorldPrelude.fs
+++ b/Nu/Nu/World/WorldPrelude.fs
@@ -9,7 +9,7 @@ open System
open System.Collections.Generic
open System.Diagnostics
open System.Numerics
-open SDL2
+open SDL
open TiledSharp
open DotRecast.Core.Collections
open DotRecast.Core.Numerics
@@ -651,23 +651,22 @@ module internal AmbientState =
let internal tryGetWindowFlags state =
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
- | Some (SglWindow window) -> Some (SDL.SDL_GetWindowFlags window.SglWindow)
+ | Some window -> Some (SDL3.SDL_GetWindowFlags window)
| _ -> None
let internal tryGetWindowMinimized state =
- Option.map (fun flags -> flags &&& uint32 SDL.SDL_WindowFlags.SDL_WINDOW_MINIMIZED <> 0u) (tryGetWindowFlags state)
+ Option.map (fun flags -> flags &&& SDL_WindowFlags.SDL_WINDOW_MINIMIZED <> LanguagePrimitives.EnumOfValue 0UL) (tryGetWindowFlags state)
let internal tryGetWindowMaximized state =
- Option.map (fun flags -> flags &&& uint32 SDL.SDL_WindowFlags.SDL_WINDOW_MAXIMIZED <> 0u) (tryGetWindowFlags state)
+ Option.map (fun flags -> flags &&& SDL_WindowFlags.SDL_WINDOW_MAXIMIZED <> LanguagePrimitives.EnumOfValue 0UL) (tryGetWindowFlags state)
let internal tryGetWindowFullScreen state =
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
- | Some (SglWindow window) ->
- let (width, height) = (ref 0, ref 0)
- SDL.SDL_GetWindowSize (window.SglWindow, width, height) |> ignore
- let mutable displayMode = Unchecked.defaultof<_>
- SDL.SDL_GetDesktopDisplayMode (0, &displayMode) |> ignore
- Some (width.Value = displayMode.w || height.Value = displayMode.h)
+ | Some window ->
+ let mutable width, height = 0, 0
+ SDL3.SDL_GetWindowSize (window, &&width, &&height) |> ignore
+ let displayMode = SdlDeps.getDesktopDisplayMode ()
+ Some (width = displayMode.w || height = displayMode.h)
| _ -> None
let internal trySetWindowFullScreen fullScreen state =
@@ -682,28 +681,28 @@ module internal AmbientState =
let internal tryGetWindowPosition state =
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
- | Some (SglWindow window) ->
- let (x, y) = (ref 0, ref 0)
- SDL.SDL_GetWindowPosition (window.SglWindow, x, y) |> ignore
- Some (v2i x.Value y.Value)
+ | Some window ->
+ let mutable x, y = 0, 0
+ SDL3.SDL_GetWindowPosition (window, &&x, &&y) |> ignore
+ Some (v2i x y)
| _ -> None
let internal trySetWindowPosition (position : Vector2i) state =
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
- | Some (SglWindow window) -> SDL.SDL_SetWindowPosition (window.SglWindow, position.X, position.Y) |> ignore
+ | Some window -> SDL3.SDL_SetWindowPosition (window, position.X, position.Y) |> ignore
| None -> ()
let internal tryGetWindowSize state =
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
- | Some (SglWindow window) ->
- let (width, height) = (ref 0, ref 0)
- SDL.SDL_GetWindowSize (window.SglWindow, width, height) |> ignore
- Some (v2i width.Value height.Value)
+ | Some window ->
+ let mutable width, height = 0, 0
+ SDL3.SDL_GetWindowSize (window, &&width, &&height) |> ignore
+ Some (v2i width height)
| _ -> None
let internal trySetWindowSize (size : Vector2i) state =
match Option.flatten (Option.map SdlDeps.getWindowOpt state.SdlDepsOpt) with
- | Some (SglWindow window) -> SDL.SDL_SetWindowSize (window.SglWindow, size.X, size.Y) |> ignore
+ | Some window -> SDL3.SDL_SetWindowSize (window, size.X, size.Y) |> ignore
| None -> ()
let internal getSymbolicsBy by state =
diff --git a/Nu/Nu/libFLAC-8.dll b/Nu/Nu/libFLAC-8.dll
deleted file mode 100644
index 71f2e19d9c..0000000000
Binary files a/Nu/Nu/libFLAC-8.dll and /dev/null differ
diff --git a/Nu/Nu/libfreetype-6.dll b/Nu/Nu/libfreetype-6.dll
deleted file mode 100644
index 16ef77711f..0000000000
Binary files a/Nu/Nu/libfreetype-6.dll and /dev/null differ
diff --git a/Nu/Nu/libjpeg-9.dll b/Nu/Nu/libjpeg-9.dll
deleted file mode 100644
index 9a05528eff..0000000000
Binary files a/Nu/Nu/libjpeg-9.dll and /dev/null differ
diff --git a/Nu/Nu/libmodplug-1.dll b/Nu/Nu/libmodplug-1.dll
deleted file mode 100644
index 7c0512674e..0000000000
Binary files a/Nu/Nu/libmodplug-1.dll and /dev/null differ
diff --git a/Nu/Nu/libmpg123-0.dll b/Nu/Nu/libmpg123-0.dll
deleted file mode 100644
index c7809b163f..0000000000
Binary files a/Nu/Nu/libmpg123-0.dll and /dev/null differ
diff --git a/Nu/Nu/libogg-0.dll b/Nu/Nu/libogg-0.dll
deleted file mode 100644
index 5ec1f1e617..0000000000
Binary files a/Nu/Nu/libogg-0.dll and /dev/null differ
diff --git a/Nu/Nu/libopus-0.dll b/Nu/Nu/libopus-0.dll
deleted file mode 100644
index 5991eb7e51..0000000000
Binary files a/Nu/Nu/libopus-0.dll and /dev/null differ
diff --git a/Nu/Nu/libopusfile-0.dll b/Nu/Nu/libopusfile-0.dll
deleted file mode 100644
index 8a5134c2e6..0000000000
Binary files a/Nu/Nu/libopusfile-0.dll and /dev/null differ
diff --git a/Nu/Nu/libpng16-16.dll b/Nu/Nu/libpng16-16.dll
deleted file mode 100644
index 709f724459..0000000000
Binary files a/Nu/Nu/libpng16-16.dll and /dev/null differ
diff --git a/Nu/Nu/libtiff-5.dll b/Nu/Nu/libtiff-5.dll
deleted file mode 100644
index 6ef56deaed..0000000000
Binary files a/Nu/Nu/libtiff-5.dll and /dev/null differ
diff --git a/Nu/Nu/libwebp-7.dll b/Nu/Nu/libwebp-7.dll
deleted file mode 100644
index fad57b229e..0000000000
Binary files a/Nu/Nu/libwebp-7.dll and /dev/null differ
diff --git a/Projects/Blaze Vector ImSim/Blaze Vector ImSim.fsproj b/Projects/Blaze Vector ImSim/Blaze Vector ImSim.fsproj
index 25e3ff171e..e0a8c438f6 100644
--- a/Projects/Blaze Vector ImSim/Blaze Vector ImSim.fsproj
+++ b/Projects/Blaze Vector ImSim/Blaze Vector ImSim.fsproj
@@ -74,9 +74,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Blaze Vector Mmcc/Blaze Vector Mmcc.fsproj b/Projects/Blaze Vector Mmcc/Blaze Vector Mmcc.fsproj
index 87f56656c1..701b90c543 100644
--- a/Projects/Blaze Vector Mmcc/Blaze Vector Mmcc.fsproj
+++ b/Projects/Blaze Vector Mmcc/Blaze Vector Mmcc.fsproj
@@ -74,9 +74,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Breakout ImSim/Breakout ImSim.fsproj b/Projects/Breakout ImSim/Breakout ImSim.fsproj
index 7fd5be608b..af148373a4 100644
--- a/Projects/Breakout ImSim/Breakout ImSim.fsproj
+++ b/Projects/Breakout ImSim/Breakout ImSim.fsproj
@@ -69,9 +69,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Breakout Mmcc/Breakout Mmcc.fsproj b/Projects/Breakout Mmcc/Breakout Mmcc.fsproj
index a3fe76a148..4c0d1d76bd 100644
--- a/Projects/Breakout Mmcc/Breakout Mmcc.fsproj
+++ b/Projects/Breakout Mmcc/Breakout Mmcc.fsproj
@@ -70,9 +70,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Jump Box/Jump Box.fsproj b/Projects/Jump Box/Jump Box.fsproj
index 40928151e2..772e5a505e 100644
--- a/Projects/Jump Box/Jump Box.fsproj
+++ b/Projects/Jump Box/Jump Box.fsproj
@@ -66,9 +66,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Metrics/Metrics.fsproj b/Projects/Metrics/Metrics.fsproj
index 3accf14b25..fb00184cc3 100644
--- a/Projects/Metrics/Metrics.fsproj
+++ b/Projects/Metrics/Metrics.fsproj
@@ -64,9 +64,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Nelmish/Nelmish.fsproj b/Projects/Nelmish/Nelmish.fsproj
index 82471b83ed..88cd3b5836 100644
--- a/Projects/Nelmish/Nelmish.fsproj
+++ b/Projects/Nelmish/Nelmish.fsproj
@@ -66,9 +66,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Sand Box 2d/FluidSim.fs b/Projects/Sand Box 2d/FluidSim.fs
index 8077e55b17..1576031e55 100644
--- a/Projects/Sand Box 2d/FluidSim.fs
+++ b/Projects/Sand Box 2d/FluidSim.fs
@@ -176,7 +176,7 @@ type FluidSimDispatcher () =
[Entity.Position .= v3 255f 80f 0f
Entity.Text @= $"Particle Sprite: {(fluidEmitter.GetStaticImage world).AssetName}"
Entity.Elevation .= 1f
- Entity.FontSizing .= Some 8] world then
+ Entity.FontSizing .= Some 8.f] world then
if fluidEmitter.GetStaticImage world = Assets.Default.Ball then
// in Paint.NET (canvas size = 50 x 50), use the Brush (size = 50, hardness = 50%, fill = solid color #0094FF)
// and click the center once, to generate this Particle image.
@@ -199,7 +199,7 @@ type FluidSimDispatcher () =
[Entity.Position .= v3 255f 50f 0f
Entity.Text @= $"Viscosity: {fluidEmitter.GetViscocity world}"
Entity.Elevation .= 1f
- Entity.FontSizing .= Some 12] world then
+ Entity.FontSizing .= Some 12.f] world then
fluidEmitter.Viscocity.Map
(function
| 0.004f -> 0.01f
@@ -216,7 +216,7 @@ type FluidSimDispatcher () =
[Entity.Position .= v3 255f 20f 0f
Entity.Text @= $"Linear Damping: {fluidEmitter.GetLinearDamping world}"
Entity.Elevation .= 1f
- Entity.FontSizing .= Some 11] world then
+ Entity.FontSizing .= Some 11.f] world then
fluidEmitter.LinearDamping.Map
(function
| 0f -> 0.2f
@@ -232,7 +232,7 @@ type FluidSimDispatcher () =
[Entity.Position .= v3 255f -10f 0f
Entity.Text @= $"Particle Radius: {fluidEmitter.GetFluidParticleRadius world}"
Entity.Elevation .= 1f
- Entity.FontSizing .= Some 10] world then
+ Entity.FontSizing .= Some 10.f] world then
fluidEmitter.FluidParticleRadius.Map
(function
| 28.8f -> fluidEmitter.LinearDamping.Map (max 0.5f) world; 22.2f // Particles would explode when tank is full without damping
@@ -299,7 +299,7 @@ type FluidSimDispatcher () =
Mouse Left and Right - Summon a giant bubble that collides with particles.\n\
Mouse Middle - Draw contours that collide with particles. \n\
NOTE: Intersecting contours are not supported and will cause tunneling!"
- Entity.FontSizing .= Some 10
+ Entity.FontSizing .= Some 10.f
Entity.TextMargin .= v2 5f 0f] world
if World.doButton "Info Close"
[Entity.LayoutOrder .= 3
diff --git a/Projects/Sand Box 2d/Sand Box 2d.fsproj b/Projects/Sand Box 2d/Sand Box 2d.fsproj
index 9ef3f57236..97a3bfc909 100644
--- a/Projects/Sand Box 2d/Sand Box 2d.fsproj
+++ b/Projects/Sand Box 2d/Sand Box 2d.fsproj
@@ -72,9 +72,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Sand Box 2d/ToyBox.fs b/Projects/Sand Box 2d/ToyBox.fs
index bde5788d82..620a76bf4a 100644
--- a/Projects/Sand Box 2d/ToyBox.fs
+++ b/Projects/Sand Box 2d/ToyBox.fs
@@ -1022,7 +1022,7 @@ type ToyBoxDispatcher () =
[Entity.Position .= v3 255f -50f 0f
Entity.Text @= $"Avatar Gravity: {fst gravity}"
Entity.Elevation .= 1f
- Entity.FontSizing .= Some 10] world then
+ Entity.FontSizing .= Some 10.f] world then
toyBox.AvatarGravities.Map List.tail world
// clear toys button
@@ -1083,7 +1083,7 @@ type ToyBoxDispatcher () =
Mouse Left - Click button or Drag entity. Mouse Right - Cause an explosion.\n\
Mouse Scroll - Apply rotation to entity.\n\
Alt+F4 - Close game if not in Editor. Read source code for explanations!"
- Entity.FontSizing .= Some 10
+ Entity.FontSizing .= Some 10.f
Entity.TextMargin .= v2 5f 0f] world
if World.doButton "Info Close"
[Entity.LayoutOrder .= 3
diff --git a/Projects/Sand Box 3d/Sand Box 3d.fsproj b/Projects/Sand Box 3d/Sand Box 3d.fsproj
index c1be72d56d..e7f7a79e89 100644
--- a/Projects/Sand Box 3d/Sand Box 3d.fsproj
+++ b/Projects/Sand Box 3d/Sand Box 3d.fsproj
@@ -69,9 +69,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Terra Firma/Terra Firma.fsproj b/Projects/Terra Firma/Terra Firma.fsproj
index 0546698a16..63e8be7314 100644
--- a/Projects/Terra Firma/Terra Firma.fsproj
+++ b/Projects/Terra Firma/Terra Firma.fsproj
@@ -72,9 +72,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll
diff --git a/Projects/Twenty 48/GameplayDispatcher.fs b/Projects/Twenty 48/GameplayDispatcher.fs
index 2dcdb817c9..1c3aad3e68 100644
--- a/Projects/Twenty 48/GameplayDispatcher.fs
+++ b/Projects/Twenty 48/GameplayDispatcher.fs
@@ -105,7 +105,7 @@ type GameplayDispatcher () =
Entity.Text := string tile.Value
Entity.Justification == Justified (JustifyCenter, JustifyMiddle)
Entity.Font == Assets.Gui.ClearSansFont
- Entity.FontSizing := if tile.Value < 16384 then Some 12 else Some 8
+ Entity.FontSizing := if tile.Value < 16384 then Some 12.f else Some 8.f
Entity.TextColor == Color.GhostWhite
Entity.BackdropImageOpt := Some (Assets.Gameplay.TileImage tile.Value)]]
diff --git a/Projects/Twenty 48/Twenty 48.fsproj b/Projects/Twenty 48/Twenty 48.fsproj
index 43c3d9906c..f87b593893 100644
--- a/Projects/Twenty 48/Twenty 48.fsproj
+++ b/Projects/Twenty 48/Twenty 48.fsproj
@@ -71,9 +71,6 @@
..\..\Nu\Nu.Dependencies\OpenGL.NET\lib\netcoreapp2.2\OpenGL.Net.dll
-
- ..\..\Nu\Nu.Dependencies\SDL2-CS\netstandard2.0\SDL2-CS.dll
-
..\..\Nu\Nu.Dependencies\TiledSharp\lib\netstandard2.0\TiledSharp.dll