summaryrefslogtreecommitdiff
path: root/src/gui/gui.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/gui.zig')
-rw-r--r--src/gui/gui.zig42
1 files changed, 38 insertions, 4 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 8fd8d360..c737450b 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -5872,6 +5872,7 @@ fn renderFrame(
if (surface.chrome.fx & 2 == 0 or surface.panelTracks().len != 0) g.hover_glow = .{ .now_ns = g.sel_glow.now_ns };
if (g.glide.moving()) g.glide.offset = g.glide.spring.value(g.glide.now_ns);
cell_decor = CellDecor.of(chrome);
+ plaque_through_len = 0;
// G13: a body's dots follow its text at a quarter of its speed: its
// first line, and a glide's picture offset, in rows.
if (chrome.fx & 8 != 0 and chrome.decor_dots != null) for (surface.regionList()) |region| {
@@ -6159,6 +6160,25 @@ fn renderFrame(
for (groups.items[0..groups.len], 0..) |group, index|
std.debug.assert(cell_next[index] == group.cell_start + group.cell_count);
shifted = emitScrollRows(g, instances, cell_total, surface, layout, win_w, win_h, page);
+ // Over a theme's plaques a see-through cell with no ink blends to
+ // the plaque under it, so it draws nothing: its quad goes, and the
+ // cells are drawn unblended (a third of the GPU's frame at 4K)
+ // unless one see-through cell does have ink, or the page itself is
+ // see-through.
+ if (cell_decor.nplaques != 0) {
+ const space_u = @as(f32, @floatFromInt(g.space_slot.u)) / @as(f32, @floatFromInt(atlas_w));
+ const space_v = @as(f32, @floatFromInt(g.space_slot.v)) / @as(f32, @floatFromInt(atlas_h));
+ if (page.clear or plaque_through_len > plaque_through.len) cell_decor.inked_clear = true;
+ for (plaque_through[0..@min(plaque_through_len, plaque_through.len)]) |at| {
+ const instance = &instances[at];
+ // A grip's button takes its cell's ground back (emitSurfaceCell).
+ if (instance.effect & clear_bg_bit == 0) continue;
+ if (instance.u0 == space_u and instance.v0 == space_v) {
+ instance.x1 = instance.x0;
+ instance.y1 = instance.y0;
+ } else cell_decor.inked_clear = true;
+ }
+ }
@memcpy(instances[cell_total + shifted ..][0..decor_len], g.decor.items);
c.SDL_UnmapGPUTransferBuffer(g.device, g.vxfer.?);
@@ -6190,7 +6210,7 @@ fn renderFrame(
// Blended over what is under: a theme's plaques show through
// blank tag cells; a dissolve's old cells fade over its new.
const dissolving = if (group.track) |active| active.effect == .dissolve else false;
- c.SDL_BindGPUGraphicsPipeline(rp, if (cell_decor.nplaques != 0 or dissolving) g.pipeline_over else g.pipeline);
+ c.SDL_BindGPUGraphicsPipeline(rp, if (cell_decor.inked_clear or dissolving) g.pipeline_over else g.pipeline);
const samp_binding = c.SDL_GPUTextureSamplerBinding{ .texture = g.atlas_tex, .sampler = g.atlas_sampler };
c.SDL_BindGPUFragmentSamplers(rp, 0, &samp_binding, 1);
if (group.cell_count != 0) {
@@ -6516,7 +6536,7 @@ fn emitTagLayer(g: *Gui, instances: [*]CellInstance, next: *u32, layer: *const p
emitInstance(g, instances, next.*, 0, y, .{ .w = band_right - left, .h = bh, .x_off = left, .y_off = slide }, win_w, win_h, track, .body, (&background)[0..1], 0, null, old_layer, false, page);
// A theme's plaque is drawn under the band: the band's own ground
// lets it show (tagPlaques).
- if (cell_decor.nplaques != 0 and cell_decor.inPlaque(left + 0.5, top + 0.5)) instances[next.*].effect |= clear_bg_bit;
+ if (cell_decor.nplaques != 0 and cell_decor.inPlaque(left + 0.5, top + 0.5)) plaqueThrough(instances, next.*);
if (slide != 0) clipInstanceTop(&instances[next.*], top, win_h);
next.* += 1;
const cells = layer.cells[index * layer.cols ..][0..layer.cols];
@@ -6728,7 +6748,7 @@ fn emitSurfaceCell(
const cell_x = @as(f32, @floatFromInt(col)) * body_layout.w + body_layout.x_off;
const cell_y = @as(f32, @floatFromInt(row)) * body_layout.h + body_layout.y_off + 0.5;
if (cell_decor.nplaques != 0 and cell_decor.inPlaque(if (here.grip) cell_x + body_layout.w - 0.5 else cell_x + 0.5, cell_y))
- instances[next.*].effect |= clear_bg_bit;
+ plaqueThrough(instances, next.*);
next.* += 1;
// Tag glyphs keep their font size inside a full physical-width grip.
// A pane's grip cells are the cell shells' form (a dirty `*`): the
@@ -7060,7 +7080,7 @@ fn emitInstance(
if (cell_decor.nplaques != 0 and resolved.role == .tagline and cellCodepoint(&line[at]) == ' ' and
(std.mem.eql(u8, &resolved.bg, &cell_decor.grounds[0]) or std.mem.eql(u8, &resolved.bg, &cell_decor.grounds[1])) and
(cell_decor.inPlaque(px0 + 0.5, py0 + 0.5) or cell_decor.inPlaque(px0 + layout.w - 0.5, py0 + 0.5)))
- instances[idx].effect |= clear_bg_bit;
+ plaqueThrough(instances, idx);
if (cell_decor.dots) |dotted| {
if (!resolved.clear_bg and std.mem.eql(u8, &resolved.bg, &dotted)) {
instances[idx].effect |= dotted_bit;
@@ -9034,6 +9054,17 @@ fn updateDisplayScale(window: *c.SDL_Window) void {
/// it falls on, and pushLayerOpacity hands the shader its colours and
/// sizes. ponytail: one window per process, as display_scale.
var cell_decor: CellDecor = .{};
+/// The cells this frame lets a plaque show through, by instance, for
+/// renderFrame to drop the ones with no ink. Past its length the frame's
+/// cells are blended instead.
+var plaque_through: [16384]u32 = undefined;
+var plaque_through_len: usize = 0;
+
+fn plaqueThrough(instances: [*]CellInstance, at: u32) void {
+ instances[at].effect |= clear_bg_bit;
+ if (plaque_through_len < plaque_through.len) plaque_through[plaque_through_len] = at;
+ plaque_through_len += 1;
+}
const CellDecor = struct {
/// The page's ground, when the theme dots it.
dots: ?[3]u8 = null,
@@ -9048,6 +9079,9 @@ const CellDecor = struct {
nplaques: usize = 0,
grounds: [2][3]u8 = .{ .{ 0, 0, 0 }, .{ 0, 0, 0 } },
plaques_off: bool = false,
+ /// A see-through cell over the plaques has ink of its own, so this
+ /// frame's cells are blended (renderFrame).
+ inked_clear: bool = false,
/// G13: each body's rectangle and how far its dots have moved.
bodies: [pardes.MAX_PANES][4]f32 = undefined,