obj: Move Platform and InitOptions fields into core.windows (#1309)
* obj: Make field tracking use a single bitset * obj: module: fix comment * obj: Move `Platform` state and `InitOptions` fields into `core.windows`, initial push, only triangle example working on macos currently * obj: `get` and `getValue` (renamed `getAll`) now do not return optionals, comment revisions, `device` is no longer optional, `native` is optional * core: Lots of cleanup of unnecessary comments * core: `Event`s now all contain `window_id`, darwin/windows: event functions now send window id * core: comments, examples: fix `core-custom-entrypoint`
This commit is contained in:
parent
b4e2da1b69
commit
1fe47b2b19
7 changed files with 651 additions and 610 deletions
455
src/Core.zig
455
src/Core.zig
|
|
@ -30,7 +30,7 @@ pub var non_blocking = false;
|
|||
|
||||
pub const mach_module = .mach_core;
|
||||
|
||||
pub const mach_systems = .{ .main, .init, .tick, .presentFrame, .processWindowUpdates, .deinit };
|
||||
pub const mach_systems = .{ .main, .init, .tick, .presentFrame, .deinit };
|
||||
|
||||
// Set track_fields to true so that when these field values change, we know about it
|
||||
// and can update the platform windows.
|
||||
|
|
@ -40,25 +40,63 @@ windows: mach.Objects(
|
|||
/// Window title string
|
||||
// TODO: document how to set this using a format string
|
||||
// TODO: allocation/free strategy
|
||||
title: []const u8,
|
||||
title: []const u8 = "Mach Window",
|
||||
|
||||
/// Texture format of the framebuffer (read-only)
|
||||
framebuffer_format: gpu.Texture.Format,
|
||||
framebuffer_format: gpu.Texture.Format = .bgra8_unorm,
|
||||
|
||||
/// Width of the framebuffer in texels (read-only)
|
||||
framebuffer_width: u32,
|
||||
/// Will be updated to reflect the actual framebuffer dimensions after window creation.
|
||||
framebuffer_width: u32 = 1920 / 2,
|
||||
|
||||
/// Height of the framebuffer in texels (read-only)
|
||||
framebuffer_height: u32,
|
||||
/// Will be updated to reflect the actual framebuffer dimensions after window creation.
|
||||
framebuffer_height: u32 = 1080 / 2,
|
||||
|
||||
/// Vertical sync mode, prevents screen tearing.
|
||||
vsync_mode: VSyncMode = .none,
|
||||
|
||||
display_mode: DisplayMode = .windowed,
|
||||
|
||||
/// Cursor
|
||||
cursor_mode: CursorMode = .normal,
|
||||
cursor_shape: CursorShape = .arrow,
|
||||
|
||||
/// Outer border
|
||||
border: bool = true,
|
||||
|
||||
/// Width of the window in virtual pixels (read-only)
|
||||
width: u32,
|
||||
width: u32 = 1920 / 2,
|
||||
|
||||
/// Height of the window in virtual pixels (read-only)
|
||||
height: u32,
|
||||
height: u32 = 1080 / 2,
|
||||
|
||||
/// Whether the window is fullscreen (read-only)
|
||||
fullscreen: bool,
|
||||
/// Target frames per second
|
||||
refresh_rate: u32 = 0,
|
||||
|
||||
// GPU
|
||||
// When device is not null, the rest of the fields have been
|
||||
// initialized.
|
||||
device: *gpu.Device = undefined,
|
||||
instance: *gpu.Instance = undefined,
|
||||
adapter: *gpu.Adapter = undefined,
|
||||
queue: *gpu.Queue = undefined,
|
||||
swap_chain: *gpu.SwapChain = undefined,
|
||||
swap_chain_descriptor: gpu.SwapChain.Descriptor = undefined,
|
||||
swap_chain_update: std.Thread.ResetEvent = .{},
|
||||
surface: *gpu.Surface = undefined,
|
||||
surface_descriptor: gpu.Surface.Descriptor = undefined,
|
||||
|
||||
// After window initialization, (when device is not null)
|
||||
// changing these will have no effect
|
||||
power_preference: gpu.PowerPreference = .undefined,
|
||||
required_features: ?[]const gpu.FeatureName = null,
|
||||
required_limits: ?gpu.Limits = null,
|
||||
swap_chain_usage: gpu.Texture.UsageFlags = .{
|
||||
.render_attachment = true,
|
||||
},
|
||||
|
||||
native: ?Platform.Native = null,
|
||||
},
|
||||
),
|
||||
|
||||
|
|
@ -79,60 +117,26 @@ state: enum {
|
|||
exited,
|
||||
} = .running,
|
||||
|
||||
// TODO: handle window titles better
|
||||
title: [256:0]u8 = undefined,
|
||||
frame: mach.time.Frequency,
|
||||
input: mach.time.Frequency,
|
||||
swap_chain_update: std.Thread.ResetEvent = .{},
|
||||
|
||||
// GPU
|
||||
instance: *gpu.Instance,
|
||||
adapter: *gpu.Adapter,
|
||||
device: *gpu.Device,
|
||||
queue: *gpu.Queue,
|
||||
surface: *gpu.Surface,
|
||||
swap_chain: *gpu.SwapChain,
|
||||
descriptor: gpu.SwapChain.Descriptor,
|
||||
|
||||
// Internal module state
|
||||
allocator: std.mem.Allocator,
|
||||
platform: Platform,
|
||||
events: EventQueue,
|
||||
input_state: InputState,
|
||||
oom: std.Thread.ResetEvent = .{},
|
||||
|
||||
pub fn init(core: *Core) !void {
|
||||
// TODO: this needs to be removed.
|
||||
const options: InitOptions = .{
|
||||
.allocator = std.heap.c_allocator,
|
||||
};
|
||||
const allocator = options.allocator;
|
||||
const allocator = std.heap.c_allocator;
|
||||
|
||||
// TODO: fix all leaks and use options.allocator
|
||||
try mach.sysgpu.Impl.init(allocator, .{});
|
||||
|
||||
const main_window = try core.windows.new(.{
|
||||
.title = options.title, // TODO
|
||||
.framebuffer_format = undefined, // TODO: null?
|
||||
.framebuffer_width = undefined, // TODO: null?
|
||||
.framebuffer_height = undefined, // TODO: null?
|
||||
.width = 1920 / 2,
|
||||
.height = 1080 / 2,
|
||||
.fullscreen = false,
|
||||
});
|
||||
|
||||
// Copy window title into owned buffer.
|
||||
var title: [256:0]u8 = undefined;
|
||||
if (options.title.len < title.len) {
|
||||
@memcpy(title[0..options.title.len], options.title);
|
||||
title[options.title.len] = 0;
|
||||
}
|
||||
const main_window = try core.windows.new(.{});
|
||||
|
||||
var events = EventQueue.init(allocator);
|
||||
try events.ensureTotalCapacity(8192);
|
||||
|
||||
// TODO: remove undefined initialization (disgusting!)
|
||||
const platform: Platform = undefined;
|
||||
core.* = .{
|
||||
// Note: since core.windows is initialized for us already, we just copy the pointer.
|
||||
.windows = core.windows,
|
||||
|
|
@ -142,33 +146,32 @@ pub fn init(core: *Core) !void {
|
|||
.events = events,
|
||||
.input_state = .{},
|
||||
|
||||
.platform = platform,
|
||||
|
||||
// TODO: these should not be state, they should be components.
|
||||
.title = title,
|
||||
.frame = undefined,
|
||||
.input = undefined,
|
||||
.instance = undefined,
|
||||
.adapter = undefined,
|
||||
.device = undefined,
|
||||
.queue = undefined,
|
||||
.surface = undefined,
|
||||
.swap_chain = undefined,
|
||||
.descriptor = undefined,
|
||||
.input = .{ .target = 0 },
|
||||
.frame = .{ .target = 1 },
|
||||
};
|
||||
|
||||
try Platform.init(&core.platform, core, options);
|
||||
// Tick the platform so that the platform can grab the newly created window
|
||||
// and perform initialization
|
||||
// TODO: consider removing `main_window` and then this wont be necessary
|
||||
try Platform.tick(core);
|
||||
|
||||
core.instance = gpu.createInstance(null) orelse {
|
||||
try core.frame.start();
|
||||
try core.input.start();
|
||||
}
|
||||
|
||||
pub fn initWindow(core: *Core, window_id: mach.ObjectID) !void {
|
||||
var core_window = core.windows.getValue(window_id);
|
||||
|
||||
core_window.instance = gpu.createInstance(null) orelse {
|
||||
log.err("failed to create GPU instance", .{});
|
||||
std.process.exit(1);
|
||||
};
|
||||
core.surface = core.instance.createSurface(&core.platform.surface_descriptor);
|
||||
core_window.surface = core_window.instance.createSurface(&core_window.surface_descriptor);
|
||||
|
||||
var response: RequestAdapterResponse = undefined;
|
||||
core.instance.requestAdapter(&gpu.RequestAdapterOptions{
|
||||
.compatible_surface = core.surface,
|
||||
.power_preference = options.power_preference,
|
||||
core_window.instance.requestAdapter(&gpu.RequestAdapterOptions{
|
||||
.compatible_surface = core_window.surface,
|
||||
.power_preference = core_window.power_preference,
|
||||
.force_fallback_adapter = .false,
|
||||
}, &response, requestAdapterCallback);
|
||||
if (response.status != .success) {
|
||||
|
|
@ -191,13 +194,13 @@ pub fn init(core: *Core) !void {
|
|||
props.driver_description,
|
||||
});
|
||||
|
||||
core.adapter = response.adapter.?;
|
||||
core_window.adapter = response.adapter.?;
|
||||
|
||||
// Create a device with default limits/features.
|
||||
core.device = response.adapter.?.createDevice(&.{
|
||||
.required_features_count = if (options.required_features) |v| @as(u32, @intCast(v.len)) else 0,
|
||||
.required_features = if (options.required_features) |v| @as(?[*]const gpu.FeatureName, v.ptr) else null,
|
||||
.required_limits = if (options.required_limits) |limits| @as(?*const gpu.RequiredLimits, &gpu.RequiredLimits{
|
||||
core_window.device = response.adapter.?.createDevice(&.{
|
||||
.required_features_count = if (core_window.required_features) |v| @as(u32, @intCast(v.len)) else 0,
|
||||
.required_features = if (core_window.required_features) |v| @as(?[*]const gpu.FeatureName, v.ptr) else null,
|
||||
.required_limits = if (core_window.required_limits) |limits| @as(?*const gpu.RequiredLimits, &gpu.RequiredLimits{
|
||||
.limits = limits,
|
||||
}) else null,
|
||||
.device_lost_callback = &deviceLostCallback,
|
||||
|
|
@ -206,51 +209,46 @@ pub fn init(core: *Core) !void {
|
|||
log.err("failed to create GPU device\n", .{});
|
||||
std.process.exit(1);
|
||||
};
|
||||
core.device.setUncapturedErrorCallback({}, printUnhandledErrorCallback);
|
||||
core.queue = core.device.getQueue();
|
||||
core_window.device.setUncapturedErrorCallback({}, printUnhandledErrorCallback);
|
||||
core_window.queue = core_window.device.getQueue();
|
||||
|
||||
core.descriptor = gpu.SwapChain.Descriptor{
|
||||
core_window.swap_chain_descriptor = gpu.SwapChain.Descriptor{
|
||||
.label = "main swap chain",
|
||||
.usage = options.swap_chain_usage,
|
||||
.usage = core_window.swap_chain_usage,
|
||||
.format = .bgra8_unorm,
|
||||
.width = @intCast(core.platform.size.width),
|
||||
.height = @intCast(core.platform.size.height),
|
||||
.present_mode = switch (core.platform.vsync_mode) {
|
||||
.width = core_window.width,
|
||||
.height = core_window.height,
|
||||
.present_mode = switch (core_window.vsync_mode) {
|
||||
.none => .immediate,
|
||||
.double => .fifo,
|
||||
.triple => .mailbox,
|
||||
},
|
||||
};
|
||||
core.swap_chain = core.device.createSwapChain(core.surface, &core.descriptor);
|
||||
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
||||
core_window.framebuffer_format = core_window.swap_chain_descriptor.format;
|
||||
core_window.framebuffer_width = core_window.swap_chain_descriptor.width;
|
||||
core_window.framebuffer_height = core_window.swap_chain_descriptor.height;
|
||||
|
||||
core.windows.setRaw(core.main_window, .framebuffer_format, core.descriptor.format);
|
||||
core.windows.setRaw(core.main_window, .framebuffer_width, core.descriptor.width);
|
||||
core.windows.setRaw(core.main_window, .framebuffer_height, core.descriptor.height);
|
||||
// TODO(important): update this information upon framebuffer resize events
|
||||
// var w = core.windows.get(core.main_window).?;
|
||||
// w.framebuffer_format = core.descriptor.format;
|
||||
// w.framebuffer_width = core.descriptor.width;
|
||||
// w.framebuffer_height = core.descriptor.height;
|
||||
// w.width = core.platform.size.width;
|
||||
// w.height = core.platform.size.height;
|
||||
// core.windows.setAll(core.main_window, w);
|
||||
|
||||
core.frame = .{ .target = 0 };
|
||||
core.input = .{ .target = 1 };
|
||||
try core.frame.start();
|
||||
try core.input.start();
|
||||
core.windows.setValueRaw(window_id, core_window);
|
||||
}
|
||||
|
||||
pub fn tick(core: *Core, core_mod: mach.Mod(Core)) void {
|
||||
pub fn tick(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||
// TODO(core)(slimsag): consider execution order of mach.Core (e.g. creating a new window
|
||||
// during application execution, rendering to multiple windows, etc.) and how
|
||||
// that relates to Platform.tick being responsible for both handling window updates
|
||||
// (like title/size changes) and window creation, plus multi-threaded rendering.
|
||||
try Platform.tick(core);
|
||||
|
||||
core_mod.run(core.on_tick.?);
|
||||
core_mod.call(.presentFrame);
|
||||
core_mod.call(.processWindowUpdates);
|
||||
}
|
||||
|
||||
pub fn main(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||
if (core.on_tick == null) @panic("core.on_tick callback must be set");
|
||||
if (core.on_exit == null) @panic("core.on_exit callback must be set");
|
||||
|
||||
try Platform.tick(core);
|
||||
|
||||
core_mod.run(core.on_tick.?);
|
||||
core_mod.call(.presentFrame);
|
||||
|
||||
|
|
@ -287,50 +285,32 @@ pub fn main(core: *Core, core_mod: mach.Mod(Core)) !void {
|
|||
}
|
||||
|
||||
fn platform_update_callback(core: *Core, core_mod: mach.Mod(Core)) !bool {
|
||||
// TODO(core)(slimsag): consider execution order of mach.Core (e.g. creating a new window
|
||||
// during application execution, rendering to multiple windows, etc.) and how
|
||||
// that relates to Platform.tick being responsible for both handling window updates
|
||||
// (like title/size changes) and window creation, plus multi-threaded rendering.
|
||||
try Platform.tick(core);
|
||||
|
||||
core_mod.run(core.on_tick.?);
|
||||
core_mod.call(.presentFrame);
|
||||
core_mod.call(.processWindowUpdates);
|
||||
//core_mod.call(.processWindowUpdates);
|
||||
|
||||
return core.state != .exited;
|
||||
}
|
||||
|
||||
pub fn processWindowUpdates(core: *Core) void {
|
||||
if (core.windows.updated(core.main_window, .width) or core.windows.updated(core.main_window, .height)) {
|
||||
const window = core.windows.getAll(core.main_window);
|
||||
|
||||
if (window) |main_window| {
|
||||
core.platform.setSize(.{
|
||||
.width = main_window.width,
|
||||
.height = main_window.height,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(core: *Core) !void {
|
||||
core.state = .exited;
|
||||
|
||||
// TODO(object)(window-title)
|
||||
// var q = try entities.query(.{
|
||||
// .titles = Mod.read(.title),
|
||||
// });
|
||||
// while (q.next()) |v| {
|
||||
// for (v.titles) |title| {
|
||||
// state.allocator.free(title);
|
||||
// }
|
||||
// }
|
||||
|
||||
// GPU backend must be released BEFORE platform deinit, otherwise we may enter a race
|
||||
// where the GPU might try to present to the window server.
|
||||
core.swap_chain.release();
|
||||
core.queue.release();
|
||||
core.device.release();
|
||||
core.surface.release();
|
||||
core.adapter.release();
|
||||
core.instance.release();
|
||||
|
||||
// Deinit the platform
|
||||
core.platform.deinit();
|
||||
var windows = core.windows.slice();
|
||||
while (windows.next()) |window_id| {
|
||||
var core_window = core.windows.getValue(window_id);
|
||||
core_window.swap_chain.release();
|
||||
core_window.queue.release();
|
||||
core_window.device.release();
|
||||
core_window.surface.release();
|
||||
core_window.adapter.release();
|
||||
core_window.instance.release();
|
||||
}
|
||||
|
||||
core.events.deinit();
|
||||
}
|
||||
|
|
@ -376,50 +356,6 @@ pub fn outOfMemory(core: *@This()) bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
// TODO(object)
|
||||
// /// Sets the window title. The string must be owned by Core, and will not be copied or freed. It is
|
||||
// /// advised to use the `core.title` buffer for this purpose, e.g.:
|
||||
// ///
|
||||
// /// ```
|
||||
// /// const title = try std.fmt.bufPrintZ(&core.title, "Hello, world!", .{});
|
||||
// /// core.setTitle(title);
|
||||
// /// ```
|
||||
// pub inline fn setTitle(core: *@This(), value: [:0]const u8) void {
|
||||
// return core.platform.setTitle(value);
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Set the window mode
|
||||
// pub inline fn setDisplayMode(core: *@This(), mode: DisplayMode) void {
|
||||
// return core.platform.setDisplayMode(mode);
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// /// Returns the window mode
|
||||
// pub inline fn displayMode(core: *@This()) DisplayMode {
|
||||
// return core.platform.display_mode;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// pub inline fn setBorder(core: *@This(), value: bool) void {
|
||||
// return core.platform.setBorder(value);
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// pub inline fn border(core: *@This()) bool {
|
||||
// return core.platform.border;
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// pub inline fn setHeadless(core: *@This(), value: bool) void {
|
||||
// return core.platform.setHeadless(value);
|
||||
// }
|
||||
|
||||
// TODO(object)
|
||||
// pub inline fn headless(core: *@This()) bool {
|
||||
// return core.platform.headless;
|
||||
// }
|
||||
|
||||
pub fn keyPressed(core: *@This(), key: Key) bool {
|
||||
return core.input_state.isKeyPressed(key);
|
||||
}
|
||||
|
|
@ -587,45 +523,37 @@ pub fn mousePosition(core: *@This()) Position {
|
|||
// }
|
||||
|
||||
pub fn presentFrame(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||
// TODO(object)(window-title)
|
||||
// // Update windows title
|
||||
// var num_windows: usize = 0;
|
||||
// var q = try entities.query(.{
|
||||
// .ids = mach.Entities.Mod.read(.id),
|
||||
// .titles = Mod.read(.title),
|
||||
// });
|
||||
// while (q.next()) |v| {
|
||||
// for (v.ids, v.titles) |_, title| {
|
||||
// num_windows += 1;
|
||||
// state.platform.setTitle(title);
|
||||
// }
|
||||
// }
|
||||
// if (num_windows > 1) @panic("mach: Core currently only supports a single window");
|
||||
var windows = core.windows.slice();
|
||||
while (windows.next()) |window_id| {
|
||||
var core_window = core.windows.getValue(window_id);
|
||||
|
||||
_ = try core.platform.update();
|
||||
mach.sysgpu.Impl.deviceTick(core.device);
|
||||
core.swap_chain.present();
|
||||
mach.sysgpu.Impl.deviceTick(core_window.device);
|
||||
|
||||
// Update swapchain for the next frame
|
||||
if (core.swap_chain_update.isSet()) blk: {
|
||||
core.swap_chain_update.reset();
|
||||
core_window.swap_chain.present();
|
||||
|
||||
switch (core.platform.vsync_mode) {
|
||||
.triple => core.frame.target = 2 * core.platform.refresh_rate,
|
||||
else => core.frame.target = 0,
|
||||
// Update swapchain for the next frame
|
||||
if (core_window.swap_chain_update.isSet()) blk: {
|
||||
core_window.swap_chain_update.reset();
|
||||
|
||||
switch (core_window.vsync_mode) {
|
||||
.triple => core.frame.target = 2 * core_window.refresh_rate,
|
||||
else => core.frame.target = 0,
|
||||
}
|
||||
|
||||
if (core_window.width == 0 or core_window.height == 0) break :blk;
|
||||
|
||||
core_window.swap_chain_descriptor.present_mode = switch (core_window.vsync_mode) {
|
||||
.none => .immediate,
|
||||
.double => .fifo,
|
||||
.triple => .mailbox,
|
||||
};
|
||||
|
||||
core_window.swap_chain_descriptor.width = core_window.width;
|
||||
core_window.swap_chain_descriptor.height = core_window.height;
|
||||
core_window.swap_chain.release();
|
||||
|
||||
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
||||
}
|
||||
|
||||
if (core.platform.size.width == 0 or core.platform.size.height == 0) break :blk;
|
||||
|
||||
core.descriptor.present_mode = switch (core.platform.vsync_mode) {
|
||||
.none => .immediate,
|
||||
.double => .fifo,
|
||||
.triple => .mailbox,
|
||||
};
|
||||
core.descriptor.width = @intCast(core.platform.size.width);
|
||||
core.descriptor.height = @intCast(core.platform.size.height);
|
||||
core.swap_chain.release();
|
||||
core.swap_chain = core.device.createSwapChain(core.surface, &core.descriptor);
|
||||
}
|
||||
|
||||
// TODO(important): update this information in response to resize events rather than
|
||||
|
|
@ -653,28 +581,6 @@ pub fn presentFrame(core: *Core, core_mod: mach.Mod(Core)) !void {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(object)(window-title)
|
||||
// /// Prints into the window title buffer using a format string and arguments. e.g.
|
||||
// ///
|
||||
// /// ```
|
||||
// /// try core.state().printTitle(core_mod, core_mod.state().main_window, "Hello, {s}!", .{"Mach"});
|
||||
// /// ```
|
||||
// pub fn printTitle(
|
||||
// core: *@This(),
|
||||
// window_id: mach.EntityID,
|
||||
// comptime fmt: []const u8,
|
||||
// args: anytype,
|
||||
// ) !void {
|
||||
// _ = window_id;
|
||||
// // Allocate and assign a new window title slice.
|
||||
// const slice = try std.fmt.allocPrintZ(core.allocator, fmt, args);
|
||||
// defer core.allocator.free(slice);
|
||||
// core.setTitle(slice);
|
||||
|
||||
// // TODO: This function does not have access to *core.Mod to update
|
||||
// // try core.Mod.set(window_id, .title, slice);
|
||||
// }
|
||||
|
||||
pub fn exit(core: *Core) void {
|
||||
core.state = .exiting;
|
||||
}
|
||||
|
|
@ -745,24 +651,6 @@ const Platform = switch (build_options.core_platform) {
|
|||
.null => @import("core/Null.zig"),
|
||||
};
|
||||
|
||||
// TODO(object): this struct should not exist
|
||||
// TODO: this should not be here, it is exposed because the platform implementations need it.
|
||||
pub const InitOptions = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
is_app: bool = false,
|
||||
headless: bool = false,
|
||||
display_mode: DisplayMode = .windowed,
|
||||
border: bool = true,
|
||||
title: [:0]const u8 = "Mach core",
|
||||
size: Size = .{ .width = 1920 / 2, .height = 1080 / 2 },
|
||||
power_preference: gpu.PowerPreference = .undefined,
|
||||
required_features: ?[]const gpu.FeatureName = null,
|
||||
required_limits: ?gpu.Limits = null,
|
||||
swap_chain_usage: gpu.Texture.UsageFlags = .{
|
||||
.render_attachment = true,
|
||||
},
|
||||
};
|
||||
|
||||
pub const InputState = struct {
|
||||
const KeyBitSet = std.StaticBitSet(@as(u8, @intFromEnum(Key.max)) + 1);
|
||||
const MouseButtonSet = std.StaticBitSet(@as(u4, @intFromEnum(MouseButton.max)) + 1);
|
||||
|
|
@ -793,34 +681,50 @@ pub const Event = union(enum) {
|
|||
key_repeat: KeyEvent,
|
||||
key_release: KeyEvent,
|
||||
char_input: struct {
|
||||
window_id: mach.ObjectID,
|
||||
codepoint: u21,
|
||||
},
|
||||
mouse_motion: struct {
|
||||
window_id: mach.ObjectID,
|
||||
pos: Position,
|
||||
},
|
||||
mouse_press: MouseButtonEvent,
|
||||
mouse_release: MouseButtonEvent,
|
||||
mouse_scroll: struct {
|
||||
window_id: mach.ObjectID,
|
||||
xoffset: f32,
|
||||
yoffset: f32,
|
||||
},
|
||||
framebuffer_resize: Size,
|
||||
focus_gained,
|
||||
focus_lost,
|
||||
close,
|
||||
window_resize: ResizeEvent,
|
||||
focus_gained: struct {
|
||||
window_id: mach.ObjectID,
|
||||
},
|
||||
focus_lost: struct {
|
||||
window_id: mach.ObjectID,
|
||||
},
|
||||
close: struct {
|
||||
window_id: mach.ObjectID,
|
||||
},
|
||||
};
|
||||
|
||||
pub const KeyEvent = struct {
|
||||
window_id: mach.ObjectID,
|
||||
key: Key,
|
||||
mods: KeyMods,
|
||||
};
|
||||
|
||||
pub const MouseButtonEvent = struct {
|
||||
window_id: mach.ObjectID,
|
||||
button: MouseButton,
|
||||
pos: Position,
|
||||
mods: KeyMods,
|
||||
};
|
||||
|
||||
pub const ResizeEvent = struct {
|
||||
window_id: mach.ObjectID,
|
||||
size: Size,
|
||||
};
|
||||
|
||||
pub const MouseButton = enum {
|
||||
left,
|
||||
right,
|
||||
|
|
@ -1070,37 +974,37 @@ const RequestAdapterResponse = struct {
|
|||
};
|
||||
|
||||
// Verifies that a platform implementation exposes the expected function declarations.
|
||||
comptime {
|
||||
// Core
|
||||
assertHasField(Platform, "surface_descriptor");
|
||||
assertHasField(Platform, "refresh_rate");
|
||||
// comptime {
|
||||
// // Core
|
||||
// assertHasField(Platform, "surface_descriptor");
|
||||
// assertHasField(Platform, "refresh_rate");
|
||||
|
||||
assertHasDecl(Platform, "init");
|
||||
assertHasDecl(Platform, "deinit");
|
||||
// assertHasDecl(Platform, "init");
|
||||
// assertHasDecl(Platform, "deinit");
|
||||
|
||||
assertHasDecl(Platform, "setTitle");
|
||||
// assertHasDecl(Platform, "setTitle");
|
||||
|
||||
assertHasDecl(Platform, "setDisplayMode");
|
||||
assertHasField(Platform, "display_mode");
|
||||
// assertHasDecl(Platform, "setDisplayMode");
|
||||
// assertHasField(Platform, "display_mode");
|
||||
|
||||
assertHasDecl(Platform, "setBorder");
|
||||
assertHasField(Platform, "border");
|
||||
// assertHasDecl(Platform, "setBorder");
|
||||
// assertHasField(Platform, "border");
|
||||
|
||||
assertHasDecl(Platform, "setHeadless");
|
||||
assertHasField(Platform, "headless");
|
||||
// assertHasDecl(Platform, "setHeadless");
|
||||
// assertHasField(Platform, "headless");
|
||||
|
||||
assertHasDecl(Platform, "setVSync");
|
||||
assertHasField(Platform, "vsync_mode");
|
||||
// assertHasDecl(Platform, "setVSync");
|
||||
// assertHasField(Platform, "vsync_mode");
|
||||
|
||||
assertHasDecl(Platform, "setSize");
|
||||
assertHasField(Platform, "size");
|
||||
// assertHasDecl(Platform, "setSize");
|
||||
// assertHasField(Platform, "size");
|
||||
|
||||
assertHasDecl(Platform, "setCursorMode");
|
||||
assertHasField(Platform, "cursor_mode");
|
||||
// assertHasDecl(Platform, "setCursorMode");
|
||||
// assertHasField(Platform, "cursor_mode");
|
||||
|
||||
assertHasDecl(Platform, "setCursorShape");
|
||||
assertHasField(Platform, "cursor_shape");
|
||||
}
|
||||
// assertHasDecl(Platform, "setCursorShape");
|
||||
// assertHasField(Platform, "cursor_shape");
|
||||
// }
|
||||
|
||||
fn assertHasDecl(comptime T: anytype, comptime decl_name: []const u8) void {
|
||||
if (!@hasDecl(T, decl_name)) @compileError(@typeName(T) ++ " missing declaration: " ++ decl_name);
|
||||
|
|
@ -1112,7 +1016,6 @@ fn assertHasField(comptime T: anytype, comptime field_name: []const u8) void {
|
|||
|
||||
test {
|
||||
_ = Platform;
|
||||
@import("std").testing.refAllDeclsRecursive(InitOptions);
|
||||
@import("std").testing.refAllDeclsRecursive(VSyncMode);
|
||||
@import("std").testing.refAllDeclsRecursive(Size);
|
||||
@import("std").testing.refAllDeclsRecursive(Position);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue