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
|
|
@ -28,8 +28,10 @@ pub fn init(
|
||||||
core.on_tick = app_mod.id.tick;
|
core.on_tick = app_mod.id.tick;
|
||||||
core.on_exit = app_mod.id.deinit;
|
core.on_exit = app_mod.id.deinit;
|
||||||
|
|
||||||
|
const main_window = core.windows.getValue(core.main_window);
|
||||||
|
|
||||||
// Create our shader module
|
// Create our shader module
|
||||||
const shader_module = core.device.createShaderModuleWGSL("shader.wgsl", @embedFile("shader.wgsl"));
|
const shader_module = main_window.device.createShaderModuleWGSL("shader.wgsl", @embedFile("shader.wgsl"));
|
||||||
defer shader_module.release();
|
defer shader_module.release();
|
||||||
|
|
||||||
// Blend state describes how rendered colors get blended
|
// Blend state describes how rendered colors get blended
|
||||||
|
|
@ -37,7 +39,7 @@ pub fn init(
|
||||||
|
|
||||||
// Color target describes e.g. the pixel format of the window we are rendering to.
|
// Color target describes e.g. the pixel format of the window we are rendering to.
|
||||||
const color_target = gpu.ColorTargetState{
|
const color_target = gpu.ColorTargetState{
|
||||||
.format = core.windows.get(core.main_window, .framebuffer_format).?,
|
.format = main_window.framebuffer_format,
|
||||||
.blend = &blend,
|
.blend = &blend,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -58,7 +60,7 @@ pub fn init(
|
||||||
.entry_point = "vertex_main",
|
.entry_point = "vertex_main",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const pipeline = core.device.createRenderPipeline(&pipeline_descriptor);
|
const pipeline = main_window.device.createRenderPipeline(&pipeline_descriptor);
|
||||||
|
|
||||||
// Store our render pipeline in our module's state, so we can access it later on.
|
// Store our render pipeline in our module's state, so we can access it later on.
|
||||||
app.* = .{
|
app.* = .{
|
||||||
|
|
@ -78,14 +80,16 @@ pub fn tick(core: *mach.Core, app: *App) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const main_window = core.windows.getValue(core.main_window);
|
||||||
|
|
||||||
// Grab the back buffer of the swapchain
|
// Grab the back buffer of the swapchain
|
||||||
// TODO(Core)
|
// TODO(Core)
|
||||||
const back_buffer_view = core.swap_chain.getCurrentTextureView().?;
|
const back_buffer_view = main_window.swap_chain.getCurrentTextureView().?;
|
||||||
defer back_buffer_view.release();
|
defer back_buffer_view.release();
|
||||||
|
|
||||||
// Create a command encoder
|
// Create a command encoder
|
||||||
const label = @tagName(mach_module) ++ ".tick";
|
const label = @tagName(mach_module) ++ ".tick";
|
||||||
const encoder = core.device.createCommandEncoder(&.{ .label = label });
|
const encoder = main_window.device.createCommandEncoder(&.{ .label = label });
|
||||||
defer encoder.release();
|
defer encoder.release();
|
||||||
|
|
||||||
// Begin render pass
|
// Begin render pass
|
||||||
|
|
@ -112,7 +116,7 @@ pub fn tick(core: *mach.Core, app: *App) !void {
|
||||||
// Submit our commands to the queue
|
// Submit our commands to the queue
|
||||||
var command = encoder.finish(&.{ .label = label });
|
var command = encoder.finish(&.{ .label = label });
|
||||||
defer command.release();
|
defer command.release();
|
||||||
core.queue.submit(&[_]*gpu.CommandBuffer{command});
|
main_window.queue.submit(&[_]*gpu.CommandBuffer{command});
|
||||||
|
|
||||||
// update the window title every second
|
// update the window title every second
|
||||||
if (app.title_timer.read() >= 1.0) {
|
if (app.title_timer.read() >= 1.0) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
const std = @import("std");
|
||||||
const mach = @import("mach");
|
const mach = @import("mach");
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
|
|
||||||
|
|
@ -24,8 +25,12 @@ pub fn init(
|
||||||
core.on_tick = app_mod.id.tick;
|
core.on_tick = app_mod.id.tick;
|
||||||
core.on_exit = app_mod.id.deinit;
|
core.on_exit = app_mod.id.deinit;
|
||||||
|
|
||||||
|
const main_window = core.windows.getValue(core.main_window);
|
||||||
|
if (main_window.native != null) {
|
||||||
|
// if window.native is not null, the window is initialized
|
||||||
|
|
||||||
// Create our shader module
|
// Create our shader module
|
||||||
const shader_module = core.device.createShaderModuleWGSL("shader.wgsl", @embedFile("shader.wgsl"));
|
const shader_module = main_window.device.createShaderModuleWGSL("shader.wgsl", @embedFile("shader.wgsl"));
|
||||||
defer shader_module.release();
|
defer shader_module.release();
|
||||||
|
|
||||||
// Blend state describes how rendered colors get blended
|
// Blend state describes how rendered colors get blended
|
||||||
|
|
@ -33,7 +38,7 @@ pub fn init(
|
||||||
|
|
||||||
// Color target describes e.g. the pixel format of the window we are rendering to.
|
// Color target describes e.g. the pixel format of the window we are rendering to.
|
||||||
const color_target = gpu.ColorTargetState{
|
const color_target = gpu.ColorTargetState{
|
||||||
.format = core.windows.get(core.main_window, .framebuffer_format).?,
|
.format = core.windows.get(core.main_window, .framebuffer_format),
|
||||||
.blend = &blend,
|
.blend = &blend,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -54,34 +59,61 @@ pub fn init(
|
||||||
.entry_point = "vertex_main",
|
.entry_point = "vertex_main",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const pipeline = core.device.createRenderPipeline(&pipeline_descriptor);
|
const pipeline = main_window.device.createRenderPipeline(&pipeline_descriptor);
|
||||||
|
|
||||||
// Store our render pipeline in our module's state, so we can access it later on.
|
// Store our render pipeline in our module's state, so we can access it later on.
|
||||||
app.* = .{
|
app.* = .{
|
||||||
.title_timer = try mach.time.Timer.start(),
|
.title_timer = try mach.time.Timer.start(),
|
||||||
.pipeline = pipeline,
|
.pipeline = pipeline,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
// TODO(object): window-title
|
|
||||||
// try updateWindowTitle(core);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(object): window-title
|
||||||
|
// try updateWindowTitle(core);
|
||||||
|
|
||||||
pub fn tick(app: *App, core: *mach.Core) void {
|
pub fn tick(app: *App, core: *mach.Core) void {
|
||||||
while (core.nextEvent()) |event| {
|
while (core.nextEvent()) |event| {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
.key_press => |ev| {
|
||||||
|
switch (ev.key) {
|
||||||
|
.right => {
|
||||||
|
var w = core.windows.getValue(core.main_window);
|
||||||
|
w.width = w.width + 10;
|
||||||
|
core.windows.setValue(core.main_window, w);
|
||||||
|
},
|
||||||
|
.left => {
|
||||||
|
var w = core.windows.getValue(core.main_window);
|
||||||
|
w.width = w.width - 10;
|
||||||
|
core.windows.setValue(core.main_window, w);
|
||||||
|
},
|
||||||
|
.up => {
|
||||||
|
core.windows.set(core.main_window, .height, core.windows.get(core.main_window, .height) + 10);
|
||||||
|
},
|
||||||
|
.down => {
|
||||||
|
core.windows.set(core.main_window, .height, core.windows.get(core.main_window, .height) - 10);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
},
|
||||||
.close => core.exit(),
|
.close => core.exit(),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var main_window = core.windows.getValue(core.main_window);
|
||||||
|
|
||||||
|
// Window is ready when device is not null
|
||||||
|
|
||||||
// Grab the back buffer of the swapchain
|
// Grab the back buffer of the swapchain
|
||||||
// TODO(Core)
|
// TODO(Core)
|
||||||
const back_buffer_view = core.swap_chain.getCurrentTextureView().?;
|
const back_buffer_view = main_window.swap_chain.getCurrentTextureView().?;
|
||||||
defer back_buffer_view.release();
|
defer back_buffer_view.release();
|
||||||
|
|
||||||
// Create a command encoder
|
// Create a command encoder
|
||||||
const label = @tagName(mach_module) ++ ".tick";
|
const label = @tagName(mach_module) ++ ".tick";
|
||||||
const encoder = core.device.createCommandEncoder(&.{ .label = label });
|
|
||||||
|
const encoder = main_window.device.createCommandEncoder(&.{ .label = label });
|
||||||
defer encoder.release();
|
defer encoder.release();
|
||||||
|
|
||||||
// Begin render pass
|
// Begin render pass
|
||||||
|
|
@ -108,14 +140,14 @@ pub fn tick(app: *App, core: *mach.Core) void {
|
||||||
// Submit our commands to the queue
|
// Submit our commands to the queue
|
||||||
var command = encoder.finish(&.{ .label = label });
|
var command = encoder.finish(&.{ .label = label });
|
||||||
defer command.release();
|
defer command.release();
|
||||||
core.queue.submit(&[_]*gpu.CommandBuffer{command});
|
main_window.queue.submit(&[_]*gpu.CommandBuffer{command});
|
||||||
|
|
||||||
// update the window title every second
|
// update the window title every second
|
||||||
if (app.title_timer.read() >= 1.0) {
|
// if (app.title_timer.read() >= 1.0) {
|
||||||
app.title_timer.reset();
|
// app.title_timer.reset();
|
||||||
// TODO(object): window-title
|
// // TODO(object): window-title
|
||||||
// try updateWindowTitle(core);
|
// // try updateWindowTitle(core);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(app: *App) void {
|
pub fn deinit(app: *App) void {
|
||||||
|
|
|
||||||
439
src/Core.zig
439
src/Core.zig
|
|
@ -30,7 +30,7 @@ pub var non_blocking = false;
|
||||||
|
|
||||||
pub const mach_module = .mach_core;
|
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
|
// Set track_fields to true so that when these field values change, we know about it
|
||||||
// and can update the platform windows.
|
// and can update the platform windows.
|
||||||
|
|
@ -40,25 +40,63 @@ windows: mach.Objects(
|
||||||
/// Window title string
|
/// Window title string
|
||||||
// TODO: document how to set this using a format string
|
// TODO: document how to set this using a format string
|
||||||
// TODO: allocation/free strategy
|
// TODO: allocation/free strategy
|
||||||
title: []const u8,
|
title: []const u8 = "Mach Window",
|
||||||
|
|
||||||
/// Texture format of the framebuffer (read-only)
|
/// 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)
|
/// 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)
|
/// 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 of the window in virtual pixels (read-only)
|
||||||
width: u32,
|
width: u32 = 1920 / 2,
|
||||||
|
|
||||||
/// Height of the window in virtual pixels (read-only)
|
/// Height of the window in virtual pixels (read-only)
|
||||||
height: u32,
|
height: u32 = 1080 / 2,
|
||||||
|
|
||||||
/// Whether the window is fullscreen (read-only)
|
/// Target frames per second
|
||||||
fullscreen: bool,
|
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,
|
exited,
|
||||||
} = .running,
|
} = .running,
|
||||||
|
|
||||||
// TODO: handle window titles better
|
|
||||||
title: [256:0]u8 = undefined,
|
|
||||||
frame: mach.time.Frequency,
|
frame: mach.time.Frequency,
|
||||||
input: 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
|
// Internal module state
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
platform: Platform,
|
|
||||||
events: EventQueue,
|
events: EventQueue,
|
||||||
input_state: InputState,
|
input_state: InputState,
|
||||||
oom: std.Thread.ResetEvent = .{},
|
oom: std.Thread.ResetEvent = .{},
|
||||||
|
|
||||||
pub fn init(core: *Core) !void {
|
pub fn init(core: *Core) !void {
|
||||||
// TODO: this needs to be removed.
|
const allocator = std.heap.c_allocator;
|
||||||
const options: InitOptions = .{
|
|
||||||
.allocator = std.heap.c_allocator,
|
|
||||||
};
|
|
||||||
const allocator = options.allocator;
|
|
||||||
|
|
||||||
// TODO: fix all leaks and use options.allocator
|
// TODO: fix all leaks and use options.allocator
|
||||||
try mach.sysgpu.Impl.init(allocator, .{});
|
try mach.sysgpu.Impl.init(allocator, .{});
|
||||||
|
|
||||||
const main_window = try core.windows.new(.{
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
var events = EventQueue.init(allocator);
|
var events = EventQueue.init(allocator);
|
||||||
try events.ensureTotalCapacity(8192);
|
try events.ensureTotalCapacity(8192);
|
||||||
|
|
||||||
// TODO: remove undefined initialization (disgusting!)
|
|
||||||
const platform: Platform = undefined;
|
|
||||||
core.* = .{
|
core.* = .{
|
||||||
// Note: since core.windows is initialized for us already, we just copy the pointer.
|
// Note: since core.windows is initialized for us already, we just copy the pointer.
|
||||||
.windows = core.windows,
|
.windows = core.windows,
|
||||||
|
|
@ -142,33 +146,32 @@ pub fn init(core: *Core) !void {
|
||||||
.events = events,
|
.events = events,
|
||||||
.input_state = .{},
|
.input_state = .{},
|
||||||
|
|
||||||
.platform = platform,
|
.input = .{ .target = 0 },
|
||||||
|
.frame = .{ .target = 1 },
|
||||||
// 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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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", .{});
|
log.err("failed to create GPU instance", .{});
|
||||||
std.process.exit(1);
|
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;
|
var response: RequestAdapterResponse = undefined;
|
||||||
core.instance.requestAdapter(&gpu.RequestAdapterOptions{
|
core_window.instance.requestAdapter(&gpu.RequestAdapterOptions{
|
||||||
.compatible_surface = core.surface,
|
.compatible_surface = core_window.surface,
|
||||||
.power_preference = options.power_preference,
|
.power_preference = core_window.power_preference,
|
||||||
.force_fallback_adapter = .false,
|
.force_fallback_adapter = .false,
|
||||||
}, &response, requestAdapterCallback);
|
}, &response, requestAdapterCallback);
|
||||||
if (response.status != .success) {
|
if (response.status != .success) {
|
||||||
|
|
@ -191,13 +194,13 @@ pub fn init(core: *Core) !void {
|
||||||
props.driver_description,
|
props.driver_description,
|
||||||
});
|
});
|
||||||
|
|
||||||
core.adapter = response.adapter.?;
|
core_window.adapter = response.adapter.?;
|
||||||
|
|
||||||
// Create a device with default limits/features.
|
// Create a device with default limits/features.
|
||||||
core.device = response.adapter.?.createDevice(&.{
|
core_window.device = response.adapter.?.createDevice(&.{
|
||||||
.required_features_count = if (options.required_features) |v| @as(u32, @intCast(v.len)) else 0,
|
.required_features_count = if (core_window.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_features = if (core_window.required_features) |v| @as(?[*]const gpu.FeatureName, v.ptr) else null,
|
||||||
.required_limits = if (options.required_limits) |limits| @as(?*const gpu.RequiredLimits, &gpu.RequiredLimits{
|
.required_limits = if (core_window.required_limits) |limits| @as(?*const gpu.RequiredLimits, &gpu.RequiredLimits{
|
||||||
.limits = limits,
|
.limits = limits,
|
||||||
}) else null,
|
}) else null,
|
||||||
.device_lost_callback = &deviceLostCallback,
|
.device_lost_callback = &deviceLostCallback,
|
||||||
|
|
@ -206,51 +209,46 @@ pub fn init(core: *Core) !void {
|
||||||
log.err("failed to create GPU device\n", .{});
|
log.err("failed to create GPU device\n", .{});
|
||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
};
|
};
|
||||||
core.device.setUncapturedErrorCallback({}, printUnhandledErrorCallback);
|
core_window.device.setUncapturedErrorCallback({}, printUnhandledErrorCallback);
|
||||||
core.queue = core.device.getQueue();
|
core_window.queue = core_window.device.getQueue();
|
||||||
|
|
||||||
core.descriptor = gpu.SwapChain.Descriptor{
|
core_window.swap_chain_descriptor = gpu.SwapChain.Descriptor{
|
||||||
.label = "main swap chain",
|
.label = "main swap chain",
|
||||||
.usage = options.swap_chain_usage,
|
.usage = core_window.swap_chain_usage,
|
||||||
.format = .bgra8_unorm,
|
.format = .bgra8_unorm,
|
||||||
.width = @intCast(core.platform.size.width),
|
.width = core_window.width,
|
||||||
.height = @intCast(core.platform.size.height),
|
.height = core_window.height,
|
||||||
.present_mode = switch (core.platform.vsync_mode) {
|
.present_mode = switch (core_window.vsync_mode) {
|
||||||
.none => .immediate,
|
.none => .immediate,
|
||||||
.double => .fifo,
|
.double => .fifo,
|
||||||
.triple => .mailbox,
|
.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.setValueRaw(window_id, core_window);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.run(core.on_tick.?);
|
||||||
core_mod.call(.presentFrame);
|
core_mod.call(.presentFrame);
|
||||||
core_mod.call(.processWindowUpdates);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(core: *Core, core_mod: mach.Mod(Core)) !void {
|
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_tick == null) @panic("core.on_tick callback must be set");
|
||||||
if (core.on_exit == null) @panic("core.on_exit 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.run(core.on_tick.?);
|
||||||
core_mod.call(.presentFrame);
|
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 {
|
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.run(core.on_tick.?);
|
||||||
core_mod.call(.presentFrame);
|
core_mod.call(.presentFrame);
|
||||||
core_mod.call(.processWindowUpdates);
|
//core_mod.call(.processWindowUpdates);
|
||||||
|
|
||||||
return core.state != .exited;
|
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 {
|
pub fn deinit(core: *Core) !void {
|
||||||
core.state = .exited;
|
core.state = .exited;
|
||||||
|
|
||||||
// TODO(object)(window-title)
|
var windows = core.windows.slice();
|
||||||
// var q = try entities.query(.{
|
while (windows.next()) |window_id| {
|
||||||
// .titles = Mod.read(.title),
|
var core_window = core.windows.getValue(window_id);
|
||||||
// });
|
core_window.swap_chain.release();
|
||||||
// while (q.next()) |v| {
|
core_window.queue.release();
|
||||||
// for (v.titles) |title| {
|
core_window.device.release();
|
||||||
// state.allocator.free(title);
|
core_window.surface.release();
|
||||||
// }
|
core_window.adapter.release();
|
||||||
// }
|
core_window.instance.release();
|
||||||
|
}
|
||||||
// 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();
|
|
||||||
|
|
||||||
core.events.deinit();
|
core.events.deinit();
|
||||||
}
|
}
|
||||||
|
|
@ -376,50 +356,6 @@ pub fn outOfMemory(core: *@This()) bool {
|
||||||
return true;
|
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 {
|
pub fn keyPressed(core: *@This(), key: Key) bool {
|
||||||
return core.input_state.isKeyPressed(key);
|
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 {
|
pub fn presentFrame(core: *Core, core_mod: mach.Mod(Core)) !void {
|
||||||
// TODO(object)(window-title)
|
var windows = core.windows.slice();
|
||||||
// // Update windows title
|
while (windows.next()) |window_id| {
|
||||||
// var num_windows: usize = 0;
|
var core_window = core.windows.getValue(window_id);
|
||||||
// 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");
|
|
||||||
|
|
||||||
_ = try core.platform.update();
|
mach.sysgpu.Impl.deviceTick(core_window.device);
|
||||||
mach.sysgpu.Impl.deviceTick(core.device);
|
|
||||||
core.swap_chain.present();
|
core_window.swap_chain.present();
|
||||||
|
|
||||||
// Update swapchain for the next frame
|
// Update swapchain for the next frame
|
||||||
if (core.swap_chain_update.isSet()) blk: {
|
if (core_window.swap_chain_update.isSet()) blk: {
|
||||||
core.swap_chain_update.reset();
|
core_window.swap_chain_update.reset();
|
||||||
|
|
||||||
switch (core.platform.vsync_mode) {
|
switch (core_window.vsync_mode) {
|
||||||
.triple => core.frame.target = 2 * core.platform.refresh_rate,
|
.triple => core.frame.target = 2 * core_window.refresh_rate,
|
||||||
else => core.frame.target = 0,
|
else => core.frame.target = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core.platform.size.width == 0 or core.platform.size.height == 0) break :blk;
|
if (core_window.width == 0 or core_window.height == 0) break :blk;
|
||||||
|
|
||||||
core.descriptor.present_mode = switch (core.platform.vsync_mode) {
|
core_window.swap_chain_descriptor.present_mode = switch (core_window.vsync_mode) {
|
||||||
.none => .immediate,
|
.none => .immediate,
|
||||||
.double => .fifo,
|
.double => .fifo,
|
||||||
.triple => .mailbox,
|
.triple => .mailbox,
|
||||||
};
|
};
|
||||||
core.descriptor.width = @intCast(core.platform.size.width);
|
|
||||||
core.descriptor.height = @intCast(core.platform.size.height);
|
core_window.swap_chain_descriptor.width = core_window.width;
|
||||||
core.swap_chain.release();
|
core_window.swap_chain_descriptor.height = core_window.height;
|
||||||
core.swap_chain = core.device.createSwapChain(core.surface, &core.descriptor);
|
core_window.swap_chain.release();
|
||||||
|
|
||||||
|
core_window.swap_chain = core_window.device.createSwapChain(core_window.surface, &core_window.swap_chain_descriptor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(important): update this information in response to resize events rather than
|
// 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 {
|
pub fn exit(core: *Core) void {
|
||||||
core.state = .exiting;
|
core.state = .exiting;
|
||||||
}
|
}
|
||||||
|
|
@ -745,24 +651,6 @@ const Platform = switch (build_options.core_platform) {
|
||||||
.null => @import("core/Null.zig"),
|
.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 {
|
pub const InputState = struct {
|
||||||
const KeyBitSet = std.StaticBitSet(@as(u8, @intFromEnum(Key.max)) + 1);
|
const KeyBitSet = std.StaticBitSet(@as(u8, @intFromEnum(Key.max)) + 1);
|
||||||
const MouseButtonSet = std.StaticBitSet(@as(u4, @intFromEnum(MouseButton.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_repeat: KeyEvent,
|
||||||
key_release: KeyEvent,
|
key_release: KeyEvent,
|
||||||
char_input: struct {
|
char_input: struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
codepoint: u21,
|
codepoint: u21,
|
||||||
},
|
},
|
||||||
mouse_motion: struct {
|
mouse_motion: struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
},
|
},
|
||||||
mouse_press: MouseButtonEvent,
|
mouse_press: MouseButtonEvent,
|
||||||
mouse_release: MouseButtonEvent,
|
mouse_release: MouseButtonEvent,
|
||||||
mouse_scroll: struct {
|
mouse_scroll: struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
xoffset: f32,
|
xoffset: f32,
|
||||||
yoffset: f32,
|
yoffset: f32,
|
||||||
},
|
},
|
||||||
framebuffer_resize: Size,
|
window_resize: ResizeEvent,
|
||||||
focus_gained,
|
focus_gained: struct {
|
||||||
focus_lost,
|
window_id: mach.ObjectID,
|
||||||
close,
|
},
|
||||||
|
focus_lost: struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
|
},
|
||||||
|
close: struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const KeyEvent = struct {
|
pub const KeyEvent = struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
key: Key,
|
key: Key,
|
||||||
mods: KeyMods,
|
mods: KeyMods,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MouseButtonEvent = struct {
|
pub const MouseButtonEvent = struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
button: MouseButton,
|
button: MouseButton,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
mods: KeyMods,
|
mods: KeyMods,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const ResizeEvent = struct {
|
||||||
|
window_id: mach.ObjectID,
|
||||||
|
size: Size,
|
||||||
|
};
|
||||||
|
|
||||||
pub const MouseButton = enum {
|
pub const MouseButton = enum {
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
|
|
@ -1070,37 +974,37 @@ const RequestAdapterResponse = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Verifies that a platform implementation exposes the expected function declarations.
|
// Verifies that a platform implementation exposes the expected function declarations.
|
||||||
comptime {
|
// comptime {
|
||||||
// Core
|
// // Core
|
||||||
assertHasField(Platform, "surface_descriptor");
|
// assertHasField(Platform, "surface_descriptor");
|
||||||
assertHasField(Platform, "refresh_rate");
|
// assertHasField(Platform, "refresh_rate");
|
||||||
|
|
||||||
assertHasDecl(Platform, "init");
|
// assertHasDecl(Platform, "init");
|
||||||
assertHasDecl(Platform, "deinit");
|
// assertHasDecl(Platform, "deinit");
|
||||||
|
|
||||||
assertHasDecl(Platform, "setTitle");
|
// assertHasDecl(Platform, "setTitle");
|
||||||
|
|
||||||
assertHasDecl(Platform, "setDisplayMode");
|
// assertHasDecl(Platform, "setDisplayMode");
|
||||||
assertHasField(Platform, "display_mode");
|
// assertHasField(Platform, "display_mode");
|
||||||
|
|
||||||
assertHasDecl(Platform, "setBorder");
|
// assertHasDecl(Platform, "setBorder");
|
||||||
assertHasField(Platform, "border");
|
// assertHasField(Platform, "border");
|
||||||
|
|
||||||
assertHasDecl(Platform, "setHeadless");
|
// assertHasDecl(Platform, "setHeadless");
|
||||||
assertHasField(Platform, "headless");
|
// assertHasField(Platform, "headless");
|
||||||
|
|
||||||
assertHasDecl(Platform, "setVSync");
|
// assertHasDecl(Platform, "setVSync");
|
||||||
assertHasField(Platform, "vsync_mode");
|
// assertHasField(Platform, "vsync_mode");
|
||||||
|
|
||||||
assertHasDecl(Platform, "setSize");
|
// assertHasDecl(Platform, "setSize");
|
||||||
assertHasField(Platform, "size");
|
// assertHasField(Platform, "size");
|
||||||
|
|
||||||
assertHasDecl(Platform, "setCursorMode");
|
// assertHasDecl(Platform, "setCursorMode");
|
||||||
assertHasField(Platform, "cursor_mode");
|
// assertHasField(Platform, "cursor_mode");
|
||||||
|
|
||||||
assertHasDecl(Platform, "setCursorShape");
|
// assertHasDecl(Platform, "setCursorShape");
|
||||||
assertHasField(Platform, "cursor_shape");
|
// assertHasField(Platform, "cursor_shape");
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn assertHasDecl(comptime T: anytype, comptime decl_name: []const u8) void {
|
fn assertHasDecl(comptime T: anytype, comptime decl_name: []const u8) void {
|
||||||
if (!@hasDecl(T, decl_name)) @compileError(@typeName(T) ++ " missing declaration: " ++ decl_name);
|
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 {
|
test {
|
||||||
_ = Platform;
|
_ = Platform;
|
||||||
@import("std").testing.refAllDeclsRecursive(InitOptions);
|
|
||||||
@import("std").testing.refAllDeclsRecursive(VSyncMode);
|
@import("std").testing.refAllDeclsRecursive(VSyncMode);
|
||||||
@import("std").testing.refAllDeclsRecursive(Size);
|
@import("std").testing.refAllDeclsRecursive(Size);
|
||||||
@import("std").testing.refAllDeclsRecursive(Position);
|
@import("std").testing.refAllDeclsRecursive(Position);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ const std = @import("std");
|
||||||
const mach = @import("../main.zig");
|
const mach = @import("../main.zig");
|
||||||
const Core = @import("../Core.zig");
|
const Core = @import("../Core.zig");
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const InitOptions = Core.InitOptions;
|
|
||||||
const Event = Core.Event;
|
const Event = Core.Event;
|
||||||
const KeyEvent = Core.KeyEvent;
|
const KeyEvent = Core.KeyEvent;
|
||||||
const MouseButtonEvent = Core.MouseButtonEvent;
|
const MouseButtonEvent = Core.MouseButtonEvent;
|
||||||
|
|
@ -21,26 +20,14 @@ const log = std.log.scoped(.mach);
|
||||||
|
|
||||||
pub const Darwin = @This();
|
pub const Darwin = @This();
|
||||||
|
|
||||||
// --------------------------
|
pub const Native = struct {
|
||||||
// Module state
|
window: ?*objc.app_kit.Window = null,
|
||||||
// --------------------------
|
};
|
||||||
allocator: std.mem.Allocator,
|
|
||||||
core: *Core,
|
|
||||||
|
|
||||||
// Core platform interface
|
pub const Context = struct {
|
||||||
surface_descriptor: gpu.Surface.Descriptor,
|
core: *Core,
|
||||||
title: [:0]const u8,
|
window_id: mach.ObjectID,
|
||||||
display_mode: DisplayMode,
|
};
|
||||||
vsync_mode: VSyncMode,
|
|
||||||
cursor_mode: CursorMode,
|
|
||||||
cursor_shape: CursorShape,
|
|
||||||
border: bool,
|
|
||||||
headless: bool,
|
|
||||||
refresh_rate: u32,
|
|
||||||
size: Size,
|
|
||||||
|
|
||||||
// Internals
|
|
||||||
window: ?*objc.app_kit.Window,
|
|
||||||
|
|
||||||
pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@TypeOf(on_each_update_fn))) noreturn {
|
pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@TypeOf(on_each_update_fn))) noreturn {
|
||||||
const Args = @TypeOf(args_tuple);
|
const Args = @TypeOf(args_tuple);
|
||||||
|
|
@ -76,193 +63,177 @@ pub fn run(comptime on_each_update_fn: anytype, args_tuple: std.meta.ArgsTuple(@
|
||||||
// TODO: support UIKit.
|
// TODO: support UIKit.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(
|
pub fn tick(core: *Core) !void {
|
||||||
darwin: *Darwin,
|
var windows = core.windows.slice();
|
||||||
core: *Core,
|
while (windows.next()) |window_id| {
|
||||||
options: InitOptions,
|
const native_opt: ?Native = core.windows.get(window_id, .native);
|
||||||
) !void {
|
|
||||||
var surface_descriptor = gpu.Surface.Descriptor{};
|
|
||||||
|
|
||||||
// TODO: support UIKit.
|
if (native_opt) |native| {
|
||||||
var window_opt: ?*objc.app_kit.Window = null;
|
if (native.window) |native_window| {
|
||||||
if (!options.headless) {
|
// Handle resizing the window when the user changes width or height
|
||||||
|
if (core.windows.updated(window_id, .width) or core.windows.updated(window_id, .height)) {
|
||||||
|
var frame = native_window.frame();
|
||||||
|
frame.size.height = @floatFromInt(core.windows.get(window_id, .width));
|
||||||
|
frame.size.width = @floatFromInt(core.windows.get(window_id, .height));
|
||||||
|
native_window.setFrame_display_animate(frame, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try initWindow(core, window_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initWindow(
|
||||||
|
core: *Core,
|
||||||
|
window_id: mach.ObjectID,
|
||||||
|
) !void {
|
||||||
|
var core_window = core.windows.getValue(window_id);
|
||||||
// If the application is not headless, we need to make the application a genuine UI application
|
// If the application is not headless, we need to make the application a genuine UI application
|
||||||
// by setting the activation policy, this moves the process to foreground
|
// by setting the activation policy, this moves the process to foreground
|
||||||
|
// TODO: Only call this on the first window creation
|
||||||
_ = objc.app_kit.Application.sharedApplication().setActivationPolicy(objc.app_kit.ApplicationActivationPolicyRegular);
|
_ = objc.app_kit.Application.sharedApplication().setActivationPolicy(objc.app_kit.ApplicationActivationPolicyRegular);
|
||||||
|
|
||||||
const metal_descriptor = try options.allocator.create(gpu.Surface.DescriptorFromMetalLayer);
|
const metal_descriptor = try core.allocator.create(gpu.Surface.DescriptorFromMetalLayer);
|
||||||
const layer = objc.quartz_core.MetalLayer.new();
|
const layer = objc.quartz_core.MetalLayer.new();
|
||||||
defer layer.release();
|
defer layer.release();
|
||||||
layer.setDisplaySyncEnabled(true);
|
layer.setDisplaySyncEnabled(true);
|
||||||
metal_descriptor.* = .{
|
metal_descriptor.* = .{
|
||||||
.layer = layer,
|
.layer = layer,
|
||||||
};
|
};
|
||||||
surface_descriptor.next_in_chain = .{ .from_metal_layer = metal_descriptor };
|
core_window.surface_descriptor = .{};
|
||||||
|
core_window.surface_descriptor.next_in_chain = .{ .from_metal_layer = metal_descriptor };
|
||||||
|
|
||||||
const screen = objc.app_kit.Screen.mainScreen();
|
const screen = objc.app_kit.Screen.mainScreen();
|
||||||
const rect = objc.core_graphics.Rect{
|
const rect = objc.core_graphics.Rect{
|
||||||
.origin = .{ .x = 0, .y = 0 },
|
.origin = .{ .x = 0, .y = 0 },
|
||||||
.size = .{ .width = @floatFromInt(options.size.width), .height = @floatFromInt(options.size.height) },
|
.size = .{ .width = @floatFromInt(core_window.width), .height = @floatFromInt(core_window.height) },
|
||||||
};
|
};
|
||||||
|
|
||||||
const window_style =
|
const window_style =
|
||||||
(if (options.display_mode == .fullscreen) objc.app_kit.WindowStyleMaskFullScreen else 0) |
|
(if (core_window.display_mode == .fullscreen) objc.app_kit.WindowStyleMaskFullScreen else 0) |
|
||||||
(if (options.display_mode == .windowed) objc.app_kit.WindowStyleMaskTitled else 0) |
|
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskTitled else 0) |
|
||||||
(if (options.display_mode == .windowed) objc.app_kit.WindowStyleMaskClosable else 0) |
|
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskClosable else 0) |
|
||||||
(if (options.display_mode == .windowed) objc.app_kit.WindowStyleMaskMiniaturizable else 0) |
|
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskMiniaturizable else 0) |
|
||||||
(if (options.display_mode == .windowed) objc.app_kit.WindowStyleMaskResizable else 0);
|
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskResizable else 0);
|
||||||
|
|
||||||
window_opt = objc.app_kit.Window.alloc().initWithContentRect_styleMask_backing_defer_screen(
|
const native_window_opt: ?*objc.app_kit.Window = objc.app_kit.Window.alloc().initWithContentRect_styleMask_backing_defer_screen(
|
||||||
rect,
|
rect,
|
||||||
window_style,
|
window_style,
|
||||||
objc.app_kit.BackingStoreBuffered,
|
objc.app_kit.BackingStoreBuffered,
|
||||||
false,
|
false,
|
||||||
screen,
|
screen,
|
||||||
);
|
);
|
||||||
if (window_opt) |window| {
|
if (native_window_opt) |native_window| {
|
||||||
window.setReleasedWhenClosed(false);
|
native_window.setReleasedWhenClosed(false);
|
||||||
|
|
||||||
var view = objc.mach.View.allocInit();
|
var view = objc.mach.View.allocInit();
|
||||||
view.setLayer(@ptrCast(layer));
|
view.setLayer(@ptrCast(layer));
|
||||||
|
|
||||||
|
var context: Context = .{ .core = core, .window_id = window_id };
|
||||||
{
|
{
|
||||||
var keyDown = objc.foundation.stackBlockLiteral(ViewCallbacks.keyDown, darwin, null, null);
|
var keyDown = objc.foundation.stackBlockLiteral(
|
||||||
|
ViewCallbacks.keyDown,
|
||||||
|
&context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
view.setBlock_keyDown(keyDown.asBlock().copy());
|
view.setBlock_keyDown(keyDown.asBlock().copy());
|
||||||
|
|
||||||
var keyUp = objc.foundation.stackBlockLiteral(ViewCallbacks.keyUp, darwin, null, null);
|
var keyUp = objc.foundation.stackBlockLiteral(
|
||||||
|
ViewCallbacks.keyUp,
|
||||||
|
&context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
view.setBlock_keyUp(keyUp.asBlock().copy());
|
view.setBlock_keyUp(keyUp.asBlock().copy());
|
||||||
}
|
}
|
||||||
window.setContentView(@ptrCast(view));
|
native_window.setContentView(@ptrCast(view));
|
||||||
window.center();
|
native_window.center();
|
||||||
window.setIsVisible(true);
|
native_window.setIsVisible(true);
|
||||||
window.makeKeyAndOrderFront(null);
|
native_window.makeKeyAndOrderFront(null);
|
||||||
|
|
||||||
const delegate = objc.mach.WindowDelegate.allocInit();
|
const delegate = objc.mach.WindowDelegate.allocInit();
|
||||||
defer window.setDelegate(@ptrCast(delegate));
|
defer native_window.setDelegate(@ptrCast(delegate));
|
||||||
{ // Set WindowDelegate blocks
|
{ // Set WindowDelegate blocks
|
||||||
var windowWillResize_toSize = objc.foundation.stackBlockLiteral(WindowDelegateCallbacks.windowWillResize_toSize, darwin, null, null);
|
|
||||||
|
var windowWillResize_toSize = objc.foundation.stackBlockLiteral(
|
||||||
|
WindowDelegateCallbacks.windowWillResize_toSize,
|
||||||
|
&context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
delegate.setBlock_windowWillResize_toSize(windowWillResize_toSize.asBlock().copy());
|
delegate.setBlock_windowWillResize_toSize(windowWillResize_toSize.asBlock().copy());
|
||||||
|
|
||||||
var windowShouldClose = objc.foundation.stackBlockLiteral(WindowDelegateCallbacks.windowShouldClose, darwin, null, null);
|
var windowShouldClose = objc.foundation.stackBlockLiteral(
|
||||||
|
WindowDelegateCallbacks.windowShouldClose,
|
||||||
|
&context,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
delegate.setBlock_windowShouldClose(windowShouldClose.asBlock().copy());
|
delegate.setBlock_windowShouldClose(windowShouldClose.asBlock().copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set core_window.native, which we use to check if a window is initialized
|
||||||
|
// Then call core.initWindow to finish initializing the window
|
||||||
|
core_window.native = .{ .window = native_window };
|
||||||
|
core.windows.setValueRaw(window_id, core_window);
|
||||||
|
try core.initWindow(window_id);
|
||||||
} else std.debug.panic("mach: window failed to initialize", .{});
|
} else std.debug.panic("mach: window failed to initialize", .{});
|
||||||
}
|
|
||||||
|
|
||||||
darwin.* = .{
|
|
||||||
.allocator = options.allocator,
|
|
||||||
.core = core,
|
|
||||||
.title = options.title,
|
|
||||||
.display_mode = options.display_mode,
|
|
||||||
.vsync_mode = .none,
|
|
||||||
.cursor_mode = .normal,
|
|
||||||
.cursor_shape = .arrow,
|
|
||||||
.border = options.border,
|
|
||||||
.headless = options.headless,
|
|
||||||
.refresh_rate = 60, // TODO: set to something meaningful
|
|
||||||
.size = options.size,
|
|
||||||
.surface_descriptor = surface_descriptor,
|
|
||||||
.window = window_opt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(darwin: *Darwin) void {
|
|
||||||
if (darwin.window) |w| @as(*objc.foundation.ObjectProtocol, @ptrCast(w)).release();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(darwin: *Darwin) !void {
|
|
||||||
if (darwin.window) |window| window.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setTitle(darwin: *Darwin, title: [:0]const u8) void {
|
|
||||||
if (darwin.window) |window| {
|
|
||||||
var string = objc.app_kit.String.allocInit();
|
|
||||||
defer string.release();
|
|
||||||
string = string.initWithUTF8String(title.ptr);
|
|
||||||
window.setTitle(string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setDisplayMode(_: *Darwin, _: DisplayMode) void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setBorder(_: *Darwin, _: bool) void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setHeadless(_: *Darwin, _: bool) void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setVSync(_: *Darwin, _: VSyncMode) void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setSize(darwin: *Darwin, size: Size) void {
|
|
||||||
if (darwin.window) |window| {
|
|
||||||
var frame = window.frame();
|
|
||||||
frame.size.height = @floatFromInt(size.height);
|
|
||||||
frame.size.width = @floatFromInt(size.width);
|
|
||||||
window.setFrame_display_animate(frame, true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setCursorMode(_: *Darwin, _: CursorMode) void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setCursorShape(_: *Darwin, _: CursorShape) void {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const WindowDelegateCallbacks = struct {
|
const WindowDelegateCallbacks = struct {
|
||||||
pub fn windowWillResize_toSize(block: *objc.foundation.BlockLiteral(*Darwin), size: objc.app_kit.Size) callconv(.C) void {
|
pub fn windowWillResize_toSize(block: *objc.foundation.BlockLiteral(*Context), size: objc.app_kit.Size) callconv(.C) void {
|
||||||
const darwin: *Darwin = block.context;
|
const core: *Core = block.context.core;
|
||||||
const s: Size = .{ .width = @intFromFloat(size.width), .height = @intFromFloat(size.height) };
|
const s: Size = .{ .width = @intFromFloat(size.width), .height = @intFromFloat(size.height) };
|
||||||
|
|
||||||
// TODO: Eventually we need to be able to tie a window here with the window Objects in core, and treat the windows
|
var window = core.windows.getValue(block.context.window_id);
|
||||||
// as a list, rather than a single main window
|
window.width = s.width;
|
||||||
darwin.size = .{
|
window.height = s.height;
|
||||||
.height = s.width,
|
window.swap_chain_update.set();
|
||||||
.width = s.height,
|
core.windows.setValueRaw(block.context.window_id, window);
|
||||||
};
|
|
||||||
darwin.core.swap_chain_update.set();
|
|
||||||
|
|
||||||
darwin.core.windows.setRaw(darwin.core.main_window, .width, s.width);
|
core.pushEvent(.{ .window_resize = .{
|
||||||
darwin.core.windows.setRaw(darwin.core.main_window, .height, s.height);
|
.window_id = block.context.window_id,
|
||||||
|
.size = s,
|
||||||
darwin.core.pushEvent(.{ .framebuffer_resize = .{ .width = s.width, .height = s.height } });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn windowShouldClose(block: *objc.foundation.BlockLiteral(*Darwin)) callconv(.C) bool {
|
pub fn windowShouldClose(block: *objc.foundation.BlockLiteral(*Context)) callconv(.C) bool {
|
||||||
const darwin: *Darwin = block.context;
|
const core: *Core = block.context.core;
|
||||||
darwin.core.pushEvent(.close);
|
core.pushEvent(.{ .close = .{ .window_id = block.context.window_id } });
|
||||||
|
|
||||||
|
// TODO: This should just attempt to close the window, not the entire program, unless
|
||||||
|
// this is the only window.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const ViewCallbacks = struct {
|
const ViewCallbacks = struct {
|
||||||
pub fn keyDown(block: *objc.foundation.BlockLiteral(*Darwin), event: *objc.app_kit.Event) callconv(.C) void {
|
pub fn keyDown(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
||||||
const darwin: *Darwin = block.context;
|
const core: *Core = block.context.core;
|
||||||
|
const window_id = block.context.window_id;
|
||||||
if (event.isARepeat()) {
|
if (event.isARepeat()) {
|
||||||
darwin.core.pushEvent(.{ .key_repeat = .{
|
core.pushEvent(.{ .key_repeat = .{
|
||||||
|
.window_id = window_id,
|
||||||
.key = machKeyFromKeycode(event.keyCode()),
|
.key = machKeyFromKeycode(event.keyCode()),
|
||||||
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
||||||
} });
|
} });
|
||||||
} else {
|
} else {
|
||||||
darwin.core.pushEvent(.{ .key_press = .{
|
core.pushEvent(.{ .key_press = .{
|
||||||
|
.window_id = window_id,
|
||||||
.key = machKeyFromKeycode(event.keyCode()),
|
.key = machKeyFromKeycode(event.keyCode()),
|
||||||
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keyUp(block: *objc.foundation.BlockLiteral(*Darwin), event: *objc.app_kit.Event) callconv(.C) void {
|
pub fn keyUp(block: *objc.foundation.BlockLiteral(*Context), event: *objc.app_kit.Event) callconv(.C) void {
|
||||||
const darwin: *Darwin = block.context;
|
const core: *Core = block.context.core;
|
||||||
|
const window_id = block.context.window_id;
|
||||||
|
|
||||||
darwin.core.pushEvent(.{ .key_release = .{
|
core.pushEvent(.{ .key_release = .{
|
||||||
|
.window_id = window_id,
|
||||||
.key = machKeyFromKeycode(event.keyCode()),
|
.key = machKeyFromKeycode(event.keyCode()),
|
||||||
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
.mods = machModifierFromModifierFlag(event.modifierFlags()),
|
||||||
} });
|
} });
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ const std = @import("std");
|
||||||
const mach = @import("../main.zig");
|
const mach = @import("../main.zig");
|
||||||
const Core = @import("../Core.zig");
|
const Core = @import("../Core.zig");
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const InitOptions = Core.InitOptions;
|
//const InitOptions = Core.InitOptions;
|
||||||
const Event = Core.Event;
|
const Event = Core.Event;
|
||||||
const KeyEvent = Core.KeyEvent;
|
const KeyEvent = Core.KeyEvent;
|
||||||
const MouseButtonEvent = Core.MouseButtonEvent;
|
const MouseButtonEvent = Core.MouseButtonEvent;
|
||||||
|
|
@ -40,10 +40,10 @@ surface_descriptor: gpu.Surface.Descriptor,
|
||||||
pub fn init(
|
pub fn init(
|
||||||
nul: *Null,
|
nul: *Null,
|
||||||
core: *Core,
|
core: *Core,
|
||||||
options: InitOptions,
|
//options: InitOptions,
|
||||||
) !void {
|
) !void {
|
||||||
_ = nul;
|
_ = nul;
|
||||||
_ = options;
|
//_ = options;
|
||||||
_ = core;
|
_ = core;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ const mach = @import("../main.zig");
|
||||||
const Core = @import("../Core.zig");
|
const Core = @import("../Core.zig");
|
||||||
|
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const InitOptions = Core.InitOptions;
|
|
||||||
const Event = Core.Event;
|
const Event = Core.Event;
|
||||||
const KeyEvent = Core.KeyEvent;
|
const KeyEvent = Core.KeyEvent;
|
||||||
const MouseButtonEvent = Core.MouseButtonEvent;
|
const MouseButtonEvent = Core.MouseButtonEvent;
|
||||||
|
|
@ -21,42 +20,147 @@ const KeyMods = Core.KeyMods;
|
||||||
const EventQueue = std.fifo.LinearFifo(Event, .Dynamic);
|
const EventQueue = std.fifo.LinearFifo(Event, .Dynamic);
|
||||||
const Win32 = @This();
|
const Win32 = @This();
|
||||||
|
|
||||||
|
pub const Native = struct {
|
||||||
|
window: w.HWND = undefined,
|
||||||
|
surrogate: u16 = 0,
|
||||||
|
dinput: *w.IDirectInput8W = undefined,
|
||||||
|
saved_window_rect: w.RECT = undefined,
|
||||||
|
surface_descriptor_from_hwnd: gpu.Surface.DescriptorFromWindowsHWND = undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Context = struct {
|
||||||
|
core: *Core,
|
||||||
|
window_id: mach.ObjectID,
|
||||||
|
};
|
||||||
|
|
||||||
// --------------------------
|
// --------------------------
|
||||||
// Module state
|
// Module state
|
||||||
// --------------------------
|
// --------------------------
|
||||||
allocator: std.mem.Allocator,
|
// allocator: std.mem.Allocator,
|
||||||
core: *Core,
|
// core: *Core,
|
||||||
|
|
||||||
// Core platform interface
|
// Core platform interface
|
||||||
surface_descriptor: gpu.Surface.Descriptor,
|
// surface_descriptor: gpu.Surface.Descriptor,
|
||||||
display_mode: DisplayMode,
|
// display_mode: DisplayMode,
|
||||||
vsync_mode: VSyncMode,
|
// vsync_mode: VSyncMode,
|
||||||
cursor_mode: CursorMode,
|
// cursor_mode: CursorMode,
|
||||||
cursor_shape: CursorShape,
|
// cursor_shape: CursorShape,
|
||||||
border: bool,
|
// border: bool,
|
||||||
headless: bool,
|
// headless: bool,
|
||||||
size: Size,
|
// size: Size,
|
||||||
|
|
||||||
// Internals
|
// // Internals
|
||||||
window: w.HWND,
|
// window: w.HWND,
|
||||||
refresh_rate: u32,
|
// refresh_rate: u32,
|
||||||
surrogate: u16 = 0,
|
// surrogate: u16 = 0,
|
||||||
dinput: *w.IDirectInput8W,
|
// dinput: *w.IDirectInput8W,
|
||||||
saved_window_rect: w.RECT,
|
// saved_window_rect: w.RECT,
|
||||||
surface_descriptor_from_hwnd: gpu.Surface.DescriptorFromWindowsHWND,
|
// surface_descriptor_from_hwnd: gpu.Surface.DescriptorFromWindowsHWND,
|
||||||
|
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
// Platform interface
|
// Platform interface
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
pub fn init(
|
// pub fn init(
|
||||||
self: *Win32,
|
// self: *Win32,
|
||||||
|
// core: *Core,
|
||||||
|
// //options: InitOptions,
|
||||||
|
// ) !void {
|
||||||
|
// // self.allocator = options.allocator;
|
||||||
|
// // self.core = core;
|
||||||
|
// // self.size = options.size;
|
||||||
|
// // self.saved_window_rect = .{ .top = 0, .left = 0, .right = 0, .bottom = 0 };
|
||||||
|
|
||||||
|
// var native: Native = .{};
|
||||||
|
|
||||||
|
// const hInstance = w.GetModuleHandleW(null);
|
||||||
|
// const class_name = w.L("mach");
|
||||||
|
// const class = std.mem.zeroInit(w.WNDCLASSW, .{
|
||||||
|
// .style = w.CS_OWNDC,
|
||||||
|
// .lpfnWndProc = wndProc,
|
||||||
|
// .hInstance = hInstance,
|
||||||
|
// .hIcon = w.LoadIconW(null, @as([*:0]align(1) const u16, @ptrFromInt(@as(u32, w.IDI_APPLICATION)))),
|
||||||
|
// .hCursor = w.LoadCursorW(null, @as([*:0]align(1) const u16, @ptrFromInt(@as(u32, w.IDC_ARROW)))),
|
||||||
|
// .lpszClassName = class_name,
|
||||||
|
// });
|
||||||
|
// if (w.RegisterClassW(&class) == 0) return error.Unexpected;
|
||||||
|
|
||||||
|
// const title = try std.unicode.utf8ToUtf16LeAllocZ(self.allocator, options.title);
|
||||||
|
// defer self.allocator.free(title);
|
||||||
|
|
||||||
|
// var request_window_width: i32 = @bitCast(self.size.width);
|
||||||
|
// var request_window_height: i32 = @bitCast(self.size.height);
|
||||||
|
|
||||||
|
// const window_ex_style: w.WINDOW_EX_STYLE = .{ .APPWINDOW = 1 };
|
||||||
|
// const window_style: w.WINDOW_STYLE = if (options.border) w.WS_OVERLAPPEDWINDOW else w.WS_POPUPWINDOW; // w.WINDOW_STYLE{.POPUP = 1};
|
||||||
|
// // TODO (win32): should border == false mean borderless display_mode?
|
||||||
|
|
||||||
|
// var rect: w.RECT = .{ .left = 0, .top = 0, .right = request_window_width, .bottom = request_window_height };
|
||||||
|
|
||||||
|
// if (w.TRUE == w.AdjustWindowRectEx(&rect, window_style, w.FALSE, window_ex_style)) {
|
||||||
|
// request_window_width = rect.right - rect.left;
|
||||||
|
// request_window_height = rect.bottom - rect.top;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const window = w.CreateWindowExW(
|
||||||
|
// window_ex_style,
|
||||||
|
// class_name,
|
||||||
|
// title,
|
||||||
|
// window_style,
|
||||||
|
// w.CW_USEDEFAULT,
|
||||||
|
// w.CW_USEDEFAULT,
|
||||||
|
// request_window_width,
|
||||||
|
// request_window_height,
|
||||||
|
// null,
|
||||||
|
// null,
|
||||||
|
// hInstance,
|
||||||
|
// null,
|
||||||
|
// ) orelse return error.Unexpected;
|
||||||
|
|
||||||
|
// native.window = window;
|
||||||
|
|
||||||
|
// var dinput: ?*w.IDirectInput8W = undefined;
|
||||||
|
// const ptr: ?*?*anyopaque = @ptrCast(&dinput);
|
||||||
|
// if (w.DirectInput8Create(hInstance, w.DIRECTINPUT_VERSION, w.IID_IDirectInput8W, ptr, null) != w.DI_OK) {
|
||||||
|
// return error.Unexpected;
|
||||||
|
// }
|
||||||
|
// native.dinput = dinput.?;
|
||||||
|
|
||||||
|
// native.surface_descriptor_from_hwnd = .{
|
||||||
|
// .hinstance = std.os.windows.kernel32.GetModuleHandleW(null).?,
|
||||||
|
// .hwnd = window,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// core_window.surface_descriptor = .{ .next_in_chain = .{
|
||||||
|
// .from_windows_hwnd = &self.surface_descriptor_from_hwnd,
|
||||||
|
// } };
|
||||||
|
// self.border = options.border;
|
||||||
|
// self.headless = options.headless;
|
||||||
|
// self.refresh_rate = 60; // TODO (win32) get monitor refresh rate
|
||||||
|
// self.vsync_mode = .triple;
|
||||||
|
|
||||||
|
// _ = w.SetWindowLongPtrW(window, w.GWLP_USERDATA, @bitCast(@intFromPtr(self)));
|
||||||
|
// if (!options.headless) {
|
||||||
|
// setDisplayMode(self, options.display_mode);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// self.size = getClientRect(self);
|
||||||
|
// _ = w.GetWindowRect(self.window, &self.saved_window_rect);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn deinit(self: *Win32) void {
|
||||||
|
// _ = self.dinput.IUnknown_Release();
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn tick(core: *Core) !void {
|
||||||
|
_ = core; // autofix
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initWindow(
|
||||||
core: *Core,
|
core: *Core,
|
||||||
options: InitOptions,
|
window_id: mach.ObjectID,
|
||||||
) !void {
|
) !void {
|
||||||
self.allocator = options.allocator;
|
const core_window = core.windows.getValue(window_id);
|
||||||
self.core = core;
|
|
||||||
self.size = options.size;
|
|
||||||
self.saved_window_rect = .{ .top = 0, .left = 0, .right = 0, .bottom = 0 };
|
|
||||||
|
|
||||||
const hInstance = w.GetModuleHandleW(null);
|
const hInstance = w.GetModuleHandleW(null);
|
||||||
const class_name = w.L("mach");
|
const class_name = w.L("mach");
|
||||||
|
|
@ -70,15 +174,14 @@ pub fn init(
|
||||||
});
|
});
|
||||||
if (w.RegisterClassW(&class) == 0) return error.Unexpected;
|
if (w.RegisterClassW(&class) == 0) return error.Unexpected;
|
||||||
|
|
||||||
const title = try std.unicode.utf8ToUtf16LeAllocZ(self.allocator, options.title);
|
const title = try std.unicode.utf8ToUtf16LeAllocZ(core.allocator, core_window.title);
|
||||||
defer self.allocator.free(title);
|
defer core.allocator.free(title);
|
||||||
|
|
||||||
var request_window_width: i32 = @bitCast(self.size.width);
|
var request_window_width: i32 = @bitCast(core_window.width);
|
||||||
var request_window_height: i32 = @bitCast(self.size.height);
|
var request_window_height: i32 = @bitCast(core_window.height);
|
||||||
|
|
||||||
const window_ex_style: w.WINDOW_EX_STYLE = .{ .APPWINDOW = 1 };
|
const window_ex_style: w.WINDOW_EX_STYLE = .{ .APPWINDOW = 1 };
|
||||||
const window_style: w.WINDOW_STYLE = if (options.border) w.WS_OVERLAPPEDWINDOW else w.WS_POPUPWINDOW; // w.WINDOW_STYLE{.POPUP = 1};
|
const window_style: w.WINDOW_STYLE = if (core_window.border) w.WS_OVERLAPPEDWINDOW else w.WS_POPUPWINDOW; // w.WINDOW_STYLE{.POPUP = 1};
|
||||||
// TODO (win32): should border == false mean borderless display_mode?
|
|
||||||
|
|
||||||
var rect: w.RECT = .{ .left = 0, .top = 0, .right = request_window_width, .bottom = request_window_height };
|
var rect: w.RECT = .{ .left = 0, .top = 0, .right = request_window_width, .bottom = request_window_height };
|
||||||
|
|
||||||
|
|
@ -87,7 +190,7 @@ pub fn init(
|
||||||
request_window_height = rect.bottom - rect.top;
|
request_window_height = rect.bottom - rect.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
const window = w.CreateWindowExW(
|
const native_window = w.CreateWindowExW(
|
||||||
window_ex_style,
|
window_ex_style,
|
||||||
class_name,
|
class_name,
|
||||||
title,
|
title,
|
||||||
|
|
@ -102,49 +205,43 @@ pub fn init(
|
||||||
null,
|
null,
|
||||||
) orelse return error.Unexpected;
|
) orelse return error.Unexpected;
|
||||||
|
|
||||||
self.window = window;
|
var native: Native = .{};
|
||||||
|
|
||||||
var dinput: ?*w.IDirectInput8W = undefined;
|
var dinput: ?*w.IDirectInput8W = undefined;
|
||||||
const ptr: ?*?*anyopaque = @ptrCast(&dinput);
|
const ptr: ?*?*anyopaque = @ptrCast(&dinput);
|
||||||
if (w.DirectInput8Create(hInstance, w.DIRECTINPUT_VERSION, w.IID_IDirectInput8W, ptr, null) != w.DI_OK) {
|
if (w.DirectInput8Create(hInstance, w.DIRECTINPUT_VERSION, w.IID_IDirectInput8W, ptr, null) != w.DI_OK) {
|
||||||
return error.Unexpected;
|
return error.Unexpected;
|
||||||
}
|
}
|
||||||
self.dinput = dinput.?;
|
native.dinput = dinput.?;
|
||||||
|
|
||||||
self.surface_descriptor_from_hwnd = .{
|
native.surface_descriptor_from_hwnd = .{
|
||||||
.hinstance = std.os.windows.kernel32.GetModuleHandleW(null).?,
|
.hinstance = std.os.windows.kernel32.GetModuleHandleW(null).?,
|
||||||
.hwnd = window,
|
.hwnd = native_window,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.surface_descriptor = .{ .next_in_chain = .{
|
core_window.surface_descriptor = .{ .next_in_chain = .{
|
||||||
.from_windows_hwnd = &self.surface_descriptor_from_hwnd,
|
.from_windows_hwnd = &native.surface_descriptor_from_hwnd,
|
||||||
} };
|
} };
|
||||||
self.border = options.border;
|
|
||||||
self.headless = options.headless;
|
|
||||||
self.refresh_rate = 60; // TODO (win32) get monitor refresh rate
|
|
||||||
self.vsync_mode = .triple;
|
|
||||||
|
|
||||||
_ = w.SetWindowLongPtrW(window, w.GWLP_USERDATA, @bitCast(@intFromPtr(self)));
|
const context: Context = .{ .core = core, .window_id = window_id };
|
||||||
if (!options.headless) {
|
|
||||||
setDisplayMode(self, options.display_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.size = getClientRect(self);
|
_ = w.SetWindowLongPtrW(native_window, w.GWLP_USERDATA, @bitCast(@intFromPtr(&context)));
|
||||||
_ = w.GetWindowRect(self.window, &self.saved_window_rect);
|
|
||||||
|
const size = getClientRect(core, window_id);
|
||||||
|
core_window.width = size.width;
|
||||||
|
core_window.height = size.height;
|
||||||
|
|
||||||
|
_ = w.GetWindowRect(native.window, &native.saved_window_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Win32) void {
|
// pub fn update(self: *Win32) !void {
|
||||||
_ = self.dinput.IUnknown_Release();
|
// _ = self;
|
||||||
}
|
// var msg: w.MSG = undefined;
|
||||||
|
// while (w.PeekMessageW(&msg, null, 0, 0, w.PM_REMOVE) != 0) {
|
||||||
pub fn update(self: *Win32) !void {
|
// _ = w.TranslateMessage(&msg);
|
||||||
_ = self;
|
// _ = w.DispatchMessageW(&msg);
|
||||||
var msg: w.MSG = undefined;
|
// }
|
||||||
while (w.PeekMessageW(&msg, null, 0, 0, w.PM_REMOVE) != 0) {
|
// }
|
||||||
_ = w.TranslateMessage(&msg);
|
|
||||||
_ = w.DispatchMessageW(&msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setTitle(self: *Win32, title: [:0]const u8) void {
|
pub fn setTitle(self: *Win32, title: [:0]const u8) void {
|
||||||
const wtitle = std.unicode.utf8ToUtf16LeAllocZ(self.allocator, title) catch {
|
const wtitle = std.unicode.utf8ToUtf16LeAllocZ(self.allocator, title) catch {
|
||||||
|
|
@ -260,21 +357,30 @@ pub fn nativeWindowWin32(self: *Win32) w.HWND {
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Internal functions
|
// Internal functions
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
fn getClientRect(self: *Win32) Size {
|
fn getClientRect(core: *Core, window_id: mach.ObjectID) Size {
|
||||||
|
const window = core.windows.getValue(window_id);
|
||||||
|
|
||||||
|
if (window.native) |native| {
|
||||||
var rect: w.RECT = undefined;
|
var rect: w.RECT = undefined;
|
||||||
_ = w.GetClientRect(self.window, &rect);
|
_ = w.GetClientRect(native.window, &rect);
|
||||||
|
|
||||||
const width: u32 = @intCast(rect.right - rect.left);
|
const width: u32 = @intCast(rect.right - rect.left);
|
||||||
const height: u32 = @intCast(rect.bottom - rect.top);
|
const height: u32 = @intCast(rect.bottom - rect.top);
|
||||||
|
|
||||||
return .{ .width = width, .height = height };
|
return .{ .width = width, .height = height };
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .width = 0, .height = 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restoreWindowPosition(self: *Win32) void {
|
fn restoreWindowPosition(core: *Core, window_id: mach.ObjectID) void {
|
||||||
if (self.saved_window_rect.right - self.saved_window_rect.left == 0) {
|
const window = core.windows.getValue(window_id);
|
||||||
_ = w.ShowWindow(self.window, w.SW_RESTORE);
|
if (window.native) |native| {
|
||||||
|
if (native.saved_window_rect.right - native.saved_window_rect.left == 0) {
|
||||||
|
_ = w.ShowWindow(native.window, w.SW_RESTORE);
|
||||||
} else {
|
} else {
|
||||||
_ = w.SetWindowPos(self.window, null, self.saved_window_rect.left, self.saved_window_rect.top, self.saved_window_rect.right - self.saved_window_rect.left, self.saved_window_rect.bottom - self.saved_window_rect.top, w.SWP_SHOWWINDOW);
|
_ = w.SetWindowPos(native.window, null, native.saved_window_rect.left, native.saved_window_rect.top, native.saved_window_rect.right - native.saved_window_rect.left, native.saved_window_rect.bottom - native.saved_window_rect.top, w.SWP_SHOWWINDOW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,28 +397,38 @@ fn getKeyboardModifiers() mach.Core.KeyMods {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w.WINAPI) w.LRESULT {
|
fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w.WINAPI) w.LRESULT {
|
||||||
const self = blk: {
|
const context = blk: {
|
||||||
const userdata: usize = @bitCast(w.GetWindowLongPtrW(wnd, w.GWLP_USERDATA));
|
const userdata: usize = @bitCast(w.GetWindowLongPtrW(wnd, w.GWLP_USERDATA));
|
||||||
const ptr: ?*Win32 = @ptrFromInt(userdata);
|
const ptr: ?*Context = @ptrFromInt(userdata);
|
||||||
break :blk ptr orelse return w.DefWindowProcW(wnd, msg, wParam, lParam);
|
break :blk ptr orelse return w.DefWindowProcW(wnd, msg, wParam, lParam);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const core = context.core;
|
||||||
|
const window_id = context.window_id;
|
||||||
|
|
||||||
|
const window = core.windows.getValue(window_id);
|
||||||
|
defer core.windows.setValueRaw(window_id, window);
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
w.WM_CLOSE => {
|
w.WM_CLOSE => {
|
||||||
self.core.pushEvent(.close);
|
core.pushEvent(.close);
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_SIZE => {
|
w.WM_SIZE => {
|
||||||
const width: u32 = @as(u32, @intCast(lParam & 0xFFFF));
|
const width: u32 = @as(u32, @intCast(lParam & 0xFFFF));
|
||||||
const height: u32 = @as(u32, @intCast((lParam >> 16) & 0xFFFF));
|
const height: u32 = @as(u32, @intCast((lParam >> 16) & 0xFFFF));
|
||||||
self.size = .{ .width = width, .height = height };
|
|
||||||
|
window.width = width;
|
||||||
|
window.height = height;
|
||||||
|
|
||||||
|
core.pushEvent(.{ .window_resize = .{ .window_id = window_id, .size = .{ .width = width, .height = height } } });
|
||||||
|
|
||||||
// TODO (win32): only send resize event when sizing is done.
|
// TODO (win32): only send resize event when sizing is done.
|
||||||
// the main mach loops does not run while resizing.
|
// the main mach loops does not run while resizing.
|
||||||
// Which means if events are pushed here they will
|
// Which means if events are pushed here they will
|
||||||
// queue up until resize is done.
|
// queue up until resize is done.
|
||||||
|
|
||||||
self.core.swap_chain_update.set();
|
window.swap_chain_update.set();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
|
|
@ -321,7 +437,7 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
if (vkey == w.VK_PROCESSKEY) return 0;
|
if (vkey == w.VK_PROCESSKEY) return 0;
|
||||||
|
|
||||||
if (msg == w.WM_SYSKEYDOWN and vkey == w.VK_F4) {
|
if (msg == w.WM_SYSKEYDOWN and vkey == w.VK_F4) {
|
||||||
self.core.pushEvent(.close);
|
core.pushEvent(.close);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,7 +448,8 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
// right alt sends left control first
|
// right alt sends left control first
|
||||||
var next: w.MSG = undefined;
|
var next: w.MSG = undefined;
|
||||||
const time = w.GetMessageTime();
|
const time = w.GetMessageTime();
|
||||||
if (w.PeekMessageW(&next, self.window, 0, 0, w.PM_NOREMOVE) != 0 and
|
if (window.native) |native| {
|
||||||
|
if (w.PeekMessageW(&next, native.window, 0, 0, w.PM_NOREMOVE) != 0 and
|
||||||
next.time == time and
|
next.time == time and
|
||||||
(next.message == msg or (msg == w.WM_SYSKEYDOWN and next.message == w.WM_KEYUP)) and
|
(next.message == msg or (msg == w.WM_SYSKEYDOWN and next.message == w.WM_KEYUP)) and
|
||||||
((next.lParam >> 16) & 0x1FF) == 0x138)
|
((next.lParam >> 16) & 0x1FF) == 0x138)
|
||||||
|
|
@ -340,26 +457,30 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const mods = getKeyboardModifiers();
|
const mods = getKeyboardModifiers();
|
||||||
const key = keyFromScancode(scancode);
|
const key = keyFromScancode(scancode);
|
||||||
if (msg == w.WM_KEYDOWN or msg == w.WM_SYSKEYDOWN) {
|
if (msg == w.WM_KEYDOWN or msg == w.WM_SYSKEYDOWN) {
|
||||||
if (flags & w.KF_REPEAT == 0)
|
if (flags & w.KF_REPEAT == 0)
|
||||||
self.core.pushEvent(.{
|
core.pushEvent(.{
|
||||||
.key_press = .{
|
.key_press = .{
|
||||||
|
.window_id = window_id,
|
||||||
.key = key,
|
.key = key,
|
||||||
.mods = mods,
|
.mods = mods,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
else
|
else
|
||||||
self.core.pushEvent(.{
|
core.pushEvent(.{
|
||||||
.key_repeat = .{
|
.key_repeat = .{
|
||||||
|
.window_id = window_id,
|
||||||
.key = key,
|
.key = key,
|
||||||
.mods = mods,
|
.mods = mods,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else self.core.pushEvent(.{
|
} else core.pushEvent(.{
|
||||||
.key_release = .{
|
.key_release = .{
|
||||||
|
.window_id = window_id,
|
||||||
.key = key,
|
.key = key,
|
||||||
.mods = mods,
|
.mods = mods,
|
||||||
},
|
},
|
||||||
|
|
@ -368,24 +489,29 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_CHAR => {
|
w.WM_CHAR => {
|
||||||
|
if (window.native) |native| {
|
||||||
const char: u16 = @truncate(wParam);
|
const char: u16 = @truncate(wParam);
|
||||||
var chars: []const u16 = undefined;
|
var chars: []const u16 = undefined;
|
||||||
if (self.surrogate != 0) {
|
if (native.surrogate != 0) {
|
||||||
chars = &.{ self.surrogate, char };
|
chars = &.{ native.surrogate, char };
|
||||||
self.surrogate = 0;
|
native.surrogate = 0;
|
||||||
} else if (std.unicode.utf16IsHighSurrogate(char)) {
|
} else if (std.unicode.utf16IsHighSurrogate(char)) {
|
||||||
self.surrogate = char;
|
native.surrogate = char;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
chars = &.{char};
|
chars = &.{char};
|
||||||
}
|
}
|
||||||
var iter = std.unicode.Utf16LeIterator.init(chars);
|
var iter = std.unicode.Utf16LeIterator.init(chars);
|
||||||
if (iter.nextCodepoint()) |codepoint| {
|
if (iter.nextCodepoint()) |codepoint| {
|
||||||
self.core.pushEvent(.{ .char_input = .{ .codepoint = codepoint.? } });
|
core.pushEvent(.{ .char_input = .{
|
||||||
|
.window_id = window_id,
|
||||||
|
.codepoint = codepoint.?,
|
||||||
|
} });
|
||||||
} else |err| {
|
} else |err| {
|
||||||
err catch {};
|
err catch {};
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
w.WM_LBUTTONDOWN,
|
w.WM_LBUTTONDOWN,
|
||||||
w.WM_LBUTTONUP,
|
w.WM_LBUTTONUP,
|
||||||
|
|
@ -412,15 +538,17 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
w.WM_MBUTTONDOWN,
|
w.WM_MBUTTONDOWN,
|
||||||
w.WM_RBUTTONDOWN,
|
w.WM_RBUTTONDOWN,
|
||||||
w.WM_XBUTTONDOWN,
|
w.WM_XBUTTONDOWN,
|
||||||
=> self.core.pushEvent(.{
|
=> core.pushEvent(.{
|
||||||
.mouse_press = .{
|
.mouse_press = .{
|
||||||
|
.window_id = window_id,
|
||||||
.button = button,
|
.button = button,
|
||||||
.mods = mods,
|
.mods = mods,
|
||||||
.pos = .{ .x = x, .y = y },
|
.pos = .{ .x = x, .y = y },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
else => self.core.pushEvent(.{
|
else => core.pushEvent(.{
|
||||||
.mouse_release = .{
|
.mouse_release = .{
|
||||||
|
.window_id = window_id,
|
||||||
.button = button,
|
.button = button,
|
||||||
.mods = mods,
|
.mods = mods,
|
||||||
.pos = .{ .x = x, .y = y },
|
.pos = .{ .x = x, .y = y },
|
||||||
|
|
@ -433,8 +561,9 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
w.WM_MOUSEMOVE => {
|
w.WM_MOUSEMOVE => {
|
||||||
const x: f64 = @floatFromInt(@as(i16, @truncate(lParam & 0xFFFF)));
|
const x: f64 = @floatFromInt(@as(i16, @truncate(lParam & 0xFFFF)));
|
||||||
const y: f64 = @floatFromInt(@as(i16, @truncate((lParam >> 16) & 0xFFFF)));
|
const y: f64 = @floatFromInt(@as(i16, @truncate((lParam >> 16) & 0xFFFF)));
|
||||||
self.core.pushEvent(.{
|
core.pushEvent(.{
|
||||||
.mouse_motion = .{
|
.mouse_motion = .{
|
||||||
|
.window_id = window_id,
|
||||||
.pos = .{
|
.pos = .{
|
||||||
.x = x,
|
.x = x,
|
||||||
.y = y,
|
.y = y,
|
||||||
|
|
@ -448,8 +577,9 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
const wheel_high_word: u16 = @truncate((wParam >> 16) & 0xffff);
|
const wheel_high_word: u16 = @truncate((wParam >> 16) & 0xffff);
|
||||||
const delta_y: f32 = @as(f32, @floatFromInt(@as(i16, @bitCast(wheel_high_word)))) / WHEEL_DELTA;
|
const delta_y: f32 = @as(f32, @floatFromInt(@as(i16, @bitCast(wheel_high_word)))) / WHEEL_DELTA;
|
||||||
|
|
||||||
self.core.pushEvent(.{
|
core.pushEvent(.{
|
||||||
.mouse_scroll = .{
|
.mouse_scroll = .{
|
||||||
|
.window_id = window_id,
|
||||||
.xoffset = 0,
|
.xoffset = 0,
|
||||||
.yoffset = delta_y,
|
.yoffset = delta_y,
|
||||||
},
|
},
|
||||||
|
|
@ -457,11 +587,11 @@ fn wndProc(wnd: w.HWND, msg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_SETFOCUS => {
|
w.WM_SETFOCUS => {
|
||||||
self.core.pushEvent(.{ .focus_gained = {} });
|
core.pushEvent(.{ .focus_gained = .{ .window_id = window_id } });
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
w.WM_KILLFOCUS => {
|
w.WM_KILLFOCUS => {
|
||||||
self.core.pushEvent(.{ .focus_lost = {} });
|
core.pushEvent(.{ .focus_lost = .{ .window_id = window_id } });
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
else => return w.DefWindowProcW(wnd, msg, wParam, lParam),
|
else => return w.DefWindowProcW(wnd, msg, wParam, lParam),
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ pub fn Objects(options: ObjectsOptions, comptime T: type) type {
|
||||||
|
|
||||||
pub const Slice = struct {
|
pub const Slice = struct {
|
||||||
index: Index,
|
index: Index,
|
||||||
objs: *Objects(T),
|
objs: *Objects(options, T),
|
||||||
|
|
||||||
/// Same as Objects(T).set but doesn't employ safety checks
|
/// Same as Objects(T).set but doesn't employ safety checks
|
||||||
pub fn set(objs: *@This(), id: ObjectID, value: T) void {
|
pub fn set(objs: *@This(), id: ObjectID, value: T) void {
|
||||||
|
|
@ -127,6 +127,7 @@ pub fn Objects(options: ObjectsOptions, comptime T: type) type {
|
||||||
defer iter.index += 1;
|
defer iter.index += 1;
|
||||||
|
|
||||||
if (!dead.isSet(iter.index)) return @bitCast(PackedID{
|
if (!dead.isSet(iter.index)) return @bitCast(PackedID{
|
||||||
|
.type_id = iter.objs.internal.type_id,
|
||||||
.generation = generation.items[iter.index],
|
.generation = generation.items[iter.index],
|
||||||
.index = iter.index,
|
.index = iter.index,
|
||||||
});
|
});
|
||||||
|
|
@ -208,10 +209,10 @@ pub fn Objects(options: ObjectsOptions, comptime T: type) type {
|
||||||
///
|
///
|
||||||
/// Unlike setAll(), this method does not respect any mach.Objects tracking
|
/// Unlike setAll(), this method does not respect any mach.Objects tracking
|
||||||
/// options, so changes made to an object through this method will not be tracked.
|
/// options, so changes made to an object through this method will not be tracked.
|
||||||
pub fn setAllRaw(objs: *@This(), id: ObjectID, value: T) void {
|
pub fn setValueRaw(objs: *@This(), id: ObjectID, value: T) void {
|
||||||
const data = &objs.internal.data;
|
const data = &objs.internal.data;
|
||||||
|
|
||||||
const unpacked = objs.validateAndUnpack(id, "setAllRaw");
|
const unpacked = objs.validateAndUnpack(id, "setValueRaw");
|
||||||
data.set(unpacked.index, value);
|
data.set(unpacked.index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -219,10 +220,10 @@ pub fn Objects(options: ObjectsOptions, comptime T: type) type {
|
||||||
///
|
///
|
||||||
/// Unlike setAllRaw, this method respects mach.Objects tracking
|
/// Unlike setAllRaw, this method respects mach.Objects tracking
|
||||||
/// and changes made to an object through this method will be tracked.
|
/// and changes made to an object through this method will be tracked.
|
||||||
pub fn setAll(objs: *@This(), id: ObjectID, value: T) void {
|
pub fn setValue(objs: *@This(), id: ObjectID, value: T) void {
|
||||||
const data = &objs.internal.data;
|
const data = &objs.internal.data;
|
||||||
|
|
||||||
const unpacked = objs.validateAndUnpack(id, "setAll");
|
const unpacked = objs.validateAndUnpack(id, "setValue");
|
||||||
data.set(unpacked.index, value);
|
data.set(unpacked.index, value);
|
||||||
|
|
||||||
if (objs.internal.updated) |*updated_fields| {
|
if (objs.internal.updated) |*updated_fields| {
|
||||||
|
|
@ -266,7 +267,7 @@ pub fn Objects(options: ObjectsOptions, comptime T: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a single field.
|
/// Get a single field.
|
||||||
pub fn get(objs: *@This(), id: ObjectID, comptime field_name: std.meta.FieldEnum(T)) ?std.meta.FieldType(T, field_name) {
|
pub fn get(objs: *@This(), id: ObjectID, comptime field_name: std.meta.FieldEnum(T)) std.meta.FieldType(T, field_name) {
|
||||||
const data = &objs.internal.data;
|
const data = &objs.internal.data;
|
||||||
|
|
||||||
const unpacked = objs.validateAndUnpack(id, "get");
|
const unpacked = objs.validateAndUnpack(id, "get");
|
||||||
|
|
@ -275,10 +276,10 @@ pub fn Objects(options: ObjectsOptions, comptime T: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all fields.
|
/// Get all fields.
|
||||||
pub fn getAll(objs: *@This(), id: ObjectID) ?T {
|
pub fn getValue(objs: *@This(), id: ObjectID) T {
|
||||||
const data = &objs.internal.data;
|
const data = &objs.internal.data;
|
||||||
|
|
||||||
const unpacked = objs.validateAndUnpack(id, "getAll");
|
const unpacked = objs.validateAndUnpack(id, "getValue");
|
||||||
return data.get(unpacked.index);
|
return data.get(unpacked.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue