Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 139 additions & 74 deletions src/backend/WebBackend.zig
Original file line number Diff line number Diff line change
Expand Up @@ -200,17 +200,50 @@ pub const wasm = if (!builtin.is_test) struct {
pub extern "dvui" fn wasm_canvas_height() f32;

pub extern "dvui" fn wasm_frame_buffer() u8;
pub extern "dvui" fn wasm_textureCreate(pixels: [*]const u8, width: u32, height: u32, interp: u8, wrap_u: u8, wrap_v: u8) u32;
pub extern "dvui" fn wasm_textureCreate(
pixels: [*]const u8,
width: u32,
height: u32,
interp: u8,
wrap_u: u8,
wrap_v: u8,
) u32;
pub extern "dvui" fn wasm_textureCreateTarget(width: u32, height: u32, interp: u8, wrap_u: u8, wrap_v: u8) u32;
pub extern "dvui" fn wasm_textureCreatePreciseTarget(width: u32, height: u32, interp: u8, wrap_u: u8, wrap_v: u8) u32;
pub extern "dvui" fn wasm_textureCreatePreciseTarget(
width: u32,
height: u32,
interp: u8,
wrap_u: u8,
wrap_v: u8,
) u32;
pub extern "dvui" fn wasm_textureBlend(texture: u32, mode: u8) u8;
pub extern "dvui" fn wasm_textureUpdate(texture: u32, pixels: [*]const u8) u8;
pub extern "dvui" fn wasm_textureUpdateSubRect(texture: u32, pixels: [*]const u8, x: u32, y: u32, w: u32, h: u32) u8;
pub extern "dvui" fn wasm_textureUpdateSubRect(
texture: u32,
pixels: [*]const u8,
x: u32,
y: u32,
w: u32,
h: u32,
) u8;
pub extern "dvui" fn wasm_textureClearTarget(u32) void;
pub extern "dvui" fn wasm_textureRead(texture: u32, pixels_out: [*]u8, width: u32, height: u32) void;
pub extern "dvui" fn wasm_renderTarget(u32) void;
pub extern "dvui" fn wasm_textureDestroy(u32) void;
pub extern "dvui" fn wasm_renderStream(index_ptr: [*]const u8, index_len: usize, vertex_ptr: [*]const u8, vertex_len: usize, sizeof_vertex: u8, offset_pos: u8, offset_col: u8, offset_uv: u8, cmd_ptr: [*]const u8, cmd_count: usize, uniform_ptr: [*]const u8, uniform_floats: usize) void;
pub extern "dvui" fn wasm_renderStream(
index_ptr: [*]const u8,
index_len: usize,
vertex_ptr: [*]const u8,
vertex_len: usize,
sizeof_vertex: u8,
offset_pos: u8,
offset_col: u8,
offset_uv: u8,
cmd_ptr: [*]const u8,
cmd_count: usize,
uniform_ptr: [*]const u8,
uniform_floats: usize,
) void;
pub extern "dvui" fn wasm_programCreate(glsl: [*]const u8, len: usize, textures: u32, uniform_vec4s: u32) u32;
pub extern "dvui" fn wasm_programStatus(id: u32) u8;
pub extern "dvui" fn wasm_programMaxVec4() u32;
Expand All @@ -220,11 +253,21 @@ pub const wasm = if (!builtin.is_test) struct {
pub extern "dvui" fn wasm_open_url(ptr: [*]const u8, len: usize, new_window: bool) void;
pub extern "dvui" fn wasm_preferred_color_scheme() u8;
pub extern "dvui" fn wasm_prefers_reduced_motion() u8;
pub extern "dvui" fn wasm_download_data(name_ptr: [*]const u8, name_len: usize, data_ptr: [*]const u8, data_len: usize) void;
pub extern "dvui" fn wasm_download_data(
name_ptr: [*]const u8,
name_len: usize,
data_ptr: [*]const u8,
data_len: usize,
) void;
pub extern "dvui" fn wasm_clipboardTextSet(ptr: [*]const u8, len: usize) void;

// NOTE: bool in extern becomes 0 and 1 in js, which is falsy and truthy respectively
pub extern "dvui" fn wasm_open_file_picker(id: u64, accept_ptr: [*]const u8, accept_len: usize, multiple: bool) void;
pub extern "dvui" fn wasm_open_file_picker(
id: u64,
accept_ptr: [*]const u8,
accept_len: usize,
multiple: bool,
) void;
pub extern "dvui" fn wasm_get_number_of_files_available(id: u64) usize;
pub extern "dvui" fn wasm_get_file_name(id: u64, file_index: usize) [*:0]u8;
pub extern "dvui" fn wasm_get_file_size(id: u64, file_index: usize) isize;
Expand Down Expand Up @@ -284,7 +327,20 @@ pub const wasm = if (!builtin.is_test) struct {
pub fn wasm_textureRead(_: u32, _: [*]u8, _: u32, _: u32) void {}
pub fn wasm_renderTarget(_: u32) void {}
pub fn wasm_textureDestroy(_: u32) void {}
pub fn wasm_renderStream(_: [*]const u8, _: usize, _: [*]const u8, _: usize, _: u8, _: u8, _: u8, _: u8, _: [*]const u8, _: usize, _: [*]const u8, _: usize) void {}
pub fn wasm_renderStream(
_: [*]const u8,
_: usize,
_: [*]const u8,
_: usize,
_: u8,
_: u8,
_: u8,
_: u8,
_: [*]const u8,
_: usize,
_: [*]const u8,
_: usize,
) void {}
pub fn wasm_programCreate(_: [*]const u8, _: usize, _: u32, _: u32) u32 {
return 1;
}
Expand Down Expand Up @@ -361,7 +417,6 @@ export fn dvui_c_realloc_sized(ptr: ?*anyopaque, oldsize: usize, newsize: usize)
dvui_c_free(ptr);
return newptr;

//std.mem.writeInt(usize, slice[0..@sizeOf(usize)], slice.len, builtin.target.cpu.arch.endian());
//return slice.ptr + 16;
}

Expand Down Expand Up @@ -475,7 +530,11 @@ fn add_event_raw(w: *dvui.Window, which: u8, int1: u32, int2: u32, float1: f32,
w.modifiers = web_mod_code_to_dvui(@intCast(int2));
_ = try w.addEventMouseButton(buttonFromJS(int1), .release);
},
4 => _ = try w.addEventMouseWheel(float1 * dvui.scroll_speed, if (int1 > 0) .vertical else .horizontal, if (int2 == 0) .mouse else .trackpad),
4 => _ = try w.addEventMouseWheel(
float1 * dvui.scroll_speed,
if (int1 > 0) .vertical else .horizontal,
if (int2 == 0) .mouse else .trackpad,
),
5 => {
const str = @as([*]u8, @ptrFromInt(int1))[0..int2];
_ = try w.addEventKey(.{
Expand Down Expand Up @@ -503,7 +562,11 @@ fn add_event_raw(w: *dvui.Window, which: u8, int1: u32, int2: u32, float1: f32,
},
9 => {
const touch: dvui.enums.Button = @fromBackingInt(@intCast(@backingInt(dvui.enums.Button.touch0) + int1));
_ = try w.addEventPointer(.{ .button = touch, .action = .release, .xynorm = .{ .x = float1, .y = float2 } });
_ = try w.addEventPointer(.{
.button = touch,
.action = .release,
.xynorm = .{ .x = float1, .y = float2 },
});
touchPoints[int1] = null;
},
10 => {
Expand Down Expand Up @@ -673,61 +736,6 @@ fn web_mod_code_to_dvui(wmod: u8) dvui.enums.Mod {
return @as(dvui.enums.Mod, @fromBackingInt(@intCast(m)));
}

//pub fn addAllEvents(self: *WebBackend, win: *dvui.Window) !void {
// for (event_temps.items) |e| {
// switch (e.kind) {
// 1 => _ = try win.addEventMouseMotion(e.float1, e.float2),
// 2 => _ = try win.addEventMouseButton(buttonFromJS(e.int1), .press),
// 3 => _ = try win.addEventMouseButton(buttonFromJS(e.int1), .release),
// 4 => _ = try win.addEventMouseWheel(if (e.float1 > 0) -20 else 20, .vertical),
// 5 => {
// const str = @as([*]u8, @ptrFromInt(e.int1))[0..e.int2];
// _ = try win.addEventKey(.{
// .action = if (e.float1 > 0) .repeat else .down,
// .code = web_key_code_to_dvui(str),
// .mod = web_mod_code_to_dvui(@trunc(e.float2)),
// });
// },
// 6 => {
// const str = @as([*]u8, @ptrFromInt(e.int1))[0..e.int2];
// _ = try win.addEventKey(.{
// .action = .up,
// .code = web_key_code_to_dvui(str),
// .mod = web_mod_code_to_dvui(@trunc(e.float2)),
// });
// },
// 7 => {
// const str = @as([*]u8, @ptrFromInt(e.int1))[0..e.int2];
// _ = try win.addEventText(str);
// },
// 8 => {
// const touch: dvui.enums.Button = @enumFromInt(@intFromEnum(dvui.enums.Button.touch0) + e.int1);
// _ = try win.addEventPointer(touch, .press, .{ .x = e.float1, .y = e.float2 });
// self.touchPoints[e.int1] = .{ .x = e.float1, .y = e.float2 };
// },
// 9 => {
// const touch: dvui.enums.Button = @enumFromInt(@intFromEnum(dvui.enums.Button.touch0) + e.int1);
// _ = try win.addEventPointer(touch, .release, .{ .x = e.float1, .y = e.float2 });
// self.touchPoints[e.int1] = null;
// },
// 10 => {
// const touch: dvui.enums.Button = @enumFromInt(@intFromEnum(dvui.enums.Button.touch0) + e.int1);
// var dx: f32 = 0;
// var dy: f32 = 0;
// if (self.touchPoints[e.int1]) |p| {
// dx = e.float1 - p.x;
// dy = e.float2 - p.y;
// }
// _ = try win.addEventTouchMotion(touch, e.float1, e.float2, dx, dy);
// self.touchPoints[e.int1] = .{ .x = e.float1, .y = e.float2 };
// },
// else => log.debug("addAllEvents unknown event kind {d}", .{e.kind}),
// }
// }
//
// event_temps.clearRetainingCapacity();
//}

pub fn init() !WebBackend {
const ret: WebBackend = .{};
return ret;
Expand All @@ -752,7 +760,13 @@ pub fn sleep(_: *WebBackend, ns: u64) void {
/// The kinds of window material the web can show (fizzy's `core.material`, field for field):
/// every one. Its glass is all drawn in the canvas, the one surface it puts glass on (Liquid Glass
/// by its own shader), and the page behind a clear canvas shows through.
pub const MaterialKinds = struct { none: bool = true, transparent: bool = true, blur: bool = true, frost: bool = true, liquid: bool = true };
pub const MaterialKinds = struct {
none: bool = true,
transparent: bool = true,
blur: bool = true,
frost: bool = true,
liquid: bool = true,
};

pub fn materialKinds(_: *WebBackend) MaterialKinds {
return .{};
Expand Down Expand Up @@ -785,7 +799,13 @@ pub fn contentScale(_: *WebBackend) f32 {
return 1.0; // comes through windowSize/pixelSize
}

pub fn drawClippedTriangles(self: *WebBackend, texture: ?dvui.Texture, vtx: []const dvui.Vertex, idx: []const dvui.Vertex.Index, maybe_clipr: ?dvui.Rect.Physical) !void {
pub fn drawClippedTriangles(
self: *WebBackend,
texture: ?dvui.Texture,
vtx: []const dvui.Vertex,
idx: []const dvui.Vertex.Index,
maybe_clipr: ?dvui.Rect.Physical,
) !void {
if (self.unseen and !target_is_fb) return;
if (batch.vtx.items.len + vtx.len > std.math.maxInt(dvui.Vertex.Index)) flushBatch();

Expand Down Expand Up @@ -844,7 +864,16 @@ fn command(texture: ?dvui.Texture, maybe_clipr: ?dvui.Rect.Physical, index_start

/// A switch or clear (`Command.clip`) of `texture` (0 the screen), in order with the draws.
fn marker(step: i32, texture: i32) !void {
try batch.cmds.append(arena, .{ .texture = texture, .clip = step, .x = 0, .y = 0, .w = 0, .h = 0, .index_start = 0, .index_count = 0 });
try batch.cmds.append(arena, .{
.texture = texture,
.clip = step,
.x = 0,
.y = 0,
.w = 0,
.h = 0,
.index_start = 0,
.index_count = 0,
});
}

/// Whether anything waiting in the stream uses texture `id` — draws from it, draws into it, or
Expand Down Expand Up @@ -901,7 +930,16 @@ fn programMarker() !void {
const p = &(program orelse return);
const at: i32 = @intCast(batch.uniforms.items.len);
try batch.uniforms.appendSlice(arena, p.uniforms[0..p.n]);
try batch.cmds.append(arena, .{ .texture = p.id, .clip = Command.use_program, .x = at, .y = @intCast(p.n), .w = p.tex1, .h = p.tex2, .index_start = 0, .index_count = 0 });
try batch.cmds.append(arena, .{
.texture = p.id,
.clip = Command.use_program,
.x = at,
.y = @intCast(p.n),
.w = p.tex1,
.h = p.tex2,
.index_start = 0,
.index_count = 0,
});
}

/// Custom programs (`core.gfx.programs`): compiled by `web.js`, switched to in the stream.
Expand All @@ -923,7 +961,13 @@ pub const program_api = struct {
return wasm.wasm_programStatus(id);
}

pub fn begin(id: u32, textures: [*]const ?*anyopaque, n_textures: u32, uniforms: [*]const [4]f32, n_uniforms: u32) callconv(.c) bool {
pub fn begin(
id: u32,
textures: [*]const ?*anyopaque,
n_textures: u32,
uniforms: [*]const [4]f32,
n_uniforms: u32,
) callconv(.c) bool {
if (n_uniforms > uniform_cap or n_textures > 2) return false;
if (wasm.wasm_programStatus(id) != 2) return false;
const tex = struct {
Expand Down Expand Up @@ -954,7 +998,16 @@ pub const program_api = struct {
blend_override = null;
if (program == null) return;
program = null;
batch.cmds.append(arena, .{ .texture = 0, .clip = Command.use_program, .x = 0, .y = 0, .w = 0, .h = 0, .index_start = 0, .index_count = 0 }) catch {};
batch.cmds.append(arena, .{
.texture = 0,
.clip = Command.use_program,
.x = 0,
.y = 0,
.w = 0,
.h = 0,
.index_start = 0,
.index_count = 0,
}) catch {};
}
};

Expand Down Expand Up @@ -994,15 +1047,27 @@ pub fn textureCreate(_: *WebBackend, pixels: [*]const u8, options: dvui.Texture.
/// See `dvui.Backend.textureUpdate`. `texSubImage2D` over the whole texture.
pub fn textureUpdate(_: *WebBackend, texture: dvui.Texture, pixels: [*]const u8) !void {
if (pendingUses(@intCast(@intFromPtr(texture.ptr)))) flushBatch();
if (wasm.wasm_textureUpdate(@intCast(@intFromPtr(texture.ptr)), pixels) == 0) return dvui.Backend.TextureError.TextureUpdate;
if (wasm.wasm_textureUpdate(@intCast(@intFromPtr(texture.ptr)), pixels) == 0) {
return dvui.Backend.TextureError.TextureUpdate;
}
}

/// See `dvui.Backend.textureUpdateSubRect`. `pixels` is the full texture's buffer; only the
/// rect is uploaded (WebGL2 reads it in place through the unpack row length and skips; WebGL1
/// copies the rect's rows out first).
pub fn textureUpdateSubRect(_: *WebBackend, texture: dvui.Texture, pixels: [*]const u8, x: u32, y: u32, w: u32, h: u32) !void {
pub fn textureUpdateSubRect(
_: *WebBackend,
texture: dvui.Texture,
pixels: [*]const u8,
x: u32,
y: u32,
w: u32,
h: u32,
) !void {
if (pendingUses(@intCast(@intFromPtr(texture.ptr)))) flushBatch();
if (wasm.wasm_textureUpdateSubRect(@intCast(@intFromPtr(texture.ptr)), pixels, x, y, w, h) == 0) return dvui.Backend.TextureError.TextureUpdate;
if (wasm.wasm_textureUpdateSubRect(@intCast(@intFromPtr(texture.ptr)), pixels, x, y, w, h) == 0) {
return dvui.Backend.TextureError.TextureUpdate;
}
}

/// See `dvui.Backend.support_precise_targets`. `precision = .high` is RGBA16F on WebGL2 with
Expand Down
32 changes: 24 additions & 8 deletions src/backend/backend_native.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Fizzy's own use of its window: the platform pieces any app gets (the backend package's `platform`
//! — dialogs, files from the OS, gestures, chrome, geometry, the window monitor, the menu bar) with
//! Fizzy's own use of its window: the platform pieces any app gets (the backend package's
//! `platform` — dialogs, files from the OS, gestures, chrome, geometry, the window monitor,
//! the menu bar) with
//! fizzy's policy over them — where dialogs start, where geometry is kept (`layout.zon`), how high
//! the titlebar strip is, what its menus hold and when their items are enabled. The web build has
//! the same surface in `backend_web.zig`.
Expand All @@ -16,8 +17,9 @@ const KeybindSettings = @import("../editor/KeybindSettings.zig");
const menu_model = @import("../editor/menu_model.zig");
const AppInfo = @import("app").AppInfo;

/// The window and platform pieces any app on these backends gets (the backend package's `platform`):
/// dialogs, files from the OS, gestures, the window's chrome and state, Windows' title bar. What
/// The window and platform pieces any app on these backends gets (the backend package's
/// `platform`): dialogs, files from the OS, gestures, the window's chrome and state,
/// Windows' title bar. What
/// follows them here is fizzy's own use of them.
const platform = @import("platform");

Expand Down Expand Up @@ -150,7 +152,10 @@ pub const WindowGlassLook = platform.window.WindowGlassLook;
pub fn windowMaterialBase(win: *dvui.Window, fill: dvui.Color, opacity: f32, look: WindowGlassLook) ?dvui.Color {
if (comptime builtin.target.os.tag != .macos) return null;
if (comptime !@hasDecl(dvui.backend, "setWindowLook")) {
return if (platform.window.liquidGlassLook(win.backend.impl.window, look.native())) dvui.Color{ .r = 0, .g = 0, .b = 0, .a = 0 } else null;
if (platform.window.liquidGlassLook(win.backend.impl.window, look.native())) {
return dvui.Color{ .r = 0, .g = 0, .b = 0, .a = 0 };
}
return null;
}
dvui.backend.setWindowLook(fill, opacity);
return dvui.backend.materialBase(win.backend.impl.effectiveMaterial(), fill);
Expand Down Expand Up @@ -195,7 +200,11 @@ fn layoutStoreSave(_: ?*anyopaque, g: platform.geometry.Geometry) void {
/// pane mid-transition; a zoom without a Space keeps the full strip. Fizzy's titlebar heights
/// over the window's state (`platform.macos_monitor.titlebarState`).
pub fn titlebarStripHeight(win: *dvui.Window) f32 {
return platform.macos_monitor.titlebarStrip(win.backend.impl.window, Constants.titlebar_height, Constants.titlebar_top_buffer);
return platform.macos_monitor.titlebarStrip(
win.backend.impl.window,
Constants.titlebar_height,
Constants.titlebar_top_buffer,
);
}

// ---- The native menu bar: fizzy's menus (`menu_model`) on the platform's (`platform.menu`) ----
Expand Down Expand Up @@ -231,7 +240,9 @@ const native_menus: []const platform.menu.Menu = blk: {
n += 1;
},
.command => |cmd| {
entries[n] = .{ .command = .{ .title = cmd.title.resolveStatic(), .tag = tag, .symbol = cmd.sf_symbol } };
entries[n] = .{
.command = .{ .title = cmd.title.resolveStatic(), .tag = tag, .symbol = cmd.sf_symbol },
};
n += 1;
tag += 1;
},
Expand Down Expand Up @@ -334,7 +345,12 @@ pub fn rebuildDynamicNativeMenus() void {
}
for (host.native_menu_items.items, 0..) |ni, i| {
if (ni.hidden) continue;
items.append(alloc(), .{ .menu_id = ni.parent_menu_id, .title = ni.title, .symbol = ni.sf_symbol, .tag = @intCast(i) }) catch {};
items.append(alloc(), .{
.menu_id = ni.parent_menu_id,
.title = ni.title,
.symbol = ni.sf_symbol,
.tag = @intCast(i),
}) catch {};
}
platform.menu.setExtras(menus.items, items.items);
// The items are built with no key equivalent; this is what puts the keymap's chords on them.
Expand Down
Loading
Loading