mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
terminal/kitty-gfx: honor "z" setting
This commit is contained in:
@ -85,6 +85,8 @@ font_shaper: font.Shaper,
|
||||
/// The images that we may render.
|
||||
images: ImageMap = .{},
|
||||
image_placements: ImagePlacementList = .{},
|
||||
image_bg_end: u32 = 0,
|
||||
image_text_end: u32 = 0,
|
||||
|
||||
/// Metal state
|
||||
shaders: Shaders, // Compiled shaders
|
||||
@ -636,50 +638,33 @@ pub fn render(
|
||||
);
|
||||
defer encoder.msgSend(void, objc.sel("endEncoding"), .{});
|
||||
|
||||
// Terminal grid
|
||||
{
|
||||
// Use our shader pipeline
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setRenderPipelineState:"),
|
||||
.{self.shaders.cell_pipeline.value},
|
||||
);
|
||||
// Draw background images first
|
||||
try self.drawImagePlacements(encoder, self.image_placements.items[0..self.image_bg_end]);
|
||||
|
||||
// Set our buffers
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setVertexBytes:length:atIndex:"),
|
||||
.{
|
||||
@as(*const anyopaque, @ptrCast(&self.uniforms)),
|
||||
@as(c_ulong, @sizeOf(@TypeOf(self.uniforms))),
|
||||
@as(c_ulong, 1),
|
||||
},
|
||||
);
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setFragmentTexture:atIndex:"),
|
||||
.{
|
||||
self.texture_greyscale.value,
|
||||
@as(c_ulong, 0),
|
||||
},
|
||||
);
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setFragmentTexture:atIndex:"),
|
||||
.{
|
||||
self.texture_color.value,
|
||||
@as(c_ulong, 1),
|
||||
},
|
||||
);
|
||||
|
||||
// Issue the draw calls for this shader
|
||||
// Then draw background cells
|
||||
try self.drawCells(encoder, &self.buf_cells_bg, self.cells_bg);
|
||||
|
||||
// Then draw images under text
|
||||
try self.drawImagePlacements(encoder, self.image_placements.items[0..self.image_text_end]);
|
||||
|
||||
// Then draw fg cells
|
||||
try self.drawCells(encoder, &self.buf_cells, self.cells);
|
||||
|
||||
// Then draw remaining images
|
||||
try self.drawImagePlacements(encoder, self.image_placements.items[self.image_text_end..]);
|
||||
}
|
||||
|
||||
// Images
|
||||
// TODO: these should not go above text
|
||||
if (self.image_placements.items.len > 0) {
|
||||
buffer.msgSend(void, objc.sel("presentDrawable:"), .{drawable.value});
|
||||
buffer.msgSend(void, objc.sel("commit"), .{});
|
||||
}
|
||||
|
||||
fn drawImagePlacements(
|
||||
self: *Metal,
|
||||
encoder: objc.Object,
|
||||
placements: []const mtl_image.Placement,
|
||||
) !void {
|
||||
if (placements.len == 0) return;
|
||||
|
||||
// Use our image shader pipeline
|
||||
encoder.msgSend(
|
||||
void,
|
||||
@ -698,14 +683,9 @@ pub fn render(
|
||||
},
|
||||
);
|
||||
|
||||
for (self.image_placements.items) |placement| {
|
||||
for (placements) |placement| {
|
||||
try self.drawImagePlacement(encoder, placement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer.msgSend(void, objc.sel("presentDrawable:"), .{drawable.value});
|
||||
buffer.msgSend(void, objc.sel("commit"), .{});
|
||||
}
|
||||
|
||||
fn drawImagePlacement(
|
||||
@ -809,14 +789,49 @@ fn drawCells(
|
||||
buf: *CellBuffer,
|
||||
cells: std.ArrayListUnmanaged(mtl_shaders.Cell),
|
||||
) !void {
|
||||
if (cells.items.len == 0) return;
|
||||
|
||||
try buf.sync(self.device, cells.items);
|
||||
|
||||
// Use our shader pipeline
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setRenderPipelineState:"),
|
||||
.{self.shaders.cell_pipeline.value},
|
||||
);
|
||||
|
||||
// Set our buffers
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setVertexBytes:length:atIndex:"),
|
||||
.{
|
||||
@as(*const anyopaque, @ptrCast(&self.uniforms)),
|
||||
@as(c_ulong, @sizeOf(@TypeOf(self.uniforms))),
|
||||
@as(c_ulong, 1),
|
||||
},
|
||||
);
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setFragmentTexture:atIndex:"),
|
||||
.{
|
||||
self.texture_greyscale.value,
|
||||
@as(c_ulong, 0),
|
||||
},
|
||||
);
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setFragmentTexture:atIndex:"),
|
||||
.{
|
||||
self.texture_color.value,
|
||||
@as(c_ulong, 1),
|
||||
},
|
||||
);
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("setVertexBuffer:offset:atIndex:"),
|
||||
.{ buf.buffer.value, @as(c_ulong, 0), @as(c_ulong, 0) },
|
||||
);
|
||||
|
||||
if (cells.items.len > 0) {
|
||||
encoder.msgSend(
|
||||
void,
|
||||
objc.sel("drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:"),
|
||||
@ -829,7 +844,6 @@ fn drawCells(
|
||||
@as(c_ulong, cells.items.len),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// This goes through the Kitty graphic placements and accumulates the
|
||||
@ -882,7 +896,7 @@ fn prepKittyGraphics(
|
||||
};
|
||||
|
||||
// If the selection isn't within our viewport then skip it.
|
||||
const image_sel = kv.value_ptr.selection(image, t);
|
||||
const image_sel = p.selection(image, t);
|
||||
if (!image_sel.within(top, bot)) continue;
|
||||
|
||||
// If the top left is outside the viewport we need to calc an offset
|
||||
@ -915,7 +929,7 @@ fn prepKittyGraphics(
|
||||
}
|
||||
|
||||
// Convert our screen point to a viewport point
|
||||
const viewport = kv.value_ptr.point.toViewport(&t.screen);
|
||||
const viewport = p.point.toViewport(&t.screen);
|
||||
|
||||
// Calculate the source rectangle
|
||||
const source_x = @min(image.width, p.source_x);
|
||||
@ -937,12 +951,13 @@ fn prepKittyGraphics(
|
||||
if (image.width > 0 and image.height > 0) {
|
||||
try self.image_placements.append(self.alloc, .{
|
||||
.image_id = kv.key_ptr.image_id,
|
||||
.x = @intCast(kv.value_ptr.point.x),
|
||||
.x = @intCast(p.point.x),
|
||||
.y = @intCast(viewport.y),
|
||||
.z = p.z,
|
||||
.width = dest_width,
|
||||
.height = dest_height,
|
||||
.cell_offset_x = kv.value_ptr.x_offset,
|
||||
.cell_offset_y = kv.value_ptr.y_offset,
|
||||
.cell_offset_x = p.x_offset,
|
||||
.cell_offset_y = p.y_offset,
|
||||
.source_x = source_x,
|
||||
.source_y = source_y,
|
||||
.source_width = source_width,
|
||||
@ -950,6 +965,36 @@ fn prepKittyGraphics(
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the placements by their Z value.
|
||||
std.mem.sortUnstable(
|
||||
mtl_image.Placement,
|
||||
self.image_placements.items,
|
||||
{},
|
||||
struct {
|
||||
fn lessThan(
|
||||
ctx: void,
|
||||
lhs: mtl_image.Placement,
|
||||
rhs: mtl_image.Placement,
|
||||
) bool {
|
||||
_ = ctx;
|
||||
return lhs.z < rhs.z or (lhs.z == rhs.z and lhs.image_id < rhs.image_id);
|
||||
}
|
||||
}.lessThan,
|
||||
);
|
||||
|
||||
// Find our indices
|
||||
self.image_bg_end = 0;
|
||||
self.image_text_end = 0;
|
||||
const bg_limit = std.math.minInt(i32) / 2;
|
||||
for (self.image_placements.items, 0..) |p, i| {
|
||||
if (self.image_bg_end == 0 and p.z >= bg_limit) {
|
||||
self.image_bg_end = @intCast(i);
|
||||
}
|
||||
if (self.image_text_end == 0 and p.z >= 0) {
|
||||
self.image_text_end = @intCast(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the configuration.
|
||||
|
@ -14,6 +14,7 @@ pub const Placement = struct {
|
||||
/// The grid x/y where this placement is located.
|
||||
x: u32,
|
||||
y: u32,
|
||||
z: i32,
|
||||
|
||||
/// The width/height of the placed image.
|
||||
width: u32,
|
||||
|
@ -198,9 +198,16 @@ pub const CommandParser = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the value as a string
|
||||
// Only "z" is currently signed. This is a bit of a kloodge; if more
|
||||
// fields become signed we can rethink this but for now we parse
|
||||
// "z" as i32 then bitcast it to u32 then bitcast it back later.
|
||||
if (self.kv_current == 'z') {
|
||||
const v = try std.fmt.parseInt(i32, self.kv_temp[0..self.kv_temp_len], 10);
|
||||
try self.kv.put(alloc, self.kv_current, @bitCast(v));
|
||||
} else {
|
||||
const v = try std.fmt.parseInt(u32, self.kv_temp[0..self.kv_temp_len], 10);
|
||||
try self.kv.put(alloc, self.kv_current, v);
|
||||
}
|
||||
|
||||
// Clear our temp buffer
|
||||
self.kv_temp_len = 0;
|
||||
@ -419,7 +426,7 @@ pub const Display = struct {
|
||||
rows: u32 = 0, // r
|
||||
cursor_movement: CursorMovement = .after, // C
|
||||
virtual_placement: bool = false, // U
|
||||
z: u32 = 0, // z
|
||||
z: i32 = 0, // z
|
||||
|
||||
pub const CursorMovement = enum {
|
||||
after, // 0
|
||||
@ -490,7 +497,8 @@ pub const Display = struct {
|
||||
}
|
||||
|
||||
if (kv.get('z')) |v| {
|
||||
result.z = v;
|
||||
// We can bitcast here because of how we parse it earlier.
|
||||
result.z = @bitCast(v);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -693,7 +701,7 @@ pub const Delete = union(enum) {
|
||||
delete: bool = false, // uppercase
|
||||
x: u32 = 0, // x
|
||||
y: u32 = 0, // y
|
||||
z: u32 = 0, // z
|
||||
z: i32 = 0, // z
|
||||
},
|
||||
|
||||
// x/X
|
||||
@ -711,7 +719,7 @@ pub const Delete = union(enum) {
|
||||
// z/Z
|
||||
z: struct {
|
||||
delete: bool = false, // uppercase
|
||||
z: u32 = 0, // z
|
||||
z: i32 = 0, // z
|
||||
},
|
||||
|
||||
fn parse(kv: KV) !Delete {
|
||||
@ -773,7 +781,8 @@ pub const Delete = union(enum) {
|
||||
result.intersect_cell_z.y = v;
|
||||
}
|
||||
if (kv.get('z')) |v| {
|
||||
result.intersect_cell_z.z = v;
|
||||
// We can bitcast here because of how we parse it earlier.
|
||||
result.intersect_cell_z.z = @bitCast(v);
|
||||
}
|
||||
|
||||
break :blk result;
|
||||
@ -800,7 +809,8 @@ pub const Delete = union(enum) {
|
||||
'z', 'Z' => blk: {
|
||||
var result: Delete = .{ .z = .{ .delete = what == 'Z' } };
|
||||
if (kv.get('z')) |v| {
|
||||
result.z.z = v;
|
||||
// We can bitcast here because of how we parse it earlier.
|
||||
result.z.z = @bitCast(v);
|
||||
}
|
||||
|
||||
break :blk result;
|
||||
|
@ -178,6 +178,7 @@ fn display(
|
||||
.source_height = d.height,
|
||||
.columns = d.columns,
|
||||
.rows = d.rows,
|
||||
.z = d.z,
|
||||
};
|
||||
storage.addPlacement(alloc, img.id, d.placement_id, p) catch |err| {
|
||||
encodeError(&result, err);
|
||||
|
@ -170,6 +170,9 @@ pub const ImageStorage = struct {
|
||||
columns: u32 = 0,
|
||||
rows: u32 = 0,
|
||||
|
||||
/// The z-index for this placement.
|
||||
z: i32 = 0,
|
||||
|
||||
/// Returns a selection of the entire rectangle this placement
|
||||
/// occupies within the screen.
|
||||
pub fn selection(
|
||||
|
Reference in New Issue
Block a user