diff --git a/src/FontAtlas.zig b/src/FontAtlas.zig index 0ade9e460..d4dd4d691 100644 --- a/src/FontAtlas.zig +++ b/src/FontAtlas.zig @@ -123,10 +123,13 @@ pub fn addGlyph(self: *FontAtlas, alloc: Allocator, v: anytype) !*Glyph { errdefer _ = self.glyphs.remove(utf32); const glyph_index = glyph_index: { + // log.warn("glyph load: {x}", .{utf32}); const idx = ftc.FT_Get_Char_Index(self.ft_face, utf32); if (idx > 0) break :glyph_index idx; // Unknown glyph. + log.warn("glyph not found: {x}", .{utf32}); + // TODO: render something more identifiable than a space 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), }; - //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; } diff --git a/src/Grid.zig b/src/Grid.zig index ae9a46f89..a3c127e31 100644 --- a/src/Grid.zig +++ b/src/Grid.zig @@ -34,6 +34,7 @@ texture: gl.Texture, /// The font atlas. font_atlas: FontAtlas, +atlas_dirty: bool, /// Whether the cursor is visible or not. This is used to control cursor /// blinking. @@ -220,6 +221,7 @@ pub fn init(alloc: Allocator) !Grid { .vbo = vbo, .texture = tex, .font_atlas = font, + .atlas_dirty = false, .cursor_visible = true, .cursor_style = .box, .foreground = .{ .r = 255, .g = 255, .b = 255 }, @@ -238,27 +240,6 @@ pub fn deinit(self: *Grid) void { 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. /// The updated cells will take effect on the next render. pub fn updateCells(self: *Grid, term: Terminal) !void { @@ -307,7 +288,12 @@ pub fn updateCells(self: *Grid, term: Terminal) !void { // Get our glyph // 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; 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 }); } +/// 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 { const t = trace(@src()); defer t.end(); diff --git a/src/Window.zig b/src/Window.zig index ccab59479..513ac44ee 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -499,6 +499,9 @@ fn renderTimerCallback(t: *libuv.Timer) void { // Update the cells for drawing win.grid.updateCells(win.terminal) catch unreachable; + // Update our texture if we have to + win.grid.flushAtlas() catch unreachable; + // Set our background gl.clearColor(win.bg_r, win.bg_g, win.bg_b, win.bg_a); gl.clear(gl.c.GL_COLOR_BUFFER_BIT); diff --git a/src/opengl/Texture.zig b/src/opengl/Texture.zig index 566d54a4e..810a15c3c 100644 --- a/src/opengl/Texture.zig +++ b/src/opengl/Texture.zig @@ -114,6 +114,30 @@ pub const Binding = struct { 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.