Files

310 lines
10 KiB
Lean4
Raw Permalink Normal View History

2025-09-20 16:11:27 -07:00
namespace SDL
2025-09-25 12:29:40 -07:00
-- All SDL errors are represented as strings, so we can just wrap them in a structure
structure SDLError where
toString : String
deriving Nonempty
instance : ToString SDLError := ⟨SDLError.toString⟩
abbrev SDLIO := EIO SDLError
@[inline, always_inline]
def SDLIO.toIO (x : SDLIO α) : IO α :=
2025-12-15 20:29:48 -08:00
x.adapt fun e => IO.userError s!"SDL Error: {e}"
2025-09-25 12:29:40 -07:00
instance : MonadLift SDLIO IO := ⟨SDLIO.toIO⟩
2025-12-17 03:10:58 -08:00
-- see https://wiki.libsdl.org/SDL3/SDL_InitFlags
2025-09-20 16:11:27 -07:00
def SDL_INIT_VIDEO : UInt32 := 0x00000020
2025-12-17 03:10:58 -08:00
def SDL_INIT_CAMERA: UInt32 := 0x00010000
2025-09-20 16:11:27 -07:00
def SDL_WINDOW_SHOWN : UInt32 := 0x00000004
def SDL_RENDERER_ACCELERATED : UInt32 := 0x00000002
def SDL_QUIT : UInt32 := 0x100
2026-09-08 15:23:49 -07:00
def SDL_EVENT_CAMERA_DEVICE_APPROVED : UInt32 := 0x1402
def SDL_EVENT_CAMERA_DEVICE_DENIED : UInt32 := 0x1403
2025-09-20 16:11:27 -07:00
def SDL_SCANCODE_W : UInt32 := 26
def SDL_SCANCODE_A : UInt32 := 4
def SDL_SCANCODE_S : UInt32 := 22
def SDL_SCANCODE_D : UInt32 := 7
def SDL_SCANCODE_LEFT : UInt32 := 80
def SDL_SCANCODE_RIGHT : UInt32 := 79
def SDL_SCANCODE_SPACE : UInt32 := 44
def SDL_SCANCODE_ESCAPE : UInt32 := 41
def SDL_MOUSEBUTTONDOWN : UInt32 := 0x401
def SDL_MOUSEBUTTONUP : UInt32 := 0x402
def SDL_MOUSEMOTION : UInt32 := 0x400
def SDL_BUTTON_LEFT : UInt32 := 1
def SDL_BUTTON_MIDDLE : UInt32 := 2
def SDL_BUTTON_RIGHT : UInt32 := 4
2025-12-24 01:13:19 -08:00
-- see SDL_Render.h, SDL_TextureAccess
def SDL_TEXTUREACCESS_STATIC : UInt32 := 0x0
def SDL_TEXTUREACCESS_STREAMING : UInt32 := 0x1
def SDL_TEXTUREACCESS_TARGET :UInt32 := 0x2
2025-12-25 19:44:20 -08:00
def SDL_ALPHA_OPAQUE_FLOAT: Float := 1.0
2025-12-25 04:23:29 -08:00
structure SDLRect where
x : Int32
y : Int32
w : Int32
h : Int32
deriving Repr
2025-12-26 22:56:19 -08:00
structure SDLFRect where
x : Float
y : Float
w : Float
h : Float
deriving Repr
2025-09-20 16:11:27 -07:00
@[extern "sdl_init"]
opaque init : UInt32 → IO UInt32
2025-09-23 21:21:42 -07:00
@[extern "sdl_ttf_init"]
opaque ttfInit : IO Bool
2025-09-24 15:11:41 -07:00
@[extern "sdl_mixer_init"]
opaque mixerInit : IO Bool
2025-09-20 16:11:27 -07:00
@[extern "sdl_quit"]
opaque quit : IO Unit
private opaque SDLWindow.nonemptyType : NonemptyType
def SDLWindow : Type := SDLWindow.nonemptyType.type
instance SDLWindow.instNonempty : Nonempty SDLWindow := SDLWindow.nonemptyType.property
2025-12-16 00:27:37 -08:00
2025-09-20 16:11:27 -07:00
@[extern "sdl_create_window"]
opaque createWindow : @& String → Int32 → Int32 → UInt32 → SDLIO SDLWindow
2025-09-20 16:11:27 -07:00
private opaque SDLRenderer.nonemptyType : NonemptyType
def SDLRenderer : Type := SDLRenderer.nonemptyType.type
instance SDLRenderer.instNonempty : Nonempty SDLRenderer := SDLRenderer.nonemptyType.property
2025-12-16 00:27:37 -08:00
2025-09-20 16:11:27 -07:00
@[extern "sdl_create_renderer"]
2025-09-25 12:29:40 -07:00
opaque createRenderer : @& SDLWindow → SDLIO SDLRenderer
2025-09-24 15:11:41 -07:00
2025-12-16 00:27:37 -08:00
@[extern "sdl_create_window_and_renderer"]
opaque createWindowAndRenderer : @& String -> Int32 -> Int32 -> UInt32 -> SDLIO (SDLWindow × SDLRenderer)
2025-12-16 00:27:37 -08:00
2025-09-20 16:11:27 -07:00
@[extern "sdl_set_render_draw_color"]
2025-09-25 12:29:40 -07:00
opaque setRenderDrawColor : @& SDLRenderer → UInt8 → UInt8 → UInt8 → UInt8 → SDLIO Int32
2025-09-20 16:11:27 -07:00
2025-12-25 19:44:20 -08:00
@[extern "sdl_set_render_draw_color_float"]
opaque setRenderDrawColorFloat : @& SDLRenderer → Float → Float → Float → Float → SDLIO Bool
2025-09-20 16:11:27 -07:00
@[extern "sdl_render_clear"]
2025-09-25 12:29:40 -07:00
opaque renderClear : @& SDLRenderer → SDLIO Int32
2025-09-20 16:11:27 -07:00
@[extern "sdl_render_present"]
opaque renderPresent : @& SDLRenderer → IO Unit
2025-09-20 16:11:27 -07:00
@[extern "sdl_render_fill_rect"]
2025-12-25 04:23:29 -08:00
opaque renderFillRect : @& SDLRenderer → @& SDLRect → SDLIO Int32
2025-09-20 16:11:27 -07:00
@[extern "sdl_delay"]
opaque delay : UInt32 → IO Unit
@[extern "sdl_poll_event"]
opaque pollEvent : IO UInt32
@[extern "sdl_get_ticks"]
2025-09-26 19:35:19 -07:00
opaque getTicks : IO UInt64
2025-09-20 16:11:27 -07:00
@[extern "sdl_get_key_state"]
opaque getKeyState : UInt32 → IO Bool
2025-12-24 02:36:38 -08:00
private opaque PixelFormat.nonemptyType : NonemptyType
def PixelFormat : Type := PixelFormat.nonemptyType.type
instance PixelFormat.instNonempty : Nonempty PixelFormat := PixelFormat.nonemptyType.property
-- make SDLTexture an opaque type, and make sure to tell Lean that it is nonempty
2025-09-25 11:10:17 -07:00
private opaque SDLTexture.nonemptyType : NonemptyType
def SDLTexture : Type := SDLTexture.nonemptyType.type
instance SDLTexture.instNonempty : Nonempty SDLTexture := SDLTexture.nonemptyType.property
private opaque SDLSurface.nonemptyType : NonemptyType
def SDLSurface : Type := SDLSurface.nonemptyType.type
instance SDLSurface.instNonempty : Nonempty SDLSurface := SDLSurface.nonemptyType.property
2025-12-24 02:40:26 -08:00
namespace SDLSurface
@[extern "sdl_Surface_get_format"]
opaque format : @& SDLSurface -> UInt32
2025-12-24 02:53:47 -08:00
@[extern "sdl_Surface_get_w"]
opaque w : @& SDLSurface -> Int32
@[extern "sdl_Surface_get_h"]
opaque h : @& SDLSurface -> Int32
2025-12-25 18:44:18 -08:00
@[extern "sdl_Surface_get_pitch"]
opaque pitch : @& SDLSurface -> Int32
2025-12-24 02:40:26 -08:00
end SDLSurface
@[extern "sdl_image_load"]
-- @& means "by reference"
2025-09-25 12:29:40 -07:00
opaque loadImage : (path : @& System.FilePath) → SDLIO SDLSurface
2025-12-24 01:13:19 -08:00
@[extern "sdl_create_texture"]
2025-12-24 02:42:04 -08:00
opaque createTexture (renderer: @& SDLRenderer) (pixelFormat: UInt32) (textureAccess: UInt32) (w: UInt32) (h: UInt32): SDLIO SDLTexture
2025-12-24 01:13:19 -08:00
@[extern "sdl_create_texture_from_surface"]
opaque createTextureFromSurface
2025-09-25 12:29:40 -07:00
(renderer : @& SDLRenderer) (surface : @& SDLSurface) : SDLIO SDLTexture
2025-12-25 18:44:18 -08:00
-- TODO handle SDLRect argument
@[extern "sdl_update_texture"]
opaque updateTexture (texture: @& SDLTexture) (pixels: @& ByteArray) (pitch: Int32): SDLIO Bool
-- Zero-copy optimization: updates a texture directly from an SDL_Surface's
-- pixel buffer, avoiding the intermediate ByteArray copy required by
-- updateTexture. This is not strictly faithful to the SDL_UpdateTexture C API
-- (which takes a generic void* for pixels), but is safe because the surface
-- is borrowed (@&) for the duration of the call, preventing the GC from
-- collecting the surface (and its pixel data) while the update is in progress.
@[extern "sdl_update_texture_from_surface"]
opaque updateTextureFromSurface (texture: @& SDLTexture) (surface: @& SDLSurface): SDLIO Bool
2025-12-25 18:44:18 -08:00
def loadImageTexture
(renderer : SDLRenderer) (path : System.FilePath)
2025-09-25 12:29:40 -07:00
: SDLIO SDLTexture := do
let surface <- SDL.loadImage path
createTextureFromSurface renderer surface
2025-09-20 16:11:27 -07:00
2025-09-25 13:13:20 -07:00
private opaque SDLFont.nonemptyType : NonemptyType
def SDLFont : Type := SDLFont.nonemptyType.type
instance SDLFont.instNonempty : Nonempty SDLFont := SDLFont.nonemptyType.property
2025-09-23 21:34:45 -07:00
2025-09-25 13:13:20 -07:00
@[extern "sdl_load_font"]
opaque loadFont : System.FilePath → UInt32 → SDLIO SDLFont
2025-09-24 15:21:48 -07:00
2025-09-27 19:29:22 -07:00
@[extern "sdl_render_entire_texture"]
opaque renderEntireTexture (renderer : @& SDLRenderer) (texture : @& SDLTexture) (x : Int64) (y : Int64) (w : Int64) (h : Int64) : SDLIO Int32
2025-12-25 19:44:20 -08:00
-- TODO renderTexture should work in terms of rects, replace this with renderTextureRect
2025-09-23 22:08:54 -07:00
@[extern "sdl_render_texture"]
2025-09-27 19:29:22 -07:00
opaque renderTexture (renderer : @& SDLRenderer) (texture : @& SDLTexture) (srcX : Int64) (srcY : Int64) (srcW : Int64) (srcH : Int64) (dstX : Int64) (dstY : Int64) (dstW : Int64) (dstH : Int64) : SDLIO Int32
2025-09-20 16:11:27 -07:00
2025-12-25 19:44:20 -08:00
@[extern "sdl_render_texture_rect"]
opaque renderTextureRect (renderer : @& SDLRenderer) (texture : @& SDLTexture) (sourceRect : @& SDLFRect) (destRect : @& SDLFRect): SDLIO Bool
2025-12-25 19:44:20 -08:00
@[extern "sdl_render_texture_fullscreen"]
opaque renderTextureFullscreen (renderer : @& SDLRenderer) (texture : @& SDLTexture) : SDLIO Bool
2025-09-25 13:26:43 -07:00
@[extern "sdl_get_texture_width"]
opaque getTextureWidth (texture : @& SDLTexture) : SDLIO Int64
@[extern "sdl_get_texture_height"]
opaque getTextureHeight (texture : @& SDLTexture) : SDLIO Int64
@[extern "sdl_text_to_surface"]
opaque textToSurface (renderer : @& SDLRenderer) (font : @& SDLFont) (message : @& String) (x : Int32) (y : Int32) (red : UInt8) (green : UInt8) (blue : UInt8) (alpha : UInt8) : SDLIO SDLSurface
-- Mouse support
@[extern "sdl_get_mouse_state"]
2025-09-25 12:29:40 -07:00
opaque getMouseStateRaw : SDLIO UInt64
@[extern "sdl_set_relative_mouse_mode"]
opaque setRelativeMouseMode (window : @& SDLWindow) (enabled : Bool) : SDLIO UInt32
2025-09-25 12:29:40 -07:00
def getMousePos : SDLIO (Int32 × Int32) := do
let packed ← getMouseStateRaw
let x := (packed >>> 32).toUInt32.toInt32
let y := ((packed >>> 16) &&& 0xFFFF).toUInt32.toInt32
return (x, y)
2025-09-25 12:29:40 -07:00
def isMousePressed (button : UInt32) : SDLIO Bool := do
let packed ← getMouseStateRaw
let buttons := (packed &&& 0xFFFF).toUInt32
return (buttons &&& button) != 0
2025-09-25 12:29:40 -07:00
def isLeftMousePressed : SDLIO Bool := isMousePressed SDL_BUTTON_LEFT
def isRightMousePressed : SDLIO Bool := isMousePressed SDL_BUTTON_RIGHT
def isMiddleMousePressed : SDLIO Bool := isMousePressed SDL_BUTTON_MIDDLE
2025-09-25 13:13:20 -07:00
-- SDL_mixer support
private opaque SDLMixer.nonemptyType : NonemptyType
def SDLMixer : Type := SDLMixer.nonemptyType.type
instance SDLMixer.instNonempty : Nonempty SDLMixer := SDLMixer.nonemptyType.property
@[extern "sdl_create_mixer"]
opaque createMixer : Unit → SDLIO SDLMixer
private opaque SDLTrack.nonemptyType : NonemptyType
def SDLTrack : Type := SDLTrack.nonemptyType.type
instance SDLTrack.instNonempty : Nonempty SDLTrack := SDLTrack.nonemptyType.property
@[extern "sdl_create_track"]
2025-09-25 13:26:43 -07:00
opaque createTrack : @& SDLMixer → SDLIO SDLTrack
2025-09-25 13:13:20 -07:00
private opaque SDLAudio.nonemptyType : NonemptyType
def SDLAudio : Type := SDLAudio.nonemptyType.type
instance SDLAudio.instNonempty : Nonempty SDLAudio := SDLAudio.nonemptyType.property
@[extern "sdl_load_audio"]
2025-09-25 13:26:43 -07:00
opaque loadAudio : @& SDLMixer → System.FilePath → SDLIO SDLAudio
2025-09-25 13:13:20 -07:00
@[extern "sdl_set_track_audio"]
2025-09-25 13:26:43 -07:00
opaque setTrackAudio : @& SDLTrack → @& SDLAudio → SDLIO Bool
2025-09-25 13:13:20 -07:00
@[extern "sdl_play_track"]
2025-09-25 13:26:43 -07:00
opaque playTrack : @& SDLTrack → SDLIO Bool
2025-09-25 13:13:20 -07:00
2025-12-17 03:10:58 -08:00
-- Webcam
@[extern "sdl_get_cameras"]
opaque getCameras : SDLIO (List UInt32)
2025-12-17 16:37:21 -08:00
private opaque SDLCamera.nonemptyType : NonemptyType
def SDLCamera : Type := SDLCamera.nonemptyType.type
instance SDLCamera.instNonempty : Nonempty SDLCamera := SDLCamera.nonemptyType.property
2025-12-17 16:49:39 -08:00
@[extern "sdl_open_camera"]
opaque openCamera : UInt32 -> SDLIO SDLCamera
2025-12-17 16:37:21 -08:00
2025-12-18 03:15:45 -08:00
-- cameraspec stuff
private opaque Colorspace.nonemptyType : NonemptyType
def Colorspace : Type := Colorspace.nonemptyType.type
instance Colorspace.instNonempty : Nonempty Colorspace := Colorspace.nonemptyType.property
2025-12-23 23:37:22 -08:00
opaque CameraSpec.nonemptyType : NonemptyType
2025-12-18 03:15:45 -08:00
def CameraSpec : Type := CameraSpec.nonemptyType.type
instance CameraSpec.instNonempty : Nonempty CameraSpec := CameraSpec.nonemptyType.property
2025-12-23 23:37:22 -08:00
namespace CameraSpec
@[extern "sdl_CameraSpec_get_width"]
opaque width : @& CameraSpec -> UInt32
@[extern "sdl_CameraSpec_get_height"]
opaque height : @& CameraSpec -> UInt32
@[extern "sdl_CameraSpec_get_framerate_numerator"]
opaque framerateNumerator : @& CameraSpec -> UInt32
@[extern "sdl_CameraSpec_get_framerate_denominator"]
opaque framerateDenominator : @& CameraSpec -> UInt32
end CameraSpec
2025-12-18 03:15:45 -08:00
@[extern "sdl_get_camera_format"]
opaque getCameraFormat : @& SDLCamera -> SDLIO CameraSpec
2025-12-24 00:00:53 -08:00
@[extern "sdl_acquire_camera_frame"]
opaque acquireCameraFrame : (camera : @& SDLCamera) → IO (Option SDLSurface)
2025-12-24 00:04:50 -08:00
-- TODO: support returning the timestampNS too
2025-12-24 00:00:53 -08:00
2025-12-24 00:53:17 -08:00
@[extern "sdl_release_camera_frame"]
2025-12-24 02:28:49 -08:00
opaque releaseCameraFrame (camera : @& SDLCamera) (frame: SDLSurface): IO Unit
2025-12-24 00:53:17 -08:00
2025-09-20 16:11:27 -07:00
end SDL