Compare commits

...

5 Commits

65 changed files with 4362 additions and 2213 deletions

View File

@ -37,6 +37,22 @@ You can specify which repo to use with `-Dsdl-url=<repo-url>` the git refs will
`-Dofficial` will use libsdl org's github repo. `-Dofficial` will use libsdl org's github repo.
If you already have SDL headers locally, use `-DsourceDir=<path>` instead of fetching from git:
```
zig build generate -DsourceDir=D:/path/to/SDL
```
`sourceDir` may point at an SDL checkout root (`include/SDL3`) or directly at a directory containing the SDL headers. Generated outputs go to `<sourceDir>/api` and `<sourceDir>/json` unless `-DoutputDir` is provided.
If you want to read headers from one location and write outputs somewhere else, add `-DoutputDir=<path>`:
```
zig build generate -DsourceDir=D:/path/to/SDL -DoutputDir=D:/path/to/output
```
That writes `api/` and `json/` under `outputDir` while still reading headers from `sourceDir`. `--basedir` remains the parser working directory for `tmp/`, `debug/`, and `archive/debug`.
## Parser Usage ## Parser Usage
building the parser for standalone use or in your own scripts building the parser for standalone use or in your own scripts

View File

@ -1,13 +1,10 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const iostream_api = @import("iostream.zig");
const properties_api = @import("properties.zig");
pub const PropertiesID = u32; pub const IOStream = iostream_api.IOStream;
pub const PropertiesID = properties_api.PropertiesID;
pub const IOStream = opaque {
pub inline fn loadWAV_IO(iostream: *IOStream, closeio: bool, spec: ?*AudioSpec, audio_buf: [*c][*c]u8, audio_len: *u32) bool {
return @bitCast(c.SDL_LoadWAV_IO(@ptrCast(iostream), @bitCast(closeio), @ptrCast(spec), audio_buf, @ptrCast(audio_len)));
}
};
pub const AudioFormat = enum(c_int) { pub const AudioFormat = enum(c_int) {
audioUnknown = 0x0000, //Unspecified audio format audioUnknown = 0x0000, //Unspecified audio format
@ -86,6 +83,14 @@ pub const AudioStream = opaque {
return @bitCast(c.SDL_PutAudioStreamData(@ptrCast(audiostream), buf, len)); return @bitCast(c.SDL_PutAudioStreamData(@ptrCast(audiostream), buf, len));
} }
pub inline fn putAudioStreamDataNoCopy(audiostream: *AudioStream, buf: ?*const anyopaque, len: c_int, callback: AudioStreamDataCompleteCallback, userdata: ?*anyopaque) bool {
return @bitCast(c.SDL_PutAudioStreamDataNoCopy(@ptrCast(audiostream), buf, len, callback, userdata));
}
pub inline fn putAudioStreamPlanarData(audiostream: *AudioStream, channel_buffers: [*c]const *anyopaque, num_channels: c_int, num_samples: c_int) bool {
return @bitCast(c.SDL_PutAudioStreamPlanarData(@ptrCast(audiostream), channel_buffers, num_channels, num_samples));
}
pub inline fn getAudioStreamData(audiostream: *AudioStream, buf: ?*anyopaque, len: c_int) c_int { pub inline fn getAudioStreamData(audiostream: *AudioStream, buf: ?*anyopaque, len: c_int) c_int {
return c.SDL_GetAudioStreamData(@ptrCast(audiostream), buf, len); return c.SDL_GetAudioStreamData(@ptrCast(audiostream), buf, len);
} }
@ -183,16 +188,16 @@ pub inline fn isAudioDevicePlayback(devid: AudioDeviceID) bool {
return @bitCast(c.SDL_IsAudioDevicePlayback(devid)); return @bitCast(c.SDL_IsAudioDevicePlayback(devid));
} }
pub inline fn pauseAudioDevice(dev: AudioDeviceID) bool { pub inline fn pauseAudioDevice(devid: AudioDeviceID) bool {
return @bitCast(c.SDL_PauseAudioDevice(dev)); return @bitCast(c.SDL_PauseAudioDevice(devid));
} }
pub inline fn resumeAudioDevice(dev: AudioDeviceID) bool { pub inline fn resumeAudioDevice(devid: AudioDeviceID) bool {
return @bitCast(c.SDL_ResumeAudioDevice(dev)); return @bitCast(c.SDL_ResumeAudioDevice(devid));
} }
pub inline fn audioDevicePaused(dev: AudioDeviceID) bool { pub inline fn audioDevicePaused(devid: AudioDeviceID) bool {
return @bitCast(c.SDL_AudioDevicePaused(dev)); return @bitCast(c.SDL_AudioDevicePaused(devid));
} }
pub inline fn getAudioDeviceGain(devid: AudioDeviceID) f32 { pub inline fn getAudioDeviceGain(devid: AudioDeviceID) f32 {
@ -223,6 +228,8 @@ pub inline fn createAudioStream(src_spec: ?*const AudioSpec, dst_spec: ?*const A
return @ptrCast(c.SDL_CreateAudioStream(@ptrCast(src_spec), @ptrCast(dst_spec))); return @ptrCast(c.SDL_CreateAudioStream(@ptrCast(src_spec), @ptrCast(dst_spec)));
} }
pub const AudioStreamDataCompleteCallback = c.SDL_AudioStreamDataCompleteCallback;
pub const AudioStreamCallback = c.SDL_AudioStreamCallback; pub const AudioStreamCallback = c.SDL_AudioStreamCallback;
pub inline fn openAudioDeviceStream(devid: AudioDeviceID, spec: ?*const AudioSpec, callback: AudioStreamCallback, userdata: ?*anyopaque) ?*AudioStream { pub inline fn openAudioDeviceStream(devid: AudioDeviceID, spec: ?*const AudioSpec, callback: AudioStreamCallback, userdata: ?*anyopaque) ?*AudioStream {
@ -235,6 +242,10 @@ pub inline fn setAudioPostmixCallback(devid: AudioDeviceID, callback: AudioPostm
return @bitCast(c.SDL_SetAudioPostmixCallback(devid, callback, userdata)); return @bitCast(c.SDL_SetAudioPostmixCallback(devid, callback, userdata));
} }
pub inline fn loadWAV_IO(src: ?*IOStream, closeio: bool, spec: ?*AudioSpec, audio_buf: [*c][*c]u8, audio_len: *u32) bool {
return @bitCast(c.SDL_LoadWAV_IO(@ptrCast(src), @bitCast(closeio), @ptrCast(spec), audio_buf, @ptrCast(audio_len)));
}
pub inline fn loadWAV(path: [*c]const u8, spec: ?*AudioSpec, audio_buf: [*c][*c]u8, audio_len: *u32) bool { pub inline fn loadWAV(path: [*c]const u8, spec: ?*AudioSpec, audio_buf: [*c][*c]u8, audio_len: *u32) bool {
return @bitCast(c.SDL_LoadWAV(path, @ptrCast(spec), audio_buf, @ptrCast(audio_len))); return @bitCast(c.SDL_LoadWAV(path, @ptrCast(spec), audio_buf, @ptrCast(audio_len)));
} }

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub const BlendMode = u32; pub const BlendMode = u32;
pub const BlendOperation = enum(c_int) { pub const BlendOperation = enum(c_int) {

View File

@ -1,56 +1,18 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const pixels_api = @import("pixels.zig");
const surface_api = @import("surface.zig");
const properties_api = @import("properties.zig");
pub const PixelFormat = enum(c_int) { pub const PixelFormat = pixels_api.PixelFormat;
pixelformatYv12 = 0x32315659, //Planar mode: Y + V + U (3 planes) pub const Surface = surface_api.Surface;
pixelformatIyuv = 0x56555949, //Planar mode: Y + U + V (3 planes) pub const Colorspace = pixels_api.Colorspace;
pixelformatYuy2 = 0x32595559, //Packed mode: Y0+U0+Y1+V0 (1 plane) pub const PropertiesID = properties_api.PropertiesID;
pixelformatUyvy = 0x59565955, //Packed mode: U0+Y0+V0+Y1 (1 plane)
pixelformatYvyu = 0x55595659, //Packed mode: Y0+V0+Y1+U0 (1 plane)
pixelformatNv12 = 0x3231564e, //Planar mode: Y + U/V interleaved (2 planes)
pixelformatNv21 = 0x3132564e, //Planar mode: Y + V/U interleaved (2 planes)
pixelformatP010 = 0x30313050, //Planar mode: Y + U/V interleaved (2 planes)
pixelformatExternalOes = 0x2053454f, //Android video texture format
};
pub const Surface = opaque {};
pub const Colorspace = enum(c_int) {
colorspaceSrgb = 0x120005a0, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
colorRangeFull,
colorPrimariesBt709,
transferCharacteristicsSrgb,
matrixCoefficientsIdentity,
colorspaceSrgbLinear = 0x12000500, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
transferCharacteristicsLinear,
colorspaceHdr10 = 0x12002600, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
colorPrimariesBt2020,
transferCharacteristicsPq,
colorspaceJpeg = 0x220004c6, //Equivalent to DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601
transferCharacteristicsBt601,
matrixCoefficientsBt601,
colorspaceBt601Limited = 0x211018c6, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601
colorRangeLimited,
colorPrimariesBt601,
colorspaceBt601Full = 0x221018c6, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601
colorspaceBt709Limited = 0x21100421, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
transferCharacteristicsBt709,
matrixCoefficientsBt709,
colorspaceBt709Full = 0x22100421, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
colorspaceBt2020Limited = 0x21102609, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020
matrixCoefficientsBt2020Ncl,
colorspaceBt2020Full = 0x22102609, //Equivalent to DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020
pub const colorspaceRgbDefault = .colorspaceSrgb; //The default colorspace for RGB surfaces if no colorspace is specified
pub const colorspaceYuvDefault = .colorspaceJpeg; //The default colorspace for YUV surfaces if no colorspace is specified
};
pub const PropertiesID = u32;
pub const CameraID = u32; pub const CameraID = u32;
pub const Camera = opaque { pub const Camera = opaque {
pub inline fn getCameraPermissionState(camera: *Camera) c_int { pub inline fn getCameraPermissionState(camera: *Camera) CameraPermissionState {
return c.SDL_GetCameraPermissionState(@ptrCast(camera)); return c.SDL_GetCameraPermissionState(@ptrCast(camera));
} }
@ -85,7 +47,7 @@ pub const CameraSpec = extern struct {
width: c_int, // Frame width width: c_int, // Frame width
height: c_int, // Frame height height: c_int, // Frame height
framerate_numerator: c_int, // Frame rate numerator ((num / denom) == FPS, (denom / num) == duration in seconds) framerate_numerator: c_int, // Frame rate numerator ((num / denom) == FPS, (denom / num) == duration in seconds)
framerate_denominator: c_int, // Frame rate demoninator ((num / denom) == FPS, (denom / num) == duration in seconds) framerate_denominator: c_int, // Frame rate denominator ((num / denom) == FPS, (denom / num) == duration in seconds)
}; };
pub const CameraPosition = enum(c_int) { pub const CameraPosition = enum(c_int) {
@ -94,6 +56,11 @@ pub const CameraPosition = enum(c_int) {
cameraPositionBackFacing, cameraPositionBackFacing,
}; };
pub const CameraPermissionState = enum(c_int) {
cameraPermissionStatePending,
cameraPermissionStateApproved,
};
pub inline fn getNumCameraDrivers() c_int { pub inline fn getNumCameraDrivers() c_int {
return c.SDL_GetNumCameraDrivers(); return c.SDL_GetNumCameraDrivers();
} }
@ -110,8 +77,8 @@ pub inline fn getCameras(count: *c_int) ?*CameraID {
return @ptrCast(c.SDL_GetCameras(@ptrCast(count))); return @ptrCast(c.SDL_GetCameras(@ptrCast(count)));
} }
pub inline fn getCameraSupportedFormats(devid: CameraID, count: *c_int) [*c]?*CameraSpec { pub inline fn getCameraSupportedFormats(instance_id: CameraID, count: *c_int) [*c]?*CameraSpec {
return c.SDL_GetCameraSupportedFormats(devid, @ptrCast(count)); return c.SDL_GetCameraSupportedFormats(instance_id, @ptrCast(count));
} }
pub inline fn getCameraName(instance_id: CameraID) [*c]const u8 { pub inline fn getCameraName(instance_id: CameraID) [*c]const u8 {

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub inline fn setClipboardText(text: [*c]const u8) bool { pub inline fn setClipboardText(text: [*c]const u8) bool {
return @bitCast(c.SDL_SetClipboardText(text)); return @bitCast(c.SDL_SetClipboardText(text));
} }

View File

@ -1,9 +1,10 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const video_api = @import("video.zig");
const properties_api = @import("properties.zig");
pub const Window = opaque {}; pub const Window = video_api.Window;
pub const PropertiesID = properties_api.PropertiesID;
pub const PropertiesID = u32;
pub const DialogFileFilter = extern struct { pub const DialogFileFilter = extern struct {
name: [*c]const u8, name: [*c]const u8,

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub inline fn outOfMemory() bool { pub inline fn outOfMemory() bool {
return @bitCast(c.SDL_OutOfMemory()); return @bitCast(c.SDL_OutOfMemory());
} }

View File

@ -1,157 +1,38 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const pen_api = @import("pen.zig");
const video_api = @import("video.zig");
const audio_api = @import("audio.zig");
const camera_api = @import("camera.zig");
const mouse_api = @import("mouse.zig");
const scancode_api = @import("scancode.zig");
const touch_api = @import("touch.zig");
const keyboard_api = @import("keyboard.zig");
const power_api = @import("power.zig");
const keycode_api = @import("keycode.zig");
const sensor_api = @import("sensor.zig");
const joystick_api = @import("joystick.zig");
pub const PenID = u32; pub const PenID = pen_api.PenID;
pub const WindowID = video_api.WindowID;
pub const WindowID = u32; pub const AudioDeviceID = audio_api.AudioDeviceID;
pub const DisplayID = video_api.DisplayID;
pub const AudioDeviceID = u32; pub const CameraID = camera_api.CameraID;
pub const PenInputFlags = pen_api.PenInputFlags;
pub const DisplayID = u32; pub const MouseButtonFlags = mouse_api.MouseButtonFlags;
pub const Scancode = scancode_api.Scancode;
pub const CameraID = u32; pub const TouchID = touch_api.TouchID;
pub const KeyboardID = keyboard_api.KeyboardID;
pub const PenInputFlags = packed struct(u32) { pub const PenAxis = pen_api.PenAxis;
penInputDown: bool = false, // pen is pressed down pub const MouseID = mouse_api.MouseID;
penInputButton1: bool = false, // button 1 is pressed pub const MouseWheelDirection = mouse_api.MouseWheelDirection;
penInputButton2: bool = false, // button 2 is pressed pub const PowerState = power_api.PowerState;
penInputButton3: bool = false, // button 3 is pressed pub const Window = video_api.Window;
penInputButton4: bool = false, // button 4 is pressed pub const FingerID = touch_api.FingerID;
penInputButton5: bool = false, // button 5 is pressed pub const Keycode = keycode_api.Keycode;
penInputEraserTip: bool = false, // eraser tip is used pub const SensorID = sensor_api.SensorID;
pad0: u24 = 0, pub const JoystickID = joystick_api.JoystickID;
rsvd: bool = false, pub const Keymod = keycode_api.Keymod;
pub const None = PenInputFlags{};
};
pub const MouseButtonFlags = packed struct(u32) {
buttonLeft: bool = false,
buttonMiddle: bool = false,
buttonX1: bool = false,
pad0: u28 = 0,
rsvd: bool = false,
pub const None = MouseButtonFlags{};
pub const ButtonRight: MouseButtonFlags = @bitCast(@as(u32, 3));
pub const ButtonX2: MouseButtonFlags = @bitCast(@as(u32, 5));
};
pub const Scancode = enum(c_int) {
scancodeBackslash = 49,
scancodeNonushash = 50,
scancodeGrave = 53,
scancodeInsert = 73,
scancodeNumlockclear = 83,
scancodeNonusbackslash = 100,
scancodeApplication = 101, //windows contextual menu, compose
scancodePower = 102,
scancodeHelp = 117, //AL Integrated Help Center
scancodeMenu = 118, //Menu (show menu)
scancodeStop = 120, //AC Stop
scancodeAgain = 121, //AC Redo/Repeat
scancodeUndo = 122, //AC Undo
scancodeCut = 123, //AC Cut
scancodeCopy = 124, //AC Copy
scancodePaste = 125, //AC Paste
scancodeFind = 126, //AC Find
scancodeInternational1 = 135,
scancodeInternational3 = 137, //Yen
scancodeLang1 = 144, //Hangul/English toggle
scancodeLang2 = 145, //Hanja conversion
scancodeLang3 = 146, //Katakana
scancodeLang4 = 147, //Hiragana
scancodeLang5 = 148, //Zenkaku/Hankaku
scancodeLang6 = 149, //reserved
scancodeLang7 = 150, //reserved
scancodeLang8 = 151, //reserved
scancodeLang9 = 152, //reserved
scancodeAlterase = 153, //Erase-Eaze
scancodeCancel = 155, //AC Cancel
scancodeLalt = 226, //alt, option
scancodeLgui = 227, //windows, command (apple), meta
scancodeRalt = 230, //alt gr, option
scancodeRgui = 231, //windows, command (apple), meta
scancodeMode = 257,
scancodeSleep = 258, //Sleep
scancodeWake = 259, //Wake
scancodeChannelIncrement = 260, //Channel Increment
scancodeChannelDecrement = 261, //Channel Decrement
scancodeMediaPlay = 262, //Play
scancodeMediaPause = 263, //Pause
scancodeMediaRecord = 264, //Record
scancodeMediaFastForward = 265, //Fast Forward
scancodeMediaRewind = 266, //Rewind
scancodeMediaNextTrack = 267, //Next Track
scancodeMediaPreviousTrack = 268, //Previous Track
scancodeMediaStop = 269, //Stop
scancodeMediaEject = 270, //Eject
scancodeMediaPlayPause = 271, //Play / Pause
scancodeMediaSelect = 272,
scancodeAcNew = 273, //AC New
scancodeAcOpen = 274, //AC Open
scancodeAcClose = 275, //AC Close
scancodeAcExit = 276, //AC Exit
scancodeAcSave = 277, //AC Save
scancodeAcPrint = 278, //AC Print
scancodeAcProperties = 279, //AC Properties
scancodeAcSearch = 280, //AC Search
scancodeAcHome = 281, //AC Home
scancodeAcBack = 282, //AC Back
scancodeAcForward = 283, //AC Forward
scancodeAcStop = 284, //AC Stop
scancodeAcRefresh = 285, //AC Refresh
scancodeAcBookmarks = 286, //AC Bookmarks
scancodeSoftleft = 287,
scancodeSoftright = 288,
scancodeCall = 289, //Used for accepting phone calls.
scancodeEndcall = 290, //Used for rejecting phone calls.
scancodeReserved = 400, //400-500 reserved for dynamic keycodes
scancodeCount = 512,
};
pub const TouchID = u64;
pub const KeyboardID = u32;
pub const PenAxis = enum(c_int) {
penAxisPressure, //Pen pressure. Unidirectional: 0 to 1.0
penAxisXtilt, //Pen horizontal tilt angle. Bidirectional: -90.0 to 90.0 (left-to-right).
penAxisYtilt, //Pen vertical tilt angle. Bidirectional: -90.0 to 90.0 (top-to-down).
penAxisDistance, //Pen distance to drawing surface. Unidirectional: 0.0 to 1.0
penAxisRotation, //Pen barrel rotation. Bidirectional: -180 to 179.9 (clockwise, 0 is facing up, -180.0 is facing down).
penAxisSlider, //Pen finger wheel or slider (e.g., Airbrush Pen). Unidirectional: 0 to 1.0
penAxisTangentialPressure, //Pressure from squeezing the pen ("barrel pressure").
penAxisCount, //Total known pen axis types in this version of SDL. This number may grow in future releases!
};
pub const MouseID = u32;
pub const MouseWheelDirection = enum(c_int) {
mousewheelNormal, //The scroll direction is normal
mousewheelFlipped, //The scroll direction is flipped / natural
};
pub const PowerState = enum(c_int) {
powerstateError = -1, //error determining power status
powerstateUnknown, //cannot determine power status
powerstateOnBattery, //Not plugged in, running on the battery
powerstateNoBattery, //Plugged in, no battery available
powerstateCharging, //Plugged in, charging battery
powerstateCharged,
};
pub const Window = opaque {};
pub const FingerID = u64;
pub const Keycode = u32;
pub const SensorID = u32;
pub const JoystickID = u32;
pub const Keymod = u16;
pub const EventType = enum(c_int) { pub const EventType = enum(c_int) {
eventFirst = 0, //Unused (do not remove) eventFirst = 0, //Unused (do not remove)
@ -171,9 +52,10 @@ pub const EventType = enum(c_int) {
eventDisplayDesktopModeChanged, //Display has changed desktop mode eventDisplayDesktopModeChanged, //Display has changed desktop mode
eventDisplayCurrentModeChanged, //Display has changed current mode eventDisplayCurrentModeChanged, //Display has changed current mode
eventDisplayContentScaleChanged, //Display has changed content scale eventDisplayContentScaleChanged, //Display has changed content scale
eventDisplayUsableBoundsChanged, //Display has changed usable bounds
eventWindowShown = 0x202, //Window has been shown eventWindowShown = 0x202, //Window has been shown
eventWindowHidden, //Window has been hidden eventWindowHidden, //Window has been hidden
eventWindowExposed, //Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event eventWindowExposed,
eventWindowMoved, //Window has been moved to data1, data2 eventWindowMoved, //Window has been moved to data1, data2
eventWindowResized, //Window has been resized to data1xdata2 eventWindowResized, //Window has been resized to data1xdata2
eventWindowPixelSizeChanged, //The pixel size of the window has changed to data1xdata2 eventWindowPixelSizeChanged, //The pixel size of the window has changed to data1xdata2
@ -204,6 +86,8 @@ pub const EventType = enum(c_int) {
eventKeyboardAdded, //A new keyboard has been inserted into the system eventKeyboardAdded, //A new keyboard has been inserted into the system
eventKeyboardRemoved, //A keyboard has been removed eventKeyboardRemoved, //A keyboard has been removed
eventTextEditingCandidates, //Keyboard text editing candidates eventTextEditingCandidates, //Keyboard text editing candidates
eventScreenKeyboardShown, //The on-screen keyboard has been shown
eventScreenKeyboardHidden, //The on-screen keyboard has been hidden
eventMouseMotion = 0x400, //Mouse moved eventMouseMotion = 0x400, //Mouse moved
eventMouseButtonDown, //Mouse button pressed eventMouseButtonDown, //Mouse button pressed
eventMouseButtonUp, //Mouse button released eventMouseButtonUp, //Mouse button released
@ -234,7 +118,10 @@ pub const EventType = enum(c_int) {
eventFingerUp, eventFingerUp,
eventFingerMotion, eventFingerMotion,
eventFingerCanceled, eventFingerCanceled,
eventClipboardUpdate = 0x900, //The clipboard or primary selection changed eventPinchBegin = 0x710, //Pinch gesture started
eventPinchUpdate, //Pinch gesture updated
eventPinchEnd, //Pinch gesture ended
eventClipboardUpdate = 0x900, //The clipboard changed
eventDropFile = 0x1000, //The system requests a file open eventDropFile = 0x1000, //The system requests a file open
eventDropText, //text/plain drag-and-drop event eventDropText, //text/plain drag-and-drop event
eventDropBegin, //A new set of drops is beginning (NULL filename) eventDropBegin, //A new set of drops is beginning (NULL filename)
@ -272,7 +159,7 @@ pub const CommonEvent = extern struct {
}; };
pub const DisplayEvent = extern struct { pub const DisplayEvent = extern struct {
_type: EventType, // SDL_DISPLAYEVENT_* _type: EventType, // SDL_EVENT_DISPLAY_*
reserved: u32, reserved: u32,
timestamp: u64, // In nanoseconds, populated using SDL_GetTicksNS() timestamp: u64, // In nanoseconds, populated using SDL_GetTicksNS()
displayID: DisplayID, // The associated display displayID: DisplayID, // The associated display
@ -387,6 +274,8 @@ pub const MouseWheelEvent = extern struct {
direction: MouseWheelDirection, // 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 direction: MouseWheelDirection, // 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
mouse_x: f32, // X coordinate, relative to window mouse_x: f32, // X coordinate, relative to window
mouse_y: f32, // Y coordinate, relative to window mouse_y: f32, // Y coordinate, relative to window
integer_x: i32, // The amount scrolled horizontally, accumulated to whole scroll "ticks" (added in 3.2.12)
integer_y: i32, // The amount scrolled vertically, accumulated to whole scroll "ticks" (added in 3.2.12)
}; };
pub const JoyAxisEvent = extern struct { pub const JoyAxisEvent = extern struct {
@ -544,6 +433,14 @@ pub const TouchFingerEvent = extern struct {
windowID: WindowID, // The window underneath the finger, if any windowID: WindowID, // The window underneath the finger, if any
}; };
pub const PinchFingerEvent = extern struct {
_type: EventType, // ::SDL_EVENT_PINCH_BEGIN or ::SDL_EVENT_PINCH_UPDATE or ::SDL_EVENT_PINCH_END
reserved: u32,
timestamp: u64, // In nanoseconds, populated using SDL_GetTicksNS()
scale: f32, // The scale change since the last SDL_EVENT_PINCH_UPDATE. Scale < 1 is "zoom out". Scale > 1 is "zoom in".
windowID: WindowID, // The window underneath the finger, if any
};
pub const PenProximityEvent = extern struct { pub const PenProximityEvent = extern struct {
_type: EventType, // SDL_EVENT_PEN_PROXIMITY_IN or SDL_EVENT_PEN_PROXIMITY_OUT _type: EventType, // SDL_EVENT_PEN_PROXIMITY_IN or SDL_EVENT_PEN_PROXIMITY_OUT
reserved: u32, reserved: u32,
@ -638,7 +535,7 @@ pub const QuitEvent = extern struct {
}; };
pub const UserEvent = extern struct { pub const UserEvent = extern struct {
_type: u32, // SDL_EVENT_USER through SDL_EVENT_LAST-1, Uint32 because these are not in the SDL_EventType enumeration _type: u32, // SDL_EVENT_USER through SDL_EVENT_LAST, Uint32 because these are not in the SDL_EventType enumeration
reserved: u32, reserved: u32,
timestamp: u64, // In nanoseconds, populated using SDL_GetTicksNS() timestamp: u64, // In nanoseconds, populated using SDL_GetTicksNS()
windowID: WindowID, // The associated window if any windowID: WindowID, // The associated window if any
@ -678,6 +575,7 @@ pub const Event = extern union {
quit: QuitEvent, // Quit request event data quit: QuitEvent, // Quit request event data
user: UserEvent, // Custom event data user: UserEvent, // Custom event data
tfinger: TouchFingerEvent, // Touch finger event data tfinger: TouchFingerEvent, // Touch finger event data
pinch: PinchFingerEvent, // Pinch event data
pproximity: PenProximityEvent, // Pen proximity event data pproximity: PenProximityEvent, // Pen proximity event data
ptouch: PenTouchEvent, // Pen tip touching event data ptouch: PenTouchEvent, // Pen tip touching event data
pmotion: PenMotionEvent, // Pen motion event data pmotion: PenMotionEvent, // Pen motion event data
@ -772,3 +670,7 @@ pub inline fn registerEvents(numevents: c_int) u32 {
pub inline fn getWindowFromEvent(event: ?*const Event) ?*Window { pub inline fn getWindowFromEvent(event: ?*const Event) ?*Window {
return @ptrCast(c.SDL_GetWindowFromEvent(@ptrCast(event))); return @ptrCast(c.SDL_GetWindowFromEvent(@ptrCast(event)));
} }
pub inline fn getEventDescription(event: ?*const Event, buf: [*c]u8, buflen: c_int) c_int {
return c.SDL_GetEventDescription(@ptrCast(event), buf, buflen);
}

View File

@ -1,7 +1,8 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const stdinc_api = @import("stdinc.zig");
pub const Time = i64; pub const Time = stdinc_api.Time;
pub inline fn getBasePath() [*c]const u8 { pub inline fn getBasePath() [*c]const u8 {
return c.SDL_GetBasePath(); return c.SDL_GetBasePath();

View File

@ -1,47 +1,20 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const joystick_api = @import("joystick.zig");
const guid_api = @import("guid.zig");
const properties_api = @import("properties.zig");
const iostream_api = @import("iostream.zig");
const sensor_api = @import("sensor.zig");
const power_api = @import("power.zig");
pub const JoystickConnectionState = enum(c_int) { pub const JoystickConnectionState = joystick_api.JoystickConnectionState;
joystickConnectionUnknown, pub const GUID = guid_api.GUID;
joystickConnectionWired, pub const PropertiesID = properties_api.PropertiesID;
joystickConnectionWireless, pub const IOStream = iostream_api.IOStream;
}; pub const JoystickID = joystick_api.JoystickID;
pub const SensorType = sensor_api.SensorType;
pub const GUID = extern struct { pub const PowerState = power_api.PowerState;
data: [16]u8, pub const Joystick = joystick_api.Joystick;
};
pub const PropertiesID = u32;
pub const IOStream = opaque {
pub inline fn addGamepadMappingsFromIO(iostream: *IOStream, closeio: bool) c_int {
return c.SDL_AddGamepadMappingsFromIO(@ptrCast(iostream), @bitCast(closeio));
}
};
pub const JoystickID = u32;
pub const SensorType = enum(c_int) {
sensorInvalid = -1, //Returned for an invalid sensor
sensorUnknown, //Unknown sensor type
sensorAccel, //Accelerometer
sensorGyro, //Gyroscope
sensorAccelL, //Accelerometer for left Joy-Con controller and Wii nunchuk
sensorGyroL, //Gyroscope for left Joy-Con controller
sensorAccelR, //Accelerometer for right Joy-Con controller
sensorGyroR, //Gyroscope for right Joy-Con controller
};
pub const PowerState = enum(c_int) {
powerstateError = -1, //error determining power status
powerstateUnknown, //cannot determine power status
powerstateOnBattery, //Not plugged in, running on the battery
powerstateNoBattery, //Plugged in, no battery available
powerstateCharging, //Plugged in, charging battery
powerstateCharged,
};
pub const Joystick = opaque {};
pub const Gamepad = opaque { pub const Gamepad = opaque {
pub inline fn getGamepadMapping(gamepad: *Gamepad) [*c]u8 { pub inline fn getGamepadMapping(gamepad: *Gamepad) [*c]u8 {
@ -216,6 +189,7 @@ pub const GamepadType = enum(c_int) {
gamepadTypeNintendoSwitchJoyconLeft, gamepadTypeNintendoSwitchJoyconLeft,
gamepadTypeNintendoSwitchJoyconRight, gamepadTypeNintendoSwitchJoyconRight,
gamepadTypeNintendoSwitchJoyconPair, gamepadTypeNintendoSwitchJoyconPair,
gamepadTypeGamecube,
gamepadTypeCount, gamepadTypeCount,
}; };
@ -236,14 +210,14 @@ pub const GamepadButton = enum(c_int) {
gamepadButtonDpadLeft, gamepadButtonDpadLeft,
gamepadButtonDpadRight, gamepadButtonDpadRight,
gamepadButtonMisc1, //Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button, Google Stadia capture button) gamepadButtonMisc1, //Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button, Google Stadia capture button)
gamepadButtonRightPaddle1, //Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1) gamepadButtonRightPaddle1, //Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1, DualSense Edge RB button, Right Joy-Con SR button)
gamepadButtonLeftPaddle1, //Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3) gamepadButtonLeftPaddle1, //Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3, DualSense Edge LB button, Left Joy-Con SL button)
gamepadButtonRightPaddle2, //Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2) gamepadButtonRightPaddle2, //Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2, DualSense Edge right Fn button, Right Joy-Con SL button)
gamepadButtonLeftPaddle2, //Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4) gamepadButtonLeftPaddle2, //Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4, DualSense Edge left Fn button, Left Joy-Con SR button)
gamepadButtonTouchpad, //PS4/PS5 touchpad button gamepadButtonTouchpad, //PS4/PS5 touchpad button
gamepadButtonMisc2, //Additional button gamepadButtonMisc2, //Additional button
gamepadButtonMisc3, //Additional button gamepadButtonMisc3, //Additional button (e.g. Nintendo GameCube left trigger click)
gamepadButtonMisc4, //Additional button gamepadButtonMisc4, //Additional button (e.g. Nintendo GameCube right trigger click)
gamepadButtonMisc5, //Additional button gamepadButtonMisc5, //Additional button
gamepadButtonMisc6, //Additional button gamepadButtonMisc6, //Additional button
gamepadButtonCount, gamepadButtonCount,
@ -283,6 +257,10 @@ pub inline fn addGamepadMapping(mapping: [*c]const u8) c_int {
return c.SDL_AddGamepadMapping(mapping); return c.SDL_AddGamepadMapping(mapping);
} }
pub inline fn addGamepadMappingsFromIO(src: ?*IOStream, closeio: bool) c_int {
return c.SDL_AddGamepadMappingsFromIO(@ptrCast(src), @bitCast(closeio));
}
pub inline fn addGamepadMappingsFromFile(file: [*c]const u8) c_int { pub inline fn addGamepadMappingsFromFile(file: [*c]const u8) c_int {
return c.SDL_AddGamepadMappingsFromFile(file); return c.SDL_AddGamepadMappingsFromFile(file);
} }

View File

@ -1,29 +1,17 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const pixels_api = @import("pixels.zig");
const properties_api = @import("properties.zig");
const rect_api = @import("rect.zig");
const video_api = @import("video.zig");
const surface_api = @import("surface.zig");
pub const FColor = extern struct { pub const FColor = pixels_api.FColor;
r: f32, pub const PropertiesID = properties_api.PropertiesID;
g: f32, pub const PixelFormat = pixels_api.PixelFormat;
b: f32, pub const Rect = rect_api.Rect;
a: f32, pub const Window = video_api.Window;
}; pub const FlipMode = surface_api.FlipMode;
pub const PropertiesID = u32;
pub const Rect = extern struct {
x: c_int,
y: c_int,
w: c_int,
h: c_int,
};
pub const Window = opaque {};
pub const FlipMode = enum(c_int) {
flipNone, //Do not flip
flipHorizontal, //flip horizontally
flipVertical, //flip vertically
};
pub const GPUDevice = opaque { pub const GPUDevice = opaque {
pub inline fn destroyGPUDevice(gpudevice: *GPUDevice) void { pub inline fn destroyGPUDevice(gpudevice: *GPUDevice) void {
@ -38,6 +26,10 @@ pub const GPUDevice = opaque {
return @bitCast(c.SDL_GetGPUShaderFormats(@ptrCast(gpudevice))); return @bitCast(c.SDL_GetGPUShaderFormats(@ptrCast(gpudevice)));
} }
pub inline fn getGPUDeviceProperties(gpudevice: *GPUDevice) PropertiesID {
return c.SDL_GetGPUDeviceProperties(@ptrCast(gpudevice));
}
pub inline fn createGPUComputePipeline(gpudevice: *GPUDevice, createinfo: ?*const GPUComputePipelineCreateInfo) ?*GPUComputePipeline { pub inline fn createGPUComputePipeline(gpudevice: *GPUDevice, createinfo: ?*const GPUComputePipelineCreateInfo) ?*GPUComputePipeline {
return @ptrCast(c.SDL_CreateGPUComputePipeline(@ptrCast(gpudevice), @ptrCast(createinfo))); return @ptrCast(c.SDL_CreateGPUComputePipeline(@ptrCast(gpudevice), @ptrCast(createinfo)));
} }
@ -666,7 +658,7 @@ pub const GPUCompareOp = enum(c_int) {
compareopLessOrEqual, //The comparison evaluates reference <= test. compareopLessOrEqual, //The comparison evaluates reference <= test.
compareopGreater, //The comparison evaluates reference > test. compareopGreater, //The comparison evaluates reference > test.
compareopNotEqual, //The comparison evaluates reference != test. compareopNotEqual, //The comparison evaluates reference != test.
compareopGreaterOrEqual, //The comparison evalutes reference >= test. compareopGreaterOrEqual, //The comparison evaluates reference >= test.
compareopAlways, //The comparison always evaluates true. compareopAlways, //The comparison always evaluates true.
}; };
@ -853,9 +845,9 @@ pub const GPUSamplerCreateInfo = extern struct {
pub const GPUVertexBufferDescription = extern struct { pub const GPUVertexBufferDescription = extern struct {
slot: u32, // The binding slot of the vertex buffer. slot: u32, // The binding slot of the vertex buffer.
pitch: u32, // The byte pitch between consecutive elements of the vertex buffer. pitch: u32, // The size of a single element + the offset between elements.
input_rate: GPUVertexInputRate, // Whether attribute addressing is a function of the vertex index or instance index. input_rate: GPUVertexInputRate, // Whether attribute addressing is a function of the vertex index or instance index.
instance_step_rate: u32, // The number of instances to draw using the same per-instance data before advancing in the instance buffer by one element. Ignored unless input_rate is SDL_GPU_VERTEXINPUTRATE_INSTANCE instance_step_rate: u32, // Reserved for future use. Must be set to 0.
}; };
pub const GPUVertexAttribute = extern struct { pub const GPUVertexAttribute = extern struct {
@ -945,9 +937,9 @@ pub const GPURasterizerState = extern struct {
pub const GPUMultisampleState = extern struct { pub const GPUMultisampleState = extern struct {
sample_count: GPUSampleCount, // The number of samples to be used in rasterization. sample_count: GPUSampleCount, // The number of samples to be used in rasterization.
sample_mask: u32, // Determines which samples get updated in the render targets. Treated as 0xFFFFFFFF if enable_mask is false. sample_mask: u32, // Reserved for future use. Must be set to 0.
enable_mask: bool, // Enables sample masking. enable_mask: bool, // Reserved for future use. Must be set to false.
padding1: u8, enable_alpha_to_coverage: bool, // true enables the alpha-to-coverage feature.
padding2: u8, padding2: u8,
padding3: u8, padding3: u8,
}; };
@ -1035,8 +1027,8 @@ pub const GPUDepthStencilTargetInfo = extern struct {
stencil_store_op: GPUStoreOp, // What is done with the stencil results of the render pass. stencil_store_op: GPUStoreOp, // What is done with the stencil results of the render pass.
cycle: bool, // true cycles the texture if the texture is bound and any load ops are not LOAD cycle: bool, // true cycles the texture if the texture is bound and any load ops are not LOAD
clear_stencil: u8, // The value to clear the stencil component to at the beginning of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used. clear_stencil: u8, // The value to clear the stencil component to at the beginning of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used.
padding1: u8, mip_level: u8, // The mip level to use as the depth stencil target.
padding2: u8, layer: u8, // The layer index to use as the depth stencil target.
}; };
pub const GPUBlitInfo = extern struct { pub const GPUBlitInfo = extern struct {
@ -1096,6 +1088,16 @@ pub inline fn createGPUDeviceWithProperties(props: PropertiesID) ?*GPUDevice {
return @ptrCast(c.SDL_CreateGPUDeviceWithProperties(props)); return @ptrCast(c.SDL_CreateGPUDeviceWithProperties(props));
} }
pub const GPUVulkanOptions = extern struct {
vulkan_api_version: u32, // The Vulkan API version to request for the instance. Use Vulkan's VK_MAKE_VERSION or VK_MAKE_API_VERSION.
feature_list: ?*anyopaque, // Pointer to the first element of a chain of Vulkan feature structs. (Requires API version 1.1 or higher.)
vulkan_10_physical_device_features: ?*anyopaque, // Pointer to a VkPhysicalDeviceFeatures struct to enable additional Vulkan 1.0 features.
device_extension_count: u32, // Number of additional device extensions to require.
device_extension_names: [*c][*c]const u8, // Pointer to a list of additional device extensions to require.
instance_extension_count: u32, // Number of additional instance extensions to require.
instance_extension_names: [*c][*c]const u8, // Pointer to a list of additional instance extensions to require.
};
pub inline fn getNumGPUDrivers() c_int { pub inline fn getNumGPUDrivers() c_int {
return c.SDL_GetNumGPUDrivers(); return c.SDL_GetNumGPUDrivers();
} }
@ -1111,3 +1113,11 @@ pub inline fn gpuTextureFormatTexelBlockSize(format: GPUTextureFormat) u32 {
pub inline fn calculateGPUTextureFormatSize(format: GPUTextureFormat, width: u32, height: u32, depth_or_layer_count: u32) u32 { pub inline fn calculateGPUTextureFormatSize(format: GPUTextureFormat, width: u32, height: u32, depth_or_layer_count: u32) u32 {
return c.SDL_CalculateGPUTextureFormatSize(@bitCast(format), width, height, depth_or_layer_count); return c.SDL_CalculateGPUTextureFormatSize(@bitCast(format), width, height, depth_or_layer_count);
} }
pub inline fn getPixelFormatFromGPUTextureFormat(format: GPUTextureFormat) PixelFormat {
return @bitCast(c.SDL_GetPixelFormatFromGPUTextureFormat(@bitCast(format)));
}
pub inline fn getGPUTextureFormatFromPixelFormat(format: PixelFormat) GPUTextureFormat {
return @bitCast(c.SDL_GetGPUTextureFormatFromPixelFormat(@bitCast(format)));
}

View File

@ -1,15 +1,8 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const joystick_api = @import("joystick.zig");
pub const Joystick = opaque { pub const Joystick = joystick_api.Joystick;
pub inline fn isJoystickHaptic(joystick: *Joystick) bool {
return @bitCast(c.SDL_IsJoystickHaptic(@ptrCast(joystick)));
}
pub inline fn openHapticFromJoystick(joystick: *Joystick) ?*Haptic {
return @ptrCast(c.SDL_OpenHapticFromJoystick(@ptrCast(joystick)));
}
};
pub const Haptic = opaque { pub const Haptic = opaque {
pub inline fn getHapticID(haptic: *Haptic) HapticID { pub inline fn getHapticID(haptic: *Haptic) HapticID {
@ -44,27 +37,27 @@ pub const Haptic = opaque {
return @bitCast(c.SDL_HapticEffectSupported(@ptrCast(haptic), @ptrCast(effect))); return @bitCast(c.SDL_HapticEffectSupported(@ptrCast(haptic), @ptrCast(effect)));
} }
pub inline fn createHapticEffect(haptic: *Haptic, effect: ?*const HapticEffect) c_int { pub inline fn createHapticEffect(haptic: *Haptic, effect: ?*const HapticEffect) HapticEffectID {
return c.SDL_CreateHapticEffect(@ptrCast(haptic), @ptrCast(effect)); return c.SDL_CreateHapticEffect(@ptrCast(haptic), @ptrCast(effect));
} }
pub inline fn updateHapticEffect(haptic: *Haptic, effect: c_int, data: ?*const HapticEffect) bool { pub inline fn updateHapticEffect(haptic: *Haptic, effect: HapticEffectID, data: ?*const HapticEffect) bool {
return @bitCast(c.SDL_UpdateHapticEffect(@ptrCast(haptic), effect, @ptrCast(data))); return @bitCast(c.SDL_UpdateHapticEffect(@ptrCast(haptic), effect, @ptrCast(data)));
} }
pub inline fn runHapticEffect(haptic: *Haptic, effect: c_int, iterations: u32) bool { pub inline fn runHapticEffect(haptic: *Haptic, effect: HapticEffectID, iterations: u32) bool {
return @bitCast(c.SDL_RunHapticEffect(@ptrCast(haptic), effect, iterations)); return @bitCast(c.SDL_RunHapticEffect(@ptrCast(haptic), effect, iterations));
} }
pub inline fn stopHapticEffect(haptic: *Haptic, effect: c_int) bool { pub inline fn stopHapticEffect(haptic: *Haptic, effect: HapticEffectID) bool {
return @bitCast(c.SDL_StopHapticEffect(@ptrCast(haptic), effect)); return @bitCast(c.SDL_StopHapticEffect(@ptrCast(haptic), effect));
} }
pub inline fn destroyHapticEffect(haptic: *Haptic, effect: c_int) void { pub inline fn destroyHapticEffect(haptic: *Haptic, effect: HapticEffectID) void {
return c.SDL_DestroyHapticEffect(@ptrCast(haptic), effect); return c.SDL_DestroyHapticEffect(@ptrCast(haptic), effect);
} }
pub inline fn getHapticEffectStatus(haptic: *Haptic, effect: c_int) bool { pub inline fn getHapticEffectStatus(haptic: *Haptic, effect: HapticEffectID) bool {
return @bitCast(c.SDL_GetHapticEffectStatus(@ptrCast(haptic), effect)); return @bitCast(c.SDL_GetHapticEffectStatus(@ptrCast(haptic), effect));
} }
@ -105,13 +98,19 @@ pub const Haptic = opaque {
} }
}; };
pub const HapticEffectType = u16;
pub const HapticDirectionType = u8;
pub const HapticEffectID = c_int;
pub const HapticDirection = extern struct { pub const HapticDirection = extern struct {
_type: u8, // The type of encoding. _type: HapticDirectionType, // The type of encoding.
dir: [3]i32, // The encoded direction. dir: [3]i32, // The encoded direction.
}; };
pub const HapticConstant = extern struct { pub const HapticConstant = extern struct {
_type: u16, // SDL_HAPTIC_CONSTANT _type: HapticEffectType, // SDL_HAPTIC_CONSTANT
direction: HapticDirection, // Direction of the effect. direction: HapticDirection, // Direction of the effect.
length: u32, // Duration of the effect. length: u32, // Duration of the effect.
delay: u16, // Delay before starting the effect. delay: u16, // Delay before starting the effect.
@ -155,7 +154,7 @@ pub const HapticCondition = extern struct {
}; };
pub const HapticRamp = extern struct { pub const HapticRamp = extern struct {
_type: u16, // SDL_HAPTIC_RAMP _type: HapticEffectType, // SDL_HAPTIC_RAMP
direction: HapticDirection, // Direction of the effect. direction: HapticDirection, // Direction of the effect.
length: u32, // Duration of the effect. length: u32, // Duration of the effect.
delay: u16, // Delay before starting the effect. delay: u16, // Delay before starting the effect.
@ -170,14 +169,14 @@ pub const HapticRamp = extern struct {
}; };
pub const HapticLeftRight = extern struct { pub const HapticLeftRight = extern struct {
_type: u16, // SDL_HAPTIC_LEFTRIGHT _type: HapticEffectType, // SDL_HAPTIC_LEFTRIGHT
length: u32, // Duration of the effect in milliseconds. length: u32, // Duration of the effect in milliseconds.
large_magnitude: u16, // Control of the large controller motor. large_magnitude: u16, // Control of the large controller motor.
small_magnitude: u16, // Control of the small controller motor. small_magnitude: u16, // Control of the small controller motor.
}; };
pub const HapticCustom = extern struct { pub const HapticCustom = extern struct {
_type: u16, // SDL_HAPTIC_CUSTOM _type: HapticEffectType, // SDL_HAPTIC_CUSTOM
direction: HapticDirection, // Direction of the effect. direction: HapticDirection, // Direction of the effect.
length: u32, // Duration of the effect. length: u32, // Duration of the effect.
delay: u16, // Delay before starting the effect. delay: u16, // Delay before starting the effect.
@ -194,7 +193,7 @@ pub const HapticCustom = extern struct {
}; };
pub const HapticEffect = extern union { pub const HapticEffect = extern union {
_type: u16, // Effect type. _type: HapticEffectType, // Effect type.
constant: HapticConstant, // Constant effect. constant: HapticConstant, // Constant effect.
periodic: HapticPeriodic, // Periodic effect. periodic: HapticPeriodic, // Periodic effect.
condition: HapticCondition, // Condition effect. condition: HapticCondition, // Condition effect.
@ -228,3 +227,11 @@ pub inline fn isMouseHaptic() bool {
pub inline fn openHapticFromMouse() ?*Haptic { pub inline fn openHapticFromMouse() ?*Haptic {
return @ptrCast(c.SDL_OpenHapticFromMouse()); return @ptrCast(c.SDL_OpenHapticFromMouse());
} }
pub inline fn isJoystickHaptic(joystick: ?*Joystick) bool {
return @bitCast(c.SDL_IsJoystickHaptic(@ptrCast(joystick)));
}
pub inline fn openHapticFromJoystick(joystick: ?*Joystick) ?*Haptic {
return @ptrCast(c.SDL_OpenHapticFromJoystick(@ptrCast(joystick)));
}

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub const HintPriority = enum(c_int) { pub const HintPriority = enum(c_int) {
hintDefault, hintDefault,
hintNormal, hintNormal,

View File

@ -1,10 +1,9 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub const InitFlags = packed struct(u32) { pub const InitFlags = packed struct(u32) {
initAudio: bool = false, // `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` initAudio: bool = false, // `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS`
initVideo: bool = false, // `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread initVideo: bool = false, // `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread
initJoystick: bool = false, // `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD initJoystick: bool = false, // `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`
initHaptic: bool = false, initHaptic: bool = false,
initGamepad: bool = false, // `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` initGamepad: bool = false, // `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK`
initEvents: bool = false, initEvents: bool = false,

View File

@ -1,31 +1,14 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const properties_api = @import("properties.zig");
const sensor_api = @import("sensor.zig");
const guid_api = @import("guid.zig");
const power_api = @import("power.zig");
pub const PropertiesID = u32; pub const PropertiesID = properties_api.PropertiesID;
pub const SensorType = sensor_api.SensorType;
pub const SensorType = enum(c_int) { pub const GUID = guid_api.GUID;
sensorInvalid = -1, //Returned for an invalid sensor pub const PowerState = power_api.PowerState;
sensorUnknown, //Unknown sensor type
sensorAccel, //Accelerometer
sensorGyro, //Gyroscope
sensorAccelL, //Accelerometer for left Joy-Con controller and Wii nunchuk
sensorGyroL, //Gyroscope for left Joy-Con controller
sensorAccelR, //Accelerometer for right Joy-Con controller
sensorGyroR, //Gyroscope for right Joy-Con controller
};
pub const GUID = extern struct {
data: [16]u8,
};
pub const PowerState = enum(c_int) {
powerstateError = -1, //error determining power status
powerstateUnknown, //cannot determine power status
powerstateOnBattery, //Not plugged in, running on the battery
powerstateNoBattery, //Plugged in, no battery available
powerstateCharging, //Plugged in, charging battery
powerstateCharged,
};
pub const Joystick = opaque { pub const Joystick = opaque {
pub inline fn setJoystickVirtualAxis(joystick: *Joystick, axis: c_int, value: i16) bool { pub inline fn setJoystickVirtualAxis(joystick: *Joystick, axis: c_int, value: i16) bool {

131
api/keyboard.zig Normal file
View File

@ -0,0 +1,131 @@
const std = @import("std");
pub const c = @import("c.zig").c;
const scancode_api = @import("scancode.zig");
const video_api = @import("video.zig");
const keycode_api = @import("keycode.zig");
const rect_api = @import("rect.zig");
const properties_api = @import("properties.zig");
pub const Scancode = scancode_api.Scancode;
pub const Window = video_api.Window;
pub const Keymod = keycode_api.Keymod;
pub const Rect = rect_api.Rect;
pub const Keycode = keycode_api.Keycode;
pub const PropertiesID = properties_api.PropertiesID;
pub const KeyboardID = u32;
pub inline fn hasKeyboard() bool {
return @bitCast(c.SDL_HasKeyboard());
}
pub inline fn getKeyboards(count: *c_int) ?*KeyboardID {
return @ptrCast(c.SDL_GetKeyboards(@ptrCast(count)));
}
pub inline fn getKeyboardNameForID(instance_id: KeyboardID) [*c]const u8 {
return c.SDL_GetKeyboardNameForID(instance_id);
}
pub inline fn getKeyboardFocus() ?*Window {
return @ptrCast(c.SDL_GetKeyboardFocus());
}
pub inline fn getKeyboardState(numkeys: *c_int) *const bool {
return @ptrCast(c.SDL_GetKeyboardState(@ptrCast(numkeys)));
}
pub inline fn resetKeyboard() void {
return c.SDL_ResetKeyboard();
}
pub inline fn getModState() Keymod {
return c.SDL_GetModState();
}
pub inline fn setModState(modstate: Keymod) void {
return c.SDL_SetModState(modstate);
}
pub inline fn getKeyFromScancode(scancode: Scancode, modstate: Keymod, key_event: bool) Keycode {
return c.SDL_GetKeyFromScancode(scancode, modstate, @bitCast(key_event));
}
pub inline fn getScancodeFromKey(key: Keycode, modstate: ?*Keymod) Scancode {
return c.SDL_GetScancodeFromKey(key, @ptrCast(modstate));
}
pub inline fn setScancodeName(scancode: Scancode, name: [*c]const u8) bool {
return @bitCast(c.SDL_SetScancodeName(scancode, name));
}
pub inline fn getScancodeName(scancode: Scancode) [*c]const u8 {
return c.SDL_GetScancodeName(scancode);
}
pub inline fn getScancodeFromName(name: [*c]const u8) Scancode {
return c.SDL_GetScancodeFromName(name);
}
pub inline fn getKeyName(key: Keycode) [*c]const u8 {
return c.SDL_GetKeyName(key);
}
pub inline fn getKeyFromName(name: [*c]const u8) Keycode {
return c.SDL_GetKeyFromName(name);
}
pub inline fn startTextInput(window: ?*Window) bool {
return @bitCast(c.SDL_StartTextInput(@ptrCast(window)));
}
pub const TextInputType = enum(c_int) {
textinputTypeText, //The input is text
textinputTypeTextName, //The input is a person's name
textinputTypeTextEmail, //The input is an e-mail address
textinputTypeTextUsername, //The input is a username
textinputTypeTextPasswordHidden, //The input is a secure password that is hidden
textinputTypeTextPasswordVisible, //The input is a secure password that is visible
textinputTypeNumber, //The input is a number
textinputTypeNumberPasswordHidden, //The input is a secure PIN that is hidden
textinputTypeNumberPasswordVisible, //The input is a secure PIN that is visible
};
pub const Capitalization = enum(c_int) {
capitalizeNone, //No auto-capitalization will be done
capitalizeSentences, //The first letter of sentences will be capitalized
capitalizeWords, //The first letter of words will be capitalized
capitalizeLetters, //All letters will be capitalized
};
pub inline fn startTextInputWithProperties(window: ?*Window, props: PropertiesID) bool {
return @bitCast(c.SDL_StartTextInputWithProperties(@ptrCast(window), props));
}
pub inline fn textInputActive(window: ?*Window) bool {
return @bitCast(c.SDL_TextInputActive(@ptrCast(window)));
}
pub inline fn stopTextInput(window: ?*Window) bool {
return @bitCast(c.SDL_StopTextInput(@ptrCast(window)));
}
pub inline fn clearComposition(window: ?*Window) bool {
return @bitCast(c.SDL_ClearComposition(@ptrCast(window)));
}
pub inline fn setTextInputArea(window: ?*Window, rect: ?*const Rect, cursor: c_int) bool {
return @bitCast(c.SDL_SetTextInputArea(@ptrCast(window), @ptrCast(rect), cursor));
}
pub inline fn getTextInputArea(window: ?*Window, rect: ?*Rect, cursor: *c_int) bool {
return @bitCast(c.SDL_GetTextInputArea(@ptrCast(window), @ptrCast(rect), @ptrCast(cursor)));
}
pub inline fn hasScreenKeyboardSupport() bool {
return @bitCast(c.SDL_HasScreenKeyboardSupport());
}
pub inline fn screenKeyboardShown(window: ?*Window) bool {
return @bitCast(c.SDL_ScreenKeyboardShown(@ptrCast(window)));
}

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub const Keycode = u32; pub const Keycode = u32;
pub const Keymod = u16; pub const Keymod = u16;

View File

@ -1,7 +1,8 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const stdinc_api = @import("stdinc.zig");
pub const FunctionPointer = c.SDL_FunctionPointer; pub const FunctionPointer = stdinc_api.FunctionPointer;
pub const SharedObject = opaque { pub const SharedObject = opaque {
pub inline fn loadFunction(sharedobject: *SharedObject, name: [*c]const u8) FunctionPointer { pub inline fn loadFunction(sharedobject: *SharedObject, name: [*c]const u8) FunctionPointer {

View File

@ -1,7 +1,8 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const video_api = @import("video.zig");
pub const Window = opaque {}; pub const Window = video_api.Window;
pub const MessageBoxFlags = packed struct(u32) { pub const MessageBoxFlags = packed struct(u32) {
messageboxError: bool = false, // error dialog messageboxError: bool = false, // error dialog

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub inline fn openURL(url: [*c]const u8) bool { pub inline fn openURL(url: [*c]const u8) bool {
return @bitCast(c.SDL_OpenURL(url)); return @bitCast(c.SDL_OpenURL(url));
} }

View File

@ -1,25 +1,10 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const video_api = @import("video.zig");
const surface_api = @import("surface.zig");
pub const Window = opaque { pub const Window = video_api.Window;
pub inline fn warpMouseInWindow(window: *Window, x: f32, y: f32) void { pub const Surface = surface_api.Surface;
return c.SDL_WarpMouseInWindow(@ptrCast(window), x, y);
}
pub inline fn setWindowRelativeMouseMode(window: *Window, enabled: bool) bool {
return @bitCast(c.SDL_SetWindowRelativeMouseMode(@ptrCast(window), @bitCast(enabled)));
}
pub inline fn getWindowRelativeMouseMode(window: *Window) bool {
return @bitCast(c.SDL_GetWindowRelativeMouseMode(@ptrCast(window)));
}
};
pub const Surface = opaque {
pub inline fn createColorCursor(surface: *Surface, hot_x: c_int, hot_y: c_int) ?*Cursor {
return @ptrCast(c.SDL_CreateColorCursor(@ptrCast(surface), hot_x, hot_y));
}
};
pub const MouseID = u32; pub const MouseID = u32;
@ -62,6 +47,11 @@ pub const MouseWheelDirection = enum(c_int) {
mousewheelFlipped, //The scroll direction is flipped / natural mousewheelFlipped, //The scroll direction is flipped / natural
}; };
pub const CursorFrameInfo = extern struct {
surface: ?*Surface, // The surface data for this frame
duration: u32, // The frame duration in milliseconds (a duration of 0 is infinite)
};
pub const MouseButtonFlags = packed struct(u32) { pub const MouseButtonFlags = packed struct(u32) {
buttonLeft: bool = false, buttonLeft: bool = false,
buttonMiddle: bool = false, buttonMiddle: bool = false,
@ -74,6 +64,8 @@ pub const MouseButtonFlags = packed struct(u32) {
pub const ButtonX2: MouseButtonFlags = @bitCast(@as(u32, 5)); pub const ButtonX2: MouseButtonFlags = @bitCast(@as(u32, 5));
}; };
pub const MouseMotionTransformCallback = c.SDL_MouseMotionTransformCallback;
pub inline fn hasMouse() bool { pub inline fn hasMouse() bool {
return @bitCast(c.SDL_HasMouse()); return @bitCast(c.SDL_HasMouse());
} }
@ -102,10 +94,26 @@ pub inline fn getRelativeMouseState(x: *f32, y: *f32) MouseButtonFlags {
return @bitCast(c.SDL_GetRelativeMouseState(@ptrCast(x), @ptrCast(y))); return @bitCast(c.SDL_GetRelativeMouseState(@ptrCast(x), @ptrCast(y)));
} }
pub inline fn warpMouseInWindow(window: ?*Window, x: f32, y: f32) void {
return c.SDL_WarpMouseInWindow(@ptrCast(window), x, y);
}
pub inline fn warpMouseGlobal(x: f32, y: f32) bool { pub inline fn warpMouseGlobal(x: f32, y: f32) bool {
return @bitCast(c.SDL_WarpMouseGlobal(x, y)); return @bitCast(c.SDL_WarpMouseGlobal(x, y));
} }
pub inline fn setRelativeMouseTransform(callback: MouseMotionTransformCallback, userdata: ?*anyopaque) bool {
return @bitCast(c.SDL_SetRelativeMouseTransform(callback, userdata));
}
pub inline fn setWindowRelativeMouseMode(window: ?*Window, enabled: bool) bool {
return @bitCast(c.SDL_SetWindowRelativeMouseMode(@ptrCast(window), @bitCast(enabled)));
}
pub inline fn getWindowRelativeMouseMode(window: ?*Window) bool {
return @bitCast(c.SDL_GetWindowRelativeMouseMode(@ptrCast(window)));
}
pub inline fn captureMouse(enabled: bool) bool { pub inline fn captureMouse(enabled: bool) bool {
return @bitCast(c.SDL_CaptureMouse(@bitCast(enabled))); return @bitCast(c.SDL_CaptureMouse(@bitCast(enabled)));
} }
@ -114,6 +122,14 @@ pub inline fn createCursor(data: [*c]const u8, mask: [*c]const u8, w: c_int, h:
return @ptrCast(c.SDL_CreateCursor(data, mask, w, h, hot_x, hot_y)); return @ptrCast(c.SDL_CreateCursor(data, mask, w, h, hot_x, hot_y));
} }
pub inline fn createColorCursor(surface: ?*Surface, hot_x: c_int, hot_y: c_int) ?*Cursor {
return @ptrCast(c.SDL_CreateColorCursor(@ptrCast(surface), hot_x, hot_y));
}
pub inline fn createAnimatedCursor(frames: ?*CursorFrameInfo, frame_count: c_int, hot_x: c_int, hot_y: c_int) ?*Cursor {
return @ptrCast(c.SDL_CreateAnimatedCursor(@ptrCast(frames), frame_count, hot_x, hot_y));
}
pub inline fn createSystemCursor(id: SystemCursor) ?*Cursor { pub inline fn createSystemCursor(id: SystemCursor) ?*Cursor {
return @ptrCast(c.SDL_CreateSystemCursor(id)); return @ptrCast(c.SDL_CreateSystemCursor(id));
} }

2
api/opengl.zig Normal file
View File

@ -0,0 +1,2 @@
const std = @import("std");
pub const c = @import("c.zig").c;

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub const PixelType = enum(c_int) { pub const PixelType = enum(c_int) {
pixeltypeUnknown, pixeltypeUnknown,
pixeltypeIndex1, pixeltypeIndex1,
@ -67,6 +66,7 @@ pub const PixelFormat = enum(c_int) {
pixelformatNv21 = 0x3132564e, //Planar mode: Y + V/U interleaved (2 planes) pixelformatNv21 = 0x3132564e, //Planar mode: Y + V/U interleaved (2 planes)
pixelformatP010 = 0x30313050, //Planar mode: Y + U/V interleaved (2 planes) pixelformatP010 = 0x30313050, //Planar mode: Y + U/V interleaved (2 planes)
pixelformatExternalOes = 0x2053454f, //Android video texture format pixelformatExternalOes = 0x2053454f, //Android video texture format
pixelformatMjpg = 0x47504a4d, //Motion JPEG
}; };
pub const ColorRange = enum(c_int) { pub const ColorRange = enum(c_int) {
@ -150,7 +150,7 @@ pub const Colorspace = enum(c_int) {
colorspaceBt2020Full = 0x22102609, //Equivalent to DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020 colorspaceBt2020Full = 0x22102609, //Equivalent to DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020
pub const colorspaceRgbDefault = .colorspaceSrgb; //The default colorspace for RGB surfaces if no colorspace is specified pub const colorspaceRgbDefault = .colorspaceSrgb; //The default colorspace for RGB surfaces if no colorspace is specified
pub const colorspaceYuvDefault = .colorspaceJpeg; //The default colorspace for YUV surfaces if no colorspace is specified pub const colorspaceYuvDefault = .colorspaceBt601Limited; //The default colorspace for YUV surfaces if no colorspace is specified
}; };
pub const Color = extern struct { pub const Color = extern struct {
@ -229,10 +229,10 @@ pub inline fn mapRGBA(format: ?*const PixelFormatDetails, palette: ?*const Palet
return c.SDL_MapRGBA(@ptrCast(format), @ptrCast(palette), r, g, b, a); return c.SDL_MapRGBA(@ptrCast(format), @ptrCast(palette), r, g, b, a);
} }
pub inline fn getRGB(pixel: u32, format: ?*const PixelFormatDetails, palette: ?*const Palette, r: [*c]u8, g: [*c]u8, b: [*c]u8) void { pub inline fn getRGB(pixelvalue: u32, format: ?*const PixelFormatDetails, palette: ?*const Palette, r: [*c]u8, g: [*c]u8, b: [*c]u8) void {
return c.SDL_GetRGB(pixel, @ptrCast(format), @ptrCast(palette), r, g, b); return c.SDL_GetRGB(pixelvalue, @ptrCast(format), @ptrCast(palette), r, g, b);
} }
pub inline fn getRGBA(pixel: u32, format: ?*const PixelFormatDetails, palette: ?*const Palette, r: [*c]u8, g: [*c]u8, b: [*c]u8, a: [*c]u8) void { pub inline fn getRGBA(pixelvalue: u32, format: ?*const PixelFormatDetails, palette: ?*const Palette, r: [*c]u8, g: [*c]u8, b: [*c]u8, a: [*c]u8) void {
return c.SDL_GetRGBA(pixel, @ptrCast(format), @ptrCast(palette), r, g, b, a); return c.SDL_GetRGBA(pixelvalue, @ptrCast(format), @ptrCast(palette), r, g, b, a);
} }

14
api/power.zig Normal file
View File

@ -0,0 +1,14 @@
const std = @import("std");
pub const c = @import("c.zig").c;
pub const PowerState = enum(c_int) {
powerstateError = -1, //error determining power status
powerstateUnknown, //cannot determine power status
powerstateOnBattery, //Not plugged in, running on the battery
powerstateNoBattery, //Plugged in, no battery available
powerstateCharging, //Plugged in, charging battery
powerstateCharged,
};
pub inline fn getPowerInfo(seconds: *c_int, percent: *c_int) PowerState {
return c.SDL_GetPowerInfo(@ptrCast(seconds), @ptrCast(percent));
}

52
api/process.zig Normal file
View File

@ -0,0 +1,52 @@
const std = @import("std");
pub const c = @import("c.zig").c;
const properties_api = @import("properties.zig");
const iostream_api = @import("iostream.zig");
pub const PropertiesID = properties_api.PropertiesID;
pub const IOStream = iostream_api.IOStream;
pub const Process = opaque {
pub inline fn getProcessProperties(process: *Process) PropertiesID {
return c.SDL_GetProcessProperties(@ptrCast(process));
}
pub inline fn readProcess(process: *Process, datasize: *usize, exitcode: *c_int) ?*anyopaque {
return c.SDL_ReadProcess(@ptrCast(process), @ptrCast(datasize), @ptrCast(exitcode));
}
pub inline fn getProcessInput(process: *Process) ?*IOStream {
return @ptrCast(c.SDL_GetProcessInput(@ptrCast(process)));
}
pub inline fn getProcessOutput(process: *Process) ?*IOStream {
return @ptrCast(c.SDL_GetProcessOutput(@ptrCast(process)));
}
pub inline fn killProcess(process: *Process, force: bool) bool {
return @bitCast(c.SDL_KillProcess(@ptrCast(process), @bitCast(force)));
}
pub inline fn waitProcess(process: *Process, block: bool, exitcode: *c_int) bool {
return @bitCast(c.SDL_WaitProcess(@ptrCast(process), @bitCast(block), @ptrCast(exitcode)));
}
pub inline fn destroyProcess(process: *Process) void {
return c.SDL_DestroyProcess(@ptrCast(process));
}
};
pub inline fn createProcess(args: [*c]const [*c]const u8, pipe_stdio: bool) ?*Process {
return @ptrCast(c.SDL_CreateProcess(args, @bitCast(pipe_stdio)));
}
pub const ProcessIO = enum(c_int) {
processStdioInherited, //The I/O stream is inherited from the application.
processStdioNull, //The I/O stream is ignored.
processStdioApp, //The I/O stream is connected to a new SDL_IOStream that the application can read or write
processStdioRedirect, //The I/O stream is redirected to an existing SDL_IOStream.
};
pub inline fn createProcessWithProperties(props: PropertiesID) ?*Process {
return @ptrCast(c.SDL_CreateProcessWithProperties(props));
}

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub const PropertiesID = u32; pub const PropertiesID = u32;
pub const PropertyType = enum(c_int) { pub const PropertyType = enum(c_int) {

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub const Point = extern struct { pub const Point = extern struct {
x: c_int, x: c_int,
y: c_int, y: c_int,

File diff suppressed because it is too large Load Diff

74
api/scancode.zig Normal file
View File

@ -0,0 +1,74 @@
const std = @import("std");
pub const c = @import("c.zig").c;
pub const Scancode = enum(c_int) {
scancodeBackslash = 49,
scancodeNonushash = 50,
scancodeGrave = 53,
scancodeInsert = 73,
scancodeNumlockclear = 83,
scancodeNonusbackslash = 100,
scancodeApplication = 101, //windows contextual menu, compose
scancodePower = 102,
scancodeHelp = 117, //AL Integrated Help Center
scancodeMenu = 118, //Menu (show menu)
scancodeStop = 120, //AC Stop
scancodeAgain = 121, //AC Redo/Repeat
scancodeUndo = 122, //AC Undo
scancodeCut = 123, //AC Cut
scancodeCopy = 124, //AC Copy
scancodePaste = 125, //AC Paste
scancodeFind = 126, //AC Find
scancodeInternational1 = 135,
scancodeInternational3 = 137, //Yen
scancodeLang1 = 144, //Hangul/English toggle
scancodeLang2 = 145, //Hanja conversion
scancodeLang3 = 146, //Katakana
scancodeLang4 = 147, //Hiragana
scancodeLang5 = 148, //Zenkaku/Hankaku
scancodeLang6 = 149, //reserved
scancodeLang7 = 150, //reserved
scancodeLang8 = 151, //reserved
scancodeLang9 = 152, //reserved
scancodeAlterase = 153, //Erase-Eaze
scancodeCancel = 155, //AC Cancel
scancodeLalt = 226, //alt, option
scancodeLgui = 227, //windows, command (apple), meta
scancodeRalt = 230, //alt gr, option
scancodeRgui = 231, //windows, command (apple), meta
scancodeMode = 257,
scancodeSleep = 258, //Sleep
scancodeWake = 259, //Wake
scancodeChannelIncrement = 260, //Channel Increment
scancodeChannelDecrement = 261, //Channel Decrement
scancodeMediaPlay = 262, //Play
scancodeMediaPause = 263, //Pause
scancodeMediaRecord = 264, //Record
scancodeMediaFastForward = 265, //Fast Forward
scancodeMediaRewind = 266, //Rewind
scancodeMediaNextTrack = 267, //Next Track
scancodeMediaPreviousTrack = 268, //Previous Track
scancodeMediaStop = 269, //Stop
scancodeMediaEject = 270, //Eject
scancodeMediaPlayPause = 271, //Play / Pause
scancodeMediaSelect = 272,
scancodeAcNew = 273, //AC New
scancodeAcOpen = 274, //AC Open
scancodeAcClose = 275, //AC Close
scancodeAcExit = 276, //AC Exit
scancodeAcSave = 277, //AC Save
scancodeAcPrint = 278, //AC Print
scancodeAcProperties = 279, //AC Properties
scancodeAcSearch = 280, //AC Search
scancodeAcHome = 281, //AC Home
scancodeAcBack = 282, //AC Back
scancodeAcForward = 283, //AC Forward
scancodeAcStop = 284, //AC Stop
scancodeAcRefresh = 285, //AC Refresh
scancodeAcBookmarks = 286, //AC Bookmarks
scancodeSoftleft = 287,
scancodeSoftright = 288,
scancodeCall = 289, //Used for accepting phone calls.
scancodeEndcall = 290, //Used for rejecting phone calls.
scancodeReserved = 400, //400-500 reserved for dynamic keycodes
scancodeCount = 512,
};

View File

@ -1,7 +1,8 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const properties_api = @import("properties.zig");
pub const PropertiesID = u32; pub const PropertiesID = properties_api.PropertiesID;
pub const Sensor = opaque { pub const Sensor = opaque {
pub inline fn getSensorProperties(sensor: *Sensor) PropertiesID { pub inline fn getSensorProperties(sensor: *Sensor) PropertiesID {
@ -44,6 +45,7 @@ pub const SensorType = enum(c_int) {
sensorGyroL, //Gyroscope for left Joy-Con controller sensorGyroL, //Gyroscope for left Joy-Con controller
sensorAccelR, //Accelerometer for right Joy-Con controller sensorAccelR, //Accelerometer for right Joy-Con controller
sensorGyroR, //Gyroscope for right Joy-Con controller sensorGyroR, //Gyroscope for right Joy-Con controller
sensorCount,
}; };
pub inline fn getSensors(count: *c_int) ?*SensorID { pub inline fn getSensors(count: *c_int) ?*SensorID {

View File

@ -1,34 +1,15 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const filesystem_api = @import("filesystem.zig");
const stdinc_api = @import("stdinc.zig");
const properties_api = @import("properties.zig");
pub const PathInfo = extern struct { pub const PathInfo = filesystem_api.PathInfo;
_type: PathType, // the path type pub const PathType = filesystem_api.PathType;
size: u64, // the file size in bytes pub const Time = stdinc_api.Time;
create_time: Time, // the time when the path was created pub const GlobFlags = filesystem_api.GlobFlags;
modify_time: Time, // the last time the path was modified pub const EnumerateDirectoryCallback = filesystem_api.EnumerateDirectoryCallback;
access_time: Time, // the last time the path was read pub const PropertiesID = properties_api.PropertiesID;
};
pub const PathType = enum(c_int) {
pathtypeNone, //path does not exist
pathtypeFile, //a normal file
pathtypeDirectory, //a directory
pathtypeOther,
};
pub const Time = i64;
pub const GlobFlags = packed struct(u32) {
globCaseinsensitive: bool = false,
pad0: u30 = 0,
rsvd: bool = false,
pub const None = GlobFlags{};
};
pub const EnumerateDirectoryCallback = c.SDL_EnumerateDirectoryCallback;
pub const PropertiesID = u32;
pub const StorageInterface = extern struct { pub const StorageInterface = extern struct {
version: u32, version: u32,

View File

@ -1,78 +1,19 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const pixels_api = @import("pixels.zig");
const blendmode_api = @import("blendmode.zig");
const iostream_api = @import("iostream.zig");
const rect_api = @import("rect.zig");
const properties_api = @import("properties.zig");
pub const PixelFormat = enum(c_int) { pub const PixelFormat = pixels_api.PixelFormat;
pixelformatYv12 = 0x32315659, //Planar mode: Y + V + U (3 planes) pub const BlendMode = blendmode_api.BlendMode;
pixelformatIyuv = 0x56555949, //Planar mode: Y + U + V (3 planes) pub const IOStream = iostream_api.IOStream;
pixelformatYuy2 = 0x32595559, //Packed mode: Y0+U0+Y1+V0 (1 plane) pub const Rect = rect_api.Rect;
pixelformatUyvy = 0x59565955, //Packed mode: U0+Y0+V0+Y1 (1 plane) pub const Palette = pixels_api.Palette;
pixelformatYvyu = 0x55595659, //Packed mode: Y0+V0+Y1+U0 (1 plane) pub const Color = pixels_api.Color;
pixelformatNv12 = 0x3231564e, //Planar mode: Y + U/V interleaved (2 planes) pub const Colorspace = pixels_api.Colorspace;
pixelformatNv21 = 0x3132564e, //Planar mode: Y + V/U interleaved (2 planes) pub const PropertiesID = properties_api.PropertiesID;
pixelformatP010 = 0x30313050, //Planar mode: Y + U/V interleaved (2 planes)
pixelformatExternalOes = 0x2053454f, //Android video texture format
};
pub const BlendMode = u32;
pub const IOStream = opaque {
pub inline fn loadBMP_IO(iostream: *IOStream, closeio: bool) ?*Surface {
return @ptrCast(c.SDL_LoadBMP_IO(@ptrCast(iostream), @bitCast(closeio)));
}
};
pub const Rect = extern struct {
x: c_int,
y: c_int,
w: c_int,
h: c_int,
};
pub const Palette = extern struct {
ncolors: c_int, // number of elements in `colors`.
colors: ?*Color, // an array of colors, `ncolors` long.
version: u32, // internal use only, do not touch.
refcount: c_int, // internal use only, do not touch.
};
pub const Color = extern struct {
r: u8,
g: u8,
b: u8,
a: u8,
};
pub const Colorspace = enum(c_int) {
colorspaceSrgb = 0x120005a0, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
colorRangeFull,
colorPrimariesBt709,
transferCharacteristicsSrgb,
matrixCoefficientsIdentity,
colorspaceSrgbLinear = 0x12000500, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
transferCharacteristicsLinear,
colorspaceHdr10 = 0x12002600, //Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
colorPrimariesBt2020,
transferCharacteristicsPq,
colorspaceJpeg = 0x220004c6, //Equivalent to DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601
transferCharacteristicsBt601,
matrixCoefficientsBt601,
colorspaceBt601Limited = 0x211018c6, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601
colorRangeLimited,
colorPrimariesBt601,
colorspaceBt601Full = 0x221018c6, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601
colorspaceBt709Limited = 0x21100421, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
transferCharacteristicsBt709,
matrixCoefficientsBt709,
colorspaceBt709Full = 0x22100421, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
colorspaceBt2020Limited = 0x21102609, //Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020
matrixCoefficientsBt2020Ncl,
colorspaceBt2020Full = 0x22102609, //Equivalent to DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020
pub const colorspaceRgbDefault = .colorspaceSrgb; //The default colorspace for RGB surfaces if no colorspace is specified
pub const colorspaceYuvDefault = .colorspaceJpeg; //The default colorspace for YUV surfaces if no colorspace is specified
};
pub const PropertiesID = u32;
pub const SurfaceFlags = packed struct(u32) { pub const SurfaceFlags = packed struct(u32) {
surfacePreallocated: bool = false, // Surface uses preallocated pixel memory surfacePreallocated: bool = false, // Surface uses preallocated pixel memory
@ -88,12 +29,16 @@ pub const SurfaceFlags = packed struct(u32) {
pub const ScaleMode = enum(c_int) { pub const ScaleMode = enum(c_int) {
scalemodeNearest, //nearest pixel sampling scalemodeNearest, //nearest pixel sampling
scalemodeLinear, //linear filtering scalemodeLinear, //linear filtering
scalemodePixelart,
}; };
pub const FlipMode = enum(c_int) { pub const FlipMode = packed struct(u32) {
flipNone, //Do not flip flipHorizontal: bool = false, // flip horizontally
flipHorizontal, //flip horizontally flipVertical: bool = false, // flip vertically
flipVertical, //flip vertically pad0: u29 = 0,
rsvd: bool = false,
pub const None = FlipMode{};
}; };
pub const Surface = opaque { pub const Surface = opaque {
@ -157,6 +102,14 @@ pub const Surface = opaque {
return @bitCast(c.SDL_SaveBMP(@ptrCast(surface), file)); return @bitCast(c.SDL_SaveBMP(@ptrCast(surface), file));
} }
pub inline fn savePNG_IO(surface: *Surface, dst: ?*IOStream, closeio: bool) bool {
return @bitCast(c.SDL_SavePNG_IO(@ptrCast(surface), @ptrCast(dst), @bitCast(closeio)));
}
pub inline fn savePNG(surface: *Surface, file: [*c]const u8) bool {
return @bitCast(c.SDL_SavePNG(@ptrCast(surface), file));
}
pub inline fn setSurfaceRLE(surface: *Surface, enabled: bool) bool { pub inline fn setSurfaceRLE(surface: *Surface, enabled: bool) bool {
return @bitCast(c.SDL_SetSurfaceRLE(@ptrCast(surface), @bitCast(enabled))); return @bitCast(c.SDL_SetSurfaceRLE(@ptrCast(surface), @bitCast(enabled)));
} }
@ -213,6 +166,10 @@ pub const Surface = opaque {
return @bitCast(c.SDL_FlipSurface(@ptrCast(surface), @intFromEnum(flip))); return @bitCast(c.SDL_FlipSurface(@ptrCast(surface), @intFromEnum(flip)));
} }
pub inline fn rotateSurface(surface: *Surface, angle: f32) ?*Surface {
return @ptrCast(c.SDL_RotateSurface(@ptrCast(surface), angle));
}
pub inline fn duplicateSurface(surface: *Surface) ?*Surface { pub inline fn duplicateSurface(surface: *Surface) ?*Surface {
return @ptrCast(c.SDL_DuplicateSurface(@ptrCast(surface))); return @ptrCast(c.SDL_DuplicateSurface(@ptrCast(surface)));
} }
@ -261,6 +218,10 @@ pub const Surface = opaque {
return @bitCast(c.SDL_BlitSurfaceUncheckedScaled(@ptrCast(surface), @ptrCast(srcrect), @ptrCast(dst), @ptrCast(dstrect), @intFromEnum(scaleMode))); return @bitCast(c.SDL_BlitSurfaceUncheckedScaled(@ptrCast(surface), @ptrCast(srcrect), @ptrCast(dst), @ptrCast(dstrect), @intFromEnum(scaleMode)));
} }
pub inline fn stretchSurface(surface: *Surface, srcrect: ?*const Rect, dst: ?*Surface, dstrect: ?*const Rect, scaleMode: ScaleMode) bool {
return @bitCast(c.SDL_StretchSurface(@ptrCast(surface), @ptrCast(srcrect), @ptrCast(dst), @ptrCast(dstrect), @intFromEnum(scaleMode)));
}
pub inline fn blitSurfaceTiled(surface: *Surface, srcrect: ?*const Rect, dst: ?*Surface, dstrect: ?*const Rect) bool { pub inline fn blitSurfaceTiled(surface: *Surface, srcrect: ?*const Rect, dst: ?*Surface, dstrect: ?*const Rect) bool {
return @bitCast(c.SDL_BlitSurfaceTiled(@ptrCast(surface), @ptrCast(srcrect), @ptrCast(dst), @ptrCast(dstrect))); return @bitCast(c.SDL_BlitSurfaceTiled(@ptrCast(surface), @ptrCast(srcrect), @ptrCast(dst), @ptrCast(dstrect)));
} }
@ -306,10 +267,30 @@ pub inline fn createSurfaceFrom(width: c_int, height: c_int, format: PixelFormat
return @ptrCast(c.SDL_CreateSurfaceFrom(width, height, @bitCast(format), pixels, pitch)); return @ptrCast(c.SDL_CreateSurfaceFrom(width, height, @bitCast(format), pixels, pitch));
} }
pub inline fn loadSurface_IO(src: ?*IOStream, closeio: bool) ?*Surface {
return @ptrCast(c.SDL_LoadSurface_IO(@ptrCast(src), @bitCast(closeio)));
}
pub inline fn loadSurface(file: [*c]const u8) ?*Surface {
return @ptrCast(c.SDL_LoadSurface(file));
}
pub inline fn loadBMP_IO(src: ?*IOStream, closeio: bool) ?*Surface {
return @ptrCast(c.SDL_LoadBMP_IO(@ptrCast(src), @bitCast(closeio)));
}
pub inline fn loadBMP(file: [*c]const u8) ?*Surface { pub inline fn loadBMP(file: [*c]const u8) ?*Surface {
return @ptrCast(c.SDL_LoadBMP(file)); return @ptrCast(c.SDL_LoadBMP(file));
} }
pub inline fn loadPNG_IO(src: ?*IOStream, closeio: bool) ?*Surface {
return @ptrCast(c.SDL_LoadPNG_IO(@ptrCast(src), @bitCast(closeio)));
}
pub inline fn loadPNG(file: [*c]const u8) ?*Surface {
return @ptrCast(c.SDL_LoadPNG(file));
}
pub inline fn convertPixels(width: c_int, height: c_int, src_format: PixelFormat, src: ?*const anyopaque, src_pitch: c_int, dst_format: PixelFormat, dst: ?*anyopaque, dst_pitch: c_int) bool { pub inline fn convertPixels(width: c_int, height: c_int, src_format: PixelFormat, src: ?*const anyopaque, src_pitch: c_int, dst_format: PixelFormat, dst: ?*anyopaque, dst_pitch: c_int) bool {
return @bitCast(c.SDL_ConvertPixels(width, height, @bitCast(src_format), src, src_pitch, @bitCast(dst_format), dst, dst_pitch)); return @bitCast(c.SDL_ConvertPixels(width, height, @bitCast(src_format), src, src_pitch, @bitCast(dst_format), dst, dst_pitch));
} }

View File

@ -1,13 +1,9 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const video_api = @import("video.zig");
pub const DisplayID = u32; pub const DisplayID = video_api.DisplayID;
pub const Window = video_api.Window;
pub const Window = opaque {
pub inline fn setiOSAnimationCallback(window: *Window, interval: c_int, callback: iOSAnimationCallback, callbackParam: ?*anyopaque) bool {
return @bitCast(c.SDL_SetiOSAnimationCallback(@ptrCast(window), interval, callback, callbackParam));
}
};
pub const MSG = opaque {}; pub const MSG = opaque {};
@ -41,6 +37,10 @@ pub inline fn setLinuxThreadPriorityAndPolicy(threadID: i64, sdlPriority: c_int,
pub const iOSAnimationCallback = c.SDL_iOSAnimationCallback; pub const iOSAnimationCallback = c.SDL_iOSAnimationCallback;
pub inline fn setiOSAnimationCallback(window: ?*Window, interval: c_int, callback: iOSAnimationCallback, callbackParam: ?*anyopaque) bool {
return @bitCast(c.SDL_SetiOSAnimationCallback(@ptrCast(window), interval, callback, callbackParam));
}
pub inline fn setiOSEventPump(enabled: bool) void { pub inline fn setiOSEventPump(enabled: bool) void {
return c.SDL_SetiOSEventPump(@bitCast(enabled)); return c.SDL_SetiOSEventPump(@bitCast(enabled));
} }

View File

@ -1,7 +1,8 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const stdinc_api = @import("stdinc.zig");
pub const Time = i64; pub const Time = stdinc_api.Time;
pub const DateTime = extern struct { pub const DateTime = extern struct {
year: c_int, // Year year: c_int, // Year

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub inline fn getTicks() u64 { pub inline fn getTicks() u64 {
return c.SDL_GetTicks(); return c.SDL_GetTicks();
} }

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub const TouchID = u64; pub const TouchID = u64;
pub const FingerID = u64; pub const FingerID = u64;

117
api/tray.zig Normal file
View File

@ -0,0 +1,117 @@
const std = @import("std");
pub const c = @import("c.zig").c;
const surface_api = @import("surface.zig");
pub const Surface = surface_api.Surface;
pub const Tray = opaque {
pub inline fn setTrayIcon(tray: *Tray, icon: ?*Surface) void {
return c.SDL_SetTrayIcon(@ptrCast(tray), @ptrCast(icon));
}
pub inline fn setTrayTooltip(tray: *Tray, tooltip: [*c]const u8) void {
return c.SDL_SetTrayTooltip(@ptrCast(tray), tooltip);
}
pub inline fn createTrayMenu(tray: *Tray) ?*TrayMenu {
return @ptrCast(c.SDL_CreateTrayMenu(@ptrCast(tray)));
}
pub inline fn getTrayMenu(tray: *Tray) ?*TrayMenu {
return @ptrCast(c.SDL_GetTrayMenu(@ptrCast(tray)));
}
pub inline fn destroyTray(tray: *Tray) void {
return c.SDL_DestroyTray(@ptrCast(tray));
}
};
pub const TrayMenu = opaque {
pub inline fn getTrayEntries(traymenu: *TrayMenu, count: *c_int) [*c]?*const TrayEntry {
return c.SDL_GetTrayEntries(@ptrCast(traymenu), @ptrCast(count));
}
pub inline fn insertTrayEntryAt(traymenu: *TrayMenu, pos: c_int, label: [*c]const u8, flags: TrayEntryFlags) ?*TrayEntry {
return @ptrCast(c.SDL_InsertTrayEntryAt(@ptrCast(traymenu), pos, label, @bitCast(flags)));
}
pub inline fn getTrayMenuParentEntry(traymenu: *TrayMenu) ?*TrayEntry {
return @ptrCast(c.SDL_GetTrayMenuParentEntry(@ptrCast(traymenu)));
}
pub inline fn getTrayMenuParentTray(traymenu: *TrayMenu) ?*Tray {
return @ptrCast(c.SDL_GetTrayMenuParentTray(@ptrCast(traymenu)));
}
};
pub const TrayEntry = opaque {
pub inline fn createTraySubmenu(trayentry: *TrayEntry) ?*TrayMenu {
return @ptrCast(c.SDL_CreateTraySubmenu(@ptrCast(trayentry)));
}
pub inline fn getTraySubmenu(trayentry: *TrayEntry) ?*TrayMenu {
return @ptrCast(c.SDL_GetTraySubmenu(@ptrCast(trayentry)));
}
pub inline fn removeTrayEntry(trayentry: *TrayEntry) void {
return c.SDL_RemoveTrayEntry(@ptrCast(trayentry));
}
pub inline fn setTrayEntryLabel(trayentry: *TrayEntry, label: [*c]const u8) void {
return c.SDL_SetTrayEntryLabel(@ptrCast(trayentry), label);
}
pub inline fn getTrayEntryLabel(trayentry: *TrayEntry) [*c]const u8 {
return c.SDL_GetTrayEntryLabel(@ptrCast(trayentry));
}
pub inline fn setTrayEntryChecked(trayentry: *TrayEntry, checked: bool) void {
return c.SDL_SetTrayEntryChecked(@ptrCast(trayentry), @bitCast(checked));
}
pub inline fn getTrayEntryChecked(trayentry: *TrayEntry) bool {
return @bitCast(c.SDL_GetTrayEntryChecked(@ptrCast(trayentry)));
}
pub inline fn setTrayEntryEnabled(trayentry: *TrayEntry, enabled: bool) void {
return c.SDL_SetTrayEntryEnabled(@ptrCast(trayentry), @bitCast(enabled));
}
pub inline fn getTrayEntryEnabled(trayentry: *TrayEntry) bool {
return @bitCast(c.SDL_GetTrayEntryEnabled(@ptrCast(trayentry)));
}
pub inline fn setTrayEntryCallback(trayentry: *TrayEntry, callback: TrayCallback, userdata: ?*anyopaque) void {
return c.SDL_SetTrayEntryCallback(@ptrCast(trayentry), callback, userdata);
}
pub inline fn clickTrayEntry(trayentry: *TrayEntry) void {
return c.SDL_ClickTrayEntry(@ptrCast(trayentry));
}
pub inline fn getTrayEntryParent(trayentry: *TrayEntry) ?*TrayMenu {
return @ptrCast(c.SDL_GetTrayEntryParent(@ptrCast(trayentry)));
}
};
pub const TrayEntryFlags = packed struct(u32) {
trayentryButton: bool = false, // Make the entry a simple button. Required.
trayentryCheckbox: bool = false, // Make the entry a checkbox. Required.
trayentrySubmenu: bool = false, // Prepare the entry to have a submenu. Required
trayentryDisabled: bool = false, // Make the entry disabled. Optional.
trayentryChecked: bool = false, // Make the entry checked. This is valid only for checkboxes. Optional.
pad0: u26 = 0,
rsvd: bool = false,
pub const None = TrayEntryFlags{};
};
pub const TrayCallback = c.SDL_TrayCallback;
pub inline fn createTray(icon: ?*Surface, tooltip: [*c]const u8) ?*Tray {
return @ptrCast(c.SDL_CreateTray(@ptrCast(icon), tooltip));
}
pub inline fn updateTrays() void {
return c.SDL_UpdateTrays();
}

View File

@ -1,6 +1,5 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
pub inline fn getVersion() c_int { pub inline fn getVersion() c_int {
return c.SDL_GetVersion(); return c.SDL_GetVersion();
} }

View File

@ -1,35 +1,17 @@
const std = @import("std"); const std = @import("std");
pub const c = @import("c.zig").c; pub const c = @import("c.zig").c;
const pixels_api = @import("pixels.zig");
const rect_api = @import("rect.zig");
const surface_api = @import("surface.zig");
const properties_api = @import("properties.zig");
const stdinc_api = @import("stdinc.zig");
pub const PixelFormat = enum(c_int) { pub const PixelFormat = pixels_api.PixelFormat;
pixelformatYv12 = 0x32315659, //Planar mode: Y + V + U (3 planes) pub const Point = rect_api.Point;
pixelformatIyuv = 0x56555949, //Planar mode: Y + U + V (3 planes) pub const Surface = surface_api.Surface;
pixelformatYuy2 = 0x32595559, //Packed mode: Y0+U0+Y1+V0 (1 plane) pub const PropertiesID = properties_api.PropertiesID;
pixelformatUyvy = 0x59565955, //Packed mode: U0+Y0+V0+Y1 (1 plane) pub const Rect = rect_api.Rect;
pixelformatYvyu = 0x55595659, //Packed mode: Y0+V0+Y1+U0 (1 plane) pub const FunctionPointer = stdinc_api.FunctionPointer;
pixelformatNv12 = 0x3231564e, //Planar mode: Y + U/V interleaved (2 planes)
pixelformatNv21 = 0x3132564e, //Planar mode: Y + V/U interleaved (2 planes)
pixelformatP010 = 0x30313050, //Planar mode: Y + U/V interleaved (2 planes)
pixelformatExternalOes = 0x2053454f, //Android video texture format
};
pub const Point = extern struct {
x: c_int,
y: c_int,
};
pub const Surface = opaque {};
pub const PropertiesID = u32;
pub const Rect = extern struct {
x: c_int,
y: c_int,
w: c_int,
h: c_int,
};
pub const FunctionPointer = c.SDL_FunctionPointer;
pub const DisplayID = u32; pub const DisplayID = u32;
@ -188,6 +170,10 @@ pub const Window = opaque {
return @bitCast(c.SDL_SetWindowAlwaysOnTop(@ptrCast(window), @bitCast(on_top))); return @bitCast(c.SDL_SetWindowAlwaysOnTop(@ptrCast(window), @bitCast(on_top)));
} }
pub inline fn setWindowFillDocument(window: *Window, fill: bool) bool {
return @bitCast(c.SDL_SetWindowFillDocument(@ptrCast(window), @bitCast(fill)));
}
pub inline fn showWindow(window: *Window) bool { pub inline fn showWindow(window: *Window) bool {
return @bitCast(c.SDL_ShowWindow(@ptrCast(window))); return @bitCast(c.SDL_ShowWindow(@ptrCast(window)));
} }
@ -308,6 +294,22 @@ pub const Window = opaque {
return @bitCast(c.SDL_FlashWindow(@ptrCast(window), @intFromEnum(operation))); return @bitCast(c.SDL_FlashWindow(@ptrCast(window), @intFromEnum(operation)));
} }
pub inline fn setWindowProgressState(window: *Window, state: ProgressState) bool {
return @bitCast(c.SDL_SetWindowProgressState(@ptrCast(window), state));
}
pub inline fn getWindowProgressState(window: *Window) ProgressState {
return c.SDL_GetWindowProgressState(@ptrCast(window));
}
pub inline fn setWindowProgressValue(window: *Window, value: f32) bool {
return @bitCast(c.SDL_SetWindowProgressValue(@ptrCast(window), value));
}
pub inline fn getWindowProgressValue(window: *Window) f32 {
return c.SDL_GetWindowProgressValue(@ptrCast(window));
}
pub inline fn destroyWindow(window: *Window) void { pub inline fn destroyWindow(window: *Window) void {
return c.SDL_DestroyWindow(@ptrCast(window)); return c.SDL_DestroyWindow(@ptrCast(window));
} }
@ -351,11 +353,12 @@ pub const WindowFlags = packed struct(u64) {
windowTooltip: bool = false, // window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window windowTooltip: bool = false, // window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window
windowPopupMenu: bool = false, // window should be treated as a popup menu, requires a parent window windowPopupMenu: bool = false, // window should be treated as a popup menu, requires a parent window
windowKeyboardGrabbed: bool = false, // window has grabbed keyboard input windowKeyboardGrabbed: bool = false, // window has grabbed keyboard input
windowFillDocument: bool = false, // window is in fill-document mode (Emscripten only), since SDL 3.4.0
windowVulkan: bool = false, // window usable for Vulkan surface windowVulkan: bool = false, // window usable for Vulkan surface
windowMetal: bool = false, // window usable for Metal view windowMetal: bool = false, // window usable for Metal view
windowTransparent: bool = false, // window with transparent buffer windowTransparent: bool = false, // window with transparent buffer
windowNotFocusable: bool = false, // window should not be focusable windowNotFocusable: bool = false, // window should not be focusable
pad0: u38 = 0, pad0: u37 = 0,
rsvd: bool = false, rsvd: bool = false,
pub const None = WindowFlags{}; pub const None = WindowFlags{};
@ -367,6 +370,15 @@ pub const FlashOperation = enum(c_int) {
flashUntilFocused, //Flash the window until it gets focus flashUntilFocused, //Flash the window until it gets focus
}; };
pub const ProgressState = enum(c_int) {
progressStateInvalid = -1, //An invalid progress state indicating an error; check SDL_GetError()
progressStateNone, //No progress bar is shown
progressStateIndeterminate, //The progress bar is shown in a indeterminate state
progressStateNormal, //The progress bar is shown in a normal state
progressStatePaused, //The progress bar is shown in a paused state
progressStateError, //The progress bar is shown in a state indicating the application had an error
};
pub const GLContext = *anyopaque; pub const GLContext = *anyopaque;
pub const EGLDisplay = ?*anyopaque; pub const EGLDisplay = ?*anyopaque;
@ -384,10 +396,10 @@ pub const EGLAttribArrayCallback = c.SDL_EGLAttribArrayCallback;
pub const EGLIntArrayCallback = c.SDL_EGLIntArrayCallback; pub const EGLIntArrayCallback = c.SDL_EGLIntArrayCallback;
pub const GLAttr = enum(c_int) { pub const GLAttr = enum(c_int) {
glRedSize, //the minimum number of bits for the red channel of the color buffer; defaults to 3. glRedSize, //the minimum number of bits for the red channel of the color buffer; defaults to 8.
glGreenSize, //the minimum number of bits for the green channel of the color buffer; defaults to 3. glGreenSize, //the minimum number of bits for the green channel of the color buffer; defaults to 8.
glBlueSize, //the minimum number of bits for the blue channel of the color buffer; defaults to 2. glBlueSize, //the minimum number of bits for the blue channel of the color buffer; defaults to 8.
glAlphaSize, //the minimum number of bits for the alpha channel of the color buffer; defaults to 0. glAlphaSize, //the minimum number of bits for the alpha channel of the color buffer; defaults to 8.
glBufferSize, //the minimum number of bits for frame buffer size; defaults to 0. glBufferSize, //the minimum number of bits for frame buffer size; defaults to 0.
glDoublebuffer, //whether the output is single or double buffered; defaults to double buffering on. glDoublebuffer, //whether the output is single or double buffered; defaults to double buffering on.
glDepthSize, //the minimum number of bits in the depth buffer; defaults to 16. glDepthSize, //the minimum number of bits in the depth buffer; defaults to 16.
@ -406,7 +418,7 @@ pub const GLAttr = enum(c_int) {
glContextFlags, //some combination of 0 or more of elements of the SDL_GLContextFlag enumeration; defaults to 0. glContextFlags, //some combination of 0 or more of elements of the SDL_GLContextFlag enumeration; defaults to 0.
glContextProfileMask, //type of GL context (Core, Compatibility, ES). See SDL_GLProfile; default value depends on platform. glContextProfileMask, //type of GL context (Core, Compatibility, ES). See SDL_GLProfile; default value depends on platform.
glShareWithCurrentContext, //OpenGL context sharing; defaults to 0. glShareWithCurrentContext, //OpenGL context sharing; defaults to 0.
glFramebufferSrgbCapable, //requests sRGB capable visual; defaults to 0. glFramebufferSrgbCapable, //requests sRGB-capable visual if 1. Defaults to -1 ("don't care"). This is a request; GL drivers might not comply!
glContextReleaseBehavior, //sets context the release behavior. See SDL_GLContextReleaseFlag; defaults to FLUSH. glContextReleaseBehavior, //sets context the release behavior. See SDL_GLContextReleaseFlag; defaults to FLUSH.
glContextResetNotification, //set context reset notification. See SDL_GLContextResetNotification; defaults to NO_NOTIFICATION. glContextResetNotification, //set context reset notification. See SDL_GLContextResetNotification; defaults to NO_NOTIFICATION.
glContextNoError, glContextNoError,

196
build.zig
View File

@ -1,5 +1,21 @@
const std = @import("std"); const std = @import("std");
fn resolveHeaderRoot(allocator: std.mem.Allocator, source_dir: []const u8) ![]const u8 {
const include_sdl3 = try std.fs.path.join(allocator, &.{ source_dir, "include", "SDL3" });
defer allocator.free(include_sdl3);
if (std.fs.cwd().access(include_sdl3, .{})) {
return try allocator.dupe(u8, "include/SDL3");
} else |_| {}
const sdl3_dir = try std.fs.path.join(allocator, &.{ source_dir, "SDL3" });
defer allocator.free(sdl3_dir);
if (std.fs.cwd().access(sdl3_dir, .{})) {
return try allocator.dupe(u8, "SDL3");
} else |_| {}
return try allocator.dupe(u8, ".");
}
fn addFetchSdlStep(b: *std.Build) *std.Build.Step { fn addFetchSdlStep(b: *std.Build) *std.Build.Step {
const default_sdl_url = "git@github.com:castholm/SDL.git"; const default_sdl_url = "git@github.com:castholm/SDL.git";
const official_sdl_url = "git@github.com:libsdl-org/SDL.git"; const official_sdl_url = "git@github.com:libsdl-org/SDL.git";
@ -47,8 +63,9 @@ fn addFetchSdlStep(b: *std.Build) *std.Build.Step {
const ArchiveStep = struct { const ArchiveStep = struct {
step: std.Build.Step, step: std.Build.Step,
base_dir: ?[]const u8,
pub fn create(b: *std.Build) *std.Build.Step { pub fn create(b: *std.Build, base_dir: ?[]const u8) *std.Build.Step {
const self = b.allocator.create(ArchiveStep) catch @panic("OOM"); const self = b.allocator.create(ArchiveStep) catch @panic("OOM");
self.* = .{ self.* = .{
.step = std.Build.Step.init(.{ .step = std.Build.Step.init(.{
@ -57,36 +74,58 @@ const ArchiveStep = struct {
.owner = b, .owner = b,
.makeFn = make, .makeFn = make,
}), }),
.base_dir = base_dir,
}; };
return &self.step; return &self.step;
} }
fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) !void { fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) !void {
_ = step;
_ = options; _ = options;
const self: *ArchiveStep = @fieldParentPtr("step", step);
const cwd = std.fs.cwd(); const cwd = std.fs.cwd();
const json_exists = if (cwd.access("json", .{})) true else |_| false; const json_path = if (self.base_dir) |base_dir|
const api_exists = if (cwd.access("api", .{})) true else |_| false; try std.fs.path.join(step.owner.allocator, &.{ base_dir, "json" })
else
try step.owner.allocator.dupe(u8, "json");
defer step.owner.allocator.free(json_path);
const api_path = if (self.base_dir) |base_dir|
try std.fs.path.join(step.owner.allocator, &.{ base_dir, "api" })
else
try step.owner.allocator.dupe(u8, "api");
defer step.owner.allocator.free(api_path);
const archive_root = if (self.base_dir) |base_dir|
try std.fs.path.join(step.owner.allocator, &.{ base_dir, "archive", "generate" })
else
try step.owner.allocator.dupe(u8, "archive/generate");
defer step.owner.allocator.free(archive_root);
const json_exists = if (cwd.access(json_path, .{})) true else |_| false;
const api_exists = if (cwd.access(api_path, .{})) true else |_| false;
if (!json_exists and !api_exists) return; if (!json_exists and !api_exists) return;
const timestamp = std.time.timestamp(); const timestamp = std.time.timestamp();
var buf: [64]u8 = undefined; const timestamp_dir = try std.fmt.allocPrint(step.owner.allocator, "{d}", .{timestamp});
const archive_path = try std.fmt.bufPrint(&buf, "archive/generate/{d}", .{timestamp}); defer step.owner.allocator.free(timestamp_dir);
const archive_path = try std.fs.path.join(step.owner.allocator, &.{ archive_root, timestamp_dir });
defer step.owner.allocator.free(archive_path);
try cwd.makePath(archive_path); try cwd.makePath(archive_path);
if (json_exists) { if (json_exists) {
var json_dest_buf: [128]u8 = undefined; const json_dest = try std.fs.path.join(step.owner.allocator, &.{ archive_path, "json" });
const json_dest = try std.fmt.bufPrint(&json_dest_buf, "{s}/json", .{archive_path}); defer step.owner.allocator.free(json_dest);
try cwd.rename("json", json_dest); try cwd.rename(json_path, json_dest);
} }
if (api_exists) { if (api_exists) {
var api_dest_buf: [128]u8 = undefined; const api_dest = try std.fs.path.join(step.owner.allocator, &.{ archive_path, "api" });
const api_dest = try std.fmt.bufPrint(&api_dest_buf, "{s}/api", .{archive_path}); defer step.owner.allocator.free(api_dest);
try cwd.rename("api", api_dest); try cwd.rename(api_path, api_dest);
} }
} }
}; };
@ -116,27 +155,100 @@ const MakeDirStep = struct {
} }
}; };
pub fn generateApi(b: *std.Build, parser_exe: *std.Build.Step.Compile, fetch_sdl_step: *std.Build.Step) void { const WriteStaticFileStep = struct {
// Archive existing json/ and api/ directories before regenerating step: std.Build.Step,
const archive_step = ArchiveStep.create(b); path: []const u8,
fetch_sdl_step.dependOn(archive_step); contents: []const u8,
// Write a build marker file after fetch to enable caching pub fn create(b: *std.Build, path: []const u8, contents: []const u8) *std.Build.Step {
const self = b.allocator.create(WriteStaticFileStep) catch @panic("OOM");
self.* = .{
.step = std.Build.Step.init(.{
.id = .custom,
.name = b.fmt("write {s}", .{path}),
.owner = b,
.makeFn = make,
}),
.path = b.dupe(path),
.contents = b.dupe(contents),
};
return &self.step;
}
fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) !void {
_ = options;
const self: *WriteStaticFileStep = @fieldParentPtr("step", step);
if (std.fs.path.dirname(self.path)) |dir| {
try std.fs.cwd().makePath(dir);
}
try std.fs.cwd().writeFile(.{
.sub_path = self.path,
.data = self.contents,
});
}
};
pub fn generateApi(b: *std.Build, parser_exe: *std.Build.Step.Compile, fetch_sdl_step: *std.Build.Step) void {
const source_dir = b.option([]const u8, "sourceDir", "Parse SDL headers from an existing local directory instead of fetching git");
const output_dir = b.option([]const u8, "outputDir", "Directory where generated api/ and json/ folders should be written");
const basedir = b.option([]const u8, "basedir", "Working directory for the parser to execute in");
const c_import_path = b.option([]const u8, "cImportPath", "Path used by generated files when importing c.zig");
const effective_output_dir = output_dir orelse source_dir;
const header_root_suffix = if (source_dir) |dir| resolveHeaderRoot(b.allocator, dir) catch @panic("OOM") else null;
// Archive existing json/ and api/ directories before regenerating
const archive_step = ArchiveStep.create(b, effective_output_dir);
const generation_root = if (source_dir != null) archive_step else fetch_sdl_step;
if (source_dir == null) {
fetch_sdl_step.dependOn(archive_step);
}
// Write a build marker file after the source selection step to enable caching
const timestamp = std.time.timestamp(); const timestamp = std.time.timestamp();
const wf = b.addWriteFiles(); const wf = b.addWriteFiles();
const marker_file = wf.add(".buildmarker", b.fmt("{d}", .{timestamp})); const marker_file = wf.add(".buildmarker", b.fmt("{d}", .{timestamp}));
_ = marker_file; _ = marker_file;
wf.step.dependOn(fetch_sdl_step); wf.step.dependOn(generation_root);
const basedir = b.option([]const u8, "basedir", "Working directory for the parser to execute in"); var path_prep_step: *std.Build.Step = &wf.step;
if (effective_output_dir) |dir| {
const output_dir_step = MakeDirStep.create(b, dir);
output_dir_step.dependOn(path_prep_step);
path_prep_step = output_dir_step;
}
if (basedir) |dir| {
const basedir_step = MakeDirStep.create(b, dir);
basedir_step.dependOn(path_prep_step);
path_prep_step = basedir_step;
}
// Create basedir if specified const output_root = if (effective_output_dir) |dir| b.fmt("{s}/api", .{dir}) else "api";
const basedir_step = if (basedir) |dir| MakeDirStep.create(b, dir) else &wf.step; const json_root = if (effective_output_dir) |dir| b.fmt("{s}/json", .{dir}) else "json";
if (basedir != null) const effective_c_import_path = c_import_path orelse "c.zig";
basedir_step.dependOn(&wf.step); const c_bridge_target = if (c_import_path) |path| path else "../c.zig";
const c_bridge_step = WriteStaticFileStep.create(
b,
b.fmt("{s}/c.zig", .{output_root}),
b.fmt("pub const c = @import(\"{s}\").c;\n", .{c_bridge_target}),
);
c_bridge_step.dependOn(path_prep_step);
path_prep_step = c_bridge_step;
// All public SDL3 API headers (53 total) const stdinc_bridge_step = WriteStaticFileStep.create(
// Skipped: assert, thread, hidapi, mutex, tray (not core APIs or problematic) b,
b.fmt("{s}/stdinc.zig", .{output_root}),
\\pub const c = @import("c.zig").c;
\\pub const Time = i64;
\\pub const FunctionPointer = c.SDL_FunctionPointer;
\\
);
stdinc_bridge_step.dependOn(path_prep_step);
path_prep_step = stdinc_bridge_step;
// All public SDL3 API headers
const headers_to_generate = [_]struct { header: []const u8, output: []const u8 }{ const headers_to_generate = [_]struct { header: []const u8, output: []const u8 }{
// .{ .header = "SDL_asyncio.h", .output = "asyncio" }, // .{ .header = "SDL_asyncio.h", .output = "asyncio" },
// .{ .header = "SDL_atomic.h", .output = "atomic" }, // .{ .header = "SDL_atomic.h", .output = "atomic" },
@ -157,9 +269,9 @@ pub fn generateApi(b: *std.Build, parser_exe: *std.Build.Step.Compile, fetch_sdl
// .{ .header = "SDL_hidapi.h", .output = "hidapi" }, // Skipped: not core API // .{ .header = "SDL_hidapi.h", .output = "hidapi" }, // Skipped: not core API
.{ .header = "SDL_hints.h", .output = "hints" }, .{ .header = "SDL_hints.h", .output = "hints" },
.{ .header = "SDL_init.h", .output = "init" }, .{ .header = "SDL_init.h", .output = "init" },
// .{ .header = "SDL_iostream.h", .output = "iostream" }, // Skipped: complex I/O API .{ .header = "SDL_iostream.h", .output = "iostream" },
.{ .header = "SDL_joystick.h", .output = "joystick" }, .{ .header = "SDL_joystick.h", .output = "joystick" },
// .{ .header = "SDL_keyboard.h", .output = "keyboard" }, .{ .header = "SDL_keyboard.h", .output = "keyboard" },
.{ .header = "SDL_keycode.h", .output = "keycode" }, .{ .header = "SDL_keycode.h", .output = "keycode" },
.{ .header = "SDL_loadso.h", .output = "loadso" }, .{ .header = "SDL_loadso.h", .output = "loadso" },
// .{ .header = "SDL_locale.h", .output = "locale" }, // .{ .header = "SDL_locale.h", .output = "locale" },
@ -169,15 +281,15 @@ pub fn generateApi(b: *std.Build, parser_exe: *std.Build.Step.Compile, fetch_sdl
.{ .header = "SDL_misc.h", .output = "misc" }, .{ .header = "SDL_misc.h", .output = "misc" },
.{ .header = "SDL_mouse.h", .output = "mouse" }, .{ .header = "SDL_mouse.h", .output = "mouse" },
// .{ .header = "SDL_mutex.h", .output = "mutex" }, // Skipped: not core API // .{ .header = "SDL_mutex.h", .output = "mutex" }, // Skipped: not core API
// .{ .header = "SDL_opengl.h", .output = "opengl" }, .{ .header = "SDL_opengl.h", .output = "opengl" },
// .{ .header = "SDL_pen.h", .output = "pen" }, // .{ .header = "SDL_pen.h", .output = "pen" },
.{ .header = "SDL_pixels.h", .output = "pixels" }, .{ .header = "SDL_pixels.h", .output = "pixels" },
// .{ .header = "SDL_power.h", .output = "power" }, .{ .header = "SDL_power.h", .output = "power" },
// .{ .header = "SDL_process.h", .output = "process" }, .{ .header = "SDL_process.h", .output = "process" },
.{ .header = "SDL_properties.h", .output = "properties" }, .{ .header = "SDL_properties.h", .output = "properties" },
.{ .header = "SDL_rect.h", .output = "rect" }, .{ .header = "SDL_rect.h", .output = "rect" },
.{ .header = "SDL_render.h", .output = "render" }, .{ .header = "SDL_render.h", .output = "render" },
// .{ .header = "SDL_scancode.h", .output = "scancode" }, .{ .header = "SDL_scancode.h", .output = "scancode" },
.{ .header = "SDL_sensor.h", .output = "sensor" }, .{ .header = "SDL_sensor.h", .output = "sensor" },
.{ .header = "SDL_storage.h", .output = "storage" }, .{ .header = "SDL_storage.h", .output = "storage" },
.{ .header = "SDL_surface.h", .output = "surface" }, .{ .header = "SDL_surface.h", .output = "surface" },
@ -186,38 +298,40 @@ pub fn generateApi(b: *std.Build, parser_exe: *std.Build.Step.Compile, fetch_sdl
.{ .header = "SDL_time.h", .output = "time" }, .{ .header = "SDL_time.h", .output = "time" },
.{ .header = "SDL_timer.h", .output = "timer" }, .{ .header = "SDL_timer.h", .output = "timer" },
.{ .header = "SDL_touch.h", .output = "touch" }, .{ .header = "SDL_touch.h", .output = "touch" },
// .{ .header = "SDL_tray.h", .output = "tray" }, // Skipped: not core API .{ .header = "SDL_tray.h", .output = "tray" }, // Skipped: not core API
.{ .header = "SDL_version.h", .output = "version" }, .{ .header = "SDL_version.h", .output = "version" },
.{ .header = "SDL_video.h", .output = "video" }, .{ .header = "SDL_video.h", .output = "video" },
// .{ .header = "SDL_vulkan.h", .output = "vulkan" }, // Skipped: Vulkan interop // .{ .header = "SDL_vulkan.h", .output = "vulkan" }, // Skipped: Vulkan interop
}; };
const regenerate_step = b.step("generate", "Regenerate bindings from SDL headers"); const regenerate_step = b.step("generate", "Regenerate bindings from SDL headers");
const header_root = if (source_dir) |dir|
const header_path = "sdl3/include/SDL3"; b.fmt("{s}/{s}", .{ dir, header_root_suffix.? })
else
"sdl3/include/SDL3";
const timestamp_arg = b.fmt("--timestamp={d}", .{timestamp}); const timestamp_arg = b.fmt("--timestamp={d}", .{timestamp});
for (headers_to_generate) |header_info| { for (headers_to_generate) |header_info| {
const regenerate = b.addRunArtifact(parser_exe); const regenerate = b.addRunArtifact(parser_exe);
regenerate.addFileArg(b.path(b.fmt("{s}/{s}", .{ header_path, header_info.header }))); regenerate.addArg(b.fmt("{s}/{s}", .{ header_root, header_info.header }));
regenerate.addArg(b.fmt("--output=api/{s}.zig", .{header_info.output})); regenerate.addArg(b.fmt("--output={s}/{s}.zig", .{ output_root, header_info.output }));
regenerate.addArg(timestamp_arg); regenerate.addArg(timestamp_arg);
if (basedir) |dir| { if (basedir) |dir| {
regenerate.addArg(b.fmt("--basedir={s}", .{dir})); regenerate.addArg(b.fmt("--basedir={s}", .{dir}));
} }
regenerate.addArg(b.fmt("--c-import={s}", .{effective_c_import_path}));
// regenerate.addArg(b.fmt("--output=api/{s}.zig --mocks=mocks/{s}.c", .{ header_info.output, header_info.output })); // regenerate.addArg(b.fmt("--output=api/{s}.zig --mocks=mocks/{s}.c", .{ header_info.output, header_info.output }));
regenerate.step.dependOn(basedir_step); regenerate.step.dependOn(path_prep_step);
regenerate_step.dependOn(&regenerate.step); regenerate_step.dependOn(&regenerate.step);
const regenerateJson = b.addRunArtifact(parser_exe); const regenerateJson = b.addRunArtifact(parser_exe);
regenerateJson.addFileArg(b.path(b.fmt("{s}/{s}", .{ header_path, header_info.header }))); regenerateJson.addArg(b.fmt("{s}/{s}", .{ header_root, header_info.header }));
regenerateJson.addArg(b.fmt("--generate-json=json/{s}.json", .{header_info.output})); regenerateJson.addArg(b.fmt("--generate-json={s}/{s}.json", .{ json_root, header_info.output }));
regenerateJson.addArg(timestamp_arg); regenerateJson.addArg(timestamp_arg);
if (basedir) |dir| { if (basedir) |dir| {
regenerateJson.addArg(b.fmt("--basedir={s}", .{dir})); regenerateJson.addArg(b.fmt("--basedir={s}", .{dir}));
} }
regenerateJson.step.dependOn(basedir_step); regenerateJson.step.dependOn(path_prep_step);
regenerate_step.dependOn(&regenerateJson.step); regenerate_step.dependOn(&regenerateJson.step);
} }
} }

View File

@ -13,6 +13,9 @@
], ],
"function_pointers": [], "function_pointers": [],
"c_type_aliases": [ "c_type_aliases": [
{
"name": "SDL_AudioStreamDataCompleteCallback"
},
{ {
"name": "SDL_AudioStreamCallback" "name": "SDL_AudioStreamCallback"
}, },
@ -218,7 +221,7 @@
"return_type": "bool", "return_type": "bool",
"parameters": [ "parameters": [
{ {
"name": "dev", "name": "devid",
"type": "SDL_AudioDeviceID" "type": "SDL_AudioDeviceID"
} }
] ]
@ -228,7 +231,7 @@
"return_type": "bool", "return_type": "bool",
"parameters": [ "parameters": [
{ {
"name": "dev", "name": "devid",
"type": "SDL_AudioDeviceID" "type": "SDL_AudioDeviceID"
} }
] ]
@ -238,7 +241,7 @@
"return_type": "bool", "return_type": "bool",
"parameters": [ "parameters": [
{ {
"name": "dev", "name": "devid",
"type": "SDL_AudioDeviceID" "type": "SDL_AudioDeviceID"
} }
] ]
@ -533,6 +536,54 @@
} }
] ]
}, },
{
"name": "SDL_PutAudioStreamDataNoCopy",
"return_type": "bool",
"parameters": [
{
"name": "stream",
"type": "SDL_AudioStream *"
},
{
"name": "buf",
"type": "const void *"
},
{
"name": "len",
"type": "int"
},
{
"name": "callback",
"type": "SDL_AudioStreamDataCompleteCallback"
},
{
"name": "userdata",
"type": "void *"
}
]
},
{
"name": "SDL_PutAudioStreamPlanarData",
"return_type": "bool",
"parameters": [
{
"name": "stream",
"type": "SDL_AudioStream *"
},
{
"name": "channel_buffers",
"type": "const void * const *"
},
{
"name": "num_channels",
"type": "int"
},
{
"name": "num_samples",
"type": "int"
}
]
},
{ {
"name": "SDL_GetAudioStreamData", "name": "SDL_GetAudioStreamData",
"return_type": "int", "return_type": "int",

View File

@ -27,6 +27,17 @@
"name": "SDL_CAMERA_POSITION_BACK_FACING" "name": "SDL_CAMERA_POSITION_BACK_FACING"
} }
] ]
},
{
"name": "SDL_CameraPermissionState",
"values": [
{
"name": "SDL_CAMERA_PERMISSION_STATE_PENDING"
},
{
"name": "SDL_CAMERA_PERMISSION_STATE_APPROVED"
}
]
} }
], ],
"structs": [ "structs": [
@ -61,7 +72,7 @@
{ {
"name": "framerate_denominator", "name": "framerate_denominator",
"type": "int", "type": "int",
"comment": "Frame rate demoninator ((num / denom) == FPS, (denom / num) == duration in seconds)" "comment": "Frame rate denominator ((num / denom) == FPS, (denom / num) == duration in seconds)"
} }
] ]
} }
@ -104,7 +115,7 @@
"return_type": "SDL_CameraSpec **", "return_type": "SDL_CameraSpec **",
"parameters": [ "parameters": [
{ {
"name": "devid", "name": "instance_id",
"type": "SDL_CameraID" "type": "SDL_CameraID"
}, },
{ {
@ -149,7 +160,7 @@
}, },
{ {
"name": "SDL_GetCameraPermissionState", "name": "SDL_GetCameraPermissionState",
"return_type": "int", "return_type": "SDL_CameraPermissionState",
"parameters": [ "parameters": [
{ {
"name": "camera", "name": "camera",

View File

@ -77,6 +77,10 @@
"name": "SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED", "name": "SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED",
"comment": "Display has changed content scale" "comment": "Display has changed content scale"
}, },
{
"name": "SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED",
"comment": "Display has changed usable bounds"
},
{ {
"name": "SDL_EVENT_WINDOW_SHOWN", "name": "SDL_EVENT_WINDOW_SHOWN",
"value": "0x202", "value": "0x202",
@ -87,8 +91,7 @@
"comment": "Window has been hidden" "comment": "Window has been hidden"
}, },
{ {
"name": "SDL_EVENT_WINDOW_EXPOSED", "name": "SDL_EVENT_WINDOW_EXPOSED"
"comment": "Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event"
}, },
{ {
"name": "SDL_EVENT_WINDOW_MOVED", "name": "SDL_EVENT_WINDOW_MOVED",
@ -209,6 +212,14 @@
"name": "SDL_EVENT_TEXT_EDITING_CANDIDATES", "name": "SDL_EVENT_TEXT_EDITING_CANDIDATES",
"comment": "Keyboard text editing candidates" "comment": "Keyboard text editing candidates"
}, },
{
"name": "SDL_EVENT_SCREEN_KEYBOARD_SHOWN",
"comment": "The on-screen keyboard has been shown"
},
{
"name": "SDL_EVENT_SCREEN_KEYBOARD_HIDDEN",
"comment": "The on-screen keyboard has been hidden"
},
{ {
"name": "SDL_EVENT_MOUSE_MOTION", "name": "SDL_EVENT_MOUSE_MOTION",
"value": "0x400", "value": "0x400",
@ -329,10 +340,23 @@
{ {
"name": "SDL_EVENT_FINGER_CANCELED" "name": "SDL_EVENT_FINGER_CANCELED"
}, },
{
"name": "SDL_EVENT_PINCH_BEGIN",
"value": "0x710",
"comment": "Pinch gesture started"
},
{
"name": "SDL_EVENT_PINCH_UPDATE",
"comment": "Pinch gesture updated"
},
{
"name": "SDL_EVENT_PINCH_END",
"comment": "Pinch gesture ended"
},
{ {
"name": "SDL_EVENT_CLIPBOARD_UPDATE", "name": "SDL_EVENT_CLIPBOARD_UPDATE",
"value": "0x900", "value": "0x900",
"comment": "The clipboard or primary selection changed" "comment": "The clipboard changed"
}, },
{ {
"name": "SDL_EVENT_DROP_FILE", "name": "SDL_EVENT_DROP_FILE",
@ -496,7 +520,7 @@
{ {
"name": "_type", "name": "_type",
"type": "SDL_EventType", "type": "SDL_EventType",
"comment": "SDL_DISPLAYEVENT_*" "comment": "SDL_EVENT_DISPLAY_*"
}, },
{ {
"name": "reserved", "name": "reserved",
@ -952,6 +976,16 @@
"name": "mouse_y", "name": "mouse_y",
"type": "float", "type": "float",
"comment": "Y coordinate, relative to window" "comment": "Y coordinate, relative to window"
},
{
"name": "integer_x",
"type": "Sint32",
"comment": "The amount scrolled horizontally, accumulated to whole scroll \"ticks\" (added in 3.2.12)"
},
{
"name": "integer_y",
"type": "Sint32",
"comment": "The amount scrolled vertically, accumulated to whole scroll \"ticks\" (added in 3.2.12)"
} }
] ]
}, },
@ -1544,6 +1578,35 @@
} }
] ]
}, },
{
"name": "SDL_PinchFingerEvent",
"fields": [
{
"name": "_type",
"type": "SDL_EventType",
"comment": "::SDL_EVENT_PINCH_BEGIN or ::SDL_EVENT_PINCH_UPDATE or ::SDL_EVENT_PINCH_END"
},
{
"name": "reserved",
"type": "Uint32"
},
{
"name": "timestamp",
"type": "Uint64",
"comment": "In nanoseconds, populated using SDL_GetTicksNS()"
},
{
"name": "scale",
"type": "float",
"comment": "The scale change since the last SDL_EVENT_PINCH_UPDATE. Scale < 1 is \"zoom out\". Scale > 1 is \"zoom in\"."
},
{
"name": "windowID",
"type": "SDL_WindowID",
"comment": "The window underneath the finger, if any"
}
]
},
{ {
"name": "SDL_PenProximityEvent", "name": "SDL_PenProximityEvent",
"fields": [ "fields": [
@ -1916,7 +1979,7 @@
{ {
"name": "_type", "name": "_type",
"type": "Uint32", "type": "Uint32",
"comment": "SDL_EVENT_USER through SDL_EVENT_LAST-1, Uint32 because these are not in the SDL_EventType enumeration" "comment": "SDL_EVENT_USER through SDL_EVENT_LAST, Uint32 because these are not in the SDL_EventType enumeration"
}, },
{ {
"name": "reserved", "name": "reserved",
@ -2104,6 +2167,11 @@
"type": "SDL_TouchFingerEvent", "type": "SDL_TouchFingerEvent",
"comment": "Touch finger event data" "comment": "Touch finger event data"
}, },
{
"name": "pinch",
"type": "SDL_PinchFingerEvent",
"comment": "Pinch event data"
},
{ {
"name": "pproximity", "name": "pproximity",
"type": "SDL_PenProximityEvent", "type": "SDL_PenProximityEvent",
@ -2389,6 +2457,24 @@
"type": "const SDL_Event *" "type": "const SDL_Event *"
} }
] ]
},
{
"name": "SDL_GetEventDescription",
"return_type": "int",
"parameters": [
{
"name": "event",
"type": "const SDL_Event *"
},
{
"name": "buf",
"type": "char *"
},
{
"name": "buflen",
"type": "int"
}
]
} }
] ]
} }

View File

@ -42,6 +42,9 @@
{ {
"name": "SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR" "name": "SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR"
}, },
{
"name": "SDL_GAMEPAD_TYPE_GAMECUBE"
},
{ {
"name": "SDL_GAMEPAD_TYPE_COUNT" "name": "SDL_GAMEPAD_TYPE_COUNT"
} }
@ -105,19 +108,19 @@
}, },
{ {
"name": "SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1", "name": "SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1",
"comment": "Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1)" "comment": "Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1, DualSense Edge RB button, Right Joy-Con SR button)"
}, },
{ {
"name": "SDL_GAMEPAD_BUTTON_LEFT_PADDLE1", "name": "SDL_GAMEPAD_BUTTON_LEFT_PADDLE1",
"comment": "Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3)" "comment": "Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3, DualSense Edge LB button, Left Joy-Con SL button)"
}, },
{ {
"name": "SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2", "name": "SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2",
"comment": "Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2)" "comment": "Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2, DualSense Edge right Fn button, Right Joy-Con SL button)"
}, },
{ {
"name": "SDL_GAMEPAD_BUTTON_LEFT_PADDLE2", "name": "SDL_GAMEPAD_BUTTON_LEFT_PADDLE2",
"comment": "Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4)" "comment": "Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4, DualSense Edge left Fn button, Left Joy-Con SR button)"
}, },
{ {
"name": "SDL_GAMEPAD_BUTTON_TOUCHPAD", "name": "SDL_GAMEPAD_BUTTON_TOUCHPAD",
@ -129,11 +132,11 @@
}, },
{ {
"name": "SDL_GAMEPAD_BUTTON_MISC3", "name": "SDL_GAMEPAD_BUTTON_MISC3",
"comment": "Additional button" "comment": "Additional button (e.g. Nintendo GameCube left trigger click)"
}, },
{ {
"name": "SDL_GAMEPAD_BUTTON_MISC4", "name": "SDL_GAMEPAD_BUTTON_MISC4",
"comment": "Additional button" "comment": "Additional button (e.g. Nintendo GameCube right trigger click)"
}, },
{ {
"name": "SDL_GAMEPAD_BUTTON_MISC5", "name": "SDL_GAMEPAD_BUTTON_MISC5",

View File

@ -718,7 +718,7 @@
}, },
{ {
"name": "SDL_GPU_COMPAREOP_GREATER_OR_EQUAL", "name": "SDL_GPU_COMPAREOP_GREATER_OR_EQUAL",
"comment": "The comparison evalutes reference >= test." "comment": "The comparison evaluates reference >= test."
}, },
{ {
"name": "SDL_GPU_COMPAREOP_ALWAYS", "name": "SDL_GPU_COMPAREOP_ALWAYS",
@ -1332,7 +1332,7 @@
{ {
"name": "pitch", "name": "pitch",
"type": "Uint32", "type": "Uint32",
"comment": "The byte pitch between consecutive elements of the vertex buffer." "comment": "The size of a single element + the offset between elements."
}, },
{ {
"name": "input_rate", "name": "input_rate",
@ -1342,7 +1342,7 @@
{ {
"name": "instance_step_rate", "name": "instance_step_rate",
"type": "Uint32", "type": "Uint32",
"comment": "The number of instances to draw using the same per-instance data before advancing in the instance buffer by one element. Ignored unless input_rate is SDL_GPU_VERTEXINPUTRATE_INSTANCE" "comment": "Reserved for future use. Must be set to 0."
} }
] ]
}, },
@ -1688,16 +1688,17 @@
{ {
"name": "sample_mask", "name": "sample_mask",
"type": "Uint32", "type": "Uint32",
"comment": "Determines which samples get updated in the render targets. Treated as 0xFFFFFFFF if enable_mask is false." "comment": "Reserved for future use. Must be set to 0."
}, },
{ {
"name": "enable_mask", "name": "enable_mask",
"type": "bool", "type": "bool",
"comment": "Enables sample masking." "comment": "Reserved for future use. Must be set to false."
}, },
{ {
"name": "padding1", "name": "enable_alpha_to_coverage",
"type": "Uint8" "type": "bool",
"comment": "true enables the alpha-to-coverage feature."
}, },
{ {
"name": "padding2", "name": "padding2",
@ -2055,12 +2056,14 @@
"comment": "The value to clear the stencil component to at the beginning of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used." "comment": "The value to clear the stencil component to at the beginning of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used."
}, },
{ {
"name": "padding1", "name": "mip_level",
"type": "Uint8" "type": "Uint8",
"comment": "The mip level to use as the depth stencil target."
}, },
{ {
"name": "padding2", "name": "layer",
"type": "Uint8" "type": "Uint8",
"comment": "The layer index to use as the depth stencil target."
} }
] ]
}, },
@ -2209,6 +2212,46 @@
"type": "Uint8" "type": "Uint8"
} }
] ]
},
{
"name": "SDL_GPUVulkanOptions",
"fields": [
{
"name": "vulkan_api_version",
"type": "Uint32",
"comment": "The Vulkan API version to request for the instance. Use Vulkan's VK_MAKE_VERSION or VK_MAKE_API_VERSION."
},
{
"name": "feature_list",
"type": "void *",
"comment": "Pointer to the first element of a chain of Vulkan feature structs. (Requires API version 1.1 or higher.)"
},
{
"name": "vulkan_10_physical_device_features",
"type": "void *",
"comment": "Pointer to a VkPhysicalDeviceFeatures struct to enable additional Vulkan 1.0 features."
},
{
"name": "device_extension_count",
"type": "Uint32",
"comment": "Number of additional device extensions to require."
},
{
"name": "device_extension_names",
"type": "const char **",
"comment": "Pointer to a list of additional device extensions to require."
},
{
"name": "instance_extension_count",
"type": "Uint32",
"comment": "Number of additional instance extensions to require."
},
{
"name": "instance_extension_names",
"type": "const char **",
"comment": "Pointer to a list of additional instance extensions to require."
}
]
} }
], ],
"unions": [], "unions": [],
@ -2451,6 +2494,16 @@
} }
] ]
}, },
{
"name": "SDL_GetGPUDeviceProperties",
"return_type": "SDL_PropertiesID",
"parameters": [
{
"name": "device",
"type": "SDL_GPUDevice *"
}
]
},
{ {
"name": "SDL_CreateGPUComputePipeline", "name": "SDL_CreateGPUComputePipeline",
"return_type": "SDL_GPUComputePipeline *", "return_type": "SDL_GPUComputePipeline *",
@ -3889,6 +3942,26 @@
} }
] ]
}, },
{
"name": "SDL_GetPixelFormatFromGPUTextureFormat",
"return_type": "SDL_PixelFormat",
"parameters": [
{
"name": "format",
"type": "SDL_GPUTextureFormat"
}
]
},
{
"name": "SDL_GetGPUTextureFormatFromPixelFormat",
"return_type": "SDL_GPUTextureFormat",
"parameters": [
{
"name": "format",
"type": "SDL_PixelFormat"
}
]
},
{ {
"name": "SDL_GDKSuspendGPU", "name": "SDL_GDKSuspendGPU",
"return_type": "void", "return_type": "void",

View File

@ -6,6 +6,18 @@
} }
], ],
"typedefs": [ "typedefs": [
{
"name": "SDL_HapticEffectType",
"underlying_type": "Uint16"
},
{
"name": "SDL_HapticDirectionType",
"underlying_type": "Uint8"
},
{
"name": "SDL_HapticEffectID",
"underlying_type": "int"
},
{ {
"name": "SDL_HapticID", "name": "SDL_HapticID",
"underlying_type": "Uint32" "underlying_type": "Uint32"
@ -20,7 +32,7 @@
"fields": [ "fields": [
{ {
"name": "_type", "name": "_type",
"type": "Uint8", "type": "SDL_HapticDirectionType",
"comment": "The type of encoding." "comment": "The type of encoding."
}, },
{ {
@ -35,7 +47,7 @@
"fields": [ "fields": [
{ {
"name": "_type", "name": "_type",
"type": "Uint16", "type": "SDL_HapticEffectType",
"comment": "SDL_HAPTIC_CONSTANT" "comment": "SDL_HAPTIC_CONSTANT"
}, },
{ {
@ -225,7 +237,7 @@
"fields": [ "fields": [
{ {
"name": "_type", "name": "_type",
"type": "Uint16", "type": "SDL_HapticEffectType",
"comment": "SDL_HAPTIC_RAMP" "comment": "SDL_HAPTIC_RAMP"
}, },
{ {
@ -290,7 +302,7 @@
"fields": [ "fields": [
{ {
"name": "_type", "name": "_type",
"type": "Uint16", "type": "SDL_HapticEffectType",
"comment": "SDL_HAPTIC_LEFTRIGHT" "comment": "SDL_HAPTIC_LEFTRIGHT"
}, },
{ {
@ -315,7 +327,7 @@
"fields": [ "fields": [
{ {
"name": "_type", "name": "_type",
"type": "Uint16", "type": "SDL_HapticEffectType",
"comment": "SDL_HAPTIC_CUSTOM" "comment": "SDL_HAPTIC_CUSTOM"
}, },
{ {
@ -392,7 +404,7 @@
"fields": [ "fields": [
{ {
"name": "_type", "name": "_type",
"type": "Uint16", "type": "SDL_HapticEffectType",
"comment": "Effect type." "comment": "Effect type."
}, },
{ {
@ -586,7 +598,7 @@
}, },
{ {
"name": "SDL_CreateHapticEffect", "name": "SDL_CreateHapticEffect",
"return_type": "int", "return_type": "SDL_HapticEffectID",
"parameters": [ "parameters": [
{ {
"name": "haptic", "name": "haptic",
@ -608,7 +620,7 @@
}, },
{ {
"name": "effect", "name": "effect",
"type": "int" "type": "SDL_HapticEffectID"
}, },
{ {
"name": "data", "name": "data",
@ -626,7 +638,7 @@
}, },
{ {
"name": "effect", "name": "effect",
"type": "int" "type": "SDL_HapticEffectID"
}, },
{ {
"name": "iterations", "name": "iterations",
@ -644,7 +656,7 @@
}, },
{ {
"name": "effect", "name": "effect",
"type": "int" "type": "SDL_HapticEffectID"
} }
] ]
}, },
@ -658,7 +670,7 @@
}, },
{ {
"name": "effect", "name": "effect",
"type": "int" "type": "SDL_HapticEffectID"
} }
] ]
}, },
@ -672,7 +684,7 @@
}, },
{ {
"name": "effect", "name": "effect",
"type": "int" "type": "SDL_HapticEffectID"
} }
] ]
}, },

View File

@ -59,7 +59,7 @@
{ {
"name": "SDL_INIT_JOYSTICK", "name": "SDL_INIT_JOYSTICK",
"value": "(1u << 9)", "value": "(1u << 9)",
"comment": "`SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD" "comment": "`SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`"
}, },
{ {
"name": "SDL_INIT_HAPTIC", "name": "SDL_INIT_HAPTIC",

332
json/keyboard.json Normal file
View File

@ -0,0 +1,332 @@
{
"header": "SDL_keyboard.h",
"opaque_types": [],
"typedefs": [
{
"name": "SDL_KeyboardID",
"underlying_type": "Uint32"
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_TextInputType",
"values": [
{
"name": "SDL_TEXTINPUT_TYPE_TEXT",
"comment": "The input is text"
},
{
"name": "SDL_TEXTINPUT_TYPE_TEXT_NAME",
"comment": "The input is a person's name"
},
{
"name": "SDL_TEXTINPUT_TYPE_TEXT_EMAIL",
"comment": "The input is an e-mail address"
},
{
"name": "SDL_TEXTINPUT_TYPE_TEXT_USERNAME",
"comment": "The input is a username"
},
{
"name": "SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN",
"comment": "The input is a secure password that is hidden"
},
{
"name": "SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE",
"comment": "The input is a secure password that is visible"
},
{
"name": "SDL_TEXTINPUT_TYPE_NUMBER",
"comment": "The input is a number"
},
{
"name": "SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN",
"comment": "The input is a secure PIN that is hidden"
},
{
"name": "SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE",
"comment": "The input is a secure PIN that is visible"
}
]
},
{
"name": "SDL_Capitalization",
"values": [
{
"name": "SDL_CAPITALIZE_NONE",
"comment": "No auto-capitalization will be done"
},
{
"name": "SDL_CAPITALIZE_SENTENCES",
"comment": "The first letter of sentences will be capitalized"
},
{
"name": "SDL_CAPITALIZE_WORDS",
"comment": "The first letter of words will be capitalized"
},
{
"name": "SDL_CAPITALIZE_LETTERS",
"comment": "All letters will be capitalized"
}
]
}
],
"structs": [],
"unions": [],
"flags": [],
"functions": [
{
"name": "SDL_HasKeyboard",
"return_type": "bool",
"parameters": []
},
{
"name": "SDL_GetKeyboards",
"return_type": "SDL_KeyboardID *",
"parameters": [
{
"name": "count",
"type": "int *"
}
]
},
{
"name": "SDL_GetKeyboardNameForID",
"return_type": "const char *",
"parameters": [
{
"name": "instance_id",
"type": "SDL_KeyboardID"
}
]
},
{
"name": "SDL_GetKeyboardFocus",
"return_type": "SDL_Window *",
"parameters": []
},
{
"name": "SDL_GetKeyboardState",
"return_type": "const bool *",
"parameters": [
{
"name": "numkeys",
"type": "int *"
}
]
},
{
"name": "SDL_ResetKeyboard",
"return_type": "void",
"parameters": []
},
{
"name": "SDL_GetModState",
"return_type": "SDL_Keymod",
"parameters": []
},
{
"name": "SDL_SetModState",
"return_type": "void",
"parameters": [
{
"name": "modstate",
"type": "SDL_Keymod"
}
]
},
{
"name": "SDL_GetKeyFromScancode",
"return_type": "SDL_Keycode",
"parameters": [
{
"name": "scancode",
"type": "SDL_Scancode"
},
{
"name": "modstate",
"type": "SDL_Keymod"
},
{
"name": "key_event",
"type": "bool"
}
]
},
{
"name": "SDL_GetScancodeFromKey",
"return_type": "SDL_Scancode",
"parameters": [
{
"name": "key",
"type": "SDL_Keycode"
},
{
"name": "modstate",
"type": "SDL_Keymod *"
}
]
},
{
"name": "SDL_SetScancodeName",
"return_type": "bool",
"parameters": [
{
"name": "scancode",
"type": "SDL_Scancode"
},
{
"name": "name",
"type": "const char *"
}
]
},
{
"name": "SDL_GetScancodeName",
"return_type": "const char *",
"parameters": [
{
"name": "scancode",
"type": "SDL_Scancode"
}
]
},
{
"name": "SDL_GetScancodeFromName",
"return_type": "SDL_Scancode",
"parameters": [
{
"name": "name",
"type": "const char *"
}
]
},
{
"name": "SDL_GetKeyName",
"return_type": "const char *",
"parameters": [
{
"name": "key",
"type": "SDL_Keycode"
}
]
},
{
"name": "SDL_GetKeyFromName",
"return_type": "SDL_Keycode",
"parameters": [
{
"name": "name",
"type": "const char *"
}
]
},
{
"name": "SDL_StartTextInput",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
}
]
},
{
"name": "SDL_StartTextInputWithProperties",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
},
{
"name": "props",
"type": "SDL_PropertiesID"
}
]
},
{
"name": "SDL_TextInputActive",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
}
]
},
{
"name": "SDL_StopTextInput",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
}
]
},
{
"name": "SDL_ClearComposition",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
}
]
},
{
"name": "SDL_SetTextInputArea",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
},
{
"name": "rect",
"type": "const SDL_Rect *"
},
{
"name": "cursor",
"type": "int"
}
]
},
{
"name": "SDL_GetTextInputArea",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
},
{
"name": "rect",
"type": "SDL_Rect *"
},
{
"name": "cursor",
"type": "int *"
}
]
},
{
"name": "SDL_HasScreenKeyboardSupport",
"return_type": "bool",
"parameters": []
},
{
"name": "SDL_ScreenKeyboardShown",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
}
]
}
]
}

View File

@ -12,7 +12,11 @@
} }
], ],
"function_pointers": [], "function_pointers": [],
"c_type_aliases": [], "c_type_aliases": [
{
"name": "SDL_MouseMotionTransformCallback"
}
],
"enums": [ "enums": [
{ {
"name": "SDL_SystemCursor", "name": "SDL_SystemCursor",
@ -116,7 +120,23 @@
] ]
} }
], ],
"structs": [], "structs": [
{
"name": "SDL_CursorFrameInfo",
"fields": [
{
"name": "surface",
"type": "SDL_Surface *",
"comment": "The surface data for this frame"
},
{
"name": "duration",
"type": "Uint32",
"comment": "The frame duration in milliseconds (a duration of 0 is infinite)"
}
]
}
],
"unions": [], "unions": [],
"flags": [ "flags": [
{ {
@ -243,6 +263,20 @@
} }
] ]
}, },
{
"name": "SDL_SetRelativeMouseTransform",
"return_type": "bool",
"parameters": [
{
"name": "callback",
"type": "SDL_MouseMotionTransformCallback"
},
{
"name": "userdata",
"type": "void *"
}
]
},
{ {
"name": "SDL_SetWindowRelativeMouseMode", "name": "SDL_SetWindowRelativeMouseMode",
"return_type": "bool", "return_type": "bool",
@ -325,6 +359,28 @@
} }
] ]
}, },
{
"name": "SDL_CreateAnimatedCursor",
"return_type": "SDL_Cursor *",
"parameters": [
{
"name": "frames",
"type": "SDL_CursorFrameInfo *"
},
{
"name": "frame_count",
"type": "int"
},
{
"name": "hot_x",
"type": "int"
},
{
"name": "hot_y",
"type": "int"
}
]
},
{ {
"name": "SDL_CreateSystemCursor", "name": "SDL_CreateSystemCursor",
"return_type": "SDL_Cursor *", "return_type": "SDL_Cursor *",

12
json/opengl.json Normal file
View File

@ -0,0 +1,12 @@
{
"header": "SDL_opengl.h",
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [],
"unions": [],
"flags": [],
"functions": []
}

View File

@ -200,6 +200,11 @@
"name": "SDL_PIXELFORMAT_EXTERNAL_OES", "name": "SDL_PIXELFORMAT_EXTERNAL_OES",
"value": "0x2053454fu", "value": "0x2053454fu",
"comment": "Android video texture format" "comment": "Android video texture format"
},
{
"name": "SDL_PIXELFORMAT_MJPG",
"value": "0x47504a4du",
"comment": "Motion JPEG"
} }
] ]
}, },
@ -527,7 +532,7 @@
}, },
{ {
"name": "SDL_COLORSPACE_YUV_DEFAULT", "name": "SDL_COLORSPACE_YUV_DEFAULT",
"value": "SDL_COLORSPACE_JPEG", "value": "SDL_COLORSPACE_BT601_LIMITED",
"comment": "The default colorspace for YUV surfaces if no colorspace is specified" "comment": "The default colorspace for YUV surfaces if no colorspace is specified"
} }
] ]
@ -853,7 +858,7 @@
"return_type": "void", "return_type": "void",
"parameters": [ "parameters": [
{ {
"name": "pixel", "name": "pixelvalue",
"type": "Uint32" "type": "Uint32"
}, },
{ {
@ -883,7 +888,7 @@
"return_type": "void", "return_type": "void",
"parameters": [ "parameters": [
{ {
"name": "pixel", "name": "pixelvalue",
"type": "Uint32" "type": "Uint32"
}, },
{ {

57
json/power.json Normal file
View File

@ -0,0 +1,57 @@
{
"header": "SDL_power.h",
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_PowerState",
"values": [
{
"name": "SDL_POWERSTATE_ERROR",
"value": "-1",
"comment": "error determining power status"
},
{
"name": "SDL_POWERSTATE_UNKNOWN",
"comment": "cannot determine power status"
},
{
"name": "SDL_POWERSTATE_ON_BATTERY",
"comment": "Not plugged in, running on the battery"
},
{
"name": "SDL_POWERSTATE_NO_BATTERY",
"comment": "Plugged in, no battery available"
},
{
"name": "SDL_POWERSTATE_CHARGING",
"comment": "Plugged in, charging battery"
},
{
"name": "SDL_POWERSTATE_CHARGED"
}
]
}
],
"structs": [],
"unions": [],
"flags": [],
"functions": [
{
"name": "SDL_GetPowerInfo",
"return_type": "SDL_PowerState",
"parameters": [
{
"name": "seconds",
"type": "int *"
},
{
"name": "percent",
"type": "int *"
}
]
}
]
}

153
json/process.json Normal file
View File

@ -0,0 +1,153 @@
{
"header": "SDL_process.h",
"opaque_types": [
{
"name": "SDL_Process"
}
],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_ProcessIO",
"values": [
{
"name": "SDL_PROCESS_STDIO_INHERITED",
"comment": "The I/O stream is inherited from the application."
},
{
"name": "SDL_PROCESS_STDIO_NULL",
"comment": "The I/O stream is ignored."
},
{
"name": "SDL_PROCESS_STDIO_APP",
"comment": "The I/O stream is connected to a new SDL_IOStream that the application can read or write"
},
{
"name": "SDL_PROCESS_STDIO_REDIRECT",
"comment": "The I/O stream is redirected to an existing SDL_IOStream."
}
]
}
],
"structs": [],
"unions": [],
"flags": [],
"functions": [
{
"name": "SDL_CreateProcess",
"return_type": "SDL_Process *",
"parameters": [
{
"name": "args",
"type": "const char * const *"
},
{
"name": "pipe_stdio",
"type": "bool"
}
]
},
{
"name": "SDL_CreateProcessWithProperties",
"return_type": "SDL_Process *",
"parameters": [
{
"name": "props",
"type": "SDL_PropertiesID"
}
]
},
{
"name": "SDL_GetProcessProperties",
"return_type": "SDL_PropertiesID",
"parameters": [
{
"name": "process",
"type": "SDL_Process *"
}
]
},
{
"name": "SDL_ReadProcess",
"return_type": "void *",
"parameters": [
{
"name": "process",
"type": "SDL_Process *"
},
{
"name": "datasize",
"type": "size_t *"
},
{
"name": "exitcode",
"type": "int *"
}
]
},
{
"name": "SDL_GetProcessInput",
"return_type": "SDL_IOStream *",
"parameters": [
{
"name": "process",
"type": "SDL_Process *"
}
]
},
{
"name": "SDL_GetProcessOutput",
"return_type": "SDL_IOStream *",
"parameters": [
{
"name": "process",
"type": "SDL_Process *"
}
]
},
{
"name": "SDL_KillProcess",
"return_type": "bool",
"parameters": [
{
"name": "process",
"type": "SDL_Process *"
},
{
"name": "force",
"type": "bool"
}
]
},
{
"name": "SDL_WaitProcess",
"return_type": "bool",
"parameters": [
{
"name": "process",
"type": "SDL_Process *"
},
{
"name": "block",
"type": "bool"
},
{
"name": "exitcode",
"type": "int *"
}
]
},
{
"name": "SDL_DestroyProcess",
"return_type": "void",
"parameters": [
{
"name": "process",
"type": "SDL_Process *"
}
]
}
]
}

View File

@ -6,6 +6,9 @@
}, },
{ {
"name": "SDL_Texture" "name": "SDL_Texture"
},
{
"name": "SDL_GPURenderState"
} }
], ],
"typedefs": [], "typedefs": [],
@ -29,6 +32,23 @@
} }
] ]
}, },
{
"name": "SDL_TextureAddressMode",
"values": [
{
"name": "SDL_TEXTURE_ADDRESS_AUTO",
"comment": "Wrapping is enabled if texture coordinates are outside [0, 1], this is the default"
},
{
"name": "SDL_TEXTURE_ADDRESS_CLAMP",
"comment": "Texture coordinates are clamped to the [0, 1] range"
},
{
"name": "SDL_TEXTURE_ADDRESS_WRAP",
"comment": "The texture is repeated (tiled)"
}
]
},
{ {
"name": "SDL_RendererLogicalPresentation", "name": "SDL_RendererLogicalPresentation",
"values": [ "values": [
@ -42,7 +62,7 @@
}, },
{ {
"name": "SDL_LOGICAL_PRESENTATION_LETTERBOX", "name": "SDL_LOGICAL_PRESENTATION_LETTERBOX",
"comment": "The rendered content is fit to the largest dimension and the other dimension is letterboxed with black bars" "comment": "The rendered content is fit to the largest dimension and the other dimension is letterboxed with the clear color"
}, },
{ {
"name": "SDL_LOGICAL_PRESENTATION_OVERSCAN", "name": "SDL_LOGICAL_PRESENTATION_OVERSCAN",
@ -75,6 +95,51 @@
"comment": "Normalized texture coordinates, if needed" "comment": "Normalized texture coordinates, if needed"
} }
] ]
},
{
"name": "SDL_GPURenderStateCreateInfo",
"fields": [
{
"name": "fragment_shader",
"type": "SDL_GPUShader *",
"comment": "The fragment shader to use when this render state is active"
},
{
"name": "num_sampler_bindings",
"type": "Sint32",
"comment": "The number of additional fragment samplers to bind when this render state is active"
},
{
"name": "sampler_bindings",
"type": "const SDL_GPUTextureSamplerBinding *",
"comment": "Additional fragment samplers to bind when this render state is active"
},
{
"name": "num_storage_textures",
"type": "Sint32",
"comment": "The number of storage textures to bind when this render state is active"
},
{
"name": "storage_textures",
"type": "SDL_GPUTexture *const *",
"comment": "Storage textures to bind when this render state is active"
},
{
"name": "num_storage_buffers",
"type": "Sint32",
"comment": "The number of storage buffers to bind when this render state is active"
},
{
"name": "storage_buffers",
"type": "SDL_GPUBuffer *const *",
"comment": "Storage buffers to bind when this render state is active"
},
{
"name": "props",
"type": "SDL_PropertiesID",
"comment": "A properties ID for extensions. Should be 0 if no extensions are needed."
}
]
} }
], ],
"unions": [], "unions": [],
@ -149,6 +214,30 @@
} }
] ]
}, },
{
"name": "SDL_CreateGPURenderer",
"return_type": "SDL_Renderer *",
"parameters": [
{
"name": "device",
"type": "SDL_GPUDevice *"
},
{
"name": "window",
"type": "SDL_Window *"
}
]
},
{
"name": "SDL_GetGPURendererDevice",
"return_type": "SDL_GPUDevice *",
"parameters": [
{
"name": "renderer",
"type": "SDL_Renderer *"
}
]
},
{ {
"name": "SDL_CreateSoftwareRenderer", "name": "SDL_CreateSoftwareRenderer",
"return_type": "SDL_Renderer *", "return_type": "SDL_Renderer *",
@ -327,6 +416,30 @@
} }
] ]
}, },
{
"name": "SDL_SetTexturePalette",
"return_type": "bool",
"parameters": [
{
"name": "texture",
"type": "SDL_Texture *"
},
{
"name": "palette",
"type": "SDL_Palette *"
}
]
},
{
"name": "SDL_GetTexturePalette",
"return_type": "SDL_Palette *",
"parameters": [
{
"name": "texture",
"type": "SDL_Texture *"
}
]
},
{ {
"name": "SDL_SetTextureColorMod", "name": "SDL_SetTextureColorMod",
"return_type": "bool", "return_type": "bool",
@ -1409,6 +1522,52 @@
} }
] ]
}, },
{
"name": "SDL_RenderTexture9GridTiled",
"return_type": "bool",
"parameters": [
{
"name": "renderer",
"type": "SDL_Renderer *"
},
{
"name": "texture",
"type": "SDL_Texture *"
},
{
"name": "srcrect",
"type": "const SDL_FRect *"
},
{
"name": "left_width",
"type": "float"
},
{
"name": "right_width",
"type": "float"
},
{
"name": "top_height",
"type": "float"
},
{
"name": "bottom_height",
"type": "float"
},
{
"name": "scale",
"type": "float"
},
{
"name": "dstrect",
"type": "const SDL_FRect *"
},
{
"name": "tileScale",
"type": "float"
}
]
},
{ {
"name": "SDL_RenderGeometry", "name": "SDL_RenderGeometry",
"return_type": "bool", "return_type": "bool",
@ -1493,6 +1652,42 @@
} }
] ]
}, },
{
"name": "SDL_SetRenderTextureAddressMode",
"return_type": "bool",
"parameters": [
{
"name": "renderer",
"type": "SDL_Renderer *"
},
{
"name": "u_mode",
"type": "SDL_TextureAddressMode"
},
{
"name": "v_mode",
"type": "SDL_TextureAddressMode"
}
]
},
{
"name": "SDL_GetRenderTextureAddressMode",
"return_type": "bool",
"parameters": [
{
"name": "renderer",
"type": "SDL_Renderer *"
},
{
"name": "u_mode",
"type": "SDL_TextureAddressMode *"
},
{
"name": "v_mode",
"type": "SDL_TextureAddressMode *"
}
]
},
{ {
"name": "SDL_RenderReadPixels", "name": "SDL_RenderReadPixels",
"return_type": "SDL_Surface *", "return_type": "SDL_Surface *",
@ -1638,6 +1833,94 @@
"type": "const char *" "type": "const char *"
} }
] ]
},
{
"name": "SDL_SetDefaultTextureScaleMode",
"return_type": "bool",
"parameters": [
{
"name": "renderer",
"type": "SDL_Renderer *"
},
{
"name": "scale_mode",
"type": "SDL_ScaleMode"
}
]
},
{
"name": "SDL_GetDefaultTextureScaleMode",
"return_type": "bool",
"parameters": [
{
"name": "renderer",
"type": "SDL_Renderer *"
},
{
"name": "scale_mode",
"type": "SDL_ScaleMode *"
}
]
},
{
"name": "SDL_CreateGPURenderState",
"return_type": "SDL_GPURenderState *",
"parameters": [
{
"name": "renderer",
"type": "SDL_Renderer *"
},
{
"name": "createinfo",
"type": "SDL_GPURenderStateCreateInfo *"
}
]
},
{
"name": "SDL_SetGPURenderStateFragmentUniforms",
"return_type": "bool",
"parameters": [
{
"name": "state",
"type": "SDL_GPURenderState *"
},
{
"name": "slot_index",
"type": "Uint32"
},
{
"name": "data",
"type": "const void *"
},
{
"name": "length",
"type": "Uint32"
}
]
},
{
"name": "SDL_SetGPURenderState",
"return_type": "bool",
"parameters": [
{
"name": "renderer",
"type": "SDL_Renderer *"
},
{
"name": "state",
"type": "SDL_GPURenderState *"
}
]
},
{
"name": "SDL_DestroyGPURenderState",
"return_type": "void",
"parameters": [
{
"name": "state",
"type": "SDL_GPURenderState *"
}
]
} }
] ]
} }

355
json/scancode.json Normal file
View File

@ -0,0 +1,355 @@
{
"header": "SDL_scancode.h",
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_Scancode",
"values": [
{
"name": "SDL_SCANCODE_BACKSLASH",
"value": "49"
},
{
"name": "SDL_SCANCODE_NONUSHASH",
"value": "50"
},
{
"name": "SDL_SCANCODE_GRAVE",
"value": "53"
},
{
"name": "SDL_SCANCODE_INSERT",
"value": "73"
},
{
"name": "SDL_SCANCODE_NUMLOCKCLEAR",
"value": "83"
},
{
"name": "SDL_SCANCODE_NONUSBACKSLASH",
"value": "100"
},
{
"name": "SDL_SCANCODE_APPLICATION",
"value": "101",
"comment": "windows contextual menu, compose"
},
{
"name": "SDL_SCANCODE_POWER",
"value": "102"
},
{
"name": "SDL_SCANCODE_HELP",
"value": "117",
"comment": "AL Integrated Help Center"
},
{
"name": "SDL_SCANCODE_MENU",
"value": "118",
"comment": "Menu (show menu)"
},
{
"name": "SDL_SCANCODE_STOP",
"value": "120",
"comment": "AC Stop"
},
{
"name": "SDL_SCANCODE_AGAIN",
"value": "121",
"comment": "AC Redo/Repeat"
},
{
"name": "SDL_SCANCODE_UNDO",
"value": "122",
"comment": "AC Undo"
},
{
"name": "SDL_SCANCODE_CUT",
"value": "123",
"comment": "AC Cut"
},
{
"name": "SDL_SCANCODE_COPY",
"value": "124",
"comment": "AC Copy"
},
{
"name": "SDL_SCANCODE_PASTE",
"value": "125",
"comment": "AC Paste"
},
{
"name": "SDL_SCANCODE_FIND",
"value": "126",
"comment": "AC Find"
},
{
"name": "SDL_SCANCODE_INTERNATIONAL1",
"value": "135"
},
{
"name": "SDL_SCANCODE_INTERNATIONAL3",
"value": "137",
"comment": "Yen"
},
{
"name": "SDL_SCANCODE_LANG1",
"value": "144",
"comment": "Hangul/English toggle"
},
{
"name": "SDL_SCANCODE_LANG2",
"value": "145",
"comment": "Hanja conversion"
},
{
"name": "SDL_SCANCODE_LANG3",
"value": "146",
"comment": "Katakana"
},
{
"name": "SDL_SCANCODE_LANG4",
"value": "147",
"comment": "Hiragana"
},
{
"name": "SDL_SCANCODE_LANG5",
"value": "148",
"comment": "Zenkaku/Hankaku"
},
{
"name": "SDL_SCANCODE_LANG6",
"value": "149",
"comment": "reserved"
},
{
"name": "SDL_SCANCODE_LANG7",
"value": "150",
"comment": "reserved"
},
{
"name": "SDL_SCANCODE_LANG8",
"value": "151",
"comment": "reserved"
},
{
"name": "SDL_SCANCODE_LANG9",
"value": "152",
"comment": "reserved"
},
{
"name": "SDL_SCANCODE_ALTERASE",
"value": "153",
"comment": "Erase-Eaze"
},
{
"name": "SDL_SCANCODE_CANCEL",
"value": "155",
"comment": "AC Cancel"
},
{
"name": "SDL_SCANCODE_LALT",
"value": "226",
"comment": "alt, option"
},
{
"name": "SDL_SCANCODE_LGUI",
"value": "227",
"comment": "windows, command (apple), meta"
},
{
"name": "SDL_SCANCODE_RALT",
"value": "230",
"comment": "alt gr, option"
},
{
"name": "SDL_SCANCODE_RGUI",
"value": "231",
"comment": "windows, command (apple), meta"
},
{
"name": "SDL_SCANCODE_MODE",
"value": "257"
},
{
"name": "SDL_SCANCODE_SLEEP",
"value": "258",
"comment": "Sleep"
},
{
"name": "SDL_SCANCODE_WAKE",
"value": "259",
"comment": "Wake"
},
{
"name": "SDL_SCANCODE_CHANNEL_INCREMENT",
"value": "260",
"comment": "Channel Increment"
},
{
"name": "SDL_SCANCODE_CHANNEL_DECREMENT",
"value": "261",
"comment": "Channel Decrement"
},
{
"name": "SDL_SCANCODE_MEDIA_PLAY",
"value": "262",
"comment": "Play"
},
{
"name": "SDL_SCANCODE_MEDIA_PAUSE",
"value": "263",
"comment": "Pause"
},
{
"name": "SDL_SCANCODE_MEDIA_RECORD",
"value": "264",
"comment": "Record"
},
{
"name": "SDL_SCANCODE_MEDIA_FAST_FORWARD",
"value": "265",
"comment": "Fast Forward"
},
{
"name": "SDL_SCANCODE_MEDIA_REWIND",
"value": "266",
"comment": "Rewind"
},
{
"name": "SDL_SCANCODE_MEDIA_NEXT_TRACK",
"value": "267",
"comment": "Next Track"
},
{
"name": "SDL_SCANCODE_MEDIA_PREVIOUS_TRACK",
"value": "268",
"comment": "Previous Track"
},
{
"name": "SDL_SCANCODE_MEDIA_STOP",
"value": "269",
"comment": "Stop"
},
{
"name": "SDL_SCANCODE_MEDIA_EJECT",
"value": "270",
"comment": "Eject"
},
{
"name": "SDL_SCANCODE_MEDIA_PLAY_PAUSE",
"value": "271",
"comment": "Play / Pause"
},
{
"name": "SDL_SCANCODE_MEDIA_SELECT",
"value": "272"
},
{
"name": "SDL_SCANCODE_AC_NEW",
"value": "273",
"comment": "AC New"
},
{
"name": "SDL_SCANCODE_AC_OPEN",
"value": "274",
"comment": "AC Open"
},
{
"name": "SDL_SCANCODE_AC_CLOSE",
"value": "275",
"comment": "AC Close"
},
{
"name": "SDL_SCANCODE_AC_EXIT",
"value": "276",
"comment": "AC Exit"
},
{
"name": "SDL_SCANCODE_AC_SAVE",
"value": "277",
"comment": "AC Save"
},
{
"name": "SDL_SCANCODE_AC_PRINT",
"value": "278",
"comment": "AC Print"
},
{
"name": "SDL_SCANCODE_AC_PROPERTIES",
"value": "279",
"comment": "AC Properties"
},
{
"name": "SDL_SCANCODE_AC_SEARCH",
"value": "280",
"comment": "AC Search"
},
{
"name": "SDL_SCANCODE_AC_HOME",
"value": "281",
"comment": "AC Home"
},
{
"name": "SDL_SCANCODE_AC_BACK",
"value": "282",
"comment": "AC Back"
},
{
"name": "SDL_SCANCODE_AC_FORWARD",
"value": "283",
"comment": "AC Forward"
},
{
"name": "SDL_SCANCODE_AC_STOP",
"value": "284",
"comment": "AC Stop"
},
{
"name": "SDL_SCANCODE_AC_REFRESH",
"value": "285",
"comment": "AC Refresh"
},
{
"name": "SDL_SCANCODE_AC_BOOKMARKS",
"value": "286",
"comment": "AC Bookmarks"
},
{
"name": "SDL_SCANCODE_SOFTLEFT",
"value": "287"
},
{
"name": "SDL_SCANCODE_SOFTRIGHT",
"value": "288"
},
{
"name": "SDL_SCANCODE_CALL",
"value": "289",
"comment": "Used for accepting phone calls."
},
{
"name": "SDL_SCANCODE_ENDCALL",
"value": "290",
"comment": "Used for rejecting phone calls."
},
{
"name": "SDL_SCANCODE_RESERVED",
"value": "400",
"comment": "400-500 reserved for dynamic keycodes"
},
{
"name": "SDL_SCANCODE_COUNT",
"value": "512"
}
]
}
],
"structs": [],
"unions": [],
"flags": [],
"functions": []
}

View File

@ -49,6 +49,9 @@
{ {
"name": "SDL_SENSOR_GYRO_R", "name": "SDL_SENSOR_GYRO_R",
"comment": "Gyroscope for right Joy-Con controller" "comment": "Gyroscope for right Joy-Con controller"
},
{
"name": "SDL_SENSOR_COUNT"
} }
] ]
} }

View File

@ -19,6 +19,9 @@
{ {
"name": "SDL_SCALEMODE_LINEAR", "name": "SDL_SCALEMODE_LINEAR",
"comment": "linear filtering" "comment": "linear filtering"
},
{
"name": "SDL_SCALEMODE_PIXELART"
} }
] ]
}, },
@ -36,6 +39,11 @@
{ {
"name": "SDL_FLIP_VERTICAL", "name": "SDL_FLIP_VERTICAL",
"comment": "flip vertically" "comment": "flip vertically"
},
{
"name": "SDL_FLIP_HORIZONTAL_AND_VERTICAL",
"value": "(SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL)",
"comment": "flip horizontally and vertically (not a diagonal flip)"
} }
] ]
} }
@ -261,6 +269,30 @@
} }
] ]
}, },
{
"name": "SDL_LoadSurface_IO",
"return_type": "SDL_Surface *",
"parameters": [
{
"name": "src",
"type": "SDL_IOStream *"
},
{
"name": "closeio",
"type": "bool"
}
]
},
{
"name": "SDL_LoadSurface",
"return_type": "SDL_Surface *",
"parameters": [
{
"name": "file",
"type": "const char *"
}
]
},
{ {
"name": "SDL_LoadBMP_IO", "name": "SDL_LoadBMP_IO",
"return_type": "SDL_Surface *", "return_type": "SDL_Surface *",
@ -317,6 +349,62 @@
} }
] ]
}, },
{
"name": "SDL_LoadPNG_IO",
"return_type": "SDL_Surface *",
"parameters": [
{
"name": "src",
"type": "SDL_IOStream *"
},
{
"name": "closeio",
"type": "bool"
}
]
},
{
"name": "SDL_LoadPNG",
"return_type": "SDL_Surface *",
"parameters": [
{
"name": "file",
"type": "const char *"
}
]
},
{
"name": "SDL_SavePNG_IO",
"return_type": "bool",
"parameters": [
{
"name": "surface",
"type": "SDL_Surface *"
},
{
"name": "dst",
"type": "SDL_IOStream *"
},
{
"name": "closeio",
"type": "bool"
}
]
},
{
"name": "SDL_SavePNG",
"return_type": "bool",
"parameters": [
{
"name": "surface",
"type": "SDL_Surface *"
},
{
"name": "file",
"type": "const char *"
}
]
},
{ {
"name": "SDL_SetSurfaceRLE", "name": "SDL_SetSurfaceRLE",
"return_type": "bool", "return_type": "bool",
@ -525,6 +613,20 @@
} }
] ]
}, },
{
"name": "SDL_RotateSurface",
"return_type": "SDL_Surface *",
"parameters": [
{
"name": "surface",
"type": "SDL_Surface *"
},
{
"name": "angle",
"type": "float"
}
]
},
{ {
"name": "SDL_DuplicateSurface", "name": "SDL_DuplicateSurface",
"return_type": "SDL_Surface *", "return_type": "SDL_Surface *",
@ -907,6 +1009,32 @@
} }
] ]
}, },
{
"name": "SDL_StretchSurface",
"return_type": "bool",
"parameters": [
{
"name": "src",
"type": "SDL_Surface *"
},
{
"name": "srcrect",
"type": "const SDL_Rect *"
},
{
"name": "dst",
"type": "SDL_Surface *"
},
{
"name": "dstrect",
"type": "const SDL_Rect *"
},
{
"name": "scaleMode",
"type": "SDL_ScaleMode"
}
]
},
{ {
"name": "SDL_BlitSurfaceTiled", "name": "SDL_BlitSurfaceTiled",
"return_type": "bool", "return_type": "bool",

332
json/tray.json Normal file
View File

@ -0,0 +1,332 @@
{
"header": "SDL_tray.h",
"opaque_types": [
{
"name": "SDL_Tray"
},
{
"name": "SDL_TrayMenu"
},
{
"name": "SDL_TrayEntry"
}
],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_TrayCallback"
}
],
"enums": [],
"structs": [],
"unions": [],
"flags": [
{
"name": "SDL_TrayEntryFlags",
"underlying_type": "Uint32",
"values": [
{
"name": "SDL_TRAYENTRY_BUTTON",
"value": "(1u << 0)",
"comment": "Make the entry a simple button. Required."
},
{
"name": "SDL_TRAYENTRY_CHECKBOX",
"value": "(1u << 1)",
"comment": "Make the entry a checkbox. Required."
},
{
"name": "SDL_TRAYENTRY_SUBMENU",
"value": "(1u << 2)",
"comment": "Prepare the entry to have a submenu. Required"
},
{
"name": "SDL_TRAYENTRY_DISABLED",
"value": "(1u << 31)",
"comment": "Make the entry disabled. Optional."
},
{
"name": "SDL_TRAYENTRY_CHECKED",
"value": "(1u << 30)",
"comment": "Make the entry checked. This is valid only for checkboxes. Optional."
}
]
}
],
"functions": [
{
"name": "SDL_CreateTray",
"return_type": "SDL_Tray *",
"parameters": [
{
"name": "icon",
"type": "SDL_Surface *"
},
{
"name": "tooltip",
"type": "const char *"
}
]
},
{
"name": "SDL_SetTrayIcon",
"return_type": "void",
"parameters": [
{
"name": "tray",
"type": "SDL_Tray *"
},
{
"name": "icon",
"type": "SDL_Surface *"
}
]
},
{
"name": "SDL_SetTrayTooltip",
"return_type": "void",
"parameters": [
{
"name": "tray",
"type": "SDL_Tray *"
},
{
"name": "tooltip",
"type": "const char *"
}
]
},
{
"name": "SDL_CreateTrayMenu",
"return_type": "SDL_TrayMenu *",
"parameters": [
{
"name": "tray",
"type": "SDL_Tray *"
}
]
},
{
"name": "SDL_CreateTraySubmenu",
"return_type": "SDL_TrayMenu *",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
}
]
},
{
"name": "SDL_GetTrayMenu",
"return_type": "SDL_TrayMenu *",
"parameters": [
{
"name": "tray",
"type": "SDL_Tray *"
}
]
},
{
"name": "SDL_GetTraySubmenu",
"return_type": "SDL_TrayMenu *",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
}
]
},
{
"name": "SDL_GetTrayEntries",
"return_type": "const SDL_TrayEntry **",
"parameters": [
{
"name": "menu",
"type": "SDL_TrayMenu *"
},
{
"name": "count",
"type": "int *"
}
]
},
{
"name": "SDL_RemoveTrayEntry",
"return_type": "void",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
}
]
},
{
"name": "SDL_InsertTrayEntryAt",
"return_type": "SDL_TrayEntry *",
"parameters": [
{
"name": "menu",
"type": "SDL_TrayMenu *"
},
{
"name": "pos",
"type": "int"
},
{
"name": "label",
"type": "const char *"
},
{
"name": "flags",
"type": "SDL_TrayEntryFlags"
}
]
},
{
"name": "SDL_SetTrayEntryLabel",
"return_type": "void",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
},
{
"name": "label",
"type": "const char *"
}
]
},
{
"name": "SDL_GetTrayEntryLabel",
"return_type": "const char *",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
}
]
},
{
"name": "SDL_SetTrayEntryChecked",
"return_type": "void",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
},
{
"name": "checked",
"type": "bool"
}
]
},
{
"name": "SDL_GetTrayEntryChecked",
"return_type": "bool",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
}
]
},
{
"name": "SDL_SetTrayEntryEnabled",
"return_type": "void",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
},
{
"name": "enabled",
"type": "bool"
}
]
},
{
"name": "SDL_GetTrayEntryEnabled",
"return_type": "bool",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
}
]
},
{
"name": "SDL_SetTrayEntryCallback",
"return_type": "void",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
},
{
"name": "callback",
"type": "SDL_TrayCallback"
},
{
"name": "userdata",
"type": "void *"
}
]
},
{
"name": "SDL_ClickTrayEntry",
"return_type": "void",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
}
]
},
{
"name": "SDL_DestroyTray",
"return_type": "void",
"parameters": [
{
"name": "tray",
"type": "SDL_Tray *"
}
]
},
{
"name": "SDL_GetTrayEntryParent",
"return_type": "SDL_TrayMenu *",
"parameters": [
{
"name": "entry",
"type": "SDL_TrayEntry *"
}
]
},
{
"name": "SDL_GetTrayMenuParentEntry",
"return_type": "SDL_TrayEntry *",
"parameters": [
{
"name": "menu",
"type": "SDL_TrayMenu *"
}
]
},
{
"name": "SDL_GetTrayMenuParentTray",
"return_type": "SDL_Tray *",
"parameters": [
{
"name": "menu",
"type": "SDL_TrayMenu *"
}
]
},
{
"name": "SDL_UpdateTrays",
"return_type": "void",
"parameters": []
}
]
}

