all: move standalone libraries to libs/ subdirectory
The root dir of our repository has grown quite a lot the past few months.
I'd like to make it more clear where the bulk of the engine lives (`src/`) and
also make it more clear which Mach libraries are consumable as standalone projects.
As for the name of this directory, `libs` was my first choice but there's a bit of
a convention of that being external libraries in Zig projects _today_, while these
are libraries maintained as part of Mach in this repository - not external ones.
We will name this directory `libs`, and if we have a need for external libraries
we will use `external` or `deps` for that directory name. I considered other names
such as `components`, `systems`, `modules` (which are bad as they overlap with
major ECS / engine concepts), and it seems likely the official Zig package manager
will break the convention of using a `libs` dir anyway.
Performed via:
```sh
mkdir libs/
git mv freetype libs/
git mv basisu libs/
git mv gamemode libs/
git mv glfw libs/
git mv gpu libs/
git mv gpu-dawn libs/
git mv sysaudio libs/
git mv sysjs libs/
git mv ecs libs/
```
git-subtree-dir: glfw
git-subtree-mainline: 0d5b853443
git-subtree-split: 572d1144f11b353abdb64fff828b25a4f0fbb7ca
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
git mv ecs libs/
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
79ec61396f
commit
0645429df9
240 changed files with 6 additions and 6 deletions
223
libs/glfw/src/Cursor.zig
Normal file
223
libs/glfw/src/Cursor.zig
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
//! Represents a cursor and provides facilities for setting cursor images.
|
||||
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
const Image = @import("Image.zig");
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
const Cursor = @This();
|
||||
|
||||
ptr: *c.GLFWcursor,
|
||||
|
||||
/// Standard system cursor shapes.
|
||||
///
|
||||
/// These are the standard cursor shapes that can be requested from the platform (window system).
|
||||
pub const Shape = enum(i32) {
|
||||
/// The regular arrow cursor shape.
|
||||
arrow = c.GLFW_ARROW_CURSOR,
|
||||
|
||||
/// The text input I-beam cursor shape.
|
||||
ibeam = c.GLFW_IBEAM_CURSOR,
|
||||
|
||||
/// The crosshair cursor shape.
|
||||
crosshair = c.GLFW_CROSSHAIR_CURSOR,
|
||||
|
||||
/// The pointing hand cursor shape.
|
||||
///
|
||||
/// NOTE: This supersedes the old `hand` enum.
|
||||
pointing_hand = c.GLFW_POINTING_HAND_CURSOR,
|
||||
|
||||
/// The horizontal resize/move arrow shape.
|
||||
///
|
||||
/// The horizontal resize/move arrow shape. This is usually a horizontal double-headed arrow.
|
||||
//
|
||||
// NOTE: This supersedes the old `hresize` enum.
|
||||
resize_ew = c.GLFW_RESIZE_EW_CURSOR,
|
||||
|
||||
/// The vertical resize/move arrow shape.
|
||||
///
|
||||
/// The vertical resize/move shape. This is usually a vertical double-headed arrow.
|
||||
///
|
||||
/// NOTE: This supersedes the old `vresize` enum.
|
||||
resize_ns = c.GLFW_RESIZE_NS_CURSOR,
|
||||
|
||||
/// The top-left to bottom-right diagonal resize/move arrow shape.
|
||||
///
|
||||
/// The top-left to bottom-right diagonal resize/move shape. This is usually a diagonal
|
||||
/// double-headed arrow.
|
||||
///
|
||||
/// macos: This shape is provided by a private system API and may fail CursorUnavailable in the
|
||||
/// future.
|
||||
///
|
||||
/// x11: This shape is provided by a newer standard not supported by all cursor themes.
|
||||
///
|
||||
/// wayland: This shape is provided by a newer standard not supported by all cursor themes.
|
||||
resize_nwse = c.GLFW_RESIZE_NWSE_CURSOR,
|
||||
|
||||
/// The top-right to bottom-left diagonal resize/move arrow shape.
|
||||
///
|
||||
/// The top-right to bottom-left diagonal resize/move shape. This is usually a diagonal
|
||||
/// double-headed arrow.
|
||||
///
|
||||
/// macos: This shape is provided by a private system API and may fail with CursorUnavailable
|
||||
/// in the future.
|
||||
///
|
||||
/// x11: This shape is provided by a newer standard not supported by all cursor themes.
|
||||
///
|
||||
/// wayland: This shape is provided by a newer standard not supported by all cursor themes.
|
||||
resize_nesw = c.GLFW_RESIZE_NESW_CURSOR,
|
||||
|
||||
/// The omni-directional resize/move cursor shape.
|
||||
///
|
||||
/// The omni-directional resize cursor/move shape. This is usually either a combined horizontal
|
||||
/// and vertical double-headed arrow or a grabbing hand.
|
||||
resize_all = c.GLFW_RESIZE_ALL_CURSOR,
|
||||
|
||||
/// The operation-not-allowed shape.
|
||||
///
|
||||
/// The operation-not-allowed shape. This is usually a circle with a diagonal line through it.
|
||||
///
|
||||
/// x11: This shape is provided by a newer standard not supported by all cursor themes.
|
||||
///
|
||||
/// wayland: This shape is provided by a newer standard not supported by all cursor themes.
|
||||
not_allowed = c.GLFW_NOT_ALLOWED_CURSOR,
|
||||
};
|
||||
|
||||
/// Creates a custom cursor.
|
||||
///
|
||||
/// Creates a new custom cursor image that can be set for a window with glfw.Cursor.set. The cursor
|
||||
/// can be destroyed with glfwCursor.destroy. Any remaining cursors are destroyed by glfw.terminate.
|
||||
///
|
||||
/// The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight bits per channel with
|
||||
/// the red channel first. They are arranged canonically as packed sequential rows, starting from
|
||||
/// the top-left corner.
|
||||
///
|
||||
/// The cursor hotspot is specified in pixels, relative to the upper-left corner of the cursor
|
||||
/// image. Like all other coordinate systems in GLFW, the X-axis points to the right and the Y-axis
|
||||
/// points down.
|
||||
///
|
||||
/// @param[in] image The desired cursor image.
|
||||
/// @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot.
|
||||
/// @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot.
|
||||
/// @return The handle of the created cursor.
|
||||
///
|
||||
/// @pointer_lifetime The specified image data is copied before this function returns.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: cursor_object, glfw.Cursor.destroy, glfw.Cursor.createStandard
|
||||
pub inline fn create(image: Image, xhot: i32, yhot: i32) error{ PlatformError, InvalidValue }!Cursor {
|
||||
internal_debug.assertInitialized();
|
||||
const img = image.toC();
|
||||
if (c.glfwCreateCursor(&img, @intCast(c_int, xhot), @intCast(c_int, yhot))) |cursor| return Cursor{ .ptr = cursor };
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
Error.InvalidValue => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwCreateCursor` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Creates a cursor with a standard shape.
|
||||
///
|
||||
/// Returns a cursor with a standard shape, that can be set for a window with glfw.Window.setCursor.
|
||||
/// The images for these cursors come from the system cursor theme and their exact appearance will
|
||||
/// vary between platforms.
|
||||
///
|
||||
/// Most of these shapes are guaranteed to exist on every supported platform but a few may not be
|
||||
/// present. See the table below for details.
|
||||
///
|
||||
/// | Cursor shape | Windows | macOS | X11 | Wayland |
|
||||
/// |------------------|---------|-----------------|-------------------|-------------------|
|
||||
/// | `.arrow` | Yes | Yes | Yes | Yes |
|
||||
/// | `.ibeam` | Yes | Yes | Yes | Yes |
|
||||
/// | `.crosshair` | Yes | Yes | Yes | Yes |
|
||||
/// | `.pointing_hand` | Yes | Yes | Yes | Yes |
|
||||
/// | `.resize_ew` | Yes | Yes | Yes | Yes |
|
||||
/// | `.resize_ns` | Yes | Yes | Yes | Yes |
|
||||
/// | `.resize_nwse` | Yes | Yes<sup>1</sup> | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
|
||||
/// | `.resize_nesw` | Yes | Yes<sup>1</sup> | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
|
||||
/// | `.resize_all` | Yes | Yes | Yes | Yes |
|
||||
/// | `.not_allowed` | Yes | Yes | Maybe<sup>2</sup> | Maybe<sup>2</sup> |
|
||||
///
|
||||
/// 1. This uses a private system API and may fail in the future.
|
||||
/// 2. This uses a newer standard that not all cursor themes support.
|
||||
///
|
||||
/// If the requested shape is not available, this function emits a CursorUnavailable error
|
||||
///
|
||||
/// thread_safety: This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: cursor_object, glfwCreateCursor
|
||||
pub inline fn createStandard(shape: Shape) error{ PlatformError, CursorUnavailable }!Cursor {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwCreateStandardCursor(@intCast(c_int, @enumToInt(shape)))) |cursor| return Cursor{ .ptr = cursor };
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.CursorUnavailable => |e| e,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwCreateStandardCursor` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Destroys a cursor.
|
||||
///
|
||||
/// This function destroys a cursor previously created with glfw.Cursor.create. Any remaining
|
||||
/// cursors will be destroyed by glfw.terminate.
|
||||
///
|
||||
/// If the specified cursor is current for any window, that window will be reverted to the default
|
||||
/// cursor. This does not affect the cursor mode.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @reentrancy This function must not be called from a callback.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: cursor_object, glfw.createCursor
|
||||
pub inline fn destroy(self: Cursor) void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwDestroyCursor(self.ptr);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.PlatformError => std.log.err("mach/glfw: unable to destroy Cursor: {}\n", .{err}),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
test "create" {
|
||||
const allocator = testing.allocator;
|
||||
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const image = try Image.init(allocator, 32, 32, 32 * 32 * 4);
|
||||
defer image.deinit(allocator);
|
||||
|
||||
const cursor = glfw.Cursor.create(image, 0, 0) catch |err| {
|
||||
std.debug.print("failed to create cursor, custom cursors not supported? error={}\n", .{err});
|
||||
return;
|
||||
};
|
||||
cursor.destroy();
|
||||
}
|
||||
|
||||
test "createStandard" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const cursor = glfw.Cursor.createStandard(.ibeam) catch |err| {
|
||||
std.debug.print("failed to create cursor, custom cursors not supported? error={}\n", .{err});
|
||||
return;
|
||||
};
|
||||
cursor.destroy();
|
||||
}
|
||||
74
libs/glfw/src/GammaRamp.zig
Normal file
74
libs/glfw/src/GammaRamp.zig
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
//! Gamma ramp for monitors and related functions.
|
||||
//!
|
||||
//! It may be .owned (e.g. in the case of a gamma ramp initialized by you for passing into
|
||||
//! glfw.Monitor.setGammaRamp) or not .owned (e.g. in the case of one gotten via
|
||||
//! glfw.Monitor.getGammaRamp.) If it is .owned, deinit should be called to free the memory. It is
|
||||
//! safe to call deinit even if not .owned.
|
||||
//!
|
||||
//! see also: monitor_gamma, glfw.Monitor.getGammaRamp
|
||||
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
const GammaRamp = @This();
|
||||
|
||||
red: []u16,
|
||||
green: []u16,
|
||||
blue: []u16,
|
||||
owned: bool,
|
||||
|
||||
/// Initializes a new owned gamma ramp with the given array size and undefined values.
|
||||
///
|
||||
/// see also: glfw.Monitor.getGammaRamp
|
||||
pub inline fn init(allocator: mem.Allocator, size: usize) !GammaRamp {
|
||||
const buf = try allocator.alloc(u16, size * 3);
|
||||
return GammaRamp{
|
||||
.red = buf[size * 0 .. (size * 0) + size],
|
||||
.green = buf[size * 1 .. (size * 1) + size],
|
||||
.blue = buf[size * 2 .. (size * 2) + size],
|
||||
.owned = true,
|
||||
};
|
||||
}
|
||||
|
||||
/// Turns a GLFW / C gamma ramp into the nicer Zig type, and sets `.owned = false`.
|
||||
///
|
||||
/// The returned memory is valid for as long as the GLFW C memory is valid.
|
||||
pub inline fn fromC(native: c.GLFWgammaramp) GammaRamp {
|
||||
return GammaRamp{
|
||||
.red = native.red[0..native.size],
|
||||
.green = native.green[0..native.size],
|
||||
.blue = native.blue[0..native.size],
|
||||
.owned = false,
|
||||
};
|
||||
}
|
||||
|
||||
/// Turns the nicer Zig type into a GLFW / C gamma ramp, for passing into GLFW C functions.
|
||||
///
|
||||
/// The returned memory is valid for as long as the Zig memory is valid.
|
||||
pub inline fn toC(self: GammaRamp) c.GLFWgammaramp {
|
||||
std.debug.assert(self.red.len == self.green.len);
|
||||
std.debug.assert(self.red.len == self.blue.len);
|
||||
return c.GLFWgammaramp{
|
||||
.red = &self.red[0],
|
||||
.green = &self.green[0],
|
||||
.blue = &self.blue[0],
|
||||
.size = @intCast(c_uint, self.red.len),
|
||||
};
|
||||
}
|
||||
|
||||
/// Deinitializes the memory using the allocator iff `.owned = true`.
|
||||
pub inline fn deinit(self: GammaRamp, allocator: mem.Allocator) void {
|
||||
if (self.owned) allocator.free(self.red);
|
||||
}
|
||||
|
||||
test "conversion" {
|
||||
const allocator = testing.allocator;
|
||||
|
||||
const ramp = try GammaRamp.init(allocator, 256);
|
||||
defer ramp.deinit(allocator);
|
||||
|
||||
const glfw = ramp.toC();
|
||||
_ = GammaRamp.fromC(glfw);
|
||||
}
|
||||
82
libs/glfw/src/Image.zig
Normal file
82
libs/glfw/src/Image.zig
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
//! Image data
|
||||
//!
|
||||
//!
|
||||
//! This describes a single 2D image. See the documentation for each related function what the
|
||||
//! expected pixel format is.
|
||||
//!
|
||||
//! see also: cursor_custom, window_icon
|
||||
//!
|
||||
//! It may be .owned (e.g. in the case of an image initialized by you for passing into glfw) or not
|
||||
//! .owned (e.g. in the case of one gotten via glfw) If it is .owned, deinit should be called to
|
||||
//! free the memory. It is safe to call deinit even if not .owned.
|
||||
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
const Image = @This();
|
||||
|
||||
/// The width of this image, in pixels.
|
||||
width: u32,
|
||||
|
||||
/// The height of this image, in pixels.
|
||||
height: u32,
|
||||
|
||||
/// The pixel data of this image, arranged left-to-right, top-to-bottom.
|
||||
pixels: []u8,
|
||||
|
||||
/// Whether or not the pixels data is owned by you (true) or GLFW (false).
|
||||
owned: bool,
|
||||
|
||||
/// Initializes a new owned image with the given size and pixel_data_len of undefined .pixel values.
|
||||
pub inline fn init(allocator: mem.Allocator, width: u32, height: u32, pixel_data_len: usize) !Image {
|
||||
const buf = try allocator.alloc(u8, pixel_data_len);
|
||||
return Image{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.pixels = buf,
|
||||
.owned = true,
|
||||
};
|
||||
}
|
||||
|
||||
/// Turns a GLFW / C image into the nicer Zig type, and sets `.owned = false`.
|
||||
///
|
||||
/// The length of pixel data must be supplied, as GLFW's image type does not itself describe the
|
||||
/// number of bytes required per pixel / the length of the pixel data array.
|
||||
///
|
||||
/// The returned memory is valid for as long as the GLFW C memory is valid.
|
||||
pub inline fn fromC(native: c.GLFWimage, pixel_data_len: usize) Image {
|
||||
return Image{
|
||||
.width = @intCast(u32, native.width),
|
||||
.height = @intCast(u32, native.height),
|
||||
.pixels = native.pixels[0..pixel_data_len],
|
||||
.owned = false,
|
||||
};
|
||||
}
|
||||
|
||||
/// Turns the nicer Zig type into a GLFW / C image, for passing into GLFW C functions.
|
||||
///
|
||||
/// The returned memory is valid for as long as the Zig memory is valid.
|
||||
pub inline fn toC(self: Image) c.GLFWimage {
|
||||
return c.GLFWimage{
|
||||
.width = @intCast(c_int, self.width),
|
||||
.height = @intCast(c_int, self.height),
|
||||
.pixels = &self.pixels[0],
|
||||
};
|
||||
}
|
||||
|
||||
/// Deinitializes the memory using the allocator iff `.owned = true`.
|
||||
pub inline fn deinit(self: Image, allocator: mem.Allocator) void {
|
||||
if (self.owned) allocator.free(self.pixels);
|
||||
}
|
||||
|
||||
test "conversion" {
|
||||
const allocator = testing.allocator;
|
||||
|
||||
const image = try Image.init(allocator, 256, 256, 256 * 256 * 4);
|
||||
defer image.deinit(allocator);
|
||||
|
||||
const glfw = image.toC();
|
||||
_ = Image.fromC(glfw, image.width * image.height * 4);
|
||||
}
|
||||
667
libs/glfw/src/Joystick.zig
Normal file
667
libs/glfw/src/Joystick.zig
Normal file
|
|
@ -0,0 +1,667 @@
|
|||
//! Represents a Joystick or gamepad
|
||||
//!
|
||||
//! It can be manually crafted via e.g. `glfw.Joystick{.jid = .one}`, but more
|
||||
//! typically you'll want to discover the joystick using `glfw.Joystick.setCallback`.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const Window = @import("Window.zig");
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
const Action = @import("action.zig").Action;
|
||||
const GamepadAxis = @import("gamepad_axis.zig").GamepadAxis;
|
||||
const GamepadButton = @import("gamepad_button.zig").GamepadButton;
|
||||
const Hat = @import("hat.zig").Hat;
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
const Joystick = @This();
|
||||
|
||||
/// The GLFW joystick ID.
|
||||
jid: Id,
|
||||
|
||||
/// Joystick IDs.
|
||||
///
|
||||
/// See glfw.Joystick.setCallback for how these are used.
|
||||
pub const Id = enum(c_int) {
|
||||
one = c.GLFW_JOYSTICK_1,
|
||||
two = c.GLFW_JOYSTICK_2,
|
||||
three = c.GLFW_JOYSTICK_3,
|
||||
four = c.GLFW_JOYSTICK_4,
|
||||
five = c.GLFW_JOYSTICK_5,
|
||||
six = c.GLFW_JOYSTICK_6,
|
||||
seven = c.GLFW_JOYSTICK_7,
|
||||
eight = c.GLFW_JOYSTICK_8,
|
||||
nine = c.GLFW_JOYSTICK_9,
|
||||
ten = c.GLFW_JOYSTICK_10,
|
||||
eleven = c.GLFW_JOYSTICK_11,
|
||||
twelve = c.GLFW_JOYSTICK_12,
|
||||
thirteen = c.GLFW_JOYSTICK_13,
|
||||
fourteen = c.GLFW_JOYSTICK_14,
|
||||
fifteen = c.GLFW_JOYSTICK_15,
|
||||
sixteen = c.GLFW_JOYSTICK_16,
|
||||
pub const last = @intToEnum(@This(), c.GLFW_JOYSTICK_LAST);
|
||||
};
|
||||
|
||||
/// Gamepad input state
|
||||
///
|
||||
/// This describes the input state of a gamepad.
|
||||
///
|
||||
/// see also: gamepad, glfwGetGamepadState
|
||||
const GamepadState = extern struct {
|
||||
/// The states of each gamepad button (see gamepad_buttons), `glfw.Action.press` or `glfw.Action.release`.
|
||||
///
|
||||
/// Use the enumeration helper e.g. `.getButton(.dpad_up)` to access these indices.
|
||||
buttons: [15]u8,
|
||||
|
||||
/// The states of each gamepad axis (see gamepad_axes), in the range -1.0 to 1.0 inclusive.
|
||||
///
|
||||
/// Use the enumeration helper e.g. `.getAxis(.left_x)` to access these indices.
|
||||
axes: [6]f32,
|
||||
|
||||
/// Returns the state of the specified gamepad button.
|
||||
pub fn getButton(self: @This(), which: GamepadButton) Action {
|
||||
_ = self;
|
||||
return @intToEnum(Action, self.buttons[@intCast(u32, @enumToInt(which))]);
|
||||
}
|
||||
|
||||
/// Returns the status of the specified gamepad axis, in the range -1.0 to 1.0 inclusive.
|
||||
pub fn getAxis(self: @This(), which: GamepadAxis) f32 {
|
||||
_ = self;
|
||||
return self.axes[@intCast(u32, @enumToInt(which))];
|
||||
}
|
||||
};
|
||||
|
||||
/// Returns whether the specified joystick is present.
|
||||
///
|
||||
/// This function returns whether the specified joystick is present.
|
||||
///
|
||||
/// There is no need to call this function before other functions that accept a joystick ID, as
|
||||
/// they all check for presence before performing any other work.
|
||||
///
|
||||
/// @return `true` if the joystick is present, or `false` otherwise.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: joystick
|
||||
pub inline fn present(self: Joystick) error{PlatformError}!bool {
|
||||
internal_debug.assertInitialized();
|
||||
const is_present = c.glfwJoystickPresent(@enumToInt(self.jid));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return is_present == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
/// Returns the values of all axes of the specified joystick.
|
||||
///
|
||||
/// This function returns the values of all axes of the specified joystick. Each element in the
|
||||
/// array is a value between -1.0 and 1.0.
|
||||
///
|
||||
/// If the specified joystick is not present this function will return null but will not generate
|
||||
/// an error. This can be used instead of first calling glfw.Joystick.present.
|
||||
///
|
||||
/// @return An array of axis values, or null if the joystick is not present.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the specified joystick is disconnected or the library is
|
||||
/// terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: joystick_axis
|
||||
/// Replaces `glfwGetJoystickPos`.
|
||||
pub inline fn getAxes(self: Joystick) error{PlatformError}!?[]const f32 {
|
||||
internal_debug.assertInitialized();
|
||||
var count: c_int = undefined;
|
||||
const axes = c.glfwGetJoystickAxes(@enumToInt(self.jid), &count);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
if (axes == null) return null;
|
||||
return axes[0..@intCast(u32, count)];
|
||||
}
|
||||
|
||||
/// Returns the state of all buttons of the specified joystick.
|
||||
///
|
||||
/// This function returns the state of all buttons of the specified joystick. Each element in the
|
||||
/// array is either `glfw.Action.press` or `glfw.Action.release`.
|
||||
///
|
||||
/// For backward compatibility with earlier versions that did not have glfw.Joystick.getHats, the
|
||||
/// button array also includes all hats, each represented as four buttons. The hats are in the same
|
||||
/// order as returned by glfw.Joystick.getHats and are in the order _up_, _right_, _down_ and
|
||||
/// _left_. To disable these extra buttons, set the glfw.joystick_hat_buttons init hint before
|
||||
/// initialization.
|
||||
///
|
||||
/// If the specified joystick is not present this function will return null but will not generate an
|
||||
/// error. This can be used instead of first calling glfw.Joystick.present.
|
||||
///
|
||||
/// @return An array of button states, or null if the joystick is not present.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the specified joystick is disconnected or the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: joystick_button
|
||||
pub inline fn getButtons(self: Joystick) error{PlatformError}!?[]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
var count: c_int = undefined;
|
||||
const buttons = c.glfwGetJoystickButtons(@enumToInt(self.jid), &count);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
if (buttons == null) return null;
|
||||
return buttons[0..@intCast(u32, count)];
|
||||
}
|
||||
|
||||
/// Returns the state of all hats of the specified joystick.
|
||||
///
|
||||
/// This function returns the state of all hats of the specified joystick. Each element in the array
|
||||
/// is one of the following values:
|
||||
///
|
||||
/// | Name | Value |
|
||||
/// |---------------------------|---------------------------------------------|
|
||||
/// | `glfw.RawHats.centered` | 0 |
|
||||
/// | `glfw.RawHats.up` | 1 |
|
||||
/// | `glfw.RawHats.right` | 2 |
|
||||
/// | `glfw.RawHats.down` | 4 |
|
||||
/// | `glfw.RawHats.left` | 8 |
|
||||
/// | `glfw.RawHats.right_up` | `glfw.RawHats.right` \| `glfw.RawHats.up` |
|
||||
/// | `glfw.RawHats.right_down` | `glfw.RawHats.right` \| `glfw.RawHats.down` |
|
||||
/// | `glfw.RawHats.left_up` | `glfw.RawHats.left` \| `glfw.RawHats.up` |
|
||||
/// | `glfw.RawHats.left_down` | `glfw.RawHats.left` \| `glfw.RawHats.down` |
|
||||
///
|
||||
/// The diagonal directions are bitwise combinations of the primary (up, right, down and left)
|
||||
/// directions, since the Zig GLFW wrapper returns a packed struct it is trivial to test for these:
|
||||
///
|
||||
/// ```
|
||||
/// if (hats.up and hats.right) {
|
||||
/// // up-right!
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If the specified joystick is not present this function will return null but will not generate an
|
||||
/// error. This can be used instead of first calling glfw.Joystick.present.
|
||||
///
|
||||
/// @return An array of hat states, or null if the joystick is not present.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the specified joystick is disconnected, this function is called
|
||||
/// again for that joystick or the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: joystick_hat
|
||||
pub inline fn getHats(self: Joystick) error{PlatformError}!?[]const Hat {
|
||||
internal_debug.assertInitialized();
|
||||
var count: c_int = undefined;
|
||||
const hats = c.glfwGetJoystickHats(@enumToInt(self.jid), &count);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
if (hats == null) return null;
|
||||
const slice = hats[0..@intCast(u32, count)];
|
||||
return @ptrCast(*const []const Hat, &slice).*;
|
||||
}
|
||||
|
||||
/// Returns the name of the specified joystick.
|
||||
///
|
||||
/// This function returns the name, encoded as UTF-8, of the specified joystick. The returned string
|
||||
/// is allocated and freed by GLFW. You should not free it yourself.
|
||||
///
|
||||
/// If the specified joystick is not present this function will return null but will not generate an
|
||||
/// error. This can be used instead of first calling glfw.Joystick.present.
|
||||
///
|
||||
/// @return The UTF-8 encoded name of the joystick, or null if the joystick is not present or an
|
||||
/// error occurred.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the specified joystick is disconnected or the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: joystick_name
|
||||
pub inline fn getName(self: Joystick) error{PlatformError}!?[:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
const name_opt = c.glfwGetJoystickName(@enumToInt(self.jid));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return if (name_opt) |name|
|
||||
std.mem.span(@ptrCast([*:0]const u8, name))
|
||||
else
|
||||
null;
|
||||
}
|
||||
|
||||
/// Returns the SDL compatible GUID of the specified joystick.
|
||||
///
|
||||
/// This function returns the SDL compatible GUID, as a UTF-8 encoded hexadecimal string, of the
|
||||
/// specified joystick. The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself.
|
||||
///
|
||||
/// The GUID is what connects a joystick to a gamepad mapping. A connected joystick will always have
|
||||
/// a GUID even if there is no gamepad mapping assigned to it.
|
||||
///
|
||||
/// If the specified joystick is not present this function will return null but will not generate an
|
||||
/// error. This can be used instead of first calling glfw.Joystick.present.
|
||||
///
|
||||
/// The GUID uses the format introduced in SDL 2.0.5. This GUID tries to uniquely identify the make
|
||||
/// and model of a joystick but does not identify a specific unit, e.g. all wired Xbox 360
|
||||
/// controllers will have the same GUID on that platform. The GUID for a unit may vary between
|
||||
/// platforms depending on what hardware information the platform specific APIs provide.
|
||||
///
|
||||
/// @return The UTF-8 encoded GUID of the joystick, or null if the joystick is not present.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the specified joystick is disconnected or the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: gamepad
|
||||
pub inline fn getGUID(self: Joystick) error{PlatformError}!?[:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
const guid_opt = c.glfwGetJoystickGUID(@enumToInt(self.jid));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return if (guid_opt) |guid|
|
||||
std.mem.span(@ptrCast([*:0]const u8, guid))
|
||||
else
|
||||
null;
|
||||
}
|
||||
|
||||
/// Sets the user pointer of the specified joystick.
|
||||
///
|
||||
/// This function sets the user-defined pointer of the specified joystick. The current value is
|
||||
/// retained until the joystick is disconnected. The initial value is null.
|
||||
///
|
||||
/// This function may be called from the joystick callback, even for a joystick that is being disconnected.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread. Access is not synchronized.
|
||||
///
|
||||
/// see also: joystick_userptr, glfw.Joystick.getUserPointer
|
||||
pub inline fn setUserPointer(self: Joystick, comptime T: type, pointer: *T) void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwSetJoystickUserPointer(@enumToInt(self.jid), @ptrCast(*anyopaque, pointer));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the user pointer of the specified joystick.
|
||||
///
|
||||
/// This function returns the current value of the user-defined pointer of the specified joystick.
|
||||
/// The initial value is null.
|
||||
///
|
||||
/// This function may be called from the joystick callback, even for a joystick that is being
|
||||
/// disconnected.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread. Access is not synchronized.
|
||||
///
|
||||
/// see also: joystick_userptr, glfw.Joystick.setUserPointer
|
||||
pub inline fn getUserPointer(self: Joystick, comptime PointerType: type) ?PointerType {
|
||||
internal_debug.assertInitialized();
|
||||
const ptr = c.glfwGetJoystickUserPointer(@enumToInt(self.jid));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
if (ptr) |p| return @ptrCast(PointerType, @alignCast(@alignOf(std.meta.Child(PointerType)), p));
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Describes an event relating to a joystick.
|
||||
pub const Event = enum(c_int) {
|
||||
/// The device was connected.
|
||||
connected = c.GLFW_CONNECTED,
|
||||
|
||||
/// The device was disconnected.
|
||||
disconnected = c.GLFW_DISCONNECTED,
|
||||
};
|
||||
|
||||
/// Sets the joystick configuration callback.
|
||||
///
|
||||
/// This function sets the joystick configuration callback, or removes the currently set callback.
|
||||
/// This is called when a joystick is connected to or disconnected from the system.
|
||||
///
|
||||
/// For joystick connection and disconnection events to be delivered on all platforms, you need to
|
||||
/// call one of the event processing (see events) functions. Joystick disconnection may also be
|
||||
/// detected and the callback called by joystick functions. The function will then return whatever
|
||||
/// it returns if the joystick is not present.
|
||||
///
|
||||
/// @param[in] callback The new callback, or null to remove the currently set callback.
|
||||
///
|
||||
/// @callback_param `jid` The joystick that was connected or disconnected.
|
||||
/// @callback_param `event` One of `.connected` or `.disconnected`. Future releases may add
|
||||
/// more events.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: joystick_event
|
||||
pub inline fn setCallback(comptime callback: ?fn (joystick: Joystick, event: Event) void) void {
|
||||
internal_debug.assertInitialized();
|
||||
|
||||
if (callback) |user_callback| {
|
||||
const CWrapper = struct {
|
||||
pub fn joystickCallbackWrapper(jid: c_int, event: c_int) callconv(.C) void {
|
||||
@call(.{ .modifier = .always_inline }, user_callback, .{
|
||||
Joystick{ .jid = @intToEnum(Joystick.Id, jid) },
|
||||
@intToEnum(Event, event),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (c.glfwSetJoystickCallback(CWrapper.joystickCallbackWrapper) != null) return;
|
||||
} else {
|
||||
if (c.glfwSetJoystickCallback(null) != null) return;
|
||||
}
|
||||
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Adds the specified SDL_GameControllerDB gamepad mappings.
|
||||
///
|
||||
/// This function parses the specified ASCII encoded string and updates the internal list with any
|
||||
/// gamepad mappings it finds. This string may contain either a single gamepad mapping or many
|
||||
/// mappings separated by newlines. The parser supports the full format of the `gamecontrollerdb.txt`
|
||||
/// source file including empty lines and comments.
|
||||
///
|
||||
/// See gamepad_mapping for a description of the format.
|
||||
///
|
||||
/// If there is already a gamepad mapping for a given GUID in the internal list, it will be
|
||||
/// replaced by the one passed to this function. If the library is terminated and re-initialized
|
||||
/// the internal list will revert to the built-in default.
|
||||
///
|
||||
/// @param[in] string The string containing the gamepad mappings.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.InvalidValue.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: gamepad, glfw.Joystick.isGamepad, glfwGetGamepadName
|
||||
///
|
||||
///
|
||||
/// @ingroup input
|
||||
pub inline fn updateGamepadMappings(gamepad_mappings: [*:0]const u8) error{InvalidValue}!void {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwUpdateGamepadMappings(gamepad_mappings) == c.GLFW_TRUE) return;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
// TODO: Maybe return as 'ParseError' here?
|
||||
// TODO: Look into upstream proposal for GLFW to publicize
|
||||
// their Gamepad mappings parsing functions/interface
|
||||
// for a better error message in debug.
|
||||
Error.InvalidValue => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns whether the specified joystick has a gamepad mapping.
|
||||
///
|
||||
/// This function returns whether the specified joystick is both present and has a gamepad mapping.
|
||||
///
|
||||
/// If the specified joystick is present but does not have a gamepad mapping this function will
|
||||
/// return `false` but will not generate an error. Call glfw.Joystick.present to check if a
|
||||
/// joystick is present regardless of whether it has a mapping.
|
||||
///
|
||||
/// @return `true` if a joystick is both present and has a gamepad mapping, or `false` otherwise.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.InvalidEnum.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: gamepad, glfw.Joystick.getGamepadState
|
||||
pub inline fn isGamepad(self: Joystick) bool {
|
||||
internal_debug.assertInitialized();
|
||||
const is_gamepad = c.glfwJoystickIsGamepad(@enumToInt(self.jid));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return is_gamepad == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
/// Returns the human-readable gamepad name for the specified joystick.
|
||||
///
|
||||
/// This function returns the human-readable name of the gamepad from the gamepad mapping assigned
|
||||
/// to the specified joystick.
|
||||
///
|
||||
/// If the specified joystick is not present or does not have a gamepad mapping this function will
|
||||
/// return null, not an error. Call glfw.Joystick.present to check whether it is
|
||||
/// present regardless of whether it has a mapping.
|
||||
///
|
||||
/// @return The UTF-8 encoded name of the gamepad, or null if the joystick is not present or does
|
||||
/// not have a mapping.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.InvalidEnum.
|
||||
///
|
||||
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the specified joystick is disconnected, the gamepad mappings are
|
||||
/// updated or the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: gamepad, glfw.Joystick.isGamepad
|
||||
pub inline fn getGamepadName(self: Joystick) ?[:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
const name_opt = c.glfwGetGamepadName(@enumToInt(self.jid));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidValue => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return if (name_opt) |name|
|
||||
std.mem.span(@ptrCast([*:0]const u8, name))
|
||||
else
|
||||
null;
|
||||
}
|
||||
|
||||
/// Retrieves the state of the joystick remapped as a gamepad.
|
||||
///
|
||||
/// This function retrieves the state of the joystick remapped to an Xbox-like gamepad.
|
||||
///
|
||||
/// If the specified joystick is not present or does not have a gamepad mapping this function will
|
||||
/// return `false`. Call glfw.joystickPresent to check whether it is present regardless of whether
|
||||
/// it has a mapping.
|
||||
///
|
||||
/// The Guide button may not be available for input as it is often hooked by the system or the
|
||||
/// Steam client.
|
||||
///
|
||||
/// Not all devices have all the buttons or axes provided by GamepadState. Unavailable buttons
|
||||
/// and axes will always report `glfw.Action.release` and 0.0 respectively.
|
||||
///
|
||||
/// @param[in] jid The joystick (see joysticks) to query.
|
||||
/// @param[out] state The gamepad input state of the joystick.
|
||||
/// @return the gamepad input state if successful, or null if no joystick is connected or it has no
|
||||
/// gamepad mapping.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.InvalidEnum.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: gamepad, glfw.UpdateGamepadMappings, glfw.Joystick.isGamepad
|
||||
pub inline fn getGamepadState(self: Joystick) ?GamepadState {
|
||||
internal_debug.assertInitialized();
|
||||
var state: GamepadState = undefined;
|
||||
const success = c.glfwGetGamepadState(@enumToInt(self.jid), @ptrCast(*c.GLFWgamepadstate, &state));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return if (success == c.GLFW_TRUE) state else null;
|
||||
}
|
||||
|
||||
test "present" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
|
||||
_ = joystick.present() catch |err| std.debug.print("failed to detect joystick, joysticks not supported? error={}\n", .{err});
|
||||
}
|
||||
|
||||
test "getAxes" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
|
||||
_ = joystick.getAxes() catch |err| std.debug.print("failed to get joystick axes, joysticks not supported? error={}\n", .{err});
|
||||
}
|
||||
|
||||
test "getButtons" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
|
||||
_ = joystick.getButtons() catch |err| std.debug.print("failed to get joystick buttons, joysticks not supported? error={}\n", .{err});
|
||||
}
|
||||
|
||||
test "getHats" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
|
||||
_ = joystick.getHats() catch |err| std.debug.print("failed to get joystick hats, joysticks not supported? error={}\n", .{err});
|
||||
const hats = std.mem.zeroes(Hat);
|
||||
if (hats.down and hats.up) {
|
||||
// down-up!
|
||||
}
|
||||
}
|
||||
|
||||
test "getName" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
|
||||
_ = joystick.getName() catch |err| std.debug.print("failed to get joystick name, joysticks not supported? error={}\n", .{err});
|
||||
}
|
||||
|
||||
test "getGUID" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
|
||||
_ = joystick.getGUID() catch |err| std.debug.print("failed to get joystick GUID, joysticks not supported? error={}\n", .{err});
|
||||
}
|
||||
|
||||
test "setUserPointer_syntax" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
|
||||
// Must be called from joystick callback, we cannot test it.
|
||||
_ = joystick;
|
||||
_ = setUserPointer;
|
||||
}
|
||||
|
||||
test "getUserPointer_syntax" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
|
||||
// Must be called from joystick callback, we cannot test it.
|
||||
_ = joystick;
|
||||
_ = getUserPointer;
|
||||
}
|
||||
|
||||
test "setCallback" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
glfw.Joystick.setCallback((struct {
|
||||
pub fn callback(joystick: Joystick, event: Event) void {
|
||||
_ = joystick;
|
||||
_ = event;
|
||||
}
|
||||
}).callback);
|
||||
}
|
||||
|
||||
test "updateGamepadMappings_syntax" {
|
||||
// We don't have a gamepad mapping to test with, just confirm the syntax is good.
|
||||
_ = updateGamepadMappings;
|
||||
}
|
||||
|
||||
test "isGamepad" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
_ = joystick.isGamepad();
|
||||
}
|
||||
|
||||
test "getGamepadName" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
_ = joystick.getGamepadName();
|
||||
}
|
||||
|
||||
test "getGamepadState" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const joystick = glfw.Joystick{ .jid = .one };
|
||||
_ = joystick.getGamepadState();
|
||||
_ = (std.mem.zeroes(GamepadState)).getAxis(.left_x);
|
||||
_ = (std.mem.zeroes(GamepadState)).getButton(.dpad_up);
|
||||
}
|
||||
626
libs/glfw/src/Monitor.zig
Normal file
626
libs/glfw/src/Monitor.zig
Normal file
|
|
@ -0,0 +1,626 @@
|
|||
//! Monitor type and related functions
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
const GammaRamp = @import("GammaRamp.zig");
|
||||
const VideoMode = @import("VideoMode.zig");
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
const Monitor = @This();
|
||||
|
||||
handle: *c.GLFWmonitor,
|
||||
|
||||
/// A monitor position, in screen coordinates, of the upper left corner of the monitor on the
|
||||
/// virtual screen.
|
||||
const Pos = struct {
|
||||
/// The x coordinate.
|
||||
x: u32,
|
||||
/// The y coordinate.
|
||||
y: u32,
|
||||
};
|
||||
|
||||
/// Returns the position of the monitor's viewport on the virtual screen.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_properties
|
||||
pub inline fn getPos(self: Monitor) error{PlatformError}!Pos {
|
||||
internal_debug.assertInitialized();
|
||||
var xpos: c_int = 0;
|
||||
var ypos: c_int = 0;
|
||||
c.glfwGetMonitorPos(self.handle, &xpos, &ypos);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return Pos{ .x = @intCast(u32, xpos), .y = @intCast(u32, ypos) };
|
||||
}
|
||||
|
||||
/// The monitor workarea, in screen coordinates.
|
||||
///
|
||||
/// This is the position of the upper-left corner of the work area of the monitor, along with the
|
||||
/// work area size. The work area is defined as the area of the monitor not occluded by the
|
||||
/// window system task bar where present. If no task bar exists then the work area is the
|
||||
/// monitor resolution in screen coordinates.
|
||||
const Workarea = struct {
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
};
|
||||
|
||||
/// Retrieves the work area of the monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_workarea
|
||||
pub inline fn getWorkarea(self: Monitor) error{PlatformError}!Workarea {
|
||||
internal_debug.assertInitialized();
|
||||
var xpos: c_int = 0;
|
||||
var ypos: c_int = 0;
|
||||
var width: c_int = 0;
|
||||
var height: c_int = 0;
|
||||
c.glfwGetMonitorWorkarea(self.handle, &xpos, &ypos, &width, &height);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return Workarea{ .x = @intCast(u32, xpos), .y = @intCast(u32, ypos), .width = @intCast(u32, width), .height = @intCast(u32, height) };
|
||||
}
|
||||
|
||||
/// The physical size, in millimetres, of the display area of a monitor.
|
||||
const PhysicalSize = struct {
|
||||
width_mm: u32,
|
||||
height_mm: u32,
|
||||
};
|
||||
|
||||
/// Returns the physical size of the monitor.
|
||||
///
|
||||
/// Some platforms do not provide accurate monitor size information, either because the monitor
|
||||
/// [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data)
|
||||
/// data is incorrect or because the driver does not report it accurately.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
///
|
||||
/// win32: On Windows 8 and earlier the physical size is calculated from
|
||||
/// the current resolution and system DPI instead of querying the monitor EDID data
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_properties
|
||||
pub inline fn getPhysicalSize(self: Monitor) PhysicalSize {
|
||||
internal_debug.assertInitialized();
|
||||
var width_mm: c_int = 0;
|
||||
var height_mm: c_int = 0;
|
||||
c.glfwGetMonitorPhysicalSize(self.handle, &width_mm, &height_mm);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return PhysicalSize{ .width_mm = @intCast(u32, width_mm), .height_mm = @intCast(u32, height_mm) };
|
||||
}
|
||||
|
||||
/// The content scale for a monitor.
|
||||
///
|
||||
/// This is the ratio between the current DPI and the platform's default DPI. This is especially
|
||||
/// important for text and any UI elements. If the pixel dimensions of your UI scaled by this look
|
||||
/// appropriate on your machine then it should appear at a reasonable size on other machines
|
||||
/// regardless of their DPI and scaling settings. This relies on the system DPI and scaling
|
||||
/// settings being somewhat correct.
|
||||
///
|
||||
/// The content scale may depend on both the monitor resolution and pixel density and on users
|
||||
/// settings. It may be very different from the raw DPI calculated from the physical size and
|
||||
/// current resolution.
|
||||
const ContentScale = struct {
|
||||
x_scale: f32,
|
||||
y_scale: f32,
|
||||
};
|
||||
|
||||
/// Returns the content scale for the monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_scale, glfw.Window.getContentScale
|
||||
pub inline fn getContentScale(self: Monitor) error{PlatformError}!ContentScale {
|
||||
internal_debug.assertInitialized();
|
||||
var x_scale: f32 = 0;
|
||||
var y_scale: f32 = 0;
|
||||
c.glfwGetMonitorContentScale(self.handle, &x_scale, &y_scale);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return ContentScale{ .x_scale = @floatCast(f32, x_scale), .y_scale = @floatCast(f32, y_scale) };
|
||||
}
|
||||
|
||||
/// Returns the name of the specified monitor.
|
||||
///
|
||||
/// This function returns a human-readable name, encoded as UTF-8, of the specified monitor. The
|
||||
/// name typically reflects the make and model of the monitor and is not guaranteed to be unique
|
||||
/// among the connected monitors.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the specified monitor is disconnected or the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_properties
|
||||
pub inline fn getName(self: Monitor) [*:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetMonitorName(self.handle)) |name| return @ptrCast([*:0]const u8, name);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetMonitorName` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Sets the user pointer of the specified monitor.
|
||||
///
|
||||
/// This function sets the user-defined pointer of the specified monitor. The current value is
|
||||
/// retained until the monitor is disconnected.
|
||||
///
|
||||
/// This function may be called from the monitor callback, even for a monitor that is being
|
||||
/// disconnected.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread. Access is not synchronized.
|
||||
///
|
||||
/// see also: monitor_userptr, glfw.Monitor.getUserPointer
|
||||
pub inline fn setUserPointer(self: Monitor, comptime T: type, ptr: *T) void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwSetMonitorUserPointer(self.handle, ptr);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the user pointer of the specified monitor.
|
||||
///
|
||||
/// This function returns the current value of the user-defined pointer of the specified monitor.
|
||||
///
|
||||
/// This function may be called from the monitor callback, even for a monitor that is being
|
||||
/// disconnected.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread. Access is not synchronized.
|
||||
///
|
||||
/// see also: monitor_userptr, glfw.Monitor.setUserPointer
|
||||
pub inline fn getUserPointer(self: Monitor, comptime T: type) ?*T {
|
||||
internal_debug.assertInitialized();
|
||||
const ptr = c.glfwGetMonitorUserPointer(self.handle);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
if (ptr == null) return null;
|
||||
return @ptrCast(*T, @alignCast(@alignOf(T), ptr.?));
|
||||
}
|
||||
|
||||
/// Returns the available video modes for the specified monitor.
|
||||
///
|
||||
/// This function returns an array of all video modes supported by the monitor. The returned slice
|
||||
/// is sorted in ascending order, first by color bit depth (the sum of all channel depths) and
|
||||
/// then by resolution area (the product of width and height), then resolution width and finally
|
||||
/// by refresh rate.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// The returned slice memory is owned by the caller.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_modes, glfw.Monitor.getVideoMode
|
||||
pub inline fn getVideoModes(self: Monitor, allocator: mem.Allocator) (mem.Allocator.Error || error{PlatformError})![]VideoMode {
|
||||
internal_debug.assertInitialized();
|
||||
var count: c_int = 0;
|
||||
if (c.glfwGetVideoModes(self.handle, &count)) |modes| {
|
||||
const slice = try allocator.alloc(VideoMode, @intCast(u32, count));
|
||||
var i: u32 = 0;
|
||||
while (i < count) : (i += 1) {
|
||||
slice[i] = VideoMode{ .handle = @ptrCast([*c]const c.GLFWvidmode, modes)[i] };
|
||||
}
|
||||
return slice;
|
||||
}
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetVideoModes` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the current mode of the specified monitor.
|
||||
///
|
||||
/// This function returns the current video mode of the specified monitor. If you have created a
|
||||
/// full screen window for that monitor, the return value will depend on whether that window is
|
||||
/// iconified.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_modes, glfw.Monitor.getVideoModes
|
||||
pub inline fn getVideoMode(self: Monitor) error{PlatformError}!VideoMode {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetVideoMode(self.handle)) |mode| return VideoMode{ .handle = mode.* };
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetVideoMode` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Generates a gamma ramp and sets it for the specified monitor.
|
||||
///
|
||||
/// This function generates an appropriately sized gamma ramp from the specified exponent and then
|
||||
/// calls glfw.Monitor.setGammaRamp with it. The value must be a finite number greater than zero.
|
||||
///
|
||||
/// The software controlled gamma ramp is applied _in addition_ to the hardware gamma correction,
|
||||
/// which today is usually an approximation of sRGB gamma. This means that setting a perfectly
|
||||
/// linear ramp, or gamma 1.0, will produce the default (usually sRGB-like) behavior.
|
||||
///
|
||||
/// For gamma correct rendering with OpenGL or OpenGL ES, see the glfw.srgb_capable hint.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidValue and glfw.Error.PlatformError.
|
||||
///
|
||||
/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
|
||||
/// and emits glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_gamma
|
||||
pub inline fn setGamma(self: Monitor, gamma: f32) error{PlatformError}!void {
|
||||
internal_debug.assertInitialized();
|
||||
|
||||
std.debug.assert(!std.math.isNan(gamma));
|
||||
std.debug.assert(gamma >= 0);
|
||||
std.debug.assert(gamma <= std.math.f32_max);
|
||||
|
||||
c.glfwSetGamma(self.handle, gamma);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidValue => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the current gamma ramp for the specified monitor.
|
||||
///
|
||||
/// This function returns the current gamma ramp of the specified monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
|
||||
/// and returns glfw.Error.PlatformError.
|
||||
/// TODO: Is the documentation obsolete? On wayland the error returned is FeatureUnavailable
|
||||
///
|
||||
/// The returned gamma ramp is `.owned = true` by GLFW, and is valid until the monitor is
|
||||
/// disconnected, this function is called again, or `glfw.terminate()` is called.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_gamma
|
||||
pub inline fn getGammaRamp(self: Monitor) error{ PlatformError, FeatureUnavailable }!GammaRamp {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetGammaRamp(self.handle)) |ramp| return GammaRamp.fromC(ramp.*);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError, Error.FeatureUnavailable => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetGammaRamp` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Sets the current gamma ramp for the specified monitor.
|
||||
///
|
||||
/// This function sets the current gamma ramp for the specified monitor. The original gamma ramp
|
||||
/// for that monitor is saved by GLFW the first time this function is called and is restored by
|
||||
/// `glfw.terminate()`.
|
||||
///
|
||||
/// The software controlled gamma ramp is applied _in addition_ to the hardware gamma correction,
|
||||
/// which today is usually an approximation of sRGB gamma. This means that setting a perfectly
|
||||
/// linear ramp, or gamma 1.0, will produce the default (usually sRGB-like) behavior.
|
||||
///
|
||||
/// For gamma correct rendering with OpenGL or OpenGL ES, see the glfw.srgb_capable hint.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// The size of the specified gamma ramp should match the size of the current ramp for that
|
||||
/// monitor. On win32, the gamma ramp size must be 256.
|
||||
///
|
||||
/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
|
||||
/// and emits glfw.Error.PlatformError.
|
||||
///
|
||||
/// @pointer_lifetime The specified gamma ramp is copied before this function returns.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_gamma
|
||||
pub inline fn setGammaRamp(self: Monitor, ramp: GammaRamp) error{PlatformError}!void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwSetGammaRamp(self.handle, &ramp.toC());
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the currently connected monitors.
|
||||
///
|
||||
/// This function returns a slice of all currently connected monitors. The primary monitor is
|
||||
/// always first. If no monitors were found, this function returns an empty slice.
|
||||
///
|
||||
/// The returned slice memory is owned by the caller. The underlying handles are owned by GLFW, and
|
||||
/// are valid until the monitor configuration changes or `glfw.terminate` is called.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_monitors, monitor_event, glfw.monitor.getPrimary
|
||||
pub inline fn getAll(allocator: mem.Allocator) mem.Allocator.Error![]Monitor {
|
||||
internal_debug.assertInitialized();
|
||||
var count: c_int = 0;
|
||||
if (c.glfwGetMonitors(&count)) |monitors| {
|
||||
const slice = try allocator.alloc(Monitor, @intCast(u32, count));
|
||||
var i: u32 = 0;
|
||||
while (i < count) : (i += 1) {
|
||||
slice[i] = Monitor{ .handle = @ptrCast([*c]const ?*c.GLFWmonitor, monitors)[i].? };
|
||||
}
|
||||
return slice;
|
||||
}
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetMonitors` returning null can be either an error or no monitors
|
||||
return &[_]Monitor{};
|
||||
}
|
||||
|
||||
/// Returns the primary monitor.
|
||||
///
|
||||
/// This function returns the primary monitor. This is usually the monitor where elements like
|
||||
/// the task bar or global menu bar are located.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_monitors, glfw.monitors.getAll
|
||||
pub inline fn getPrimary() ?Monitor {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetPrimaryMonitor()) |handle| return Monitor{ .handle = handle };
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Describes an event relating to a monitor.
|
||||
pub const Event = enum(c_int) {
|
||||
/// The device was connected.
|
||||
connected = c.GLFW_CONNECTED,
|
||||
|
||||
/// The device was disconnected.
|
||||
disconnected = c.GLFW_DISCONNECTED,
|
||||
};
|
||||
|
||||
/// Sets the monitor configuration callback.
|
||||
///
|
||||
/// This function sets the monitor configuration callback, or removes the currently set callback.
|
||||
/// This is called when a monitor is connected to or disconnected from the system. Example:
|
||||
///
|
||||
/// ```
|
||||
/// fn monitorCallback(monitor: glfw.Monitor, event: glfw.Monitor.Event, data: *MyData) void {
|
||||
/// // data is the pointer you passed into setCallback.
|
||||
/// // event is one of .connected or .disconnected
|
||||
/// }
|
||||
/// ...
|
||||
/// glfw.Monitor.setCallback(MyData, &myData, monitorCallback)
|
||||
/// ```
|
||||
///
|
||||
/// `event` may be one of .connected or .disconnected. More events may be added in the future.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: monitor_event
|
||||
pub inline fn setCallback(comptime callback: ?fn (monitor: Monitor, event: Event) void) void {
|
||||
internal_debug.assertInitialized();
|
||||
|
||||
if (callback) |user_callback| {
|
||||
const CWrapper = struct {
|
||||
pub fn monitorCallbackWrapper(monitor: ?*c.GLFWmonitor, event: c_int) callconv(.C) void {
|
||||
@call(.{ .modifier = .always_inline }, user_callback, .{
|
||||
Monitor{ .handle = monitor.? },
|
||||
@intToEnum(Event, event),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (c.glfwSetMonitorCallback(CWrapper.monitorCallbackWrapper) != null) return;
|
||||
} else {
|
||||
if (c.glfwSetMonitorCallback(null) != null) return;
|
||||
}
|
||||
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
test "getAll" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const allocator = testing.allocator;
|
||||
const monitors = try getAll(allocator);
|
||||
defer allocator.free(monitors);
|
||||
}
|
||||
|
||||
test "getPrimary" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = getPrimary();
|
||||
}
|
||||
|
||||
test "getPos" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
_ = try m.getPos();
|
||||
}
|
||||
}
|
||||
|
||||
test "getWorkarea" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
_ = try m.getWorkarea();
|
||||
}
|
||||
}
|
||||
|
||||
test "getPhysicalSize" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
_ = m.getPhysicalSize();
|
||||
}
|
||||
}
|
||||
|
||||
test "getContentScale" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
_ = try m.getContentScale();
|
||||
}
|
||||
}
|
||||
|
||||
test "getName" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
_ = m.getName();
|
||||
}
|
||||
}
|
||||
|
||||
test "userPointer" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
var p = m.getUserPointer(u32);
|
||||
try testing.expect(p == null);
|
||||
var x: u32 = 5;
|
||||
m.setUserPointer(u32, &x);
|
||||
p = m.getUserPointer(u32);
|
||||
try testing.expectEqual(p.?.*, 5);
|
||||
}
|
||||
}
|
||||
|
||||
test "setCallback" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
setCallback(struct {
|
||||
fn callback(monitor: Monitor, event: Event) void {
|
||||
_ = monitor;
|
||||
_ = event;
|
||||
}
|
||||
}.callback);
|
||||
}
|
||||
|
||||
test "getVideoModes" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
const allocator = testing.allocator;
|
||||
const modes = try m.getVideoModes(allocator);
|
||||
defer allocator.free(modes);
|
||||
}
|
||||
}
|
||||
|
||||
test "getVideoMode" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
_ = try m.getVideoMode();
|
||||
}
|
||||
}
|
||||
|
||||
test "set_getGammaRamp" {
|
||||
const allocator = testing.allocator;
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const monitor = getPrimary();
|
||||
if (monitor) |m| {
|
||||
const ramp = m.getGammaRamp() catch |err| {
|
||||
std.debug.print("can't get window position, wayland maybe? error={}\n", .{err});
|
||||
return;
|
||||
};
|
||||
|
||||
// Set it to the exact same value; if we do otherwise an our tests fail it wouldn't call
|
||||
// terminate and our made-up gamma ramp would get stuck.
|
||||
try m.setGammaRamp(ramp);
|
||||
|
||||
// technically not needed here / noop because GLFW owns this gamma ramp.
|
||||
defer ramp.deinit(allocator);
|
||||
}
|
||||
}
|
||||
50
libs/glfw/src/VideoMode.zig
Normal file
50
libs/glfw/src/VideoMode.zig
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
//! Monitor video modes and related functions
|
||||
//!
|
||||
//! see also: glfw.Monitor.getVideoMode
|
||||
|
||||
const std = @import("std");
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
const VideoMode = @This();
|
||||
|
||||
handle: c.GLFWvidmode,
|
||||
|
||||
/// Returns the width of the video mode, in screen coordinates.
|
||||
pub inline fn getWidth(self: VideoMode) u32 {
|
||||
return @intCast(u32, self.handle.width);
|
||||
}
|
||||
|
||||
/// Returns the height of the video mode, in screen coordinates.
|
||||
pub inline fn getHeight(self: VideoMode) u32 {
|
||||
return @intCast(u32, self.handle.height);
|
||||
}
|
||||
|
||||
/// Returns the bit depth of the red channel of the video mode.
|
||||
pub inline fn getRedBits(self: VideoMode) u32 {
|
||||
return @intCast(u32, self.handle.redBits);
|
||||
}
|
||||
|
||||
/// Returns the bit depth of the green channel of the video mode.
|
||||
pub inline fn getGreenBits(self: VideoMode) u32 {
|
||||
return @intCast(u32, self.handle.greenBits);
|
||||
}
|
||||
|
||||
/// Returns the bit depth of the blue channel of the video mode.
|
||||
pub inline fn getBlueBits(self: VideoMode) u32 {
|
||||
return @intCast(u32, self.handle.blueBits);
|
||||
}
|
||||
|
||||
/// Returns the refresh rate of the video mode, in Hz.
|
||||
pub inline fn getRefreshRate(self: VideoMode) u32 {
|
||||
return @intCast(u32, self.handle.refreshRate);
|
||||
}
|
||||
|
||||
test "getters" {
|
||||
const x = std.mem.zeroes(VideoMode);
|
||||
_ = x.getWidth();
|
||||
_ = x.getHeight();
|
||||
_ = x.getRedBits();
|
||||
_ = x.getGreenBits();
|
||||
_ = x.getBlueBits();
|
||||
_ = x.getRefreshRate();
|
||||
}
|
||||
3684
libs/glfw/src/Window.zig
Normal file
3684
libs/glfw/src/Window.zig
Normal file
File diff suppressed because it is too large
Load diff
13
libs/glfw/src/action.zig
Normal file
13
libs/glfw/src/action.zig
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const c = @import("c.zig").c;
|
||||
|
||||
/// Key and button actions
|
||||
pub const Action = enum(c_int) {
|
||||
/// The key or mouse button was released.
|
||||
release = c.GLFW_RELEASE,
|
||||
|
||||
/// The key or mouse button was pressed.
|
||||
press = c.GLFW_PRESS,
|
||||
|
||||
/// The key was held down until it repeated.
|
||||
repeat = c.GLFW_REPEAT,
|
||||
};
|
||||
143
libs/glfw/src/allocator.zig
Normal file
143
libs/glfw/src/allocator.zig
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
// TODO: implement custom allocator support
|
||||
|
||||
// /*! @brief
|
||||
// *
|
||||
// * @sa @ref init_allocator
|
||||
// * @sa @ref glfwInitAllocator
|
||||
// *
|
||||
// * @since Added in version 3.4.
|
||||
// *
|
||||
// * @ingroup init
|
||||
// */
|
||||
// typedef struct GLFWallocator
|
||||
// {
|
||||
// GLFWallocatefun allocate;
|
||||
// GLFWreallocatefun reallocate;
|
||||
// GLFWdeallocatefun deallocate;
|
||||
// void* user;
|
||||
// } GLFWallocator;
|
||||
|
||||
// /*! @brief The function pointer type for memory allocation callbacks.
|
||||
// *
|
||||
// * This is the function pointer type for memory allocation callbacks. A memory
|
||||
// * allocation callback function has the following signature:
|
||||
// * @code
|
||||
// * void* function_name(size_t size, void* user)
|
||||
// * @endcode
|
||||
// *
|
||||
// * This function must return either a memory block at least `size` bytes long,
|
||||
// * or `NULL` if allocation failed. Note that not all parts of GLFW handle allocation
|
||||
// * failures gracefully yet.
|
||||
// *
|
||||
// * This function may be called during @ref glfwInit but before the library is
|
||||
// * flagged as initialized, as well as during @ref glfwTerminate after the
|
||||
// * library is no longer flagged as initialized.
|
||||
// *
|
||||
// * Any memory allocated by this function will be deallocated during library
|
||||
// * termination or earlier.
|
||||
// *
|
||||
// * The size will always be greater than zero. Allocations of size zero are filtered out
|
||||
// * before reaching the custom allocator.
|
||||
// *
|
||||
// * @param[in] size The minimum size, in bytes, of the memory block.
|
||||
// * @param[in] user The user-defined pointer from the allocator.
|
||||
// * @return The address of the newly allocated memory block, or `NULL` if an
|
||||
// * error occurred.
|
||||
// *
|
||||
// * @pointer_lifetime The returned memory block must be valid at least until it
|
||||
// * is deallocated.
|
||||
// *
|
||||
// * @reentrancy This function should not call any GLFW function.
|
||||
// *
|
||||
// * @thread_safety This function may be called from any thread that calls GLFW functions.
|
||||
// *
|
||||
// * @sa @ref init_allocator
|
||||
// * @sa @ref GLFWallocator
|
||||
// *
|
||||
// * @since Added in version 3.4.
|
||||
// *
|
||||
// * @ingroup init
|
||||
// */
|
||||
// typedef void* (* GLFWallocatefun)(size_t size, void* user);
|
||||
|
||||
// /*! @brief The function pointer type for memory reallocation callbacks.
|
||||
// *
|
||||
// * This is the function pointer type for memory reallocation callbacks.
|
||||
// * A memory reallocation callback function has the following signature:
|
||||
// * @code
|
||||
// * void* function_name(void* block, size_t size, void* user)
|
||||
// * @endcode
|
||||
// *
|
||||
// * This function must return a memory block at least `size` bytes long, or
|
||||
// * `NULL` if allocation failed. Note that not all parts of GLFW handle allocation
|
||||
// * failures gracefully yet.
|
||||
// *
|
||||
// * This function may be called during @ref glfwInit but before the library is
|
||||
// * flagged as initialized, as well as during @ref glfwTerminate after the
|
||||
// * library is no longer flagged as initialized.
|
||||
// *
|
||||
// * Any memory allocated by this function will be deallocated during library
|
||||
// * termination or earlier.
|
||||
// *
|
||||
// * The block address will never be `NULL` and the size will always be greater than zero.
|
||||
// * Reallocations of a block to size zero are converted into deallocations. Reallocations
|
||||
// * of `NULL` to a non-zero size are converted into regular allocations.
|
||||
// *
|
||||
// * @param[in] block The address of the memory block to reallocate.
|
||||
// * @param[in] size The new minimum size, in bytes, of the memory block.
|
||||
// * @param[in] user The user-defined pointer from the allocator.
|
||||
// * @return The address of the newly allocated or resized memory block, or
|
||||
// * `NULL` if an error occurred.
|
||||
// *
|
||||
// * @pointer_lifetime The returned memory block must be valid at least until it
|
||||
// * is deallocated.
|
||||
// *
|
||||
// * @reentrancy This function should not call any GLFW function.
|
||||
// *
|
||||
// * @thread_safety This function may be called from any thread that calls GLFW functions.
|
||||
// *
|
||||
// * @sa @ref init_allocator
|
||||
// * @sa @ref GLFWallocator
|
||||
// *
|
||||
// * @since Added in version 3.4.
|
||||
// *
|
||||
// * @ingroup init
|
||||
// */
|
||||
// typedef void* (* GLFWreallocatefun)(void* block, size_t size, void* user);
|
||||
|
||||
// /*! @brief The function pointer type for memory deallocation callbacks.
|
||||
// *
|
||||
// * This is the function pointer type for memory deallocation callbacks.
|
||||
// * A memory deallocation callback function has the following signature:
|
||||
// * @code
|
||||
// * void function_name(void* block, void* user)
|
||||
// * @endcode
|
||||
// *
|
||||
// * This function may deallocate the specified memory block. This memory block
|
||||
// * will have been allocated with the same allocator.
|
||||
// *
|
||||
// * This function may be called during @ref glfwInit but before the library is
|
||||
// * flagged as initialized, as well as during @ref glfwTerminate after the
|
||||
// * library is no longer flagged as initialized.
|
||||
// *
|
||||
// * The block address will never be `NULL`. Deallocations of `NULL` are filtered out
|
||||
// * before reaching the custom allocator.
|
||||
// *
|
||||
// * @param[in] block The address of the memory block to deallocate.
|
||||
// * @param[in] user The user-defined pointer from the allocator.
|
||||
// *
|
||||
// * @pointer_lifetime The specified memory block will not be accessed by GLFW
|
||||
// * after this function is called.
|
||||
// *
|
||||
// * @reentrancy This function should not call any GLFW function.
|
||||
// *
|
||||
// * @thread_safety This function may be called from any thread that calls GLFW functions.
|
||||
// *
|
||||
// * @sa @ref init_allocator
|
||||
// * @sa @ref GLFWallocator
|
||||
// *
|
||||
// * @since Added in version 3.4.
|
||||
// *
|
||||
// * @ingroup init
|
||||
// */
|
||||
// typedef void (* GLFWdeallocatefun)(void* block, void* user);
|
||||
11
libs/glfw/src/c.zig
Normal file
11
libs/glfw/src/c.zig
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
pub const c = if (@import("builtin").zig_backend == .stage1)
|
||||
@cImport({
|
||||
@cDefine("GLFW_INCLUDE_VULKAN", "1");
|
||||
@cInclude("GLFW/glfw3.h");
|
||||
})
|
||||
else
|
||||
// TODO(self-hosted): HACK: workaround https://github.com/ziglang/zig/issues/12483
|
||||
//
|
||||
// Extracted from a build using stage1 from zig-cache/ (`cimport.zig`)
|
||||
// Then find+replace `= ?fn` -> `= ?*const fn`
|
||||
@import("cimport2.zig");
|
||||
65914
libs/glfw/src/cimport1.zig
Normal file
65914
libs/glfw/src/cimport1.zig
Normal file
File diff suppressed because it is too large
Load diff
15045
libs/glfw/src/cimport2.zig
Normal file
15045
libs/glfw/src/cimport2.zig
Normal file
File diff suppressed because it is too large
Load diff
75
libs/glfw/src/clipboard.zig
Normal file
75
libs/glfw/src/clipboard.zig
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
/// Sets the clipboard to the specified string.
|
||||
///
|
||||
/// This function sets the system clipboard to the specified, UTF-8 encoded string.
|
||||
///
|
||||
/// @param[in] string A UTF-8 encoded string.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @pointer_lifetime The specified string is copied before this function returns.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: clipboard, glfwGetClipboardString
|
||||
pub inline fn setClipboardString(value: [*:0]const u8) error{PlatformError}!void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwSetClipboardString(null, value);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the contents of the clipboard as a string.
|
||||
///
|
||||
/// This function returns the contents of the system clipboard, if it contains or is convertible to
|
||||
/// a UTF-8 encoded string. If the clipboard is empty or if its contents cannot be converted,
|
||||
/// glfw.Error.FormatUnavailable is returned.
|
||||
///
|
||||
/// @return The contents of the clipboard as a UTF-8 encoded string.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.FormatUnavailable and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the next call to glfw.getClipboardString or glfw.setClipboardString
|
||||
/// or until the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: clipboard, glfwSetClipboardString
|
||||
pub inline fn getClipboardString() error{ FormatUnavailable, PlatformError }![:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetClipboardString(null)) |c_str| return std.mem.span(@ptrCast([*:0]const u8, c_str));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.FormatUnavailable, Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetClipboardString` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
test "setClipboardString" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
try glfw.setClipboardString("hello mach");
|
||||
}
|
||||
|
||||
test "getClipboardString" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.getClipboardString() catch |err| std.debug.print("can't get clipboard, not supported by OS? error={}\n", .{err});
|
||||
}
|
||||
274
libs/glfw/src/errors.zig
Normal file
274
libs/glfw/src/errors.zig
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
//! Errors
|
||||
|
||||
const testing = @import("std").testing;
|
||||
const mem = @import("std").mem;
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
/// Errors that GLFW can produce.
|
||||
pub const Error = error{
|
||||
/// GLFW has not been initialized.
|
||||
///
|
||||
/// This occurs if a GLFW function was called that must not be called unless the library is
|
||||
/// initialized.
|
||||
NotInitialized,
|
||||
|
||||
/// No context is current for this thread.
|
||||
///
|
||||
/// This occurs if a GLFW function was called that needs and operates on the current OpenGL or
|
||||
/// OpenGL ES context but no context is current on the calling thread. One such function is
|
||||
/// glfw.SwapInterval.
|
||||
NoCurrentContext,
|
||||
|
||||
/// One of the arguments to the function was an invalid enum value.
|
||||
///
|
||||
/// One of the arguments to the function was an invalid enum value, for example requesting
|
||||
/// glfw.red_bits with glfw.getWindowAttrib.
|
||||
InvalidEnum,
|
||||
|
||||
/// One of the arguments to the function was an invalid value.
|
||||
///
|
||||
/// One of the arguments to the function was an invalid value, for example requesting a
|
||||
/// non-existent OpenGL or OpenGL ES version like 2.7.
|
||||
///
|
||||
/// Requesting a valid but unavailable OpenGL or OpenGL ES version will instead result in a
|
||||
/// glfw.Error.VersionUnavailable error.
|
||||
InvalidValue,
|
||||
|
||||
/// A memory allocation failed.
|
||||
OutOfMemory,
|
||||
|
||||
/// GLFW could not find support for the requested API on the system.
|
||||
///
|
||||
/// The installed graphics driver does not support the requested API, or does not support it
|
||||
/// via the chosen context creation API. Below are a few examples.
|
||||
///
|
||||
/// Some pre-installed Windows graphics drivers do not support OpenGL. AMD only supports
|
||||
/// OpenGL ES via EGL, while Nvidia and Intel only support it via a WGL or GLX extension. macOS
|
||||
/// does not provide OpenGL ES at all. The Mesa EGL, OpenGL and OpenGL ES libraries do not
|
||||
/// interface with the Nvidia binary driver. Older graphics drivers do not support Vulkan.
|
||||
APIUnavailable,
|
||||
|
||||
/// The requested OpenGL or OpenGL ES version (including any requested context or framebuffer
|
||||
/// hints) is not available on this machine.
|
||||
///
|
||||
/// The machine does not support your requirements. If your application is sufficiently
|
||||
/// flexible, downgrade your requirements and try again. Otherwise, inform the user that their
|
||||
/// machine does not match your requirements.
|
||||
///
|
||||
/// Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 comes out
|
||||
/// before the 4.x series gets that far, also fail with this error and not glfw.Error.InvalidValue,
|
||||
/// because GLFW cannot know what future versions will exist.
|
||||
VersionUnavailable,
|
||||
|
||||
/// A platform-specific error occurred that does not match any of the more specific categories.
|
||||
///
|
||||
/// A bug or configuration error in GLFW, the underlying operating system or its drivers, or a
|
||||
/// lack of required resources. Report the issue to our [issue tracker](https://github.com/glfw/glfw/issues).
|
||||
PlatformError,
|
||||
|
||||
/// The requested format is not supported or available.
|
||||
///
|
||||
/// If emitted during window creation, the requested pixel format is not supported.
|
||||
///
|
||||
/// If emitted when querying the clipboard, the contents of the clipboard could not be
|
||||
/// converted to the requested format.
|
||||
///
|
||||
/// If emitted during window creation, one or more hard constraints did not match any of the
|
||||
/// available pixel formats. If your application is sufficiently flexible, downgrade your
|
||||
/// requirements and try again. Otherwise, inform the user that their machine does not match
|
||||
/// your requirements.
|
||||
///
|
||||
/// If emitted when querying the clipboard, ignore the error or report it to the user, as
|
||||
/// appropriate.
|
||||
FormatUnavailable,
|
||||
|
||||
/// The specified window does not have an OpenGL or OpenGL ES context.
|
||||
///
|
||||
/// A window that does not have an OpenGL or OpenGL ES context was passed to a function that
|
||||
/// requires it to have one.
|
||||
NoWindowContext,
|
||||
|
||||
/// The specified cursor shape is not available.
|
||||
///
|
||||
/// The specified standard cursor shape is not available, either because the
|
||||
/// current platform cursor theme does not provide it or because it is not
|
||||
/// available on the platform.
|
||||
///
|
||||
/// analysis: Platform or system settings limitation. Pick another standard cursor shape or
|
||||
/// create a custom cursor.
|
||||
CursorUnavailable,
|
||||
|
||||
/// The requested feature is not provided by the platform.
|
||||
///
|
||||
/// The requested feature is not provided by the platform, so GLFW is unable to
|
||||
/// implement it. The documentation for each function notes if it could emit
|
||||
/// this error.
|
||||
///
|
||||
/// analysis: Platform or platform version limitation. The error can be ignored
|
||||
/// unless the feature is critical to the application.
|
||||
///
|
||||
/// A function call that emits this error has no effect other than the error and
|
||||
/// updating any existing out parameters.
|
||||
///
|
||||
FeatureUnavailable,
|
||||
|
||||
/// The requested feature is not implemented for the platform.
|
||||
///
|
||||
/// The requested feature has not yet been implemented in GLFW for this platform.
|
||||
///
|
||||
/// analysis: An incomplete implementation of GLFW for this platform, hopefully
|
||||
/// fixed in a future release. The error can be ignored unless the feature is
|
||||
/// critical to the application.
|
||||
///
|
||||
/// A function call that emits this error has no effect other than the error and
|
||||
/// updating any existing out parameters.
|
||||
///
|
||||
FeatureUnimplemented,
|
||||
|
||||
/// Platform unavailable or no matching platform was found.
|
||||
///
|
||||
/// If emitted during initialization, no matching platform was found. If glfw.InitHint.platform
|
||||
/// is set to `.any_platform`, GLFW could not detect any of the platforms supported by this
|
||||
/// library binary, except for the Null platform. If set to a specific platform, it is either
|
||||
/// not supported by this library binary or GLFW was not able to detect it.
|
||||
///
|
||||
/// If emitted by a native access function, GLFW was initialized for a different platform
|
||||
/// than the function is for.
|
||||
///
|
||||
/// analysis: Failure to detect any platform usually only happens on non-macOS Unix
|
||||
/// systems, either when no window system is running or the program was run from
|
||||
/// a terminal that does not have the necessary environment variables. Fall back to
|
||||
/// a different platform if possible or notify the user that no usable platform was
|
||||
/// detected.
|
||||
///
|
||||
/// Failure to detect a specific platform may have the same cause as above or be because
|
||||
/// support for that platform was not compiled in. Call glfw.platformSupported to
|
||||
/// check whether a specific platform is supported by a library binary.
|
||||
///
|
||||
PlatformUnavailable,
|
||||
};
|
||||
|
||||
fn convertError(e: c_int) Error!void {
|
||||
return switch (e) {
|
||||
c.GLFW_NO_ERROR => {},
|
||||
c.GLFW_NOT_INITIALIZED => Error.NotInitialized,
|
||||
c.GLFW_NO_CURRENT_CONTEXT => Error.NoCurrentContext,
|
||||
c.GLFW_INVALID_ENUM => Error.InvalidEnum,
|
||||
c.GLFW_INVALID_VALUE => Error.InvalidValue,
|
||||
c.GLFW_OUT_OF_MEMORY => Error.OutOfMemory,
|
||||
c.GLFW_API_UNAVAILABLE => Error.APIUnavailable,
|
||||
c.GLFW_VERSION_UNAVAILABLE => Error.VersionUnavailable,
|
||||
c.GLFW_PLATFORM_ERROR => Error.PlatformError,
|
||||
c.GLFW_FORMAT_UNAVAILABLE => Error.FormatUnavailable,
|
||||
c.GLFW_NO_WINDOW_CONTEXT => Error.NoWindowContext,
|
||||
c.GLFW_CURSOR_UNAVAILABLE => Error.CursorUnavailable,
|
||||
c.GLFW_FEATURE_UNAVAILABLE => Error.FeatureUnavailable,
|
||||
c.GLFW_FEATURE_UNIMPLEMENTED => Error.FeatureUnimplemented,
|
||||
c.GLFW_PLATFORM_UNAVAILABLE => Error.PlatformUnavailable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns and clears the last error for the calling thread.
|
||||
///
|
||||
/// This function returns and clears the error code of the last error that occurred on the calling
|
||||
/// thread, and optionally a UTF-8 encoded human-readable description of it. If no error has
|
||||
/// occurred since the last call, it returns GLFW_NO_ERROR (zero) and the description pointer is
|
||||
/// set to `NULL`.
|
||||
///
|
||||
/// * @param[in] description Where to store the error description pointer, or `NULL`.
|
||||
/// @return The last error code for the calling thread, or @ref GLFW_NO_ERROR (zero).
|
||||
///
|
||||
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is guaranteed to be valid only until the next error occurs or the library is
|
||||
/// terminated.
|
||||
///
|
||||
/// @remark This function may be called before @ref glfwInit.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
pub inline fn getError() Error!void {
|
||||
return convertError(c.glfwGetError(null));
|
||||
}
|
||||
|
||||
/// Returns and clears the last error description for the calling thread.
|
||||
///
|
||||
/// This function returns a UTF-8 encoded human-readable description of the last error that occured
|
||||
/// on the calling thread. If no error has occurred since the last call, it returns null.
|
||||
///
|
||||
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is guaranteed to be valid only until the next error occurs or the library is
|
||||
/// terminated.
|
||||
///
|
||||
/// @remark This function may be called before @ref glfwInit.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
pub inline fn getErrorString() ?[]const u8 {
|
||||
var desc: [*c]const u8 = null;
|
||||
const error_code = c.glfwGetError(&desc);
|
||||
convertError(error_code) catch {
|
||||
return mem.sliceTo(desc, 0);
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Sets the error callback.
|
||||
///
|
||||
/// This function sets the error callback, which is called with an error code
|
||||
/// and a human-readable description each time a GLFW error occurs.
|
||||
///
|
||||
/// The error code is set before the callback is called. Calling @ref
|
||||
/// glfwGetError from the error callback will return the same value as the error
|
||||
/// code argument.
|
||||
///
|
||||
/// The error callback is called on the thread where the error occurred. If you
|
||||
/// are using GLFW from multiple threads, your error callback needs to be
|
||||
/// written accordingly.
|
||||
///
|
||||
/// Because the description string may have been generated specifically for that
|
||||
/// error, it is not guaranteed to be valid after the callback has returned. If
|
||||
/// you wish to use it after the callback returns, you need to make a copy.
|
||||
///
|
||||
/// Once set, the error callback remains set even after the library has been
|
||||
/// terminated.
|
||||
///
|
||||
/// @param[in] callback The new callback, or `NULL` to remove the currently set
|
||||
/// callback.
|
||||
///
|
||||
/// @callback_param `error_code` An error code. Future releases may add more error codes.
|
||||
/// @callback_param `description` A UTF-8 encoded string describing the error.
|
||||
///
|
||||
/// @errors None.
|
||||
///
|
||||
/// @remark This function may be called before @ref glfwInit.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
pub fn setErrorCallback(comptime callback: ?fn (error_code: Error, description: [:0]const u8) void) void {
|
||||
if (callback) |user_callback| {
|
||||
const CWrapper = struct {
|
||||
pub fn errorCallbackWrapper(err_int: c_int, c_description: [*c]const u8) callconv(.C) void {
|
||||
if (convertError(err_int)) |_| {
|
||||
// This means the error was `GLFW_NO_ERROR`
|
||||
return;
|
||||
} else |err| {
|
||||
user_callback(err, mem.sliceTo(c_description, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_ = c.glfwSetErrorCallback(CWrapper.errorCallbackWrapper);
|
||||
return;
|
||||
}
|
||||
|
||||
_ = c.glfwSetErrorCallback(null);
|
||||
}
|
||||
|
||||
test "errorCallback" {
|
||||
const TestStruct = struct {
|
||||
pub fn callback(_: Error, _: [:0]const u8) void {}
|
||||
};
|
||||
setErrorCallback(TestStruct.callback);
|
||||
}
|
||||
|
||||
test "error string" {
|
||||
try testing.expect(getErrorString() == null);
|
||||
}
|
||||
16
libs/glfw/src/gamepad_axis.zig
Normal file
16
libs/glfw/src/gamepad_axis.zig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
const c = @import("c.zig").c;
|
||||
|
||||
/// Gamepad axes.
|
||||
///
|
||||
/// See glfw.getGamepadState for how these are used.
|
||||
pub const GamepadAxis = enum(c_int) {
|
||||
left_x = c.GLFW_GAMEPAD_AXIS_LEFT_X,
|
||||
left_y = c.GLFW_GAMEPAD_AXIS_LEFT_Y,
|
||||
right_x = c.GLFW_GAMEPAD_AXIS_RIGHT_X,
|
||||
right_y = c.GLFW_GAMEPAD_AXIS_RIGHT_Y,
|
||||
left_trigger = c.GLFW_GAMEPAD_AXIS_LEFT_TRIGGER,
|
||||
right_trigger = c.GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER,
|
||||
};
|
||||
|
||||
/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
|
||||
pub const last = GamepadAxis.right_trigger;
|
||||
37
libs/glfw/src/gamepad_button.zig
Normal file
37
libs/glfw/src/gamepad_button.zig
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
const c = @import("c.zig").c;
|
||||
|
||||
/// Gamepad buttons.
|
||||
///
|
||||
/// See glfw.getGamepadState for how these are used.
|
||||
pub const GamepadButton = enum(c_int) {
|
||||
a = c.GLFW_GAMEPAD_BUTTON_A,
|
||||
b = c.GLFW_GAMEPAD_BUTTON_B,
|
||||
x = c.GLFW_GAMEPAD_BUTTON_X,
|
||||
y = c.GLFW_GAMEPAD_BUTTON_Y,
|
||||
left_bumper = c.GLFW_GAMEPAD_BUTTON_LEFT_BUMPER,
|
||||
right_bumper = c.GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER,
|
||||
back = c.GLFW_GAMEPAD_BUTTON_BACK,
|
||||
start = c.GLFW_GAMEPAD_BUTTON_START,
|
||||
guide = c.GLFW_GAMEPAD_BUTTON_GUIDE,
|
||||
left_thumb = c.GLFW_GAMEPAD_BUTTON_LEFT_THUMB,
|
||||
right_thumb = c.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB,
|
||||
dpad_up = c.GLFW_GAMEPAD_BUTTON_DPAD_UP,
|
||||
dpad_right = c.GLFW_GAMEPAD_BUTTON_DPAD_RIGHT,
|
||||
dpad_down = c.GLFW_GAMEPAD_BUTTON_DPAD_DOWN,
|
||||
dpad_left = c.GLFW_GAMEPAD_BUTTON_DPAD_LEFT,
|
||||
};
|
||||
|
||||
/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
|
||||
pub const last = GamepadButton.dpad_left;
|
||||
|
||||
/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
|
||||
pub const cross = GamepadButton.a;
|
||||
|
||||
/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
|
||||
pub const circle = GamepadButton.b;
|
||||
|
||||
/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
|
||||
pub const square = GamepadButton.x;
|
||||
|
||||
/// Not in the GamepadAxis enumeration as it is a duplicate value which is forbidden.
|
||||
pub const triangle = GamepadButton.y;
|
||||
100
libs/glfw/src/hat.zig
Normal file
100
libs/glfw/src/hat.zig
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
const c = @import("c.zig").c;
|
||||
|
||||
// must be in sync with GLFW C constants in hat state group, search for "@defgroup hat_state Joystick hat states"
|
||||
/// A bitmask of all Joystick hat states
|
||||
///
|
||||
/// See glfw.Joystick.getHats for how these are used.
|
||||
pub const Hat = packed struct {
|
||||
up: bool = false,
|
||||
right: bool = false,
|
||||
down: bool = false,
|
||||
left: bool = false,
|
||||
_reserved: u4 = 0,
|
||||
|
||||
pub inline fn centered(self: Hat) bool {
|
||||
return self.up == false and self.right == false and self.down == false and self.left == false;
|
||||
}
|
||||
|
||||
inline fn verifyIntType(comptime IntType: type) void {
|
||||
comptime {
|
||||
switch (@typeInfo(IntType)) {
|
||||
.Int => {},
|
||||
else => @compileError("Int was not of int type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub inline fn toInt(self: Hat, comptime IntType: type) IntType {
|
||||
verifyIntType(IntType);
|
||||
return @intCast(IntType, @bitCast(u8, self));
|
||||
}
|
||||
|
||||
pub inline fn fromInt(flags: anytype) Hat {
|
||||
verifyIntType(@TypeOf(flags));
|
||||
return @bitCast(Hat, @intCast(u8, flags));
|
||||
}
|
||||
};
|
||||
|
||||
/// Holds all GLFW hat values in their raw form.
|
||||
pub const RawHat = struct {
|
||||
pub const centered = c.GLFW_HAT_CENTERED;
|
||||
pub const up = c.GLFW_HAT_UP;
|
||||
pub const right = c.GLFW_HAT_RIGHT;
|
||||
pub const down = c.GLFW_HAT_DOWN;
|
||||
pub const left = c.GLFW_HAT_LEFT;
|
||||
|
||||
pub const right_up = right | up;
|
||||
pub const right_down = right | down;
|
||||
pub const left_up = left | up;
|
||||
pub const left_down = left | down;
|
||||
};
|
||||
|
||||
test "from int, single" {
|
||||
const std = @import("std");
|
||||
|
||||
try std.testing.expectEqual(Hat{
|
||||
.up = true,
|
||||
.right = false,
|
||||
.down = false,
|
||||
.left = false,
|
||||
._reserved = 0,
|
||||
}, Hat.fromInt(RawHat.up));
|
||||
}
|
||||
|
||||
test "from int, multi" {
|
||||
const std = @import("std");
|
||||
|
||||
try std.testing.expectEqual(Hat{
|
||||
.up = true,
|
||||
.right = false,
|
||||
.down = true,
|
||||
.left = true,
|
||||
._reserved = 0,
|
||||
}, Hat.fromInt(RawHat.up | RawHat.down | RawHat.left));
|
||||
}
|
||||
|
||||
test "to int, single" {
|
||||
const std = @import("std");
|
||||
|
||||
var v = Hat{
|
||||
.up = true,
|
||||
.right = false,
|
||||
.down = false,
|
||||
.left = false,
|
||||
._reserved = 0,
|
||||
};
|
||||
try std.testing.expectEqual(v.toInt(c_int), RawHat.up);
|
||||
}
|
||||
|
||||
test "to int, multi" {
|
||||
const std = @import("std");
|
||||
|
||||
var v = Hat{
|
||||
.up = true,
|
||||
.right = false,
|
||||
.down = true,
|
||||
.left = true,
|
||||
._reserved = 0,
|
||||
};
|
||||
try std.testing.expectEqual(v.toInt(c_int), RawHat.up | RawHat.down | RawHat.left);
|
||||
}
|
||||
14
libs/glfw/src/internal_debug.zig
Normal file
14
libs/glfw/src/internal_debug.zig
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
const std = @import("std");
|
||||
const zig_builtin = @import("builtin");
|
||||
|
||||
const debug_mode = (zig_builtin.mode == .Debug);
|
||||
var glfw_initialized = if (debug_mode) false else @as(void, {});
|
||||
pub inline fn toggleInitialized() void {
|
||||
if (debug_mode) glfw_initialized = !glfw_initialized;
|
||||
}
|
||||
pub inline fn assertInitialized() void {
|
||||
if (debug_mode) std.debug.assert(glfw_initialized);
|
||||
}
|
||||
pub inline fn assumeInitialized() void {
|
||||
glfw_initialized = true;
|
||||
}
|
||||
273
libs/glfw/src/key.zig
Normal file
273
libs/glfw/src/key.zig
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
//! Keyboard key IDs.
|
||||
//!
|
||||
//! See glfw.setKeyCallback for how these are used.
|
||||
//!
|
||||
//! These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), but re-arranged to
|
||||
//! map to 7-bit ASCII for printable keys (function keys are put in the 256+ range).
|
||||
//!
|
||||
//! The naming of the key codes follow these rules:
|
||||
//!
|
||||
//! - The US keyboard layout is used
|
||||
//! - Names of printable alphanumeric characters are used (e.g. "a", "r", "three", etc.)
|
||||
//! - For non-alphanumeric characters, Unicode:ish names are used (e.g. "comma", "left_bracket",
|
||||
//! etc.). Note that some names do not correspond to the Unicode standard (usually for brevity)
|
||||
//! - Keys that lack a clear US mapping are named "world_x"
|
||||
//! - For non-printable keys, custom names are used (e.g. "F4", "backspace", etc.)
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const cc = @import("c.zig").c;
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
/// enum containing all glfw keys
|
||||
pub const Key = enum(c_int) {
|
||||
/// The unknown key
|
||||
unknown = cc.GLFW_KEY_UNKNOWN,
|
||||
|
||||
/// Printable keys
|
||||
space = cc.GLFW_KEY_SPACE,
|
||||
apostrophe = cc.GLFW_KEY_APOSTROPHE,
|
||||
comma = cc.GLFW_KEY_COMMA,
|
||||
minus = cc.GLFW_KEY_MINUS,
|
||||
period = cc.GLFW_KEY_PERIOD,
|
||||
slash = cc.GLFW_KEY_SLASH,
|
||||
zero = cc.GLFW_KEY_0,
|
||||
one = cc.GLFW_KEY_1,
|
||||
two = cc.GLFW_KEY_2,
|
||||
three = cc.GLFW_KEY_3,
|
||||
four = cc.GLFW_KEY_4,
|
||||
five = cc.GLFW_KEY_5,
|
||||
six = cc.GLFW_KEY_6,
|
||||
seven = cc.GLFW_KEY_7,
|
||||
eight = cc.GLFW_KEY_8,
|
||||
nine = cc.GLFW_KEY_9,
|
||||
semicolon = cc.GLFW_KEY_SEMICOLON,
|
||||
equal = cc.GLFW_KEY_EQUAL,
|
||||
a = cc.GLFW_KEY_A,
|
||||
b = cc.GLFW_KEY_B,
|
||||
c = cc.GLFW_KEY_C,
|
||||
d = cc.GLFW_KEY_D,
|
||||
e = cc.GLFW_KEY_E,
|
||||
f = cc.GLFW_KEY_F,
|
||||
g = cc.GLFW_KEY_G,
|
||||
h = cc.GLFW_KEY_H,
|
||||
i = cc.GLFW_KEY_I,
|
||||
j = cc.GLFW_KEY_J,
|
||||
k = cc.GLFW_KEY_K,
|
||||
l = cc.GLFW_KEY_L,
|
||||
m = cc.GLFW_KEY_M,
|
||||
n = cc.GLFW_KEY_N,
|
||||
o = cc.GLFW_KEY_O,
|
||||
p = cc.GLFW_KEY_P,
|
||||
q = cc.GLFW_KEY_Q,
|
||||
r = cc.GLFW_KEY_R,
|
||||
s = cc.GLFW_KEY_S,
|
||||
t = cc.GLFW_KEY_T,
|
||||
u = cc.GLFW_KEY_U,
|
||||
v = cc.GLFW_KEY_V,
|
||||
w = cc.GLFW_KEY_W,
|
||||
x = cc.GLFW_KEY_X,
|
||||
y = cc.GLFW_KEY_Y,
|
||||
z = cc.GLFW_KEY_Z,
|
||||
left_bracket = cc.GLFW_KEY_LEFT_BRACKET,
|
||||
backslash = cc.GLFW_KEY_BACKSLASH,
|
||||
right_bracket = cc.GLFW_KEY_RIGHT_BRACKET,
|
||||
grave_accent = cc.GLFW_KEY_GRAVE_ACCENT,
|
||||
world_1 = cc.GLFW_KEY_WORLD_1, // non-US #1
|
||||
world_2 = cc.GLFW_KEY_WORLD_2, // non-US #2
|
||||
|
||||
// Function keys
|
||||
escape = cc.GLFW_KEY_ESCAPE,
|
||||
enter = cc.GLFW_KEY_ENTER,
|
||||
tab = cc.GLFW_KEY_TAB,
|
||||
backspace = cc.GLFW_KEY_BACKSPACE,
|
||||
insert = cc.GLFW_KEY_INSERT,
|
||||
delete = cc.GLFW_KEY_DELETE,
|
||||
right = cc.GLFW_KEY_RIGHT,
|
||||
left = cc.GLFW_KEY_LEFT,
|
||||
down = cc.GLFW_KEY_DOWN,
|
||||
up = cc.GLFW_KEY_UP,
|
||||
page_up = cc.GLFW_KEY_PAGE_UP,
|
||||
page_down = cc.GLFW_KEY_PAGE_DOWN,
|
||||
home = cc.GLFW_KEY_HOME,
|
||||
end = cc.GLFW_KEY_END,
|
||||
caps_lock = cc.GLFW_KEY_CAPS_LOCK,
|
||||
scroll_lock = cc.GLFW_KEY_SCROLL_LOCK,
|
||||
num_lock = cc.GLFW_KEY_NUM_LOCK,
|
||||
print_screen = cc.GLFW_KEY_PRINT_SCREEN,
|
||||
pause = cc.GLFW_KEY_PAUSE,
|
||||
F1 = cc.GLFW_KEY_F1,
|
||||
F2 = cc.GLFW_KEY_F2,
|
||||
F3 = cc.GLFW_KEY_F3,
|
||||
F4 = cc.GLFW_KEY_F4,
|
||||
F5 = cc.GLFW_KEY_F5,
|
||||
F6 = cc.GLFW_KEY_F6,
|
||||
F7 = cc.GLFW_KEY_F7,
|
||||
F8 = cc.GLFW_KEY_F8,
|
||||
F9 = cc.GLFW_KEY_F9,
|
||||
F10 = cc.GLFW_KEY_F10,
|
||||
F11 = cc.GLFW_KEY_F11,
|
||||
F12 = cc.GLFW_KEY_F12,
|
||||
F13 = cc.GLFW_KEY_F13,
|
||||
F14 = cc.GLFW_KEY_F14,
|
||||
F15 = cc.GLFW_KEY_F15,
|
||||
F16 = cc.GLFW_KEY_F16,
|
||||
F17 = cc.GLFW_KEY_F17,
|
||||
F18 = cc.GLFW_KEY_F18,
|
||||
F19 = cc.GLFW_KEY_F19,
|
||||
F20 = cc.GLFW_KEY_F20,
|
||||
F21 = cc.GLFW_KEY_F21,
|
||||
F22 = cc.GLFW_KEY_F22,
|
||||
F23 = cc.GLFW_KEY_F23,
|
||||
F24 = cc.GLFW_KEY_F24,
|
||||
F25 = cc.GLFW_KEY_F25,
|
||||
kp_0 = cc.GLFW_KEY_KP_0,
|
||||
kp_1 = cc.GLFW_KEY_KP_1,
|
||||
kp_2 = cc.GLFW_KEY_KP_2,
|
||||
kp_3 = cc.GLFW_KEY_KP_3,
|
||||
kp_4 = cc.GLFW_KEY_KP_4,
|
||||
kp_5 = cc.GLFW_KEY_KP_5,
|
||||
kp_6 = cc.GLFW_KEY_KP_6,
|
||||
kp_7 = cc.GLFW_KEY_KP_7,
|
||||
kp_8 = cc.GLFW_KEY_KP_8,
|
||||
kp_9 = cc.GLFW_KEY_KP_9,
|
||||
kp_decimal = cc.GLFW_KEY_KP_DECIMAL,
|
||||
kp_divide = cc.GLFW_KEY_KP_DIVIDE,
|
||||
kp_multiply = cc.GLFW_KEY_KP_MULTIPLY,
|
||||
kp_subtract = cc.GLFW_KEY_KP_SUBTRACT,
|
||||
kp_add = cc.GLFW_KEY_KP_ADD,
|
||||
kp_enter = cc.GLFW_KEY_KP_ENTER,
|
||||
kp_equal = cc.GLFW_KEY_KP_EQUAL,
|
||||
left_shift = cc.GLFW_KEY_LEFT_SHIFT,
|
||||
left_control = cc.GLFW_KEY_LEFT_CONTROL,
|
||||
left_alt = cc.GLFW_KEY_LEFT_ALT,
|
||||
left_super = cc.GLFW_KEY_LEFT_SUPER,
|
||||
right_shift = cc.GLFW_KEY_RIGHT_SHIFT,
|
||||
right_control = cc.GLFW_KEY_RIGHT_CONTROL,
|
||||
right_alt = cc.GLFW_KEY_RIGHT_ALT,
|
||||
right_super = cc.GLFW_KEY_RIGHT_SUPER,
|
||||
menu = cc.GLFW_KEY_MENU,
|
||||
|
||||
pub inline fn last() Key {
|
||||
return @intToEnum(Key, cc.GLFW_KEY_LAST);
|
||||
}
|
||||
|
||||
/// Returns the layout-specific name of the specified printable key.
|
||||
///
|
||||
/// This function returns the name of the specified printable key, encoded as UTF-8. This is
|
||||
/// typically the character that key would produce without any modifier keys, intended for
|
||||
/// displaying key bindings to the user. For dead keys, it is typically the diacritic it would add
|
||||
/// to a character.
|
||||
///
|
||||
/// __Do not use this function__ for text input (see input_char). You will break text input for many
|
||||
/// languages even if it happens to work for yours.
|
||||
///
|
||||
/// If the key is `glfw.key.unknown`, the scancode is used to identify the key, otherwise the
|
||||
/// scancode is ignored. If you specify a non-printable key, or `glfw.key.unknown` and a scancode
|
||||
/// that maps to a non-printable key, this function returns null but does not emit an error.
|
||||
///
|
||||
/// This behavior allows you to always pass in the arguments in the key callback (see input_key)
|
||||
/// without modification.
|
||||
///
|
||||
/// The printable keys are:
|
||||
///
|
||||
/// - `glfw.Key.apostrophe`
|
||||
/// - `glfw.Key.comma`
|
||||
/// - `glfw.Key.minus`
|
||||
/// - `glfw.Key.period`
|
||||
/// - `glfw.Key.slash`
|
||||
/// - `glfw.Key.semicolon`
|
||||
/// - `glfw.Key.equal`
|
||||
/// - `glfw.Key.left_bracket`
|
||||
/// - `glfw.Key.right_bracket`
|
||||
/// - `glfw.Key.backslash`
|
||||
/// - `glfw.Key.world_1`
|
||||
/// - `glfw.Key.world_2`
|
||||
/// - `glfw.Key.0` to `glfw.key.9`
|
||||
/// - `glfw.Key.a` to `glfw.key.z`
|
||||
/// - `glfw.Key.kp_0` to `glfw.key.kp_9`
|
||||
/// - `glfw.Key.kp_decimal`
|
||||
/// - `glfw.Key.kp_divide`
|
||||
/// - `glfw.Key.kp_multiply`
|
||||
/// - `glfw.Key.kp_subtract`
|
||||
/// - `glfw.Key.kp_add`
|
||||
/// - `glfw.Key.kp_equal`
|
||||
///
|
||||
/// Names for printable keys depend on keyboard layout, while names for non-printable keys are the
|
||||
/// same across layouts but depend on the application language and should be localized along with
|
||||
/// other user interface text.
|
||||
///
|
||||
/// @param[in] key The key to query, or `glfw.key.unknown`.
|
||||
/// @param[in] scancode The scancode of the key to query.
|
||||
/// @return The UTF-8 encoded, layout-specific name of the key, or null.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// The contents of the returned string may change when a keyboard layout change event is received.
|
||||
///
|
||||
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: input_key_name
|
||||
pub inline fn getName(self: Key, scancode: i32) error{PlatformError}!?[:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
const name_opt = cc.glfwGetKeyName(@enumToInt(self), @intCast(c_int, scancode));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return if (name_opt) |name|
|
||||
std.mem.span(@ptrCast([*:0]const u8, name))
|
||||
else
|
||||
null;
|
||||
}
|
||||
|
||||
/// Returns the platform-specific scancode of the specified key.
|
||||
///
|
||||
/// This function returns the platform-specific scancode of the specified key.
|
||||
///
|
||||
/// If the key is `glfw.key.UNKNOWN` or does not exist on the keyboard this method will return `-1`.
|
||||
///
|
||||
/// @param[in] key Any named key (see keys).
|
||||
/// @return The platform-specific scancode for the key.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidEnum and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
pub inline fn getScancode(self: Key) error{PlatformError}!i32 {
|
||||
internal_debug.assertInitialized();
|
||||
const scancode = cc.glfwGetKeyScancode(@enumToInt(self));
|
||||
if (scancode != -1) return scancode;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetKeyScancode` returns `-1` only for errors
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: https://github.com/hexops/mach/issues/375
|
||||
// test "getName" {
|
||||
// const glfw = @import("main.zig");
|
||||
// try glfw.init(.{});
|
||||
// defer glfw.terminate();
|
||||
|
||||
// _ = glfw.Key.a.getName(0) catch |err| std.debug.print("failed to get key name, not supported? error={}\n", .{err});
|
||||
// }
|
||||
|
||||
test "getScancode" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.Key.a.getScancode() catch |err| std.debug.print("failed to get key scancode, not supported? error={}\n", .{err});
|
||||
}
|
||||
580
libs/glfw/src/main.zig
Normal file
580
libs/glfw/src/main.zig
Normal file
|
|
@ -0,0 +1,580 @@
|
|||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
const key = @import("key.zig");
|
||||
|
||||
/// Possible value for various window hints, etc.
|
||||
pub const dont_care = c.GLFW_DONT_CARE;
|
||||
|
||||
const errors = @import("errors.zig");
|
||||
const getError = errors.getError;
|
||||
pub const setErrorCallback = errors.setErrorCallback;
|
||||
pub const Error = errors.Error;
|
||||
|
||||
pub const Action = @import("action.zig").Action;
|
||||
pub const GamepadAxis = @import("gamepad_axis.zig").GamepadAxis;
|
||||
pub const GamepadButton = @import("gamepad_button.zig").GamepadButton;
|
||||
pub const gamepad_axis = @import("gamepad_axis.zig");
|
||||
pub const gamepad_button = @import("gamepad_button.zig");
|
||||
pub const GammaRamp = @import("GammaRamp.zig");
|
||||
pub const Image = @import("Image.zig");
|
||||
pub const Joystick = @import("Joystick.zig");
|
||||
pub const Monitor = @import("Monitor.zig");
|
||||
pub const mouse_button = @import("mouse_button.zig");
|
||||
pub const MouseButton = mouse_button.MouseButton;
|
||||
pub const version = @import("version.zig");
|
||||
pub const VideoMode = @import("VideoMode.zig");
|
||||
pub const Window = @import("Window.zig");
|
||||
pub const Cursor = @import("Cursor.zig");
|
||||
pub const Native = @import("native.zig").Native;
|
||||
pub const BackendOptions = @import("native.zig").BackendOptions;
|
||||
pub const Key = key.Key;
|
||||
|
||||
pub usingnamespace @import("clipboard.zig");
|
||||
pub usingnamespace @import("opengl.zig");
|
||||
pub usingnamespace @import("vulkan.zig");
|
||||
pub usingnamespace @import("time.zig");
|
||||
pub usingnamespace @import("hat.zig");
|
||||
pub usingnamespace @import("mod.zig");
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
/// If GLFW was already initialized in your program, e.g. you are embedding Zig code into an existing
|
||||
/// program that has already called glfwInit via the C API for you - then you need to tell mach/glfw
|
||||
/// that it has in fact been initialized already, otherwise when you call other methods mach/glfw
|
||||
/// would panic thinking glfw.init has not been called yet.
|
||||
pub fn assumeInitialized() void {
|
||||
internal_debug.assumeInitialized();
|
||||
}
|
||||
|
||||
/// Initializes the GLFW library.
|
||||
///
|
||||
/// This function initializes the GLFW library. Before most GLFW functions can be used, GLFW must
|
||||
/// be initialized, and before an application terminates GLFW should be terminated in order to free
|
||||
/// any resources allocated during or after initialization.
|
||||
///
|
||||
/// If this function fails, it calls glfw.Terminate before returning. If it succeeds, you should
|
||||
/// call glfw.Terminate before the application exits.
|
||||
///
|
||||
/// Additional calls to this function after successful initialization but before termination will
|
||||
/// return immediately with no error.
|
||||
///
|
||||
/// The glfw.InitHint.platform init hint controls which platforms are considered during
|
||||
/// initialization. This also depends on which platforms the library was compiled to support.
|
||||
///
|
||||
/// macos: This function will change the current directory of the application to the
|
||||
/// `Contents/Resources` subdirectory of the application's bundle, if present. This can be disabled
|
||||
/// with `glfw.InitHint.cocoa_chdir_resources`.
|
||||
///
|
||||
/// macos: This function will create the main menu and dock icon for the application. If GLFW finds
|
||||
/// a `MainMenu.nib` it is loaded and assumed to contain a menu bar. Otherwise a minimal menu bar is
|
||||
/// created manually with common commands like Hide, Quit and About. The About entry opens a minimal
|
||||
/// about dialog with information from the application's bundle. The menu bar and dock icon can be
|
||||
/// disabled entirely with `glfw.InitHint.cocoa_menubar`.
|
||||
///
|
||||
/// x11: This function will set the `LC_CTYPE` category of the application locale according to the
|
||||
/// current environment if that category is still "C". This is because the "C" locale breaks
|
||||
/// Unicode text input.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
pub inline fn init(hints: InitHints) error{ PlatformUnavailable, PlatformError }!void {
|
||||
internal_debug.toggleInitialized();
|
||||
internal_debug.assertInitialized();
|
||||
errdefer {
|
||||
internal_debug.assertInitialized();
|
||||
internal_debug.toggleInitialized();
|
||||
}
|
||||
|
||||
inline for (comptime std.meta.fieldNames(InitHints)) |field_name| {
|
||||
const init_hint = @field(InitHint, field_name);
|
||||
const init_value = @field(hints, field_name);
|
||||
if (@TypeOf(init_value) == PlatformType) {
|
||||
initHint(init_hint, @enumToInt(init_value));
|
||||
} else {
|
||||
initHint(init_hint, init_value);
|
||||
}
|
||||
}
|
||||
|
||||
if (c.glfwInit() == c.GLFW_TRUE) return;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.PlatformUnavailable => |e| e,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: implement custom allocator support
|
||||
//
|
||||
// /*! @brief Sets the init allocator to the desired value.
|
||||
// *
|
||||
// * To use the default allocator, call this function with a `NULL` argument.
|
||||
// *
|
||||
// * If you specify an allocator struct, every member must be a valid function
|
||||
// * pointer. If any member is `NULL`, this function emits @ref
|
||||
// * GLFW_INVALID_VALUE and the init allocator is unchanged.
|
||||
// *
|
||||
// * @param[in] allocator The allocator to use at the next initialization, or
|
||||
// * `NULL` to use the default one.
|
||||
// *
|
||||
// * @errors Possible errors include @ref GLFW_INVALID_VALUE.
|
||||
// *
|
||||
// * @pointer_lifetime The specified allocator is copied before this function
|
||||
// * returns.
|
||||
// *
|
||||
// * @thread_safety This function must only be called from the main thread.
|
||||
// *
|
||||
// * @sa @ref init_allocator
|
||||
// * @sa @ref glfwInit
|
||||
// *
|
||||
// * @since Added in version 3.4.
|
||||
// *
|
||||
// * @ingroup init
|
||||
// */
|
||||
// GLFWAPI void glfwInitAllocator(const GLFWallocator* allocator);
|
||||
|
||||
/// Terminates the GLFW library.
|
||||
///
|
||||
/// This function destroys all remaining windows and cursors, restores any modified gamma ramps
|
||||
/// and frees any other allocated resources. Once this function is called, you must again call
|
||||
/// glfw.init successfully before you will be able to use most GLFW functions.
|
||||
///
|
||||
/// If GLFW has been successfully initialized, this function should be called before the
|
||||
/// application exits. If initialization fails, there is no need to call this function, as it is
|
||||
/// called by glfw.init before it returns failure.
|
||||
///
|
||||
/// This function has no effect if GLFW is not initialized.
|
||||
///
|
||||
/// Possible errors include glfw.Error.PlatformError.
|
||||
///
|
||||
/// warning: The contexts of any remaining windows must not be current on any other thread when
|
||||
/// this function is called.
|
||||
///
|
||||
/// reentrancy: This function must not be called from a callback.
|
||||
///
|
||||
/// thread_safety: This function must only be called from the main thread.
|
||||
pub inline fn terminate() void {
|
||||
internal_debug.assertInitialized();
|
||||
internal_debug.toggleInitialized();
|
||||
c.glfwTerminate();
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.PlatformError => std.log.err("mach/glfw: Failed to terminate GLFW: {}", .{err}),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Initialization hints for passing into glfw.init
|
||||
pub const InitHints = struct {
|
||||
/// Specifies whether to also expose joystick hats as buttons, for compatibility with earlier
|
||||
/// versions of GLFW that did not have glfwGetJoystickHats.
|
||||
joystick_hat_buttons: bool = true,
|
||||
|
||||
/// macOS specific init hint. Ignored on other platforms.
|
||||
///
|
||||
/// Specifies whether to set the current directory to the application to the Contents/Resources
|
||||
/// subdirectory of the application's bundle, if present.
|
||||
cocoa_chdir_resources: bool = true,
|
||||
|
||||
/// macOS specific init hint. Ignored on other platforms.
|
||||
///
|
||||
/// specifies whether to create a basic menu bar, either from a nib or manually, when the first
|
||||
/// window is created, which is when AppKit is initialized.
|
||||
cocoa_menubar: bool = true,
|
||||
|
||||
/// Platform selection init hint.
|
||||
///
|
||||
/// Possible values are `PlatformType` enums.
|
||||
platform: PlatformType = .any,
|
||||
};
|
||||
|
||||
/// Initialization hints for passing into glfw.initHint
|
||||
const InitHint = enum(c_int) {
|
||||
/// Specifies whether to also expose joystick hats as buttons, for compatibility with earlier
|
||||
/// versions of GLFW that did not have glfwGetJoystickHats.
|
||||
///
|
||||
/// Possible values are `true` and `false`.
|
||||
joystick_hat_buttons = c.GLFW_JOYSTICK_HAT_BUTTONS,
|
||||
|
||||
/// ANGLE rendering backend init hint.
|
||||
///
|
||||
/// Possible values are `AnglePlatformType` enums.
|
||||
angle_platform_type = c.GLFW_ANGLE_PLATFORM_TYPE,
|
||||
|
||||
/// Platform selection init hint.
|
||||
///
|
||||
/// Possible values are `PlatformType` enums.
|
||||
platform = c.GLFW_PLATFORM,
|
||||
|
||||
/// macOS specific init hint. Ignored on other platforms.
|
||||
///
|
||||
/// Specifies whether to set the current directory to the application to the Contents/Resources
|
||||
/// subdirectory of the application's bundle, if present.
|
||||
///
|
||||
/// Possible values are `true` and `false`.
|
||||
cocoa_chdir_resources = c.GLFW_COCOA_CHDIR_RESOURCES,
|
||||
|
||||
/// macOS specific init hint. Ignored on other platforms.
|
||||
///
|
||||
/// specifies whether to create a basic menu bar, either from a nib or manually, when the first
|
||||
/// window is created, which is when AppKit is initialized.
|
||||
///
|
||||
/// Possible values are `true` and `false`.
|
||||
cocoa_menubar = c.GLFW_COCOA_MENUBAR,
|
||||
|
||||
/// X11 specific init hint.
|
||||
x11_xcb_vulkan_surface = c.GLFW_X11_XCB_VULKAN_SURFACE,
|
||||
};
|
||||
|
||||
/// Angle platform type hints for glfw.InitHint.angle_platform_type
|
||||
pub const AnglePlatformType = enum(c_int) {
|
||||
none = c.GLFW_ANGLE_PLATFORM_TYPE_NONE,
|
||||
opengl = c.GLFW_ANGLE_PLATFORM_TYPE_OPENGL,
|
||||
opengles = c.GLFW_ANGLE_PLATFORM_TYPE_OPENGLES,
|
||||
d3d9 = c.GLFW_ANGLE_PLATFORM_TYPE_D3D9,
|
||||
d3d11 = c.GLFW_ANGLE_PLATFORM_TYPE_D3D11,
|
||||
vulkan = c.GLFW_ANGLE_PLATFORM_TYPE_VULKAN,
|
||||
metal = c.GLFW_ANGLE_PLATFORM_TYPE_METAL,
|
||||
};
|
||||
|
||||
/// Platform type hints for glfw.InitHint.platform
|
||||
pub const PlatformType = enum(c_int) {
|
||||
/// Enables automatic platform detection.
|
||||
/// Will default to X11 on wayland.
|
||||
any = c.GLFW_ANY_PLATFORM,
|
||||
win32 = c.GLFW_PLATFORM_WIN32,
|
||||
cocoa = c.GLFW_PLATFORM_COCOA,
|
||||
wayland = c.GLFW_PLATFORM_WAYLAND,
|
||||
x11 = c.GLFW_PLATFORM_X11,
|
||||
nul = c.GLFW_PLATFORM_NULL,
|
||||
};
|
||||
|
||||
/// Sets the specified init hint to the desired value.
|
||||
///
|
||||
/// This function sets hints for the next initialization of GLFW.
|
||||
///
|
||||
/// The values you set hints to are never reset by GLFW, but they only take effect during
|
||||
/// initialization. Once GLFW has been initialized, any values you set will be ignored until the
|
||||
/// library is terminated and initialized again.
|
||||
///
|
||||
/// Some hints are platform specific. These may be set on any platform but they will only affect
|
||||
/// their specific platform. Other platforms will ignore them. Setting these hints requires no
|
||||
/// platform specific headers or functions.
|
||||
///
|
||||
/// @param hint: The init hint to set.
|
||||
/// @param value: The new value of the init hint.
|
||||
///
|
||||
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.InvalidValue.
|
||||
///
|
||||
/// @remarks This function may be called before glfw.init.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
fn initHint(hint: InitHint, value: anytype) void {
|
||||
switch (@typeInfo(@TypeOf(value))) {
|
||||
.Int, .ComptimeInt => {
|
||||
c.glfwInitHint(@enumToInt(hint), @intCast(c_int, value));
|
||||
},
|
||||
.Bool => c.glfwInitHint(@enumToInt(hint), @intCast(c_int, @boolToInt(value))),
|
||||
else => @compileError("expected a int or bool, got " ++ @typeName(@TypeOf(value))),
|
||||
}
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.InvalidEnum => unreachable,
|
||||
Error.InvalidValue => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns a string describing the compile-time configuration.
|
||||
///
|
||||
/// This function returns the compile-time generated version string of the GLFW library binary. It
|
||||
/// describes the version, platform, compiler and any platform or operating system specific
|
||||
/// compile-time options. It should not be confused with the OpenGL or OpenGL ES version string,
|
||||
/// queried with `glGetString`.
|
||||
///
|
||||
/// __Do not use the version string__ to parse the GLFW library version. Use the glfw.version
|
||||
/// constants instead.
|
||||
///
|
||||
/// __Do not use the version string__ to parse what platforms are supported. The
|
||||
/// `glfw.platformSupported` function lets you query platform support.
|
||||
///
|
||||
/// returns: The ASCII encoded GLFW version string.
|
||||
///
|
||||
/// remark: This function may be called before @ref glfw.Init.
|
||||
///
|
||||
/// pointer_lifetime: The returned string is static and compile-time generated.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread.
|
||||
pub inline fn getVersionString() [:0]const u8 {
|
||||
return std.mem.span(@ptrCast([*:0]const u8, c.glfwGetVersionString()));
|
||||
}
|
||||
|
||||
/// Returns the currently selected platform.
|
||||
///
|
||||
/// This function returns the platform that was selected during initialization. The returned value
|
||||
/// will be one of `glfw.PlatformType.win32`, `glfw.PlatformType.cocoa`,
|
||||
/// `glfw.PlatformType.wayland`, `glfw.PlatformType.x11` or `glfw.PlatformType.nul`.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread.
|
||||
pub fn getPlatform() PlatformType {
|
||||
internal_debug.assertInitialized();
|
||||
const platform = @intToEnum(PlatformType, c.glfwGetPlatform());
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return platform;
|
||||
}
|
||||
|
||||
/// Returns whether the library includes support for the specified platform.
|
||||
///
|
||||
/// This function returns whether the library was compiled with support for the specified platform.
|
||||
/// The platform must be one of `glfw.PlatformType.win32`, `glfw.PlatformType.cocoa`,
|
||||
/// `glfw.PlatformType.wayland`, `glfw.PlatformType.x11` or `glfw.PlatformType.nul`.
|
||||
///
|
||||
/// remark: This function may be called before glfw.Init.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread.
|
||||
pub fn platformSupported(platform: PlatformType) bool {
|
||||
internal_debug.assertInitialized();
|
||||
const is_supported = c.glfwPlatformSupported(@enumToInt(platform));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.InvalidEnum => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return is_supported == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
/// Processes all pending events.
|
||||
///
|
||||
/// This function processes only those events that are already in the event queue and then returns
|
||||
/// immediately. Processing events will cause the window and input callbacks associated with those
|
||||
/// events to be called.
|
||||
///
|
||||
/// On some platforms, a window move, resize or menu operation will cause event processing to
|
||||
/// block. This is due to how event processing is designed on those platforms. You can use the
|
||||
/// window refresh callback (see window_refresh) to redraw the contents of your window when
|
||||
/// necessary during such operations.
|
||||
///
|
||||
/// Do not assume that callbacks you set will _only_ be called in response to event processing
|
||||
/// functions like this one. While it is necessary to poll for events, window systems that require
|
||||
/// GLFW to register callbacks of its own can pass events to GLFW in response to many window system
|
||||
/// function calls. GLFW will pass those events on to the application callbacks before returning.
|
||||
///
|
||||
/// Event processing is not required for joystick input to work.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @reentrancy This function must not be called from a callback.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: events, glfw.waitEvents, glfw.waitEventsTimeout
|
||||
pub inline fn pollEvents() error{PlatformError}!void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwPollEvents();
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Waits until events are queued and processes them.
|
||||
///
|
||||
/// This function puts the calling thread to sleep until at least one event is available in the
|
||||
/// event queue. Once one or more events are available, it behaves exactly like glfw.pollEvents,
|
||||
/// i.e. the events in the queue are processed and the function then returns immediately.
|
||||
/// Processing events will cause the window and input callbacks associated with those events to be
|
||||
/// called.
|
||||
///
|
||||
/// Since not all events are associated with callbacks, this function may return without a callback
|
||||
/// having been called even if you are monitoring all callbacks.
|
||||
///
|
||||
/// On some platforms, a window move, resize or menu operation will cause event processing to
|
||||
/// block. This is due to how event processing is designed on those platforms. You can use the
|
||||
/// window refresh callback (see window_refresh) to redraw the contents of your window when
|
||||
/// necessary during such operations.
|
||||
///
|
||||
/// Do not assume that callbacks you set will _only_ be called in response to event processing
|
||||
/// functions like this one. While it is necessary to poll for events, window systems that require
|
||||
/// GLFW to register callbacks of its own can pass events to GLFW in response to many window system
|
||||
/// function calls. GLFW will pass those events on to the application callbacks before returning.
|
||||
///
|
||||
/// Event processing is not required for joystick input to work.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @reentrancy This function must not be called from a callback.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: events, glfw.pollEvents, glfw.waitEventsTimeout
|
||||
pub inline fn waitEvents() error{PlatformError}!void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwWaitEvents();
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Waits with timeout until events are queued and processes them.
|
||||
///
|
||||
/// This function puts the calling thread to sleep until at least one event is available in the
|
||||
/// event queue, or until the specified timeout is reached. If one or more events are available, it
|
||||
/// behaves exactly like glfw.pollEvents, i.e. the events in the queue are processed and the
|
||||
/// function then returns immediately. Processing events will cause the window and input callbacks
|
||||
/// associated with those events to be called.
|
||||
///
|
||||
/// The timeout value must be a positive finite number.
|
||||
///
|
||||
/// Since not all events are associated with callbacks, this function may return without a callback
|
||||
/// having been called even if you are monitoring all callbacks.
|
||||
///
|
||||
/// On some platforms, a window move, resize or menu operation will cause event processing to
|
||||
/// block. This is due to how event processing is designed on those platforms. You can use the
|
||||
/// window refresh callback (see window_refresh) to redraw the contents of your window when
|
||||
/// necessary during such operations.
|
||||
///
|
||||
/// Do not assume that callbacks you set will _only_ be called in response to event processing
|
||||
/// functions like this one. While it is necessary to poll for events, window systems that require
|
||||
/// GLFW to register callbacks of its own can pass events to GLFW in response to many window system
|
||||
/// function calls. GLFW will pass those events on to the application callbacks before returning.
|
||||
///
|
||||
/// Event processing is not required for joystick input to work.
|
||||
///
|
||||
/// @param[in] timeout The maximum amount of time, in seconds, to wait.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.InvalidValue and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @reentrancy This function must not be called from a callback.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: events, glfw.pollEvents, glfw.waitEvents
|
||||
pub inline fn waitEventsTimeout(timeout: f64) error{PlatformError}!void {
|
||||
internal_debug.assertInitialized();
|
||||
std.debug.assert(!std.math.isNan(timeout));
|
||||
std.debug.assert(timeout >= 0);
|
||||
std.debug.assert(timeout <= std.math.f64_max);
|
||||
c.glfwWaitEventsTimeout(timeout);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidValue => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Posts an empty event to the event queue.
|
||||
///
|
||||
/// This function posts an empty event from the current thread to the event queue, causing
|
||||
/// glfw.waitEvents or glfw.waitEventsTimeout to return.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: events, glfw.waitEvents, glfw.waitEventsTimeout
|
||||
pub inline fn postEmptyEvent() error{PlatformError}!void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwPostEmptyEvent();
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns whether raw mouse motion is supported.
|
||||
///
|
||||
/// This function returns whether raw mouse motion is supported on the current system. This status
|
||||
/// does not change after GLFW has been initialized so you only need to check this once. If you
|
||||
/// attempt to enable raw motion on a system that does not support it, glfw.Error.PlatformError will
|
||||
/// be emitted.
|
||||
///
|
||||
/// Raw mouse motion is closer to the actual motion of the mouse across a surface. It is not
|
||||
/// affected by the scaling and acceleration applied to the motion of the desktop cursor. That
|
||||
/// processing is suitable for a cursor while raw motion is better for controlling for example a 3D
|
||||
/// camera. Because of this, raw mouse motion is only provided when the cursor is disabled.
|
||||
///
|
||||
/// @return `true` if raw mouse motion is supported on the current machine, or `false` otherwise.
|
||||
///
|
||||
/// @thread_safety This function must only be called from the main thread.
|
||||
///
|
||||
/// see also: raw_mouse_motion, glfw.setInputMode
|
||||
pub inline fn rawMouseMotionSupported() bool {
|
||||
internal_debug.assertInitialized();
|
||||
const supported = c.glfwRawMouseMotionSupported();
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return supported == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
pub fn basicTest() !void {
|
||||
try init(.{});
|
||||
defer terminate();
|
||||
|
||||
const window = Window.create(640, 480, "GLFW example", null, null, .{}) catch |err| {
|
||||
// return without fail, because most of our CI environments are headless / we cannot open
|
||||
// windows on them.
|
||||
std.debug.print("note: failed to create window: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer window.destroy();
|
||||
|
||||
var start = std.time.milliTimestamp();
|
||||
while (std.time.milliTimestamp() < start + 1000 and !window.shouldClose()) {
|
||||
c.glfwPollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
std.testing.refAllDeclsRecursive(@This());
|
||||
}
|
||||
|
||||
test "getVersionString" {
|
||||
std.debug.print("\nGLFW version v{}.{}.{}\n", .{ version.major, version.minor, version.revision });
|
||||
std.debug.print("\nstring: {s}\n", .{getVersionString()});
|
||||
}
|
||||
|
||||
test "pollEvents" {
|
||||
try init(.{ .cocoa_chdir_resources = true });
|
||||
defer terminate();
|
||||
}
|
||||
|
||||
test "pollEvents" {
|
||||
try init(.{});
|
||||
defer terminate();
|
||||
|
||||
try pollEvents();
|
||||
}
|
||||
|
||||
test "waitEventsTimeout" {
|
||||
try init(.{});
|
||||
defer terminate();
|
||||
|
||||
try waitEventsTimeout(0.25);
|
||||
}
|
||||
|
||||
test "postEmptyEvent_and_waitEvents" {
|
||||
try init(.{});
|
||||
defer terminate();
|
||||
|
||||
try postEmptyEvent();
|
||||
try waitEvents();
|
||||
}
|
||||
|
||||
test "rawMouseMotionSupported" {
|
||||
try init(.{});
|
||||
defer terminate();
|
||||
|
||||
_ = rawMouseMotionSupported();
|
||||
}
|
||||
|
||||
test "basic" {
|
||||
try basicTest();
|
||||
}
|
||||
167
libs/glfw/src/mod.zig
Normal file
167
libs/glfw/src/mod.zig
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
//! Modifier key flags
|
||||
//!
|
||||
//! See glfw.setKeyCallback for how these are used.
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
// must be in sync with GLFW C constants in modifier group, search for "@defgroup mods Modifier key flags"
|
||||
/// A bitmask of all key modifiers
|
||||
pub const Mods = packed struct {
|
||||
shift: bool = false,
|
||||
control: bool = false,
|
||||
alt: bool = false,
|
||||
super: bool = false,
|
||||
caps_lock: bool = false,
|
||||
num_lock: bool = false,
|
||||
_reserved: u2 = 0,
|
||||
|
||||
inline fn verifyIntType(comptime IntType: type) void {
|
||||
comptime {
|
||||
switch (@typeInfo(IntType)) {
|
||||
.Int => {},
|
||||
else => @compileError("Int was not of int type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub inline fn toInt(self: Mods, comptime IntType: type) IntType {
|
||||
verifyIntType(IntType);
|
||||
return @intCast(IntType, @bitCast(u8, self));
|
||||
}
|
||||
|
||||
pub inline fn fromInt(flags: anytype) Mods {
|
||||
verifyIntType(@TypeOf(flags));
|
||||
return @bitCast(Mods, @intCast(u8, flags));
|
||||
}
|
||||
};
|
||||
|
||||
/// Holds all GLFW mod values in their raw form.
|
||||
pub const RawMods = struct {
|
||||
/// If this bit is set one or more Shift keys were held down.
|
||||
pub const shift = c.GLFW_MOD_SHIFT;
|
||||
|
||||
/// If this bit is set one or more Control keys were held down.
|
||||
pub const control = c.GLFW_MOD_CONTROL;
|
||||
|
||||
/// If this bit is set one or more Alt keys were held down.
|
||||
pub const alt = c.GLFW_MOD_ALT;
|
||||
|
||||
/// If this bit is set one or more Super keys were held down.
|
||||
pub const super = c.GLFW_MOD_SUPER;
|
||||
|
||||
/// If this bit is set the Caps Lock key is enabled and the glfw.lock_key_mods input mode is set.
|
||||
pub const caps_lock = c.GLFW_MOD_CAPS_LOCK;
|
||||
|
||||
/// If this bit is set the Num Lock key is enabled and the glfw.lock_key_mods input mode is set.
|
||||
pub const num_lock = c.GLFW_MOD_NUM_LOCK;
|
||||
};
|
||||
|
||||
test "shift int to bitmask" {
|
||||
const std = @import("std");
|
||||
|
||||
const int_mod = RawMods.shift;
|
||||
const mod = Mods.fromInt(int_mod);
|
||||
|
||||
try std.testing.expect(mod.shift == true);
|
||||
try std.testing.expect(mod.control == false);
|
||||
try std.testing.expect(mod.alt == false);
|
||||
try std.testing.expect(mod.super == false);
|
||||
try std.testing.expect(mod.caps_lock == false);
|
||||
try std.testing.expect(mod.num_lock == false);
|
||||
}
|
||||
|
||||
test "shift int and alt to bitmask" {
|
||||
const std = @import("std");
|
||||
|
||||
const int_mod = RawMods.shift | RawMods.alt;
|
||||
const mod = Mods.fromInt(int_mod);
|
||||
|
||||
try std.testing.expect(mod.shift == true);
|
||||
try std.testing.expect(mod.control == false);
|
||||
try std.testing.expect(mod.alt == true);
|
||||
try std.testing.expect(mod.super == false);
|
||||
try std.testing.expect(mod.caps_lock == false);
|
||||
try std.testing.expect(mod.num_lock == false);
|
||||
}
|
||||
|
||||
test "super int to bitmask" {
|
||||
const std = @import("std");
|
||||
|
||||
const int_mod = RawMods.super;
|
||||
const mod = Mods.fromInt(int_mod);
|
||||
|
||||
try std.testing.expect(mod.shift == false);
|
||||
try std.testing.expect(mod.control == false);
|
||||
try std.testing.expect(mod.alt == false);
|
||||
try std.testing.expect(mod.super == true);
|
||||
try std.testing.expect(mod.caps_lock == false);
|
||||
try std.testing.expect(mod.num_lock == false);
|
||||
}
|
||||
|
||||
test "num lock int to bitmask" {
|
||||
const std = @import("std");
|
||||
|
||||
const int_mod = RawMods.num_lock;
|
||||
const mod = Mods.fromInt(int_mod);
|
||||
|
||||
try std.testing.expect(mod.shift == false);
|
||||
try std.testing.expect(mod.control == false);
|
||||
try std.testing.expect(mod.alt == false);
|
||||
try std.testing.expect(mod.super == false);
|
||||
try std.testing.expect(mod.caps_lock == false);
|
||||
try std.testing.expect(mod.num_lock == true);
|
||||
}
|
||||
|
||||
test "all int to bitmask" {
|
||||
const std = @import("std");
|
||||
|
||||
const int_mod = RawMods.shift | RawMods.control |
|
||||
RawMods.alt | RawMods.super |
|
||||
RawMods.caps_lock | RawMods.num_lock;
|
||||
const mod = Mods.fromInt(int_mod);
|
||||
|
||||
try std.testing.expect(mod.shift == true);
|
||||
try std.testing.expect(mod.control == true);
|
||||
try std.testing.expect(mod.alt == true);
|
||||
try std.testing.expect(mod.super == true);
|
||||
try std.testing.expect(mod.caps_lock == true);
|
||||
try std.testing.expect(mod.num_lock == true);
|
||||
}
|
||||
|
||||
test "shift bitmask to int" {
|
||||
const std = @import("std");
|
||||
|
||||
const mod = Mods{ .shift = true };
|
||||
const int_mod = mod.toInt(c_int);
|
||||
|
||||
try std.testing.expectEqual(int_mod, RawMods.shift);
|
||||
}
|
||||
|
||||
test "shift and alt bitmask to int" {
|
||||
const std = @import("std");
|
||||
|
||||
const mod = Mods{ .shift = true, .alt = true };
|
||||
const int_mod = mod.toInt(c_int);
|
||||
|
||||
try std.testing.expectEqual(int_mod, RawMods.shift | RawMods.alt);
|
||||
}
|
||||
|
||||
test "all bitmask to int" {
|
||||
const std = @import("std");
|
||||
|
||||
const mod = Mods{
|
||||
.shift = true,
|
||||
.control = true,
|
||||
.alt = true,
|
||||
.super = true,
|
||||
.caps_lock = true,
|
||||
.num_lock = true,
|
||||
};
|
||||
const int_mod = mod.toInt(c_int);
|
||||
|
||||
const expected = RawMods.shift | RawMods.control |
|
||||
RawMods.alt | RawMods.super |
|
||||
RawMods.caps_lock | RawMods.num_lock;
|
||||
|
||||
try std.testing.expectEqual(int_mod, expected);
|
||||
}
|
||||
23
libs/glfw/src/mouse_button.zig
Normal file
23
libs/glfw/src/mouse_button.zig
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
const c = @import("c.zig").c;
|
||||
|
||||
/// Mouse button IDs.
|
||||
///
|
||||
/// See glfw.setMouseButtonCallback for how these are used.
|
||||
pub const MouseButton = enum(c_int) {
|
||||
// We use left/right/middle aliases here because those are more common and we cannot have
|
||||
// duplicate values in a Zig enum.
|
||||
left = c.GLFW_MOUSE_BUTTON_1,
|
||||
right = c.GLFW_MOUSE_BUTTON_2,
|
||||
middle = c.GLFW_MOUSE_BUTTON_3,
|
||||
four = c.GLFW_MOUSE_BUTTON_4,
|
||||
five = c.GLFW_MOUSE_BUTTON_5,
|
||||
six = c.GLFW_MOUSE_BUTTON_6,
|
||||
seven = c.GLFW_MOUSE_BUTTON_7,
|
||||
eight = c.GLFW_MOUSE_BUTTON_8,
|
||||
};
|
||||
|
||||
/// Not in the MouseButton enumeration as it is a duplicate value which is forbidden.
|
||||
pub const last = MouseButton.eight;
|
||||
pub const one = MouseButton.left;
|
||||
pub const two = MouseButton.right;
|
||||
pub const three = MouseButton.middle;
|
||||
528
libs/glfw/src/native.zig
Normal file
528
libs/glfw/src/native.zig
Normal file
|
|
@ -0,0 +1,528 @@
|
|||
//! Native access functions
|
||||
const std = @import("std");
|
||||
|
||||
const Window = @import("Window.zig");
|
||||
const Monitor = @import("Monitor.zig");
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
pub const BackendOptions = struct {
|
||||
win32: bool = false,
|
||||
wgl: bool = false,
|
||||
cocoa: bool = false,
|
||||
nsgl: bool = false,
|
||||
x11: bool = false,
|
||||
glx: bool = false,
|
||||
wayland: bool = false,
|
||||
egl: bool = false,
|
||||
osmesa: bool = false,
|
||||
};
|
||||
|
||||
/// This function returns a type which allows provides an interface to access
|
||||
/// the native handles based on backends selected.
|
||||
///
|
||||
/// The available window API options are:
|
||||
/// * win32
|
||||
/// * cocoa
|
||||
/// * x11
|
||||
/// * wayland
|
||||
///
|
||||
/// The available context API options are:
|
||||
///
|
||||
/// * wgl
|
||||
/// * nsgl
|
||||
/// * glx
|
||||
/// * egl
|
||||
/// * osmesa
|
||||
///
|
||||
/// The chosen backends must match those the library was compiled for. Failure to do so
|
||||
/// will cause a link-time error.
|
||||
pub fn Native(comptime options: BackendOptions) type {
|
||||
const native = if (@import("builtin").zig_backend == .stage1)
|
||||
@cImport({
|
||||
@cDefine("GLFW_INCLUDE_VULKAN", "1");
|
||||
@cInclude("GLFW/glfw3.h");
|
||||
|
||||
if (options.win32) @cDefine("GLFW_EXPOSE_NATIVE_WIN32", "1");
|
||||
if (options.wgl) @cDefine("GLFW_EXPOSE_NATIVE_WGL", "1");
|
||||
if (options.cocoa) @cDefine("GLFW_EXPOSE_NATIVE_COCOA", "1");
|
||||
if (options.nsgl) @cDefine("GLFW_EXPOSE_NATIVE_NGSL", "1");
|
||||
if (options.x11) @cDefine("GLFW_EXPOSE_NATIVE_X11", "1");
|
||||
if (options.glx) @cDefine("GLFW_EXPOSE_NATIVE_GLX", "1");
|
||||
if (options.wayland) @cDefine("GLFW_EXPOSE_NATIVE_WAYLAND", "1");
|
||||
if (options.egl) @cDefine("GLFW_EXPOSE_NATIVE_EGL", "1");
|
||||
if (options.osmesa) @cDefine("GLFW_EXPOSE_NATIVE_OSMESA", "1");
|
||||
@cInclude("GLFW/glfw3native.h");
|
||||
})
|
||||
else
|
||||
// TODO(self-hosted): HACK: workaround https://github.com/ziglang/zig/issues/12483
|
||||
//
|
||||
// Extracted from a build using stage1 from zig-cache/ (`cimport.zig`)
|
||||
// Then find+replace `= ?fn` -> `= ?*const fn`
|
||||
@import("cimport1.zig");
|
||||
|
||||
return struct {
|
||||
/// Returns the adapter device name of the specified monitor.
|
||||
///
|
||||
/// return: The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) of the
|
||||
/// specified monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getWin32Adapter(monitor: Monitor) [*:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetWin32Adapter(@ptrCast(*native.GLFWmonitor, monitor.handle))) |adapter| return adapter;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetWin32Adapter` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the display device name of the specified monitor.
|
||||
///
|
||||
/// return: The UTF-8 encoded display device name (for example `\\.\DISPLAY1\Monitor0`)
|
||||
/// of the specified monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getWin32Monitor(monitor: Monitor) [*:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetWin32Monitor(@ptrCast(*native.GLFWmonitor, monitor.handle))) |mon| return mon;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetWin32Monitor` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `HWND` of the specified window.
|
||||
///
|
||||
/// The `HDC` associated with the window can be queried with the
|
||||
/// [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc)
|
||||
/// function.
|
||||
/// ```
|
||||
/// const dc = std.os.windows.user32.GetDC(native.getWin32Window(window));
|
||||
/// ```
|
||||
/// This DC is private and does not need to be released.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getWin32Window(window: Window) std.os.windows.HWND {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetWin32Window(@ptrCast(*native.GLFWwindow, window.handle))) |win|
|
||||
return @ptrCast(std.os.windows.HWND, win);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetWin32Window` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `HGLRC` of the specified window.
|
||||
///
|
||||
/// The `HDC` associated with the window can be queried with the
|
||||
/// [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc)
|
||||
/// function.
|
||||
/// ```
|
||||
/// const dc = std.os.windows.user32.GetDC(native.getWin32Window(window));
|
||||
/// ```
|
||||
/// This DC is private and does not need to be released.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getWGLContext(window: Window) error{NoWindowContext}!std.os.windows.HGLRC {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetWGLContext(@ptrCast(*native.GLFWwindow, window.handle))) |context| return context;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetWGLContext` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `CGDirectDisplayID` of the specified monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getCocoaMonitor(monitor: Monitor) u32 {
|
||||
internal_debug.assertInitialized();
|
||||
const mon = native.glfwGetCocoaMonitor(@ptrCast(*native.GLFWmonitor, monitor.handle));
|
||||
if (mon != native.kCGNullDirectDisplay) return mon;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetCocoaMonitor` returns `kCGNullDirectDisplay` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `NSWindow` of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getCocoaWindow(window: Window) ?*anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
const win = native.glfwGetCocoaWindow(@ptrCast(*native.GLFWwindow, window.handle));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return win;
|
||||
}
|
||||
|
||||
/// Returns the `NSWindow` of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.NoWindowContext.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getNSGLContext(window: Window) error{NoWindowContext}!u32 {
|
||||
internal_debug.assertInitialized();
|
||||
const context = native.glfwGetNSGLContext(@ptrCast(*native.GLFWwindow, window.handle));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return context;
|
||||
}
|
||||
|
||||
/// Returns the `Display` used by GLFW.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getX11Display() *anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetX11Display()) |display| return @ptrCast(*anyopaque, display);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetX11Display` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `RRCrtc` of the specified monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getX11Adapter(monitor: Monitor) u32 {
|
||||
internal_debug.assertInitialized();
|
||||
const adapter = native.glfwGetX11Adapter(@ptrCast(*native.GLFWMonitor, monitor.handle));
|
||||
if (adapter != 0) return adapter;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetX11Adapter` returns `0` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `RROutput` of the specified monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getX11Monitor(monitor: Monitor) u32 {
|
||||
internal_debug.assertInitialized();
|
||||
const mon = native.glfwGetX11Monitor(@ptrCast(*native.GLFWmonitor, monitor.handle));
|
||||
if (mon != 0) return mon;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetX11Monitor` returns `0` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `Window` of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getX11Window(window: Window) u32 {
|
||||
internal_debug.assertInitialized();
|
||||
const win = native.glfwGetX11Window(@ptrCast(*native.GLFWwindow, window.handle));
|
||||
if (win != 0) return @intCast(u32, win);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetX11Window` returns `0` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Sets the current primary selection to the specified string.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// The specified string is copied before this function returns.
|
||||
///
|
||||
/// thread_safety: This function must only be called from the main thread.
|
||||
pub fn setX11SelectionString(string: [*:0]const u8) error{PlatformError}!void {
|
||||
internal_debug.assertInitialized();
|
||||
native.glfwSetX11SelectionString(string);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the contents of the current primary selection as a string.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.PlatformError.
|
||||
///
|
||||
/// The returned string is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is valid until the next call to getX11SelectionString or
|
||||
/// setX11SelectionString, or until the library is terminated.
|
||||
///
|
||||
/// thread_safety: This function must only be called from the main thread.
|
||||
pub fn getX11SelectionString() error{FormatUnavailable}![*:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetX11SelectionString()) |str| return str;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.FormatUnavailable => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetX11SelectionString` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `GLXContext` of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NoWindowContext and glfw.Error.NotInitialized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getGLXContext(window: Window) error{NoWindowContext}!*anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetGLXContext(@ptrCast(*native.GLFWwindow, window.handle))) |context| return @ptrCast(*anyopaque, context);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetGLXContext` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `GLXWindow` of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NoWindowContext and glfw.Error.NotInitialized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getGLXWindow(window: Window) error{NoWindowContext}!*anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
const win = native.glfwGetGLXWindow(@ptrCast(*native.GLFWwindow, window.handle));
|
||||
if (win != 0) return @ptrCast(*anyopaque, win);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetGLXWindow` returns `0` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `*wl_display` used by GLFW.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getWaylandDisplay() *anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetWaylandDisplay()) |display| return @ptrCast(*anyopaque, display);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetWaylandDisplay` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `*wl_output` of the specified monitor.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getWaylandMonitor(monitor: Monitor) *anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetWaylandMonitor(@ptrCast(*native.GLFWmonitor, monitor.handle))) |mon| return @ptrCast(*anyopaque, mon);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetWaylandMonitor` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `*wl_surface` of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getWaylandWindow(window: Window) *anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetWaylandWindow(@ptrCast(*native.GLFWwindow, window.handle))) |win| return @ptrCast(*anyopaque, win);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetWaylandWindow` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `EGLDisplay` used by GLFW.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized.
|
||||
///
|
||||
/// remark: Because EGL is initialized on demand, this function will return `EGL_NO_DISPLAY`
|
||||
/// until the first context has been created via EGL.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getEGLDisplay() *anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
const display = native.glfwGetEGLDisplay();
|
||||
if (display != native.EGL_NO_DISPLAY) return @ptrCast(*anyopaque, display);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetEGLDisplay` returns `EGL_NO_DISPLAY` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `EGLContext` of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized and glfw.Error.NoWindowContext.
|
||||
///
|
||||
/// thread_safety This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getEGLContext(window: Window) error{NoWindowContext}!*anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
const context = native.glfwGetEGLContext(@ptrCast(*native.GLFWwindow, window.handle));
|
||||
if (context != native.EGL_NO_CONTEXT) return @ptrCast(*anyopaque, context);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetEGLContext` returns `EGL_NO_CONTEXT` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the `EGLSurface` of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized and glfw.Error.NoWindowContext.
|
||||
///
|
||||
/// thread_safety This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getEGLSurface(window: Window) error{NoWindowContext}!*anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
const surface = native.glfwGetEGLSurface(@ptrCast(*native.GLFWwindow, window.handle));
|
||||
if (surface != native.EGL_NO_SURFACE) return @ptrCast(*anyopaque, surface);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetEGLSurface` returns `EGL_NO_SURFACE` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub const OSMesaColorBuffer = struct {
|
||||
width: c_int,
|
||||
height: c_int,
|
||||
format: c_int,
|
||||
buffer: *anyopaque,
|
||||
};
|
||||
|
||||
/// Retrieves the color buffer associated with the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized, glfw.Error.NoWindowContext
|
||||
/// and glfw.Error.PlatformError.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getOSMesaColorBuffer(window: Window) error{ PlatformError, NoWindowContext }!OSMesaColorBuffer {
|
||||
internal_debug.assertInitialized();
|
||||
var buf: OSMesaColorBuffer = undefined;
|
||||
if (native.glfwGetOSMesaColorBuffer(
|
||||
@ptrCast(*native.GLFWwindow, window.handle),
|
||||
&buf.width,
|
||||
&buf.height,
|
||||
&buf.format,
|
||||
&buf.buffer,
|
||||
) == native.GLFW_TRUE) return buf;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError, Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetOSMesaColorBuffer` returns `GLFW_FALSE` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
pub const OSMesaDepthBuffer = struct {
|
||||
width: c_int,
|
||||
height: c_int,
|
||||
bytes_per_value: c_int,
|
||||
buffer: *anyopaque,
|
||||
};
|
||||
|
||||
/// Retrieves the depth buffer associated with the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized, glfw.Error.NoWindowContext
|
||||
/// and glfw.Error.PlatformError.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getOSMesaDepthBuffer(window: Window) error{ PlatformError, NoWindowContext }!OSMesaDepthBuffer {
|
||||
internal_debug.assertInitialized();
|
||||
var buf: OSMesaDepthBuffer = undefined;
|
||||
if (native.glfwGetOSMesaDepthBuffer(
|
||||
@ptrCast(*native.GLFWwindow, window.handle),
|
||||
&buf.width,
|
||||
&buf.height,
|
||||
&buf.bytes_per_value,
|
||||
&buf.buffer,
|
||||
) == native.GLFW_TRUE) return buf;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.PlatformError, Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetOSMesaDepthBuffer` returns `GLFW_FALSE` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the 'OSMesaContext' of the specified window.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitalized and glfw.Error.NoWindowContext.
|
||||
///
|
||||
/// thread_safety: This function may be called from any thread. Access is not synchronized.
|
||||
pub fn getOSMesaContext(window: Window) error{NoWindowContext}!*anyopaque {
|
||||
internal_debug.assertInitialized();
|
||||
if (native.glfwGetOSMesaContext(@ptrCast(*native.GLFWwindow, window.handle))) |context| return @ptrCast(*anyopaque, context);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoWindowContext => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetOSMesaContext` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
}
|
||||
270
libs/glfw/src/opengl.zig
Normal file
270
libs/glfw/src/opengl.zig
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const Window = @import("Window.zig");
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
/// Makes the context of the specified window current for the calling thread.
|
||||
///
|
||||
/// This function makes the OpenGL or OpenGL ES context of the specified window current on the
|
||||
/// calling thread. A context must only be made current on a single thread at a time and each
|
||||
/// thread can have only a single current context at a time.
|
||||
///
|
||||
/// When moving a context between threads, you must make it non-current on the old thread before
|
||||
/// making it current on the new one.
|
||||
///
|
||||
/// By default, making a context non-current implicitly forces a pipeline flush. On machines that
|
||||
/// support `GL_KHR_context_flush_control`, you can control whether a context performs this flush
|
||||
/// by setting the glfw.context_release_behavior hint.
|
||||
///
|
||||
/// The specified window must have an OpenGL or OpenGL ES context. Specifying a window without a
|
||||
/// context will generate Error.NoWindowContext.
|
||||
///
|
||||
/// @param[in] window The window whose context to make current, or null to
|
||||
/// detach the current context.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.NoWindowContext and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: context_current, glfwGetCurrentContext
|
||||
pub inline fn makeContextCurrent(window: ?Window) error{ NoWindowContext, PlatformError }!void {
|
||||
internal_debug.assertInitialized();
|
||||
if (window) |w| c.glfwMakeContextCurrent(w.handle) else c.glfwMakeContextCurrent(null);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoWindowContext, Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the window whose context is current on the calling thread.
|
||||
///
|
||||
/// This function returns the window whose OpenGL or OpenGL ES context is current on the calling
|
||||
/// thread.
|
||||
///
|
||||
/// Returns he window whose context is current, or null if no window's context is current.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: context_current, glfwMakeContextCurrent
|
||||
pub inline fn getCurrentContext() ?Window {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetCurrentContext()) |handle| return Window.from(handle);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Sets the swap interval for the current context.
|
||||
///
|
||||
/// This function sets the swap interval for the current OpenGL or OpenGL ES context, i.e. the
|
||||
/// number of screen updates to wait from the time glfw.SwapBuffers was called before swapping the
|
||||
/// buffers and returning. This is sometimes called _vertical synchronization_, _vertical retrace
|
||||
/// synchronization_ or just _vsync_.
|
||||
///
|
||||
/// A context that supports either of the `WGL_EXT_swap_control_tear` and `GLX_EXT_swap_control_tear`
|
||||
/// extensions also accepts _negative_ swap intervals, which allows the driver to swap immediately
|
||||
/// even if a frame arrives a little bit late. You can check for these extensions with glfw.extensionSupported.
|
||||
///
|
||||
/// A context must be current on the calling thread. Calling this function without a current context
|
||||
/// will cause Error.NoCurrentContext.
|
||||
///
|
||||
/// This function does not apply to Vulkan. If you are rendering with Vulkan, see the present mode
|
||||
/// of your swapchain instead.
|
||||
///
|
||||
/// @param[in] interval The minimum number of screen updates to wait for until the buffers are
|
||||
/// swapped by glfw.swapBuffers.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.NoCurrentContext and glfw.Error.PlatformError.
|
||||
///
|
||||
/// This function is not called during context creation, leaving the swap interval set to whatever
|
||||
/// is the default for that API. This is done because some swap interval extensions used by
|
||||
/// GLFW do not allow the swap interval to be reset to zero once it has been set to a non-zero
|
||||
/// value.
|
||||
///
|
||||
/// Some GPU drivers do not honor the requested swap interval, either because of a user setting
|
||||
/// that overrides the application's request or due to bugs in the driver.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: buffer_swap, glfwSwapBuffers
|
||||
pub inline fn swapInterval(interval: i32) error{ NoCurrentContext, PlatformError }!void {
|
||||
internal_debug.assertInitialized();
|
||||
c.glfwSwapInterval(@intCast(c_int, interval));
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.NoCurrentContext, Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns whether the specified extension is available.
|
||||
///
|
||||
/// This function returns whether the specified API extension (see context_glext) is supported by
|
||||
/// the current OpenGL or OpenGL ES context. It searches both for client API extension and context
|
||||
/// creation API extensions.
|
||||
///
|
||||
/// A context must be current on the calling thread. Calling this function without a current
|
||||
/// context will cause Error.NoCurrentContext.
|
||||
///
|
||||
/// As this functions retrieves and searches one or more extension strings each call, it is
|
||||
/// recommended that you cache its results if it is going to be used frequently. The extension
|
||||
/// strings will not change during the lifetime of a context, so there is no danger in doing this.
|
||||
///
|
||||
/// This function does not apply to Vulkan. If you are using Vulkan, see glfw.getRequiredInstanceExtensions,
|
||||
/// `vkEnumerateInstanceExtensionProperties` and `vkEnumerateDeviceExtensionProperties` instead.
|
||||
///
|
||||
/// @param[in] extension The ASCII encoded name of the extension.
|
||||
/// @return `true` if the extension is available, or `false` otherwise.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.NoCurrentContext, glfw.Error.InvalidValue
|
||||
/// and glfw.Error.PlatformError.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: context_glext, glfw.getProcAddress
|
||||
pub inline fn extensionSupported(extension: [:0]const u8) error{ NoCurrentContext, PlatformError }!bool {
|
||||
internal_debug.assertInitialized();
|
||||
|
||||
std.debug.assert(extension.len != 0);
|
||||
std.debug.assert(extension[0] != 0);
|
||||
|
||||
const supported = c.glfwExtensionSupported(extension.ptr);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NoCurrentContext, Error.PlatformError => |e| e,
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidValue => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
return supported == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
const builtin = @import("builtin");
|
||||
/// Client API function pointer type.
|
||||
///
|
||||
/// Generic function pointer used for returning client API function pointers.
|
||||
///
|
||||
/// see also: context_glext, glfwGetProcAddress
|
||||
pub const GLProc = if (builtin.zig_backend == .stage1 or builtin.zig_backend == .other) fn () callconv(.C) void else *const fn () callconv(.C) void;
|
||||
|
||||
/// Returns the address of the specified function for the current context.
|
||||
///
|
||||
/// This function returns the address of the specified OpenGL or OpenGL ES core or extension
|
||||
/// function (see context_glext), if it is supported by the current context.
|
||||
///
|
||||
/// A context must be current on the calling thread. Calling this function without a current
|
||||
/// context will cause Error.NoCurrentContext.
|
||||
///
|
||||
/// This function does not apply to Vulkan. If you are rendering with Vulkan, see glfw.getInstanceProcAddress,
|
||||
/// `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` instead.
|
||||
///
|
||||
/// @param[in] procname The ASCII encoded name of the function.
|
||||
/// @return The address of the function, or null if an error occurred.
|
||||
///
|
||||
/// To maintain ABI compatability with the C glfwGetProcAddress, as it is commonly passed into
|
||||
/// libraries expecting that exact ABI, this function does not return an error. Instead, if
|
||||
/// glfw.Error.NotInitialized, glfw.Error.NoCurrentContext, or glfw.Error.PlatformError would
|
||||
/// occur this function will panic. You should ensure a valid OpenGL context exists and the
|
||||
/// GLFW is initialized before calling this function.
|
||||
///
|
||||
/// The address of a given function is not guaranteed to be the same between contexts.
|
||||
///
|
||||
/// This function may return a non-null address despite the associated version or extension
|
||||
/// not being available. Always check the context version or extension string first.
|
||||
///
|
||||
/// @pointer_lifetime The returned function pointer is valid until the context is destroyed or the
|
||||
/// library is terminated.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: context_glext, glfwExtensionSupported
|
||||
pub fn getProcAddress(proc_name: [*:0]const u8) callconv(.C) ?GLProc {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetProcAddress(proc_name)) |proc_address| return proc_address;
|
||||
getError() catch |err| @panic(@errorName(err));
|
||||
return null;
|
||||
}
|
||||
|
||||
test "makeContextCurrent" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) catch |err| {
|
||||
// return without fail, because most of our CI environments are headless / we cannot open
|
||||
// windows on them.
|
||||
std.debug.print("note: failed to create window: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer window.destroy();
|
||||
|
||||
try glfw.makeContextCurrent(window);
|
||||
}
|
||||
|
||||
test "getCurrentContext" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const current_context = glfw.getCurrentContext();
|
||||
std.debug.assert(current_context == null);
|
||||
}
|
||||
|
||||
test "swapInterval" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) catch |err| {
|
||||
// return without fail, because most of our CI environments are headless / we cannot open
|
||||
// windows on them.
|
||||
std.debug.print("note: failed to create window: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer window.destroy();
|
||||
|
||||
try glfw.makeContextCurrent(window);
|
||||
glfw.swapInterval(1) catch |err| std.debug.print("failed to set swap interval, error={}\n", .{err});
|
||||
}
|
||||
|
||||
test "getProcAddress" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) catch |err| {
|
||||
// return without fail, because most of our CI environments are headless / we cannot open
|
||||
// windows on them.
|
||||
std.debug.print("note: failed to create window: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer window.destroy();
|
||||
|
||||
try glfw.makeContextCurrent(window);
|
||||
_ = glfw.getProcAddress("foobar");
|
||||
}
|
||||
|
||||
test "extensionSupported" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) catch |err| {
|
||||
// return without fail, because most of our CI environments are headless / we cannot open
|
||||
// windows on them.
|
||||
std.debug.print("note: failed to create window: {}\n", .{err});
|
||||
return;
|
||||
};
|
||||
defer window.destroy();
|
||||
|
||||
try glfw.makeContextCurrent(window);
|
||||
_ = glfw.extensionSupported("foobar") catch |err| std.debug.print("failed to check if extension supported, error={}\n", .{err});
|
||||
}
|
||||
14
libs/glfw/src/sources_all.c
Normal file
14
libs/glfw/src/sources_all.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// General sources
|
||||
#include "monitor.c"
|
||||
#include "init.c"
|
||||
#include "vulkan.c"
|
||||
#include "input.c"
|
||||
#include "osmesa_context.c"
|
||||
#include "egl_context.c"
|
||||
#include "context.c"
|
||||
#include "window.c"
|
||||
#include "platform.c"
|
||||
#include "null_init.c"
|
||||
#include "null_monitor.c"
|
||||
#include "null_window.c"
|
||||
#include "null_joystick.c"
|
||||
7
libs/glfw/src/sources_linux.c
Normal file
7
libs/glfw/src/sources_linux.c
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// General Linux-like sources
|
||||
#include "posix_time.c"
|
||||
#include "posix_thread.c"
|
||||
#include "linux_joystick.c"
|
||||
#include "xkb_unicode.c"
|
||||
#include "posix_module.c"
|
||||
#include "posix_poll.c"
|
||||
4
libs/glfw/src/sources_linux_wayland.c
Normal file
4
libs/glfw/src/sources_linux_wayland.c
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// General Linux-like sources
|
||||
#include "wl_monitor.c"
|
||||
#include "wl_window.c"
|
||||
#include "wl_init.c"
|
||||
5
libs/glfw/src/sources_linux_x11.c
Normal file
5
libs/glfw/src/sources_linux_x11.c
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// General Linux-like sources
|
||||
#include "x11_init.c"
|
||||
#include "x11_window.c"
|
||||
#include "x11_monitor.c"
|
||||
#include "glx_context.c"
|
||||
4
libs/glfw/src/sources_macos.c
Normal file
4
libs/glfw/src/sources_macos.c
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// MacOS-specific sources
|
||||
#include "cocoa_time.c"
|
||||
#include "posix_thread.c"
|
||||
#include "posix_module.c"
|
||||
6
libs/glfw/src/sources_macos.m
Normal file
6
libs/glfw/src/sources_macos.m
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// MacOS-specific sources
|
||||
#include "cocoa_joystick.m"
|
||||
#include "cocoa_init.m"
|
||||
#include "cocoa_window.m"
|
||||
#include "cocoa_monitor.m"
|
||||
#include "nsgl_context.m"
|
||||
9
libs/glfw/src/sources_windows.c
Normal file
9
libs/glfw/src/sources_windows.c
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Windows-specific sources
|
||||
#include "win32_thread.c"
|
||||
#include "wgl_context.c"
|
||||
#include "win32_init.c"
|
||||
#include "win32_monitor.c"
|
||||
#include "win32_time.c"
|
||||
#include "win32_joystick.c"
|
||||
#include "win32_window.c"
|
||||
#include "win32_module.c"
|
||||
153
libs/glfw/src/time.zig
Normal file
153
libs/glfw/src/time.zig
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
/// Returns the GLFW time.
|
||||
///
|
||||
/// This function returns the current GLFW time, in seconds. Unless the time
|
||||
/// has been set using @ref glfwSetTime it measures time elapsed since GLFW was
|
||||
/// initialized.
|
||||
///
|
||||
/// This function and @ref glfwSetTime are helper functions on top of glfw.getTimerFrequency
|
||||
/// and glfw.getTimerValue.
|
||||
///
|
||||
/// The resolution of the timer is system dependent, but is usually on the order
|
||||
/// of a few micro- or nanoseconds. It uses the highest-resolution monotonic
|
||||
/// time source on each supported operating system.
|
||||
///
|
||||
/// @return The current time, in seconds, or zero if an
|
||||
/// error occurred.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread. Reading and
|
||||
/// writing of the internal base time is not atomic, so it needs to be
|
||||
/// externally synchronized with calls to @ref glfwSetTime.
|
||||
///
|
||||
/// see also: time
|
||||
pub inline fn getTime() f64 {
|
||||
internal_debug.assertInitialized();
|
||||
const time = c.glfwGetTime();
|
||||
if (time != 0) return time;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetTime` returns `0` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Sets the GLFW time.
|
||||
///
|
||||
/// This function sets the current GLFW time, in seconds. The value must be a positive finite
|
||||
/// number less than or equal to 18446744073.0, which is approximately 584.5 years.
|
||||
///
|
||||
/// This function and @ref glfwGetTime are helper functions on top of glfw.getTimerFrequency and
|
||||
/// glfw.getTimerValue.
|
||||
///
|
||||
/// @param[in] time The new value, in seconds.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.InvalidValue.
|
||||
///
|
||||
/// The upper limit of GLFW time is calculated as `floor((2^64 - 1) / 10^9)` and is due to
|
||||
/// implementations storing nanoseconds in 64 bits. The limit may be increased in the future.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread. Reading and writing of the internal
|
||||
/// base time is not atomic, so it needs to be externally synchronized with calls to glfw.getTime.
|
||||
///
|
||||
/// see also: time
|
||||
pub inline fn setTime(time: f64) void {
|
||||
internal_debug.assertInitialized();
|
||||
|
||||
std.debug.assert(!std.math.isNan(time));
|
||||
std.debug.assert(time >= 0);
|
||||
// assert time is lteq to largest number of seconds representable by u64 with nanosecond precision
|
||||
std.debug.assert(time <= max_time: {
|
||||
const @"2^64" = std.math.maxInt(u64);
|
||||
break :max_time @divTrunc(@"2^64", std.time.ns_per_s);
|
||||
});
|
||||
|
||||
c.glfwSetTime(time);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidValue => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the current value of the raw timer.
|
||||
///
|
||||
/// This function returns the current value of the raw timer, measured in `1/frequency` seconds. To
|
||||
/// get the frequency, call glfw.getTimerFrequency.
|
||||
///
|
||||
/// @return The value of the timer, or zero if an error occurred.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: time, glfw.getTimerFrequency
|
||||
pub inline fn getTimerValue() u64 {
|
||||
internal_debug.assertInitialized();
|
||||
const value = c.glfwGetTimerValue();
|
||||
if (value != 0) return value;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetTimerValue` returns `0` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Returns the frequency, in Hz, of the raw timer.
|
||||
///
|
||||
/// This function returns the frequency, in Hz, of the raw timer.
|
||||
///
|
||||
/// @return The frequency of the timer, in Hz, or zero if an error occurred.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: time, glfw.getTimerValue
|
||||
pub inline fn getTimerFrequency() u64 {
|
||||
internal_debug.assertInitialized();
|
||||
const frequency = c.glfwGetTimerFrequency();
|
||||
if (frequency != 0) return frequency;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetTimerFrequency` returns `0` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
test "getTime" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = getTime();
|
||||
}
|
||||
|
||||
test "setTime" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.setTime(1234);
|
||||
}
|
||||
|
||||
test "getTimerValue" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.getTimerValue();
|
||||
}
|
||||
|
||||
test "getTimerFrequency" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.getTimerFrequency();
|
||||
}
|
||||
18
libs/glfw/src/version.zig
Normal file
18
libs/glfw/src/version.zig
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//! GLFW version info
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
/// The major version number of the GLFW library.
|
||||
///
|
||||
/// This is incremented when the API is changed in non-compatible ways.
|
||||
pub const major = c.GLFW_VERSION_MAJOR;
|
||||
|
||||
/// The minor version number of the GLFW library.
|
||||
///
|
||||
/// This is incremented when features are added to the API but it remains backward-compatible.
|
||||
pub const minor = c.GLFW_VERSION_MINOR;
|
||||
|
||||
/// The revision number of the GLFW library.
|
||||
///
|
||||
/// This is incremented when a bug fix release is made that does not contain any API changes.
|
||||
pub const revision = c.GLFW_VERSION_REVISION;
|
||||
307
libs/glfw/src/vulkan.zig
Normal file
307
libs/glfw/src/vulkan.zig
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
const std = @import("std");
|
||||
|
||||
const c = @import("c.zig").c;
|
||||
const Error = @import("errors.zig").Error;
|
||||
const getError = @import("errors.zig").getError;
|
||||
const Window = @import("Window.zig");
|
||||
|
||||
const internal_debug = @import("internal_debug.zig");
|
||||
|
||||
/// Sets the desired Vulkan `vkGetInstanceProcAddr` function.
|
||||
///
|
||||
/// This function sets the `vkGetInstanceProcAddr` function that GLFW will use for all
|
||||
/// Vulkan related entry point queries.
|
||||
///
|
||||
/// This feature is mostly useful on macOS, if your copy of the Vulkan loader is in
|
||||
/// a location where GLFW cannot find it through dynamic loading, or if you are still
|
||||
/// using the static library version of the loader.
|
||||
///
|
||||
/// If set to `NULL`, GLFW will try to load the Vulkan loader dynamically by its standard
|
||||
/// name and get this function from there. This is the default behavior.
|
||||
///
|
||||
/// The standard name of the loader is `vulkan-1.dll` on Windows, `libvulkan.so.1` on
|
||||
/// Linux and other Unix-like systems and `libvulkan.1.dylib` on macOS. If your code is
|
||||
/// also loading it via these names then you probably don't need to use this function.
|
||||
///
|
||||
/// The function address you set is never reset by GLFW, but it only takes effect during
|
||||
/// initialization. Once GLFW has been initialized, any updates will be ignored until the
|
||||
/// library is terminated and initialized again.
|
||||
///
|
||||
/// remark: This function may be called before glfw.Init.
|
||||
///
|
||||
/// thread_safety: This function must only be called from the main thread.
|
||||
pub fn initVulkanLoader(loader_function: ?VKGetInstanceProcAddr) void {
|
||||
c.glfwInitVulkanLoader(loader_function orelse null);
|
||||
}
|
||||
|
||||
pub const VKGetInstanceProcAddr = if (@import("builtin").zig_backend == .stage1)
|
||||
fn (vk_instance: c.VkInstance, name: [*c]const u8) callconv(.C) ?VKProc
|
||||
else
|
||||
*const fn (vk_instance: c.VkInstance, name: [*c]const u8) callconv(.C) ?VKProc;
|
||||
|
||||
/// Returns whether the Vulkan loader and an ICD have been found.
|
||||
///
|
||||
/// This function returns whether the Vulkan loader and any minimally functional ICD have been
|
||||
/// found.
|
||||
///
|
||||
/// The availability of a Vulkan loader and even an ICD does not by itself guarantee that surface
|
||||
/// creation or even instance creation is possible. Call glfw.getRequiredInstanceExtensions
|
||||
/// to check whether the extensions necessary for Vulkan surface creation are available and
|
||||
/// glfw.getPhysicalDevicePresentationSupport to check whether a queue family of a physical device
|
||||
/// supports image presentation.
|
||||
///
|
||||
/// @return `true` if Vulkan is minimally available, or `false` otherwise.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
pub inline fn vulkanSupported() bool {
|
||||
internal_debug.assertInitialized();
|
||||
const supported = c.glfwVulkanSupported();
|
||||
getError() catch unreachable; // Only error 'GLFW_NOT_INITIALIZED' is impossible
|
||||
return supported == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
/// Returns the Vulkan instance extensions required by GLFW.
|
||||
///
|
||||
/// This function returns an array of names of Vulkan instance extensions required by GLFW for
|
||||
/// creating Vulkan surfaces for GLFW windows. If successful, the list will always contain
|
||||
/// `VK_KHR_surface`, so if you don't require any additional extensions you can pass this list
|
||||
/// directly to the `VkInstanceCreateInfo` struct.
|
||||
///
|
||||
/// If Vulkan is not available on the machine, this function returns null and generates a
|
||||
/// glfw.Error.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at least
|
||||
/// minimally available.
|
||||
///
|
||||
/// If Vulkan is available but no set of extensions allowing window surface creation was found,
|
||||
/// this function returns null. You may still use Vulkan for off-screen rendering and compute work.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized and glfw.Error.APIUnavailable.
|
||||
///
|
||||
/// Additional extensions may be required by future versions of GLFW. You should check if any
|
||||
/// extensions you wish to enable are already in the returned array, as it is an error to specify
|
||||
/// an extension more than once in the `VkInstanceCreateInfo` struct.
|
||||
///
|
||||
/// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it
|
||||
/// yourself. It is guaranteed to be valid only until the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
///
|
||||
/// see also: vulkan_ext, glfwCreateWindowSurface
|
||||
pub inline fn getRequiredInstanceExtensions() error{APIUnavailable}![][*:0]const u8 {
|
||||
internal_debug.assertInitialized();
|
||||
var count: u32 = 0;
|
||||
if (c.glfwGetRequiredInstanceExtensions(&count)) |extensions| return @ptrCast([*][*:0]const u8, extensions)[0..count];
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.APIUnavailable => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwGetRequiredInstanceExtensions` returns `null` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
/// Vulkan API function pointer type.
|
||||
///
|
||||
/// Generic function pointer used for returning Vulkan API function pointers.
|
||||
///
|
||||
/// see also: vulkan_proc, glfw.getInstanceProcAddress
|
||||
pub const VKProc = if (@import("builtin").zig_backend == .stage1)
|
||||
fn () callconv(.C) void
|
||||
else
|
||||
*const fn () callconv(.C) void;
|
||||
|
||||
/// Returns the address of the specified Vulkan instance function.
|
||||
///
|
||||
/// This function returns the address of the specified Vulkan core or extension function for the
|
||||
/// specified instance. If instance is set to null it can return any function exported from the
|
||||
/// Vulkan loader, including at least the following functions:
|
||||
///
|
||||
/// - `vkEnumerateInstanceExtensionProperties`
|
||||
/// - `vkEnumerateInstanceLayerProperties`
|
||||
/// - `vkCreateInstance`
|
||||
/// - `vkGetInstanceProcAddr`
|
||||
///
|
||||
/// If Vulkan is not available on the machine, this function returns null and generates a
|
||||
/// glfw.Error.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at least
|
||||
/// minimally available.
|
||||
///
|
||||
/// This function is equivalent to calling `vkGetInstanceProcAddr` with a platform-specific query
|
||||
/// of the Vulkan loader as a fallback.
|
||||
///
|
||||
/// @param[in] instance The Vulkan instance to query, or null to retrieve functions related to
|
||||
/// instance creation.
|
||||
/// @param[in] procname The ASCII encoded name of the function.
|
||||
/// @return The address of the function, or null if an error occurred.
|
||||
///
|
||||
/// To maintain ABI compatability with the C glfwGetInstanceProcAddress, as it is commonly passed
|
||||
/// into libraries expecting that exact ABI, this function does not return an error. Instead, if
|
||||
/// glfw.Error.NotInitialized or glfw.Error.APIUnavailable would occur this function will panic.
|
||||
/// You may check glfw.vulkanSupported prior to invoking this function.
|
||||
///
|
||||
/// @pointer_lifetime The returned function pointer is valid until the library is terminated.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread.
|
||||
pub fn getInstanceProcAddress(vk_instance: ?*anyopaque, proc_name: [*:0]const u8) callconv(.C) ?VKProc {
|
||||
internal_debug.assertInitialized();
|
||||
if (c.glfwGetInstanceProcAddress(if (vk_instance) |v| @ptrCast(c.VkInstance, v) else null, proc_name)) |proc_address| return proc_address;
|
||||
getError() catch |err| @panic(@errorName(err));
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Returns whether the specified queue family can present images.
|
||||
///
|
||||
/// This function returns whether the specified queue family of the specified physical device
|
||||
/// supports presentation to the platform GLFW was built for.
|
||||
///
|
||||
/// If Vulkan or the required window surface creation instance extensions are not available on the
|
||||
/// machine, or if the specified instance was not created with the required extensions, this
|
||||
/// function returns `GLFW_FALSE` and generates a glfw.Error.APIUnavailable error. Call
|
||||
/// glfw.vulkanSupported to check whether Vulkan is at least minimally available and
|
||||
/// glfw.getRequiredInstanceExtensions to check what instance extensions are required.
|
||||
///
|
||||
/// @param[in] instance The instance that the physical device belongs to.
|
||||
/// @param[in] device The physical device that the queue family belongs to.
|
||||
/// @param[in] queuefamily The index of the queue family to query.
|
||||
/// @return `true` if the queue family supports presentation, or `false` otherwise.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.APIUnavailable and glfw.Error.PlatformError.
|
||||
///
|
||||
/// macos: This function currently always returns `true`, as the `VK_MVK_macos_surface` and
|
||||
/// 'VK_EXT_metal_surface' extension does not provide a `vkGetPhysicalDevice*PresentationSupport` type function.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread. For synchronization details of
|
||||
/// Vulkan objects, see the Vulkan specification.
|
||||
///
|
||||
/// see also: vulkan_present
|
||||
pub inline fn getPhysicalDevicePresentationSupport(
|
||||
vk_instance: *anyopaque,
|
||||
vk_physical_device: *anyopaque,
|
||||
queue_family: u32,
|
||||
) error{ APIUnavailable, PlatformError }!bool {
|
||||
internal_debug.assertInitialized();
|
||||
const v = c.glfwGetPhysicalDevicePresentationSupport(
|
||||
@ptrCast(c.VkInstance, vk_instance),
|
||||
@ptrCast(c.VkPhysicalDevice, vk_physical_device),
|
||||
queue_family,
|
||||
);
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.APIUnavailable, Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
return v == c.GLFW_TRUE;
|
||||
}
|
||||
|
||||
/// Creates a Vulkan surface for the specified window.
|
||||
///
|
||||
/// This function creates a Vulkan surface for the specified window.
|
||||
///
|
||||
/// If the Vulkan loader or at least one minimally functional ICD were not found, this function
|
||||
/// returns `VK_ERROR_INITIALIZATION_FAILED` and generates a glfw.Error.APIUnavailable error. Call
|
||||
/// glfw.vulkanSupported to check whether Vulkan is at least minimally available.
|
||||
///
|
||||
/// If the required window surface creation instance extensions are not available or if the
|
||||
/// specified instance was not created with these extensions enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT`
|
||||
/// and generates a glfw.Error.APIUnavailable error. Call glfw.getRequiredInstanceExtensions to
|
||||
/// check what instance extensions are required.
|
||||
///
|
||||
/// The window surface cannot be shared with another API so the window must have been created with
|
||||
/// the client api hint set to `GLFW_NO_API` otherwise it generates a glfw.Error.InvalidValue error
|
||||
/// and returns `VK_ERROR_NATIVE_WINDOW_IN_USE_KHR`.
|
||||
///
|
||||
/// The window surface must be destroyed before the specified Vulkan instance. It is the
|
||||
/// responsibility of the caller to destroy the window surface. GLFW does not destroy it for you.
|
||||
/// Call `vkDestroySurfaceKHR` to destroy the surface.
|
||||
///
|
||||
/// @param[in] vk_instance The Vulkan instance to create the surface in.
|
||||
/// @param[in] window The window to create the surface for.
|
||||
/// @param[in] vk_allocation_callbacks The allocator to use, or null to use the default
|
||||
/// allocator.
|
||||
/// @param[out] surface Where to store the handle of the surface. This is set
|
||||
/// to `VK_NULL_HANDLE` if an error occurred.
|
||||
/// @return `VkResult` type, `VK_SUCCESS` if successful, or a Vulkan error code if an
|
||||
/// error occurred.
|
||||
///
|
||||
/// Possible errors include glfw.Error.NotInitialized, glfw.Error.APIUnavailable, glfw.Error.PlatformError and glfw.Error.InvalidValue
|
||||
///
|
||||
/// If an error occurs before the creation call is made, GLFW returns the Vulkan error code most
|
||||
/// appropriate for the error. Appropriate use of glfw.vulkanSupported and glfw.getRequiredInstanceExtensions
|
||||
/// should eliminate almost all occurrences of these errors.
|
||||
///
|
||||
/// macos: GLFW prefers the `VK_EXT_metal_surface` extension, with the `VK_MVK_macos_surface`
|
||||
/// extension as a fallback. The name of the selected extension, if any, is included in the array
|
||||
/// returned by glfw.getRequiredInstanceExtensions.
|
||||
///
|
||||
/// macos: This function currently only supports the `VK_MVK_macos_surface` extension from MoltenVK.
|
||||
///
|
||||
/// macos: This function creates and sets a `CAMetalLayer` instance for the window content view,
|
||||
/// which is required for MoltenVK to function.
|
||||
///
|
||||
/// x11: By default GLFW prefers the `VK_KHR_xcb_surface` extension, with the `VK_KHR_xlib_surface`
|
||||
/// extension as a fallback. You can make `VK_KHR_xlib_surface` the preferred extension by setting
|
||||
/// glfw.InitHints.x11_xcb_vulkan_surface. The name of the selected extension, if any, is included
|
||||
/// in the array returned by glfw.getRequiredInstanceExtensions.
|
||||
///
|
||||
/// @thread_safety This function may be called from any thread. For synchronization details of
|
||||
/// Vulkan objects, see the Vulkan specification.
|
||||
///
|
||||
/// see also: vulkan_surface, glfw.getRequiredInstanceExtensions
|
||||
pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_allocation_callbacks: anytype, vk_surface_khr: anytype) error{ APIUnavailable, PlatformError }!i32 {
|
||||
internal_debug.assertInitialized();
|
||||
// zig-vulkan uses enums to represent opaque pointers:
|
||||
// pub const Instance = enum(usize) { null_handle = 0, _ };
|
||||
const instance: c.VkInstance = switch (@typeInfo(@TypeOf(vk_instance))) {
|
||||
.Enum => @intToPtr(c.VkInstance, @enumToInt(vk_instance)),
|
||||
else => @ptrCast(c.VkInstance, vk_instance),
|
||||
};
|
||||
|
||||
const v = c.glfwCreateWindowSurface(
|
||||
instance,
|
||||
window.handle,
|
||||
if (vk_allocation_callbacks == null) null else @ptrCast(*const c.VkAllocationCallbacks, @alignCast(@alignOf(c.VkAllocationCallbacks), vk_allocation_callbacks)),
|
||||
@ptrCast(*c.VkSurfaceKHR, @alignCast(@alignOf(c.VkSurfaceKHR), vk_surface_khr)),
|
||||
);
|
||||
if (v == c.VK_SUCCESS) return v;
|
||||
getError() catch |err| return switch (err) {
|
||||
Error.NotInitialized => unreachable,
|
||||
Error.InvalidValue => @panic("Attempted to use window with client api to create vulkan surface."),
|
||||
Error.APIUnavailable, Error.PlatformError => |e| e,
|
||||
else => unreachable,
|
||||
};
|
||||
// `glfwCreateWindowSurface` returns `!VK_SUCCESS` only for errors
|
||||
unreachable;
|
||||
}
|
||||
|
||||
test "vulkanSupported" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.vulkanSupported();
|
||||
}
|
||||
|
||||
test "getRequiredInstanceExtensions" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
_ = glfw.getRequiredInstanceExtensions() catch |err| std.debug.print("failed to get vulkan instance extensions, error={}\n", .{err});
|
||||
}
|
||||
|
||||
test "getInstanceProcAddress" {
|
||||
const glfw = @import("main.zig");
|
||||
try glfw.init(.{});
|
||||
defer glfw.terminate();
|
||||
|
||||
// syntax check only, we don't have a real vulkan instance and so this function would panic.
|
||||
_ = glfw.getInstanceProcAddress;
|
||||
}
|
||||
|
||||
test "syntax" {
|
||||
// Best we can do for these two functions in terms of testing in lieu of an actual Vulkan
|
||||
// context.
|
||||
_ = getPhysicalDevicePresentationSupport;
|
||||
_ = createWindowSurface;
|
||||
_ = initVulkanLoader;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue