diff --git a/examples/core-transparent-window/App.zig b/examples/core-transparent-window/App.zig index 0851115078..0427637585 100644 --- a/examples/core-transparent-window/App.zig +++ b/examples/core-transparent-window/App.zig @@ -16,6 +16,9 @@ pub const main = mach.schedule(.{ window: mach.ObjectID, title_timer: mach.time.Timer, +color_timer: mach.time.Timer, +color_time: f32 = 0.0, +flip: bool = false, pipeline: *gpu.RenderPipeline, pub fn init( @@ -34,6 +37,7 @@ pub fn init( app.* = .{ .window = window, .title_timer = try mach.time.Timer.start(), + .color_timer = try mach.time.Timer.start(), .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 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. 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 // TODO(Core) @@ -130,7 +124,7 @@ pub fn tick(app: *App, core: *mach.Core) void { defer encoder.release(); // 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{.{ .view = back_buffer_view, .clear_value = sky_blue_background, @@ -155,28 +149,32 @@ pub fn tick(app: *App, core: *mach.Core) void { defer command.release(); window.queue.submit(&[_]*gpu.CommandBuffer{command}); - // update the window title every second - // if (app.title_timer.read() >= 1.0) { - // app.title_timer.reset(); - // // TODO(object): window-title - // // try updateWindowTitle(core); - // } + if (app.title_timer.read() >= 1.0) { + app.title_timer.reset(); + // TODO(object): window-title + + // 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 { 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); -// } diff --git a/src/Core.zig b/src/Core.zig index 0826f7e004..28a0c19d26 100644 --- a/src/Core.zig +++ b/src/Core.zig @@ -74,6 +74,9 @@ windows: mach.Objects( /// Target frames per second refresh_rate: u32 = 0, + /// Color of the window background/titlebar + color: WindowColor = .system, + // GPU // When `native` is not null, the rest of the fields have been // 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) { key_press: KeyEvent, key_repeat: KeyEvent, @@ -957,39 +974,6 @@ const RequestAdapterResponse = struct { 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 { if (!@hasDecl(T, decl_name)) @compileError(@typeName(T) ++ " missing declaration: " ++ decl_name); } diff --git a/src/core/Darwin.zig b/src/core/Darwin.zig index c991834210..ef58e19abc 100644 --- a/src/core/Darwin.zig +++ b/src/core/Darwin.zig @@ -70,6 +70,34 @@ pub fn tick(core: *Core) !void { if (core_window.native) |native| { 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)) { const string = objc.foundation.String.allocInit(); 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.WindowStyleMaskMiniaturizable 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( rect, @@ -163,9 +192,28 @@ fn initWindow( native_window.setIsVisible(true); native_window.makeKeyAndOrderFront(null); - const color = objc.app_kit.Color.colorWithRed_green_blue_alpha(0.5, 0.5, 0.5, 0.5); - native_window.setBackgroundColor(color); - native_window.setTitlebarAppearsTransparent(true); + 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); + }, + .system => {}, + } const string = objc.foundation.String.allocInit(); defer string.release();