mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
update the font atlas if there are changes
This commit is contained in:
@ -123,10 +123,13 @@ pub fn addGlyph(self: *FontAtlas, alloc: Allocator, v: anytype) !*Glyph {
|
|||||||
errdefer _ = self.glyphs.remove(utf32);
|
errdefer _ = self.glyphs.remove(utf32);
|
||||||
|
|
||||||
const glyph_index = glyph_index: {
|
const glyph_index = glyph_index: {
|
||||||
|
// log.warn("glyph load: {x}", .{utf32});
|
||||||
const idx = ftc.FT_Get_Char_Index(self.ft_face, utf32);
|
const idx = ftc.FT_Get_Char_Index(self.ft_face, utf32);
|
||||||
if (idx > 0) break :glyph_index idx;
|
if (idx > 0) break :glyph_index idx;
|
||||||
|
|
||||||
// Unknown glyph.
|
// Unknown glyph.
|
||||||
|
log.warn("glyph not found: {x}", .{utf32});
|
||||||
|
|
||||||
// TODO: render something more identifiable than a space
|
// TODO: render something more identifiable than a space
|
||||||
break :glyph_index ftc.FT_Get_Char_Index(self.ft_face, ' ');
|
break :glyph_index ftc.FT_Get_Char_Index(self.ft_face, ' ');
|
||||||
};
|
};
|
||||||
@ -178,7 +181,7 @@ pub fn addGlyph(self: *FontAtlas, alloc: Allocator, v: anytype) !*Glyph {
|
|||||||
.advance_x = f26dot6ToFloat(glyph.*.advance.x),
|
.advance_x = f26dot6ToFloat(glyph.*.advance.x),
|
||||||
};
|
};
|
||||||
|
|
||||||
//log.debug("loaded glyph codepoint={} glyph={}", .{ utf32, gop.value_ptr.* });
|
//log.debug("loaded glyph codepoint=U+{x} glyph={}", .{ utf32, gop.value_ptr.* });
|
||||||
|
|
||||||
return gop.value_ptr;
|
return gop.value_ptr;
|
||||||
}
|
}
|
||||||
|
50
src/Grid.zig
50
src/Grid.zig
@ -34,6 +34,7 @@ texture: gl.Texture,
|
|||||||
|
|
||||||
/// The font atlas.
|
/// The font atlas.
|
||||||
font_atlas: FontAtlas,
|
font_atlas: FontAtlas,
|
||||||
|
atlas_dirty: bool,
|
||||||
|
|
||||||
/// Whether the cursor is visible or not. This is used to control cursor
|
/// Whether the cursor is visible or not. This is used to control cursor
|
||||||
/// blinking.
|
/// blinking.
|
||||||
@ -220,6 +221,7 @@ pub fn init(alloc: Allocator) !Grid {
|
|||||||
.vbo = vbo,
|
.vbo = vbo,
|
||||||
.texture = tex,
|
.texture = tex,
|
||||||
.font_atlas = font,
|
.font_atlas = font,
|
||||||
|
.atlas_dirty = false,
|
||||||
.cursor_visible = true,
|
.cursor_visible = true,
|
||||||
.cursor_style = .box,
|
.cursor_style = .box,
|
||||||
.foreground = .{ .r = 255, .g = 255, .b = 255 },
|
.foreground = .{ .r = 255, .g = 255, .b = 255 },
|
||||||
@ -238,27 +240,6 @@ pub fn deinit(self: *Grid) void {
|
|||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: remove, this is for testing
|
|
||||||
pub fn demoCells(self: *Grid) !void {
|
|
||||||
self.cells.clearRetainingCapacity();
|
|
||||||
try self.cells.ensureUnusedCapacity(self.alloc, self.size.columns * self.size.rows);
|
|
||||||
|
|
||||||
var row: u32 = 0;
|
|
||||||
while (row < self.size.rows) : (row += 1) {
|
|
||||||
var col: u32 = 0;
|
|
||||||
while (col < self.size.columns) : (col += 1) {
|
|
||||||
self.cells.appendAssumeCapacity(.{
|
|
||||||
.grid_col = @intCast(u16, col),
|
|
||||||
.grid_row = @intCast(u16, row),
|
|
||||||
.bg_r = @intCast(u8, @mod(col * row, 255)),
|
|
||||||
.bg_g = @intCast(u8, @mod(col, 255)),
|
|
||||||
.bg_b = @intCast(u8, 255 - @mod(col, 255)),
|
|
||||||
.bg_a = 255,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// updateCells updates our GPU cells from the current terminal view.
|
/// updateCells updates our GPU cells from the current terminal view.
|
||||||
/// The updated cells will take effect on the next render.
|
/// The updated cells will take effect on the next render.
|
||||||
pub fn updateCells(self: *Grid, term: Terminal) !void {
|
pub fn updateCells(self: *Grid, term: Terminal) !void {
|
||||||
@ -307,7 +288,12 @@ pub fn updateCells(self: *Grid, term: Terminal) !void {
|
|||||||
|
|
||||||
// Get our glyph
|
// Get our glyph
|
||||||
// TODO: if we add a glyph, I think we need to rerender the texture.
|
// TODO: if we add a glyph, I think we need to rerender the texture.
|
||||||
const glyph = try self.font_atlas.addGlyph(self.alloc, cell.char);
|
const glyph = if (self.font_atlas.getGlyph(cell.char)) |glyph|
|
||||||
|
glyph
|
||||||
|
else glyph: {
|
||||||
|
self.atlas_dirty = true;
|
||||||
|
break :glyph try self.font_atlas.addGlyph(self.alloc, cell.char);
|
||||||
|
};
|
||||||
|
|
||||||
const fg = cell.fg orelse self.foreground;
|
const fg = cell.fg orelse self.foreground;
|
||||||
self.cells.appendAssumeCapacity(.{
|
self.cells.appendAssumeCapacity(.{
|
||||||
@ -374,6 +360,26 @@ pub fn setScreenSize(self: *Grid, dim: ScreenSize) !void {
|
|||||||
log.debug("screen size screen={} grid={}, cell={}", .{ dim, self.size, self.cell_size });
|
log.debug("screen size screen={} grid={}, cell={}", .{ dim, self.size, self.cell_size });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates the font texture atlas if it is dirty.
|
||||||
|
pub fn flushAtlas(self: *Grid) !void {
|
||||||
|
if (!self.atlas_dirty) return;
|
||||||
|
|
||||||
|
var texbind = try self.texture.bind(.@"2D");
|
||||||
|
defer texbind.unbind();
|
||||||
|
try texbind.subImage2D(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
@intCast(c_int, self.font_atlas.atlas.size),
|
||||||
|
@intCast(c_int, self.font_atlas.atlas.size),
|
||||||
|
.Red,
|
||||||
|
.UnsignedByte,
|
||||||
|
self.font_atlas.atlas.data.ptr,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.atlas_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render(self: Grid) !void {
|
pub fn render(self: Grid) !void {
|
||||||
const t = trace(@src());
|
const t = trace(@src());
|
||||||
defer t.end();
|
defer t.end();
|
||||||
|
@ -499,6 +499,9 @@ fn renderTimerCallback(t: *libuv.Timer) void {
|
|||||||
// Update the cells for drawing
|
// Update the cells for drawing
|
||||||
win.grid.updateCells(win.terminal) catch unreachable;
|
win.grid.updateCells(win.terminal) catch unreachable;
|
||||||
|
|
||||||
|
// Update our texture if we have to
|
||||||
|
win.grid.flushAtlas() catch unreachable;
|
||||||
|
|
||||||
// Set our background
|
// Set our background
|
||||||
gl.clearColor(win.bg_r, win.bg_g, win.bg_b, win.bg_a);
|
gl.clearColor(win.bg_r, win.bg_g, win.bg_b, win.bg_a);
|
||||||
gl.clear(gl.c.GL_COLOR_BUFFER_BIT);
|
gl.clear(gl.c.GL_COLOR_BUFFER_BIT);
|
||||||
|
@ -114,6 +114,30 @@ pub const Binding = struct {
|
|||||||
data,
|
data,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subImage2D(
|
||||||
|
b: Binding,
|
||||||
|
level: c.GLint,
|
||||||
|
xoffset: c.GLint,
|
||||||
|
yoffset: c.GLint,
|
||||||
|
width: c.GLsizei,
|
||||||
|
height: c.GLsizei,
|
||||||
|
format: Format,
|
||||||
|
typ: DataType,
|
||||||
|
data: ?*const anyopaque,
|
||||||
|
) !void {
|
||||||
|
c.glTexSubImage2D(
|
||||||
|
@enumToInt(b.target),
|
||||||
|
level,
|
||||||
|
xoffset,
|
||||||
|
yoffset,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
@enumToInt(format),
|
||||||
|
@enumToInt(typ),
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Create a single texture.
|
/// Create a single texture.
|
||||||
|
Reference in New Issue
Block a user