View File

@ -129,24 +129,54 @@
} }
] ]
}, },
{
"name": "SDL_ProgressState",
"values": [
{
"name": "SDL_PROGRESS_STATE_INVALID",
"value": "-1",
"comment": "An invalid progress state indicating an error; check SDL_GetError()"
},
{
"name": "SDL_PROGRESS_STATE_NONE",
"comment": "No progress bar is shown"
},
{
"name": "SDL_PROGRESS_STATE_INDETERMINATE",
"comment": "The progress bar is shown in a indeterminate state"
},
{
"name": "SDL_PROGRESS_STATE_NORMAL",
"comment": "The progress bar is shown in a normal state"
},
{
"name": "SDL_PROGRESS_STATE_PAUSED",
"comment": "The progress bar is shown in a paused state"
},
{
"name": "SDL_PROGRESS_STATE_ERROR",
"comment": "The progress bar is shown in a state indicating the application had an error"
}
]
},
{ {
"name": "SDL_GLAttr", "name": "SDL_GLAttr",
"values": [ "values": [
{ {
"name": "SDL_GL_RED_SIZE", "name": "SDL_GL_RED_SIZE",
"comment": "the minimum number of bits for the red channel of the color buffer; defaults to 3." "comment": "the minimum number of bits for the red channel of the color buffer; defaults to 8."
}, },
{ {
"name": "SDL_GL_GREEN_SIZE", "name": "SDL_GL_GREEN_SIZE",
"comment": "the minimum number of bits for the green channel of the color buffer; defaults to 3." "comment": "the minimum number of bits for the green channel of the color buffer; defaults to 8."
}, },
{ {
"name": "SDL_GL_BLUE_SIZE", "name": "SDL_GL_BLUE_SIZE",
"comment": "the minimum number of bits for the blue channel of the color buffer; defaults to 2." "comment": "the minimum number of bits for the blue channel of the color buffer; defaults to 8."
}, },
{ {
"name": "SDL_GL_ALPHA_SIZE", "name": "SDL_GL_ALPHA_SIZE",
"comment": "the minimum number of bits for the alpha channel of the color buffer; defaults to 0." "comment": "the minimum number of bits for the alpha channel of the color buffer; defaults to 8."
}, },
{ {
"name": "SDL_GL_BUFFER_SIZE", "name": "SDL_GL_BUFFER_SIZE",
@ -222,7 +252,7 @@
}, },
{ {
"name": "SDL_GL_FRAMEBUFFER_SRGB_CAPABLE", "name": "SDL_GL_FRAMEBUFFER_SRGB_CAPABLE",
"comment": "requests sRGB capable visual; defaults to 0." "comment": "requests sRGB-capable visual if 1. Defaults to -1 (\"don't care\"). This is a request; GL drivers might not comply!"
}, },
{ {
"name": "SDL_GL_CONTEXT_RELEASE_BEHAVIOR", "name": "SDL_GL_CONTEXT_RELEASE_BEHAVIOR",
@ -452,6 +482,11 @@
"value": "(1u << 20)", "value": "(1u << 20)",
"comment": "window has grabbed keyboard input" "comment": "window has grabbed keyboard input"
}, },
{
"name": "SDL_WINDOW_FILL_DOCUMENT",
"value": "(1u << 21)",
"comment": "window is in fill-document mode (Emscripten only), since SDL 3.4.0"
},
{ {
"name": "SDL_WINDOW_VULKAN", "name": "SDL_WINDOW_VULKAN",
"value": "(1u << 28)", "value": "(1u << 28)",
@ -1196,6 +1231,20 @@
} }
] ]
}, },
{
"name": "SDL_SetWindowFillDocument",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
},
{
"name": "fill",
"type": "bool"
}
]
},
{ {
"name": "SDL_ShowWindow", "name": "SDL_ShowWindow",
"return_type": "bool", "return_type": "bool",
@ -1573,6 +1622,54 @@
} }
] ]
}, },
{
"name": "SDL_SetWindowProgressState",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
},
{
"name": "state",
"type": "SDL_ProgressState"
}
]
},
{
"name": "SDL_GetWindowProgressState",
"return_type": "SDL_ProgressState",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
}
]
},
{
"name": "SDL_SetWindowProgressValue",
"return_type": "bool",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
},
{
"name": "value",
"type": "float"
}
]
},
{
"name": "SDL_GetWindowProgressValue",
"return_type": "float",
"parameters": [
{
"name": "window",
"type": "SDL_Window *"
}
]
},
{ {
"name": "SDL_DestroyWindow", "name": "SDL_DestroyWindow",
"return_type": "void", "return_type": "void",

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +1,48 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const patterns = @import("patterns.zig"); const patterns = @import("patterns.zig");
const resolved_decl = @import("resolved_decl.zig");
const Declaration = patterns.Declaration; const Declaration = patterns.Declaration;
const ResolvedDecl = resolved_decl.ResolvedDecl;
const CachedDecl = struct {
decl: Declaration,
source_header: []const u8,
fn deinit(self: CachedDecl, allocator: Allocator) void {
switch (self.decl) {
inline else => |*d| d.deinit(allocator),
}
allocator.free(self.source_header);
}
};
pub const HeaderCache = struct { pub const HeaderCache = struct {
// Map from type name to its declaration type_cache: std.StringHashMap(CachedDecl),
type_cache: std.StringHashMap(Declaration),
// Track which headers we've already parsed (avoid re-parsing)
parsed_headers: std.StringHashMap(void), parsed_headers: std.StringHashMap(void),
allocator: Allocator, allocator: Allocator,
pub fn init(allocator: Allocator) HeaderCache { pub fn init(allocator: Allocator) HeaderCache {
return .{ return .{
.type_cache = std.StringHashMap(Declaration).init(allocator), .type_cache = std.StringHashMap(CachedDecl).init(allocator),
.parsed_headers = std.StringHashMap(void).init(allocator), .parsed_headers = std.StringHashMap(void).init(allocator),
.allocator = allocator, .allocator = allocator,
}; };
} }
pub fn deinit(self: *HeaderCache) void { pub fn deinit(self: *HeaderCache) void {
// Free type cache keys
var type_it = self.type_cache.keyIterator(); var type_it = self.type_cache.keyIterator();
while (type_it.next()) |key| { while (type_it.next()) |key| {
self.allocator.free(key.*); self.allocator.free(key.*);
} }
// Free cached declarations
var val_it = self.type_cache.valueIterator(); var val_it = self.type_cache.valueIterator();
while (val_it.next()) |decl| { while (val_it.next()) |cached_decl| {
freeDeclaration(self.allocator, decl.*); cached_decl.deinit(self.allocator);
} }
self.type_cache.deinit(); self.type_cache.deinit();
// Free parsed headers keys
var header_it = self.parsed_headers.keyIterator(); var header_it = self.parsed_headers.keyIterator();
while (header_it.next()) |key| { while (header_it.next()) |key| {
self.allocator.free(key.*); self.allocator.free(key.*);
@ -45,31 +56,20 @@ pub const HeaderCache = struct {
const header_dir = std.fs.path.dirname(header_path) orelse "."; const header_dir = std.fs.path.dirname(header_path) orelse ".";
try cache.parseHeaderRecursive(header_dir, std.fs.path.basename(header_path)); try cache.parseHeaderRecursive(header_dir, std.fs.path.basename(header_path));
return cache; return cache;
} }
fn parseHeaderRecursive(self: *HeaderCache, header_dir: []const u8, filename: []const u8) !void { fn parseHeaderRecursive(self: *HeaderCache, header_dir: []const u8, filename: []const u8) !void {
// Skip non-SDL headers (stdlib, system headers, etc) if (!std.mem.startsWith(u8, filename, "SDL_")) return;
if (!std.mem.startsWith(u8, filename, "SDL_")) { if (self.parsed_headers.contains(filename)) return;
return;
}
// Skip if already parsed
if (self.parsed_headers.contains(filename)) {
return;
}
// Mark as parsed
try self.parsed_headers.put(try self.allocator.dupe(u8, filename), {}); try self.parsed_headers.put(try self.allocator.dupe(u8, filename), {});
// Build full path const full_path = try std.fs.path.join(self.allocator, &.{ header_dir, filename });
const full_path = try std.fs.path.join(self.allocator, &[_][]const u8{ header_dir, filename });
defer self.allocator.free(full_path); defer self.allocator.free(full_path);
std.debug.print(" Caching types from: {s}\n", .{filename}); std.debug.print(" Caching types from: {s}\n", .{filename});
// Read and parse this header
const content = std.fs.cwd().readFileAlloc(self.allocator, full_path, 10_000_000) catch |err| { const content = std.fs.cwd().readFileAlloc(self.allocator, full_path, 10_000_000) catch |err| {
std.debug.print(" Warning: Could not read {s}: {}\n", .{ filename, err }); std.debug.print(" Warning: Could not read {s}: {}\n", .{ filename, err });
return; return;
@ -83,25 +83,24 @@ pub const HeaderCache = struct {
}; };
defer self.allocator.free(decls); defer self.allocator.free(decls);
// Add all type definitions to cache
for (decls) |decl| { for (decls) |decl| {
const type_name = getTypeName(decl); const type_name = resolved_decl.getTypeName(decl);
if (type_name) |name| { if (type_name) |name| {
// Don't cache if already present (first occurrence wins)
if (!self.type_cache.contains(name)) { if (!self.type_cache.contains(name)) {
const name_copy = try self.allocator.dupe(u8, name); try self.type_cache.put(try self.allocator.dupe(u8, name), .{
const decl_copy = try cloneDeclaration(self.allocator, decl); .decl = try resolved_decl.cloneDeclaration(self.allocator, decl),
try self.type_cache.put(name_copy, decl_copy); .source_header = try self.allocator.dupe(u8, filename),
});
} }
} }
} }
// Free the original declarations (we made copies)
for (decls) |decl| { for (decls) |decl| {
freeDeclaration(self.allocator, decl); switch (decl) {
inline else => |*d| d.deinit(self.allocator),
}
} }
// Find and recursively parse all #include "SDL_*.h" directives
const includes = try findSDLIncludes(self.allocator, content); const includes = try findSDLIncludes(self.allocator, content);
defer { defer {
for (includes) |inc| self.allocator.free(inc); for (includes) |inc| self.allocator.free(inc);
@ -114,25 +113,21 @@ pub const HeaderCache = struct {
} }
pub fn lookupType(self: *HeaderCache, type_name: []const u8) ?Declaration { pub fn lookupType(self: *HeaderCache, type_name: []const u8) ?Declaration {
const decl = self.type_cache.get(type_name) orelse return null; const cached_decl = self.type_cache.get(type_name) orelse return null;
// Return a copy so caller owns it return resolved_decl.cloneDeclaration(self.allocator, cached_decl.decl) catch null;
return cloneDeclaration(self.allocator, decl) catch null;
} }
/// Lookup a type and recursively resolve all its dependencies pub fn lookupTypeWithDependencies(self: *HeaderCache, type_name: []const u8) ![]ResolvedDecl {
/// Returns an array of declarations: [0] is the requested type, [1..] are dependencies
pub fn lookupTypeWithDependencies(self: *HeaderCache, type_name: []const u8) ![]Declaration {
const dependency_resolver = @import("dependency_resolver.zig"); const dependency_resolver = @import("dependency_resolver.zig");
var result = try std.ArrayList(Declaration).initCapacity(self.allocator, 10); var result = try std.ArrayList(ResolvedDecl).initCapacity(self.allocator, 10);
errdefer { errdefer {
for (result.items) |decl| { for (result.items) |decl| {
freeDeclaration(self.allocator, decl); decl.deinit(self.allocator);
} }
result.deinit(self.allocator); result.deinit(self.allocator);
} }
// Track which types we've already processed
var processed = std.StringHashMap(void).init(self.allocator); var processed = std.StringHashMap(void).init(self.allocator);
defer { defer {
var it = processed.keyIterator(); var it = processed.keyIterator();
@ -142,7 +137,6 @@ pub const HeaderCache = struct {
processed.deinit(); processed.deinit();
} }
// Work queue for types to resolve
var queue = try std.ArrayList([]const u8).initCapacity(self.allocator, 10); var queue = try std.ArrayList([]const u8).initCapacity(self.allocator, 10);
defer { defer {
for (queue.items) |item| { for (queue.items) |item| {
@ -151,30 +145,27 @@ pub const HeaderCache = struct {
queue.deinit(self.allocator); queue.deinit(self.allocator);
} }
// Start with the requested type
try queue.append(self.allocator, try self.allocator.dupe(u8, type_name)); try queue.append(self.allocator, try self.allocator.dupe(u8, type_name));
// Process queue until empty
while (queue.items.len > 0) { while (queue.items.len > 0) {
const current_type = queue.orderedRemove(0); const current_type = queue.orderedRemove(0);
defer self.allocator.free(current_type); defer self.allocator.free(current_type);
// Skip if already processed
if (processed.contains(current_type)) continue; if (processed.contains(current_type)) continue;
try processed.put(try self.allocator.dupe(u8, current_type), {}); try processed.put(try self.allocator.dupe(u8, current_type), {});
// Look up the type const cached_decl = self.type_cache.get(current_type) orelse continue;
const decl = self.type_cache.get(current_type) orelse continue;
// Add cloned declaration to result try result.append(self.allocator, .{
const decl_copy = try cloneDeclaration(self.allocator, decl); .decl = try resolved_decl.cloneDeclaration(self.allocator, cached_decl.decl),
try result.append(self.allocator, decl_copy); .source_header = try self.allocator.dupe(u8, cached_decl.source_header),
.is_primary_header_decl = false,
});
// Analyze this declaration to find its dependencies
var resolver = dependency_resolver.DependencyResolver.init(self.allocator); var resolver = dependency_resolver.DependencyResolver.init(self.allocator);
defer resolver.deinit(); defer resolver.deinit();
const single_decl = [_]Declaration{decl}; const single_decl = [_]Declaration{cached_decl.decl};
try resolver.analyze(&single_decl); try resolver.analyze(&single_decl);
const missing = try resolver.getMissingTypes(self.allocator); const missing = try resolver.getMissingTypes(self.allocator);
@ -183,7 +174,6 @@ pub const HeaderCache = struct {
self.allocator.free(missing); self.allocator.free(missing);
} }
// Add missing types to queue if not already processed
for (missing) |missing_type| { for (missing) |missing_type| {
if (!processed.contains(missing_type) and self.type_cache.contains(missing_type)) { if (!processed.contains(missing_type) and self.type_cache.contains(missing_type)) {
try queue.append(self.allocator, try self.allocator.dupe(u8, missing_type)); try queue.append(self.allocator, try self.allocator.dupe(u8, missing_type));
@ -194,22 +184,8 @@ pub const HeaderCache = struct {
return try result.toOwnedSlice(self.allocator); return try result.toOwnedSlice(self.allocator);
} }
fn getTypeName(decl: Declaration) ?[]const u8 {
return switch (decl) {
.opaque_type => |o| o.name,
.typedef_decl => |t| t.name,
.function_pointer_decl => |fp| fp.name,
.c_type_alias => |a| a.name,
.enum_decl => |e| e.name,
.struct_decl => |s| s.name,
.union_decl => |u| u.name,
.flag_decl => |f| f.name,
.function_decl => null, // Functions don't define types
};
}
fn findSDLIncludes(allocator: Allocator, source: []const u8) ![][]const u8 { fn findSDLIncludes(allocator: Allocator, source: []const u8) ![][]const u8 {
var includes = std.ArrayList([]const u8){}; var includes: std.ArrayList([]const u8) = .empty;
errdefer { errdefer {
for (includes.items) |inc| allocator.free(inc); for (includes.items) |inc| allocator.free(inc);
includes.deinit(allocator); includes.deinit(allocator);
@ -219,7 +195,6 @@ pub const HeaderCache = struct {
while (lines.next()) |line| { while (lines.next()) |line| {
const trimmed = std.mem.trim(u8, line, " \t\r"); const trimmed = std.mem.trim(u8, line, " \t\r");
// Match: #include <SDL3/SDL_something.h>
if (std.mem.startsWith(u8, trimmed, "#include <SDL3/")) { if (std.mem.startsWith(u8, trimmed, "#include <SDL3/")) {
const after_open = "#include <SDL3/".len; const after_open = "#include <SDL3/".len;
if (std.mem.indexOf(u8, trimmed[after_open..], ">")) |end| { if (std.mem.indexOf(u8, trimmed[after_open..], ">")) |end| {
@ -228,9 +203,7 @@ pub const HeaderCache = struct {
try includes.append(allocator, try allocator.dupe(u8, header_name)); try includes.append(allocator, try allocator.dupe(u8, header_name));
} }
} }
} } else if (std.mem.startsWith(u8, trimmed, "#include \"SDL_")) {
// Also match: #include "SDL_something.h"
else if (std.mem.startsWith(u8, trimmed, "#include \"SDL_")) {
const after_open = "#include \"".len; const after_open = "#include \"".len;
if (std.mem.indexOf(u8, trimmed[after_open..], "\"")) |end| { if (std.mem.indexOf(u8, trimmed[after_open..], "\"")) |end| {
const header_name = trimmed[after_open..][0..end]; const header_name = trimmed[after_open..][0..end];
@ -244,212 +217,3 @@ pub const HeaderCache = struct {
return try includes.toOwnedSlice(allocator); return try includes.toOwnedSlice(allocator);
} }
}; };
fn cloneDeclaration(allocator: Allocator, decl: Declaration) !Declaration {
return switch (decl) {
.opaque_type => |o| Declaration{
.opaque_type = .{
.name = try allocator.dupe(u8, o.name),
.doc_comment = if (o.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.typedef_decl => |t| Declaration{
.typedef_decl = .{
.name = try allocator.dupe(u8, t.name),
.underlying_type = try allocator.dupe(u8, t.underlying_type),
.doc_comment = if (t.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.enum_decl => |e| Declaration{
.enum_decl = .{
.name = try allocator.dupe(u8, e.name),
.values = try cloneEnumValues(allocator, e.values),
.doc_comment = if (e.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.struct_decl => |s| Declaration{
.struct_decl = .{
.name = try allocator.dupe(u8, s.name),
.fields = try cloneFields(allocator, s.fields),
.doc_comment = if (s.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
.has_unions = s.has_unions,
},
},
.union_decl => |u| Declaration{
.union_decl = .{
.name = try allocator.dupe(u8, u.name),
.fields = try cloneFields(allocator, u.fields),
.doc_comment = if (u.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.flag_decl => |f| Declaration{
.flag_decl = .{
.name = try allocator.dupe(u8, f.name),
.underlying_type = try allocator.dupe(u8, f.underlying_type),
.flags = try cloneFlagValues(allocator, f.flags),
.constants = try cloneConstValues(allocator, f.constants),
.doc_comment = if (f.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.function_decl => |func| Declaration{
.function_decl = .{
.name = try allocator.dupe(u8, func.name),
.return_type = try allocator.dupe(u8, func.return_type),
.params = try cloneParams(allocator, func.params),
.doc_comment = if (func.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.function_pointer_decl => |fp| Declaration{
.function_pointer_decl = .{
.name = try allocator.dupe(u8, fp.name),
.return_type = try allocator.dupe(u8, fp.return_type),
.params = try cloneParams(allocator, fp.params),
.doc_comment = if (fp.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.c_type_alias => |a| Declaration{
.c_type_alias = .{
.name = try allocator.dupe(u8, a.name),
.doc_comment = if (a.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
};
}
fn cloneEnumValues(allocator: Allocator, values: []const patterns.EnumValue) ![]patterns.EnumValue {
const new_values = try allocator.alloc(patterns.EnumValue, values.len);
for (values, 0..) |val, i| {
new_values[i] = .{
.name = try allocator.dupe(u8, val.name),
.value = if (val.value) |v| try allocator.dupe(u8, v) else null,
.comment = if (val.comment) |c| try allocator.dupe(u8, c) else null,
};
}
return new_values;
}
fn cloneFlagValues(allocator: Allocator, flags: []const patterns.FlagValue) ![]patterns.FlagValue {
const new_flags = try allocator.alloc(patterns.FlagValue, flags.len);
for (flags, 0..) |flag, i| {
new_flags[i] = .{
.name = try allocator.dupe(u8, flag.name),
.value = try allocator.dupe(u8, flag.value),
.comment = if (flag.comment) |c| try allocator.dupe(u8, c) else null,
};
}
return new_flags;
}
fn cloneConstValues(allocator: Allocator, constants: []const patterns.ConstValue) ![]patterns.ConstValue {
const new_constants = try allocator.alloc(patterns.ConstValue, constants.len);
for (constants, 0..) |constant, i| {
new_constants[i] = .{
.name = try allocator.dupe(u8, constant.name),
.value = try allocator.dupe(u8, constant.value),
.comment = if (constant.comment) |c| try allocator.dupe(u8, c) else null,
};
}
return new_constants;
}
fn cloneFields(allocator: Allocator, fields: []const patterns.FieldDecl) ![]patterns.FieldDecl {
const new_fields = try allocator.alloc(patterns.FieldDecl, fields.len);
for (fields, 0..) |field, i| {
new_fields[i] = .{
.name = try allocator.dupe(u8, field.name),
.type_name = try allocator.dupe(u8, field.type_name),
.comment = if (field.comment) |c| try allocator.dupe(u8, c) else null,
};
}
return new_fields;
}
fn cloneParams(allocator: Allocator, params: []const patterns.ParamDecl) ![]patterns.ParamDecl {
const new_params = try allocator.alloc(patterns.ParamDecl, params.len);
for (params, 0..) |param, i| {
new_params[i] = .{
.name = try allocator.dupe(u8, param.name),
.type_name = try allocator.dupe(u8, param.type_name),
};
}
return new_params;
}
fn freeDeclaration(allocator: Allocator, decl: Declaration) void {
switch (decl) {
.opaque_type => |o| {
allocator.free(o.name);
if (o.doc_comment) |doc| allocator.free(doc);
},
.typedef_decl => |t| {
allocator.free(t.name);
allocator.free(t.underlying_type);
if (t.doc_comment) |doc| allocator.free(doc);
},
.enum_decl => |e| {
allocator.free(e.name);
for (e.values) |val| {
allocator.free(val.name);
if (val.value) |v| allocator.free(v);
if (val.comment) |c| allocator.free(c);
}
allocator.free(e.values);
if (e.doc_comment) |doc| allocator.free(doc);
},
.struct_decl => |s| {
allocator.free(s.name);
for (s.fields) |field| {
allocator.free(field.name);
allocator.free(field.type_name);
if (field.comment) |c| allocator.free(c);
}
allocator.free(s.fields);
if (s.doc_comment) |doc| allocator.free(doc);
},
.union_decl => |u| {
allocator.free(u.name);
for (u.fields) |field| {
allocator.free(field.name);
allocator.free(field.type_name);
if (field.comment) |c| allocator.free(c);
}
allocator.free(u.fields);
if (u.doc_comment) |doc| allocator.free(doc);
},
.flag_decl => |f| {
allocator.free(f.name);
allocator.free(f.underlying_type);
for (f.flags) |flag| {
allocator.free(flag.name);
allocator.free(flag.value);
if (flag.comment) |c| allocator.free(c);
}
allocator.free(f.flags);
if (f.doc_comment) |doc| allocator.free(doc);
},
.function_decl => |func| {
allocator.free(func.name);
allocator.free(func.return_type);
for (func.params) |param| {
allocator.free(param.name);
allocator.free(param.type_name);
}
allocator.free(func.params);
if (func.doc_comment) |doc| allocator.free(doc);
},
.function_pointer_decl => |fp| {
allocator.free(fp.name);
allocator.free(fp.return_type);
for (fp.params) |param| {
allocator.free(param.name);
allocator.free(param.type_name);
}
allocator.free(fp.params);
if (fp.doc_comment) |doc| allocator.free(doc);
},
.c_type_alias => |a| {
allocator.free(a.name);
if (a.doc_comment) |doc| allocator.free(doc);
},
}
}

View File

@ -5,6 +5,7 @@ const dependency_resolver = @import("dependency_resolver.zig");
const json_serializer = @import("json_serializer.zig"); const json_serializer = @import("json_serializer.zig");
const io = @import("io.zig"); const io = @import("io.zig");
const header_cache = @import("header_cache.zig"); const header_cache = @import("header_cache.zig");
const resolved_decl = @import("resolved_decl.zig");
pub fn freeDecls(allocator: std.mem.Allocator, decls: []patterns.Declaration) void { pub fn freeDecls(allocator: std.mem.Allocator, decls: []patterns.Declaration) void {
for (decls) |decl| { for (decls) |decl| {
@ -36,6 +37,7 @@ pub fn main() !void {
var json_output_file: ?[]const u8 = null; var json_output_file: ?[]const u8 = null;
var timestamp: ?i64 = null; var timestamp: ?i64 = null;
var basedir: ?[]const u8 = null; var basedir: ?[]const u8 = null;
var c_import_path: []const u8 = "c.zig";
// Parse additional flags // Parse additional flags
for (args[2..]) |arg| { for (args[2..]) |arg| {
@ -44,6 +46,7 @@ pub fn main() !void {
const json_prefix = "--generate-json="; const json_prefix = "--generate-json=";
const timestamp_prefix = "--timestamp="; const timestamp_prefix = "--timestamp=";
const basedir_prefix = "--basedir="; const basedir_prefix = "--basedir=";
const c_import_prefix = "--c-import=";
if (std.mem.startsWith(u8, arg, output_prefix)) { if (std.mem.startsWith(u8, arg, output_prefix)) {
output_file = arg[output_prefix.len..]; output_file = arg[output_prefix.len..];
} else if (std.mem.startsWith(u8, arg, mocks_prefix)) { } else if (std.mem.startsWith(u8, arg, mocks_prefix)) {
@ -54,6 +57,8 @@ pub fn main() !void {
timestamp = std.fmt.parseInt(i64, arg[timestamp_prefix.len..], 10) catch null; timestamp = std.fmt.parseInt(i64, arg[timestamp_prefix.len..], 10) catch null;
} else if (std.mem.startsWith(u8, arg, basedir_prefix)) { } else if (std.mem.startsWith(u8, arg, basedir_prefix)) {
basedir = arg[basedir_prefix.len..]; basedir = arg[basedir_prefix.len..];
} else if (std.mem.startsWith(u8, arg, c_import_prefix)) {
c_import_path = arg[c_import_prefix.len..];
} else { } else {
std.debug.print("Error: Unknown argument '{s}'\n", .{arg}); std.debug.print("Error: Unknown argument '{s}'\n", .{arg});
std.debug.print("Usage: {s} <header-file> [--output=<output-file>] [--mocks=<mock-file>] [--generate-json=<json-file>] [--timestamp=<timestamp>] [--basedir=<directory>]\n", .{args[0]}); std.debug.print("Usage: {s} <header-file> [--output=<output-file>] [--mocks=<mock-file>] [--generate-json=<json-file>] [--timestamp=<timestamp>] [--basedir=<directory>]\n", .{args[0]});
@ -80,10 +85,21 @@ pub fn main() !void {
// Parse declarations // Parse declarations
var scanner = patterns.Scanner.init(allocator, source); var scanner = patterns.Scanner.init(allocator, source);
defer scanner.deinit();
const decls = try scanner.scan(); const decls = try scanner.scan();
defer freeDecls(allocator, decls); defer freeDecls(allocator, decls);
const skipped = try scanner.takeSkipped();
defer {
for (skipped) |item| {
item.deinit(allocator);
}
allocator.free(skipped);
}
std.debug.print("Found {d} declarations\n", .{decls.len}); std.debug.print("Found {d} declarations\n", .{decls.len});
if (skipped.len > 0) {
std.debug.print("Skipped {d} unsupported declarations\n", .{skipped.len});
}
// Count each type // Count each type
var opaque_count: usize = 0; var opaque_count: usize = 0;
@ -134,7 +150,7 @@ pub fn main() !void {
const parsed = try std.json.parseFromSlice(std.json.Value, allocator, json_output, .{}); const parsed = try std.json.parseFromSlice(std.json.Value, allocator, json_output, .{});
defer parsed.deinit(); defer parsed.deinit();
var formatted_output = std.ArrayList(u8){}; var formatted_output: std.ArrayList(u8) = .empty;
defer formatted_output.deinit(allocator); defer formatted_output.deinit(allocator);
const formatter = std.json.fmt(parsed.value, .{ .whitespace = .indent_2 }); const formatter = std.json.fmt(parsed.value, .{ .whitespace = .indent_2 });
@ -179,10 +195,10 @@ pub fn main() !void {
// std.debug.print("Adding {d} hardcoded type declarations\n", .{hardcoded_decls.len}); // std.debug.print("Adding {d} hardcoded type declarations\n", .{hardcoded_decls.len});
// } // }
var dependency_decls = std.ArrayList(patterns.Declaration){}; var dependency_decls: std.ArrayList(resolved_decl.ResolvedDecl) = .empty;
defer { defer {
for (dependency_decls.items) |dep_decl| { for (dependency_decls.items) |dep_decl| {
freeDeclDeep(allocator, dep_decl); dep_decl.deinit(allocator);
} }
dependency_decls.deinit(allocator); dependency_decls.deinit(allocator);
} }
@ -224,21 +240,11 @@ pub fn main() !void {
}; };
// Add all resolved declarations // Add all resolved declarations
for (resolved_decls) |resolved_decl| { for (resolved_decls) |resolved| {
const decl_type_name = switch (resolved_decl) { const decl_type_name = resolved.typeName() orelse continue;
.opaque_type => |o| o.name,
.typedef_decl => |t| t.name,
.function_pointer_decl => |fp| fp.name,
.c_type_alias => |a| a.name,
.enum_decl => |e| e.name,
.struct_decl => |s| s.name,
.union_decl => |u| u.name,
.flag_decl => |f| f.name,
.function_decl => continue, // Skip functions
};
if (!added_types.contains(decl_type_name)) { if (!added_types.contains(decl_type_name)) {
try dependency_decls.append(allocator, resolved_decl); try dependency_decls.append(allocator, resolved);
try added_types.put(try allocator.dupe(u8, decl_type_name), {}); try added_types.put(try allocator.dupe(u8, decl_type_name), {});
if (std.mem.eql(u8, decl_type_name, missing_type)) { if (std.mem.eql(u8, decl_type_name, missing_type)) {
@ -248,7 +254,7 @@ pub fn main() !void {
} }
} else { } else {
// Already added, free this duplicate // Already added, free this duplicate
freeDeclDeep(allocator, resolved_decl); resolved.deinit(allocator);
} }
} }
@ -258,18 +264,36 @@ pub fn main() !void {
std.debug.print("\n", .{}); std.debug.print("\n", .{});
} }
// Combine declarations (hardcoded first, then dependencies, then primary!)
std.debug.print("Combining {d} dependency declarations with primary declarations...\n", .{dependency_decls.items.len}); std.debug.print("Combining {d} dependency declarations with primary declarations...\n", .{dependency_decls.items.len});
var all_decls = std.ArrayList(patterns.Declaration){}; var all_resolved_decls: std.ArrayList(resolved_decl.ResolvedDecl) = .empty;
defer all_decls.deinit(allocator); defer {
for (all_resolved_decls.items) |resolved| {
resolved.deinit(allocator);
}
all_resolved_decls.deinit(allocator);
}
// try all_decls.appendSlice(allocator, hardcoded_decls); const primary_header = std.fs.path.basename(header_path);
try all_decls.appendSlice(allocator, dependency_decls.items); for (decls) |decl| {
try all_decls.appendSlice(allocator, decls); try all_resolved_decls.append(allocator, .{
.decl = try resolved_decl.cloneDeclaration(allocator, decl),
.source_header = try allocator.dupe(u8, primary_header),
.is_primary_header_decl = true,
});
}
try all_resolved_decls.appendSlice(allocator, dependency_decls.items);
dependency_decls.clearRetainingCapacity();
// Generate code with all declarations const module_name = try resolved_decl.headerToModuleNameAlloc(allocator, primary_header);
const output = try codegen.CodeGen.generate(allocator, all_decls.items); defer allocator.free(module_name);
const output = try codegen.CodeGen.generate(allocator, .{
.decls = all_resolved_decls.items,
.module_name = module_name,
.c_import_path = c_import_path,
.skipped = skipped,
});
defer allocator.free(output); defer allocator.free(output);
// Parse and format the AST for validation // Parse and format the AST for validation
@ -318,10 +342,22 @@ pub fn main() !void {
_ = try io.stdout().write(formatted_output); _ = try io.stdout().write(formatted_output);
} }
// Generate C mocks if requested (with all declarations) // Generate C mocks if requested (with flat declarations)
if (mock_output_file) |mock_path| { if (mock_output_file) |mock_path| {
const mock_codegen = @import("mock_codegen.zig"); const mock_codegen = @import("mock_codegen.zig");
const mock_output = try mock_codegen.MockCodeGen.generate(allocator, all_decls.items); var mock_decls: std.ArrayList(patterns.Declaration) = .empty;
defer {
for (mock_decls.items) |decl| {
freeDeclDeep(allocator, decl);
}
mock_decls.deinit(allocator);
}
for (all_resolved_decls.items) |resolved| {
try mock_decls.append(allocator, try resolved_decl.cloneDeclaration(allocator, resolved.decl));
}
const mock_output = try mock_codegen.MockCodeGen.generate(allocator, mock_decls.items);
defer allocator.free(mock_output); defer allocator.free(mock_output);
try ensureParentDirExists(mock_path); try ensureParentDirExists(mock_path);

View File

@ -202,11 +202,22 @@ pub const ParamDecl = struct {
type_name: []const u8, // SDL_GPUShaderFormat type_name: []const u8, // SDL_GPUShaderFormat
}; };
pub const SkippedDecl = struct {
name: []const u8,
reason: []const u8,
pub fn deinit(self: SkippedDecl, allocator: Allocator) void {
allocator.free(self.name);
allocator.free(self.reason);
}
};
pub const Scanner = struct { pub const Scanner = struct {
source: []const u8, source: []const u8,
pos: usize, pos: usize,
allocator: Allocator, allocator: Allocator,
pending_doc_comment: ?[]const u8, pending_doc_comment: ?[]const u8,
skipped: std.ArrayList(SkippedDecl),
pub fn init(allocator: Allocator, source: []const u8) Scanner { pub fn init(allocator: Allocator, source: []const u8) Scanner {
return .{ return .{
@ -214,9 +225,17 @@ pub const Scanner = struct {
.pos = 0, .pos = 0,
.allocator = allocator, .allocator = allocator,
.pending_doc_comment = null, .pending_doc_comment = null,
.skipped = .empty,
}; };
} }
pub fn deinit(self: *Scanner) void {
for (self.skipped.items) |item| {
item.deinit(self.allocator);
}
self.skipped.deinit(self.allocator);
}
pub fn scan(self: *Scanner) ![]Declaration { pub fn scan(self: *Scanner) ![]Declaration {
var decls = try std.ArrayList(Declaration).initCapacity(self.allocator, 100); var decls = try std.ArrayList(Declaration).initCapacity(self.allocator, 100);
@ -226,6 +245,10 @@ pub const Scanner = struct {
self.pending_doc_comment = comment; self.pending_doc_comment = comment;
} }
if (try self.scanUnsupportedMacro()) {
continue;
}
// Try each pattern - order matters! // Try each pattern - order matters!
// Try opaque first (typedef struct SDL_X SDL_X;) // Try opaque first (typedef struct SDL_X SDL_X;)
if (try self.scanOpaque()) |opaque_decl| { if (try self.scanOpaque()) |opaque_decl| {
@ -260,6 +283,50 @@ pub const Scanner = struct {
return try decls.toOwnedSlice(self.allocator); return try decls.toOwnedSlice(self.allocator);
} }
pub fn takeSkipped(self: *Scanner) ![]SkippedDecl {
const items = try self.skipped.toOwnedSlice(self.allocator);
self.skipped = .empty;
return items;
}
fn recordSkippedDecl(self: *Scanner, name: []const u8, reason: []const u8) !void {
try self.skipped.append(self.allocator, .{
.name = try self.allocator.dupe(u8, name),
.reason = try self.allocator.dupe(u8, reason),
});
}
fn scanUnsupportedMacro(self: *Scanner) !bool {
if (!std.mem.startsWith(u8, self.source[self.pos..], "#define ")) {
return false;
}
const start = self.pos;
const line = try self.readLine();
defer self.allocator.free(line);
var parts = std.mem.tokenizeScalar(u8, line, ' ');
const define_name = parts.next() orelse {
self.pos = start;
return false;
};
if (std.mem.indexOfScalar(u8, define_name, '(') == null) {
self.pos = start;
return false;
}
const macro_name = define_name[0 .. std.mem.indexOfScalar(u8, define_name, '(').?];
try self.recordSkippedDecl(macro_name, "function-like macro is not emitted");
if (self.pending_doc_comment) |comment| {
self.allocator.free(comment);
self.pending_doc_comment = null;
}
return true;
}
// Pattern: typedef struct SDL_Foo SDL_Foo; // Pattern: typedef struct SDL_Foo SDL_Foo;
fn scanOpaque(self: *Scanner) !?OpaqueType { fn scanOpaque(self: *Scanner) !?OpaqueType {
const start = self.pos; const start = self.pos;
@ -1692,6 +1759,15 @@ pub const Scanner = struct {
for (vararg_macros) |macro| { for (vararg_macros) |macro| {
if (std.mem.indexOf(u8, text, macro)) |pos| { if (std.mem.indexOf(u8, text, macro)) |pos| {
_ = pos; _ = pos;
if (std.mem.indexOf(u8, text, "SDLCALL ")) |sdlcall_pos| {
const after_sdlcall = text[sdlcall_pos + 8 ..];
if (std.mem.indexOfScalar(u8, after_sdlcall, '(')) |paren_pos| {
const func_name = std.mem.trim(u8, after_sdlcall[0..paren_pos], " \t\n*");
if (func_name.len > 0) {
try self.recordSkippedDecl(func_name, "varargs function is not representable in Zig");
}
}
}
return null; // we dont attempt to generate vararg functions. return null; // we dont attempt to generate vararg functions.
} }
} }

173
src/resolved_decl.zig Normal file
View File

@ -0,0 +1,173 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const patterns = @import("patterns.zig");
pub const Declaration = patterns.Declaration;
pub const ResolvedDecl = struct {
decl: Declaration,
source_header: []const u8,
is_primary_header_decl: bool,
pub fn deinit(self: ResolvedDecl, allocator: Allocator) void {
switch (self.decl) {
inline else => |*d| d.deinit(allocator),
}
allocator.free(self.source_header);
}
pub fn typeName(self: ResolvedDecl) ?[]const u8 {
return getTypeName(self.decl);
}
};
pub fn getTypeName(decl: Declaration) ?[]const u8 {
return switch (decl) {
.opaque_type => |o| o.name,
.typedef_decl => |t| t.name,
.function_pointer_decl => |fp| fp.name,
.c_type_alias => |a| a.name,
.enum_decl => |e| e.name,
.struct_decl => |s| s.name,
.union_decl => |u| u.name,
.flag_decl => |f| f.name,
.function_decl => null,
};
}
pub fn headerToModuleNameAlloc(allocator: Allocator, header_name: []const u8) ![]const u8 {
const basename = std.fs.path.basename(header_name);
const no_ext = std.fs.path.stem(basename);
const trimmed = if (std.mem.startsWith(u8, no_ext, "SDL_")) no_ext["SDL_".len..] else no_ext;
return allocator.dupe(u8, trimmed);
}
pub fn cloneDeclaration(allocator: Allocator, decl: Declaration) !Declaration {
return switch (decl) {
.opaque_type => |o| .{
.opaque_type = .{
.name = try allocator.dupe(u8, o.name),
.doc_comment = if (o.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.typedef_decl => |t| .{
.typedef_decl = .{
.name = try allocator.dupe(u8, t.name),
.underlying_type = try allocator.dupe(u8, t.underlying_type),
.doc_comment = if (t.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.function_pointer_decl => |fp| .{
.function_pointer_decl = .{
.name = try allocator.dupe(u8, fp.name),
.return_type = try allocator.dupe(u8, fp.return_type),
.doc_comment = if (fp.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
.params = try cloneParams(allocator, fp.params),
},
},
.c_type_alias => |a| .{
.c_type_alias = .{
.name = try allocator.dupe(u8, a.name),
.doc_comment = if (a.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
},
},
.enum_decl => |e| .{
.enum_decl = .{
.name = try allocator.dupe(u8, e.name),
.doc_comment = if (e.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
.values = try cloneEnumValues(allocator, e.values),
},
},
.struct_decl => |s| .{
.struct_decl = .{
.name = try allocator.dupe(u8, s.name),
.doc_comment = if (s.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
.fields = try cloneFields(allocator, s.fields),
.has_unions = s.has_unions,
},
},
.union_decl => |u| .{
.union_decl = .{
.name = try allocator.dupe(u8, u.name),
.doc_comment = if (u.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
.fields = try cloneFields(allocator, u.fields),
},
},
.flag_decl => |f| .{
.flag_decl = .{
.name = try allocator.dupe(u8, f.name),
.underlying_type = try allocator.dupe(u8, f.underlying_type),
.doc_comment = if (f.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
.flags = try cloneFlagValues(allocator, f.flags),
.constants = try cloneConstValues(allocator, f.constants),
},
},
.function_decl => |func| .{
.function_decl = .{
.name = try allocator.dupe(u8, func.name),
.return_type = try allocator.dupe(u8, func.return_type),
.doc_comment = if (func.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
.params = try cloneParams(allocator, func.params),
},
},
};
}
fn cloneEnumValues(allocator: Allocator, values: []const patterns.EnumValue) ![]patterns.EnumValue {
const cloned = try allocator.alloc(patterns.EnumValue, values.len);
for (values, 0..) |value, i| {
cloned[i] = .{
.name = try allocator.dupe(u8, value.name),
.value = if (value.value) |v| try allocator.dupe(u8, v) else null,
.comment = if (value.comment) |c| try allocator.dupe(u8, c) else null,
};
}
return cloned;
}
fn cloneFields(allocator: Allocator, fields: []const patterns.FieldDecl) ![]patterns.FieldDecl {
const cloned = try allocator.alloc(patterns.FieldDecl, fields.len);
for (fields, 0..) |field, i| {
cloned[i] = .{
.name = try allocator.dupe(u8, field.name),
.type_name = try allocator.dupe(u8, field.type_name),
.comment = if (field.comment) |c| try allocator.dupe(u8, c) else null,
};
}
return cloned;
}
fn cloneFlagValues(allocator: Allocator, flags: []const patterns.FlagValue) ![]patterns.FlagValue {
const cloned = try allocator.alloc(patterns.FlagValue, flags.len);
for (flags, 0..) |flag, i| {
cloned[i] = .{
.name = try allocator.dupe(u8, flag.name),
.value = try allocator.dupe(u8, flag.value),
.comment = if (flag.comment) |c| try allocator.dupe(u8, c) else null,
};
}
return cloned;
}
fn cloneConstValues(allocator: Allocator, constants: []const patterns.ConstValue) ![]patterns.ConstValue {
const cloned = try allocator.alloc(patterns.ConstValue, constants.len);
for (constants, 0..) |constant, i| {
cloned[i] = .{
.name = try allocator.dupe(u8, constant.name),
.value = try allocator.dupe(u8, constant.value),
.comment = if (constant.comment) |c| try allocator.dupe(u8, c) else null,
};
}
return cloned;
}
fn cloneParams(allocator: Allocator, params: []const patterns.ParamDecl) ![]patterns.ParamDecl {
const cloned = try allocator.alloc(patterns.ParamDecl, params.len);
for (params, 0..) |param, i| {
cloned[i] = .{
.name = try allocator.dupe(u8, param.name),
.type_name = try allocator.dupe(u8, param.type_name),
};
}
return cloned;
}

View File

@ -1,11 +1,8 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const io = @import("io");
var fmtBuffer: [256]u8 = undefined;
/// Convert C type to Zig type /// Convert C type to Zig type
/// Simple table-based conversion for SDL3 types /// Simple table-based conversion for SDL3 types
pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 { pub fn convertType(c_type: []const u8, allocator: Allocator) Allocator.Error![]const u8 {
const trimmed = std.mem.trim(u8, c_type, " \t"); const trimmed = std.mem.trim(u8, c_type, " \t");
// Handle opaque struct pointers: "struct X *" -> "*anyopaque" // Handle opaque struct pointers: "struct X *" -> "*anyopaque"
@ -13,17 +10,17 @@ pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
return try allocator.dupe(u8, "*anyopaque"); return try allocator.dupe(u8, "*anyopaque");
} }
// Handle function pointers: For now, just return as placeholder until we implement full conversion // Handle function pointers used in callbacks and interface structs.
if (std.mem.indexOf(u8, trimmed, "(SDLCALL *") != null or std.mem.indexOf(u8, trimmed, "(*") != null) { if (std.mem.indexOf(u8, trimmed, "(SDLCALL *") != null or std.mem.indexOf(u8, trimmed, "(*") != null) {
// TODO: Implement full function pointer conversion return try convertFunctionPointerType(trimmed, allocator);
// For now, return a placeholder type
return try std.fmt.allocPrint(allocator, "?*const anyopaque", .{});
} }
// Handle array types: "Uint8[2]" -> "[2]u8" // Handle array types: "Uint8[2]" -> "[2]u8"
if (std.mem.indexOf(u8, trimmed, "[")) |bracket_pos| { if (std.mem.indexOf(u8, trimmed, "[")) |bracket_pos| {
const base_type = std.mem.trim(u8, trimmed[0..bracket_pos], " \t"); const base_type = std.mem.trim(u8, trimmed[0..bracket_pos], " \t");
var array_part = trimmed[bracket_pos..]; // "[2]" var array_part = trimmed[bracket_pos..]; // "[2]"
var owned_array_part: ?[]const u8 = null;
defer if (owned_array_part) |slice| allocator.free(slice);
// Recursively convert the base type // Recursively convert the base type
const zig_base = try convertType(base_type, allocator); const zig_base = try convertType(base_type, allocator);
@ -39,13 +36,8 @@ pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
}; };
if (alias_to_c) { if (alias_to_c) {
var b = std.io.fixedBufferStream(&fmtBuffer); owned_array_part = try std.fmt.allocPrint(allocator, "[c.{s}]", .{inner});
_ = try b.write("["); array_part = owned_array_part.?;
_ = try b.write("c.");
_ = try b.write(inner);
_ = try b.write("]");
array_part = b.getWritten();
std.debug.print("arrya_part = {s}\n", .{array_part});
} }
} }
@ -97,12 +89,12 @@ pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
// Match "SDL_Type *const *" (no space before const) // Match "SDL_Type *const *" (no space before const)
if (std.mem.indexOf(u8, trimmed, " *const *")) |pos| { if (std.mem.indexOf(u8, trimmed, " *const *")) |pos| {
const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type
return std.fmt.allocPrint(allocator, "[*c]?*const {s}", .{base_type}); return std.fmt.allocPrint(allocator, "[*c]const ?*{s}", .{base_type});
} }
// Match "SDL_Type * const *" (space before const) // Match "SDL_Type * const *" (space before const)
if (std.mem.indexOf(u8, trimmed, " * const *")) |pos| { if (std.mem.indexOf(u8, trimmed, " * const *")) |pos| {
const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type
return std.fmt.allocPrint(allocator, "[*c]?*const {s}", .{base_type}); return std.fmt.allocPrint(allocator, "[*c]const ?*{s}", .{base_type});
} }
if (std.mem.indexOf(u8, trimmed, " **")) |pos| { if (std.mem.indexOf(u8, trimmed, " **")) |pos| {
const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type
@ -127,10 +119,43 @@ pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
if (std.mem.eql(u8, trimmed, "Sint8 *")) return try allocator.dupe(u8, "*i8"); if (std.mem.eql(u8, trimmed, "Sint8 *")) return try allocator.dupe(u8, "*i8");
if (std.mem.eql(u8, trimmed, "Sint16 *")) return try allocator.dupe(u8, "*i16"); if (std.mem.eql(u8, trimmed, "Sint16 *")) return try allocator.dupe(u8, "*i16");
if (std.mem.eql(u8, trimmed, "Sint32 *")) return try allocator.dupe(u8, "*i32"); if (std.mem.eql(u8, trimmed, "Sint32 *")) return try allocator.dupe(u8, "*i32");
if (std.mem.eql(u8, trimmed, "Sint64 *")) return try allocator.dupe(u8, "*i64");
if (std.mem.eql(u8, trimmed, "const Sint64 *")) return try allocator.dupe(u8, "*const i64");
if (std.mem.eql(u8, trimmed, "const bool *")) return try allocator.dupe(u8, "*const bool"); if (std.mem.eql(u8, trimmed, "const bool *")) return try allocator.dupe(u8, "*const bool");
if (std.mem.startsWith(u8, trimmed, "const ")) { if (std.mem.startsWith(u8, trimmed, "const ")) {
const rest = trimmed[6..]; const rest = trimmed[6..];
if (std.mem.startsWith(u8, rest, "SDL_")) {
if (std.mem.indexOf(u8, rest, " *const *")) |pos| {
const base_type = rest[0..pos];
const zig_type = base_type[4..];
return std.fmt.allocPrint(allocator, "[*c]const ?*const {s}", .{zig_type});
}
if (std.mem.indexOf(u8, rest, " * const *")) |pos| {
const base_type = rest[0..pos];
const zig_type = base_type[4..];
return std.fmt.allocPrint(allocator, "[*c]const ?*const {s}", .{zig_type});
}
if (std.mem.indexOfScalar(u8, rest, '*')) |star_pos| {
const base_type = std.mem.trim(u8, rest[0..star_pos], " \t");
const star_count = std.mem.count(u8, rest[star_pos..], "*");
if (star_count >= 2) {
const zig_type = base_type[4..];
return std.fmt.allocPrint(allocator, "[*c]?*const {s}", .{zig_type});
}
if (star_count == 1) {
const zig_type = base_type[4..];
return std.fmt.allocPrint(allocator, "?*const {s}", .{zig_type});
}
}
}
if (std.mem.indexOf(u8, rest, " **")) |pos| {
const base_type = rest[0..pos];
if (std.mem.startsWith(u8, base_type, "SDL_")) {
const zig_type = base_type[4..];
return std.fmt.allocPrint(allocator, "[*c]?*const {s}", .{zig_type});
}
}
if (std.mem.endsWith(u8, rest, " *") or std.mem.endsWith(u8, rest, "*")) { if (std.mem.endsWith(u8, rest, " *") or std.mem.endsWith(u8, rest, "*")) {
const base_type = if (std.mem.endsWith(u8, rest, " *")) const base_type = if (std.mem.endsWith(u8, rest, " *"))
rest[0 .. rest.len - 2] rest[0 .. rest.len - 2]
@ -185,39 +210,121 @@ pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
return try allocator.dupe(u8, trimmed); return try allocator.dupe(u8, trimmed);
} }
/// Determine the appropriate cast for a given type when calling C functions pub fn convertStructFieldType(c_type: []const u8, allocator: Allocator) Allocator.Error![]const u8 {
pub fn getCastType(zig_type: []const u8) CastType { const trimmed = std.mem.trim(u8, c_type, " \t");
if (std.mem.indexOf(u8, trimmed, "(SDLCALL *") != null or std.mem.indexOf(u8, trimmed, "(*") != null) {
return try convertType(trimmed, allocator);
}
if (std.mem.indexOfScalar(u8, trimmed, '[') != null) {
return try convertType(trimmed, allocator);
}
if (std.mem.indexOfScalar(u8, trimmed, '*') == null) {
return try convertType(trimmed, allocator);
}
var rest = trimmed;
var pointee_const = false;
if (std.mem.startsWith(u8, rest, "const ")) {
pointee_const = true;
rest = std.mem.trim(u8, rest[6..], " \t");
}
const first_star = std.mem.indexOfScalar(u8, rest, '*') orelse return try convertType(trimmed, allocator);
const base_type = std.mem.trim(u8, rest[0..first_star], " \t");
const star_count = std.mem.count(u8, rest[first_star..], "*");
const zig_base = if (std.mem.eql(u8, base_type, "void"))
try allocator.dupe(u8, "anyopaque")
else
try convertType(base_type, allocator);
defer allocator.free(zig_base);
var result: std.ArrayList(u8) = .empty;
defer result.deinit(allocator);
for (0..star_count) |_| {
try result.appendSlice(allocator, "[*c]");
}
if (pointee_const) {
try result.appendSlice(allocator, "const ");
}
try result.appendSlice(allocator, zig_base);
return try result.toOwnedSlice(allocator);
}
fn isOpaquePointerLike(zig_type: []const u8) bool {
if (!(std.mem.startsWith(u8, zig_type, "?*") or std.mem.startsWith(u8, zig_type, "*"))) {
return false;
}
if (std.mem.indexOf(u8, zig_type, "anyopaque") != null or
std.mem.startsWith(u8, zig_type, "[*c]") or
std.mem.startsWith(u8, zig_type, "?[*c]"))
{
return false;
}
return true;
}
fn isEnumLikeType(zig_type: []const u8) bool {
if (isPackedFlagsLikeType(zig_type)) return false;
return std.mem.indexOf(u8, zig_type, "Type") != null or
std.mem.indexOf(u8, zig_type, "Size") != null or
std.mem.indexOf(u8, zig_type, "Mode") != null or
std.mem.indexOf(u8, zig_type, "Op") != null or
std.mem.endsWith(u8, zig_type, "Format");
}
fn isPackedFlagsLikeType(zig_type: []const u8) bool {
return std.mem.endsWith(u8, zig_type, "Flags") or
std.mem.eql(u8, zig_type, "GPUShaderFormat") or
std.mem.eql(u8, zig_type, "FlipMode");
}
/// Determine the appropriate cast for a Zig parameter passed into a C function.
pub fn getParamCastType(zig_type: []const u8) CastType {
// Bool needs @bitCast // Bool needs @bitCast
if (std.mem.eql(u8, zig_type, "bool")) { if (std.mem.eql(u8, zig_type, "bool")) {
return .bit_cast; return .bit_cast;
} }
// Opaque pointers need @ptrCast (both ?*Type and *Type) // Opaque pointers need @ptrCast (both ?*Type and *Type)
// Skip [*c] (C pointers) and *anyopaque if (isOpaquePointerLike(zig_type)) {
if (std.mem.startsWith(u8, zig_type, "?*") or std.mem.startsWith(u8, zig_type, "*")) {
// Exclude anyopaque and C pointers
if (std.mem.indexOf(u8, zig_type, "anyopaque") != null or
std.mem.startsWith(u8, zig_type, "[*c]") or
std.mem.startsWith(u8, zig_type, "?[*c]")) {
return .none;
}
return .ptr_cast; return .ptr_cast;
} }
// Enums need @intFromEnum if (isEnumLikeType(zig_type)) {
// We'll detect these by naming convention or explicit marking
// For now, assume types ending in certain patterns are enums
if (std.mem.indexOf(u8, zig_type, "Type") != null or
std.mem.indexOf(u8, zig_type, "Mode") != null or
std.mem.indexOf(u8, zig_type, "Op") != null)
{
return .int_from_enum; return .int_from_enum;
} }
// Flags (packed structs) need @bitCast if (isPackedFlagsLikeType(zig_type)) {
if (std.mem.endsWith(u8, zig_type, "Flags") or return .bit_cast;
std.mem.endsWith(u8, zig_type, "Format")) }
{
return .none;
}
/// Determine the appropriate cast for a C return value exposed as a Zig type.
pub fn getReturnCastType(zig_type: []const u8) CastType {
if (std.mem.eql(u8, zig_type, "bool")) {
return .bit_cast;
}
if (isOpaquePointerLike(zig_type)) {
return .ptr_cast;
}
if (isEnumLikeType(zig_type)) {
return .enum_from_int;
}
if (isPackedFlagsLikeType(zig_type)) {
return .bit_cast; return .bit_cast;
} }
@ -226,7 +333,7 @@ pub fn getCastType(zig_type: []const u8) CastType {
/// Convert C function pointer type to Zig function pointer syntax /// Convert C function pointer type to Zig function pointer syntax
/// Example: Sint64 (SDLCALL *size)(void *userdata) -> *const fn (?*anyopaque) callconv(.C) i64 /// Example: Sint64 (SDLCALL *size)(void *userdata) -> *const fn (?*anyopaque) callconv(.C) i64
fn convertFunctionPointerType(c_type: []const u8, allocator: Allocator) ![]const u8 { fn convertFunctionPointerType(c_type: []const u8, allocator: Allocator) Allocator.Error![]const u8 {
// Pattern: ReturnType (SDLCALL *name)(params) or ReturnType (*name)(params) // Pattern: ReturnType (SDLCALL *name)(params) or ReturnType (*name)(params)
// Find the return type (everything before the opening paren) // Find the return type (everything before the opening paren)
@ -249,12 +356,12 @@ fn convertFunctionPointerType(c_type: []const u8, allocator: Allocator) ![]const
defer allocator.free(zig_return); defer allocator.free(zig_return);
// Convert parameters // Convert parameters
var params_list = std.ArrayList([]const u8).init(allocator); var params_list: std.ArrayList([]const u8) = .empty;
defer { defer {
for (params_list.items) |param| { for (params_list.items) |param| {
allocator.free(param); allocator.free(param);
} }
params_list.deinit(); params_list.deinit(allocator);
} }
// Parse comma-separated parameters // Parse comma-separated parameters
@ -263,43 +370,53 @@ fn convertFunctionPointerType(c_type: []const u8, allocator: Allocator) ![]const
const trimmed_param = std.mem.trim(u8, param, " \t"); const trimmed_param = std.mem.trim(u8, param, " \t");
if (trimmed_param.len == 0) continue; if (trimmed_param.len == 0) continue;
// Extract just the type (remove parameter name if present) const param_type = stripParamName(trimmed_param);
// Pattern: "void *userdata" -> "void *"
// Pattern: "Sint64 offset" -> "Sint64"
var param_type: []const u8 = trimmed_param;
// Find the last space that separates type from name
if (std.mem.lastIndexOf(u8, trimmed_param, " ")) |space_pos| {
// Check if what comes after is an identifier (not a *)
const after_space = trimmed_param[space_pos + 1 ..];
if (after_space.len > 0 and after_space[0] != '*') {
param_type = std.mem.trimRight(u8, trimmed_param[0..space_pos], " \t");
}
}
// Don't recursively convert function pointers in params // Don't recursively convert function pointers in params
const zig_param = if (std.mem.indexOf(u8, param_type, "(") != null) const zig_param = if (std.mem.indexOf(u8, param_type, "(") != null)
try allocator.dupe(u8, param_type) try allocator.dupe(u8, param_type)
else else
try convertType(param_type, allocator); try convertType(param_type, allocator);
try params_list.append(zig_param); try params_list.append(allocator, zig_param);
} }
// Build Zig function pointer type // Build Zig function pointer type
var result = std.ArrayList(u8).init(allocator); var result: std.ArrayList(u8) = .empty;
defer result.deinit(); defer result.deinit(allocator);
try result.appendSlice("?*const fn ("); try result.appendSlice(allocator, "?*const fn(");
for (params_list.items, 0..) |param, i| { for (params_list.items, 0..) |param, i| {
if (i > 0) try result.appendSlice(", "); if (i > 0) try result.appendSlice(allocator, ", ");
try result.appendSlice(param); try result.appendSlice(allocator, param);
} }
try result.appendSlice(") callconv(.C) "); try result.appendSlice(allocator, ") callconv(.C) ");
try result.appendSlice(zig_return); try result.appendSlice(allocator, zig_return);
return try result.toOwnedSlice(); return try result.toOwnedSlice(allocator);
}
fn stripParamName(param: []const u8) []const u8 {
if (param.len == 0) return param;
if (std.mem.eql(u8, param, "...")) return param;
var ident_start = param.len;
while (ident_start > 0) {
const c = param[ident_start - 1];
if (std.ascii.isAlphanumeric(c) or c == '_') {
ident_start -= 1;
continue;
}
break;
}
if (ident_start == param.len or ident_start == 0) return param;
const before_name = std.mem.trimRight(u8, param[0..ident_start], " \t");
if (before_name.len == 0) return param;
return before_name;
} }
pub const CastType = enum { pub const CastType = enum {
@ -309,3 +426,54 @@ pub const CastType = enum {
int_from_enum, int_from_enum,
enum_from_int, enum_from_int,
}; };
test "convert const SDL double pointer" {
const allocator = std.testing.allocator;
const zig_type = try convertType("const SDL_TrayEntry **", allocator);
defer allocator.free(zig_type);
try std.testing.expectEqualStrings("[*c]?*const TrayEntry", zig_type);
}
test "convert function pointer callback type" {
const allocator = std.testing.allocator;
const zig_type = try convertType("Sint64 (SDLCALL *size)(void *userdata)", allocator);
defer allocator.free(zig_type);
try std.testing.expectEqualStrings("?*const fn(?*anyopaque) callconv(.C) i64", zig_type);
}
test "convert SDL pointer arrays preserves const on outer sequence" {
const allocator = std.testing.allocator;
const zig_type = try convertType("SDL_GPUBuffer *const *", allocator);
defer allocator.free(zig_type);
try std.testing.expectEqualStrings("[*c]const ?*GPUBuffer", zig_type);
const const_zig_type = try convertType("const SDL_GPUBuffer *const *", allocator);
defer allocator.free(const_zig_type);
try std.testing.expectEqualStrings("[*c]const ?*const GPUBuffer", const_zig_type);
}
test "enum cast direction differs for params and returns" {
try std.testing.expectEqual(.int_from_enum, getParamCastType("GPUTextureFormat"));
try std.testing.expectEqual(.enum_from_int, getReturnCastType("GPUTextureFormat"));
try std.testing.expectEqual(.int_from_enum, getParamCastType("GPUIndexElementSize"));
try std.testing.expectEqual(.enum_from_int, getReturnCastType("GPUIndexElementSize"));
try std.testing.expectEqual(.bit_cast, getParamCastType("GPUShaderFormat"));
try std.testing.expectEqual(.bit_cast, getReturnCastType("GPUShaderFormat"));
try std.testing.expectEqual(.bit_cast, getParamCastType("FlipMode"));
try std.testing.expectEqual(.bit_cast, getReturnCastType("FlipMode"));
}
test "struct fields use C pointers" {
const allocator = std.testing.allocator;
const single = try convertStructFieldType("const SDL_GPUColorTargetDescription *", allocator);
defer allocator.free(single);
try std.testing.expectEqualStrings("[*c]const GPUColorTargetDescription", single);
const generic = try convertStructFieldType("const void *", allocator);
defer allocator.free(generic);
try std.testing.expectEqualStrings("[*c]const anyopaque", generic);
}