From 6f32a338c0828cb256db8465ce56d0a9c591d729 Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Wed, 9 Feb 2022 23:03:35 +0000 Subject: [PATCH] glfw: use comptime magic to remove `InternalUserPointer` and associated overhead --- glfw/src/Joystick.zig | 26 ++- glfw/src/Monitor.zig | 38 ++-- glfw/src/Window.zig | 515 ++++++++++++++++++++++++------------------ glfw/src/errors.zig | 4 +- glfw/src/opengl.zig | 9 +- 5 files changed, 330 insertions(+), 262 deletions(-) diff --git a/glfw/src/Joystick.zig b/glfw/src/Joystick.zig index 1500483b..68aaa01f 100644 --- a/glfw/src/Joystick.zig +++ b/glfw/src/Joystick.zig @@ -352,12 +352,6 @@ pub const Event = enum(c_int) { disconnected = c.GLFW_DISCONNECTED, }; -var _callback: ?fn (joystick: Joystick, event: Event) void = null; - -fn callbackWrapper(jid: c_int, event: c_int) callconv(.C) void { - _callback.?(Joystick{ .jid = @intToEnum(Joystick.Id, jid) }, @intToEnum(Event, event)); -} - /// Sets the joystick configuration callback. /// /// This function sets the joystick configuration callback, or removes the currently set callback. @@ -379,10 +373,24 @@ fn callbackWrapper(jid: c_int, event: c_int) callconv(.C) void { /// @thread_safety This function must only be called from the main thread. /// /// see also: joystick_event -pub inline fn setCallback(callback: ?fn (joystick: Joystick, event: Event) void) void { +pub inline fn setCallback(comptime callback: ?fn (joystick: Joystick, event: Event) void) void { internal_debug.assertInitialized(); - _callback = callback; - _ = if (_callback != null) c.glfwSetJoystickCallback(callbackWrapper) else c.glfwSetJoystickCallback(null); + + 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, diff --git a/glfw/src/Monitor.zig b/glfw/src/Monitor.zig index df7599b9..4199ad8d 100644 --- a/glfw/src/Monitor.zig +++ b/glfw/src/Monitor.zig @@ -422,9 +422,6 @@ pub inline fn getPrimary() ?Monitor { return null; } -var callback_fn_ptr: ?usize = null; -var callback_data_ptr: ?usize = undefined; - /// Describes an event relating to a monitor. pub const Event = enum(c_int) { /// The device was connected. @@ -455,27 +452,24 @@ pub const Event = enum(c_int) { /// @thread_safety This function must only be called from the main thread. /// /// see also: monitor_event -pub inline fn setCallback(comptime Data: type, data: *Data, f: ?*const fn (monitor: Monitor, event: Event, data: *Data) void) void { +pub inline fn setCallback(comptime callback: ?fn (monitor: Monitor, event: Event) void) void { internal_debug.assertInitialized(); - if (f) |new_callback| { - callback_fn_ptr = @ptrToInt(new_callback); - callback_data_ptr = @ptrToInt(data); - const NewCallback = @TypeOf(new_callback); - _ = c.glfwSetMonitorCallback((struct { - fn callbackC(monitor: ?*c.GLFWmonitor, event: c_int) callconv(.C) void { - const callback = @intToPtr(NewCallback, callback_fn_ptr.?); - callback.*( + + 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), - @intToPtr(*Data, callback_data_ptr.?), - ); + }); } - }).callbackC); + }; + + if (c.glfwSetMonitorCallback(CWrapper.monitorCallbackWrapper) != null) return; } else { - _ = c.glfwSetMonitorCallback(null); - callback_fn_ptr = null; - callback_data_ptr = null; + if (c.glfwSetMonitorCallback(null) != null) return; } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, @@ -576,14 +570,12 @@ test "setCallback" { try glfw.init(.{}); defer glfw.terminate(); - var custom_data: u32 = 5; - setCallback(u32, &custom_data, &(struct { - fn callback(monitor: Monitor, event: Event, data: *u32) void { + setCallback(struct { + fn callback(monitor: Monitor, event: Event) void { _ = monitor; _ = event; - _ = data; } - }).callback); + }.callback); } test "getVideoModes" { diff --git a/glfw/src/Window.zig b/glfw/src/Window.zig index 6fd5044e..e03e8d8a 100644 --- a/glfw/src/Window.zig +++ b/glfw/src/Window.zig @@ -23,49 +23,10 @@ const Window = @This(); handle: *c.GLFWwindow, /// Returns a Zig GLFW window from an underlying C GLFW window handle. -/// -/// Note that the Zig GLFW library stores a custom user pointer in order to make callbacks nicer, -/// see glfw.Window.InternalUserPointer. -pub inline fn from(handle: *c.GLFWwindow) mem.Allocator.Error!Window { - internal_debug.assertInitialized(); - const ptr = c.glfwGetWindowUserPointer(handle); - if (ptr == null) { - const internal = try std.heap.c_allocator.create(InternalUserPointer); - c.glfwSetWindowUserPointer(handle, @ptrCast(*anyopaque, internal)); - getError() catch |err| return switch (err) { - Error.NotInitialized => unreachable, - else => unreachable, - }; - } +pub inline fn from(handle: *c.GLFWwindow) Window { return Window{ .handle = handle }; } -/// The actual type which is stored by the Zig GLFW library in glfwSetWindowUserPointer. -/// -/// This is used to internally carry function callbacks with nicer Zig interfaces. -pub const InternalUserPointer = struct { - /// The actual user pointer that the user of the library wished to set via setUserPointer. - user_pointer: ?*anyopaque, - - // Callbacks to be invoked by wrapper functions. - setPosCallback: ?fn (window: Window, xpos: i32, ypos: i32) void, - setSizeCallback: ?fn (window: Window, width: i32, height: i32) void, - setCloseCallback: ?fn (window: Window) void, - setRefreshCallback: ?fn (window: Window) void, - setFocusCallback: ?fn (window: Window, focused: bool) void, - setIconifyCallback: ?fn (window: Window, iconified: bool) void, - setMaximizeCallback: ?fn (window: Window, maximized: bool) void, - setFramebufferSizeCallback: ?fn (window: Window, width: u32, height: u32) void, - setContentScaleCallback: ?fn (window: Window, xscale: f32, yscale: f32) void, - setKeyCallback: ?fn (window: Window, key: Key, scancode: i32, action: Action, mods: Mods) void, - setCharCallback: ?fn (window: Window, codepoint: u21) void, - setMouseButtonCallback: ?fn (window: Window, button: MouseButton, action: Action, mods: Mods) void, - setCursorPosCallback: ?fn (window: Window, xpos: f64, ypos: f64) void, - setCursorEnterCallback: ?fn (window: Window, entered: bool) void, - setScrollCallback: ?fn (window: Window, xoffset: f64, yoffset: f64) void, - setDropCallback: ?fn (window: Window, paths: [][*:0]const u8) void, -}; - /// Resets all window hints to their default values. /// /// This function resets all window hints to their default values. @@ -418,7 +379,7 @@ pub inline fn create( monitor: ?Monitor, share: ?Window, hints: Hints, -) (mem.Allocator.Error || error{ APIUnavailable, VersionUnavailable, FormatUnavailable, PlatformError })!Window { +) error{ APIUnavailable, VersionUnavailable, FormatUnavailable, PlatformError }!Window { internal_debug.assertInitialized(); const ignore_hints_struct = if (comptime @import("builtin").is_test) testing_ignore_window_hints_struct else false; if (!ignore_hints_struct) hints.set(); @@ -468,9 +429,7 @@ var testing_ignore_window_hints_struct = if (@import("builtin").is_test) false e /// see also: window_creation, glfw.Window.create pub inline fn destroy(self: Window) void { internal_debug.assertInitialized(); - const internal = self.getInternal(); c.glfwDestroyWindow(self.handle); - std.heap.c_allocator.destroy(internal); // Technically, glfwDestroyWindow could produce errors including glfw.Error.NotInitialized and // glfw.Error.PlatformError. But how would anybody handle them? By creating a new window to @@ -1353,13 +1312,6 @@ pub inline fn setAttrib(self: Window, attrib: Attrib, value: bool) error{Platfor }; } -pub inline fn getInternal(self: Window) *InternalUserPointer { - internal_debug.assertInitialized(); - const ptr = c.glfwGetWindowUserPointer(self.handle); - if (ptr) |p| return @ptrCast(*InternalUserPointer, @alignCast(@alignOf(*InternalUserPointer), p)); - @panic("expected GLFW window user pointer to be *glfw.Window.InternalUserPointer, found null"); -} - /// Sets the user pointer of the specified window. /// /// This function sets the user-defined pointer of the specified window. The current value is @@ -1370,8 +1322,11 @@ pub inline fn getInternal(self: Window) *InternalUserPointer { /// see also: window_userptr, glfw.Window.getUserPointer pub inline fn setUserPointer(self: Window, pointer: ?*anyopaque) void { internal_debug.assertInitialized(); - const internal = self.getInternal(); - internal.user_pointer = pointer; + c.glfwSetWindowUserPointer(self.handle, pointer); + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; } /// Returns the user pointer of the specified window. @@ -1384,18 +1339,14 @@ pub inline fn setUserPointer(self: Window, pointer: ?*anyopaque) void { /// see also: window_userptr, glfw.Window.setUserPointer pub inline fn getUserPointer(self: Window, comptime T: type) ?*T { internal_debug.assertInitialized(); - const internal = self.getInternal(); - if (internal.user_pointer) |p| return @ptrCast(?*T, @alignCast(@alignOf(T), p)); + if (c.glfwGetWindowUserPointer(self.handle)) |user_pointer| return @ptrCast(?*T, @alignCast(@alignOf(T), user_pointer)); + getError() catch |err| return switch (err) { + Error.NotInitialized => unreachable, + else => unreachable, + }; return null; } -fn setPosCallbackWrapper(handle: ?*c.GLFWwindow, xpos: c_int, ypos: c_int) callconv(.C) void { - internal_debug.assertInitialized(); - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setPosCallback.?(window, @intCast(i32, xpos), @intCast(i32, ypos)); -} - /// Sets the position callback for the specified window. /// /// This function sets the position callback of the specified window, which is called when the @@ -1416,24 +1367,31 @@ fn setPosCallbackWrapper(handle: ?*c.GLFWwindow, xpos: c_int, ypos: c_int) callc /// @thread_safety This function must only be called from the main thread. /// /// see also: window_pos -pub inline fn setPosCallback(self: Window, callback: ?fn (window: Window, xpos: i32, ypos: i32) void) void { +pub inline fn setPosCallback(self: Window, comptime callback: ?fn (window: Window, xpos: i32, ypos: i32) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setPosCallback = callback; - _ = c.glfwSetWindowPosCallback(self.handle, if (callback != null) setPosCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn posCallbackWrapper(handle: ?*c.GLFWwindow, xpos: c_int, ypos: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + @intCast(i32, xpos), + @intCast(i32, ypos), + }); + } + }; + + if (c.glfwSetWindowPosCallback(self.handle, CWrapper.posCallbackWrapper) != null) return; + } else { + if (c.glfwSetWindowPosCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setSizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { - internal_debug.assertInitialized(); - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setSizeCallback.?(window, @intCast(i32, width), @intCast(i32, height)); -} - /// Sets the size callback for the specified window. /// /// This function sets the size callback of the specified window, which is called when the window @@ -1447,24 +1405,31 @@ fn setSizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) c /// @thread_safety This function must only be called from the main thread. /// /// see also: window_size -pub inline fn setSizeCallback(self: Window, callback: ?fn (window: Window, width: i32, height: i32) void) void { +pub inline fn setSizeCallback(self: Window, comptime callback: ?fn (window: Window, width: i32, height: i32) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setSizeCallback = callback; - _ = c.glfwSetWindowSizeCallback(self.handle, if (callback != null) setSizeCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn sizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + @intCast(i32, width), + @intCast(i32, height), + }); + } + }; + + if (c.glfwSetWindowSizeCallback(self.handle, CWrapper.sizeCallbackWrapper) != null) return; + } else { + if (c.glfwSetWindowSizeCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setCloseCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { - internal_debug.assertInitialized(); - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setCloseCallback.?(window); -} - /// Sets the close callback for the specified window. /// /// This function sets the close callback of the specified window, which is called when the user @@ -1486,23 +1451,29 @@ fn setCloseCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_close -pub inline fn setCloseCallback(self: Window, callback: ?fn (window: Window) void) void { +pub inline fn setCloseCallback(self: Window, comptime callback: ?fn (window: Window) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setCloseCallback = callback; - _ = c.glfwSetWindowCloseCallback(self.handle, if (callback != null) setCloseCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn closeCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + }); + } + }; + + if (c.glfwSetWindowCloseCallback(self.handle, CWrapper.closeCallbackWrapper) != null) return; + } else { + if (c.glfwSetWindowCloseCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setRefreshCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setRefreshCallback.?(window); -} - /// Sets the refresh callback for the specified window. /// /// This function sets the refresh callback of the specified window, which is @@ -1522,24 +1493,29 @@ fn setRefreshCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { /// @thread_safety This function must only be called from the main thread. /// /// see also: window_refresh -pub inline fn setRefreshCallback(self: Window, callback: ?fn (window: Window) void) void { +pub inline fn setRefreshCallback(self: Window, comptime callback: ?fn (window: Window) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setRefreshCallback = callback; - _ = c.glfwSetWindowRefreshCallback(self.handle, if (callback != null) setRefreshCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn refreshCallbackWrapper(handle: ?*c.GLFWwindow) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + }); + } + }; + + if (c.glfwSetWindowRefreshCallback(self.handle, CWrapper.refreshCallbackWrapper) != null) return; + } else { + if (c.glfwSetWindowRefreshCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setFocusCallbackWrapper(handle: ?*c.GLFWwindow, focused: c_int) callconv(.C) void { - internal_debug.assertInitialized(); - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setFocusCallback.?(window, if (focused == c.GLFW_TRUE) true else false); -} - /// Sets the focus callback for the specified window. /// /// This function sets the focus callback of the specified window, which is @@ -1560,24 +1536,30 @@ fn setFocusCallbackWrapper(handle: ?*c.GLFWwindow, focused: c_int) callconv(.C) /// @thread_safety This function must only be called from the main thread. /// /// see also: window_focus -pub inline fn setFocusCallback(self: Window, callback: ?fn (window: Window, focused: bool) void) void { +pub inline fn setFocusCallback(self: Window, comptime callback: ?fn (window: Window, focused: bool) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setFocusCallback = callback; - _ = c.glfwSetWindowFocusCallback(self.handle, if (callback != null) setFocusCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn focusCallbackWrapper(handle: ?*c.GLFWwindow, focused: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + focused == c.GLFW_TRUE, + }); + } + }; + + if (c.glfwSetWindowFocusCallback(self.handle, CWrapper.focusCallbackWrapper) != null) return; + } else { + if (c.glfwSetWindowFocusCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setIconifyCallbackWrapper(handle: ?*c.GLFWwindow, iconified: c_int) callconv(.C) void { - internal_debug.assertInitialized(); - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setIconifyCallback.?(window, if (iconified == c.GLFW_TRUE) true else false); -} - /// Sets the iconify callback for the specified window. /// /// This function sets the iconification callback of the specified window, which @@ -1596,24 +1578,30 @@ fn setIconifyCallbackWrapper(handle: ?*c.GLFWwindow, iconified: c_int) callconv( /// @thread_safety This function must only be called from the main thread. /// /// see also: window_iconify -pub inline fn setIconifyCallback(self: Window, callback: ?fn (window: Window, iconified: bool) void) void { +pub inline fn setIconifyCallback(self: Window, comptime callback: ?fn (window: Window, iconified: bool) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setIconifyCallback = callback; - _ = c.glfwSetWindowIconifyCallback(self.handle, if (callback != null) setIconifyCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn iconifyCallbackWrapper(handle: ?*c.GLFWwindow, iconified: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + iconified == c.GLFW_TRUE, + }); + } + }; + + if (c.glfwSetWindowIconifyCallback(self.handle, CWrapper.iconifyCallbackWrapper) != null) return; + } else { + if (c.glfwSetWindowIconifyCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setMaximizeCallbackWrapper(handle: ?*c.GLFWwindow, maximized: c_int) callconv(.C) void { - internal_debug.assertInitialized(); - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setMaximizeCallback.?(window, if (maximized == c.GLFW_TRUE) true else false); -} - /// Sets the maximize callback for the specified window. /// /// This function sets the maximization callback of the specified window, which @@ -1630,24 +1618,30 @@ fn setMaximizeCallbackWrapper(handle: ?*c.GLFWwindow, maximized: c_int) callconv /// /// see also: window_maximize // GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun callback); -pub inline fn setMaximizeCallback(self: Window, callback: ?fn (window: Window, maximized: bool) void) void { +pub inline fn setMaximizeCallback(self: Window, comptime callback: ?fn (window: Window, maximized: bool) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setMaximizeCallback = callback; - _ = c.glfwSetWindowMaximizeCallback(self.handle, if (callback != null) setMaximizeCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn maximizeCallbackWrapper(handle: ?*c.GLFWwindow, maximized: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + maximized == c.GLFW_TRUE, + }); + } + }; + + if (c.glfwSetWindowMaximizeCallback(self.handle, CWrapper.maximizeCallbackWrapper) != null) return; + } else { + if (c.glfwSetWindowMaximizeCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setFramebufferSizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { - internal_debug.assertInitialized(); - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setFramebufferSizeCallback.?(window, @intCast(u32, width), @intCast(u32, height)); -} - /// Sets the framebuffer resize callback for the specified window. /// /// This function sets the framebuffer resize callback of the specified window, @@ -1664,24 +1658,31 @@ fn setFramebufferSizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, heigh /// @thread_safety This function must only be called from the main thread. /// /// see also: window_fbsize -pub inline fn setFramebufferSizeCallback(self: Window, callback: ?fn (window: Window, width: u32, height: u32) void) void { +pub inline fn setFramebufferSizeCallback(self: Window, comptime callback: ?fn (window: Window, width: u32, height: u32) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setFramebufferSizeCallback = callback; - _ = c.glfwSetFramebufferSizeCallback(self.handle, if (callback != null) setFramebufferSizeCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn framebufferSizeCallbackWrapper(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + @intCast(u32, width), + @intCast(u32, height), + }); + } + }; + + if (c.glfwSetFramebufferSizeCallback(self.handle, CWrapper.framebufferSizeCallbackWrapper) != null) return; + } else { + if (c.glfwSetFramebufferSizeCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setContentScaleCallbackWrapper(handle: ?*c.GLFWwindow, xscale: f32, yscale: f32) callconv(.C) void { - internal_debug.assertInitialized(); - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setContentScaleCallback.?(window, xscale, yscale); -} - /// Sets the window content scale callback for the specified window. /// /// This function sets the window content scale callback of the specified window, @@ -1698,11 +1699,25 @@ fn setContentScaleCallbackWrapper(handle: ?*c.GLFWwindow, xscale: f32, yscale: f /// @thread_safety This function must only be called from the main thread. /// /// see also: window_scale, glfw.Window.getContentScale -pub inline fn setContentScaleCallback(self: Window, callback: ?fn (window: Window, xscale: f32, yscale: f32) void) void { +pub inline fn setContentScaleCallback(self: Window, comptime callback: ?fn (window: Window, xscale: f32, yscale: f32) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setContentScaleCallback = callback; - _ = c.glfwSetWindowContentScaleCallback(self.handle, if (callback != null) setContentScaleCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn windowScaleCallbackWrapper(handle: ?*c.GLFWwindow, xscale: f32, yscale: f32) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + xscale, + yscale, + }); + } + }; + + if (c.glfwSetWindowContentScaleCallback(self.handle, CWrapper.windowScaleCallbackWrapper) != null) return; + } else { + if (c.glfwSetWindowContentScaleCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, @@ -2044,12 +2059,6 @@ pub inline fn setCursor(self: Window, cursor: Cursor) error{PlatformError}!void }; } -fn setKeyCallbackWrapper(handle: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setKeyCallback.?(window, @intToEnum(Key, key), @intCast(i32, scancode), @intToEnum(Action, action), Mods.fromInt(mods)); -} - /// Sets the key callback. /// /// This function sets the key callback of the specified window, which is called when a key is @@ -2084,23 +2093,33 @@ fn setKeyCallbackWrapper(handle: ?*c.GLFWwindow, key: c_int, scancode: c_int, ac /// @thread_safety This function must only be called from the main thread. /// /// see also: input_key -pub inline fn setKeyCallback(self: Window, callback: ?fn (window: Window, key: Key, scancode: i32, action: Action, mods: Mods) void) void { +pub inline fn setKeyCallback(self: Window, comptime callback: ?fn (window: Window, key: Key, scancode: i32, action: Action, mods: Mods) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setKeyCallback = callback; - _ = c.glfwSetKeyCallback(self.handle, if (callback != null) setKeyCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn keyCallbackWrapper(handle: ?*c.GLFWwindow, key: c_int, scancode: c_int, action: c_int, mods: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + @intToEnum(Key, key), + @intCast(i32, scancode), + @intToEnum(Action, action), + Mods.fromInt(mods), + }); + } + }; + + if (c.glfwSetKeyCallback(self.handle, CWrapper.keyCallbackWrapper) != null) return; + } else { + if (c.glfwSetKeyCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setCharCallbackWrapper(handle: ?*c.GLFWwindow, codepoint: c_uint) callconv(.C) void { - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setCharCallback.?(window, @intCast(u21, codepoint)); -} - /// Sets the Unicode character callback. /// /// This function sets the character callback of the specified window, which is called when a @@ -2125,23 +2144,30 @@ fn setCharCallbackWrapper(handle: ?*c.GLFWwindow, codepoint: c_uint) callconv(.C /// @thread_safety This function must only be called from the main thread. /// /// see also: input_char -pub inline fn setCharCallback(self: Window, callback: ?fn (window: Window, codepoint: u21) void) void { +pub inline fn setCharCallback(self: Window, comptime callback: ?fn (window: Window, codepoint: u21) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setCharCallback = callback; - _ = c.glfwSetCharCallback(self.handle, if (callback != null) setCharCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn charCallbackWrapper(handle: ?*c.GLFWwindow, codepoint: c_uint) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + @intCast(u21, codepoint), + }); + } + }; + + if (c.glfwSetCharCallback(self.handle, CWrapper.charCallbackWrapper) != null) return; + } else { + if (c.glfwSetCharCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setMouseButtonCallbackWrapper(handle: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) callconv(.C) void { - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setMouseButtonCallback.?(window, @intToEnum(MouseButton, button), @intToEnum(Action, action), Mods.fromInt(mods)); -} - /// Sets the mouse button callback. /// /// This function sets the mouse button callback of the specified window, which is called when a @@ -2164,23 +2190,32 @@ fn setMouseButtonCallbackWrapper(handle: ?*c.GLFWwindow, button: c_int, action: /// @thread_safety This function must only be called from the main thread. /// /// see also: input_mouse_button -pub inline fn setMouseButtonCallback(self: Window, callback: ?fn (window: Window, button: MouseButton, action: Action, mods: Mods) void) void { +pub inline fn setMouseButtonCallback(self: Window, comptime callback: ?fn (window: Window, button: MouseButton, action: Action, mods: Mods) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setMouseButtonCallback = callback; - _ = c.glfwSetMouseButtonCallback(self.handle, if (callback != null) setMouseButtonCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn mouseButtonCallbackWrapper(handle: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + @intToEnum(MouseButton, button), + @intToEnum(Action, action), + Mods.fromInt(mods), + }); + } + }; + + if (c.glfwSetMouseButtonCallback(self.handle, CWrapper.mouseButtonCallbackWrapper) != null) return; + } else { + if (c.glfwSetMouseButtonCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setCursorPosCallbackWrapper(handle: ?*c.GLFWwindow, xpos: f64, ypos: f64) callconv(.C) void { - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setCursorPosCallback.?(window, xpos, ypos); -} - /// Sets the cursor position callback. /// /// This function sets the cursor position callback of the specified window, which is called when @@ -2198,23 +2233,31 @@ fn setCursorPosCallbackWrapper(handle: ?*c.GLFWwindow, xpos: f64, ypos: f64) cal /// @thread_safety This function must only be called from the main thread. /// /// see also: cursor_pos -pub inline fn setCursorPosCallback(self: Window, callback: ?fn (window: Window, xpos: f64, ypos: f64) void) void { +pub inline fn setCursorPosCallback(self: Window, comptime callback: ?fn (window: Window, xpos: f64, ypos: f64) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setCursorPosCallback = callback; - _ = c.glfwSetCursorPosCallback(self.handle, if (callback != null) setCursorPosCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn cursorPosCallbackWrapper(handle: ?*c.GLFWwindow, xpos: f64, ypos: f64) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + xpos, + ypos, + }); + } + }; + + if (c.glfwSetCursorPosCallback(self.handle, CWrapper.cursorPosCallbackWrapper) != null) return; + } else { + if (c.glfwSetCursorPosCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setCursorEnterCallbackWrapper(handle: ?*c.GLFWwindow, entered: c_int) callconv(.C) void { - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setCursorEnterCallback.?(window, entered == c.GLFW_TRUE); -} - /// Sets the cursor enter/leave callback. /// /// This function sets the cursor boundary crossing callback of the specified window, which is @@ -2229,23 +2272,30 @@ fn setCursorEnterCallbackWrapper(handle: ?*c.GLFWwindow, entered: c_int) callcon /// @thread_safety This function must only be called from the main thread. /// /// see also: cursor_enter -pub inline fn setCursorEnterCallback(self: Window, callback: ?fn (window: Window, entered: bool) void) void { +pub inline fn setCursorEnterCallback(self: Window, comptime callback: ?fn (window: Window, entered: bool) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setCursorEnterCallback = callback; - _ = c.glfwSetCursorEnterCallback(self.handle, if (callback != null) setCursorEnterCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn cursorEnterCallbackWrapper(handle: ?*c.GLFWwindow, entered: c_int) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + entered == c.GLFW_TRUE, + }); + } + }; + + if (c.glfwSetCursorEnterCallback(self.handle, CWrapper.cursorEnterCallbackWrapper) != null) return; + } else { + if (c.glfwSetCursorEnterCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setScrollCallbackWrapper(handle: ?*c.GLFWwindow, xoffset: f64, yoffset: f64) callconv(.C) void { - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setScrollCallback.?(window, xoffset, yoffset); -} - /// Sets the scroll callback. /// /// This function sets the scroll callback of the specified window, which is called when a scrolling @@ -2264,23 +2314,31 @@ fn setScrollCallbackWrapper(handle: ?*c.GLFWwindow, xoffset: f64, yoffset: f64) /// @thread_safety This function must only be called from the main thread. /// /// see also: scrolling -pub inline fn setScrollCallback(self: Window, callback: ?fn (window: Window, xoffset: f64, yoffset: f64) void) void { +pub inline fn setScrollCallback(self: Window, comptime callback: ?fn (window: Window, xoffset: f64, yoffset: f64) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setScrollCallback = callback; - _ = c.glfwSetScrollCallback(self.handle, if (callback != null) setScrollCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn scrollCallbackWrapper(handle: ?*c.GLFWwindow, xoffset: f64, yoffset: f64) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + xoffset, + yoffset, + }); + } + }; + + if (c.glfwSetScrollCallback(self.handle, CWrapper.scrollCallbackWrapper) != null) return; + } else { + if (c.glfwSetScrollCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, }; } -fn setDropCallbackWrapper(handle: ?*c.GLFWwindow, path_count: c_int, paths: [*c][*c]const u8) callconv(.C) void { - const window = from(handle.?) catch unreachable; - const internal = window.getInternal(); - internal.setDropCallback.?(window, @ptrCast([*][*:0]const u8, paths)[0..@intCast(u32, path_count)]); -} - /// Sets the path drop callback. /// /// This function sets the path drop callback of the specified window, which is called when one or @@ -2306,11 +2364,24 @@ fn setDropCallbackWrapper(handle: ?*c.GLFWwindow, path_count: c_int, paths: [*c] /// @thread_safety This function must only be called from the main thread. /// /// see also: path_drop -pub inline fn setDropCallback(self: Window, callback: ?fn (window: Window, paths: [][*:0]const u8) void) void { +pub inline fn setDropCallback(self: Window, comptime callback: ?fn (window: Window, paths: [][*:0]const u8) void) void { internal_debug.assertInitialized(); - var internal = self.getInternal(); - internal.setDropCallback = callback; - _ = c.glfwSetDropCallback(self.handle, if (callback != null) setDropCallbackWrapper else null); + + if (callback) |user_callback| { + const CWrapper = struct { + pub fn dropCallbackWrapper(handle: ?*c.GLFWwindow, path_count: c_int, paths: [*c][*c]const u8) callconv(.C) void { + @call(.{ .modifier = .always_inline }, user_callback, .{ + from(handle.?), + @ptrCast([*][*:0]const u8, paths)[0..@intCast(u32, path_count)], + }); + } + }; + + if (c.glfwSetDropCallback(self.handle, CWrapper.dropCallbackWrapper) != null) return; + } else { + if (c.glfwSetDropCallback(self.handle, null) != null) return; + } + getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, diff --git a/glfw/src/errors.zig b/glfw/src/errors.zig index 4742ff5b..b4f69283 100644 --- a/glfw/src/errors.zig +++ b/glfw/src/errors.zig @@ -161,7 +161,7 @@ pub inline fn getError() Error!void { pub fn setErrorCallback(comptime callback: ?fn (error_code: Error, description: [:0]const u8) void) void { if (callback) |user_callback| { const CWrapper = struct { - pub fn c_wrapper(err_int: c_int, c_description: [*c]const u8) callconv(.C) void { + 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; @@ -171,7 +171,7 @@ pub fn setErrorCallback(comptime callback: ?fn (error_code: Error, description: } }; - _ = c.glfwSetErrorCallback(CWrapper.c_wrapper); + _ = c.glfwSetErrorCallback(CWrapper.errorCallbackWrapper); return; } diff --git a/glfw/src/opengl.zig b/glfw/src/opengl.zig index 9bffff9c..12127335 100644 --- a/glfw/src/opengl.zig +++ b/glfw/src/opengl.zig @@ -53,9 +53,9 @@ pub inline fn makeContextCurrent(window: ?Window) error{ NoWindowContext, Platfo /// @thread_safety This function may be called from any thread. /// /// see also: context_current, glfwMakeContextCurrent -pub inline fn getCurrentContext() std.mem.Allocator.Error!?Window { +pub inline fn getCurrentContext() ?Window { internal_debug.assertInitialized(); - if (c.glfwGetCurrentContext()) |handle| return try Window.from(handle); + if (c.glfwGetCurrentContext()) |handle| return Window.from(handle); getError() catch |err| return switch (err) { Error.NotInitialized => unreachable, else => unreachable, @@ -213,10 +213,7 @@ test "getCurrentContext" { try glfw.init(.{}); defer glfw.terminate(); - const current_context = glfw.getCurrentContext() catch |err| { - std.debug.print("can't get current context, error={}\n", .{err}); - return; - }; + const current_context = glfw.getCurrentContext(); std.debug.assert(current_context == null); }