example: core-transparent-window now animates the window color and transparency
This commit is contained in:
parent
4bbca0eb95
commit
6ef58d8c1f
3 changed files with 98 additions and 68 deletions
|
|
@ -16,6 +16,9 @@ pub const main = mach.schedule(.{
|
||||||
|
|
||||||
window: mach.ObjectID,
|
window: mach.ObjectID,
|
||||||
title_timer: mach.time.Timer,
|
title_timer: mach.time.Timer,
|
||||||
|
color_timer: mach.time.Timer,
|
||||||
|
color_time: f32 = 0.0,
|
||||||
|
flip: bool = false,
|
||||||
pipeline: *gpu.RenderPipeline,
|
pipeline: *gpu.RenderPipeline,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
|
|
@ -34,6 +37,7 @@ pub fn init(
|
||||||
app.* = .{
|
app.* = .{
|
||||||
.window = window,
|
.window = window,
|
||||||
.title_timer = try mach.time.Timer.start(),
|
.title_timer = try mach.time.Timer.start(),
|
||||||
|
.color_timer = try mach.time.Timer.start(),
|
||||||
.pipeline = undefined,
|
.pipeline = undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -48,16 +52,6 @@ fn setupPipeline(core: *mach.Core, app: *App, window_id: mach.ObjectID) !void {
|
||||||
|
|
||||||
// Blend state describes how rendered colors get blended
|
// Blend state describes how rendered colors get blended
|
||||||
var blend = gpu.BlendState{};
|
var blend = gpu.BlendState{};
|
||||||
blend.alpha = .{
|
|
||||||
.dst_factor = .one_minus_src_alpha,
|
|
||||||
.src_factor = .one,
|
|
||||||
.operation = .add,
|
|
||||||
};
|
|
||||||
blend.color = .{
|
|
||||||
.dst_factor = .one_minus_src_alpha,
|
|
||||||
.src_factor = .src_alpha,
|
|
||||||
.operation = .add,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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{
|
||||||
|
|
@ -116,7 +110,7 @@ pub fn tick(app: *App, core: *mach.Core) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const window = core.windows.getValue(app.window);
|
var window = core.windows.getValue(app.window);
|
||||||
|
|
||||||
// Grab the back buffer of the swapchain
|
// Grab the back buffer of the swapchain
|
||||||
// TODO(Core)
|
// TODO(Core)
|
||||||
|
|
@ -130,7 +124,7 @@ pub fn tick(app: *App, core: *mach.Core) void {
|
||||||
defer encoder.release();
|
defer encoder.release();
|
||||||
|
|
||||||
// Begin render pass
|
// Begin render pass
|
||||||
const sky_blue_background = gpu.Color{ .r = 0.776, .g = 0.988, .b = 1.0, .a = 0.0 };
|
const sky_blue_background = gpu.Color{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 0.0 };
|
||||||
const color_attachments = [_]gpu.RenderPassColorAttachment{.{
|
const color_attachments = [_]gpu.RenderPassColorAttachment{.{
|
||||||
.view = back_buffer_view,
|
.view = back_buffer_view,
|
||||||
.clear_value = sky_blue_background,
|
.clear_value = sky_blue_background,
|
||||||
|
|
@ -155,28 +149,32 @@ pub fn tick(app: *App, core: *mach.Core) void {
|
||||||
defer command.release();
|
defer command.release();
|
||||||
window.queue.submit(&[_]*gpu.CommandBuffer{command});
|
window.queue.submit(&[_]*gpu.CommandBuffer{command});
|
||||||
|
|
||||||
// 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);
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
if (app.color_time >= 4.0 or app.color_time <= 0.0) {
|
||||||
|
app.color_time = @trunc(app.color_time);
|
||||||
|
app.flip = !app.flip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!app.flip) {
|
||||||
|
app.color_time -= app.color_timer.lap();
|
||||||
|
} else {
|
||||||
|
app.color_time += app.color_timer.lap();
|
||||||
|
}
|
||||||
|
|
||||||
|
const red = mach.math.lerp(0.1, 0.6, mach.math.clamp(app.color_time, 0.0, 1.0));
|
||||||
|
const blue = mach.math.lerp(0.2, 0.6, mach.math.clamp(app.color_time - 1.0, 0.0, 1.0));
|
||||||
|
const green = mach.math.lerp(0.2, 0.6, mach.math.clamp(app.color_time - 2.0, 0.0, 1.0));
|
||||||
|
const alpha = mach.math.lerp(0.3, 1.0, app.color_time / 4.0);
|
||||||
|
|
||||||
|
core.windows.set(app.window, .color, .{ .transparent = .{ .color = .{ .r = red, .g = green, .b = blue, .a = alpha }, .titlebar = true } });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(app: *App) void {
|
pub fn deinit(app: *App) void {
|
||||||
app.pipeline.release();
|
app.pipeline.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(object): window-title
|
|
||||||
// fn updateWindowTitle(core: *mach.Core) !void {
|
|
||||||
// try core.printTitle(
|
|
||||||
// core.main_window,
|
|
||||||
// "core-custom-entrypoint [ {d}fps ] [ Input {d}hz ]",
|
|
||||||
// .{
|
|
||||||
// // TODO(Core)
|
|
||||||
// core.frameRate(),
|
|
||||||
// core.inputRate(),
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// core.schedule(.update);
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
50
src/Core.zig
50
src/Core.zig
|
|
@ -74,6 +74,9 @@ windows: mach.Objects(
|
||||||
/// Target frames per second
|
/// Target frames per second
|
||||||
refresh_rate: u32 = 0,
|
refresh_rate: u32 = 0,
|
||||||
|
|
||||||
|
/// Color of the window background/titlebar
|
||||||
|
color: WindowColor = .system,
|
||||||
|
|
||||||
// GPU
|
// GPU
|
||||||
// When `native` is not null, the rest of the fields have been
|
// When `native` is not null, the rest of the fields have been
|
||||||
// initialized.
|
// initialized.
|
||||||
|
|
@ -657,6 +660,20 @@ pub const InputState = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const WindowColor = union(enum) {
|
||||||
|
system: void, // Default window colors
|
||||||
|
transparent: struct {
|
||||||
|
color: gpu.Color,
|
||||||
|
// If true, and the OS supports it, the titlebar will also be set to color
|
||||||
|
titlebar: bool = false,
|
||||||
|
},
|
||||||
|
solid: struct {
|
||||||
|
color: gpu.Color,
|
||||||
|
// If titlebar is true, and the OS supports it, the titlebar will also be set to color
|
||||||
|
titlebar: bool = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
pub const Event = union(enum) {
|
pub const Event = union(enum) {
|
||||||
key_press: KeyEvent,
|
key_press: KeyEvent,
|
||||||
key_repeat: KeyEvent,
|
key_repeat: KeyEvent,
|
||||||
|
|
@ -957,39 +974,6 @@ const RequestAdapterResponse = struct {
|
||||||
message: ?[*:0]const u8,
|
message: ?[*:0]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Verifies that a platform implementation exposes the expected function declarations.
|
|
||||||
// comptime {
|
|
||||||
// // Core
|
|
||||||
// assertHasField(Platform, "surface_descriptor");
|
|
||||||
// assertHasField(Platform, "refresh_rate");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "init");
|
|
||||||
// assertHasDecl(Platform, "deinit");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "setTitle");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "setDisplayMode");
|
|
||||||
// assertHasField(Platform, "display_mode");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "setBorder");
|
|
||||||
// assertHasField(Platform, "border");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "setHeadless");
|
|
||||||
// assertHasField(Platform, "headless");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "setVSync");
|
|
||||||
// assertHasField(Platform, "vsync_mode");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "setSize");
|
|
||||||
// assertHasField(Platform, "size");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "setCursorMode");
|
|
||||||
// assertHasField(Platform, "cursor_mode");
|
|
||||||
|
|
||||||
// assertHasDecl(Platform, "setCursorShape");
|
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,34 @@ pub fn tick(core: *Core) !void {
|
||||||
if (core_window.native) |native| {
|
if (core_window.native) |native| {
|
||||||
const native_window: *objc.app_kit.Window = native.window;
|
const native_window: *objc.app_kit.Window = native.window;
|
||||||
|
|
||||||
|
if (core.windows.updated(window_id, .color)) {
|
||||||
|
switch (core_window.color) {
|
||||||
|
.transparent => |wc| {
|
||||||
|
const color = objc.app_kit.Color.colorWithRed_green_blue_alpha(
|
||||||
|
wc.color.r,
|
||||||
|
wc.color.g,
|
||||||
|
wc.color.b,
|
||||||
|
wc.color.a,
|
||||||
|
);
|
||||||
|
native_window.setBackgroundColor(color);
|
||||||
|
native_window.setTitlebarAppearsTransparent(true);
|
||||||
|
},
|
||||||
|
.solid => |wc| {
|
||||||
|
const color = objc.app_kit.Color.colorWithRed_green_blue_alpha(
|
||||||
|
wc.color.r,
|
||||||
|
wc.color.g,
|
||||||
|
wc.color.b,
|
||||||
|
wc.color.a,
|
||||||
|
);
|
||||||
|
native_window.setBackgroundColor(color);
|
||||||
|
native_window.setTitlebarAppearsTransparent(false);
|
||||||
|
},
|
||||||
|
.system => {
|
||||||
|
native_window.setTitlebarAppearsTransparent(false);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (core.windows.updated(window_id, .title)) {
|
if (core.windows.updated(window_id, .title)) {
|
||||||
const string = objc.foundation.String.allocInit();
|
const string = objc.foundation.String.allocInit();
|
||||||
defer string.release();
|
defer string.release();
|
||||||
|
|
@ -123,6 +151,7 @@ fn initWindow(
|
||||||
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskClosable else 0) |
|
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskClosable else 0) |
|
||||||
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskMiniaturizable else 0) |
|
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskMiniaturizable else 0) |
|
||||||
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskResizable else 0);
|
(if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskResizable else 0);
|
||||||
|
// (if (core_window.display_mode == .windowed) objc.app_kit.WindowStyleMaskFullSizeContentView else 0);
|
||||||
|
|
||||||
const native_window_opt: ?*objc.app_kit.Window = 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,
|
||||||
|
|
@ -163,9 +192,28 @@ fn initWindow(
|
||||||
native_window.setIsVisible(true);
|
native_window.setIsVisible(true);
|
||||||
native_window.makeKeyAndOrderFront(null);
|
native_window.makeKeyAndOrderFront(null);
|
||||||
|
|
||||||
const color = objc.app_kit.Color.colorWithRed_green_blue_alpha(0.5, 0.5, 0.5, 0.5);
|
switch (core_window.color) {
|
||||||
|
.transparent => |wc| {
|
||||||
|
const color = objc.app_kit.Color.colorWithRed_green_blue_alpha(
|
||||||
|
wc.color.r,
|
||||||
|
wc.color.g,
|
||||||
|
wc.color.b,
|
||||||
|
wc.color.a,
|
||||||
|
);
|
||||||
native_window.setBackgroundColor(color);
|
native_window.setBackgroundColor(color);
|
||||||
native_window.setTitlebarAppearsTransparent(true);
|
native_window.setTitlebarAppearsTransparent(true);
|
||||||
|
},
|
||||||
|
.solid => |wc| {
|
||||||
|
const color = objc.app_kit.Color.colorWithRed_green_blue_alpha(
|
||||||
|
wc.color.r,
|
||||||
|
wc.color.g,
|
||||||
|
wc.color.b,
|
||||||
|
wc.color.a,
|
||||||
|
);
|
||||||
|
native_window.setBackgroundColor(color);
|
||||||
|
},
|
||||||
|
.system => {},
|
||||||
|
}
|
||||||
|
|
||||||
const string = objc.foundation.String.allocInit();
|
const string = objc.foundation.String.allocInit();
|
||||||
defer string.release();
|
defer string.release();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue