├── .gitignore ├── README.md ├── build.sh ├── example.mojo ├── magic.lock ├── mojoproject.toml ├── src ├── __init__.mojo ├── _sdl.mojo ├── error.mojo ├── events.mojo ├── gfx │ └── __init__.mojo ├── img │ └── __init__.mojo ├── keyboard.mojo ├── mix │ ├── __init__.mojo │ └── sound.mojo ├── mouse.mojo ├── pixel.mojo ├── primitives.mojo ├── render.mojo ├── surface.mojo ├── texture.mojo ├── time.mojo ├── ttf │ ├── __init__.mojo │ └── font.mojo ├── utils.mojo └── window.mojo └── test_cons.mojo /.gitignore: -------------------------------------------------------------------------------- 1 | assets/ 2 | *.mojopkg 3 | .magic 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sdl-bindings -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | set -euo pipefail 2 | 3 | REPO_NAME="sdl" 4 | 5 | BUILD_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 6 | REPO_ROOT=$(realpath "${BUILD_DIR}") 7 | SRC_PATH="${REPO_ROOT}/src" 8 | 9 | PACKAGE_NAME=${REPO_NAME}".mojopkg" 10 | PACKAGE_PATH=${BUILD_DIR}"/"${PACKAGE_NAME} 11 | 12 | echo "╓─── Packaging the sdl library for mojo" 13 | mojo package "${SRC_PATH}" -o "${PACKAGE_PATH}" 14 | echo Successfully created "${PACKAGE_PATH}" -------------------------------------------------------------------------------- /example.mojo: -------------------------------------------------------------------------------- 1 | from sdl import * 2 | 3 | # TODO: collision rect/point 4 | 5 | 6 | def main(): 7 | alias screen_width = 640 8 | alias screen_height = 480 9 | 10 | # mix breaks on wsl 11 | var sdl = SDL( 12 | video=True, 13 | audio=True, 14 | timer=True, 15 | events=True, 16 | gfx=True, 17 | img=True, 18 | mix=False, 19 | ttf=True, 20 | ) 21 | var window = Window(sdl, "SDL Test", screen_width, screen_height) 22 | var clock = Clock(sdl, target_fps=60) 23 | var held_keys = SIMD[DType.bool, 512]() 24 | 25 | var apple = Surface(sdl, sdl._img().load_image(('assets/apple.png').unsafe_cstr_ptr().bitcast[DType.uint8]())) 26 | var rotated_apple = apple.rotozoomed(90, 1, True) 27 | var font = ttf.Font(sdl, "assets/Beef'd.ttf", 24) 28 | var hello = font.render_solid("Hello, World!", Color(255, 0, 255, 255)) 29 | hello.convert(window.get_surface()) 30 | 31 | # var test_sound = mix.MixMusic(sdl.mix, 'assets/audio/error_003.ogg') 32 | 33 | var player_color = Color(255, 0, 0, 255) 34 | var background_color = Color(255, 255, 255, 255) 35 | var player_box = Rect(100, 100, 50, 50) 36 | var player_speed = 200 37 | 38 | var playing = True 39 | while playing: 40 | for event in sdl.event_list(): 41 | if event[].isa[QuitEvent](): 42 | playing = 0 43 | elif event[].isa[KeyDownEvent](): 44 | var e = event[][KeyDownEvent] 45 | held_keys[int(e.key)] = True 46 | # if e.key == Keys.space: 47 | # test_sound.play(1) 48 | elif event[].isa[KeyUpEvent](): 49 | var e = event[][KeyUpEvent] 50 | held_keys[int(e.key)] = False 51 | 52 | if held_keys[Keys.w]: 53 | player_box.y -= int(player_speed * clock.delta_time) 54 | if held_keys[Keys.a]: 55 | player_box.x -= int(player_speed * clock.delta_time) 56 | if held_keys[Keys.s]: 57 | player_box.y += int(player_speed * clock.delta_time) 58 | if held_keys[Keys.d]: 59 | player_box.x += int(player_speed * clock.delta_time) 60 | 61 | window.get_surface().fill(background_color) 62 | window.get_surface().fill(player_color, player_box) 63 | 64 | var green = Surface(sdl, 100, 100, Color(0, 255, 0)) 65 | window.get_surface().blit(green, None, Rect(200, 200, 30, 30)) 66 | window.get_surface().blit(rotated_apple, None, Rect(300, 300, 30, 30)) 67 | window.get_surface().blit(hello, None, Rect(300, 100, 300, 44)) 68 | 69 | window.update_surface() 70 | clock.tick() 71 | -------------------------------------------------------------------------------- /mojoproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | authors = ["helehex "] 3 | channels = ["conda-forge", "https://conda.modular.com/max"] 4 | description = "SDL bindings and wrappers for use in Mojo" 5 | name = "sdl-bindings" 6 | platforms = ["linux-64", "osx-arm64"] 7 | version = "0.1.0" 8 | 9 | [tasks] 10 | build = "mojo package src -o sdl.mojopkg" 11 | test = { cmd = "mojo example.mojo", depends-on = ["build"] } 12 | format = "mojo format -l 1000 src" 13 | 14 | [dependencies] 15 | max = "*" 16 | sdl2 = ">=2.30.7,<3" 17 | sdl2_gfx = ">=1.0.4,<2" 18 | sdl2_image = ">=2.8.2,<3" 19 | sdl2_mixer = ">=2.6.3,<3" 20 | sdl2_ttf = ">=2.22.0,<3" 21 | -------------------------------------------------------------------------------- /src/__init__.mojo: -------------------------------------------------------------------------------- 1 | """## SDL Bindings 2 | 3 | A package for SDL bindings and wrappers for use in Mojo. 4 | """ 5 | 6 | from ._sdl import SDL 7 | from .error import SDL_Error 8 | from .window import Window, WindowFlags, DisplayMode, FlashOperation 9 | from .surface import Surface 10 | from .render import Renderer, RendererFlags, RendererInfo, RendererFlip 11 | from .texture import Texture, TextureAccess, BlendMode, ScaleMode 12 | from .primitives import Color, DPoint, Point, FPoint, DRect, Rect, FRect, Vertex 13 | from .pixel import Pixels, Palette, SurfacePixelFormat, TexturePixelFormat 14 | from .events import Event, QuitEvent, WindowEvent, KeyDownEvent, KeyUpEvent 15 | from .keyboard import Keyboard, Keys, KeyCode 16 | from .mouse import Mouse 17 | from .time import Clock 18 | 19 | # from .opengl import gl_create_context, gl_delete_context 20 | 21 | 22 | # TODO: Pointer indirection and overall layout can be fixed once we have either 23 | # top level vars which work from a .mojopkg, or builtin c interop. 24 | 25 | 26 | alias error_level = 2 27 | """Define the amount of error handling you want. 28 | 29 | `0`: No error handling 30 | `1`: Fast error handling 31 | `2`: Verbose error handling 32 | """ 33 | 34 | 35 | alias Ptr = UnsafePointer 36 | alias UIntC = UInt32 37 | alias IntC = Int32 38 | alias CharC = UInt8 39 | alias BoolC = Bool 40 | -------------------------------------------------------------------------------- /src/_sdl.mojo: -------------------------------------------------------------------------------- 1 | """Defines an SDL struct.""" 2 | 3 | from sys import DLHandle, os_is_macos, os_is_linux 4 | from pathlib import Path 5 | from collections import Optional 6 | from .window import _Window, _GLContext 7 | from .surface import _Surface 8 | from .render import _Renderer 9 | from .texture import _Texture 10 | from .events import _Event 11 | from .gfx import _GFX 12 | from .img import _IMG 13 | from .mix import _MIX 14 | from .ttf import _TTF 15 | from builtin.constrained import constrained 16 | 17 | 18 | trait AddonLib: 19 | fn __init__(inout self, error: SDL_Error): 20 | ... 21 | 22 | fn quit(self): 23 | ... 24 | 25 | 26 | struct OptionalLib[LibType: AddonLib, error_msg: StringLiteral]: 27 | var _lib: LibType 28 | var _enabled: Bool 29 | 30 | fn __init__(inout self, none: None): 31 | self._lib = utils._uninit[LibType]() 32 | self._enabled = False 33 | 34 | fn __init__(inout self, error: SDL_Error): 35 | self._lib = LibType(error) 36 | self._enabled = True 37 | 38 | fn __bool__(self) -> Bool: 39 | return self._enabled 40 | 41 | fn __call__(self) raises -> ref [__lifetime_of(self)] LibType: 42 | """Unwrap the optional if possible, otherwise error.""" 43 | 44 | @parameter 45 | if error.error_level > 0: 46 | if not self: 47 | raise error_msg 48 | return self._lib 49 | 50 | fn __del__(owned self): 51 | if self._enabled: 52 | self._lib.quit() 53 | 54 | 55 | struct SDL: 56 | """Safe wrapper around sdl bindings.""" 57 | 58 | # raw bindings 59 | var _sdl: _SDL 60 | 61 | # libraries 62 | var _gfx: OptionalLib[_GFX, "sdl_gfx is not enabled"] 63 | var _img: OptionalLib[_IMG, "sdl_img is not enabled"] 64 | var _mix: OptionalLib[_MIX, "sdl_mix is not enabled"] 65 | var _ttf: OptionalLib[_TTF, "sdl_ttf is not enabled"] 66 | 67 | fn __init__( 68 | inout self, 69 | timer: Bool = False, 70 | audio: Bool = False, 71 | video: Bool = False, 72 | joystick: Bool = False, 73 | haptic: Bool = False, 74 | gamecontroller: Bool = False, 75 | events: Bool = False, 76 | everything: Bool = False, 77 | gfx: Bool = False, 78 | img: Bool = False, 79 | mix: Bool = False, 80 | ttf: Bool = False, 81 | ) raises: 82 | """This initializes SDL bindings, and SDL itself. 83 | 84 | If you want to only initialize the bindings, use `_SDL`. 85 | """ 86 | self._sdl = _SDL() 87 | self._gfx = None 88 | self._img = None 89 | self._mix = None 90 | self._ttf = None 91 | 92 | # x--- set window flags 93 | var flags: UInt32 = 0 94 | flags |= 0x00000001 * timer 95 | flags |= 0x00000010 * audio 96 | flags |= 0x00000020 * video 97 | flags |= 0x00000200 * joystick 98 | flags |= 0x00001000 * haptic 99 | flags |= 0x00002000 * gamecontroller 100 | flags |= 0x00004000 * events 101 | flags |= 0x0000FFFF * everything 102 | # this flag is ignored 103 | # flags |= 0x00100000 * no_parachute 104 | 105 | # x--- initialize sdl 106 | self._sdl.init(flags) 107 | 108 | if gfx: 109 | self.init_gfx() 110 | if img: 111 | self.init_img() 112 | if mix: 113 | self.init_mix() 114 | if ttf: 115 | self.init_ttf() 116 | 117 | fn init_gfx(inout self) raises: 118 | self._gfx = self._sdl.error 119 | 120 | fn init_img(inout self, jpeg: Bool = True, png: Bool = True, tif: Bool = False, webp: Bool = False) raises: 121 | self._img = self._sdl.error 122 | var flags: Int32 = 0 123 | flags |= 0x00000001 * jpeg 124 | flags |= 0x00000002 * png 125 | flags |= 0x00000004 * tif 126 | flags |= 0x00000008 * webp 127 | self._img._lib.init(flags) 128 | 129 | fn init_mix(inout self, frequency: Int32 = 44100, format: UInt16 = mix.sound.AUDIO_S16LSB, channels: Int32 = 2, chunksize: Int32 = 2048) raises: 130 | self._mix = self._sdl.error 131 | self._mix._lib.init(frequency, format, channels, chunksize) 132 | 133 | fn init_ttf(inout self) raises: 134 | self._ttf = self._sdl.error 135 | self._ttf._lib.init() 136 | 137 | fn __del__(owned self): 138 | self._sdl.quit() 139 | 140 | fn next_event(self) -> Optional[Event]: 141 | var event_ptr = Ptr[_Event].alloc(1) 142 | var result = Optional[Event](None) 143 | if self._sdl.poll_event(event_ptr) != 0: 144 | result = _Event.to_event(event_ptr) 145 | event_ptr.free() 146 | return result 147 | 148 | fn event_list(self) -> List[Event]: 149 | var l = List[Event]() 150 | var event_ptr = Ptr[_Event].alloc(1) 151 | while self._sdl.poll_event(event_ptr) != 0: 152 | l.append(_Event.to_event(event_ptr)) 153 | event_ptr.free() 154 | return l 155 | 156 | 157 | # TODO: This is so we dont have to carry around aliases to function types, 158 | # since __type_of currently doesnt work for this. Maybe this could 159 | # be taken further to abstract away the secondary functions as well, 160 | # but using variadic packs here doesnt work yet, so i'm not sure yet. 161 | @register_passable("trivial") 162 | struct SDL_Fn[name: String, T: AnyTrivialRegType]: 163 | var call: T 164 | 165 | @always_inline("nodebug") 166 | fn __init__(inout self, _handle: DLHandle): 167 | self.call = _handle.get_function[T](name) 168 | 169 | 170 | struct _SDL: 171 | """Raw unsafe SDL Bindings.""" 172 | 173 | # sdl handle 174 | var _handle: DLHandle 175 | 176 | # sdl error 177 | var error: SDL_Error 178 | 179 | # sdl bindings 180 | var _init: SDL_Fn["SDL_Init", fn (UInt32) -> IntC] 181 | var _quit: SDL_Fn["SDL_Quit", fn () -> NoneType] 182 | var _init_sub_system: SDL_Fn["SDL_InitSubSystem", fn (UInt32) -> IntC] 183 | var _quit_sub_system: SDL_Fn["SDL_QuitSubSystem", fn (UInt32) -> NoneType] 184 | 185 | # keyboard bindings 186 | var _get_keyboard_state: SDL_Fn["SDL_GetKeyboardState", fn (Ptr[IntC]) -> Ptr[UInt8]] 187 | 188 | # mouse bindings 189 | var _get_mouse_state: SDL_Fn["SDL_GetMouseState", fn (Ptr[IntC], Ptr[IntC]) -> UInt32] 190 | 191 | # event bindings 192 | var _poll_event: SDL_Fn["SDL_PollEvent", fn (Ptr[_Event]) -> IntC] 193 | 194 | # timer 195 | var _get_ticks: SDL_Fn["SDL_GetTicks", fn () -> UInt32] 196 | var _delay: SDL_Fn["SDL_Delay", fn (UInt32) -> NoneType] 197 | 198 | # window bindings 199 | var _create_window: SDL_Fn["SDL_CreateWindow", fn (Ptr[CharC], IntC, IntC, IntC, IntC, UInt32) -> Ptr[_Window]] 200 | var _create_shaped_window: SDL_Fn["SDL_CreateShapedWindow", fn (Ptr[CharC], UIntC, UIntC, UIntC, UIntC, UInt32) -> Ptr[_Window]] 201 | var _create_window_and_renderer: SDL_Fn["SDL_CreateWindowAndRenderer", fn (IntC, IntC, UInt32, Ptr[_Window], Ptr[_Renderer]) -> IntC] 202 | var _create_window_from: SDL_Fn["SDL_CreateWindowFrom", fn (Ptr[NoneType]) -> Ptr[_Window]] 203 | var _destroy_window_surface: SDL_Fn["SDL_DestroyWindowSurface", fn (Ptr[_Window]) -> IntC] 204 | var _destroy_window: SDL_Fn["SDL_DestroyWindow", fn (Ptr[_Window]) -> NoneType] 205 | var _is_shaped_window: SDL_Fn["SDL_IsShapedWindow", fn (Ptr[_Window]) -> BoolC] 206 | var _has_window_surface: SDL_Fn["SDL_HasWindowSurface", fn (Ptr[_Window]) -> BoolC] 207 | var _get_grabbed_window: SDL_Fn["SDL_GetGrabbedWindow", fn () -> Ptr[_Window]] 208 | # SDL_GetShapedWindowMode 209 | var _get_window_border_size: SDL_Fn[ 210 | "SDL_GetWindowBordersSize", 211 | fn (Ptr[_Window], Ptr[IntC], Ptr[IntC], Ptr[IntC], Ptr[IntC]) -> IntC, 212 | ] 213 | var _get_window_brightness: SDL_Fn["SDL_GetWindowBrightness", fn (Ptr[_Window]) -> Float32] 214 | var _get_window_gamma_ramp: SDL_Fn["SDL_GetWindowGammaRamp", fn (Ptr[_Window], Ptr[UInt16], Ptr[UInt16], Ptr[UInt16]) -> IntC] 215 | var _get_window_opacity: SDL_Fn["SDL_GetWindowOpacity", fn (Ptr[_Window], Ptr[Float32]) -> IntC] 216 | var _get_window_data: SDL_Fn["SDL_GetWindowData", fn (Ptr[_Window], Ptr[CharC]) -> Ptr[NoneType]] 217 | var _get_window_display_index: SDL_Fn["SDL_GetWindowDisplayIndex", fn (Ptr[_Window]) -> IntC] 218 | var _get_window_display_mode: SDL_Fn["SDL_GetWindowDisplayMode", fn (Ptr[_Window], Ptr[DisplayMode]) -> IntC] 219 | var _get_window_flags: SDL_Fn["SDL_GetWindowFlags", fn (Ptr[_Window]) -> UInt32] 220 | var _get_window_from_id: SDL_Fn["SDL_GetWindowFromID", fn (UInt32) -> Ptr[_Window]] 221 | var _get_window_grab: SDL_Fn["SDL_GetWindowGrab", fn (Ptr[_Window]) -> BoolC] 222 | # SDL_GetWindowICCProfile 223 | var _get_window_id: SDL_Fn["SDL_GetWindowID", fn (Ptr[_Window]) -> UInt32] 224 | var _get_window_keyboard_grab: SDL_Fn["SDL_GetWindowKeyboardGrab", fn (Ptr[_Window]) -> BoolC] 225 | var _get_window_mouse_grab: SDL_Fn["SDL_GetWindowMouseGrab", fn (Ptr[_Window]) -> BoolC] 226 | var _get_window_maximum_size: SDL_Fn[ 227 | "SDL_GetWindowMaximumSize", 228 | fn (Ptr[_Window], Ptr[IntC], Ptr[IntC]) -> NoneType, 229 | ] 230 | var _get_window_minimum_size: SDL_Fn[ 231 | "SDL_GetWindowMinimumSize", 232 | fn (Ptr[_Window], Ptr[IntC], Ptr[IntC]) -> NoneType, 233 | ] 234 | var _get_window_mouse_rect: SDL_Fn["SDL_GetWindowMouseRect", fn (Ptr[_Window]) -> Ptr[Rect]] 235 | var _get_window_pixel_format: SDL_Fn["SDL_GetWindowPixelFormat", fn (Ptr[_Window]) -> UInt32] 236 | var _get_window_title: SDL_Fn["SDL_GetWindowTitle", fn (Ptr[_Window]) -> Ptr[CharC]] 237 | var _get_window_position: SDL_Fn[ 238 | "SDL_GetWindowPosition", 239 | fn (Ptr[_Window], Ptr[IntC], Ptr[IntC]) -> NoneType, 240 | ] 241 | var _get_window_size: SDL_Fn["SDL_GetWindowSize", fn (Ptr[_Window], Ptr[IntC], Ptr[IntC]) -> NoneType] 242 | var _get_window_size_in_pixels: SDL_Fn[ 243 | "SDL_GetWindowSizeInPixels", 244 | fn (Ptr[_Window], Ptr[IntC], Ptr[IntC]) -> NoneType, 245 | ] 246 | # # SDL_GetWindowWMInfo 247 | var _get_window_surface: SDL_Fn["SDL_GetWindowSurface", fn (Ptr[_Window]) -> Ptr[_Surface]] 248 | var _get_renderer: SDL_Fn["SDL_GetRenderer", fn (Ptr[_Window]) -> Ptr[_Renderer]] 249 | var _set_window_always_on_top: SDL_Fn["SDL_SetWindowAlwaysOnTop", fn (Ptr[_Window], BoolC) -> NoneType] 250 | var _set_window_bordered: SDL_Fn["SDL_SetWindowBordered", fn (Ptr[_Window], BoolC) -> NoneType] 251 | var _set_window_brightness: SDL_Fn["SDL_SetWindowBrightness", fn (Ptr[_Window], Float32) -> IntC] 252 | var _set_window_gamma_ramp: SDL_Fn[ 253 | "SDL_SetWindowGammaRamp", 254 | fn (Ptr[_Window], Ptr[UInt16], Ptr[UInt16], Ptr[UInt16]) -> IntC, 255 | ] 256 | var _set_window_opacity: SDL_Fn["SDL_SetWindowOpacity", fn (Ptr[_Window], Float32) -> IntC] 257 | var _set_window_data: SDL_Fn[ 258 | "SDL_SetWindowData", 259 | fn (Ptr[_Window], Ptr[CharC], Ptr[NoneType]) -> Ptr[NoneType], 260 | ] 261 | var _set_window_display_mode: SDL_Fn["SDL_SetWindowDisplayMode", fn (Ptr[_Window], Ptr[DisplayMode]) -> IntC] 262 | var _set_window_fullscreen: SDL_Fn["SDL_SetWindowFullscreen", fn (Ptr[_Window], UInt32) -> IntC] 263 | var _set_window_grab: SDL_Fn["SDL_SetWindowGrab", fn (Ptr[_Window], BoolC) -> NoneType] 264 | # SDL_SetWindowHitTest 265 | var _set_window_icon: SDL_Fn["SDL_SetWindowIcon", fn (Ptr[_Window], Ptr[_Surface]) -> NoneType] 266 | var _set_window_input_focus: SDL_Fn["SDL_SetWindowInputFocus", fn (Ptr[_Window]) -> IntC] 267 | var _set_window_keyboard_grab: SDL_Fn["SDL_SetWindowKeyboardGrab", fn (Ptr[_Window], BoolC) -> NoneType] 268 | var _set_window_mouse_grab: SDL_Fn["SDL_SetWindowMouseGrab", fn (Ptr[_Window], BoolC) -> NoneType] 269 | var _set_window_maximum_size: SDL_Fn["SDL_SetWindowMaximumSize", fn (Ptr[_Window], IntC, IntC) -> NoneType] 270 | var _set_window_minimum_size: SDL_Fn["SDL_SetWindowMinimumSize", fn (Ptr[_Window], IntC, IntC) -> NoneType] 271 | var _set_window_modal_for: SDL_Fn["SDL_SetWindowModalFor", fn (Ptr[_Window], Ptr[_Window]) -> IntC] 272 | var _set_window_mouse_rect: SDL_Fn["SDL_SetWindowMouseRect", fn (Ptr[_Window], Ptr[Rect]) -> IntC] 273 | var _set_window_position: SDL_Fn["SDL_SetWindowPosition", fn (Ptr[_Window], IntC, IntC) -> NoneType] 274 | var _set_window_resizable: SDL_Fn["SDL_SetWindowResizable", fn (Ptr[_Window], BoolC) -> NoneType] 275 | var _set_window_size: SDL_Fn["SDL_SetWindowSize", fn (Ptr[_Window], IntC, IntC) -> NoneType] 276 | # SDL_SetWindowsMessageHook 277 | # SDL_SetWindowShape 278 | var _set_window_title: SDL_Fn["SDL_SetWindowTitle", fn (Ptr[_Window], Ptr[CharC]) -> NoneType] 279 | # # SDL_GL_GetCurrentWindow 280 | # # SDL_GL_SwapWindow 281 | var _update_window_surface: SDL_Fn["SDL_UpdateWindowSurface", fn (Ptr[_Window]) -> IntC] 282 | var _update_window_surface_rects: SDL_Fn[ 283 | "SDL_UpdateWindowSurfaceRects", 284 | fn (Ptr[_Window], Ptr[Rect], IntC) -> IntC, 285 | ] 286 | var _show_window: SDL_Fn["SDL_ShowWindow", fn (Ptr[_Window]) -> NoneType] 287 | var _hide_window: SDL_Fn["SDL_HideWindow", fn (Ptr[_Window]) -> NoneType] 288 | var _maximize_window: SDL_Fn["SDL_MaximizeWindow", fn (Ptr[_Window]) -> NoneType] 289 | var _minimize_window: SDL_Fn["SDL_MinimizeWindow", fn (Ptr[_Window]) -> NoneType] 290 | var _flash_window: SDL_Fn["SDL_FlashWindow", fn (Ptr[_Window], FlashOperation) -> IntC] 291 | var _raise_window: SDL_Fn["SDL_RaiseWindow", fn (Ptr[_Window]) -> NoneType] 292 | var _restore_window: SDL_Fn["SDL_RestoreWindow", fn (Ptr[_Window]) -> NoneType] 293 | var _warp_mouse_in_window: SDL_Fn["SDL_WarpMouseInWindow", fn (Ptr[_Window], IntC, IntC) -> NoneType] 294 | 295 | # surface bindings 296 | var _create_rgb_surface: SDL_Fn["SDL_CreateRGBSurface", fn (UInt32, IntC, IntC, IntC, UInt32, UInt32, UInt32, UInt32) -> Ptr[_Surface]] 297 | var _create_rgb_surface_from: SDL_Fn["SDL_CreateRGBSurfaceFrom", fn (Ptr[NoneType], IntC, IntC, IntC, IntC, UInt32, UInt32, UInt32, UInt32) -> Ptr[_Surface]] 298 | var _create_rgb_surface_with_format: SDL_Fn["SDL_CreateRGBSurfaceWithFormat", fn (UInt32, IntC, IntC, IntC, UInt32) -> Ptr[_Surface]] 299 | var _create_rgb_surface_with_format_from: SDL_Fn["SDL_CreateRGBSurfaceWithFormatFrom", fn (Ptr[NoneType], IntC, IntC, IntC, IntC, UInt32) -> Ptr[_Surface]] 300 | var _free_surface: SDL_Fn["SDL_FreeSurface", fn (Ptr[_Surface]) -> None] 301 | var _convert_surface: SDL_Fn[ 302 | "SDL_ConvertSurface", 303 | fn (Ptr[_Surface], Ptr[SurfacePixelFormat], UInt32) -> Ptr[_Surface], 304 | ] 305 | var _convert_surface_format: SDL_Fn[ 306 | "SDL_ConvertSurfaceFormat", 307 | fn (Ptr[_Surface], UInt32, UInt32) -> Ptr[_Surface], 308 | ] 309 | var _has_surface_rle: SDL_Fn["SDL_HasSurfaceRLE", fn (Ptr[_Surface]) -> BoolC] 310 | var _get_surface_color_mod: SDL_Fn[ 311 | "SDL_GetSurfaceColorMod", 312 | fn (Ptr[_Surface], Ptr[UInt8], Ptr[UInt8], Ptr[UInt8]) -> IntC, 313 | ] 314 | var _get_surface_alpha_mod: SDL_Fn["SDL_GetSurfaceAlphaMod", fn (Ptr[_Surface], Ptr[UInt8]) -> IntC] 315 | var _get_surface_blend_mode: SDL_Fn["SDL_GetSurfaceBlendMode", fn (Ptr[_Surface], Ptr[BlendMode]) -> IntC] 316 | var _set_surface_color_mod: SDL_Fn["SDL_SetSurfaceColorMod", fn (Ptr[_Surface], UInt8, UInt8, UInt8) -> IntC] 317 | var _set_surface_alpha_mod: SDL_Fn["SDL_SetSurfaceAlphaMod", fn (Ptr[_Surface], UInt8) -> IntC] 318 | var _set_surface_blend_mode: SDL_Fn["SDL_SetSurfaceBlendMode", fn (Ptr[_Surface], BlendMode) -> IntC] 319 | var _set_surface_palette: SDL_Fn["SDL_SetSurfacePalette", fn (Ptr[_Surface], Ptr[Palette]) -> IntC] 320 | var _set_surface_rle: SDL_Fn["SDL_SetSurfaceRLE", fn (Ptr[_Surface], IntC) -> IntC] 321 | var _fill_rect: SDL_Fn["SDL_FillRect", fn (Ptr[_Surface], Ptr[Rect], UInt32) -> IntC] 322 | var _fill_rects: SDL_Fn["SDL_FillRects", fn (Ptr[_Surface], Ptr[Rect], IntC, UInt32) -> IntC] 323 | var _lock_surface: SDL_Fn["SDL_LockSurface", fn (Ptr[_Surface]) -> IntC] 324 | var _unlock_surface: SDL_Fn["SDL_UnlockSurface", fn (Ptr[_Surface]) -> NoneType] 325 | var _lower_blit: SDL_Fn[ 326 | "SDL_LowerBlit", 327 | fn (Ptr[_Surface], Ptr[Rect], Ptr[_Surface], Ptr[Rect]) -> IntC, 328 | ] 329 | var _lower_blit_scaled: SDL_Fn[ 330 | "SDL_LowerBlitScaled", 331 | fn (Ptr[_Surface], Ptr[Rect], Ptr[_Surface], Ptr[Rect]) -> IntC, 332 | ] 333 | var _upper_blit: SDL_Fn[ 334 | "SDL_UpperBlit", 335 | fn (Ptr[_Surface], Ptr[Rect], Ptr[_Surface], Ptr[Rect]) -> IntC, 336 | ] 337 | var _upper_blit_scaled: SDL_Fn[ 338 | "SDL_UpperBlitScaled", 339 | fn (Ptr[_Surface], Ptr[Rect], Ptr[_Surface], Ptr[Rect]) -> IntC, 340 | ] 341 | 342 | # renderer bindings 343 | var _create_renderer: SDL_Fn["SDL_CreateRenderer", fn (Ptr[_Window], IntC, UInt32) -> Ptr[_Renderer]] 344 | var _create_software_renderer: SDL_Fn["SDL_CreateSoftwareRenderer", fn (Ptr[_Surface]) -> Ptr[_Renderer]] 345 | var _destroy_renderer: SDL_Fn["SDL_DestroyRenderer", fn (Ptr[_Renderer]) -> None] 346 | var _render_clear: SDL_Fn["SDL_RenderClear", fn (Ptr[_Renderer]) -> IntC] 347 | var _render_present: SDL_Fn["SDL_RenderPresent", fn (Ptr[_Renderer]) -> None] 348 | var _render_get_window: SDL_Fn["SDL_RenderGetWindow", fn (Ptr[_Renderer]) -> Ptr[_Window]] 349 | var _set_render_target: SDL_Fn["SDL_SetRenderTarget", fn (Ptr[_Renderer], Ptr[_Texture]) -> IntC] 350 | var _set_render_draw_color: SDL_Fn[ 351 | "SDL_SetRenderDrawColor", 352 | fn (Ptr[_Renderer], UInt8, UInt8, UInt8, UInt8) -> IntC, 353 | ] 354 | var _set_render_draw_blend_mode: SDL_Fn["SDL_SetRenderDrawBlendMode", fn (Ptr[_Renderer], BlendMode) -> IntC] 355 | var _get_render_draw_color: SDL_Fn["SDL_GetRenderDrawColor", fn (Ptr[_Renderer], Ptr[UInt8], Ptr[UInt8], Ptr[UInt8], Ptr[UInt8]) -> IntC] 356 | var _get_render_draw_blend_mode: SDL_Fn["SDL_GetRenderDrawBlendMode", fn (Ptr[_Renderer], Ptr[BlendMode]) -> IntC] 357 | var _get_renderer_info: SDL_Fn["SDL_GetRendererInfo", fn (Ptr[_Renderer], Ptr[RendererInfo]) -> IntC] 358 | var _get_renderer_output_size: SDL_Fn[ 359 | "SDL_GetRendererOutputSize", 360 | fn (Ptr[_Renderer], Ptr[IntC], Ptr[IntC]) -> IntC, 361 | ] 362 | var _get_render_target: SDL_Fn["SDL_GetRenderTarget", fn (Ptr[_Renderer]) -> Ptr[_Texture]] 363 | var _get_num_render_drivers: SDL_Fn["SDL_GetNumRenderDrivers", fn () -> IntC] 364 | var _get_render_driver_info: SDL_Fn["SDL_GetRenderDriverInfo", fn (IntC, Ptr[RendererInfo]) -> IntC] 365 | var _render_copy: SDL_Fn[ 366 | "SDL_RenderCopy", 367 | fn (Ptr[_Renderer], Ptr[_Texture], Ptr[Rect], Ptr[Rect]) -> IntC, 368 | ] 369 | var _render_copy_f: SDL_Fn[ 370 | "SDL_RenderCopyF", 371 | fn (Ptr[_Renderer], Ptr[_Texture], Ptr[Rect], Ptr[FRect]) -> IntC, 372 | ] 373 | var _render_copy_ex: SDL_Fn[ 374 | "SDL_RenderCopyEx", 375 | fn ( 376 | Ptr[_Renderer], 377 | Ptr[_Texture], 378 | Ptr[Rect], 379 | Ptr[Rect], 380 | Float64, 381 | Ptr[Point], 382 | RendererFlip, 383 | ) -> IntC, 384 | ] 385 | var _render_copy_exf: SDL_Fn[ 386 | "SDL_RenderCopyExF", 387 | fn ( 388 | Ptr[_Renderer], 389 | Ptr[_Texture], 390 | Ptr[Rect], 391 | Ptr[FRect], 392 | Float64, 393 | Ptr[FPoint], 394 | RendererFlip, 395 | ) -> IntC, 396 | ] 397 | var _render_draw_line: SDL_Fn[ 398 | "SDL_RenderDrawLine", 399 | fn (Ptr[_Renderer], IntC, IntC, IntC, IntC) -> IntC, 400 | ] 401 | var _render_draw_line_f: SDL_Fn[ 402 | "SDL_RenderDrawLineF", 403 | fn (Ptr[_Renderer], Float32, Float32, Float32, Float32) -> IntC, 404 | ] 405 | var _render_draw_lines: SDL_Fn["SDL_RenderDrawLines", fn (Ptr[_Renderer], Ptr[Point], IntC) -> IntC] 406 | var _render_draw_lines_f: SDL_Fn["SDL_RenderDrawLinesF", fn (Ptr[_Renderer], Ptr[FPoint], IntC) -> IntC] 407 | var _render_draw_point: SDL_Fn["SDL_RenderDrawPoint", fn (Ptr[_Renderer], IntC, IntC) -> IntC] 408 | var _render_draw_point_f: SDL_Fn["SDL_RenderDrawPointF", fn (Ptr[_Renderer], Float32, Float32) -> IntC] 409 | var _render_draw_points: SDL_Fn["SDL_RenderDrawPoints", fn (Ptr[_Renderer], Ptr[Point], IntC) -> IntC] 410 | var _render_draw_points_f: SDL_Fn["SDL_RenderDrawPointsF", fn (Ptr[_Renderer], Ptr[FPoint], IntC) -> IntC] 411 | var _render_draw_rect: SDL_Fn["SDL_RenderDrawRect", fn (Ptr[_Renderer], Rect) -> IntC] 412 | var _render_draw_rect_f: SDL_Fn["SDL_RenderDrawRectF", fn (Ptr[_Renderer], FRect) -> IntC] 413 | var _render_draw_rects: SDL_Fn["SDL_RenderDrawRects", fn (Ptr[_Renderer], Ptr[Rect], IntC) -> IntC] 414 | var _render_draw_rects_f: SDL_Fn["SDL_RenderDrawRectsF", fn (Ptr[_Renderer], Ptr[FRect], IntC) -> IntC] 415 | var _render_fill_rect: SDL_Fn["SDL_RenderFillRect", fn (Ptr[_Renderer], Rect) -> IntC] 416 | var _render_fill_rect_f: SDL_Fn["SDL_RenderFillRectF", fn (Ptr[_Renderer], FRect) -> IntC] 417 | var _render_fill_rects: SDL_Fn["SDL_RenderFillRects", fn (Ptr[_Renderer], Ptr[Rect], IntC) -> IntC] 418 | var _render_fill_rects_f: SDL_Fn["SDL_RenderFillRectsF", fn (Ptr[_Renderer], Ptr[FRect], IntC) -> IntC] 419 | var _render_flush: SDL_Fn["SDL_RenderFlush", fn (Ptr[_Renderer]) -> IntC] 420 | var _render_geometry: SDL_Fn[ 421 | "SDL_RenderGeometry", 422 | fn (Ptr[_Renderer], Ptr[_Texture], Ptr[Vertex], IntC, Ptr[IntC], IntC) -> IntC, 423 | ] 424 | var _render_geometry_raw: SDL_Fn[ 425 | "SDL_RenderGeometryRaw", 426 | fn ( 427 | Ptr[_Renderer], 428 | Ptr[_Texture], 429 | Ptr[Float32], 430 | IntC, 431 | Ptr[Color], 432 | IntC, 433 | Ptr[Float32], 434 | IntC, 435 | IntC, 436 | Ptr[NoneType], 437 | IntC, 438 | IntC, 439 | ) -> IntC, 440 | ] 441 | var _render_get_clip_rect: SDL_Fn["SDL_RenderGetClipRect", fn (Ptr[_Renderer], Ptr[Rect]) -> NoneType] 442 | var _render_get_integer_scale: SDL_Fn["SDL_RenderGetIntegerScale", fn (Ptr[_Renderer]) -> BoolC] 443 | var _render_get_logical_size: SDL_Fn[ 444 | "SDL_RenderGetLogicalSize", 445 | fn (Ptr[_Renderer], Ptr[IntC], Ptr[IntC]) -> NoneType, 446 | ] 447 | var _render_get_metal_command_encoder: SDL_Fn["SDL_RenderGetMetalCommandEncoder", fn (Ptr[_Renderer]) -> Ptr[NoneType]] 448 | var _render_get_metal_layer: SDL_Fn["SDL_RenderGetMetalLayer", fn (Ptr[_Renderer]) -> Ptr[NoneType]] 449 | var _render_get_scale: SDL_Fn[ 450 | "SDL_RenderGetScale", 451 | fn (Ptr[_Renderer], Ptr[IntC], Ptr[IntC]) -> NoneType, 452 | ] 453 | var _render_get_viewport: SDL_Fn["SDL_RenderGetViewport", fn (Ptr[_Renderer], Ptr[Rect]) -> NoneType] 454 | var _render_is_clip_enabled: SDL_Fn["SDL_RenderIsClipEnabled", fn (Ptr[_Renderer]) -> BoolC] 455 | var _render_logical_to_window: SDL_Fn[ 456 | "SDL_RenderLogicalToWindow", 457 | fn (Ptr[_Renderer], Float32, Float32, Ptr[IntC], Ptr[IntC]) -> NoneType, 458 | ] 459 | var _render_read_pixels: SDL_Fn[ 460 | "SDL_RenderReadPixels", 461 | fn (Ptr[_Renderer], Ptr[Rect], UInt32, Ptr[NoneType], IntC) -> IntC, 462 | ] 463 | var _render_set_clip_rect: SDL_Fn["SDL_RenderSetClipRect", fn (Ptr[_Renderer], Ptr[Rect]) -> IntC] 464 | var _render_set_integer_scale: SDL_Fn["SDL_RenderSetIntegerScale", fn (Ptr[_Renderer], BoolC) -> IntC] 465 | var _render_set_logical_size: SDL_Fn["SDL_RenderSetLogicalSize", fn (Ptr[_Renderer], IntC, IntC) -> IntC] 466 | var _render_set_scale: SDL_Fn["SDL_RenderSetScale", fn (Ptr[_Renderer], Float32, Float32) -> IntC] 467 | var _render_set_viewport: SDL_Fn["SDL_RenderSetViewport", fn (Ptr[_Renderer], Ptr[Rect]) -> IntC] 468 | var _render_set_vsync: SDL_Fn["SDL_RenderSetVSync", fn (Ptr[_Renderer], IntC) -> IntC] 469 | var _render_target_supported: SDL_Fn["SDL_RenderTargetSupported", fn (Ptr[_Renderer]) -> BoolC] 470 | var _render_window_to_logical: SDL_Fn[ 471 | "SDL_RenderWindowToLogical", 472 | fn (Ptr[_Renderer], IntC, IntC, Ptr[Float32], Ptr[Float32]) -> NoneType, 473 | ] 474 | 475 | # texture bindings 476 | var _create_texture: SDL_Fn[ 477 | "SDL_CreateTexture", 478 | fn (Ptr[_Renderer], UInt32, IntC, IntC, IntC) -> Ptr[_Texture], 479 | ] 480 | var _create_texture_from_surface: SDL_Fn[ 481 | "SDL_CreateTextureFromSurface", 482 | fn (Ptr[_Renderer], Ptr[_Surface]) -> Ptr[_Texture], 483 | ] 484 | var _destroy_texture: SDL_Fn["SDL_DestroyTexture", fn (Ptr[_Texture]) -> NoneType] 485 | var _gl_bind_texture: SDL_Fn[ 486 | "SDL_GL_BindTexture", 487 | fn (Ptr[_Texture], Ptr[Float32], Ptr[Float32]) -> IntC, 488 | ] 489 | var _gl_unbind_texture: SDL_Fn["SDL_GL_UnbindTexture", fn (Ptr[_Texture]) -> IntC] 490 | var _lock_texture: SDL_Fn[ 491 | "SDL_LockTexture", 492 | fn (Ptr[_Texture], Ptr[Rect], Ptr[Ptr[NoneType]], Ptr[IntC]) -> IntC, 493 | ] 494 | var _lock_texture_to_surface: SDL_Fn[ 495 | "SDL_LockTextureToSurface", 496 | fn (Ptr[_Texture], Ptr[Rect], Ptr[Ptr[_Surface]]) -> IntC, 497 | ] 498 | var _unlock_texture: SDL_Fn["SDL_UnlockTexture", fn (Ptr[_Texture]) -> NoneType] 499 | var _query_texture: SDL_Fn[ 500 | "SDL_QueryTexture", 501 | fn (Ptr[_Texture], Ptr[UInt32], Ptr[IntC], Ptr[IntC], Ptr[IntC]) -> IntC, 502 | ] 503 | var _get_texture_color_mod: SDL_Fn[ 504 | "SDL_GetTextureColorMod", 505 | fn (Ptr[_Texture], Ptr[UInt8], Ptr[UInt8], Ptr[UInt8]) -> IntC, 506 | ] 507 | var _get_texture_alpha_mod: SDL_Fn["SDL_GetTextureAlphaMod", fn (Ptr[_Texture], Ptr[UInt8]) -> IntC] 508 | var _get_texture_blend_mode: SDL_Fn["SDL_GetTextureBlendMode", fn (Ptr[_Texture], Ptr[BlendMode]) -> IntC] 509 | var _get_texture_scale_mode: SDL_Fn["SDL_GetTextureScaleMode", fn (Ptr[_Texture], Ptr[ScaleMode]) -> IntC] 510 | var _get_texture_user_data: SDL_Fn["SDL_GetTextureUserData", fn (Ptr[_Texture]) -> Ptr[NoneType]] 511 | var _set_texture_color_mod: SDL_Fn[ 512 | "SDL_SetTextureColorMod", 513 | fn (Ptr[_Texture], UInt8, UInt8, UInt8) -> IntC, 514 | ] 515 | var _set_texture_alpha_mod: SDL_Fn["SDL_SetTextureAlphaMod", fn (Ptr[_Texture], UInt8) -> IntC] 516 | var _set_texture_blend_mode: SDL_Fn["SDL_SetTextureBlendMode", fn (Ptr[_Texture], BlendMode) -> IntC] 517 | var _set_texture_scale_mode: SDL_Fn["SDL_SetTextureScaleMode", fn (Ptr[_Texture], ScaleMode) -> IntC] 518 | var _set_texture_user_data: SDL_Fn["SDL_SetTextureUserData", fn (Ptr[_Texture], Ptr[NoneType]) -> IntC] 519 | var _update_texture: SDL_Fn[ 520 | "SDL_UpdateTexture", 521 | fn (Ptr[_Texture], Ptr[Rect], Ptr[NoneType], IntC) -> IntC, 522 | ] 523 | var _update_nv_texture: SDL_Fn[ 524 | "SDL_UpdateNVTexture", 525 | fn (Ptr[_Texture], Ptr[Rect], Ptr[UInt8], IntC, Ptr[UInt8], IntC) -> IntC, 526 | ] 527 | var _update_yuv_texture: SDL_Fn[ 528 | "SDL_UpdateYUVTexture", 529 | fn ( 530 | Ptr[_Texture], 531 | Ptr[Rect], 532 | Ptr[UInt8], 533 | IntC, 534 | Ptr[UInt8], 535 | IntC, 536 | Ptr[UInt8], 537 | IntC, 538 | ) -> IntC, 539 | ] 540 | 541 | # opengl 542 | var _gl_create_context: SDL_Fn["SDL_GL_CreateContext", fn (Ptr[_Window]) -> Ptr[_GLContext]] 543 | var _gl_delete_context: SDL_Fn["SDL_GL_DeleteContext", fn (Ptr[_GLContext]) -> None] 544 | 545 | fn __init__(inout self): 546 | # x--- initialize sdl bindings 547 | @parameter 548 | if os_is_macos(): 549 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2.dylib") 550 | elif os_is_linux(): 551 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2.so") 552 | else: 553 | constrained[False, "OS is not supported"]() 554 | self._handle = utils._uninit[DLHandle]() 555 | 556 | self._init = self._handle 557 | self._quit = self._handle 558 | self._init_sub_system = self._handle 559 | self._quit_sub_system = self._handle 560 | 561 | # x--- initialize sdl error 562 | self.error = self._handle 563 | 564 | # x--- initialize keyboard bindings 565 | self._get_keyboard_state = self._handle 566 | 567 | # x--- initialize mouse bindings 568 | self._get_mouse_state = self._handle 569 | 570 | # x--- initialize event bindings 571 | self._poll_event = self._handle 572 | 573 | # x--- initialize timer 574 | self._get_ticks = self._handle 575 | self._delay = self._handle 576 | 577 | # x--- initialize window bindings 578 | self._create_window = self._handle 579 | self._create_shaped_window = self._handle 580 | self._create_window_and_renderer = self._handle 581 | self._create_window_from = self._handle 582 | self._destroy_window_surface = self._handle 583 | self._destroy_window = self._handle 584 | self._is_shaped_window = self._handle 585 | self._has_window_surface = self._handle 586 | self._get_grabbed_window = self._handle 587 | # SDL_GetShapedWindowMode 588 | self._get_window_border_size = self._handle 589 | self._get_window_brightness = self._handle 590 | self._get_window_gamma_ramp = self._handle 591 | self._get_window_opacity = self._handle 592 | self._get_window_data = self._handle 593 | self._get_window_display_index = self._handle 594 | self._get_window_display_mode = self._handle 595 | self._get_window_flags = self._handle 596 | self._get_window_from_id = self._handle 597 | self._get_window_grab = self._handle 598 | # SDL_GetWindowICCProfile 599 | self._get_window_id = self._handle 600 | self._get_window_keyboard_grab = self._handle 601 | self._get_window_mouse_grab = self._handle 602 | self._get_window_maximum_size = self._handle 603 | self._get_window_minimum_size = self._handle 604 | self._get_window_mouse_rect = self._handle 605 | self._get_window_pixel_format = self._handle 606 | self._get_window_title = self._handle 607 | self._get_window_position = self._handle 608 | self._get_window_size = self._handle 609 | self._get_window_size_in_pixels = self._handle 610 | # # SDL_GetWindowWMInfo 611 | self._get_window_surface = self._handle 612 | self._get_renderer = self._handle 613 | self._set_window_always_on_top = self._handle 614 | self._set_window_bordered = self._handle 615 | self._set_window_brightness = self._handle 616 | self._set_window_gamma_ramp = self._handle 617 | self._set_window_opacity = self._handle 618 | self._set_window_data = self._handle 619 | self._set_window_display_mode = self._handle 620 | self._set_window_fullscreen = self._handle 621 | self._set_window_grab = self._handle 622 | # SDL_SetWindowHitTest 623 | self._set_window_icon = self._handle 624 | self._set_window_input_focus = self._handle 625 | self._set_window_keyboard_grab = self._handle 626 | self._set_window_mouse_grab = self._handle 627 | self._set_window_maximum_size = self._handle 628 | self._set_window_minimum_size = self._handle 629 | self._set_window_modal_for = self._handle 630 | self._set_window_mouse_rect = self._handle 631 | self._set_window_position = self._handle 632 | self._set_window_resizable = self._handle 633 | self._set_window_size = self._handle 634 | # SDL_SetWindowsMessageHook 635 | # SDL_SetWindowShape 636 | self._set_window_title = self._handle 637 | # # SDL_GL_GetCurrentWindow 638 | # # SDL_GL_SwapWindow 639 | self._update_window_surface = self._handle 640 | self._update_window_surface_rects = self._handle 641 | self._show_window = self._handle 642 | self._hide_window = self._handle 643 | self._maximize_window = self._handle 644 | self._minimize_window = self._handle 645 | self._flash_window = self._handle 646 | self._raise_window = self._handle 647 | self._restore_window = self._handle 648 | self._warp_mouse_in_window = self._handle 649 | 650 | # x--- initialize surface bindings 651 | self._create_rgb_surface = self._handle 652 | self._create_rgb_surface_from = self._handle 653 | self._create_rgb_surface_with_format = self._handle 654 | self._create_rgb_surface_with_format_from = self._handle 655 | self._free_surface = self._handle 656 | self._convert_surface = self._handle 657 | self._convert_surface_format = self._handle 658 | self._has_surface_rle = self._handle 659 | self._get_surface_color_mod = self._handle 660 | self._get_surface_alpha_mod = self._handle 661 | self._get_surface_blend_mode = self._handle 662 | self._set_surface_color_mod = self._handle 663 | self._set_surface_alpha_mod = self._handle 664 | self._set_surface_blend_mode = self._handle 665 | self._set_surface_palette = self._handle 666 | self._set_surface_rle = self._handle 667 | self._fill_rect = self._handle 668 | self._fill_rects = self._handle 669 | self._lock_surface = self._handle 670 | self._unlock_surface = self._handle 671 | self._lower_blit = self._handle 672 | self._lower_blit_scaled = self._handle 673 | self._upper_blit = self._handle 674 | self._upper_blit_scaled = self._handle 675 | 676 | # x--- initialize renderer bindings 677 | self._create_renderer = self._handle 678 | self._create_software_renderer = self._handle 679 | self._destroy_renderer = self._handle 680 | self._render_clear = self._handle 681 | self._render_present = self._handle 682 | self._render_get_window = self._handle 683 | self._set_render_target = self._handle 684 | self._set_render_draw_color = self._handle 685 | self._set_render_draw_blend_mode = self._handle 686 | self._get_render_draw_color = self._handle 687 | self._get_render_draw_blend_mode = self._handle 688 | self._get_renderer_info = self._handle 689 | self._get_renderer_output_size = self._handle 690 | self._get_render_target = self._handle 691 | self._get_num_render_drivers = self._handle 692 | self._get_render_driver_info = self._handle 693 | self._render_copy = self._handle 694 | self._render_copy_f = self._handle 695 | self._render_copy_ex = self._handle 696 | self._render_copy_exf = self._handle 697 | self._render_draw_line = self._handle 698 | self._render_draw_line_f = self._handle 699 | self._render_draw_lines = self._handle 700 | self._render_draw_lines_f = self._handle 701 | self._render_draw_point = self._handle 702 | self._render_draw_point_f = self._handle 703 | self._render_draw_points = self._handle 704 | self._render_draw_points_f = self._handle 705 | self._render_draw_rect = self._handle 706 | self._render_draw_rect_f = self._handle 707 | self._render_draw_rects = self._handle 708 | self._render_draw_rects_f = self._handle 709 | self._render_fill_rect = self._handle 710 | self._render_fill_rect_f = self._handle 711 | self._render_fill_rects = self._handle 712 | self._render_fill_rects_f = self._handle 713 | self._render_flush = self._handle 714 | self._render_geometry = self._handle 715 | self._render_geometry_raw = self._handle 716 | self._render_get_clip_rect = self._handle 717 | self._render_get_integer_scale = self._handle 718 | self._render_get_logical_size = self._handle 719 | self._render_get_metal_command_encoder = self._handle 720 | self._render_get_metal_layer = self._handle 721 | self._render_get_scale = self._handle 722 | self._render_get_viewport = self._handle 723 | self._render_is_clip_enabled = self._handle 724 | self._render_logical_to_window = self._handle 725 | self._render_read_pixels = self._handle 726 | self._render_set_clip_rect = self._handle 727 | self._render_set_integer_scale = self._handle 728 | self._render_set_logical_size = self._handle 729 | self._render_set_scale = self._handle 730 | self._render_set_viewport = self._handle 731 | self._render_set_vsync = self._handle 732 | self._render_target_supported = self._handle 733 | self._render_window_to_logical = self._handle 734 | 735 | # x--- initialize texture bindings 736 | self._create_texture = self._handle 737 | self._create_texture_from_surface = self._handle 738 | self._destroy_texture = self._handle 739 | self._gl_bind_texture = self._handle 740 | self._gl_unbind_texture = self._handle 741 | self._lock_texture = self._handle 742 | self._lock_texture_to_surface = self._handle 743 | self._unlock_texture = self._handle 744 | self._query_texture = self._handle 745 | self._get_texture_color_mod = self._handle 746 | self._get_texture_alpha_mod = self._handle 747 | self._get_texture_blend_mode = self._handle 748 | self._get_texture_scale_mode = self._handle 749 | self._get_texture_user_data = self._handle 750 | self._set_texture_color_mod = self._handle 751 | self._set_texture_alpha_mod = self._handle 752 | self._set_texture_blend_mode = self._handle 753 | self._set_texture_scale_mode = self._handle 754 | self._set_texture_user_data = self._handle 755 | self._update_texture = self._handle 756 | self._update_nv_texture = self._handle 757 | self._update_yuv_texture = self._handle 758 | 759 | # x--- initialize opengl 760 | self._gl_create_context = self._handle 761 | self._gl_delete_context = self._handle 762 | 763 | # TODO: These could be generated automatically, but 764 | # im still looking for a nice way. Then these 765 | # could be made more private and parametrically 766 | # use the raising version if desired. 767 | 768 | # +--- sdl functions 769 | 770 | @always_inline 771 | fn init(self, flags: UInt32) raises: 772 | self.error.if_code(self._init.call(flags), "Could not initialize SDL") 773 | 774 | @always_inline 775 | fn quit(self): 776 | self._quit.call() 777 | 778 | @always_inline 779 | fn init_sub_system(self, flags: UInt32) raises: 780 | """Compatibility function to initialize the SDL library.""" 781 | self.error.if_code(self._init_sub_system.call(flags), "Could not initialize sub-system") 782 | 783 | @always_inline 784 | fn quit_sub_system(self, flags: UInt32): 785 | """Shut down specific SDL subsystems.""" 786 | self._quit_sub_system.call(flags) 787 | 788 | # +--- keyboard functions 789 | 790 | @always_inline 791 | fn get_keyboard_state(self, numkeys: Ptr[IntC]) -> Ptr[UInt8]: 792 | """Get a snapshot of the current state of the keyboard.""" 793 | return self._get_keyboard_state.call(numkeys) 794 | 795 | # +--- keyboard functions 796 | 797 | @always_inline 798 | fn get_mouse_state(self, x: Ptr[IntC], y: Ptr[IntC]) -> UInt32: 799 | """Retrieve the current state of the mouse.""" 800 | return self._get_mouse_state.call(x, y) 801 | 802 | # +--- event functions 803 | 804 | @always_inline 805 | fn poll_event(self, event: Ptr[_Event]) -> IntC: 806 | """Poll for currently pending events.""" 807 | return self._poll_event.call(event) 808 | 809 | # +--- timer functions 810 | 811 | @always_inline 812 | fn get_ticks(self) -> UInt32: 813 | """Get the number of milliseconds since SDL library initialization.""" 814 | return self._get_ticks.call() 815 | 816 | @always_inline 817 | fn delay(self, ms: UInt32): 818 | """Wait a specified number of milliseconds before returning.""" 819 | self._delay.call(ms) 820 | 821 | # +--- window functions 822 | 823 | @always_inline 824 | fn create_window( 825 | self, 826 | title: Ptr[CharC], 827 | x: IntC, 828 | y: IntC, 829 | w: IntC, 830 | h: IntC, 831 | flags: UInt32, 832 | ) raises -> Ptr[_Window]: 833 | """Create a window with the specified position, dimensions, and flags.""" 834 | return self.error.if_null( 835 | self._create_window.call(title, x, y, w, h, flags), 836 | "Could not create window", 837 | ) 838 | 839 | @always_inline 840 | fn create_shaped_window( 841 | self, 842 | title: Ptr[CharC], 843 | x: UIntC, 844 | y: UIntC, 845 | w: UIntC, 846 | h: UIntC, 847 | flags: UInt32, 848 | ) raises -> Ptr[_Window]: 849 | """Create a window that can be shaped with the specified position, dimensions, and flags.""" 850 | return self.error.if_null( 851 | self._create_shaped_window.call(title, x, y, w, h, flags), 852 | "Could not create shaped window", 853 | ) 854 | 855 | @always_inline 856 | fn create_window_and_renderer( 857 | self, 858 | width: IntC, 859 | height: IntC, 860 | window_flags: UInt32, 861 | window: Ptr[_Window], 862 | renderer: Ptr[_Renderer], 863 | ) raises: 864 | """Create a window and default renderer.""" 865 | self.error.if_code( 866 | self._create_window_and_renderer.call(width, height, window_flags, window, renderer), 867 | "Could not create window and renderer", 868 | ) 869 | 870 | @always_inline 871 | fn create_window_from(self, data: Ptr[NoneType]) raises -> Ptr[_Window]: 872 | """Create an SDL window from an existing native window.""" 873 | return self.error.if_null(self._create_window_from.call(data), "Could not create window from") 874 | 875 | @always_inline 876 | fn destroy_window(self, window: Ptr[_Window]): 877 | """Destroy a window.""" 878 | self._destroy_window.call(window) 879 | 880 | @always_inline 881 | fn destroy_window_surface(self, window: Ptr[_Window]) raises: 882 | """Destroy the surface associated with the window.""" 883 | self.error.if_code( 884 | self._destroy_window_surface.call(window), 885 | "Could not destroy window surface", 886 | ) 887 | 888 | @always_inline 889 | fn get_window_surface(self, window: Ptr[_Window]) raises -> Ptr[_Surface]: 890 | """Get the SDL surface associated with the window.""" 891 | return self.error.if_null(self._get_window_surface.call(window), "Could not get surface") 892 | 893 | @always_inline 894 | fn get_renderer(self, window: Ptr[_Window]) raises -> Ptr[_Renderer]: 895 | """Get the renderer associated with a window.""" 896 | return self.error.if_null(self._get_renderer.call(window), "Could not get renderer") 897 | 898 | @always_inline 899 | fn set_window_fullscreen(self, window: Ptr[_Window], flags: UInt32) raises: 900 | """Set a window's fullscreen state.""" 901 | self.error.if_code( 902 | self._set_window_fullscreen.call(window, flags), 903 | "Could not set fullscreen", 904 | ) 905 | 906 | @always_inline 907 | fn update_window_surface(self, window: Ptr[_Window]) raises: 908 | """Copy the window surface to the screen.""" 909 | self.error.if_code( 910 | self._update_window_surface.call(window), 911 | "Could not update window surface", 912 | ) 913 | 914 | # +--- surface functions 915 | 916 | @always_inline 917 | fn create_rgb_surface( 918 | self, 919 | flags: UInt32, 920 | width: IntC, 921 | height: IntC, 922 | depth: IntC, 923 | r_mask: UInt32, 924 | g_mask: UInt32, 925 | b_mask: UInt32, 926 | a_mask: UInt32, 927 | ) raises -> Ptr[_Surface]: 928 | """Allocate a new RGB surface.""" 929 | return self.error.if_null( 930 | self._create_rgb_surface.call(flags, width, height, depth, r_mask, g_mask, b_mask, a_mask), 931 | "Could not create surface", 932 | ) 933 | 934 | @always_inline 935 | fn create_rgb_surface_from( 936 | self, 937 | pixels: Ptr[NoneType], 938 | width: IntC, 939 | height: IntC, 940 | depth: IntC, 941 | pitch: IntC, 942 | r_mask: UInt32, 943 | g_mask: UInt32, 944 | b_mask: UInt32, 945 | a_mask: UInt32, 946 | ) raises -> Ptr[_Surface]: 947 | """Allocate a new RGB surface with existing pixel data.""" 948 | return self.error.if_null( 949 | self._create_rgb_surface_from.call( 950 | pixels, 951 | width, 952 | height, 953 | depth, 954 | pitch, 955 | r_mask, 956 | g_mask, 957 | b_mask, 958 | a_mask, 959 | ), 960 | "Could not create surface from", 961 | ) 962 | 963 | @always_inline 964 | fn create_rgb_surface_with_format( 965 | self, 966 | flags: UInt32, 967 | width: IntC, 968 | height: IntC, 969 | depth: IntC, 970 | format: UInt32, 971 | ) raises -> Ptr[_Surface]: 972 | """Allocate a new RGB surface with a specific pixel format.""" 973 | return self.error.if_null( 974 | self._create_rgb_surface_with_format.call(flags, width, height, depth, format), 975 | "Could not create surface with format", 976 | ) 977 | 978 | @always_inline 979 | fn create_rgb_surface_with_format_from( 980 | self, 981 | pixels: Ptr[NoneType], 982 | width: IntC, 983 | height: IntC, 984 | depth: IntC, 985 | pitch: IntC, 986 | format: UInt32, 987 | ) raises -> Ptr[_Surface]: 988 | """Allocate a new RGB surface with with a specific pixel format and existing pixel data.""" 989 | return self.error.if_null( 990 | self._create_rgb_surface_with_format_from.call(pixels, width, height, depth, pitch, format), 991 | "Could not create surface with format from", 992 | ) 993 | 994 | @always_inline 995 | fn free_surface(self, surface: Ptr[_Surface]): 996 | """Free an RGB surface.""" 997 | self._free_surface.call(surface) 998 | 999 | @always_inline 1000 | fn convert_surface(self, src: Ptr[_Surface], fmt: Ptr[SurfacePixelFormat], flags: UInt32) raises -> Ptr[_Surface]: 1001 | """Copy an existing surface to a new surface of the specified format.""" 1002 | return self.error.if_null( 1003 | self._convert_surface.call(src, fmt, flags), 1004 | "Could not convert surface", 1005 | ) 1006 | 1007 | @always_inline 1008 | fn convert_surface_format(self, src: Ptr[_Surface], pixel_format: UInt32, flags: UInt32) raises -> Ptr[_Surface]: 1009 | """Copy an existing surface to a new surface of the specified format enum.""" 1010 | return self.error.if_null( 1011 | self._convert_surface_format.call(src, pixel_format, flags), 1012 | "Could not convert surface format", 1013 | ) 1014 | 1015 | @always_inline 1016 | fn fill_rect(self, surface: Ptr[_Surface], rect: Ptr[Rect], color: UInt32) raises: 1017 | """Perform a fast fill of a rectangle with a specific color.""" 1018 | self.error.if_code(self._fill_rect.call(surface, rect, color), "Could not fill rect") 1019 | 1020 | @always_inline 1021 | fn fill_rects( 1022 | self, 1023 | surface: Ptr[_Surface], 1024 | rects: Ptr[Rect], 1025 | count: IntC, 1026 | color: UInt32, 1027 | ) raises: 1028 | """Perform a fast fill of a set of rectangles with a specific color.""" 1029 | self.error.if_code(self._fill_rects.call(surface, rects, count, color), "Could not fill rects") 1030 | 1031 | # var _get_surface_color_mod: SDL_Fn["SDL_GetSurfaceColorMod", fn (Ptr[_Surface], Ptr[UInt8], Ptr[UInt8], Ptr[UInt8]) -> IntC] 1032 | # var _get_surface_alpha_mod: SDL_Fn["SDL_GetSurfaceAlphaMod", fn (Ptr[_Surface], Ptr[UInt8]) -> IntC] 1033 | # var _get_surface_blend_mode: SDL_Fn["SDL_GetSurfaceBlendMode", fn (Ptr[_Surface], Ptr[BlendMode]) -> IntC] 1034 | # var _has_surface_rle: SDL_Fn["SDL_HasSurfaceRLE", fn (Ptr[_Surface]) -> BoolC] 1035 | 1036 | @always_inline 1037 | fn lock_surface(self, surface: Ptr[_Surface]) raises: 1038 | """Set up a surface for directly accessing the pixels.""" 1039 | self.error.if_code(self._lock_surface.call(surface), "Could not lock surface") 1040 | 1041 | @always_inline 1042 | fn unlock_surface(self, surface: Ptr[_Surface]): 1043 | """Release a surface after directly accessing the pixels.""" 1044 | self._unlock_surface.call(surface) 1045 | 1046 | # var _set_surface_color_mod: SDL_Fn["SDL_SetSurfaceColorMod", fn(Ptr[_Surface], UInt8, UInt8, UInt8) -> IntC] 1047 | # var _set_surface_alpha_mod: SDL_Fn["SDL_SetSurfaceAlphaMod", fn (Ptr[_Surface], UInt8) -> IntC] 1048 | # var _set_surface_blend_mode: SDL_Fn["SDL_SetSurfaceBlendMode", fn (Ptr[_Surface], BlendMode) -> IntC] 1049 | # var _set_surface_palette: SDL_Fn["SDL_SetSurfacePalette", fn (Ptr[_Surface], Ptr[Palette]) -> IntC] 1050 | # var _set_surface_rle: SDL_Fn["SDL_SetSurfaceRLE", fn (Ptr[_Surface], IntC) -> IntC] 1051 | 1052 | @always_inline 1053 | fn lower_blit( 1054 | self, 1055 | src: Ptr[_Surface], 1056 | src_rect: Ptr[Rect], 1057 | dst: Ptr[_Surface], 1058 | dst_rect: Ptr[Rect], 1059 | ) raises: 1060 | """Perform low-level surface blitting only, assuming the input rectangles have already been clipped.""" 1061 | self.error.if_code( 1062 | self._lower_blit.call(src, src_rect, dst, dst_rect), 1063 | "Could not lower blit surface", 1064 | ) 1065 | 1066 | @always_inline 1067 | fn lower_blit_scaled( 1068 | self, 1069 | src: Ptr[_Surface], 1070 | src_rect: Ptr[Rect], 1071 | dst: Ptr[_Surface], 1072 | dst_rect: Ptr[Rect], 1073 | ) raises: 1074 | """Perform low-level surface scaled blitting only, assuming the input rectangles have already been clipped.""" 1075 | self.error.if_code( 1076 | self._lower_blit_scaled.call(src, src_rect, dst, dst_rect), 1077 | "Could not lower blit scaled surface", 1078 | ) 1079 | 1080 | @always_inline 1081 | fn upper_blit( 1082 | self, 1083 | src: Ptr[_Surface], 1084 | src_rect: Ptr[Rect], 1085 | dst: Ptr[_Surface], 1086 | dst_rect: Ptr[Rect], 1087 | ) raises: 1088 | """Perform a fast blit from the source surface to the destination surface.""" 1089 | self.error.if_code( 1090 | self._upper_blit.call(src, src_rect, dst, dst_rect), 1091 | "Could not upper blit surface", 1092 | ) 1093 | 1094 | @always_inline 1095 | fn upper_blit_scaled( 1096 | self, 1097 | src: Ptr[_Surface], 1098 | src_rect: Ptr[Rect], 1099 | dst: Ptr[_Surface], 1100 | dst_rect: Ptr[Rect], 1101 | ) raises: 1102 | """Perform a scaled surface copy to a destination surface.""" 1103 | self.error.if_code( 1104 | self._upper_blit_scaled.call(src, src_rect, dst, dst_rect), 1105 | "Could not upper blit scaled surface", 1106 | ) 1107 | 1108 | # +--- renderer functions 1109 | 1110 | @always_inline 1111 | fn create_renderer(self, window: Ptr[_Window], index: IntC, flags: UInt32) raises -> Ptr[_Renderer]: 1112 | """Create a 2D rendering context for a window.""" 1113 | return self.error.if_null( 1114 | self._create_renderer.call(window, index, flags), 1115 | "Could not create renderer", 1116 | ) 1117 | 1118 | @always_inline 1119 | fn create_software_renderer(self, surface: Ptr[_Surface]) raises -> Ptr[_Renderer]: 1120 | """Create a 2D software rendering context for a surface.""" 1121 | return self.error.if_null( 1122 | self._create_software_renderer.call(surface), 1123 | "Could not create software renderer", 1124 | ) 1125 | 1126 | @always_inline 1127 | fn destroy_renderer(self, renderer: Ptr[_Renderer]): 1128 | """Destroy the rendering context for a window and free associated textures.""" 1129 | self._destroy_renderer.call(renderer) 1130 | 1131 | @always_inline 1132 | fn render_clear(self, renderer: Ptr[_Renderer]) raises: 1133 | """Clear the current rendering target with the drawing color.""" 1134 | self.error.if_code( 1135 | self._render_clear.call(renderer), 1136 | "Could not clear the current rendering target", 1137 | ) 1138 | 1139 | @always_inline 1140 | fn render_present(self, renderer: Ptr[_Renderer]): 1141 | """Update the screen with any rendering performed since the previous call.""" 1142 | self._render_present.call(renderer) 1143 | 1144 | @always_inline 1145 | fn render_get_window(self, renderer: Ptr[_Renderer]) raises -> Ptr[_Window]: 1146 | """Get the window associated with a renderer.""" 1147 | return self.error.if_null( 1148 | self._render_get_window.call(renderer), 1149 | "Could not get renderer window", 1150 | ) 1151 | 1152 | @always_inline 1153 | fn set_render_target(self, renderer: Ptr[_Renderer], texture: Ptr[_Texture]) raises: 1154 | """Set a texture as the current rendering target.""" 1155 | self.error.if_code( 1156 | self._set_render_target.call(renderer, texture), 1157 | "Could not set render target", 1158 | ) 1159 | 1160 | @always_inline 1161 | fn set_render_draw_color(self, renderer: Ptr[_Renderer], r: UInt8, g: UInt8, b: UInt8, a: UInt8) raises: 1162 | """Set the color used for drawing operations (Rect, Line and Clear).""" 1163 | self.error.if_code( 1164 | self._set_render_draw_color.call(renderer, r, g, b, a), 1165 | "Could not set render draw color", 1166 | ) 1167 | 1168 | @always_inline 1169 | fn set_render_draw_blend_mode(self, renderer: Ptr[_Renderer], blend_mode: BlendMode) raises: 1170 | """Set the blend mode used for drawing operations (Fill and Line).""" 1171 | self.error.if_code( 1172 | self._set_render_draw_blend_mode.call(renderer, blend_mode), 1173 | "Could not set render draw blend mode", 1174 | ) 1175 | 1176 | @always_inline 1177 | fn get_render_draw_color( 1178 | self, 1179 | renderer: Ptr[_Renderer], 1180 | r: Ptr[UInt8], 1181 | g: Ptr[UInt8], 1182 | b: Ptr[UInt8], 1183 | a: Ptr[UInt8], 1184 | ) raises: 1185 | """Get the color used for drawing operations (Rect, Line and Clear).""" 1186 | self.error.if_code( 1187 | self._get_render_draw_color.call(renderer, r, g, b, a), 1188 | "Could not get render draw color", 1189 | ) 1190 | 1191 | @always_inline 1192 | fn get_render_draw_blend_mode(self, renderer: Ptr[_Renderer], blend_mode: Ptr[BlendMode]) raises: 1193 | """Get the blend mode used for drawing operations.""" 1194 | self.error.if_code( 1195 | self._get_render_draw_blend_mode.call(renderer, blend_mode), 1196 | "Could not get render draw blend mode", 1197 | ) 1198 | 1199 | @always_inline 1200 | fn get_renderer_info(self, renderer: Ptr[_Renderer], info: Ptr[RendererInfo]) raises: 1201 | """Get information about a rendering context.""" 1202 | self.error.if_code( 1203 | self._get_renderer_info.call(renderer, info), 1204 | "Could not get renderer info", 1205 | ) 1206 | 1207 | @always_inline 1208 | fn get_renderer_output_size(self, renderer: Ptr[_Renderer], w: Ptr[IntC], h: Ptr[IntC]) raises: 1209 | """Get the output size in pixels of a rendering context.""" 1210 | self.error.if_code( 1211 | self._get_renderer_output_size.call(renderer, w, h), 1212 | "Could not get renderer output size", 1213 | ) 1214 | 1215 | @always_inline 1216 | fn get_render_target(self, renderer: Ptr[_Renderer]) -> Ptr[_Texture]: 1217 | """Get the current render target.""" 1218 | return self._get_render_target.call(renderer) 1219 | 1220 | @always_inline 1221 | fn get_num_render_drivers(self) raises -> IntC: 1222 | """Get the number of 2D rendering drivers available for the current display.""" 1223 | var num_render_drivers = self._get_num_render_drivers.call() 1224 | if num_render_drivers < 0: 1225 | raise self.error() 1226 | return num_render_drivers 1227 | 1228 | @always_inline 1229 | fn get_render_driver_info(self, index: IntC) raises -> RendererInfo: 1230 | """Get info about a specific 2D rendering driver for the current display.""" 1231 | var renderer_info = utils._uninit[RendererInfo]() 1232 | self.error.if_code(self._get_render_driver_info.call(index, Ptr.address_of(renderer_info)), "Could not get render driver info") 1233 | return renderer_info 1234 | 1235 | @always_inline 1236 | fn render_copy( 1237 | self, 1238 | renderer: Ptr[_Renderer], 1239 | texture: Ptr[_Texture], 1240 | src_rect: Ptr[Rect], 1241 | dst_rect: Ptr[Rect], 1242 | ) raises: 1243 | """Copy a portion of the texture to the current rendering target.""" 1244 | self.error.if_code( 1245 | self._render_copy.call(renderer, texture, src_rect, dst_rect), 1246 | "Could not copy texture", 1247 | ) 1248 | 1249 | @always_inline 1250 | fn render_copy_f( 1251 | self, 1252 | renderer: Ptr[_Renderer], 1253 | texture: Ptr[_Texture], 1254 | src_rect: Ptr[Rect], 1255 | dst_rect: Ptr[FRect], 1256 | ) raises: 1257 | """Copy a portion of the texture to the current rendering target at subpixel precision.""" 1258 | self.error.if_code( 1259 | self._render_copy_f.call(renderer, texture, src_rect, dst_rect), 1260 | "Could not copy texture", 1261 | ) 1262 | 1263 | @always_inline 1264 | fn render_copy_ex( 1265 | self, 1266 | renderer: Ptr[_Renderer], 1267 | texture: Ptr[_Texture], 1268 | src_rect: Ptr[Rect], 1269 | dst_rect: Ptr[Rect], 1270 | angle: Float64, 1271 | center: Ptr[Point], 1272 | flip: RendererFlip, 1273 | ) raises: 1274 | """Copy a portion of the texture to the current rendering, with optional rotation and flipping.""" 1275 | self.error.if_code( 1276 | self._render_copy_ex.call(renderer, texture, src_rect, dst_rect, angle, center, flip), 1277 | "Could not copy texture", 1278 | ) 1279 | 1280 | @always_inline 1281 | fn render_copy_exf( 1282 | self, 1283 | renderer: Ptr[_Renderer], 1284 | texture: Ptr[_Texture], 1285 | src_rect: Ptr[Rect], 1286 | dst_rect: Ptr[FRect], 1287 | angle: Float64, 1288 | center: Ptr[FPoint], 1289 | flip: RendererFlip, 1290 | ) raises: 1291 | """Copy a portion of the source texture to the current rendering target, with rotation and flipping, at subpixel precision.""" 1292 | self.error.if_code( 1293 | self._render_copy_exf.call(renderer, texture, src_rect, dst_rect, angle, center, flip), 1294 | "Could not copy texture", 1295 | ) 1296 | 1297 | @always_inline 1298 | fn render_draw_line(self, renderer: Ptr[_Renderer], x1: IntC, y1: IntC, x2: IntC, y2: IntC) raises: 1299 | """Draw a line on the current rendering target.""" 1300 | self.error.if_code( 1301 | self._render_draw_line.call(renderer, x1, y1, x2, y2), 1302 | "Could not draw line", 1303 | ) 1304 | 1305 | @always_inline 1306 | fn render_draw_line_f( 1307 | self, 1308 | renderer: Ptr[_Renderer], 1309 | x1: Float32, 1310 | y1: Float32, 1311 | x2: Float32, 1312 | y2: Float32, 1313 | ) raises: 1314 | """Draw a line on the current rendering target at subpixel precision.""" 1315 | self.error.if_code( 1316 | self._render_draw_line_f.call(renderer, x1, y1, x2, y2), 1317 | "Could not draw line", 1318 | ) 1319 | 1320 | @always_inline 1321 | fn render_draw_lines(self, renderer: Ptr[_Renderer], points: Ptr[Point[]], count: IntC) raises: 1322 | """Draw a series of connected lines on the current rendering target at subpixel precision.""" 1323 | self.error.if_code( 1324 | self._render_draw_lines.call(renderer, points, count), 1325 | "Could not draw lines", 1326 | ) 1327 | 1328 | @always_inline 1329 | fn render_draw_lines_f(self, renderer: Ptr[_Renderer], points: Ptr[FPoint], count: IntC) raises: 1330 | """Draw a series of connected lines on the current rendering target at subpixel precision.""" 1331 | self.error.if_code( 1332 | self._render_draw_lines_f.call(renderer, points, count), 1333 | "Could not draw lines", 1334 | ) 1335 | 1336 | @always_inline 1337 | fn render_draw_point(self, renderer: Ptr[_Renderer], x: IntC, y: IntC) raises: 1338 | """Draw a point on the current rendering target.""" 1339 | self.error.if_code(self._render_draw_point.call(renderer, x, y), "Could not draw point") 1340 | 1341 | @always_inline 1342 | fn render_draw_point_f(self, renderer: Ptr[_Renderer], x: Float32, y: Float32) raises: 1343 | """Draw a point on the current rendering target at subpixel precision.""" 1344 | self.error.if_code( 1345 | self._render_draw_point_f.call(renderer, x, y), 1346 | "Could not draw point", 1347 | ) 1348 | 1349 | @always_inline 1350 | fn render_draw_points(self, renderer: Ptr[_Renderer], points: Ptr[Point[]], count: IntC) raises: 1351 | """Draw multiple points on the current rendering target.""" 1352 | self.error.if_code( 1353 | self._render_draw_points.call(renderer, points, count), 1354 | "Could not draw points", 1355 | ) 1356 | 1357 | @always_inline 1358 | fn render_draw_points_f(self, renderer: Ptr[_Renderer], points: Ptr[FPoint], count: IntC) raises: 1359 | """Draw multiple points on the current rendering target at subpixel precision.""" 1360 | self.error.if_code( 1361 | self._render_draw_points_f.call(renderer, points, count), 1362 | "Could not draw points", 1363 | ) 1364 | 1365 | @always_inline 1366 | fn render_draw_rect(self, renderer: Ptr[_Renderer], rect: Rect) raises: 1367 | """Draw a rectangle on the current rendering target.""" 1368 | self.error.if_code(self._render_draw_rect.call(renderer, rect), "Could not draw rect") 1369 | 1370 | @always_inline 1371 | fn render_draw_rect_f(self, renderer: Ptr[_Renderer], rect: FRect) raises: 1372 | """Draw a rectangle on the current rendering target at subpixel precision.""" 1373 | self.error.if_code(self._render_draw_rect_f.call(renderer, rect), "Could not draw rect") 1374 | 1375 | @always_inline 1376 | fn render_draw_rects(self, renderer: Ptr[_Renderer], rects: Ptr[Rect], count: IntC) raises: 1377 | """Draw some number of rectangles on the current rendering target.""" 1378 | self.error.if_code( 1379 | self._render_draw_rects.call(renderer, rects, count), 1380 | "Could not draw rects", 1381 | ) 1382 | 1383 | @always_inline 1384 | fn render_draw_rects_f(self, renderer: Ptr[_Renderer], rects: Ptr[FRect], count: IntC) raises: 1385 | """Draw some number of rectangles on the current rendering target at subpixel precision.""" 1386 | self.error.if_code( 1387 | self._render_draw_rects_f.call(renderer, rects, count), 1388 | "Could not draw rects", 1389 | ) 1390 | 1391 | @always_inline 1392 | fn render_fill_rect(self, renderer: Ptr[_Renderer], rect: Rect) raises: 1393 | """Fill a rectangle on the current rendering target.""" 1394 | self.error.if_code(self._render_fill_rect.call(renderer, rect), "Could not fill rect") 1395 | 1396 | @always_inline 1397 | fn render_fill_rect_f(self, renderer: Ptr[_Renderer], rect: FRect) raises: 1398 | """Fill a rectangle on the current rendering target at subpixel precision.""" 1399 | self.error.if_code(self._render_fill_rect_f.call(renderer, rect), "Could not fill rect") 1400 | 1401 | @always_inline 1402 | fn render_fill_rects(self, renderer: Ptr[_Renderer], rects: Ptr[Rect], count: IntC) raises: 1403 | """Fill some number of rectangles on the current rendering target.""" 1404 | self.error.if_code( 1405 | self._render_fill_rects.call(renderer, rects, count), 1406 | "Could not fill rects", 1407 | ) 1408 | 1409 | @always_inline 1410 | fn render_fill_rects_f(self, renderer: Ptr[_Renderer], rects: Ptr[FRect], count: IntC) raises: 1411 | """Fill some number of rectangles on the current rendering target at subpixel precision.""" 1412 | self.error.if_code( 1413 | self._render_fill_rects_f.call(renderer, rects, count), 1414 | "Could not fill rects", 1415 | ) 1416 | 1417 | @always_inline 1418 | fn render_flush(self, renderer: Ptr[_Renderer]) raises: 1419 | """Force the rendering context to flush any pending commands to the underlying rendering API.""" 1420 | self.error.if_code(self._render_flush.call(renderer), "Could not flush, clogged") 1421 | 1422 | @always_inline 1423 | fn render_geometry(self, renderer: Ptr[_Renderer], texture: Ptr[_Texture], vertices: Ptr[Vertex], num_vertices: IntC, indices: Ptr[IntC], num_indices: IntC) raises: 1424 | """Render a list of triangles, optionally using a texture and indices into the vertex array Color 1425 | and alpha modulation is done per vertex (SDL_SetTextureColorMod and SDL_SetTextureAlphaMod are ignored).""" 1426 | self.error.if_code(self._render_geometry.call(renderer, texture, vertices, num_vertices, indices, num_indices), "Could not render geometry") 1427 | 1428 | @always_inline 1429 | fn render_geometry_raw( 1430 | self, 1431 | renderer: Ptr[_Renderer], 1432 | texture: Ptr[_Texture], 1433 | xy: Ptr[Float32], 1434 | xy_stride: IntC, 1435 | color: Ptr[Color], 1436 | color_stride: IntC, 1437 | uv: Ptr[Float32], 1438 | uv_stride: IntC, 1439 | num_vertices: IntC, 1440 | indices: Ptr[NoneType], 1441 | num_indices: IntC, 1442 | size_indices: IntC, 1443 | ) raises: 1444 | self.error.if_code( 1445 | self._render_geometry_raw.call( 1446 | renderer, 1447 | texture, 1448 | xy, 1449 | xy_stride, 1450 | color, 1451 | color_stride, 1452 | uv, 1453 | uv_stride, 1454 | num_vertices, 1455 | indices, 1456 | num_indices, 1457 | size_indices, 1458 | ), 1459 | "Could not render geometry raw", 1460 | ) 1461 | 1462 | @always_inline 1463 | fn render_get_clip_rect(self, renderer: Ptr[_Renderer], rect: Ptr[Rect]): 1464 | """Get the clip rectangle for the current target.""" 1465 | self._render_get_clip_rect.call(renderer, rect) 1466 | 1467 | @always_inline 1468 | fn render_get_integer_scale(self, renderer: Ptr[_Renderer]) -> Bool: 1469 | """Get whether integer scales are forced for resolution-independent rendering.""" 1470 | return self._render_get_integer_scale.call(renderer) 1471 | 1472 | @always_inline 1473 | fn render_get_logical_size(self, renderer: Ptr[_Renderer], w: Ptr[IntC], h: Ptr[IntC]): 1474 | """Get device independent resolution for rendering.""" 1475 | self._render_get_logical_size.call(renderer, w, h) 1476 | 1477 | @always_inline 1478 | fn render_get_metal_command_encoder(self, renderer: Ptr[_Renderer]) raises -> Ptr[NoneType]: 1479 | """Get the Metal command encoder for the current frame.""" 1480 | return self.error.if_null( 1481 | self._render_get_metal_command_encoder.call(renderer), 1482 | "Could not get metal command encoder", 1483 | ) 1484 | 1485 | @always_inline 1486 | fn render_get_metal_layer(self, renderer: Ptr[_Renderer]) raises -> Ptr[NoneType]: 1487 | """Get the CAMetalLayer associated with the given Metal renderer.""" 1488 | return self.error.if_null( 1489 | self._render_get_metal_layer.call(renderer), 1490 | "Could not get metal layer", 1491 | ) 1492 | 1493 | @always_inline 1494 | fn render_get_scale(self, renderer: Ptr[_Renderer], scale_x: Ptr[IntC], scale_y: Ptr[IntC]): 1495 | """Get the drawing scale for the current target.""" 1496 | self._render_get_scale.call(renderer, scale_x, scale_y) 1497 | 1498 | @always_inline 1499 | fn render_get_viewport(self, renderer: Ptr[_Renderer], rect: Ptr[Rect]): 1500 | """Get the drawing area for the current target.""" 1501 | self._render_get_viewport.call(renderer, rect) 1502 | 1503 | @always_inline 1504 | fn render_is_clip_enabled(self, renderer: Ptr[_Renderer]) -> Bool: 1505 | """Get whether clipping is enabled on the given renderer.""" 1506 | return self._render_is_clip_enabled.call(renderer) 1507 | 1508 | @always_inline 1509 | fn render_logical_to_window( 1510 | self, 1511 | renderer: Ptr[_Renderer], 1512 | logical_x: Float32, 1513 | logical_y: Float32, 1514 | window_x: Ptr[IntC], 1515 | window_y: Ptr[IntC], 1516 | ): 1517 | """Get real coordinates of point in window when given logical coordinates of point in renderer.""" 1518 | self._render_logical_to_window.call(renderer, logical_x, logical_y, window_x, window_y) 1519 | 1520 | @always_inline 1521 | fn render_read_pixels( 1522 | self, 1523 | renderer: Ptr[_Renderer], 1524 | rect: Ptr[Rect], 1525 | format: UInt32, 1526 | pixels: Ptr[NoneType], 1527 | pitch: IntC, 1528 | ) raises: 1529 | """Read pixels from the current rendering target to an array of pixels.""" 1530 | self.error.if_code( 1531 | self._render_read_pixels.call(renderer, rect, format, pixels, pitch), 1532 | "Could not read pixels", 1533 | ) 1534 | 1535 | @always_inline 1536 | fn render_set_clip_rect(self, renderer: Ptr[_Renderer], rect: Ptr[Rect]) raises: 1537 | """Set the clip rectangle for rendering on the specified target.""" 1538 | self.error.if_code( 1539 | self._render_set_clip_rect.call(renderer, rect), 1540 | "Could not set render clip rect", 1541 | ) 1542 | 1543 | @always_inline 1544 | fn render_set_integer_scale(self, renderer: Ptr[_Renderer], enable: Bool) raises: 1545 | """Set whether to force integer scales for resolution-independent rendering.""" 1546 | self.error.if_code( 1547 | self._render_set_integer_scale.call(renderer, enable), 1548 | "Could not set integer render scale", 1549 | ) 1550 | 1551 | @always_inline 1552 | fn render_set_logical_size(self, renderer: Ptr[_Renderer], w: IntC, h: IntC) raises: 1553 | """Set a device independent resolution for rendering.""" 1554 | self.error.if_code( 1555 | self._render_set_logical_size.call(renderer, w, h), 1556 | "Could not set logical render size", 1557 | ) 1558 | 1559 | @always_inline 1560 | fn render_set_scale(self, renderer: Ptr[_Renderer], scale_x: Float32, scale_y: Float32) raises: 1561 | """Set the drawing scale for rendering on the current target.""" 1562 | self.error.if_code( 1563 | self._render_set_scale.call(renderer, scale_x, scale_y), 1564 | "Could not set render scale", 1565 | ) 1566 | 1567 | @always_inline 1568 | fn render_set_viewport(self, renderer: Ptr[_Renderer], rect: Ptr[Rect]) raises: 1569 | """Set the drawing area for rendering on the current target.""" 1570 | self.error.if_code( 1571 | self._render_set_viewport.call(renderer, rect), 1572 | "Could not set viewport", 1573 | ) 1574 | 1575 | @always_inline 1576 | fn render_set_vsync(self, renderer: Ptr[_Renderer], vsync: IntC) raises: 1577 | """Toggle VSync of the given renderer.""" 1578 | self.error.if_code(self._render_set_vsync.call(renderer, vsync), "Could not set vsync") 1579 | 1580 | @always_inline 1581 | fn render_target_supported(self, renderer: Ptr[_Renderer]) -> Bool: 1582 | """Determine whether a renderer supports the use of render targets.""" 1583 | return self._render_target_supported.call(renderer) 1584 | 1585 | @always_inline 1586 | fn render_window_to_logical( 1587 | self, 1588 | renderer: Ptr[_Renderer], 1589 | window_x: IntC, 1590 | window_y: IntC, 1591 | logical_x: Ptr[Float32], 1592 | logical_y: Ptr[Float32], 1593 | ): 1594 | """Get logical coordinates of point in renderer when given real coordinates of point in window.""" 1595 | self._render_window_to_logical.call(renderer, window_x, window_y, logical_x, logical_y) 1596 | 1597 | # +--- texture functions 1598 | 1599 | @always_inline 1600 | fn create_texture( 1601 | self, 1602 | renderer: Ptr[_Renderer], 1603 | format: UInt32, 1604 | access: IntC, 1605 | w: IntC, 1606 | h: IntC, 1607 | ) raises -> Ptr[_Texture]: 1608 | """Create a texture for a rendering context.""" 1609 | return self.error.if_null( 1610 | self._create_texture.call(renderer, format, access, w, h), 1611 | "Could not create texture", 1612 | ) 1613 | 1614 | @always_inline 1615 | fn create_texture_from_surface(self, renderer: Ptr[_Renderer], surface: Ptr[_Surface]) raises -> Ptr[_Texture]: 1616 | """Create a texture from an existing surface.""" 1617 | return self.error.if_null( 1618 | self._create_texture_from_surface.call(renderer, surface), 1619 | "Could not create texture from surface", 1620 | ) 1621 | 1622 | @always_inline 1623 | fn destroy_texture(self, texture: Ptr[_Texture]): 1624 | """Destroy the specified texture.""" 1625 | self._destroy_texture.call(texture) 1626 | 1627 | @always_inline 1628 | fn gl_bind_texture(self, texture: Ptr[_Texture], texw: Ptr[Float32], texh: Ptr[Float32]) raises: 1629 | """Bind an OpenGL/ES/ES2 texture to the current context.""" 1630 | self.error.if_code( 1631 | self._gl_bind_texture.call(texture, texw, texh), 1632 | "Could not bind GL texture", 1633 | ) 1634 | 1635 | @always_inline 1636 | fn gl_unbind_texture(self, texture: Ptr[_Texture]) raises: 1637 | """Unbind an OpenGL/ES/ES2 texture from the current context.""" 1638 | self.error.if_code(self._gl_unbind_texture.call(texture), "Could not unbind GL texture") 1639 | 1640 | @always_inline 1641 | fn lock_texture( 1642 | self, 1643 | texture: Ptr[_Texture], 1644 | rect: Ptr[Rect], 1645 | pixels: Ptr[Ptr[NoneType]], 1646 | pitch: Ptr[IntC], 1647 | ) raises: 1648 | """Lock a portion of the texture for write-only pixel access.""" 1649 | self.error.if_code( 1650 | self._lock_texture.call(texture, rect, pixels, pitch), 1651 | "Could not lock texture", 1652 | ) 1653 | 1654 | @always_inline 1655 | fn lock_texture_to_surface( 1656 | self, 1657 | texture: Ptr[_Texture], 1658 | rect: Ptr[Rect], 1659 | surface: Ptr[Ptr[_Surface]], 1660 | ) raises: 1661 | """Lock a portion of the texture for write-only pixel access, and expose it as a SDL surface.""" 1662 | self.error.if_code( 1663 | self._lock_texture_to_surface.call(texture, rect, surface), 1664 | "Could not lock texture to surface", 1665 | ) 1666 | 1667 | @always_inline 1668 | fn unlock_texture(self, texture: Ptr[_Texture]): 1669 | """Unlock a texture, uploading the changes to video memory, if needed.""" 1670 | self._unlock_texture.call(texture) 1671 | 1672 | @always_inline 1673 | fn query_texture( 1674 | self, 1675 | texture: Ptr[_Texture], 1676 | format: Ptr[UInt32], 1677 | access: Ptr[IntC], 1678 | w: Ptr[IntC], 1679 | h: Ptr[IntC], 1680 | ) raises: 1681 | """Query the attributes of a texture.""" 1682 | self.error.if_code( 1683 | self._query_texture.call(texture, format, access, w, h), 1684 | "Could not query texture", 1685 | ) 1686 | 1687 | @always_inline 1688 | fn get_texture_color_mod( 1689 | self, 1690 | texture: Ptr[_Texture], 1691 | r: Ptr[UInt8], 1692 | g: Ptr[UInt8], 1693 | b: Ptr[UInt8], 1694 | ) raises: 1695 | """Get the additional color value multiplied into render copy operations.""" 1696 | self.error.if_code( 1697 | self._get_texture_color_mod.call(texture, r, g, b), 1698 | "Could not get texture color mod", 1699 | ) 1700 | 1701 | @always_inline 1702 | fn get_texture_alpha_mod(self, texture: Ptr[_Texture], a: Ptr[UInt8]) raises: 1703 | """Get the additional alpha value multiplied into render copy operations.""" 1704 | self.error.if_code( 1705 | self._get_texture_alpha_mod.call(texture, a), 1706 | "Could not get texture alpha mod", 1707 | ) 1708 | 1709 | @always_inline 1710 | fn get_texture_blend_mode(self, texture: Ptr[_Texture], blend_mode: Ptr[BlendMode]) raises: 1711 | """Get the blend mode used for texture copy operations.""" 1712 | self.error.if_code( 1713 | self._get_texture_blend_mode.call(texture, blend_mode), 1714 | "Could not get texture blend mode", 1715 | ) 1716 | 1717 | @always_inline 1718 | fn get_texture_scale_mode(self, texture: Ptr[_Texture], scale_mode: Ptr[ScaleMode]) raises: 1719 | """Get the scale mode used for texture scale operations.""" 1720 | self.error.if_code( 1721 | self._get_texture_scale_mode.call(texture, scale_mode), 1722 | "Could not get texture scale mode", 1723 | ) 1724 | 1725 | @always_inline 1726 | fn get_texture_user_data(self, texture: Ptr[_Texture]) raises -> Ptr[NoneType]: 1727 | """Get the user-specified pointer associated with a texture.""" 1728 | return self.error.if_null( 1729 | self._get_texture_user_data.call(texture), 1730 | "Could not get texture user data", 1731 | ) 1732 | 1733 | @always_inline 1734 | fn set_texture_color_mod(self, texture: Ptr[_Texture], r: UInt8, g: UInt8, b: UInt8) raises: 1735 | """Set an additional color value multiplied into render copy operations.""" 1736 | self.error.if_code( 1737 | self._set_texture_color_mod.call(texture, r, g, b), 1738 | "Could not set texture color mod", 1739 | ) 1740 | 1741 | @always_inline 1742 | fn set_texture_alpha_mod(self, texture: Ptr[_Texture], alpha: UInt8) raises: 1743 | """Set an additional alpha value multiplied into render copy operations.""" 1744 | self.error.if_code( 1745 | self._set_texture_alpha_mod.call(texture, alpha), 1746 | "Could not set texture alpha mod", 1747 | ) 1748 | 1749 | @always_inline 1750 | fn set_texture_blend_mode(self, texture: Ptr[_Texture], blend_mode: BlendMode) raises: 1751 | """Set the scale mode used for texture scale operations.""" 1752 | self.error.if_code( 1753 | self._set_texture_blend_mode.call(texture, blend_mode), 1754 | "Could not set texture blend mode", 1755 | ) 1756 | 1757 | @always_inline 1758 | fn set_texture_scale_mode(self, texture: Ptr[_Texture], scale_mode: ScaleMode) raises: 1759 | """Set the scale mode used for texture scale operations.""" 1760 | self.error.if_code( 1761 | self._set_texture_scale_mode.call(texture, scale_mode), 1762 | "Could not set texture scale mode", 1763 | ) 1764 | 1765 | @always_inline 1766 | fn set_texture_user_data(self, texture: Ptr[_Texture], user_data: Ptr[NoneType]) raises: 1767 | """Associate a user-specified pointer with a texture.""" 1768 | self.error.if_code( 1769 | self._set_texture_user_data.call(texture, user_data), 1770 | "Could not set texture user data", 1771 | ) 1772 | 1773 | @always_inline 1774 | fn update_texture( 1775 | self, 1776 | texture: Ptr[_Texture], 1777 | rect: Ptr[Rect], 1778 | pixels: Ptr[NoneType], 1779 | pitch: IntC, 1780 | ) raises: 1781 | """Update the given texture rectangle with new pixel data.""" 1782 | self.error.if_code( 1783 | self._update_texture.call(texture, rect, pixels, pitch), 1784 | "Could not update texture", 1785 | ) 1786 | 1787 | @always_inline 1788 | fn update_nv_texture( 1789 | self, 1790 | texture: Ptr[_Texture], 1791 | rect: Ptr[Rect], 1792 | y_plane: Ptr[UInt8], 1793 | y_pitch: IntC, 1794 | uv_plane: Ptr[UInt8], 1795 | uv_pitch: IntC, 1796 | ) raises: 1797 | """Update a rectangle within a planar NV12 or NV21 texture with new pixels.""" 1798 | self.error.if_code( 1799 | self._update_nv_texture.call(texture, rect, y_plane, y_pitch, uv_plane, uv_pitch), 1800 | "Could not update nv texture", 1801 | ) 1802 | 1803 | @always_inline 1804 | fn update_yuv_texture( 1805 | self, 1806 | texture: Ptr[_Texture], 1807 | rect: Ptr[Rect], 1808 | y_plane: Ptr[UInt8], 1809 | y_pitch: Int, 1810 | u_plane: Ptr[UInt8], 1811 | u_pitch: Int, 1812 | v_plane: Ptr[UInt8], 1813 | v_pitch: Int, 1814 | ) raises: 1815 | """Update a rectangle within a planar YV12 or IYUV texture with new pixel data.""" 1816 | self.error.if_code( 1817 | self._update_yuv_texture.call( 1818 | texture, 1819 | rect, 1820 | y_plane, 1821 | y_pitch, 1822 | u_plane, 1823 | u_pitch, 1824 | v_plane, 1825 | v_pitch, 1826 | ), 1827 | "Could not update yuv texture", 1828 | ) 1829 | 1830 | # +--- opengl functions 1831 | 1832 | fn gl_create_context(self, window: Ptr[_Window]) raises -> Ptr[_GLContext]: 1833 | return self.error.if_null(self._gl_create_context.call(window), "Could not create gl context") 1834 | 1835 | fn gl_delete_context(self, gl_context: Ptr[_GLContext]): 1836 | self._gl_delete_context.call(gl_context) 1837 | -------------------------------------------------------------------------------- /src/error.mojo: -------------------------------------------------------------------------------- 1 | """Defines an SDL_Error.""" 2 | 3 | from sys.ffi import DLHandle 4 | from ._sdl import SDL_Fn 5 | 6 | 7 | @value 8 | @register_passable("trivial") 9 | struct SDL_Error: 10 | """A wrapper around sdl errors.""" 11 | 12 | var _get_error: SDL_Fn["SDL_GetError", fn () -> Ptr[CharC]] 13 | var _set_error: SDL_Fn["SDL_SetError", fn (Ptr[CharC]) -> IntC] 14 | var _clear_error: SDL_Fn["SDL_ClearError", fn () -> NoneType] 15 | 16 | @always_inline("nodebug") 17 | fn __init__(inout self, _handle: DLHandle): 18 | self._get_error = _handle 19 | self._set_error = _handle 20 | self._clear_error = _handle 21 | 22 | @always_inline("nodebug") 23 | fn __call__(self) -> Error: 24 | @parameter 25 | if error_level == 2: 26 | return String.format_sequence("SDL_Error: ", String(self._get_error.call())) 27 | else: 28 | return "SDL_Error" 29 | 30 | @always_inline("nodebug") 31 | fn __call__(self, msg: StringLiteral) -> Error: 32 | @parameter 33 | if error_level == 2: 34 | return String.format_sequence("SDL_Error: ", msg, ", ", String(self._get_error.call())) 35 | else: 36 | return String.format_sequence("SDL_Error: ", msg) 37 | 38 | @always_inline("nodebug") 39 | fn set_error(self, fmt: StringLiteral) raises: 40 | _ = self._set_error.call(fmt.unsafe_cstr_ptr().bitcast[CharC]()) 41 | raise self(fmt) 42 | 43 | @always_inline("nodebug") 44 | fn clear_error(self): 45 | self._clear_error.call() 46 | 47 | @always_inline("nodebug") 48 | fn if_null(self, ptr: Ptr, msg: StringLiteral) raises -> __type_of(ptr): 49 | """Raises an error if the pointer is null.""" 50 | if ptr: 51 | return ptr 52 | 53 | @parameter 54 | if error_level > 0: 55 | raise self(msg) 56 | 57 | @always_inline("nodebug") 58 | fn if_code(self, code: IntC, msg: StringLiteral) raises: 59 | """Raises an error if the error code is not zero.""" 60 | 61 | @parameter 62 | if error_level > 0: 63 | if code != 0: 64 | raise self(msg) 65 | -------------------------------------------------------------------------------- /src/events.mojo: -------------------------------------------------------------------------------- 1 | """Defines SDL Events.""" 2 | 3 | from utils import Variant 4 | from ._sdl import _SDL 5 | 6 | 7 | struct EventType: 8 | alias FIRSTEVENT = 0 9 | """Unused (do not remove).""" 10 | 11 | # Application events 12 | alias QUIT = 0x100 13 | """User-requested quit.""" 14 | 15 | # These application events have special meaning on iOS, see README-ios.md for details 16 | alias APP_TERMINATING = 0x101 17 | """ 18 | The application is being terminated by the OS 19 | Called on iOS in applicationWillTerminate() 20 | Called on Android in onDestroy(). 21 | """ 22 | 23 | alias APP_LOWMEMORY = 0x102 24 | """ 25 | The application is low on memory, free memory if possible. 26 | Called on iOS in applicationDidReceiveMemoryWarning(). 27 | Called on Android in onLowMemory(). 28 | """ 29 | 30 | alias APP_WILLENTERBACKGROUND = 0x103 31 | """ 32 | The application is about to enter the background. 33 | Called on iOS in applicationWillResignActive(). 34 | Called on Android in onPause(). 35 | """ 36 | 37 | alias APP_DIDENTERBACKGROUND = 0x104 38 | """ 39 | The application did enter the background and may not get CPU for some time. 40 | Called on iOS in applicationDidEnterBackground(). 41 | Called on Android in onPause(). 42 | """ 43 | 44 | alias APP_WILLENTERFOREGROUND = 0x105 45 | """ 46 | The application is about to enter the foreground. 47 | Called on iOS in applicationWillEnterForeground(). 48 | Called on Android in onResume(). 49 | """ 50 | 51 | alias APP_DIDENTERFOREGROUND = 0x106 52 | """ 53 | The application is now interactive. 54 | Called on iOS in applicationDidBecomeActive(). 55 | Called on Android in onResume(). 56 | """ 57 | 58 | alias LOCALECHANGED = 0x107 59 | """The user's locale preferences have changed.""" 60 | 61 | # Display events 62 | alias DISPLAYEVENT = 0x150 63 | """Display state change.""" 64 | 65 | # Window events 66 | alias WINDOWEVENT = 0x200 67 | """Window state change.""" 68 | 69 | alias SYSWMEVENT = 0x201 70 | """System specific event.""" 71 | 72 | # Keyboard events 73 | alias KEYDOWN = 0x300 74 | """Key pressed.""" 75 | 76 | alias KEYUP = 0x301 77 | """Key released.""" 78 | 79 | alias TEXTEDITING = 0x302 80 | """Keyboard text editing (composition).""" 81 | 82 | alias TEXTINPUT = 0x303 83 | """Keyboard text input.""" 84 | 85 | alias KEYMAPCHANGED = 0x304 86 | """Keymap changed due to a system event such as an input language or keyboard layout change.""" 87 | 88 | alias TEXTEDITING_EXT = 0x305 89 | """Extended keyboard text editing (composition).""" 90 | 91 | # Mouse events 92 | alias MOUSEMOTION = 0x400 93 | """Mouse moved.""" 94 | 95 | alias MOUSEBUTTONDOWN = 0x401 96 | """Mouse button pressed.""" 97 | 98 | alias MOUSEBUTTONUP = 0x402 99 | """Mouse button released.""" 100 | 101 | alias MOUSEWHEEL = 0x403 102 | """Mouse wheel motion.""" 103 | 104 | # Joystick events 105 | alias JOYAXISMOTION = 0x600 106 | """Joystick axis motion.""" 107 | 108 | alias JOYBALLMOTION = 0x601 109 | """Joystick trackball motion.""" 110 | 111 | alias JOYHATMOTION = 0x602 112 | """Joystick hat position change.""" 113 | 114 | alias JOYBUTTONDOWN = 0x603 115 | """Joystick button pressed.""" 116 | 117 | alias JOYBUTTONUP = 0x604 118 | """Joystick button released.""" 119 | 120 | alias JOYDEVICEADDED = 0x605 121 | """A new joystick has been inserted into the system.""" 122 | 123 | alias JOYDEVICEREMOVED = 0x606 124 | """An opened joystick has been removed.""" 125 | 126 | alias JOYBATTERYUPDATED = 0x607 127 | """Joystick battery level change.""" 128 | 129 | # Game controller events 130 | alias CONTROLLERAXISMOTION = 0x650 131 | """Game controller axis motion.""" 132 | 133 | alias CONTROLLERBUTTONDOWN = 0x651 134 | """Game controller button pressed.""" 135 | 136 | alias CONTROLLERBUTTONUP = 0x652 137 | """Game controller button released.""" 138 | 139 | alias CONTROLLERDEVICEADDED = 0x653 140 | """A new Game controller has been inserted into the system.""" 141 | 142 | alias CONTROLLERDEVICEREMOVED = 0x654 143 | """An opened Game controller has been removed.""" 144 | 145 | alias CONTROLLERDEVICEREMAPPED = 0x655 146 | """The controller mapping was updated.""" 147 | 148 | alias CONTROLLERTOUCHPADDOWN = 0x656 149 | """Game controller touchpad was touched.""" 150 | 151 | alias CONTROLLERTOUCHPADMOTION = 0x657 152 | """Game controller touchpad finger was moved.""" 153 | 154 | alias CONTROLLERTOUCHPADUP = 0x658 155 | """Game controller touchpad finger was lifted.""" 156 | 157 | alias CONTROLLERSENSORUPDATE = 0x659 158 | """Game controller sensor was updated.""" 159 | 160 | alias CONTROLLERUPDATECOMPLETE_RESERVED_FOR_SDL3 = 0x65A 161 | 162 | alias CONTROLLERSTEAMHANDLEUPDATED = 0x65B 163 | """Game controller Steam handle has changed.""" 164 | 165 | # Touch events 166 | alias FINGERDOWN = 0x700 167 | alias FINGERUP = 0x701 168 | alias FINGERMOTION = 0x702 169 | 170 | # Gesture events 171 | alias DOLLARGESTURE = 0x800 172 | alias DOLLARRECORD = 0x801 173 | alias MULTIGESTURE = 0x802 174 | 175 | # Clipboard events 176 | alias CLIPBOARDUPDATE = 0x900 177 | """The clipboard or primary selection changed.""" 178 | 179 | # Drag and drop events 180 | alias DROPFILE = 0x1000 181 | """The system requests a file open.""" 182 | 183 | alias DROPTEXT = 0x1001 184 | """text/plain drag-and-drop event.""" 185 | 186 | alias DROPBEGIN = 0x1002 187 | """A new set of drops is beginning (NULL filename).""" 188 | 189 | alias DROPCOMPLETE = 0x1003 190 | """Current set of drops is now complete (NULL filename).""" 191 | 192 | # Audio hotplug events 193 | alias AUDIODEVICEADDED = 0x1100 194 | """A new audio device is available.""" 195 | 196 | alias AUDIODEVICEREMOVED = 0x1101 197 | """An audio device has been removed.""" 198 | 199 | # Sensor events 200 | alias SENSORUPDATE = 0x1200 201 | """A sensor was updated.""" 202 | 203 | # Render events 204 | alias RENDER_TARGETS_RESET = 0x2000 205 | """The render targets have been reset and their contents need to be updated.""" 206 | 207 | alias RENDER_DEVICE_RESET = 0x2001 208 | """The device has been reset and all textures need to be recreated.""" 209 | 210 | # Internal events 211 | alias POLLSENTINEL = 0x7F00 212 | """Signals the end of an event poll cycle.""" 213 | 214 | # Events SDL_USEREVENT through SDL_LASTEVENT are for your use, 215 | # and should be allocated with SDL_RegisterEvents() 216 | alias USEREVENT = 0x8000 217 | 218 | # This last event is only for bounding internal arrays 219 | alias LASTEVENT = 0xFFFF 220 | 221 | 222 | alias Event = Variant[ 223 | QuitEvent, 224 | DisplayEvent, 225 | WindowEvent, 226 | KeyDownEvent, 227 | KeyUpEvent, 228 | TextEditingEvent, 229 | TextInputEvent, 230 | KeyMapChangedEvent, 231 | MouseMotionEvent, 232 | MouseButtonEvent, 233 | MouseWheelEvent, 234 | AudioDeviceEvent, 235 | ] 236 | 237 | 238 | # alias C_EventAction = Variant[C_ADDEVENT, C_PEEKEVENT, C_GETEVENT] 239 | # @value 240 | # struct C_ADDEVENT: pass 241 | # @value 242 | # struct C_PEEKEVENT: pass 243 | # @value 244 | # struct C_GETEVENT: pass 245 | 246 | 247 | @value 248 | @register_passable("trivial") 249 | struct _Event: 250 | """Total size is 56 bytes.""" 251 | 252 | var type: UInt32 253 | var data0: SIMD[DType.uint8, 4] 254 | var data1: SIMD[DType.uint8, 16] 255 | var data2: SIMD[DType.uint8, 32] 256 | 257 | fn __init__(inout self): 258 | self.type = 0 259 | self.data0 = 0 260 | self.data1 = 0 261 | self.data2 = 0 262 | 263 | @staticmethod 264 | fn to_event(_event: Ptr[_Event]) -> Event: 265 | if _event[].type == EventType.QUIT: 266 | return _event.bitcast[QuitEvent]()[] 267 | elif _event[].type == EventType.DISPLAYEVENT: 268 | return _event.bitcast[DisplayEvent]()[] 269 | elif _event[].type == EventType.WINDOWEVENT: 270 | return _event.bitcast[WindowEvent]()[] 271 | elif _event[].type == EventType.KEYDOWN: 272 | return _event.bitcast[KeyDownEvent]()[] 273 | elif _event[].type == EventType.KEYUP: 274 | return _event.bitcast[KeyUpEvent]()[] 275 | elif _event[].type == EventType.TEXTEDITING: 276 | return _event.bitcast[TextEditingEvent]()[] 277 | elif _event[].type == EventType.TEXTINPUT: 278 | return _event.bitcast[TextInputEvent]()[] 279 | elif _event[].type == EventType.KEYMAPCHANGED: 280 | return _event.bitcast[KeyMapChangedEvent]()[] 281 | elif _event[].type == EventType.MOUSEMOTION: 282 | return _event.bitcast[MouseMotionEvent]()[] 283 | elif _event[].type == EventType.MOUSEBUTTONDOWN or _event[].type == EventType.MOUSEBUTTONUP: 284 | return _event.bitcast[MouseButtonEvent]()[] 285 | elif _event[].type == EventType.MOUSEWHEEL: 286 | return _event.bitcast[MouseWheelEvent]()[] 287 | elif _event[].type == EventType.AUDIODEVICEADDED or _event[].type == EventType.AUDIODEVICEREMOVED: 288 | return _event.bitcast[AudioDeviceEvent]()[] 289 | else: 290 | print("Unhandled event type: " + str(_event[].type)) 291 | return _event.bitcast[QuitEvent]()[] 292 | 293 | 294 | @value 295 | @register_passable("trivial") 296 | struct QuitEvent: 297 | var _type: UInt32 298 | var timestamp: UInt32 299 | 300 | 301 | @value 302 | @register_passable("trivial") 303 | struct DisplayEvent: 304 | var type: UInt32 305 | """SDL_DISPLAYEVENT.""" 306 | var timestamp: UInt32 307 | """In milliseconds, populated using SDL_GetTicks().""" 308 | var display: UInt32 309 | """The associated display index.""" 310 | var event: UInt8 311 | """SDL_DisplayEventID.""" 312 | var padding1: UInt8 313 | var padding2: UInt8 314 | var padding3: UInt8 315 | var data1: Int32 316 | """Event dependent data.""" 317 | 318 | 319 | @value 320 | @register_passable("trivial") 321 | struct WindowEvent: 322 | """Window state change event data (event.window.*).""" 323 | 324 | var _type: UInt32 325 | """SDL_WINDOWEVENT.""" 326 | var timestamp: UInt32 327 | """In milliseconds, populated using SDL_GetTicks().""" 328 | var window_id: UInt32 329 | """The associated window.""" 330 | var event: UInt8 331 | """SDL_WindowEventID.""" 332 | var _padding1: UInt8 333 | var _padding2: UInt8 334 | var _padding3: UInt8 335 | var data1: Int32 336 | """Event dependent data.""" 337 | var data2: Int32 338 | """Event dependent data.""" 339 | 340 | 341 | struct WindowEventID: 342 | """Event subtype for window events.""" 343 | 344 | alias WINDOWEVENT_NONE: IntC = 0 345 | """Never used.""" 346 | alias WINDOWEVENT_SHOWN: IntC = 1 347 | """Window has been shown.""" 348 | alias WINDOWEVENT_HIDDEN: IntC = 2 349 | """Window has been hidden.""" 350 | alias WINDOWEVENT_EXPOSED: IntC = 3 351 | """Window has been exposed and should be redrawn.""" 352 | alias WINDOWEVENT_MOVED: IntC = 4 353 | """Window has been moved to data1, data2.""" 354 | alias WINDOWEVENT_RESIZED: IntC = 5 355 | """Window has been resized to data1xdata2.""" 356 | alias WINDOWEVENT_SIZE_CHANGED: IntC = 6 357 | """The window size has changed, either as a result of an API call or through the system or user changing the window size.""" 358 | alias WINDOWEVENT_MINIMIZED: IntC = 7 359 | """Window has been minimized.""" 360 | alias WINDOWEVENT_MAXIMIZED: IntC = 8 361 | """Window has been maximized.""" 362 | alias WINDOWEVENT_RESTORED: IntC = 9 363 | """Window has been restored to normal size and position.""" 364 | alias WINDOWEVENT_ENTER: IntC = 10 365 | """Window has gained mouse focus.""" 366 | alias WINDOWEVENT_LEAVE: IntC = 11 367 | """Window has lost mouse focus.""" 368 | alias WINDOWEVENT_FOCUS_GAINED: IntC = 12 369 | """Window has gained keyboard focus.""" 370 | alias WINDOWEVENT_FOCUS_LOST: IntC = 13 371 | """Window has lost keyboard focus.""" 372 | alias WINDOWEVENT_CLOSE: IntC = 14 373 | """The window manager requests that the window be closed.""" 374 | alias WINDOWEVENT_TAKE_FOCUS: IntC = 15 375 | """Window is being offered a focus (should SetWindowInputFocus() on itself or a subwindow, or ignore).""" 376 | alias WINDOWEVENT_HIT_TEST: IntC = 16 377 | """Window had a hit test that wasn't SDL_HITTEST_NORMAL.""" 378 | alias WINDOWEVENT_ICCPROF_CHANGED: IntC = 17 379 | """The ICC profile of the window's display has changed.""" 380 | alias WINDOWEVENT_DISPLAY_CHANGED: IntC = 18 381 | """Window has been moved to display data1.""" 382 | 383 | 384 | @value 385 | @register_passable("trivial") 386 | struct KeyDownEvent: 387 | var _type: UInt32 388 | var timestamp: UInt32 389 | var window_id: UInt32 390 | var state: UInt8 391 | var repeat: UInt8 392 | var _padding2: UInt8 393 | var _padding3: UInt8 394 | var keysym: Keysym 395 | 396 | fn __getattr__[name: StringLiteral](self) -> Int32: 397 | constrained[name == "key", "Not a valid attr"]() 398 | return self.keysym.sym 399 | 400 | 401 | @value 402 | @register_passable("trivial") 403 | struct KeyUpEvent: 404 | var _type: UInt32 405 | var timestamp: UInt32 406 | var window_id: UInt32 407 | var state: UInt8 408 | var repeat: UInt8 409 | var _padding2: UInt8 410 | var _padding3: UInt8 411 | var keysym: Keysym 412 | 413 | fn __getattr__[name: StringLiteral](self) -> Int32: 414 | constrained[name == "key", "Not a valid attr"]() 415 | return self.keysym.sym 416 | 417 | 418 | @value 419 | @register_passable("trivial") 420 | struct Keysym: 421 | var scancode: UInt32 422 | var sym: Int32 423 | var mode: UInt16 424 | var unused: UInt32 425 | 426 | 427 | @value 428 | @register_passable("trivial") 429 | struct TextEditingEvent: 430 | var type: UInt32 431 | var timestamp: UInt32 432 | var window_id: UInt32 433 | var text: Ptr[CharC] 434 | var start: Int32 435 | var length: Int32 436 | 437 | 438 | @value 439 | @register_passable("trivial") 440 | struct TextInputEvent: 441 | var _type: UInt32 442 | var timestamp: UInt32 443 | var window_id: UInt32 444 | var text: Ptr[CharC] 445 | 446 | 447 | @value 448 | @register_passable("trivial") 449 | struct KeyMapChangedEvent: 450 | var _type: UInt32 451 | var timestamp: UInt32 452 | 453 | 454 | @value 455 | @register_passable("trivial") 456 | struct MouseMotionEvent: 457 | var type: UInt32 458 | var timestamp: UInt32 459 | var window_id: UInt32 460 | var which: UInt32 461 | var state: UInt32 462 | var x: UInt8 463 | var y: UInt8 464 | var xrel: Int32 465 | var yrel: Int32 466 | 467 | 468 | @value 469 | @register_passable("trivial") 470 | struct MouseButtonEvent: 471 | var type: UInt32 472 | var timestamp: UInt32 473 | var window_id: UInt32 474 | var which: UInt32 475 | var button: UInt8 476 | var state: UInt8 477 | var clicks: UInt8 478 | var _padding1: UInt8 479 | var x: Int32 480 | var y: Int32 481 | 482 | 483 | @value 484 | @register_passable("trivial") 485 | struct MouseWheelEvent: 486 | """Mouse wheel event structure (event.wheel.*).""" 487 | 488 | var type: UInt32 489 | """SDL_MOUSEWHEEL.""" 490 | var timestamp: UInt32 491 | """In milliseconds, populated using SDL_GetTicks().""" 492 | var windowID: UInt32 493 | """The window with mouse focus, if any.""" 494 | var which: UInt32 495 | """The mouse instance id, or SDL_TOUCH_MOUSEID.""" 496 | var x: Int32 497 | """The amount scrolled horizontally, positive to the right and negative to the left.""" 498 | var y: Int32 499 | """The amount scrolled vertically, positive away from the user and negative toward the user.""" 500 | var direction: UInt32 501 | """Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back.""" 502 | var preciseX: Float32 503 | """The amount scrolled horizontally, positive to the right and negative to the left, with float precision (added in 2.0.18).""" 504 | var preciseY: Float32 505 | """The amount scrolled vertically, positive away from the user and negative toward the user, with float precision (added in 2.0.18).""" 506 | var mouseX: Int32 507 | """X coordinate, relative to window (added in 2.26.0).""" 508 | var mouseY: Int32 509 | """Y coordinate, relative to window (added in 2.26.0).""" 510 | 511 | 512 | @value 513 | @register_passable("trivial") 514 | struct AudioDeviceEvent: 515 | var type: UInt32 516 | var timestamp: UInt32 517 | var which: UInt32 518 | var iscapture: UInt8 519 | 520 | 521 | # # var _peep_events = _sdl.get_function[fn(Ptr[C_Event], Int32, UInt8, UInt32, UInt32) -> Int32]('SDL_PeepEvents') 522 | # # fn peep_events(events: Ptr[C_Event], numevents: Int32, action: C_EventAction, min_type: Int32, max_type: Int32) -> Int32: 523 | -------------------------------------------------------------------------------- /src/gfx/__init__.mojo: -------------------------------------------------------------------------------- 1 | """Defines SDL_gfx bindings and wrappers for use in Mojo.""" 2 | 3 | from sys import DLHandle, os_is_macos, os_is_linux 4 | from collections import Optional 5 | from .._sdl import SDL_Fn 6 | from ..surface import _Surface 7 | from ..render import _Renderer 8 | from builtin.constrained import constrained 9 | 10 | 11 | struct _GFX: 12 | """Raw bindings to sdl_gfx.""" 13 | 14 | var _handle: DLHandle 15 | var error: SDL_Error 16 | 17 | var _rotozoom_surface: SDL_Fn[ 18 | "rotozoomSurface", 19 | fn (UnsafePointer[_Surface], Float64, Float64, Int32) -> UnsafePointer[_Surface], 20 | ] 21 | var _circle_color: SDL_Fn[ 22 | "circleColor", 23 | fn (UnsafePointer[_Renderer], Int16, Int16, Int16, UInt32) -> IntC, 24 | ] 25 | var _circle_rgba: SDL_Fn[ 26 | "circleRGBA", 27 | fn ( 28 | UnsafePointer[_Renderer], 29 | Int16, 30 | Int16, 31 | Int16, 32 | UInt8, 33 | UInt8, 34 | UInt8, 35 | UInt8, 36 | ) -> IntC, 37 | ] 38 | 39 | fn __init__(inout self, error: SDL_Error): 40 | @parameter 41 | if os_is_macos(): 42 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2_gfx.dylib") 43 | elif os_is_linux(): 44 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2_gfx.so") 45 | else: 46 | constrained[False, "OS is not supported"]() 47 | self._handle = utils._uninit[DLHandle]() 48 | 49 | self.error = error 50 | self._rotozoom_surface = self._handle 51 | self._circle_color = self._handle 52 | self._circle_rgba = self._handle 53 | 54 | fn quit(self): 55 | pass 56 | 57 | @always_inline 58 | fn rotozoom_surface(self, source: Ptr[_Surface], angle: Float64, zoom: Float64, smooth: Bool) -> Ptr[_Surface]: 59 | return self._rotozoom_surface.call(source, angle, zoom, Int32(smooth)) 60 | 61 | @always_inline 62 | fn circle_color( 63 | self, 64 | renderer: Ptr[_Renderer], 65 | x: Int16, 66 | y: Int16, 67 | rad: Int16, 68 | color: UInt32, 69 | ) raises: 70 | self.error.if_code( 71 | self._circle_color.call(renderer, x, y, rad, color), 72 | "Could not draw circle", 73 | ) 74 | 75 | @always_inline 76 | fn circle_rgba(self, renderer: Ptr[_Renderer], x: Int16, y: Int16, rad: Int16, r: UInt8, g: UInt8, b: UInt8, a: UInt8) raises: 77 | self.error.if_code(self._circle_rgba.call(renderer, x, y, rad, r, g, b, a), "Could not draw circle") 78 | -------------------------------------------------------------------------------- /src/img/__init__.mojo: -------------------------------------------------------------------------------- 1 | """Defines SDL_img bindings and wrappers for use in Mojo.""" 2 | 3 | from sys import DLHandle, os_is_macos, os_is_linux 4 | from collections import Optional 5 | from .._sdl import SDL_Fn 6 | from ..surface import _Surface 7 | from builtin.constrained import constrained 8 | 9 | 10 | struct _IMG: 11 | """Raw bindings to sdl_img.""" 12 | 13 | var _handle: DLHandle 14 | var error: SDL_Error 15 | 16 | var _img_init: SDL_Fn["IMG_Init", fn (Int32) -> Int32] 17 | var _img_quit: SDL_Fn["IMG_Quit", fn () -> NoneType] 18 | var _img_load: SDL_Fn["IMG_Load", fn (Ptr[CharC]) -> Ptr[_Surface]] 19 | 20 | fn __init__(inout self, error: SDL_Error): 21 | @parameter 22 | if os_is_macos(): 23 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2_image.dylib") 24 | elif os_is_linux(): 25 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2_image.so") 26 | else: 27 | constrained[False, "OS is not supported"]() 28 | self._handle = utils._uninit[DLHandle]() 29 | 30 | self.error = error 31 | self._img_init = self._handle 32 | self._img_quit = self._handle 33 | self._img_load = self._handle 34 | 35 | @always_inline 36 | fn init(self, flags: Int32) raises: 37 | _ = self._img_init.call(flags) 38 | # self.error.if_code(self._img_init.call(flags), "Could not initialize sdl_img") 39 | 40 | @always_inline 41 | fn quit(self): 42 | self._img_quit.call() 43 | 44 | @always_inline 45 | fn load_image(self, file: Ptr[CharC]) raises -> Ptr[_Surface]: 46 | return self.error.if_null(self._img_load.call(file), "Could not load image") 47 | -------------------------------------------------------------------------------- /src/keyboard.mojo: -------------------------------------------------------------------------------- 1 | """Defines SDL Keyboard and Keys.""" 2 | 3 | from .utils import adr 4 | from ._sdl import _SDL 5 | 6 | 7 | struct Keyboard[lif: AnyLifetime[False].type]: 8 | var sdl: Reference[SDL, lif] 9 | var state: Ptr[UInt8] 10 | 11 | fn __init__(inout self, ref [lif]sdl: SDL): 12 | self.sdl = sdl 13 | var numkeys = IntC() 14 | self.state = sdl._sdl.get_keyboard_state(adr(numkeys)) 15 | 16 | fn get_key(self, key: KeyCode) -> Bool: 17 | return bool(self.state[int(key.value)]) 18 | 19 | 20 | struct Keys: 21 | alias retvrn = ord("\r") 22 | alias escape = ord("\x1B") 23 | alias backspace = ord("\b") 24 | alias tab = ord("\t") 25 | alias space = ord(" ") 26 | alias exclaim = ord("!") 27 | alias quotedbl = ord('"') 28 | alias hash = ord("#") 29 | alias percent = ord("%") 30 | alias dollar = ord("$") 31 | alias ampersand = ord("&") 32 | alias quote = ord("'") 33 | alias leftparen = ord("(") 34 | alias rightparen = ord(")") 35 | alias asterisk = ord("*") 36 | alias plus = ord("+") 37 | alias comma = ord(",") 38 | alias minus = ord("-") 39 | alias period = ord(".") 40 | alias slash = ord("/") 41 | alias n0 = ord("0") 42 | alias n1 = ord("1") 43 | alias n2 = ord("2") 44 | alias n3 = ord("3") 45 | alias n4 = ord("4") 46 | alias n5 = ord("5") 47 | alias n6 = ord("6") 48 | alias n7 = ord("7") 49 | alias n8 = ord("8") 50 | alias n9 = ord("9") 51 | alias colon = ord(":") 52 | alias semicolon = ord(";") 53 | alias less = ord("<") 54 | alias equals = ord("=") 55 | alias greater = ord(">") 56 | alias question = ord("?") 57 | alias at = ord("@") 58 | # skip uppercase letters 59 | alias leftbracket = ord("[") 60 | alias backslash = ord("\\") 61 | alias rightbracket = ord("]") 62 | alias caret = ord("^") 63 | alias underscore = ord("_") 64 | alias backquote = ord("`") 65 | alias a = ord("a") 66 | alias b = ord("b") 67 | alias c = ord("c") 68 | alias d = ord("d") 69 | alias e = ord("e") 70 | alias f = ord("f") 71 | alias g = ord("g") 72 | alias h = ord("h") 73 | alias i = ord("i") 74 | alias j = ord("j") 75 | alias k = ord("k") 76 | alias l = ord("l") 77 | alias m = ord("m") 78 | alias n = ord("n") 79 | alias o = ord("o") 80 | alias p = ord("p") 81 | alias q = ord("q") 82 | alias r = ord("r") 83 | alias s = ord("s") 84 | alias t = ord("t") 85 | alias u = ord("u") 86 | alias v = ord("v") 87 | alias w = ord("w") 88 | alias x = ord("x") 89 | alias y = ord("y") 90 | alias z = ord("z") 91 | 92 | 93 | @value 94 | @register_passable("trivial") 95 | struct KeyCode: 96 | var value: IntC 97 | 98 | alias UNKNOWN = 0 99 | 100 | alias A = 4 101 | alias B = 5 102 | alias C = 6 103 | alias D = 7 104 | alias E = 8 105 | alias F = 9 106 | alias G = 10 107 | alias H = 11 108 | alias I = 12 109 | alias J = 13 110 | alias K = 14 111 | alias L = 15 112 | alias M = 16 113 | alias N = 17 114 | alias O = 18 115 | alias P = 19 116 | alias Q = 20 117 | alias R = 21 118 | alias S = 22 119 | alias T = 23 120 | alias U = 24 121 | alias V = 25 122 | alias W = 26 123 | alias X = 27 124 | alias Y = 28 125 | alias Z = 29 126 | 127 | alias _1 = 30 128 | alias _2 = 31 129 | alias _3 = 32 130 | alias _4 = 33 131 | alias _5 = 34 132 | alias _6 = 35 133 | alias _7 = 36 134 | alias _8 = 37 135 | alias _9 = 38 136 | alias _0 = 39 137 | 138 | alias RETURN = 40 139 | alias ESCAPE = 41 140 | alias BACKSPACE = 42 141 | alias TAB = 43 142 | alias SPACE = 44 143 | 144 | alias MINUS = 45 145 | alias EQUALS = 46 146 | alias LEFTBRACKET = 47 147 | alias RIGHTBRACKET = 48 148 | alias BACKSLASH = 49 149 | """Located at the lower left of the return 150 | key on ISO keyboards and at the right end 151 | of the QWERTY row on ANSI keyboards. 152 | Produces REVERSE SOLIDUS (backslash) and 153 | VERTICAL LINE in a US layout, REVERSE 154 | SOLIDUS and VERTICAL LINE in a UK Mac 155 | layout, NUMBER SIGN and TILDE in a UK 156 | Windows layout, DOLLAR SIGN and POUND SIGN 157 | in a Swiss German layout, NUMBER SIGN and 158 | APOSTROPHE in a German layout, GRAVE 159 | ACCENT and POUND SIGN in a French Mac 160 | layout, and ASTERISK and MICRO SIGN in a 161 | French Windows layout.""" 162 | alias NONUSHASH = 50 163 | """ISO USB keyboards actually use this code 164 | instead of 49 for the same key, but all 165 | OSes I've seen treat the two codes 166 | identically. So, as an implementor, unless 167 | your keyboard generates both of those 168 | codes and your OS treats them differently, 169 | you should generate SDL_SCANCODE_BACKSLASH 170 | instead of this code. As a user, you 171 | should not rely on this code because SDL 172 | will never generate it with most (all?) 173 | keyboards.""" 174 | alias SEMICOLON = 51 175 | alias APOSTROPHE = 52 176 | alias GRAVE = 53 177 | """Located in the top left corner (on both ANSI 178 | and ISO keyboards). Produces GRAVE ACCENT and 179 | TILDE in a US Windows layout and in US and UK 180 | Mac layouts on ANSI keyboards, GRAVE ACCENT 181 | and NOT SIGN in a UK Windows layout, SECTION 182 | SIGN and PLUS-MINUS SIGN in US and UK Mac 183 | layouts on ISO keyboards, SECTION SIGN and 184 | DEGREE SIGN in a Swiss German layout (Mac: 185 | only on ISO keyboards), CIRCUMFLEX ACCENT and 186 | DEGREE SIGN in a German layout (Mac: only on 187 | ISO keyboards), SUPERSCRIPT TWO and TILDE in a 188 | French Windows layout, COMMERCIAL AT and 189 | NUMBER SIGN in a French Mac layout on ISO 190 | keyboards, and LESS-THAN SIGN and GREATER-THAN 191 | SIGN in a Swiss German, German, or French Mac 192 | layout on ANSI keyboards.""" 193 | alias COMMA = 54 194 | alias PERIOD = 55 195 | alias SLASH = 56 196 | 197 | alias CAPSLOCK = 57 198 | 199 | alias F1 = 58 200 | alias F2 = 59 201 | alias F3 = 60 202 | alias F4 = 61 203 | alias F5 = 62 204 | alias F6 = 63 205 | alias F7 = 64 206 | alias F8 = 65 207 | alias F9 = 66 208 | alias F10 = 67 209 | alias F11 = 68 210 | alias F12 = 69 211 | 212 | alias PRINTSCREEN = 70 213 | alias SCROLLLOCK = 71 214 | alias PAUSE = 72 215 | alias INSERT = 73 216 | """insert on PC, help on some Mac keyboards (but does send code 73, not 117).""" 217 | alias HOME = 74 218 | alias PAGEUP = 75 219 | alias DELETE = 76 220 | alias END = 77 221 | alias PAGEDOWN = 78 222 | alias RIGHT = 79 223 | alias LEFT = 80 224 | alias DOWN = 81 225 | alias UP = 82 226 | 227 | alias NUMLOCKCLEAR = 83 228 | """num lock on PC, clear on Mac keyboards.""" 229 | alias KP_DIVIDE = 84 230 | alias KP_MULTIPLY = 85 231 | alias KP_MINUS = 86 232 | alias KP_PLUS = 87 233 | alias KP_ENTER = 88 234 | alias KP_1 = 89 235 | alias KP_2 = 90 236 | alias KP_3 = 91 237 | alias KP_4 = 92 238 | alias KP_5 = 93 239 | alias KP_6 = 94 240 | alias KP_7 = 95 241 | alias KP_8 = 96 242 | alias KP_9 = 97 243 | alias KP_0 = 98 244 | alias KP_PERIOD = 99 245 | 246 | alias NONUSBACKSLASH = 100 247 | """This is the additional key that ISO 248 | keyboards have over ANSI ones, 249 | located between left shift and Y. 250 | Produces GRAVE ACCENT and TILDE in a 251 | US or UK Mac layout, REVERSE SOLIDUS 252 | (backslash) and VERTICAL LINE in a 253 | US or UK Windows layout, and 254 | LESS-THAN SIGN and GREATER-THAN SIGN 255 | in a Swiss German, German, or French 256 | layout.""" 257 | alias APPLICATION = 101 258 | """Windows contextual menu, compose.""" 259 | alias POWER = 102 260 | """The USB document says this is a status flag, not a physical key - but some Mac keyboards do have a power key.""" 261 | alias KP_EQUALS = 103 262 | alias F13 = 104 263 | alias F14 = 105 264 | alias F15 = 106 265 | alias F16 = 107 266 | alias F17 = 108 267 | alias F18 = 109 268 | alias F19 = 110 269 | alias F20 = 111 270 | alias F21 = 112 271 | alias F22 = 113 272 | alias F23 = 114 273 | alias F24 = 115 274 | alias EXECUTE = 116 275 | alias HELP = 117 276 | """Integrated Help Center.""" 277 | alias MENU = 118 278 | """Menu (show menu).""" 279 | alias SELECT = 119 280 | alias STOP = 120 281 | """Stop.""" 282 | alias AGAIN = 121 283 | """Redo/Repeat.""" 284 | alias UNDO = 122 285 | """Undo.""" 286 | alias CUT = 123 287 | """Cut.""" 288 | alias COPY = 124 289 | """Copy.""" 290 | alias PASTE = 125 291 | """Paste.""" 292 | alias FIND = 126 293 | """Find.""" 294 | alias MUTE = 127 295 | alias VOLUMEUP = 128 296 | alias VOLUMEDOWN = 129 297 | alias LOCKINGCAPSLOCK = 130 298 | """Possibly useless.""" 299 | alias LOCKINGNUMLOCK = 131 300 | """Possibly useless.""" 301 | alias LOCKINGSCROLLLOCK = 132 302 | """Possibly useless.""" 303 | alias KP_COMMA = 133 304 | alias KP_EQUALSAS400 = 134 305 | 306 | alias INTERNATIONAL1 = 135 307 | """used on Asian keyboards, see footnotes in USB doc.""" 308 | alias INTERNATIONAL2 = 136 309 | alias INTERNATIONAL3 = 137 310 | """Yen.""" 311 | alias INTERNATIONAL4 = 138 312 | alias INTERNATIONAL5 = 139 313 | alias INTERNATIONAL6 = 140 314 | alias INTERNATIONAL7 = 141 315 | alias INTERNATIONAL8 = 142 316 | alias INTERNATIONAL9 = 143 317 | alias LANG1 = 144 318 | """Hangul/English toggle.""" 319 | alias LANG2 = 145 320 | """Hanja conversion.""" 321 | alias LANG3 = 146 322 | """Katakana.""" 323 | alias LANG4 = 147 324 | """Hiragana.""" 325 | alias LANG5 = 148 326 | """Zenkaku/Hankaku.""" 327 | alias LANG6 = 149 328 | """Reserved.""" 329 | alias LANG7 = 150 330 | """Reserved.""" 331 | alias LANG8 = 151 332 | """Reserved.""" 333 | alias LANG9 = 152 334 | """Reserved.""" 335 | 336 | alias ALTERASE = 153 337 | """Erase-Eaze.""" 338 | alias SYSREQ = 154 339 | alias CANCEL = 155 340 | """Cancel.""" 341 | alias CLEAR = 156 342 | alias PRIOR = 157 343 | alias RETURN2 = 158 344 | alias SEPARATOR = 159 345 | alias OUT = 160 346 | alias OPER = 161 347 | alias CLEARAGAIN = 162 348 | alias CRSEL = 163 349 | alias EXSEL = 164 350 | 351 | alias KP_00 = 176 352 | alias KP_000 = 177 353 | alias THOUSANDSSEPARATOR = 178 354 | alias DECIMALSEPARATOR = 179 355 | alias CURRENCYUNIT = 180 356 | alias CURRENCYSUBUNIT = 181 357 | alias KP_LEFTPAREN = 182 358 | alias KP_RIGHTPAREN = 183 359 | alias KP_LEFTBRACE = 184 360 | alias KP_RIGHTBRACE = 185 361 | alias KP_TAB = 186 362 | alias KP_BACKSPACE = 187 363 | alias KP_A = 188 364 | alias KP_B = 189 365 | alias KP_C = 190 366 | alias KP_D = 191 367 | alias KP_E = 192 368 | alias KP_F = 193 369 | alias KP_XOR = 194 370 | alias KP_POWER = 195 371 | alias KP_PERCENT = 196 372 | alias KP_LESS = 197 373 | alias KP_GREATER = 198 374 | alias KP_AMPERSAND = 199 375 | alias KP_DBLAMPERSAND = 200 376 | alias KP_VERTICALBAR = 201 377 | alias KP_DBLVERTICALBAR = 202 378 | alias KP_COLON = 203 379 | alias KP_HASH = 204 380 | alias KP_SPACE = 205 381 | alias KP_AT = 206 382 | alias KP_EXCLAM = 207 383 | alias KP_MEMSTORE = 208 384 | alias KP_MEMRECALL = 209 385 | alias KP_MEMCLEAR = 210 386 | alias KP_MEMADD = 211 387 | alias KP_MEMSUBTRACT = 212 388 | alias KP_MEMMULTIPLY = 213 389 | alias KP_MEMDIVIDE = 214 390 | alias KP_PLUSMINUS = 215 391 | alias KP_CLEAR = 216 392 | alias KP_CLEARENTRY = 217 393 | alias KP_BINARY = 218 394 | alias KP_OCTAL = 219 395 | alias KP_DECIMAL = 220 396 | alias KP_HEXADECIMAL = 221 397 | 398 | alias LCTRL = 224 399 | alias LSHIFT = 225 400 | alias LALT = 226 401 | """alt, option.""" 402 | alias LGUI = 227 403 | """windows, command (apple), meta.""" 404 | alias RCTRL = 228 405 | alias RSHIFT = 229 406 | alias RALT = 230 407 | """alt gr, option.""" 408 | alias RGUI = 231 409 | """windows, command (apple), meta""" 410 | 411 | alias MODE = 257 412 | 413 | # These values are mapped from usage page 0x0C (USB consumer page). 414 | # See https://usb.org/sites/default/files/hut1_2.pdf 415 | 416 | alias AUDIONEXT = 258 417 | alias AUDIOPREV = 259 418 | alias AUDIOSTOP = 260 419 | alias AUDIOPLAY = 261 420 | alias AUDIOMUTE = 262 421 | alias MEDIASELECT = 263 422 | alias WWW = 264 423 | """Internet Browser.""" 424 | alias MAIL = 265 425 | alias CALCULATOR = 266 426 | """Calculator""" 427 | alias COMPUTER = 267 428 | alias AC_SEARCH = 268 429 | """Search.""" 430 | alias AC_HOME = 269 431 | """Home.""" 432 | alias AC_BACK = 270 433 | """Back.""" 434 | alias AC_FORWARD = 271 435 | """Forward.""" 436 | alias AC_STOP = 272 437 | """Stop.""" 438 | alias AC_REFRESH = 273 439 | """Refresh.""" 440 | alias AC_BOOKMARKS = 274 441 | """Bookmarks.""" 442 | 443 | # thank you Christian Walther 444 | 445 | alias BRIGHTNESSDOWN = 275 446 | alias BRIGHTNESSUP = 276 447 | alias DISPLAYSWITCH = 277 448 | """display mirroring/dual display switch, video mode switch.""" 449 | 450 | alias KBDILLUMTOGGLE = 278 451 | alias KBDILLUMDOWN = 279 452 | alias KBDILLUMUP = 280 453 | alias EJECT = 281 454 | alias SLEEP = 282 455 | """System Sleep""" 456 | 457 | alias APP1 = 283 458 | alias APP2 = 284 459 | 460 | # Media keys 461 | # These values are mapped from usage page 0x0C (USB consumer page). 462 | 463 | alias AUDIOREWIND = 285 464 | alias AUDIOFASTFORWARD = 286 465 | 466 | # Mobile keys 467 | # These are values that are often used on mobile phones. 468 | 469 | alias SOFTLEFT = 287 470 | """Usually situated below the display on phones and used as a multi-function feature key for selecting a software defined function shown on the bottom left of the display.""" 471 | 472 | alias SOFTRIGHT = 288 473 | """Usually situated below the display on phones and used as a multi-function feature key for selecting a software defined function shown on the bottom right of the display.""" 474 | 475 | alias CALL = 289 476 | """Used for accepting phone calls.""" 477 | 478 | alias ENDCALL = 290 479 | """Used for rejecting phone calls.""" 480 | 481 | # Add any other keys here. 482 | 483 | alias NUM_SCANCODES = 512 484 | """not a key, just marks the number of scancodes for array bounds.""" 485 | -------------------------------------------------------------------------------- /src/mix/__init__.mojo: -------------------------------------------------------------------------------- 1 | """Defines SDL_mix bindings and wrappers for use in Mojo.""" 2 | 3 | from sys import DLHandle, os_is_macos, os_is_linux 4 | from .._sdl import SDL_Fn 5 | from .sound import MixChunk, _MixChunk, MixMusic, _MixMusic 6 | from builtin.constrained import constrained 7 | 8 | 9 | struct _MIX: 10 | """Raw bindings to sdl_mix.""" 11 | 12 | var _handle: DLHandle 13 | var error: SDL_Error 14 | 15 | var _open_audio: SDL_Fn["Mix_OpenAudio", fn (Int32, UInt16, Int32, Int32) -> Int32] 16 | var _close_audio: SDL_Fn["Mix_CloseAudio", fn () -> NoneType] 17 | var _load_wav: SDL_Fn["Mix_LoadWAV", fn (Ptr[CharC]) -> Ptr[_MixChunk]] 18 | var _free_chunk: SDL_Fn["Mix_FreeChunk", fn (Ptr[_MixChunk]) -> NoneType] 19 | var _play_channel: SDL_Fn["Mix_PlayChannel", fn (Int32, Ptr[_MixChunk], Int32) -> Int32] 20 | var _load_mus: SDL_Fn["Mix_LoadMUS", fn (Ptr[CharC]) -> Ptr[_MixMusic]] 21 | var _free_music: SDL_Fn["Mix_FreeMusic", fn (Ptr[_MixMusic]) -> NoneType] 22 | var _play_music: SDL_Fn["Mix_PlayMusic", fn (Ptr[_MixMusic], Int32) -> Int32] 23 | 24 | fn __init__(inout self, error: SDL_Error): 25 | @parameter 26 | if os_is_macos(): 27 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2_mixer.dylib") 28 | elif os_is_linux(): 29 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2_mixer.so") 30 | else: 31 | constrained[False, "OS is not supported"]() 32 | self._handle = utils._uninit[DLHandle]() 33 | 34 | self.error = error 35 | self._open_audio = self._handle 36 | self._close_audio = self._handle 37 | self._load_wav = self._handle 38 | self._free_chunk = self._handle 39 | self._play_channel = self._handle 40 | self._load_mus = self._handle 41 | self._free_music = self._handle 42 | self._play_music = self._handle 43 | 44 | @always_inline 45 | fn init( 46 | self, 47 | frequency: Int32, 48 | format: UInt16, 49 | channels: Int32, 50 | chunksize: Int32, 51 | ) raises: 52 | self.error.if_code( 53 | self._open_audio.call(frequency, format, channels, chunksize), 54 | "Could not initialize sdl mix", 55 | ) 56 | 57 | @always_inline 58 | fn quit(self): 59 | self._close_audio.call() 60 | 61 | @always_inline 62 | fn load_wav(self, file: Ptr[CharC]) raises -> Ptr[_MixChunk]: 63 | return self.error.if_null(self._load_wav.call(file), "Could not load WAV file") 64 | 65 | @always_inline 66 | fn free_chunk(self, _mixchunk_ptr: Ptr[_MixChunk]): 67 | self._free_chunk.call(_mixchunk_ptr) 68 | 69 | @always_inline 70 | fn play_channel(self, channel: Int32, mix_chunk: Ptr[_MixChunk], loops: Int32) raises: 71 | self.error.if_code( 72 | self._play_channel.call(channel, mix_chunk, loops), 73 | "Could not play channel", 74 | ) 75 | 76 | @always_inline 77 | fn load_music(self, file: Ptr[CharC]) raises -> Ptr[_MixMusic]: 78 | return self.error.if_null(self._load_mus.call(file), "Could not load sound file") 79 | 80 | @always_inline 81 | fn free_music(self, _mixmusic_ptr: Ptr[_MixMusic]): 82 | self._free_music.call(_mixmusic_ptr) 83 | 84 | @always_inline 85 | fn play_music(self, music: Ptr[_MixMusic], loops: Int32) raises: 86 | self.error.if_code(self._play_music.call(music, loops), "Could not play sound file") 87 | -------------------------------------------------------------------------------- /src/mix/sound.mojo: -------------------------------------------------------------------------------- 1 | """Defines an sdl mix Sound.""" 2 | 3 | 4 | alias AUDIO_U8 = 0x0008 5 | alias AUDIO_S8 = 0x8008 6 | alias AUDIO_U16LSB = 0x0010 7 | alias AUDIO_S16LSB = 0x8008 8 | alias AUDIO_U16MSB = 0x1010 9 | alias AUDIO_S16MSB = 0x9010 10 | alias AUDIO_U16 = AUDIO_U16LSB 11 | alias AUDIO_S16 = AUDIO_S16LSB 12 | 13 | alias AUDIO_S32LSB = 0x8020 14 | alias AUDIO_S32MSB = 0x9020 15 | alias AUDIO_S32 = AUDIO_S32LSB 16 | 17 | alias AUDIO_F32LSB = 0x8120 18 | alias AUDIO_F32MSB = 0x9120 19 | alias AUDIO_F32 = AUDIO_F32LSB 20 | 21 | 22 | struct MixChunk[lif: AnyLifetime[False].type]: 23 | var mix: Reference[_MIX, lif] 24 | var _mixchunk_ptr: Ptr[_MixChunk] 25 | 26 | fn __init__(inout self, ref [lif]mix: _MIX, _mixchunk_ptr: Ptr[_MixChunk]): 27 | self.mix = mix 28 | self._mixchunk_ptr = _mixchunk_ptr 29 | 30 | fn __del__(owned self): 31 | self.mix[].free_chunk(self._mixchunk_ptr) 32 | 33 | fn play(self, channel: Int32, loops: Int32) raises: 34 | self.mix[].play_channel(channel, self._mixchunk_ptr, loops) 35 | 36 | 37 | @register_passable("trivial") 38 | struct _MixChunk: 39 | pass 40 | 41 | 42 | struct MixMusic[lif: AnyLifetime[False].type]: 43 | var mix: Reference[_MIX, lif] 44 | var _mixmusic_ptr: Ptr[_MixMusic] 45 | 46 | fn __init__(inout self, ref [lif]mix: _MIX, path: String) raises: 47 | self.mix = mix 48 | self._mixmusic_ptr = mix.load_music(path.unsafe_cstr_ptr().bitcast[DType.uint8]()) 49 | 50 | fn __init__(inout self, ref [lif]mix: _MIX, _mixmusic_ptr: Ptr[_MixMusic]): 51 | self.mix = mix 52 | self._mixmusic_ptr = _mixmusic_ptr 53 | 54 | fn __del__(owned self): 55 | self.mix[].free_music(self._mixmusic_ptr) 56 | 57 | fn play(self, loops: Int32) raises: 58 | self.mix[].play_music(self._mixmusic_ptr, loops) 59 | 60 | 61 | @register_passable("trivial") 62 | struct _MixMusic: 63 | pass 64 | -------------------------------------------------------------------------------- /src/mouse.mojo: -------------------------------------------------------------------------------- 1 | """Defines SDL Mouse.""" 2 | 3 | from .utils import adr 4 | from ._sdl import _SDL 5 | 6 | 7 | struct Mouse[lif: AnyLifetime[False].type]: 8 | var sdl: Reference[SDL, lif] 9 | 10 | fn __init__(inout self, ref [lif]sdl: SDL): 11 | self.sdl = sdl 12 | 13 | fn get_position(self) -> (Int, Int): 14 | var x: IntC = 0 15 | var y: IntC = 0 16 | _ = self.sdl[]._sdl.get_mouse_state(adr(x), adr(y)) 17 | return (int(x), int(y)) 18 | 19 | fn get_buttons(self) -> UInt32: 20 | return self.sdl[]._sdl.get_mouse_state(Ptr[IntC](), Ptr[IntC]()) 21 | -------------------------------------------------------------------------------- /src/pixel.mojo: -------------------------------------------------------------------------------- 1 | """Defines an SDL Pixel Format.""" 2 | 3 | from sys.info import is_big_endian 4 | 5 | 6 | @value 7 | struct Pixels: 8 | var _ptr: Ptr[NoneType] 9 | var pitch: IntC 10 | 11 | 12 | struct Palette: 13 | var ncolors: IntC 14 | """The number of colors in the palette.""" 15 | var colors: Ptr[Color] 16 | """An array of SDL_Color structures representing the palette.""" 17 | var version: UInt32 18 | """Incrementally tracks changes to the palette (internal use).""" 19 | var refcount: IntC 20 | """Reference count (internal use).""" 21 | 22 | 23 | @value 24 | @register_passable("trivial") 25 | struct SurfacePixelFormat: 26 | var format: UInt32 27 | var palette: Ptr[Palette] 28 | var bits_per_pixel: UInt8 29 | var bytes_per_pixel: UInt8 30 | var padding: UInt16 31 | var rmask: UInt32 32 | var gmask: UInt32 33 | var bmask: UInt32 34 | var amask: UInt32 35 | var rloss: UInt8 36 | var gloss: UInt8 37 | var bloss: UInt8 38 | var aloss: UInt8 39 | var rshift: UInt8 40 | var gshift: UInt8 41 | var bshift: UInt8 42 | var ashift: UInt8 43 | var refcount: Int32 44 | var next: Ptr[SurfacePixelFormat] 45 | 46 | 47 | @value 48 | @register_passable("trivial") 49 | struct TexturePixelFormat: 50 | alias RGBA8888: UInt32 = 0x16462004 51 | alias ABGR8888: UInt32 = 0x16762004 52 | alias RGBA32: UInt32 = Self.RGBA8888 if is_big_endian() else Self.ABGR8888 53 | alias RGB24: UInt32 = 0x17101803 54 | -------------------------------------------------------------------------------- /src/primitives.mojo: -------------------------------------------------------------------------------- 1 | """Defines SDL Primitives.""" 2 | 3 | from .utils import adr 4 | 5 | 6 | @value 7 | struct Color: 8 | var r: UInt8 9 | var g: UInt8 10 | var b: UInt8 11 | var a: UInt8 12 | 13 | fn __init__(inout self, r: UInt8, g: UInt8, b: UInt8, a: UInt8 = 0): 14 | self.r = r 15 | self.g = g 16 | self.b = b 17 | self.a = a 18 | 19 | fn as_uint32(owned self) -> UInt32: 20 | return adr(Color(self.b, self.g, self.r, self.a)).bitcast[UInt32]()[] 21 | 22 | 23 | @value 24 | struct DPoint[type: DType]: 25 | var x: Scalar[type] 26 | var y: Scalar[type] 27 | 28 | @always_inline("nodebug") 29 | fn __init__(inout self, x: Scalar, y: Scalar): 30 | self.x = x.cast[type]() 31 | self.y = y.cast[type]() 32 | 33 | @always_inline("nodebug") 34 | fn cast[type: DType](self) -> DPoint[type]: 35 | return DPoint[type](self.x, self.y) 36 | 37 | 38 | alias Point = DPoint[DType.int32] 39 | alias FPoint = DPoint[DType.float32] 40 | 41 | 42 | @value 43 | struct DRect[type: DType]: 44 | var x: Scalar[type] 45 | var y: Scalar[type] 46 | var w: Scalar[type] 47 | var h: Scalar[type] 48 | 49 | @always_inline("nodebug") 50 | fn __init__(inout self, x: Scalar, y: Scalar, w: Scalar, h: Scalar): 51 | self.x = x.cast[type]() 52 | self.y = y.cast[type]() 53 | self.w = w.cast[type]() 54 | self.h = h.cast[type]() 55 | 56 | @always_inline("nodebug") 57 | fn cast[type: DType](self) -> DRect[type]: 58 | return DRect[type](self.x, self.y, self.w, self.h) 59 | 60 | 61 | alias Rect = DRect[DType.int32] 62 | alias FRect = DRect[DType.float32] 63 | 64 | 65 | @value 66 | struct Vertex: 67 | """Vertex structure.""" 68 | 69 | var position: FPoint 70 | """Vertex position, in SDL_Renderer coordinates.""" 71 | 72 | var color: Color 73 | """Vertex color.""" 74 | 75 | var tex_coord: FPoint 76 | """Normalized texture coordinates, if needed.""" 77 | -------------------------------------------------------------------------------- /src/render.mojo: -------------------------------------------------------------------------------- 1 | """Defines an SDL Renderer.""" 2 | 3 | from collections import Optional 4 | from .utils import opt2ptr, adr 5 | from ._sdl import _SDL 6 | from .texture import _Texture 7 | 8 | 9 | struct Renderer[lif: AnyLifetime[False].type]: 10 | var sdl: Reference[SDL, lif] 11 | var _renderer_ptr: Ptr[_Renderer] 12 | var window: Window[lif] 13 | 14 | fn __init__( 15 | inout self, 16 | owned window: Window[lif], 17 | index: Int = -1, 18 | flags: UInt32 = 0, 19 | ) raises: 20 | self.sdl = window.sdl 21 | self.window = window^ 22 | self._renderer_ptr = self.sdl[]._sdl.create_renderer(self.window._window_ptr, index, flags) 23 | 24 | fn __init__(inout self, owned surface: Surface[lif]) raises: 25 | self.sdl = surface.sdl 26 | self._renderer_ptr = self.sdl[]._sdl.create_software_renderer(surface._surface_ptr) 27 | self.window = Window(self.sdl[]) 28 | 29 | fn __moveinit__(inout self, owned other: Self): 30 | self.sdl = other.sdl 31 | self._renderer_ptr = other._renderer_ptr 32 | self.window = other.window^ 33 | 34 | fn __del__(owned self): 35 | self.sdl[]._sdl.destroy_renderer(self._renderer_ptr) 36 | 37 | fn clear(self) raises: 38 | self.sdl[]._sdl.render_clear(self._renderer_ptr) 39 | 40 | fn copy[type: DType = DType.int32](self, texture: Texture, src: Optional[Rect]) raises: 41 | @parameter 42 | if type.is_integral(): 43 | self.sdl[]._sdl.render_copy( 44 | self._renderer_ptr, 45 | texture._texture_ptr, 46 | opt2ptr(src), 47 | Ptr[Rect](), 48 | ) 49 | elif type.is_floating_point(): 50 | self.sdl[]._sdl.render_copy_f( 51 | self._renderer_ptr, 52 | texture._texture_ptr, 53 | opt2ptr(src), 54 | Ptr[FRect](), 55 | ) 56 | 57 | fn copy[type: DType = DType.int32](self, texture: Texture, src: Optional[Rect], dst: DRect[type]) raises: 58 | @parameter 59 | if type.is_integral(): 60 | var _dst = dst.cast[DType.int32]() 61 | self.sdl[]._sdl.render_copy( 62 | self._renderer_ptr, 63 | texture._texture_ptr, 64 | opt2ptr(src), 65 | adr(_dst), 66 | ) 67 | _ = _dst 68 | elif type.is_floating_point(): 69 | var _dst = dst.cast[DType.float32]() 70 | self.sdl[]._sdl.render_copy_f( 71 | self._renderer_ptr, 72 | texture._texture_ptr, 73 | opt2ptr(src), 74 | adr(_dst), 75 | ) 76 | _ = _dst 77 | 78 | fn copy( 79 | self, 80 | texture: Texture, 81 | src: Optional[Rect], 82 | dst: Optional[Rect], 83 | angle: Float64, 84 | point: Point, 85 | flip: RendererFlip, 86 | ) raises: 87 | self.sdl[]._sdl.render_copy_ex( 88 | self._renderer_ptr, 89 | texture._texture_ptr, 90 | opt2ptr(src), 91 | opt2ptr(dst), 92 | angle, 93 | adr(point), 94 | flip, 95 | ) 96 | 97 | fn copy( 98 | self, 99 | texture: Texture, 100 | src: Optional[Rect], 101 | dst: Optional[FRect], 102 | angle: Float64, 103 | point: FPoint, 104 | flip: RendererFlip, 105 | ) raises: 106 | self.sdl[]._sdl.render_copy_exf( 107 | self._renderer_ptr, 108 | texture._texture_ptr, 109 | opt2ptr(src), 110 | opt2ptr(dst), 111 | angle, 112 | adr(point), 113 | flip, 114 | ) 115 | 116 | fn present(self): 117 | self.sdl[]._sdl.render_present(self._renderer_ptr) 118 | 119 | fn target_supported(self) -> Bool: 120 | return self.sdl[]._sdl.render_target_supported(self._renderer_ptr) 121 | 122 | fn set_target(self, texture: Texture) raises: 123 | self.sdl[]._sdl.set_render_target(self._renderer_ptr, texture._texture_ptr) 124 | 125 | fn reset_target(self) raises: 126 | self.sdl[]._sdl.set_render_target(self._renderer_ptr, Ptr[_Texture]()) 127 | 128 | fn get_target(self) raises -> Texture: 129 | var texture = self.sdl[]._sdl.get_render_target(self._renderer_ptr) 130 | return Texture(self.sdl[], texture) 131 | 132 | fn set_color(self, color: Color) raises: 133 | self.sdl[]._sdl.set_render_draw_color(self._renderer_ptr, color.r, color.g, color.b, color.a) 134 | 135 | fn get_color(self) raises -> Color: 136 | var color = utils._uninit[Color]() 137 | self.sdl[]._sdl.get_render_draw_color(self._renderer_ptr, adr(color.r), adr(color.g), adr(color.b), adr(color.a)) 138 | return color 139 | 140 | fn set_blendmode(self, blendmode: BlendMode) raises: 141 | self.sdl[]._sdl.set_render_draw_blend_mode(self._renderer_ptr, blendmode) 142 | 143 | fn set_vsync(self, vsync: Int) raises: 144 | self.sdl[]._sdl.render_set_vsync(self._renderer_ptr, vsync) 145 | 146 | fn get_blendmode(self) raises -> BlendMode: 147 | var blend_mode = utils._uninit[BlendMode]() 148 | self.sdl[]._sdl.get_render_draw_blend_mode(self._renderer_ptr, adr(blend_mode)) 149 | return blend_mode 150 | 151 | fn get_viewport(self) -> Rect: 152 | var rect = utils._uninit[Rect]() 153 | self.sdl[]._sdl.render_get_viewport(self._renderer_ptr, adr(rect)) 154 | return rect 155 | 156 | fn set_viewport(self, rect: Rect) raises: 157 | return self.sdl[]._sdl.render_set_viewport(self._renderer_ptr, adr(rect)) 158 | 159 | fn get_info(self) raises -> RendererInfo: 160 | var info = utils._uninit[RendererInfo]() 161 | self.sdl[]._sdl.get_renderer_info(self._renderer_ptr, adr(info)) 162 | return info 163 | 164 | fn get_output_size(self) raises -> (Int, Int): 165 | var w = utils._uninit[IntC]() 166 | var h = utils._uninit[IntC]() 167 | self.sdl[]._sdl.get_renderer_output_size(self._renderer_ptr, adr(w), adr(h)) 168 | return int(w), int(h) 169 | 170 | fn draw_point[type: DType = DType.float32](self, x: Scalar[type], y: Scalar[type]) raises: 171 | @parameter 172 | if type.is_integral(): 173 | self.sdl[]._sdl.render_draw_point(self._renderer_ptr, x.cast[DType.int32](), y.cast[DType.int32]()) 174 | elif type.is_floating_point(): 175 | self.sdl[]._sdl.render_draw_point_f( 176 | self._renderer_ptr, 177 | x.cast[DType.float32](), 178 | y.cast[DType.float32](), 179 | ) 180 | 181 | fn draw_points(self, points: List[Point]) raises: 182 | self.sdl[]._sdl.render_draw_points(self._renderer_ptr, points.unsafe_ptr(), len(points)) 183 | 184 | fn draw_points(self, points: List[FPoint]) raises: 185 | self.sdl[]._sdl.render_draw_points_f(self._renderer_ptr, points.unsafe_ptr(), len(points)) 186 | 187 | fn draw_line[ 188 | type: DType = DType.float32 189 | ](self, x1: Scalar[type], y1: Scalar[type], x2: Scalar[type], y2: Scalar[type],) raises: 190 | @parameter 191 | if type.is_integral(): 192 | self.sdl[]._sdl.render_draw_line( 193 | self._renderer_ptr, 194 | x1.cast[DType.int32](), 195 | y1.cast[DType.int32](), 196 | x2.cast[DType.int32](), 197 | y2.cast[DType.int32](), 198 | ) 199 | elif type.is_floating_point(): 200 | self.sdl[]._sdl.render_draw_line_f( 201 | self._renderer_ptr, 202 | x1.cast[DType.float32](), 203 | y1.cast[DType.float32](), 204 | x2.cast[DType.float32](), 205 | y2.cast[DType.float32](), 206 | ) 207 | 208 | fn draw_lines(self, points: List[Point]) raises: 209 | self.sdl[]._sdl.render_draw_lines(self._renderer_ptr, points.unsafe_ptr(), len(points)) 210 | 211 | fn draw_lines(self, points: List[FPoint]) raises: 212 | self.sdl[]._sdl.render_draw_lines_f(self._renderer_ptr, points.unsafe_ptr(), len(points)) 213 | 214 | fn draw_circle[type: DType = DType.float32](self, center: DPoint[type], radius: Scalar) raises: 215 | self.sdl[]._gfx().circle_color(self._renderer_ptr, center.x.cast[DType.int16](), center.y.cast[DType.int16](), radius.cast[DType.int16](), self.get_color().as_uint32()) 216 | 217 | fn draw_rect[type: DType = DType.float32](self, rect: DRect[type]) raises: 218 | @parameter 219 | if type.is_integral(): 220 | self.sdl[]._sdl.render_draw_rect(self._renderer_ptr, rect.cast[DType.int32]()) 221 | if type.is_floating_point(): 222 | self.sdl[]._sdl.render_draw_rect_f(self._renderer_ptr, rect.cast[DType.float32]()) 223 | 224 | fn draw_rects(self, rects: List[Rect]) raises: 225 | self.sdl[]._sdl.render_draw_rects(self._renderer_ptr, rects.unsafe_ptr(), len(rects)) 226 | 227 | fn draw_rects(self, rects: List[FRect]) raises: 228 | self.sdl[]._sdl.render_draw_rects_f(self._renderer_ptr, rects.unsafe_ptr(), len(rects)) 229 | 230 | fn fill_rect[type: DType = DType.float32](self, rect: DRect[type]) raises: 231 | @parameter 232 | if type.is_integral(): 233 | self.sdl[]._sdl.render_fill_rect(self._renderer_ptr, rect.cast[DType.int32]()) 234 | if type.is_floating_point(): 235 | self.sdl[]._sdl.render_fill_rect_f(self._renderer_ptr, rect.cast[DType.float32]()) 236 | 237 | fn fill_rects(self, rects: List[Rect]) raises: 238 | self.sdl[]._sdl.render_fill_rects(self._renderer_ptr, rects.unsafe_ptr(), len(rects)) 239 | 240 | fn fill_rects(self, rects: List[FRect]) raises: 241 | self.sdl[]._sdl.render_fill_rects_f(self._renderer_ptr, rects.unsafe_ptr(), len(rects)) 242 | 243 | fn render_geometry(self, texture: Texture, vertices: List[Vertex], indices: List[IntC]) raises: 244 | self.sdl[]._sdl.render_geometry( 245 | self._renderer_ptr, 246 | texture._texture_ptr, 247 | vertices.unsafe_ptr(), 248 | len(vertices), 249 | indices.unsafe_ptr(), 250 | len(indices), 251 | ) 252 | 253 | fn flush(self) raises: 254 | self.sdl[]._sdl.render_flush(self._renderer_ptr) 255 | 256 | 257 | @register_passable("trivial") 258 | struct _Renderer: 259 | pass 260 | 261 | 262 | @register_passable("trivial") 263 | struct RendererFlags: 264 | alias SDL_RENDERER_SOFTWARE = 0x00000001 265 | """The renderer is a software fallback.""" 266 | 267 | alias SDL_RENDERER_ACCELERATED = 0x00000002 268 | """The renderer uses hardware acceleration.""" 269 | 270 | alias SDL_RENDERER_PRESENTVSYNC = 0x00000004 271 | """Present is synchronized with the refresh rate.""" 272 | 273 | alias SDL_RENDERER_TARGETTEXTURE = 0x00000008 274 | """The renderer supports rendering to texture.""" 275 | 276 | 277 | @register_passable("trivial") 278 | struct RendererFlip: 279 | """Flip constants for `SDL_RenderCopyEx()`.""" 280 | 281 | var value: Int 282 | 283 | alias NONE: Int = 0x00000000 284 | """Do not flip.""" 285 | 286 | alias HORIZONTAL: Int = 0x00000001 287 | """Flip horizontally.""" 288 | 289 | alias VERTICAL: Int = 0x00000002 290 | """Flip vertically.""" 291 | 292 | 293 | @value 294 | @register_passable("trivial") 295 | struct RendererInfo: 296 | var name: Ptr[CharC] 297 | var flags: UInt32 298 | var num_texture_formats: UInt32 299 | var texture_formats: SIMD[DType.uint32, 16] 300 | var max_texture_width: IntC 301 | var max_texture_height: IntC 302 | -------------------------------------------------------------------------------- /src/surface.mojo: -------------------------------------------------------------------------------- 1 | """Defines an SDL Surface.""" 2 | 3 | from collections import Optional 4 | from .utils import adr, opt2ptr 5 | from ._sdl import _SDL 6 | 7 | 8 | struct Surface[lif: AnyLifetime[False].type]: 9 | """A higher level wrapper around an SDL_Surface.""" 10 | 11 | var sdl: Reference[SDL, lif] 12 | var _surface_ptr: Ptr[_Surface] 13 | 14 | fn __init__(inout self, ref [lif]sdl: SDL, width: Int32, height: Int32) raises: 15 | self.sdl = sdl 16 | self._surface_ptr = sdl._sdl.create_rgb_surface(0, width, height, 32, 0, 0, 0, 0) 17 | 18 | fn __init__(inout self, ref [lif]sdl: SDL, width: Int32, height: Int32, color: Color) raises: 19 | self = Self(sdl, width, height) 20 | self.fill(color) 21 | 22 | fn __init__(inout self, ref [lif]sdl: SDL, _surface_ptr: Ptr[_Surface] = Ptr[_Surface]()): 23 | self.sdl = sdl 24 | self._surface_ptr = _surface_ptr 25 | 26 | fn __moveinit__(inout self, owned other: Self): 27 | self.sdl = other.sdl 28 | self._surface_ptr = other._surface_ptr 29 | 30 | fn __del__(owned self): 31 | self.sdl[]._sdl.free_surface(self._surface_ptr) 32 | 33 | fn lock(self) raises: 34 | self.sdl[]._sdl.lock_surface(self._surface_ptr) 35 | 36 | fn unlock(self): 37 | self.sdl[]._sdl.unlock_surface(self._surface_ptr) 38 | 39 | fn fill(self, color: Color, rect: Rect) raises: 40 | self.sdl[]._sdl.fill_rect(self._surface_ptr, adr(rect), color.as_uint32()) 41 | 42 | fn fill(self, color: Color) raises: 43 | self.sdl[]._sdl.fill_rect(self._surface_ptr, Ptr[Rect](), color.as_uint32()) 44 | 45 | fn blit( 46 | self, 47 | source: Surface, 48 | source_rect: Optional[Rect], 49 | destination_rect: Optional[Rect], 50 | ) raises: 51 | self.sdl[]._sdl.upper_blit_scaled( 52 | source._surface_ptr, 53 | opt2ptr(source_rect), 54 | self._surface_ptr, 55 | opt2ptr(destination_rect), 56 | ) 57 | 58 | fn rotozoomed(self, angle: Float64, zoom: Float64, smooth: Bool = False) raises -> Surface[lif]: 59 | return Surface(self.sdl[], self.sdl[]._gfx().rotozoom_surface(self._surface_ptr, angle, zoom, smooth)) 60 | 61 | fn convert(inout self, format: Surface): 62 | self._surface_ptr = self.sdl[]._sdl._convert_surface.call(self._surface_ptr, format._surface_ptr[].format, 0) 63 | 64 | 65 | struct _Surface: 66 | var flags: UInt32 67 | var format: Ptr[SurfacePixelFormat] 68 | var width: Int32 69 | var height: Int32 70 | var pitch: Int32 71 | var pixels: Ptr[UInt32] 72 | var reserved: Ptr[UInt8] 73 | var locked: Int32 74 | var list_blitmap: Ptr[UInt8] 75 | var clip_rect: Rect 76 | var map: Ptr[UInt8] 77 | var refcount: Int32 78 | -------------------------------------------------------------------------------- /src/texture.mojo: -------------------------------------------------------------------------------- 1 | """Defines an SDL Texture.""" 2 | 3 | from collections import Optional 4 | from .utils import adr, opt2ptr 5 | from ._sdl import _SDL 6 | 7 | 8 | struct Texture: 9 | var sdl: UnsafePointer[SDL] 10 | var _texture_ptr: Ptr[_Texture] 11 | var _rc: UnsafePointer[Int] 12 | 13 | fn __init__( 14 | inout self, 15 | renderer: Renderer, 16 | format: UInt32, 17 | access: Int, 18 | w: Int, 19 | h: Int, 20 | ) raises: 21 | self.sdl = adr(renderer.sdl[]) 22 | self._texture_ptr = self.sdl[]._sdl.create_texture(renderer._renderer_ptr, format, access, w, h) 23 | self._rc = UnsafePointer[Int].alloc(1) 24 | self._rc[] = 0 25 | 26 | fn __init__(inout self, renderer: Renderer, surface: Surface) raises: 27 | self.sdl = adr(renderer.sdl[]) 28 | self._texture_ptr = self.sdl[]._sdl.create_texture_from_surface(renderer._renderer_ptr, surface._surface_ptr) 29 | self._rc = UnsafePointer[Int].alloc(1) 30 | self._rc[] = 0 31 | 32 | fn __init__(inout self, sdl: SDL, texture_ptr: Ptr[_Texture] = Ptr[_Texture]()) raises: 33 | self.sdl = adr(sdl) 34 | self._texture_ptr = texture_ptr 35 | self._rc = UnsafePointer[Int].alloc(1) 36 | self._rc[] = 0 37 | 38 | fn __copyinit__(inout self, other: Self): 39 | self.sdl = other.sdl 40 | self._texture_ptr = other._texture_ptr 41 | self._rc = other._rc 42 | self._rc[] += 1 43 | 44 | fn __moveinit__(inout self, owned other: Self): 45 | self.sdl = other.sdl 46 | self._texture_ptr = other._texture_ptr 47 | self._rc = other._rc 48 | 49 | fn __del__(owned self): 50 | if self._rc[] == 0: 51 | self.sdl[]._sdl.destroy_texture(self._texture_ptr) 52 | else: 53 | self._rc[] -= 1 54 | 55 | fn lock(self, rect: Optional[Rect] = None) raises -> Pixels: 56 | var pixels_ptr = utils._uninit[Ptr[NoneType]]() 57 | var pixels_pitch = utils._uninit[IntC]() 58 | self.sdl[]._sdl.lock_texture(self._texture_ptr, opt2ptr(rect), adr(pixels_ptr), adr(pixels_pitch)) 59 | return Pixels(pixels_ptr, pixels_pitch) 60 | 61 | fn unlock(self): 62 | self.sdl[]._sdl.unlock_texture(self._texture_ptr) 63 | 64 | fn get_color_mod(self) raises -> (UInt8, UInt8, UInt8): 65 | var r = utils._uninit[UInt8]() 66 | var g = utils._uninit[UInt8]() 67 | var b = utils._uninit[UInt8]() 68 | self.sdl[]._sdl.get_texture_color_mod(self._texture_ptr, adr(r), adr(g), adr(b)) 69 | return r, g, b 70 | 71 | fn set_color_mod(self, color: Color) raises: 72 | self.sdl[]._sdl.set_texture_color_mod(self._texture_ptr, color.r, color.g, color.b) 73 | 74 | fn get_alpha_mod(self) raises -> UInt8: 75 | var a = utils._uninit[UInt8]() 76 | self.sdl[]._sdl.get_texture_alpha_mod(self._texture_ptr, adr(a)) 77 | return a 78 | 79 | fn set_alpha_mod(self, alpha: UInt8) raises: 80 | self.sdl[]._sdl.set_texture_alpha_mod(self._texture_ptr, alpha) 81 | 82 | fn get_blend_mode(self) raises -> BlendMode: 83 | var blend_mode = utils._uninit[BlendMode]() 84 | self.sdl[]._sdl.get_texture_blend_mode(self._texture_ptr, adr(blend_mode)) 85 | return blend_mode 86 | 87 | fn set_blend_mode(self, blend_mode: BlendMode) raises: 88 | self.sdl[]._sdl.set_texture_blend_mode(self._texture_ptr, blend_mode) 89 | 90 | fn get_scale_mode(self) raises -> ScaleMode: 91 | var scale_mode = utils._uninit[ScaleMode]() 92 | self.sdl[]._sdl.get_texture_scale_mode(self._texture_ptr, adr(scale_mode)) 93 | return scale_mode 94 | 95 | fn set_scale_mode(self, scale_mode: ScaleMode) raises: 96 | self.sdl[]._sdl.set_texture_scale_mode(self._texture_ptr, scale_mode) 97 | 98 | 99 | @register_passable("trivial") 100 | struct _Texture: 101 | pass 102 | 103 | 104 | @register_passable("trivial") 105 | struct TextureAccess: 106 | alias STATIC = 0 107 | """Changes rarely, not lockable.""" 108 | alias STREAMING = 1 109 | """Changes frequently, lockable.""" 110 | alias TARGET = 2 111 | """Texture can be used as a render target.""" 112 | 113 | 114 | @value 115 | @register_passable("trivial") 116 | struct BlendMode: 117 | """The blend mode used in `SDL_RenderCopy()` and drawing operations. 118 | 119 | Additional custom blend modes can be returned by `SDL_ComposeCustomBlendMode()`. 120 | """ 121 | 122 | var value: IntC 123 | 124 | alias NONE: IntC = 0x00000000 125 | """No blending. 126 | 127 | dstRGBA = srcRGBA 128 | """ 129 | 130 | alias BLEND: IntC = 0x00000001 131 | """Alpha blending. 132 | 133 | dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA)) 134 | dstA = srcA + (dstA * (1-srcA)) 135 | """ 136 | 137 | alias ADD: IntC = 0x00000002 138 | """Additive blending. 139 | 140 | dstRGB = (srcRGB * srcA) + dstRGB 141 | dstA = dstA 142 | """ 143 | 144 | alias MOD: IntC = 0x00000004 145 | """Color modulate. 146 | 147 | dstRGB = srcRGB * dstRGB 148 | dstA = dstA 149 | """ 150 | 151 | alias MUL: IntC = 0x00000008 152 | """Color multiply. 153 | 154 | dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA)) 155 | dstA = dstA 156 | """ 157 | 158 | alias INVALID: IntC = 0x7FFFFFFF 159 | """Invalid.""" 160 | 161 | 162 | @value 163 | @register_passable("trivial") 164 | struct ScaleMode: 165 | """The scaling mode for a texture.""" 166 | 167 | var value: IntC 168 | 169 | alias Nearest: IntC = 0 170 | """Nearest pixel sampling.""" 171 | 172 | alias Linear: IntC = 1 173 | """Linear filtering.""" 174 | 175 | alias Best: IntC = 2 176 | """Anisotropic filtering.""" 177 | 178 | 179 | @value 180 | @register_passable("trivial") 181 | struct TextureModulate: 182 | """The texture channel modulation used in SDL_RenderCopy().""" 183 | 184 | var value: IntC 185 | 186 | alias NONE: IntC = 0x00000000 187 | """No modulation.""" 188 | 189 | alias COLOR: IntC = 0x00000001 190 | """srcC = srcC * color""" 191 | 192 | alias ALPHA: IntC = 0x00000002 193 | """srcA = srcA * alpha""" 194 | -------------------------------------------------------------------------------- /src/time.mojo: -------------------------------------------------------------------------------- 1 | """Defines an SDL Clock.""" 2 | 3 | from time import now, sleep 4 | from ._sdl import _SDL 5 | 6 | 7 | @value 8 | struct Clock[lif: AnyLifetime[False].type]: 9 | var sdl: Reference[SDL, lif] 10 | var target_fps: Int 11 | var delta_time: Float64 12 | var _last_tick_time: Int 13 | 14 | fn __init__(inout self, ref [lif]sdl: SDL, target_fps: Int): 15 | self.sdl = sdl 16 | self.target_fps = target_fps 17 | self.delta_time = 1 / target_fps 18 | self._last_tick_time = now() 19 | 20 | fn tick(inout self): 21 | var tick_time = now() 22 | var target_frame_time = 1 / self.target_fps 23 | var elapsed_time = (tick_time - self._last_tick_time) / 1_000_000_000 24 | if elapsed_time < target_frame_time: 25 | sleep(target_frame_time - elapsed_time) 26 | self.delta_time = target_frame_time 27 | else: 28 | self.delta_time = elapsed_time 29 | self._last_tick_time = tick_time 30 | -------------------------------------------------------------------------------- /src/ttf/__init__.mojo: -------------------------------------------------------------------------------- 1 | """Defines SDL_ttf bindings and wrappers for use in Mojo.""" 2 | 3 | from sys import DLHandle, os_is_macos, os_is_linux 4 | from .._sdl import SDL_Fn 5 | from ..surface import _Surface 6 | from .font import Font, _Font 7 | from builtin.constrained import constrained 8 | 9 | 10 | struct _TTF: 11 | """Raw bindings to sdl_ttf.""" 12 | 13 | var _handle: DLHandle 14 | var error: SDL_Error 15 | var _ttf_init: SDL_Fn["TTF_Init", fn () -> Int32] 16 | var _ttf_quit: SDL_Fn["TTF_Quit", fn () -> NoneType] 17 | var _ttf_open_font: SDL_Fn["TTF_OpenFont", fn (Ptr[CharC], Int32) -> Ptr[_Font]] 18 | var _ttf_close_font: SDL_Fn["TTF_CloseFont", fn (Ptr[_Font]) -> NoneType] 19 | var _ttf_render_text_solid: SDL_Fn[ 20 | "TTF_RenderText_Solid", 21 | fn (Ptr[_Font], Ptr[CharC], UInt32) -> Ptr[_Surface], 22 | ] 23 | var _ttf_render_text_shaded: SDL_Fn[ 24 | "TTF_RenderText_Shaded", 25 | fn (Ptr[_Font], Ptr[CharC], UInt32, UInt32) -> Ptr[_Surface], 26 | ] 27 | var _ttf_render_text_blended: SDL_Fn[ 28 | "TTF_RenderText_Blended", 29 | fn (Ptr[_Font], Ptr[CharC], UInt32) -> UnsafePointer[_Surface], 30 | ] 31 | 32 | fn __init__(inout self, error: SDL_Error): 33 | @parameter 34 | if os_is_macos(): 35 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2_ttf.dylib") 36 | elif os_is_linux(): 37 | self._handle = DLHandle(".magic/envs/default/lib/libSDL2_ttf.so") 38 | else: 39 | constrained[False, "OS is not supported"]() 40 | self._handle = utils._uninit[DLHandle]() 41 | 42 | self.error = error 43 | self._ttf_init = self._handle 44 | self._ttf_quit = self._handle 45 | self._ttf_open_font = self._handle 46 | self._ttf_close_font = self._handle 47 | self._ttf_render_text_solid = self._handle 48 | self._ttf_render_text_shaded = self._handle 49 | self._ttf_render_text_blended = self._handle 50 | 51 | @always_inline 52 | fn init(self) raises: 53 | self.error.if_code(self._ttf_init.call(), "Could not initialize SDL TTF") 54 | 55 | @always_inline 56 | fn quit(self): 57 | self._ttf_quit.call() 58 | 59 | @always_inline 60 | fn open_font(self, path: Ptr[CharC], size: Int32) raises -> Ptr[_Font]: 61 | return self.error.if_null(self._ttf_open_font.call(path, size), "Could not open font") 62 | 63 | @always_inline 64 | fn close_font(self, font: Ptr[_Font]): 65 | self._ttf_close_font.call(font) 66 | 67 | @always_inline 68 | fn render_solid_text(self, font: Ptr[_Font], text: Ptr[CharC], fg: UInt32) raises -> Ptr[_Surface]: 69 | return self.error.if_null( 70 | self._ttf_render_text_solid.call(font, text, fg), 71 | "Could not render solid text", 72 | ) 73 | 74 | @always_inline 75 | fn render_shaded_text(self, font: Ptr[_Font], text: Ptr[CharC], fg: UInt32, bg: UInt32) raises -> Ptr[_Surface]: 76 | return self.error.if_null( 77 | self._ttf_render_text_shaded.call(font, text, fg, bg), 78 | "Could not render shaded text", 79 | ) 80 | 81 | @always_inline 82 | fn render_blended_text(self, font: Ptr[_Font], text: Ptr[CharC], fg: UInt32) raises -> Ptr[_Surface]: 83 | return self.error.if_null(self._ttf_render_text_blended.call(font, text, fg), "Could not render blended text") 84 | -------------------------------------------------------------------------------- /src/ttf/font.mojo: -------------------------------------------------------------------------------- 1 | """Defines an sdl ttf font.""" 2 | 3 | 4 | struct Font[lif: AnyLifetime[False].type]: 5 | var sdl: Reference[SDL, lif] 6 | var _font_ptr: Ptr[_Font] 7 | 8 | fn __init__(inout self, ref [lif]sdl: SDL, path: String, size: Int32) raises: 9 | self.sdl = sdl 10 | self._font_ptr = sdl._ttf().open_font(path.unsafe_cstr_ptr().bitcast[DType.uint8](), size) 11 | 12 | fn __init__(inout self, ref [lif]sdl: SDL, font_ptr: Ptr[_Font]): 13 | self.sdl = sdl 14 | self._font_ptr = font_ptr 15 | 16 | fn __del__(owned self): 17 | if self.sdl[]._ttf: 18 | self.sdl[]._ttf._lib.close_font(self._font_ptr) 19 | 20 | fn render_solid(self, text: String, color: Color) raises -> Surface[lif]: 21 | return Surface(self.sdl[], self.sdl[]._ttf().render_solid_text(self._font_ptr, text.unsafe_cstr_ptr().bitcast[DType.uint8](), color.as_uint32())) 22 | 23 | fn render_shaded(self, text: String, foreground: Color, background: Color) raises -> Surface[lif]: 24 | return Surface(self.sdl[], self.sdl[]._ttf().render_shaded_text(self._font_ptr, text.unsafe_cstr_ptr().bitcast[DType.uint8](), foreground.as_uint32(), background.as_uint32())) 25 | 26 | fn render_blended(self, text: String, color: Color) raises -> Surface[lif]: 27 | return Surface(self.sdl[], self.sdl[]._ttf().render_blended_text(self._font_ptr, text.unsafe_cstr_ptr().bitcast[DType.uint8](), color.as_uint32())) 28 | 29 | 30 | @register_passable("trivial") 31 | struct _Font: 32 | pass 33 | -------------------------------------------------------------------------------- /src/utils.mojo: -------------------------------------------------------------------------------- 1 | """Defines utility functions.""" 2 | 3 | from collections import Optional 4 | 5 | 6 | @always_inline("nodebug") 7 | fn adr[T: AnyType, //](ref [_]arg: T) -> Ptr[T]: 8 | return Ptr[T](__mlir_op.`lit.ref.to_pointer`(__get_mvalue_as_litref(arg))) 9 | 10 | 11 | @always_inline("nodebug") 12 | fn opt2ptr(optional: Optional) -> Ptr[optional.T]: 13 | if optional: 14 | return adr(optional.unsafe_value()) 15 | else: 16 | return Ptr[optional.T]() 17 | 18 | 19 | @always_inline 20 | fn _uninit[T: AnyType]() -> T as value: 21 | # Returns uninitialized data. 22 | __mlir_op.`lit.ownership.mark_initialized`(__get_mvalue_as_litref(value)) 23 | -------------------------------------------------------------------------------- /src/window.mojo: -------------------------------------------------------------------------------- 1 | """Defines an SDL Window.""" 2 | 3 | from collections import Optional 4 | from ._sdl import _SDL 5 | 6 | alias windowpos_undefined_mask = 0x1FFF0000 7 | alias windowpos_centered_mask = 0x2FFF0000 8 | alias WINDOWPOS_UNDEFINED = windowpos_undefined_display(0) 9 | alias WINDOWPOS_CENTERED = windowpos_centered_display(0) 10 | 11 | 12 | @always_inline 13 | fn windowpos_undefined_display(x: Int32) -> Int32: 14 | return windowpos_undefined_mask | (x & 0xFFFF) 15 | 16 | 17 | @always_inline 18 | fn windowpos_centered_display(x: Int32) -> Int32: 19 | return windowpos_centered_mask | (x & 0xFFFF) 20 | 21 | 22 | struct Window[lif: AnyLifetime[False].type]: 23 | """A higher level wrapper around an SDL_Window.""" 24 | 25 | var sdl: Reference[SDL, lif] 26 | var _window_ptr: Ptr[_Window] 27 | 28 | fn __init__( 29 | inout self, 30 | ref [lif]sdl: SDL, 31 | name: String, 32 | width: Int32, 33 | height: Int32, 34 | xpos: Optional[Int32] = None, 35 | ypos: Optional[Int32] = None, 36 | xcenter: Bool = False, 37 | ycenter: Bool = False, 38 | fullscreen: Bool = False, 39 | opengl: Bool = False, 40 | shown: Bool = False, 41 | hidden: Bool = False, 42 | borderless: Bool = False, 43 | resizable: Bool = False, 44 | minimized: Bool = False, 45 | maximized: Bool = False, 46 | input_grabbed: Bool = False, 47 | allow_highdpi: Bool = False, 48 | ) raises: 49 | # set sdl 50 | self.sdl = sdl 51 | 52 | # calculate window position 53 | if xpos and xcenter: 54 | raise Error("Expected only one of `xpos` or `xcenter` but got both") 55 | if ypos and ycenter: 56 | raise Error("Expected only one of `ypos` or `ycenter` but got both") 57 | var x = xpos.or_else(WINDOWPOS_CENTERED if xcenter else WINDOWPOS_UNDEFINED) 58 | var y = ypos.or_else(WINDOWPOS_CENTERED if ycenter else WINDOWPOS_UNDEFINED) 59 | 60 | # set window flags 61 | var flags: UInt32 = 0 62 | flags |= WindowFlags.FULLSCREEN * fullscreen 63 | flags |= WindowFlags.OPENGL * opengl 64 | flags |= WindowFlags.SHOWN * shown 65 | flags |= WindowFlags.HIDDEN * hidden 66 | flags |= WindowFlags.BORDERLESS * borderless 67 | flags |= WindowFlags.RESIZABLE * resizable 68 | flags |= WindowFlags.MINIMIZED * minimized 69 | flags |= WindowFlags.MAXIMIZED * maximized 70 | flags |= WindowFlags.INPUT_GRABBED * input_grabbed 71 | flags |= WindowFlags.ALLOW_HIGHDPI * allow_highdpi 72 | 73 | self._window_ptr = self.sdl[]._sdl.create_window( 74 | name.unsafe_cstr_ptr().bitcast[DType.uint8](), 75 | x, 76 | y, 77 | width, 78 | height, 79 | flags, 80 | ) 81 | 82 | fn __init__(inout self, ref [lif]sdl: SDL, _window_ptr: Ptr[_Window] = Ptr[_Window]()): 83 | self.sdl = sdl 84 | self._window_ptr = _window_ptr 85 | 86 | fn __moveinit__(inout self, owned other: Self): 87 | self.sdl = other.sdl 88 | self._window_ptr = other._window_ptr 89 | 90 | fn __del__(owned self): 91 | self.sdl[]._sdl.destroy_window(self._window_ptr) 92 | 93 | fn set_fullscreen(inout self, flags: UInt32) raises: 94 | self.sdl[]._sdl.set_window_fullscreen(self._window_ptr, flags) 95 | 96 | fn get_surface(inout self) raises -> Surface[lif]: 97 | var surface = Surface(self.sdl[], self.sdl[]._sdl.get_window_surface(self._window_ptr)) 98 | surface._surface_ptr[].refcount += 1 99 | return surface^ 100 | 101 | fn update_surface(self) raises: 102 | self.sdl[]._sdl.update_window_surface(self._window_ptr) 103 | 104 | fn destroy_surface(inout self) raises: 105 | self.sdl[]._sdl.destroy_window_surface(self._window_ptr) 106 | 107 | 108 | @register_passable("trivial") 109 | struct _Window: 110 | """The opaque type used to identify a window.""" 111 | 112 | pass 113 | 114 | 115 | struct WindowFlags: 116 | """Window Flags.""" 117 | 118 | alias FULLSCREEN = 0x00000001 119 | """Fullscreen window.""" 120 | 121 | alias OPENGL = 0x00000002 122 | """Window usable with OpenGL context.""" 123 | alias SHOWN = 0x00000004 124 | """Window is visible.""" 125 | alias HIDDEN = 0x00000008 126 | """Window is not visible.""" 127 | alias BORDERLESS = 0x00000010 128 | """No window decoration.""" 129 | alias RESIZABLE = 0x00000020 130 | """Window can be resized.""" 131 | alias MINIMIZED = 0x00000040 132 | """Window is minimized.""" 133 | alias MAXIMIZED = 0x00000080 134 | """Window is maximized.""" 135 | alias MOUSE_GRABBED = 0x00000100 136 | """Window has grabbed mouse input.""" 137 | alias INPUT_FOCUS = 0x00000200 138 | """Window has input focus.""" 139 | alias MOUSE_FOCUS = 0x00000400 140 | """Window has mouse focus.""" 141 | alias FULLSCREEN_DESKTOP = (Self.FULLSCREEN | 0x00001000) 142 | """Fullscreen desktop window.""" 143 | alias FOREIGN = 0x00000800 144 | """Window not created by SDL.""" 145 | alias ALLOW_HIGHDPI = 0x00002000 146 | """Window should be created in high-DPI mode if supported. 147 | On macOS NSHighResolutionCapable must be set true in the application's Info.plist for this to have any effect.""" 148 | alias MOUSE_CAPTURE = 0x00004000 149 | """Window has mouse captured (unrelated to MOUSE_GRABBED).""" 150 | alias ALWAYS_ON_TOP = 0x00008000 151 | """Window should always be above others.""" 152 | alias SKIP_TASKBAR = 0x00010000 153 | """Window should not be added to the taskbar.""" 154 | alias UTILITY = 0x00020000 155 | """Window should be treated as a utility window.""" 156 | alias TOOLTIP = 0x00040000 157 | """Window should be treated as a tooltip.""" 158 | alias POPUP_MENU = 0x00080000 159 | """Window should be treated as a popup menu.""" 160 | alias KEYBOARD_GRABBED = 0x00100000 161 | """Window has grabbed keyboard input.""" 162 | alias VULKAN = 0x10000000 163 | """Window usable for Vulkan surface.""" 164 | alias METAL = 0x20000000 165 | """Window usable for Metal view.""" 166 | 167 | alias INPUT_GRABBED = Self.MOUSE_GRABBED 168 | """Equivalent to SDL_WINDOW_MOUSE_GRABBED for compatibility.""" 169 | 170 | 171 | struct DisplayMode: 172 | """The structure that defines a display mode.""" 173 | 174 | var format: UInt32 175 | """Pixel format.""" 176 | var w: IntC 177 | """Width, in screen coordinates.""" 178 | var h: IntC 179 | """Height, in screen coordinates.""" 180 | var refresh_rate: IntC 181 | """Refresh rate (or zero for unspecified).""" 182 | var driverdata: Ptr[NoneType] 183 | """Driver-specific data, initialize to 0.""" 184 | 185 | 186 | struct FlashOperation: 187 | """Window flash operation.""" 188 | 189 | alias FLASH_CANCEL: IntC = 0 190 | """Cancel any window flash state.""" 191 | alias FLASH_BRIEFLY: IntC = 1 192 | """Flash the window briefly to get attention.""" 193 | alias SDL_FLASH_UNTIL_FOCUSED: IntC = 2 194 | """Flash the window until it gets focus.""" 195 | 196 | 197 | @register_passable("trivial") 198 | struct _GLContext: 199 | pass 200 | -------------------------------------------------------------------------------- /test_cons.mojo: -------------------------------------------------------------------------------- 1 | from sys.info import os_is_linux, os_is_macos 2 | 3 | 4 | fn main(): 5 | constrained[(os_is_linux() or os_is_macos()), "OS is not supported"]() 6 | print("mac", os_is_macos()) 7 | print("linux", os_is_linux()) 8 | --------------------------------------------------------------------------------