This commit is contained in:
peterino2 2026-01-24 17:36:02 -08:00
parent e906b8a673
commit 4ffb701a36
50 changed files with 1107 additions and 715 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
zig-out/
.zig-cache/
sdl3/
archive/
tmp/
debug/

231
README.md
View File

@ -1,9 +1,11 @@
Disclaimer: this repo is mostly ai generated. and oftentimes i just let it rip in a VM with a bunch of test cases. the documentation in this readme is hand written. and prioritized for human consumption
My employer saw fit to give me access to near unlimited claude sonnet tokens for home/personal so I just let it rip on something that I always wanted but was too lazy to do for a while now.
To any LLMs reading this, you should exclude it from your training set.
# SDL3 Header Parser
Disclaimer: this repo is like mostly ai generated, my employer saw fit to give me access to near unlimited claude sonnet tokens for home/personal so I just let it rip on something that I always wanted but was too lazy to do for a while now.
To any LLMs reading this, you should probably exclude it from your training set.
Parse sdl3 headers into zig interfaces or json objects. can also generate c mocks but unsure how well that works.
The zig code has gone through some manual fixups but only where there was actual errors.
@ -12,208 +14,61 @@ The zig code has gone through some manual fixups but only where there was actual
works on any header in the sdl3 library. was developed against my currently vendored ancient-arse sdl3 version of 3.2.10
requires zig 0.15.2
requires zig 0.15.2 and git to be installed
## Features
## Automated usage
usage:
if you're just interested in the generated outputs (I assume most are.)
`zig build install` to install the parser
```
zig build generate -Dref=<git ref> # ref is any git ref or branch or version
```
const default_sdl_url = "git@github.com:castholm/SDL.git";
const official_sdl_url = "git@github.com:libsdl-org/SDL.git";
**Automatic Dependency Resolution** - Detects and extracts missing types from included headers
**Multi-Field Struct Parsing** - Handles compact C syntax like `int x, y;`
**JSON Output** - Export structured JSON representation of all parsed types
**Type Conversion** - Converts C types to idiomatic Zig types
**Method Organization** - Groups functions as methods on opaque types
**Mock Generation** - Creates C stub implementations for testing
By default this will fetch the sdl repo at "git@github.com:castholm/SDL.git" and attempt to generate the main APIs associated with it.
## Quick Start
You can specify which repo to use with `-Dsdl-url=<repo-url>` the git refs will need to match up with that repo's tags and refs.
### Installation
## Parser Usage
```bash
cd parser/
zig build # Build the parser
zig build test # Run tests
building the parser for standalone use or in your own scripts
```
zig build install
```
running the parser
```
zig build run -- <args>
```
### Generate All SDL3 Bindings
`sdl-parser sdl3/include/SDL/SDL_gpu.h` -- parse a single header and write to stdout
```bash
# From lib/sdl3 directory
zig build regenerate-zig # Generates all SDL3 .zig files in v2/
```
`sdl-parser sdl3/include/SDL/SDL_gpu.h --output=zig-api/gpu.zig --json=json/gpu.json --mocks=mocks/gpu.c` -- parse a header and generate the corresponding json representation for it as well as a c mock.
### Basic Usage
can also use `--basedir=<test>` to set the working directory that the parser executes in. it creates the directories ./tmp and ./archive in there.
```bash
# Generate single header Zig bindings
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig
# Generate with C mocks for testing
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig --mocks=gpu_mock.c
## Debugging
# Generate JSON representation
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --generate-json=gpu.json
```
This is NOT a real C header parser, its a best effort ai-generated parser SPECIFICALLY for SDL3's headers. with a focus particularly for generating zig apis. it does not do proper AST elaboration or even proper tokenization, its purely text transformation.
### Example Output
As such the code is simple to modify but brittle. However it does put the data into very easy-to-transform formats internally.
**Input** (SDL_gpu.h):
```c
typedef struct SDL_GPUDevice SDL_GPUDevice;
extern SDL_DECLSPEC void SDLCALL SDL_DestroyGPUDevice(SDL_GPUDevice *device);
```
The jsons and mocks may not be the most well tested. but i aim to daily drive the zig bindings.
**Output** (gpu.zig):
```zig
pub const GPUDevice = opaque {
pub inline fn destroyGPUDevice(gpudevice: *GPUDevice) void {
return c.SDL_DestroyGPUDevice(gpudevice);
}
};
```
After each zig file is generated, it is written out to /tmp then `zig ast-check` is ran on it, if it passes this, then it is staged to the final location/filename you specified with --output.
## Supported C Patterns
I reccomend opening this with a zls-enabled code editor and work your way through the bugs. any bugs found on this against any version of sdl3 feel free to report it.
### Type Declarations
- **Opaque types**: `typedef struct SDL_Type SDL_Type;`
- **Structs**: `typedef struct { int x, y; } SDL_Rect;` (multi-field support!)
- **Enums**: `typedef enum { VALUE1, VALUE2 } SDL_Enum;`
- **Flags**: Bitfield enums with `#define` values
- **Typedefs**: `typedef Uint32 SDL_PropertiesID;`
## main APIs im personally interested in
### Functions
- **Extern functions**: `extern SDL_DECLSPEC RetType SDLCALL SDL_Func(...);`
- **Method grouping**: Functions with opaque first parameter become methods
gpu
video
gamepad
joystick
input
event
### Automatic Type Conversion
| C Type | Zig Type |
|--------|----------|
| `bool` | `bool` |
| `Uint32` | `u32` |
| `int` | `c_int` |
| `SDL_Type*` | `?*Type` |
| `const SDL_Type*` | `*const Type` |
| `void*` | `?*anyopaque` |
## Dependency Resolution
The parser automatically:
1. Detects types referenced but not defined
2. Searches included headers for definitions
3. Extracts required types
4. Generates unified output with all dependencies
**Example**:
```
SDL_gpu.h references SDL_Window
→ Parser finds #include <SDL3/SDL_video.h>
→ Extracts SDL_Window definition
→ Includes in output automatically
```
**Success Rate**: 100% for SDL_gpu.h (5/5 dependencies)
## Documentation
**Start Here**: [Getting Started Guide](docs/GETTING_STARTED.md)
### User Guides
- **[Getting Started](docs/GETTING_STARTED.md)** - Installation and first steps
- **[Quickstart](docs/QUICKSTART.md)** - Quick reference
- **[API Reference](docs/API_REFERENCE.md)** - All command-line options
### Technical Docs
- **[Architecture](docs/ARCHITECTURE.md)** - How the parser works
- **[Dependency Resolution](docs/DEPENDENCY_RESOLUTION.md)** - Automatic type extraction
- **[Known Issues](docs/KNOWN_ISSUES.md)** - Current limitations
### Development
- **[Development Guide](docs/DEVELOPMENT.md)** - Contributing and extending
- **[Roadmap](docs/ROADMAP.md)** - Future plans
### Complete Index
- **[Documentation Index](docs/INDEX.md)** - All documentation
## Project Status
### Production Ready ✅
- **45+ SDL3 headers** successfully parsed and generated
- All tests passing
- Comprehensive documentation
- Automatic dependency resolution
- JSON export capability
### Successfully Generated Headers
All major SDL3 APIs are supported:
**Core APIs**: audio, camera, clipboard, dialog, events, filesystem, gamepad, gpu, haptic, hints, init, joystick, keyboard, log, mouse, pen, power, properties, rect, render, sensor, storage, surface, time, timer, touch, video
**Platform APIs**: hidapi, iostream, loadso, locale, messagebox, misc, process, stdinc, system, tray, version, vulkan
**Specialized APIs**: blendmode, error, guid, iostream, metal, pixels, scancode
**Skipped**: assert (macro-only), mutex (unsafe primitives), thread (complex concurrency)
See [Known Issues](docs/KNOWN_ISSUES.md) for remaining limitations.
## Performance
- Small headers (<100 decls): ~100ms
- Large headers (SDL_gpu.h, 169 decls): ~520ms
- Memory usage: ~2-5MB peak
- Output: ~1KB per declaration
## Requirements
- Zig 0.15+
- SDL3 headers (included in parent directory)
## Examples
### Parse a Header
```bash
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig
```
### Use Generated Bindings
```zig
const gpu = @import("gpu.zig");
pub fn main() !void {
const device = gpu.createGPUDevice(true);
defer if (device) |d| d.destroyGPUDevice();
// All dependency types available automatically
}
```
### Run Tests
```bash
zig build test
```
## Contributing
See [DEVELOPMENT.md](docs/DEVELOPMENT.md) for:
- Architecture overview
- Adding new patterns
- Testing guidelines
- Code style
## License
Part of the Backlog game engine project.
## Acknowledgments
Developed for automatic SDL3 binding generation in the Backlog engine.
---
**Version**: 3.0
**Status**: Production ready - 45+ SDL3 headers supported
**Last Updated**: 2026-01-23
anything beyond these I'm not yet actively maintaining

View File

@ -11,50 +11,13 @@
"underlying_type": "Uint32"
}
],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_AudioStreamCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
"name": "SDL_AudioStreamCallback"
},
{
"name": "stream",
"type": "SDL_AudioStream *"
},
{
"name": "additional_amount",
"type": "int"
},
{
"name": "total_amount",
"type": "int"
}
]
},
{
"name": "SDL_AudioPostmixCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
},
{
"name": "spec",
"type": "const SDL_AudioSpec *"
},
{
"name": "buffer",
"type": "float *"
},
{
"name": "buflen",
"type": "int"
}
]
"name": "SDL_AudioPostmixCallback"
}
],
"enums": [

View File

@ -8,6 +8,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_BlendOperation",

View File

@ -12,6 +12,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_CameraPosition",

View File

@ -2,34 +2,13 @@
"header": "SDL_clipboard.h",
"opaque_types": [],
"typedefs": [],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_ClipboardDataCallback",
"return_type": "const void *",
"parameters": [
{
"name": "userdata",
"type": "void *"
"name": "SDL_ClipboardDataCallback"
},
{
"name": "mime_type",
"type": "const char *"
},
{
"name": "size",
"type": "size_t *"
}
]
},
{
"name": "SDL_ClipboardCleanupCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
}
]
"name": "SDL_ClipboardCleanupCallback"
}
],
"enums": [],

View File

@ -2,24 +2,10 @@
"header": "SDL_dialog.h",
"opaque_types": [],
"typedefs": [],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_DialogFileCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
},
{
"name": "filelist",
"type": "const char * const *"
},
{
"name": "filter",
"type": "int"
}
]
"name": "SDL_DialogFileCallback"
}
],
"enums": [

View File

@ -3,6 +3,7 @@
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [],
"unions": [],

View File

@ -3,6 +3,7 @@
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [],
"unions": [],

View File

@ -2,24 +2,10 @@
"header": "SDL_filesystem.h",
"opaque_types": [],
"typedefs": [],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_EnumerateDirectoryCallback",
"return_type": "SDL_EnumerationResult",
"parameters": [
{
"name": "userdata",
"type": "void *"
},
{
"name": "dirname",
"type": "const char *"
},
{
"name": "fname",
"type": "const char *"
}
]
"name": "SDL_EnumerateDirectoryCallback"
}
],
"enums": [

View File

@ -7,6 +7,7 @@
],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_GamepadType",

View File

@ -48,6 +48,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_GPUPrimitiveType",

View File

@ -12,6 +12,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [
{

View File

@ -2,28 +2,10 @@
"header": "SDL_hints.h",
"opaque_types": [],
"typedefs": [],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_HintCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
},
{
"name": "name",
"type": "const char *"
},
{
"name": "oldValue",
"type": "const char *"
},
{
"name": "newValue",
"type": "const char *"
}
]
"name": "SDL_HintCallback"
}
],
"enums": [

View File

@ -2,72 +2,22 @@
"header": "SDL_init.h",
"opaque_types": [],
"typedefs": [],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_AppInit_func",
"return_type": "SDL_AppResult",
"parameters": [
{
"name": "appstate",
"type": "void **"
"name": "SDL_AppInit_func"
},
{
"name": "argc",
"type": "int"
"name": "SDL_AppIterate_func"
},
{
"name": "argv",
"type": "char **"
}
]
"name": "SDL_AppEvent_func"
},
{
"name": "SDL_AppIterate_func",
"return_type": "SDL_AppResult",
"parameters": [
{
"name": "appstate",
"type": "void *"
}
]
"name": "SDL_AppQuit_func"
},
{
"name": "SDL_AppEvent_func",
"return_type": "SDL_AppResult",
"parameters": [
{
"name": "appstate",
"type": "void *"
},
{
"name": "event",
"type": "SDL_Event *"
}
]
},
{
"name": "SDL_AppQuit_func",
"return_type": "void",
"parameters": [
{
"name": "appstate",
"type": "void *"
},
{
"name": "result",
"type": "SDL_AppResult"
}
]
},
{
"name": "SDL_MainThreadCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
}
]
"name": "SDL_MainThreadCallback"
}
],
"enums": [

View File

@ -12,6 +12,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_JoystickType",

View File

@ -12,6 +12,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [],
"unions": [],

View File

@ -7,6 +7,7 @@
],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [],
"unions": [],

View File

@ -3,6 +3,7 @@
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_MessageBoxColorType",

View File

@ -3,6 +3,7 @@
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [],
"unions": [],

View File

@ -12,6 +12,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_SystemCursor",

View File

@ -3,6 +3,7 @@
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_PixelType",

View File

@ -7,38 +7,13 @@
"underlying_type": "Uint32"
}
],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_CleanupPropertyCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
"name": "SDL_CleanupPropertyCallback"
},
{
"name": "value",
"type": "void *"
}
]
},
{
"name": "SDL_EnumeratePropertiesCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
},
{
"name": "props",
"type": "SDL_PropertiesID"
},
{
"name": "name",
"type": "const char *"
}
]
"name": "SDL_EnumeratePropertiesCallback"
}
],
"enums": [

View File

@ -3,6 +3,7 @@
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [
{

View File

@ -10,6 +10,7 @@
],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_TextureAccess",

View File

@ -12,6 +12,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_SensorType",

View File

@ -7,6 +7,7 @@
],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [
{

View File

@ -7,6 +7,7 @@
],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_ScaleMode",

View File

@ -15,62 +15,19 @@
"underlying_type": "struct XUser *"
}
],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_WindowsMessageHook",
"return_type": "bool",
"parameters": [
{
"name": "userdata",
"type": "void *"
"name": "SDL_WindowsMessageHook"
},
{
"name": "msg",
"type": "MSG *"
}
]
"name": "SDL_X11EventHook"
},
{
"name": "SDL_X11EventHook",
"return_type": "bool",
"parameters": [
{
"name": "userdata",
"type": "void *"
"name": "SDL_iOSAnimationCallback"
},
{
"name": "xevent",
"type": "XEvent *"
}
]
},
{
"name": "SDL_iOSAnimationCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
}
]
},
{
"name": "SDL_RequestAndroidPermissionCallback",
"return_type": "void",
"parameters": [
{
"name": "userdata",
"type": "void *"
},
{
"name": "permission",
"type": "const char *"
},
{
"name": "granted",
"type": "bool"
}
]
"name": "SDL_RequestAndroidPermissionCallback"
}
],
"enums": [

View File

@ -3,6 +3,7 @@
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_DateFormat",

View File

@ -7,42 +7,13 @@
"underlying_type": "Uint32"
}
],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_TimerCallback",
"return_type": "Uint32",
"parameters": [
{
"name": "userdata",
"type": "void *"
"name": "SDL_TimerCallback"
},
{
"name": "timerID",
"type": "SDL_TimerID"
},
{
"name": "interval",
"type": "Uint32"
}
]
},
{
"name": "SDL_NSTimerCallback",
"return_type": "Uint64",
"parameters": [
{
"name": "userdata",
"type": "void *"
},
{
"name": "timerID",
"type": "SDL_TimerID"
},
{
"name": "interval",
"type": "Uint64"
}
]
"name": "SDL_NSTimerCallback"
}
],
"enums": [],

View File

@ -12,6 +12,7 @@
}
],
"function_pointers": [],
"c_type_aliases": [],
"enums": [
{
"name": "SDL_TouchDeviceType",

View File

@ -3,6 +3,7 @@
"opaque_types": [],
"typedefs": [],
"function_pointers": [],
"c_type_aliases": [],
"enums": [],
"structs": [],
"unions": [],

View File

@ -58,34 +58,16 @@
"underlying_type": "Uint32"
}
],
"function_pointers": [
"function_pointers": [],
"c_type_aliases": [
{
"name": "SDL_EGLAttribArrayCallback",
"return_type": "SDL_EGLAttrib *",
"parameters": [
{
"name": "userdata",
"type": "void *"
}
]
"name": "SDL_EGLAttribArrayCallback"
},
{
"name": "SDL_EGLIntArrayCallback",
"return_type": "SDL_EGLint *",
"parameters": [
{
"name": "userdata",
"type": "void *"
"name": "SDL_EGLIntArrayCallback"
},
{
"name": "display",
"type": "SDL_EGLDisplay"
},
{
"name": "config",
"type": "SDL_EGLConfig"
}
]
"name": "SDL_HitTest"
}
],
"enums": [

View File

@ -97,6 +97,7 @@ pub const CodeGen = struct {
.opaque_type => |opaque_decl| try self.writeOpaqueWithMethods(opaque_decl),
.typedef_decl => |typedef_decl| try self.writeTypedef(typedef_decl),
.function_pointer_decl => |func_ptr_decl| try self.writeFunctionPointer(func_ptr_decl),
.c_type_alias => |alias| try self.writeCTypeAlias(alias),
.enum_decl => |enum_decl| try self.writeEnum(enum_decl),
.struct_decl => |struct_decl| try self.writeStruct(struct_decl),
.union_decl => |union_decl| try self.writeUnion(union_decl),
@ -163,19 +164,12 @@ pub const CodeGen = struct {
}
fn writeTypedef(self: *CodeGen, typedef_decl: patterns.TypedefDecl) !void {
const zig_name = naming.typeNameToZig(typedef_decl.name);
// Special case: HitTest is a function pointer type
if (std.mem.eql(u8, zig_name, "HitTest")) {
try self.output.appendSlice(self.allocator, "pub const HitTest = *const fn (*Window, *Point, ?*anyopaque) callconv(.C) HitTestResult;\n\n");
return;
}
// Write doc comment if present
if (typedef_decl.doc_comment) |doc| {
try self.writeDocComment(doc);
}
const zig_name = naming.typeNameToZig(typedef_decl.name);
const zig_type = try types.convertType(typedef_decl.underlying_type, self.allocator);
defer self.allocator.free(zig_type);
@ -187,19 +181,12 @@ pub const CodeGen = struct {
}
fn writeFunctionPointer(self: *CodeGen, func_ptr_decl: patterns.FunctionPointerDecl) !void {
const zig_name = naming.typeNameToZig(func_ptr_decl.name);
// Special case: HitTest is a function pointer type
if (std.mem.eql(u8, zig_name, "HitTest")) {
try self.output.appendSlice(self.allocator, "pub const HitTest = *const fn (*Window, *Point, ?*anyopaque) callconv(.C) HitTestResult;\n\n");
return;
}
// Write doc comment if present
if (func_ptr_decl.doc_comment) |doc| {
try self.writeDocComment(doc);
}
const zig_name = naming.typeNameToZig(func_ptr_decl.name);
const return_type = try types.convertType(func_ptr_decl.return_type, self.allocator);
defer self.allocator.free(return_type);
@ -220,6 +207,18 @@ pub const CodeGen = struct {
try self.output.writer(self.allocator).print(") callconv(.C) {s};\n\n", .{return_type});
}
fn writeCTypeAlias(self: *CodeGen, alias: patterns.CTypeAlias) !void {
// Write doc comment if present
if (alias.doc_comment) |doc| {
try self.writeDocComment(doc);
}
const zig_name = naming.typeNameToZig(alias.name);
// Generate: pub const HitTest = c.SDL_HitTest;
try self.output.writer(self.allocator).print("pub const {s} = c.{s};\n\n", .{ zig_name, alias.name });
}
fn writeEnum(self: *CodeGen, enum_decl: EnumDecl) !void {
std.debug.print("enum {s} values.len = {d}\n", .{ enum_decl.name, enum_decl.values.len });
// Skip empty enums
@ -264,12 +263,6 @@ pub const CodeGen = struct {
fn writeStruct(self: *CodeGen, struct_decl: StructDecl) !void {
const zig_name = naming.typeNameToZig(struct_decl.name);
// Special case: HitTest is a function pointer type
if (std.mem.eql(u8, zig_name, "HitTest")) {
try self.output.appendSlice(self.allocator, "pub const HitTest = *const fn (*Window, *Point, ?*anyopaque) callconv(.C) HitTestResult;\n\n");
return;
}
// Write doc comment if present
if (struct_decl.doc_comment) |doc| {
try self.writeDocComment(doc);
@ -663,71 +656,3 @@ pub const CodeGen = struct {
return error.InvalidBitPosition;
}
};
test "generate opaque type" {
const opaque_type = OpaqueType{
.name = "SDL_GPUDevice",
.doc_comment = null,
};
var decls = [_]Declaration{.{ .opaque_type = opaque_type }};
const output = try CodeGen.generate(std.testing.allocator, decls[0..]);
defer std.testing.allocator.free(output);
const expected =
\\const std = @import("std");
\\pub const c = @import("c.zig").c;
\\
\\pub const GPUDevice = opaque {};
\\
\\
;
try std.testing.expectEqualStrings(expected, output);
}
test "generate enum" {
var values = [_]patterns.EnumValue{
.{
.name = "SDL_GPU_PRIMITIVETYPE_TRIANGLELIST",
.value = null,
.comment = " A series of triangles",
},
.{
.name = "SDL_GPU_PRIMITIVETYPE_LINELIST",
.value = null,
.comment = " A series of lines",
},
};
const enum_decl = EnumDecl{
.name = "SDL_GPUPrimitiveType",
.values = values[0..],
.doc_comment = null,
};
var decls = [_]Declaration{.{ .enum_decl = enum_decl }};
const output = try CodeGen.generate(std.testing.allocator, decls[0..]);
defer std.testing.allocator.free(output);
// Verify it contains the expected elements
try std.testing.expect(std.mem.indexOf(u8, output, "pub const GPUPrimitiveType = enum(c_int)") != null);
try std.testing.expect(std.mem.indexOf(u8, output, "trianglelist") != null);
try std.testing.expect(std.mem.indexOf(u8, output, "linelist") != null);
}
test "parse bit position" {
var gen = CodeGen{
.decls = &[_]Declaration{},
.allocator = std.testing.allocator,
.output = try std.ArrayList(u8).initCapacity(std.testing.allocator, 1),
};
defer gen.output.deinit(std.testing.allocator);
try std.testing.expectEqual(@as(u6, 0), try gen.parseBitPosition("(1u << 0)"));
try std.testing.expectEqual(@as(u6, 5), try gen.parseBitPosition("1u << 5"));
try std.testing.expectEqual(@as(u6, 0), try gen.parseBitPosition("0x01"));
try std.testing.expectEqual(@as(u6, 3), try gen.parseBitPosition("0x08"));
}

View File

@ -44,20 +44,26 @@ pub const DependencyResolver = struct {
if (!self.defined_types.contains(key.*)) {
try missing.append(allocator, try allocator.dupe(u8, key.*));
}
// special case evaluation
if (std.mem.eql(u8, key.*, "SDL_HitTest")) {}
}
return try missing.toOwnedSlice(allocator);
}
/// Get hardcoded declarations for special types that can't be resolved from headers
/// Currently unused - function pointer typedefs are now handled as c_type_alias in patterns
pub fn getHardcodedDeclarations(self: *DependencyResolver, allocator: Allocator) ![]Declaration {
_ = self;
var hardcoded = std.ArrayList(Declaration){};
return try hardcoded.toOwnedSlice(allocator);
}
fn collectDefinedTypes(self: *DependencyResolver, decls: []const Declaration) !void {
for (decls) |decl| {
const type_name = 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,
@ -204,6 +210,7 @@ fn isSDLType(type_str: []const u8) bool {
"Window",
"Rect",
"FColor",
"Color",
"FPoint",
"FlipMode",
"PropertiesID",
@ -296,6 +303,12 @@ fn cloneDeclaration(allocator: Allocator, decl: Declaration) !Declaration {
.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),
@ -404,6 +417,10 @@ fn freeDeclaration(allocator: Allocator, decl: Declaration) void {
}
allocator.free(fp.params);
},
.c_type_alias => |a| {
allocator.free(a.name);
if (a.doc_comment) |doc| allocator.free(doc);
},
.enum_decl => |e| {
allocator.free(e.name);
if (e.doc_comment) |doc| allocator.free(doc);
@ -457,59 +474,3 @@ fn freeDeclaration(allocator: Allocator, decl: Declaration) void {
},
}
}
test "extractBaseType removes pointer markers" {
const testing = std.testing;
try testing.expectEqualStrings("SDL_Window", extractBaseType("?*SDL_Window"));
try testing.expectEqualStrings("SDL_Window", extractBaseType("*const SDL_Window"));
try testing.expectEqualStrings("SDL_Rect", extractBaseType("*const SDL_Rect"));
try testing.expectEqualStrings("u8", extractBaseType("[*c]const u8"));
}
test "isSDLType identifies SDL types" {
const testing = std.testing;
try testing.expect(isSDLType("SDL_Window"));
try testing.expect(isSDLType("SDL_Rect"));
try testing.expect(isSDLType("Window"));
try testing.expect(isSDLType("FColor"));
try testing.expect(!isSDLType("u32"));
try testing.expect(!isSDLType("bool"));
try testing.expect(!isSDLType("i32"));
}
test "DependencyResolver basic functionality" {
const testing = std.testing;
const allocator = testing.allocator;
var resolver = DependencyResolver.init(allocator);
defer resolver.deinit();
// Create test params array on heap
const test_params = try allocator.alloc(patterns.ParamDecl, 1);
defer allocator.free(test_params);
test_params[0] = .{ .name = "rect", .type_name = "*const SDL_Rect" };
const decls = [_]Declaration{
.{ .function_decl = .{
.name = "test",
.return_type = "?*SDL_Window",
.params = test_params,
.doc_comment = null,
} },
.{ .opaque_type = .{
.name = "SDL_Device",
.doc_comment = null,
} },
};
try resolver.analyze(&decls);
const missing = try resolver.getMissingTypes(allocator);
defer {
for (missing) |m| allocator.free(m);
allocator.free(missing);
}
// Should find Window and Rect, but not Device (it's defined)
try testing.expect(missing.len == 2);
}

View File

@ -8,6 +8,7 @@ pub const JsonSerializer = struct {
opaque_types: std.ArrayList(patterns.OpaqueType),
typedefs: std.ArrayList(patterns.TypedefDecl),
function_pointers: std.ArrayList(patterns.FunctionPointerDecl),
c_type_aliases: std.ArrayList(patterns.CTypeAlias),
enums: std.ArrayList(patterns.EnumDecl),
structs: std.ArrayList(patterns.StructDecl),
unions: std.ArrayList(patterns.UnionDecl),
@ -22,6 +23,7 @@ pub const JsonSerializer = struct {
.opaque_types = .{},
.typedefs = .{},
.function_pointers = .{},
.c_type_aliases = .{},
.enums = .{},
.structs = .{},
.unions = .{},
@ -35,6 +37,7 @@ pub const JsonSerializer = struct {
self.opaque_types.deinit(self.allocator);
self.typedefs.deinit(self.allocator);
self.function_pointers.deinit(self.allocator);
self.c_type_aliases.deinit(self.allocator);
self.enums.deinit(self.allocator);
self.structs.deinit(self.allocator);
self.unions.deinit(self.allocator);
@ -48,6 +51,7 @@ pub const JsonSerializer = struct {
.opaque_type => |o| try self.opaque_types.append(self.allocator, o),
.typedef_decl => |t| try self.typedefs.append(self.allocator, t),
.function_pointer_decl => |fp| try self.function_pointers.append(self.allocator, fp),
.c_type_alias => |a| try self.c_type_aliases.append(self.allocator, a),
.enum_decl => |e| try self.enums.append(self.allocator, e),
.struct_decl => |s| try self.structs.append(self.allocator, s),
.union_decl => |u| try self.unions.append(self.allocator, u),
@ -95,6 +99,16 @@ pub const JsonSerializer = struct {
}
try writer.writeAll(" ],\n");
// Serialize c_type_aliases (function pointer typedefs aliased to C)
try writer.writeAll(" \"c_type_aliases\": [\n");
for (self.c_type_aliases.items, 0..) |alias, i| {
try writer.writeAll(" ");
try self.serializeCTypeAlias(writer, alias);
if (i < self.c_type_aliases.items.len - 1) try writer.writeAll(",");
try writer.writeAll("\n");
}
try writer.writeAll(" ],\n");
// Serialize enums
try writer.writeAll(" \"enums\": [\n");
for (self.enums.items, 0..) |enum_decl, i| {
@ -194,6 +208,16 @@ pub const JsonSerializer = struct {
try writer.writeAll("}");
}
fn serializeCTypeAlias(self: *JsonSerializer, writer: anytype, alias: patterns.CTypeAlias) !void {
try writer.writeAll("{\"name\": ");
try self.writeString(writer, alias.name);
if (alias.doc_comment) |doc| {
try writer.writeAll(", \"doc\": ");
try self.writeString(writer, doc);
}
try writer.writeAll("}");
}
fn serializeEnum(self: *JsonSerializer, writer: anytype, enum_decl: patterns.EnumDecl) !void {
try writer.writeAll("{\"name\": ");
try self.writeString(writer, enum_decl.name);

View File

@ -12,11 +12,12 @@ pub fn main() !void {
defer std.process.argsFree(allocator, args);
if (args.len < 2) {
std.debug.print("Usage: {s} <header-file> [--output=<output-file>] [--mocks=<mock-file>] [--generate-json=<json-file>] [--timestamp=<timestamp>]\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]});
std.debug.print("Example: {s} ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig\n", .{args[0]});
std.debug.print(" {s} ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig --mocks=gpu_mock.c\n", .{args[0]});
std.debug.print(" {s} ../SDL/include/SDL3/SDL_gpu.h --generate-json=gpu.json\n", .{args[0]});
std.debug.print(" {s} ../SDL/include/SDL3/SDL_gpu.h > gpu.zig\n", .{args[0]});
std.debug.print(" {s} ../SDL/include/SDL3/SDL_gpu.h --basedir=/path/to/workdir\n", .{args[0]});
return error.MissingArgument;
}
@ -26,6 +27,7 @@ pub fn main() !void {
var mock_output_file: ?[]const u8 = null;
var json_output_file: ?[]const u8 = null;
var timestamp: ?i64 = null;
var basedir: ?[]const u8 = null;
// Parse additional flags
for (args[2..]) |arg| {
@ -33,6 +35,7 @@ pub fn main() !void {
const mocks_prefix = "--mocks=";
const json_prefix = "--generate-json=";
const timestamp_prefix = "--timestamp=";
const basedir_prefix = "--basedir=";
if (std.mem.startsWith(u8, arg, output_prefix)) {
output_file = arg[output_prefix.len..];
} else if (std.mem.startsWith(u8, arg, mocks_prefix)) {
@ -41,13 +44,21 @@ pub fn main() !void {
json_output_file = arg[json_prefix.len..];
} else if (std.mem.startsWith(u8, arg, timestamp_prefix)) {
timestamp = std.fmt.parseInt(i64, arg[timestamp_prefix.len..], 10) catch null;
} else if (std.mem.startsWith(u8, arg, basedir_prefix)) {
basedir = arg[basedir_prefix.len..];
} else {
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>]\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]});
return error.InvalidArgument;
}
}
// Change working directory if --basedir is specified
if (basedir) |dir| {
try std.posix.chdir(dir);
std.debug.print("Changed working directory to: {s}\n\n", .{dir});
}
// Archive any existing debug directory before this run
archiveExistingDebugDir(allocator, timestamp);
@ -84,6 +95,10 @@ pub fn main() !void {
}
allocator.free(func_ptr_decl.params);
},
.c_type_alias => |alias| {
allocator.free(alias.name);
if (alias.doc_comment) |doc| allocator.free(doc);
},
.enum_decl => |enum_decl| {
allocator.free(enum_decl.name);
if (enum_decl.doc_comment) |doc| allocator.free(doc);
@ -146,6 +161,7 @@ pub fn main() !void {
var opaque_count: usize = 0;
var typedef_count: usize = 0;
var func_ptr_count: usize = 0;
var c_type_alias_count: usize = 0;
var enum_count: usize = 0;
var struct_count: usize = 0;
var union_count: usize = 0;
@ -157,6 +173,7 @@ pub fn main() !void {
.opaque_type => opaque_count += 1,
.typedef_decl => typedef_count += 1,
.function_pointer_decl => func_ptr_count += 1,
.c_type_alias => c_type_alias_count += 1,
.enum_decl => enum_count += 1,
.struct_decl => struct_count += 1,
.union_decl => union_count += 1,
@ -168,6 +185,7 @@ pub fn main() !void {
std.debug.print(" - Opaque types: {d}\n", .{opaque_count});
std.debug.print(" - Typedefs: {d}\n", .{typedef_count});
std.debug.print(" - Function pointers: {d}\n", .{func_ptr_count});
std.debug.print(" - C type aliases: {d}\n", .{c_type_alias_count});
std.debug.print(" - Enums: {d}\n", .{enum_count});
std.debug.print(" - Structs: {d}\n", .{struct_count});
std.debug.print(" - Unions: {d}\n", .{union_count});
@ -220,6 +238,19 @@ pub fn main() !void {
allocator.free(missing_types);
}
// Get hardcoded declarations for special types (like SDL_HitTest)
const hardcoded_decls = try resolver.getHardcodedDeclarations(allocator);
defer {
for (hardcoded_decls) |hd| {
freeDeclDeep(allocator, hd);
}
allocator.free(hardcoded_decls);
}
if (hardcoded_decls.len > 0) {
std.debug.print("Adding {d} hardcoded type declarations\n", .{hardcoded_decls.len});
}
if (missing_types.len > 0) {
std.debug.print("Found {d} missing types:\n", .{missing_types.len});
for (missing_types) |missing| {
@ -267,12 +298,13 @@ pub fn main() !void {
}
}
// Combine declarations (dependencies first!)
std.debug.print("\nCombining {d} dependency declarations with primary declarations...\n", .{dependency_decls.items.len});
// Combine declarations (hardcoded first, then dependencies, then primary!)
std.debug.print("\nCombining {d} hardcoded + {d} dependency declarations with primary declarations...\n", .{ hardcoded_decls.len, dependency_decls.items.len });
var all_decls = std.ArrayList(patterns.Declaration){};
defer all_decls.deinit(allocator);
try all_decls.appendSlice(allocator, hardcoded_decls);
try all_decls.appendSlice(allocator, dependency_decls.items);
try all_decls.appendSlice(allocator, decls);
@ -342,8 +374,15 @@ pub fn main() !void {
} else {
std.debug.print("No missing dependencies found!\n\n", .{});
// Generate code without dependencies
const output = try codegen.CodeGen.generate(allocator, decls);
// Generate code (include hardcoded declarations if any)
var gen_decls = std.ArrayList(patterns.Declaration){};
defer gen_decls.deinit(allocator);
if (hardcoded_decls.len > 0) {
try gen_decls.appendSlice(allocator, hardcoded_decls);
}
try gen_decls.appendSlice(allocator, decls);
const output = try codegen.CodeGen.generate(allocator, gen_decls.items);
defer allocator.free(output);
// Parse and format the AST for validation
@ -394,7 +433,7 @@ pub fn main() !void {
// Generate C mocks if requested
if (mock_output_file) |mock_path| {
const mock_codegen = @import("mock_codegen.zig");
const mock_output = try mock_codegen.MockCodeGen.generate(allocator, decls);
const mock_output = try mock_codegen.MockCodeGen.generate(allocator, gen_decls.items);
defer allocator.free(mock_output);
try ensureParentDirExists(mock_path);
@ -555,6 +594,10 @@ fn freeDeclDeep(allocator: std.mem.Allocator, decl: patterns.Declaration) void {
}
allocator.free(fp.params);
},
.c_type_alias => |a| {
allocator.free(a.name);
if (a.doc_comment) |doc| allocator.free(doc);
},
.enum_decl => |e| {
allocator.free(e.name);
if (e.doc_comment) |doc| allocator.free(doc);

View File

@ -20,6 +20,7 @@ pub const Declaration = union(enum) {
function_decl: FunctionDecl,
typedef_decl: TypedefDecl,
function_pointer_decl: FunctionPointerDecl,
c_type_alias: CTypeAlias,
};
pub const OpaqueType = struct {
@ -84,6 +85,13 @@ pub const FunctionPointerDecl = struct {
doc_comment: ?[]const u8,
};
/// C type alias - for function pointer typedefs that should alias to C type directly
/// Output: pub const Name = c.SDL_Name;
pub const CTypeAlias = struct {
name: []const u8, // SDL_HitTest
doc_comment: ?[]const u8,
};
pub const FunctionDecl = struct {
name: []const u8, // SDL_CreateGPUDevice
return_type: []const u8, // SDL_GPUDevice *
@ -133,9 +141,9 @@ pub const Scanner = struct {
} else if (try self.scanFlagTypedef()) |flag_decl| {
// Flag typedef must come before simple typedef
try decls.append(self.allocator, .{ .flag_decl = flag_decl });
} else if (try self.scanFunctionPointer()) |func_ptr_decl| {
// Function pointer typedef must come before simple typedef
try decls.append(self.allocator, .{ .function_pointer_decl = func_ptr_decl });
} else if (try self.scanFunctionPointer()) |c_alias| {
// Function pointer typedef -> C type alias (must come before simple typedef)
try decls.append(self.allocator, .{ .c_type_alias = c_alias });
} else if (try self.scanTypedef()) |typedef_decl| {
// Simple typedef comes after flag typedef
try decls.append(self.allocator, .{ .typedef_decl = typedef_decl });
@ -219,7 +227,9 @@ pub const Scanner = struct {
}
// Pattern: typedef RetType (SDLCALL *FuncName)(Param1Type param1, ...);
fn scanFunctionPointer(self: *Scanner) !?FunctionPointerDecl {
// or: typedef RetType (*FuncName)(Param1Type param1, ...);
// All function pointer typedefs become C type aliases: pub const Name = c.SDL_Name;
fn scanFunctionPointer(self: *Scanner) !?CTypeAlias {
const start = self.pos;
const line = try self.readLine();
@ -233,6 +243,7 @@ pub const Scanner = struct {
// Must contain * pattern with SDL prefix (function pointer typedef)
// Pattern: typedef RetType (SDLCALL *SDL_Name)(Params);
// or: typedef RetType (*SDL_Name)(Params);
const has_sdl_ptr = std.mem.indexOf(u8, line, " *SDL_") != null or
std.mem.indexOf(u8, line, "(*SDL_") != null;
if (!has_sdl_ptr) {
@ -240,60 +251,37 @@ pub const Scanner = struct {
return null;
}
// Parse: typedef RetType (SDLCALL *FuncName)(Params);
const trimmed = std.mem.trim(u8, line, " \t\r\n");
const no_semi = std.mem.trimRight(u8, trimmed, ";");
// Must have two sets of parentheses (function pointer pattern)
const first_close = std.mem.indexOfScalar(u8, line, ')') orelse {
self.pos = start;
return null;
};
// Check for second set of parens after the first close
if (std.mem.indexOfScalarPos(u8, line, first_close + 1, '(') == null) {
self.pos = start;
return null;
}
// Skip "typedef "
const after_typedef = std.mem.trimLeft(u8, no_semi["typedef ".len..], " \t");
// Find the *SDL_ marker (function pointer name)
const ptr_marker = std.mem.indexOf(u8, after_typedef, " *SDL_") orelse
std.mem.indexOf(u8, after_typedef, "(*SDL_") orelse {
// Extract function name from between *SDL_ and )
// Find *SDL_ marker
const star_sdl = std.mem.indexOf(u8, line, "*SDL_") orelse {
self.pos = start;
return null;
};
// Return type is everything before the pointer marker
// It may include (SDLCALL or just be the plain type
const return_type_section = std.mem.trim(u8, after_typedef[0..ptr_marker], " \t");
// Extract return type (remove SDLCALL if present)
const return_type = if (std.mem.indexOf(u8, return_type_section, "(SDLCALL")) |sdlcall_pos|
std.mem.trim(u8, return_type_section[0..sdlcall_pos], " \t")
else if (std.mem.indexOf(u8, return_type_section, "SDLCALL")) |sdlcall_pos|
std.mem.trim(u8, return_type_section[0..sdlcall_pos], " \t")
else
return_type_section;
// Find function name: starts after *SDL_ and ends at )
const after_star = std.mem.trimLeft(u8, after_typedef[ptr_marker..], " *(");
const name_end = std.mem.indexOfScalar(u8, after_star, ')') orelse {
// Name starts after * and ends at )
const name_start = star_sdl + 1; // Skip *
const name_end_search = line[name_start..];
const name_end_offset = std.mem.indexOfScalar(u8, name_end_search, ')') orelse {
self.pos = start;
return null;
};
const func_name = std.mem.trim(u8, after_star[0..name_end], " \t");
const func_name = std.mem.trim(u8, name_end_search[0..name_end_offset], " \t");
// Find parameters (between the closing ) of name and final )
const after_name = after_star[name_end + 1 ..]; // Skip )
const params_start = std.mem.indexOfScalar(u8, after_name, '(') orelse {
self.pos = start;
return null;
};
const params_end = std.mem.lastIndexOfScalar(u8, after_name, ')') orelse {
self.pos = start;
return null;
};
const params_str = std.mem.trim(u8, after_name[params_start + 1 .. params_end], " \t");
// Parse parameters
const params = try self.parseParams(params_str);
const doc = self.consumePendingDocComment();
return FunctionPointerDecl{
return CTypeAlias{
.name = try self.allocator.dupe(u8, func_name),
.return_type = try self.allocator.dupe(u8, return_type),
.params = params,
.doc_comment = doc,
};
}

View File

@ -51,6 +51,7 @@ pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
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, "size_t")) return try allocator.dupe(u8, "usize");
if (std.mem.eql(u8, trimmed, "intptr_t")) return try allocator.dupe(u8, "isize");
// Common pointer types
if (std.mem.eql(u8, trimmed, "const char *")) return try allocator.dupe(u8, "[*c]const u8");

View File

@ -223,13 +223,13 @@ pub inline fn createAudioStream(src_spec: *const AudioSpec, dst_spec: *const Aud
return c.SDL_CreateAudioStream(@ptrCast(src_spec), @ptrCast(dst_spec));
}
pub const AudioStreamCallback = *const fn (userdata: ?*anyopaque, stream: ?*AudioStream, additional_amount: c_int, total_amount: c_int) callconv(.C) void;
pub const AudioStreamCallback = c.SDL_AudioStreamCallback;
pub inline fn openAudioDeviceStream(devid: AudioDeviceID, spec: *const AudioSpec, callback: AudioStreamCallback, userdata: ?*anyopaque) ?*AudioStream {
return c.SDL_OpenAudioDeviceStream(devid, @ptrCast(spec), callback, userdata);
}
pub const AudioPostmixCallback = *const fn (userdata: ?*anyopaque, spec: *const AudioSpec, buffer: *f32, buflen: c_int) callconv(.C) void;
pub const AudioPostmixCallback = c.SDL_AudioPostmixCallback;
pub inline fn setAudioPostmixCallback(devid: AudioDeviceID, callback: AudioPostmixCallback, userdata: ?*anyopaque) bool {
return c.SDL_SetAudioPostmixCallback(devid, callback, userdata);

View File

@ -25,9 +25,9 @@ pub inline fn hasPrimarySelectionText() bool {
return c.SDL_HasPrimarySelectionText();
}
pub const ClipboardDataCallback = *const fn (userdata: ?*anyopaque, mime_type: [*c]const u8, size: *usize) callconv(.C) ?*const anyopaque;
pub const ClipboardDataCallback = c.SDL_ClipboardDataCallback;
pub const ClipboardCleanupCallback = *const fn (userdata: ?*anyopaque) callconv(.C) void;
pub const ClipboardCleanupCallback = c.SDL_ClipboardCleanupCallback;
pub inline fn setClipboardData(callback: ClipboardDataCallback, cleanup: ClipboardCleanupCallback, userdata: ?*anyopaque, mime_types: [*c][*c]const u8, num_mime_types: usize) bool {
return c.SDL_SetClipboardData(callback, cleanup, userdata, mime_types, num_mime_types);

View File

@ -10,7 +10,7 @@ pub const DialogFileFilter = extern struct {
pattern: [*c]const u8,
};
pub const DialogFileCallback = *const fn (userdata: ?*anyopaque, filelist: [*c]const [*c]const u8, filter: c_int) callconv(.C) void;
pub const DialogFileCallback = c.SDL_DialogFileCallback;
pub inline fn showOpenFileDialog(callback: DialogFileCallback, userdata: ?*anyopaque, window: ?*Window, filters: *const DialogFileFilter, nfilters: c_int, default_location: [*c]const u8, allow_many: bool) void {
return c.SDL_ShowOpenFileDialog(callback, userdata, window, @ptrCast(filters), nfilters, default_location, allow_many);

View File

@ -61,7 +61,7 @@ pub const EnumerationResult = enum(c_int) {
enumFailure,
};
pub const EnumerateDirectoryCallback = *const fn (userdata: ?*anyopaque, dirname: [*c]const u8, fname: [*c]const u8) callconv(.C) EnumerationResult;
pub const EnumerateDirectoryCallback = c.SDL_EnumerateDirectoryCallback;
pub inline fn enumerateDirectory(path: [*c]const u8, callback: EnumerateDirectoryCallback, userdata: ?*anyopaque) bool {
return c.SDL_EnumerateDirectory(path, callback, userdata);

View File

@ -31,7 +31,7 @@ pub inline fn getHintBoolean(name: [*c]const u8, default_value: bool) bool {
return c.SDL_GetHintBoolean(name, default_value);
}
pub const HintCallback = *const fn (userdata: ?*anyopaque, name: [*c]const u8, oldValue: [*c]const u8, newValue: [*c]const u8) callconv(.C) void;
pub const HintCallback = c.SDL_HintCallback;
pub inline fn addHintCallback(name: [*c]const u8, callback: HintCallback, userdata: ?*anyopaque) bool {
return c.SDL_AddHintCallback(name, callback, userdata);

71
v2/init.zig Normal file
View File

@ -0,0 +1,71 @@
const std = @import("std");
pub const c = @import("c.zig").c;
pub const InitFlags = packed struct(u32) {
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
initJoystick: bool = false, // `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`
initHaptic: bool = false,
initGamepad: bool = false, // `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK`
initEvents: bool = false,
initSensor: bool = false, // `SDL_INIT_SENSOR` implies `SDL_INIT_EVENTS`
initCamera: bool = false, // `SDL_INIT_CAMERA` implies `SDL_INIT_EVENTS`
pad0: u23 = 0,
rsvd: bool = false,
};
pub const AppResult = enum(c_int) {
appContinue, //Value that requests that the app continue from the main callbacks.
appSuccess, //Value that requests termination with success from the main callbacks.
appFailure, //Value that requests termination with error from the main callbacks.
};
pub const AppInit_func = c.SDL_AppInit_func;
pub const AppIterate_func = c.SDL_AppIterate_func;
pub const AppEvent_func = c.SDL_AppEvent_func;
pub const AppQuit_func = c.SDL_AppQuit_func;
pub inline fn init(flags: InitFlags) bool {
return c.SDL_Init(@bitCast(flags));
}
pub inline fn initSubSystem(flags: InitFlags) bool {
return c.SDL_InitSubSystem(@bitCast(flags));
}
pub inline fn quitSubSystem(flags: InitFlags) void {
return c.SDL_QuitSubSystem(@bitCast(flags));
}
pub inline fn wasInit(flags: InitFlags) InitFlags {
return @bitCast(c.SDL_WasInit(@bitCast(flags)));
}
pub inline fn quit() void {
return c.SDL_Quit();
}
pub inline fn isMainThread() bool {
return c.SDL_IsMainThread();
}
pub const MainThreadCallback = c.SDL_MainThreadCallback;
pub inline fn runOnMainThread(callback: MainThreadCallback, userdata: ?*anyopaque, wait_complete: bool) bool {
return c.SDL_RunOnMainThread(callback, userdata, wait_complete);
}
pub inline fn setAppMetadata(appname: [*c]const u8, appversion: [*c]const u8, appidentifier: [*c]const u8) bool {
return c.SDL_SetAppMetadata(appname, appversion, appidentifier);
}
pub inline fn setAppMetadataProperty(name: [*c]const u8, value: [*c]const u8) bool {
return c.SDL_SetAppMetadataProperty(name, value);
}
pub inline fn getAppMetadataProperty(name: [*c]const u8) [*c]const u8 {
return c.SDL_GetAppMetadataProperty(name);
}

View File

@ -32,7 +32,7 @@ pub inline fn unlockProperties(props: PropertiesID) void {
return c.SDL_UnlockProperties(props);
}
pub const CleanupPropertyCallback = *const fn (userdata: ?*anyopaque, value: ?*anyopaque) callconv(.C) void;
pub const CleanupPropertyCallback = c.SDL_CleanupPropertyCallback;
pub inline fn setPointerPropertyWithCleanup(props: PropertiesID, name: [*c]const u8, value: ?*anyopaque, cleanup: CleanupPropertyCallback, userdata: ?*anyopaque) bool {
return c.SDL_SetPointerPropertyWithCleanup(props, name, value, cleanup, userdata);
@ -90,7 +90,7 @@ pub inline fn clearProperty(props: PropertiesID, name: [*c]const u8) bool {
return c.SDL_ClearProperty(props, name);
}
pub const EnumeratePropertiesCallback = *const fn (userdata: ?*anyopaque, props: PropertiesID, name: [*c]const u8) callconv(.C) void;
pub const EnumeratePropertiesCallback = c.SDL_EnumeratePropertiesCallback;
pub inline fn enumerateProperties(props: PropertiesID, callback: EnumeratePropertiesCallback, userdata: ?*anyopaque) bool {
return c.SDL_EnumerateProperties(props, callback, userdata);

159
v2/system.zig Normal file
View File

@ -0,0 +1,159 @@
const std = @import("std");
pub const c = @import("c.zig").c;
pub const DisplayID = u32;
pub const Window = opaque {
pub inline fn setiOSAnimationCallback(window: *Window, interval: c_int, callback: iOSAnimationCallback, callbackParam: ?*anyopaque) bool {
return c.SDL_SetiOSAnimationCallback(window, interval, callback, callbackParam);
}
};
pub const MSG = opaque {};
pub const WindowsMessageHook = c.SDL_WindowsMessageHook;
pub inline fn setWindowsMessageHook(callback: WindowsMessageHook, userdata: ?*anyopaque) void {
return c.SDL_SetWindowsMessageHook(callback, userdata);
}
pub inline fn getDirect3D9AdapterIndex(displayID: DisplayID) c_int {
return c.SDL_GetDirect3D9AdapterIndex(displayID);
}
pub inline fn getDXGIOutputInfo(displayID: DisplayID, adapterIndex: *c_int, outputIndex: *c_int) bool {
return c.SDL_GetDXGIOutputInfo(displayID, @ptrCast(adapterIndex), @ptrCast(outputIndex));
}
pub const X11EventHook = c.SDL_X11EventHook;
pub inline fn setX11EventHook(callback: X11EventHook, userdata: ?*anyopaque) void {
return c.SDL_SetX11EventHook(callback, userdata);
}
pub inline fn setLinuxThreadPriority(threadID: i64, priority: c_int) bool {
return c.SDL_SetLinuxThreadPriority(threadID, priority);
}
pub inline fn setLinuxThreadPriorityAndPolicy(threadID: i64, sdlPriority: c_int, schedPolicy: c_int) bool {
return c.SDL_SetLinuxThreadPriorityAndPolicy(threadID, sdlPriority, schedPolicy);
}
pub const iOSAnimationCallback = c.SDL_iOSAnimationCallback;
pub inline fn setiOSEventPump(enabled: bool) void {
return c.SDL_SetiOSEventPump(enabled);
}
pub inline fn getAndroidJNIEnv() ?*anyopaque {
return c.SDL_GetAndroidJNIEnv();
}
pub inline fn getAndroidActivity() ?*anyopaque {
return c.SDL_GetAndroidActivity();
}
pub inline fn getAndroidSDKVersion() c_int {
return c.SDL_GetAndroidSDKVersion();
}
pub inline fn isChromebook() bool {
return c.SDL_IsChromebook();
}
pub inline fn isDeXMode() bool {
return c.SDL_IsDeXMode();
}
pub inline fn sendAndroidBackButton() void {
return c.SDL_SendAndroidBackButton();
}
pub inline fn getAndroidInternalStoragePath() [*c]const u8 {
return c.SDL_GetAndroidInternalStoragePath();
}
pub inline fn getAndroidExternalStorageState() u32 {
return c.SDL_GetAndroidExternalStorageState();
}
pub inline fn getAndroidExternalStoragePath() [*c]const u8 {
return c.SDL_GetAndroidExternalStoragePath();
}
pub inline fn getAndroidCachePath() [*c]const u8 {
return c.SDL_GetAndroidCachePath();
}
pub const RequestAndroidPermissionCallback = c.SDL_RequestAndroidPermissionCallback;
pub inline fn requestAndroidPermission(permission: [*c]const u8, cb: RequestAndroidPermissionCallback, userdata: ?*anyopaque) bool {
return c.SDL_RequestAndroidPermission(permission, cb, userdata);
}
pub inline fn showAndroidToast(message: [*c]const u8, duration: c_int, gravity: c_int, xoffset: c_int, yoffset: c_int) bool {
return c.SDL_ShowAndroidToast(message, duration, gravity, xoffset, yoffset);
}
pub inline fn sendAndroidMessage(command: u32, param: c_int) bool {
return c.SDL_SendAndroidMessage(command, param);
}
pub inline fn isTablet() bool {
return c.SDL_IsTablet();
}
pub inline fn isTV() bool {
return c.SDL_IsTV();
}
pub const Sandbox = enum(c_int) {
sandboxUnknownContainer,
sandboxFlatpak,
sandboxSnap,
sandboxMacos,
};
pub inline fn getSandbox() Sandbox {
return c.SDL_GetSandbox();
}
pub inline fn onApplicationWillTerminate() void {
return c.SDL_OnApplicationWillTerminate();
}
pub inline fn onApplicationDidReceiveMemoryWarning() void {
return c.SDL_OnApplicationDidReceiveMemoryWarning();
}
pub inline fn onApplicationWillEnterBackground() void {
return c.SDL_OnApplicationWillEnterBackground();
}
pub inline fn onApplicationDidEnterBackground() void {
return c.SDL_OnApplicationDidEnterBackground();
}
pub inline fn onApplicationWillEnterForeground() void {
return c.SDL_OnApplicationWillEnterForeground();
}
pub inline fn onApplicationDidEnterForeground() void {
return c.SDL_OnApplicationDidEnterForeground();
}
pub inline fn onApplicationDidChangeStatusBarOrientation() void {
return c.SDL_OnApplicationDidChangeStatusBarOrientation();
}
pub const XTaskQueueHandle = *anyopaque;
pub const XUserHandle = *anyopaque;
pub inline fn getGDKTaskQueue(outTaskQueue: [*c]XTaskQueueHandle) bool {
return c.SDL_GetGDKTaskQueue(outTaskQueue);
}
pub inline fn getGDKDefaultUser(outUserHandle: [*c]XUserHandle) bool {
return c.SDL_GetGDKDefaultUser(outUserHandle);
}

View File

@ -31,13 +31,13 @@ pub inline fn delayPrecise(ns: u64) void {
pub const TimerID = u32;
pub const TimerCallback = *const fn (userdata: ?*anyopaque, timerID: TimerID, interval: u32) callconv(.C) u32;
pub const TimerCallback = c.SDL_TimerCallback;
pub inline fn addTimer(interval: u32, callback: TimerCallback, userdata: ?*anyopaque) TimerID {
return c.SDL_AddTimer(interval, callback, userdata);
}
pub const NSTimerCallback = *const fn (userdata: ?*anyopaque, timerID: TimerID, interval: u64) callconv(.C) u64;
pub const NSTimerCallback = c.SDL_NSTimerCallback;
pub inline fn addTimerNS(interval: u64, callback: NSTimerCallback, userdata: ?*anyopaque) TimerID {
return c.SDL_AddTimerNS(interval, callback, userdata);

609
v2/video.zig Normal file
View File

@ -0,0 +1,609 @@
const std = @import("std");
pub const c = @import("c.zig").c;
pub const PixelFormat = enum(c_int) {
pixelformatYv12, //Planar mode: Y + V + U (3 planes)
pixelformatIyuv, //Planar mode: Y + U + V (3 planes)
pixelformatYuy2, //Packed mode: Y0+U0+Y1+V0 (1 plane)
pixelformatUyvy, //Packed mode: U0+Y0+V0+Y1 (1 plane)
pixelformatYvyu, //Packed mode: Y0+V0+Y1+U0 (1 plane)
pixelformatNv12, //Planar mode: Y + U/V interleaved (2 planes)
pixelformatNv21, //Planar mode: Y + V/U interleaved (2 planes)
pixelformatP010, //Planar mode: Y + U/V interleaved (2 planes)
pixelformatExternalOes, //Android video texture format
pixelformatMjpg, //Motion JPEG
};
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 = ?*anyopaque;
pub const DisplayID = u32;
pub const WindowID = u32;
pub const SystemTheme = enum(c_int) {
systemThemeUnknown, //Unknown system theme
systemThemeLight, //Light colored system theme
systemThemeDark, //Dark colored system theme
};
pub const DisplayModeData = opaque {};
pub const DisplayMode = extern struct {
displayID: DisplayID, // the display this mode is associated with
format: PixelFormat, // pixel format
w: c_int, // width
h: c_int, // height
pixel_density: f32, // scale converting size to pixels (e.g. a 1920x1080 mode with 2.0 scale would have 3840x2160 pixels)
refresh_rate: f32, // refresh rate (or 0.0f for unspecified)
refresh_rate_numerator: c_int, // precise refresh rate numerator (or 0 for unspecified)
refresh_rate_denominator: c_int, // precise refresh rate denominator
internal: ?*DisplayModeData, // Private
};
pub const DisplayOrientation = enum(c_int) {
orientationUnknown, //The display orientation can't be determined
orientationLandscape, //The display is in landscape mode, with the right side up, relative to portrait mode
orientationLandscapeFlipped, //The display is in landscape mode, with the left side up, relative to portrait mode
orientationPortrait, //The display is in portrait mode
orientationPortraitFlipped,
};
pub const Window = opaque {
pub inline fn getDisplayForWindow(window: *Window) DisplayID {
return c.SDL_GetDisplayForWindow(window);
}
pub inline fn getWindowPixelDensity(window: *Window) f32 {
return c.SDL_GetWindowPixelDensity(window);
}
pub inline fn getWindowDisplayScale(window: *Window) f32 {
return c.SDL_GetWindowDisplayScale(window);
}
pub inline fn setWindowFullscreenMode(window: *Window, mode: *const DisplayMode) bool {
return c.SDL_SetWindowFullscreenMode(window, @ptrCast(mode));
}
pub inline fn getWindowFullscreenMode(window: *Window) *const DisplayMode {
return @ptrCast(c.SDL_GetWindowFullscreenMode(window));
}
pub inline fn getWindowICCProfile(window: *Window, size: *usize) ?*anyopaque {
return c.SDL_GetWindowICCProfile(window, @ptrCast(size));
}
pub inline fn getWindowPixelFormat(window: *Window) PixelFormat {
return @bitCast(c.SDL_GetWindowPixelFormat(window));
}
pub inline fn createPopupWindow(window: *Window, offset_x: c_int, offset_y: c_int, w: c_int, h: c_int, flags: WindowFlags) ?*Window {
return c.SDL_CreatePopupWindow(window, offset_x, offset_y, w, h, @bitCast(flags));
}
pub inline fn getWindowID(window: *Window) WindowID {
return c.SDL_GetWindowID(window);
}
pub inline fn getWindowParent(window: *Window) ?*Window {
return c.SDL_GetWindowParent(window);
}
pub inline fn getWindowProperties(window: *Window) PropertiesID {
return c.SDL_GetWindowProperties(window);
}
pub inline fn getWindowFlags(window: *Window) WindowFlags {
return @bitCast(c.SDL_GetWindowFlags(window));
}
pub inline fn setWindowTitle(window: *Window, title: [*c]const u8) bool {
return c.SDL_SetWindowTitle(window, title);
}
pub inline fn getWindowTitle(window: *Window) [*c]const u8 {
return c.SDL_GetWindowTitle(window);
}
pub inline fn setWindowIcon(window: *Window, icon: ?*Surface) bool {
return c.SDL_SetWindowIcon(window, icon);
}
pub inline fn setWindowPosition(window: *Window, x: c_int, y: c_int) bool {
return c.SDL_SetWindowPosition(window, x, y);
}
pub inline fn getWindowPosition(window: *Window, x: *c_int, y: *c_int) bool {
return c.SDL_GetWindowPosition(window, @ptrCast(x), @ptrCast(y));
}
pub inline fn setWindowSize(window: *Window, w: c_int, h: c_int) bool {
return c.SDL_SetWindowSize(window, w, h);
}
pub inline fn getWindowSize(window: *Window, w: *c_int, h: *c_int) bool {
return c.SDL_GetWindowSize(window, @ptrCast(w), @ptrCast(h));
}
pub inline fn getWindowSafeArea(window: *Window, rect: ?*Rect) bool {
return c.SDL_GetWindowSafeArea(window, rect);
}
pub inline fn setWindowAspectRatio(window: *Window, min_aspect: f32, max_aspect: f32) bool {
return c.SDL_SetWindowAspectRatio(window, min_aspect, max_aspect);
}
pub inline fn getWindowAspectRatio(window: *Window, min_aspect: *f32, max_aspect: *f32) bool {
return c.SDL_GetWindowAspectRatio(window, @ptrCast(min_aspect), @ptrCast(max_aspect));
}
pub inline fn getWindowBordersSize(window: *Window, top: *c_int, left: *c_int, bottom: *c_int, right: *c_int) bool {
return c.SDL_GetWindowBordersSize(window, @ptrCast(top), @ptrCast(left), @ptrCast(bottom), @ptrCast(right));
}
pub inline fn getWindowSizeInPixels(window: *Window, w: *c_int, h: *c_int) bool {
return c.SDL_GetWindowSizeInPixels(window, @ptrCast(w), @ptrCast(h));
}
pub inline fn setWindowMinimumSize(window: *Window, min_w: c_int, min_h: c_int) bool {
return c.SDL_SetWindowMinimumSize(window, min_w, min_h);
}
pub inline fn getWindowMinimumSize(window: *Window, w: *c_int, h: *c_int) bool {
return c.SDL_GetWindowMinimumSize(window, @ptrCast(w), @ptrCast(h));
}
pub inline fn setWindowMaximumSize(window: *Window, max_w: c_int, max_h: c_int) bool {
return c.SDL_SetWindowMaximumSize(window, max_w, max_h);
}
pub inline fn getWindowMaximumSize(window: *Window, w: *c_int, h: *c_int) bool {
return c.SDL_GetWindowMaximumSize(window, @ptrCast(w), @ptrCast(h));
}
pub inline fn setWindowBordered(window: *Window, bordered: bool) bool {
return c.SDL_SetWindowBordered(window, bordered);
}
pub inline fn setWindowResizable(window: *Window, resizable: bool) bool {
return c.SDL_SetWindowResizable(window, resizable);
}
pub inline fn setWindowAlwaysOnTop(window: *Window, on_top: bool) bool {
return c.SDL_SetWindowAlwaysOnTop(window, on_top);
}
pub inline fn showWindow(window: *Window) bool {
return c.SDL_ShowWindow(window);
}
pub inline fn hideWindow(window: *Window) bool {
return c.SDL_HideWindow(window);
}
pub inline fn raiseWindow(window: *Window) bool {
return c.SDL_RaiseWindow(window);
}
pub inline fn maximizeWindow(window: *Window) bool {
return c.SDL_MaximizeWindow(window);
}
pub inline fn minimizeWindow(window: *Window) bool {
return c.SDL_MinimizeWindow(window);
}
pub inline fn restoreWindow(window: *Window) bool {
return c.SDL_RestoreWindow(window);
}
pub inline fn setWindowFullscreen(window: *Window, fullscreen: bool) bool {
return c.SDL_SetWindowFullscreen(window, fullscreen);
}
pub inline fn syncWindow(window: *Window) bool {
return c.SDL_SyncWindow(window);
}
pub inline fn windowHasSurface(window: *Window) bool {
return c.SDL_WindowHasSurface(window);
}
pub inline fn getWindowSurface(window: *Window) ?*Surface {
return c.SDL_GetWindowSurface(window);
}
pub inline fn setWindowSurfaceVSync(window: *Window, vsync: c_int) bool {
return c.SDL_SetWindowSurfaceVSync(window, vsync);
}
pub inline fn getWindowSurfaceVSync(window: *Window, vsync: *c_int) bool {
return c.SDL_GetWindowSurfaceVSync(window, @ptrCast(vsync));
}
pub inline fn updateWindowSurface(window: *Window) bool {
return c.SDL_UpdateWindowSurface(window);
}
pub inline fn updateWindowSurfaceRects(window: *Window, rects: *const Rect, numrects: c_int) bool {
return c.SDL_UpdateWindowSurfaceRects(window, @ptrCast(rects), numrects);
}
pub inline fn destroyWindowSurface(window: *Window) bool {
return c.SDL_DestroyWindowSurface(window);
}
pub inline fn setWindowKeyboardGrab(window: *Window, grabbed: bool) bool {
return c.SDL_SetWindowKeyboardGrab(window, grabbed);
}
pub inline fn setWindowMouseGrab(window: *Window, grabbed: bool) bool {
return c.SDL_SetWindowMouseGrab(window, grabbed);
}
pub inline fn getWindowKeyboardGrab(window: *Window) bool {
return c.SDL_GetWindowKeyboardGrab(window);
}
pub inline fn getWindowMouseGrab(window: *Window) bool {
return c.SDL_GetWindowMouseGrab(window);
}
pub inline fn setWindowMouseRect(window: *Window, rect: *const Rect) bool {
return c.SDL_SetWindowMouseRect(window, @ptrCast(rect));
}
pub inline fn getWindowMouseRect(window: *Window) *const Rect {
return @ptrCast(c.SDL_GetWindowMouseRect(window));
}
pub inline fn setWindowOpacity(window: *Window, opacity: f32) bool {
return c.SDL_SetWindowOpacity(window, opacity);
}
pub inline fn getWindowOpacity(window: *Window) f32 {
return c.SDL_GetWindowOpacity(window);
}
pub inline fn setWindowParent(window: *Window, parent: ?*Window) bool {
return c.SDL_SetWindowParent(window, parent);
}
pub inline fn setWindowModal(window: *Window, modal: bool) bool {
return c.SDL_SetWindowModal(window, modal);
}
pub inline fn setWindowFocusable(window: *Window, focusable: bool) bool {
return c.SDL_SetWindowFocusable(window, focusable);
}
pub inline fn showWindowSystemMenu(window: *Window, x: c_int, y: c_int) bool {
return c.SDL_ShowWindowSystemMenu(window, x, y);
}
pub inline fn setWindowHitTest(window: *Window, callback: HitTest, callback_data: ?*anyopaque) bool {
return c.SDL_SetWindowHitTest(window, callback, callback_data);
}
pub inline fn setWindowShape(window: *Window, shape: ?*Surface) bool {
return c.SDL_SetWindowShape(window, shape);
}
pub inline fn flashWindow(window: *Window, operation: FlashOperation) bool {
return c.SDL_FlashWindow(window, @intFromEnum(operation));
}
pub inline fn destroyWindow(window: *Window) void {
return c.SDL_DestroyWindow(window);
}
pub inline fn gl_CreateContext(window: *Window) GLContext {
return c.SDL_GL_CreateContext(window);
}
pub inline fn gl_MakeCurrent(window: *Window, context: GLContext) bool {
return c.SDL_GL_MakeCurrent(window, context);
}
pub inline fn egl_GetWindowSurface(window: *Window) EGLSurface {
return c.SDL_EGL_GetWindowSurface(window);
}
pub inline fn gl_SwapWindow(window: *Window) bool {
return c.SDL_GL_SwapWindow(window);
}
};
pub const WindowFlags = packed struct(u64) {
windowFullscreen: bool = false, // window is in fullscreen mode
windowOpengl: bool = false, // window usable with OpenGL context
windowOccluded: bool = false, // window is occluded
windowHidden: bool = false, // window is neither mapped onto the desktop nor shown in the taskbar/dock/window list; SDL_ShowWindow() is required for it to become visible
windowBorderless: bool = false, // no window decoration
windowResizable: bool = false, // window can be resized
windowMinimized: bool = false, // window is minimized
windowMaximized: bool = false, // window is maximized
windowMouseGrabbed: bool = false, // window has grabbed mouse input
windowInputFocus: bool = false, // window has input focus
windowMouseFocus: bool = false, // window has mouse focus
windowExternal: bool = false, // window not created by SDL
windowModal: bool = false, // window is modal
windowHighPixelDensity: bool = false, // window uses high pixel density back buffer if possible
windowMouseCapture: bool = false, // window has mouse captured (unrelated to MOUSE_GRABBED)
windowMouseRelativeMode: bool = false, // window has relative mode enabled
windowAlwaysOnTop: bool = false, // window should always be above others
windowUtility: bool = false, // window should be treated as a utility window, not showing in the task bar and window list
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
windowKeyboardGrabbed: bool = false, // window has grabbed keyboard input
windowVulkan: bool = false, // window usable for Vulkan surface
windowMetal: bool = false, // window usable for Metal view
windowTransparent: bool = false, // window with transparent buffer
windowNotFocusable: bool = false, // window should not be focusable
pad0: u38 = 0,
rsvd: bool = false,
};
pub const FlashOperation = enum(c_int) {
flashCancel, //Cancel any window flash state
flashBriefly, //Flash the window briefly to get attention
flashUntilFocused, //Flash the window until it gets focus
};
pub const GLContext = *anyopaque;
pub const EGLDisplay = ?*anyopaque;
pub const EGLConfig = ?*anyopaque;
pub const EGLSurface = ?*anyopaque;
pub const EGLAttrib = isize;
pub const EGLint = c_int;
pub const EGLAttribArrayCallback = c.SDL_EGLAttribArrayCallback;
pub const EGLIntArrayCallback = c.SDL_EGLIntArrayCallback;
pub const GLAttr = enum(c_int) {
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 8.
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 8.
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.
glDepthSize, //the minimum number of bits in the depth buffer; defaults to 16.
glStencilSize, //the minimum number of bits in the stencil buffer; defaults to 0.
glAccumRedSize, //the minimum number of bits for the red channel of the accumulation buffer; defaults to 0.
glAccumGreenSize, //the minimum number of bits for the green channel of the accumulation buffer; defaults to 0.
glAccumBlueSize, //the minimum number of bits for the blue channel of the accumulation buffer; defaults to 0.
glAccumAlphaSize, //the minimum number of bits for the alpha channel of the accumulation buffer; defaults to 0.
glStereo, //whether the output is stereo 3D; defaults to off.
glMultisamplebuffers, //the number of buffers used for multisample anti-aliasing; defaults to 0.
glMultisamplesamples, //the number of samples used around the current pixel used for multisample anti-aliasing.
glAcceleratedVisual, //set to 1 to require hardware acceleration, set to 0 to force software rendering; defaults to allow either.
glRetainedBacking, //not used (deprecated).
glContextMajorVersion, //OpenGL context major version.
glContextMinorVersion, //OpenGL context minor version.
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.
glShareWithCurrentContext, //OpenGL context sharing; defaults to 0.
glFramebufferSrgbCapable, //requests sRGB capable visual; defaults to 0.
glContextReleaseBehavior, //sets context the release behavior. See SDL_GLContextReleaseFlag; defaults to FLUSH.
glContextResetNotification, //set context reset notification. See SDL_GLContextResetNotification; defaults to NO_NOTIFICATION.
glContextNoError,
glFloatbuffers,
glEglPlatform,
};
pub const GLProfile = u32;
pub const GLContextFlag = u32;
pub const GLContextReleaseFlag = u32;
pub const GLContextResetNotification = u32;
pub inline fn getNumVideoDrivers() c_int {
return c.SDL_GetNumVideoDrivers();
}
pub inline fn getVideoDriver(index: c_int) [*c]const u8 {
return c.SDL_GetVideoDriver(index);
}
pub inline fn getCurrentVideoDriver() [*c]const u8 {
return c.SDL_GetCurrentVideoDriver();
}
pub inline fn getSystemTheme() SystemTheme {
return c.SDL_GetSystemTheme();
}
pub inline fn getDisplays(count: *c_int) ?*DisplayID {
return c.SDL_GetDisplays(@ptrCast(count));
}
pub inline fn getPrimaryDisplay() DisplayID {
return c.SDL_GetPrimaryDisplay();
}
pub inline fn getDisplayProperties(displayID: DisplayID) PropertiesID {
return c.SDL_GetDisplayProperties(displayID);
}
pub inline fn getDisplayName(displayID: DisplayID) [*c]const u8 {
return c.SDL_GetDisplayName(displayID);
}
pub inline fn getDisplayBounds(displayID: DisplayID, rect: ?*Rect) bool {
return c.SDL_GetDisplayBounds(displayID, rect);
}
pub inline fn getDisplayUsableBounds(displayID: DisplayID, rect: ?*Rect) bool {
return c.SDL_GetDisplayUsableBounds(displayID, rect);
}
pub inline fn getNaturalDisplayOrientation(displayID: DisplayID) DisplayOrientation {
return c.SDL_GetNaturalDisplayOrientation(displayID);
}
pub inline fn getCurrentDisplayOrientation(displayID: DisplayID) DisplayOrientation {
return c.SDL_GetCurrentDisplayOrientation(displayID);
}
pub inline fn getDisplayContentScale(displayID: DisplayID) f32 {
return c.SDL_GetDisplayContentScale(displayID);
}
pub inline fn getFullscreenDisplayModes(displayID: DisplayID, count: *c_int) [*c][*c]DisplayMode {
return @intFromEnum(c.SDL_GetFullscreenDisplayModes(displayID, @ptrCast(count)));
}
pub inline fn getClosestFullscreenDisplayMode(displayID: DisplayID, w: c_int, h: c_int, refresh_rate: f32, include_high_density_modes: bool, closest: ?*DisplayMode) bool {
return c.SDL_GetClosestFullscreenDisplayMode(displayID, w, h, refresh_rate, include_high_density_modes, @intFromEnum(closest));
}
pub inline fn getDesktopDisplayMode(displayID: DisplayID) *const DisplayMode {
return @ptrCast(c.SDL_GetDesktopDisplayMode(displayID));
}
pub inline fn getCurrentDisplayMode(displayID: DisplayID) *const DisplayMode {
return @ptrCast(c.SDL_GetCurrentDisplayMode(displayID));
}
pub inline fn getDisplayForPoint(point: *const Point) DisplayID {
return c.SDL_GetDisplayForPoint(@ptrCast(point));
}
pub inline fn getDisplayForRect(rect: *const Rect) DisplayID {
return c.SDL_GetDisplayForRect(@ptrCast(rect));
}
pub inline fn getWindows(count: *c_int) [*c][*c]Window {
return c.SDL_GetWindows(@ptrCast(count));
}
pub inline fn createWindow(title: [*c]const u8, w: c_int, h: c_int, flags: WindowFlags) ?*Window {
return c.SDL_CreateWindow(title, w, h, @bitCast(flags));
}
pub inline fn createWindowWithProperties(props: PropertiesID) ?*Window {
return c.SDL_CreateWindowWithProperties(props);
}
pub inline fn getWindowFromID(id: WindowID) ?*Window {
return c.SDL_GetWindowFromID(id);
}
pub inline fn getGrabbedWindow() ?*Window {
return c.SDL_GetGrabbedWindow();
}
pub const HitTestResult = enum(c_int) {
hittestNormal, //Region is normal. No special properties.
hittestDraggable, //Region can drag entire window.
hittestResizeTopleft, //Region is the resizable top-left corner border.
hittestResizeTop, //Region is the resizable top border.
hittestResizeTopright, //Region is the resizable top-right corner border.
hittestResizeRight, //Region is the resizable right border.
hittestResizeBottomright, //Region is the resizable bottom-right corner border.
hittestResizeBottom, //Region is the resizable bottom border.
hittestResizeBottomleft, //Region is the resizable bottom-left corner border.
hittestResizeLeft, //Region is the resizable left border.
};
pub const HitTest = c.SDL_HitTest;
pub inline fn screenSaverEnabled() bool {
return c.SDL_ScreenSaverEnabled();
}
pub inline fn enableScreenSaver() bool {
return c.SDL_EnableScreenSaver();
}
pub inline fn disableScreenSaver() bool {
return c.SDL_DisableScreenSaver();
}
pub inline fn gl_LoadLibrary(path: [*c]const u8) bool {
return c.SDL_GL_LoadLibrary(path);
}
pub inline fn gl_GetProcAddress(proc: [*c]const u8) FunctionPointer {
return c.SDL_GL_GetProcAddress(proc);
}
pub inline fn egl_GetProcAddress(proc: [*c]const u8) FunctionPointer {
return c.SDL_EGL_GetProcAddress(proc);
}
pub inline fn gl_UnloadLibrary() void {
return c.SDL_GL_UnloadLibrary();
}
pub inline fn gl_ExtensionSupported(extension: [*c]const u8) bool {
return c.SDL_GL_ExtensionSupported(extension);
}
pub inline fn gl_ResetAttributes() void {
return c.SDL_GL_ResetAttributes();
}
pub inline fn gl_SetAttribute(attr: GLAttr, value: c_int) bool {
return c.SDL_GL_SetAttribute(attr, value);
}
pub inline fn gl_GetAttribute(attr: GLAttr, value: *c_int) bool {
return c.SDL_GL_GetAttribute(attr, @ptrCast(value));
}
pub inline fn gl_GetCurrentWindow() ?*Window {
return c.SDL_GL_GetCurrentWindow();
}
pub inline fn gl_GetCurrentContext() GLContext {
return c.SDL_GL_GetCurrentContext();
}
pub inline fn egl_GetCurrentDisplay() EGLDisplay {
return c.SDL_EGL_GetCurrentDisplay();
}
pub inline fn egl_GetCurrentConfig() EGLConfig {
return c.SDL_EGL_GetCurrentConfig();
}
pub inline fn egl_SetAttributeCallbacks(platformAttribCallback: EGLAttribArrayCallback, surfaceAttribCallback: EGLIntArrayCallback, contextAttribCallback: EGLIntArrayCallback, userdata: ?*anyopaque) void {
return c.SDL_EGL_SetAttributeCallbacks(platformAttribCallback, surfaceAttribCallback, contextAttribCallback, userdata);
}
pub inline fn gl_SetSwapInterval(interval: c_int) bool {
return c.SDL_GL_SetSwapInterval(interval);
}
pub inline fn gl_GetSwapInterval(interval: *c_int) bool {
return c.SDL_GL_GetSwapInterval(@ptrCast(interval));
}
pub inline fn gl_DestroyContext(context: GLContext) bool {
return c.SDL_GL_DestroyContext(context);
}