renderer: font size changed event, OpenGL impl

This commit is contained in:
Mitchell Hashimoto
2022-11-15 19:48:32 -08:00
parent 6ec5684c27
commit 657c8540c8
4 changed files with 84 additions and 21 deletions

View File

@ -156,22 +156,15 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL {
var shaper = try font.Shaper.init(shape_buf); var shaper = try font.Shaper.init(shape_buf);
errdefer shaper.deinit(); errdefer shaper.deinit();
// Get our cell metrics based on a regular font ascii 'M'. Why 'M'?
// Doesn't matter, any normal ASCII will do we're just trying to make
// sure we use the regular font.
const metrics = metrics: {
const index = (try options.font_group.indexForCodepoint(alloc, 'M', .regular, .text)).?;
const face = try options.font_group.group.faceFromIndex(index);
break :metrics face.metrics;
};
log.debug("cell dimensions={}", .{metrics});
// Create our shader // Create our shader
const program = try gl.Program.createVF( const program = try gl.Program.createVF(
@embedFile("shaders/cell.v.glsl"), @embedFile("shaders/cell.v.glsl"),
@embedFile("shaders/cell.f.glsl"), @embedFile("shaders/cell.f.glsl"),
); );
// Setup our font metrics uniform
const metrics = try resetFontMetrics(alloc, program, options.font_group);
// Set our cell dimensions // Set our cell dimensions
const pbind = try program.use(); const pbind = try program.use();
defer pbind.unbind(); defer pbind.unbind();
@ -314,21 +307,26 @@ pub fn deinit(self: *OpenGL) void {
self.vao.destroy(); self.vao.destroy();
self.program.destroy(); self.program.destroy();
{ self.resetCellsLRU();
// Our LRU values are array lists so we need to deallocate those first self.cells_lru.deinit(self.alloc);
var it = self.cells_lru.queue.first;
while (it) |node| {
it = node.next;
node.data.value.deinit(self.alloc);
}
self.cells_lru.deinit(self.alloc);
}
self.cells.deinit(self.alloc); self.cells.deinit(self.alloc);
self.* = undefined; self.* = undefined;
} }
fn resetCellsLRU(self: *OpenGL) void {
// Our LRU values are array lists so we need to deallocate those first
var it = self.cells_lru.queue.first;
while (it) |node| {
it = node.next;
node.data.value.deinit(self.alloc);
}
self.cells_lru.deinit(self.alloc);
// Initialize our new LRU
self.cells_lru = CellsLRU.init(0);
}
/// Returns the hints that we want for this /// Returns the hints that we want for this
pub fn windowHints() glfw.Window.Hints { pub fn windowHints() glfw.Window.Hints {
return .{ return .{
@ -448,15 +446,69 @@ pub fn threadExit(self: *const OpenGL) void {
} }
/// Callback when the focus changes for the terminal this is rendering. /// Callback when the focus changes for the terminal this is rendering.
///
/// Must be called on the render thread.
pub fn setFocus(self: *OpenGL, focus: bool) !void { pub fn setFocus(self: *OpenGL, focus: bool) !void {
self.focused = focus; self.focused = focus;
} }
/// Called to toggle the blink state of the cursor /// Called to toggle the blink state of the cursor
///
/// Must be called on the render thread.
pub fn blinkCursor(self: *OpenGL, reset: bool) void { pub fn blinkCursor(self: *OpenGL, reset: bool) void {
self.cursor_visible = reset or !self.cursor_visible; self.cursor_visible = reset or !self.cursor_visible;
} }
/// Set the new font size.
///
/// Must be called on the render thread.
pub fn setFontSize(self: *OpenGL, size: font.face.DesiredSize) !void {
// Set our new size, this will also reset our font atlas.
try self.font_group.setSize(size);
// Invalidate our cell cache.
self.resetCellsLRU();
// Reset our GPU uniforms
const metrics = try resetFontMetrics(self.alloc, self.program, self.font_group);
// Recalculate our cell size. If it is the same as before, then we do
// nothing since the grid size couldn't have possibly changed.
const new_cell_size = .{ .width = metrics.cell_width, .height = metrics.cell_height };
if (std.meta.eql(self.cell_size, new_cell_size)) return;
// Notify the window that the cell size changed.
}
/// Reload the font metrics, recalculate cell size, and send that all
/// down to the GPU.
fn resetFontMetrics(
alloc: Allocator,
program: gl.Program,
font_group: *font.GroupCache,
) !font.face.Metrics {
// Get our cell metrics based on a regular font ascii 'M'. Why 'M'?
// Doesn't matter, any normal ASCII will do we're just trying to make
// sure we use the regular font.
const metrics = metrics: {
const index = (try font_group.indexForCodepoint(alloc, 'M', .regular, .text)).?;
const face = try font_group.group.faceFromIndex(index);
break :metrics face.metrics;
};
log.debug("cell dimensions={}", .{metrics});
// Set our uniforms that rely on metrics
const pbind = try program.use();
defer pbind.unbind();
try program.setUniform("cell_size", @Vector(2, f32){ metrics.cell_width, metrics.cell_height });
try program.setUniform("underline_position", metrics.underline_position);
try program.setUniform("underline_thickness", metrics.underline_thickness);
try program.setUniform("strikethrough_position", metrics.strikethrough_position);
try program.setUniform("strikethrough_thickness", metrics.strikethrough_thickness);
return metrics;
}
/// The primary render callback that is completely thread-safe. /// The primary render callback that is completely thread-safe.
pub fn render( pub fn render(
self: *OpenGL, self: *OpenGL,
@ -946,7 +998,7 @@ pub fn updateCell(
/// Returns the grid size for a given screen size. This is safe to call /// Returns the grid size for a given screen size. This is safe to call
/// on any thread. /// on any thread.
pub fn gridSize(self: *OpenGL, screen_size: renderer.ScreenSize) renderer.GridSize { fn gridSize(self: *OpenGL, screen_size: renderer.ScreenSize) renderer.GridSize {
return renderer.GridSize.init( return renderer.GridSize.init(
screen_size.subPadding(self.padding.explicit), screen_size.subPadding(self.padding.explicit),
self.cell_size, self.cell_size,

View File

@ -275,6 +275,10 @@ fn drainMailbox(self: *Thread) !void {
_ = try self.cursor_h.again(); _ = try self.cursor_h.again();
} }
}, },
.font_size => |size| {
try self.renderer.setFontSize(size);
},
} }
} }
} }

View File

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const font = @import("../font/main.zig");
/// The messages that can be sent to a renderer thread. /// The messages that can be sent to a renderer thread.
pub const Message = union(enum) { pub const Message = union(enum) {
@ -12,4 +13,9 @@ pub const Message = union(enum) {
/// Reset the cursor blink by immediately showing the cursor then /// Reset the cursor blink by immediately showing the cursor then
/// restarting the timer. /// restarting the timer.
reset_cursor_blink: void, reset_cursor_blink: void,
/// Change the font size. This should recalculate the grid size and
/// send a grid size change message back to the window thread if
/// the size changes.
font_size: font.face.DesiredSize,
}; };

View File

@ -1,5 +1,6 @@
const App = @import("../App.zig"); const App = @import("../App.zig");
const Window = @import("../Window.zig"); const Window = @import("../Window.zig");
const renderer = @import("../renderer.zig");
/// The message types that can be sent to a single window. /// The message types that can be sent to a single window.
pub const Message = union(enum) { pub const Message = union(enum) {