c6a25e27
Add Atlas.reset and Face.reinit for scale changes
a73x 2026-04-09 10:19
Commit message
src/font.zig
| Old | New | ||
|---|---|---|---|
| @@ -85,6 +85,25 @@ pub const Face = struct { | |||
| 85 | _ = c.FT_Done_FreeType(self.library); | 85 | _ = c.FT_Done_FreeType(self.library); |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | pub fn reinit( | ||
| 89 | self: *Face, | ||
| 90 | path: [:0]const u8, | ||
| 91 | index: c_int, | ||
| 92 | px_size: u32, | ||
| 93 | ) !void { | ||
| 94 | _ = c.FT_Done_Face(self.face); | ||
| 95 | self.face = null; | ||
| 96 | |||
| 97 | var new_face: c.FT_Face = null; | ||
| 98 | if (c.FT_New_Face(self.library, path.ptr, index, &new_face) != 0) return error.FtNewFaceFailed; | ||
| 99 | errdefer _ = c.FT_Done_Face(new_face); | ||
| 100 | |||
| 101 | if (c.FT_Set_Pixel_Sizes(new_face, 0, px_size) != 0) return error.FtSetPixelSizesFailed; | ||
| 102 | |||
| 103 | self.face = new_face; | ||
| 104 | self.px_size = px_size; | ||
| 105 | } | ||
| 106 | |||
| 88 | pub fn rasterize(self: *Face, codepoint: u21) !Glyph { | 107 | pub fn rasterize(self: *Face, codepoint: u21) !Glyph { |
| 89 | const glyph_index = c.FT_Get_Char_Index(self.face, codepoint); | 108 | const glyph_index = c.FT_Get_Char_Index(self.face, codepoint); |
| 90 | if (c.FT_Load_Glyph(self.face, glyph_index, c.FT_LOAD_RENDER) != 0) { | 109 | if (c.FT_Load_Glyph(self.face, glyph_index, c.FT_LOAD_RENDER) != 0) { |
| @@ -191,6 +210,16 @@ pub const Atlas = struct { | |||
| 191 | self.cache.deinit(); | 210 | self.cache.deinit(); |
| 192 | } | 211 | } |
| 193 | 212 | ||
| 213 | pub fn reset(self: *Atlas) void { | ||
| 214 | @memset(self.pixels, 0); | ||
| 215 | self.pixels[0] = 255; | ||
| 216 | self.cursor_x = 1; | ||
| 217 | self.cursor_y = 0; | ||
| 218 | self.row_height = 1; | ||
| 219 | self.cache.clearRetainingCapacity(); | ||
| 220 | self.dirty = true; | ||
| 221 | } | ||
| 222 | |||
| 194 | pub fn cursorUV(self: *const Atlas) GlyphUV { | 223 | pub fn cursorUV(self: *const Atlas) GlyphUV { |
| 195 | return .{ | 224 | return .{ |
| 196 | .u0 = 0, | 225 | .u0 = 0, |
| @@ -301,3 +330,39 @@ test "Atlas reserves a white pixel for cursor rendering" { | |||
| 301 | try std.testing.expectEqual(@as(f32, 0), uv.u0); | 330 | try std.testing.expectEqual(@as(f32, 0), uv.u0); |
| 302 | try std.testing.expectEqual(@as(f32, 0), uv.v0); | 331 | try std.testing.expectEqual(@as(f32, 0), uv.v0); |
| 303 | } | 332 | } |
| 333 | |||
| 334 | test "Atlas.reset clears cache and starts fresh" { | ||
| 335 | var lookup = try lookupConfiguredFont(std.testing.allocator); | ||
| 336 | defer lookup.deinit(std.testing.allocator); | ||
| 337 | |||
| 338 | var face = try Face.init(std.testing.allocator, lookup.path, lookup.index, 14); | ||
| 339 | defer face.deinit(); | ||
| 340 | |||
| 341 | var atlas = try Atlas.init(std.testing.allocator, 256, 256); | ||
| 342 | defer atlas.deinit(); | ||
| 343 | |||
| 344 | _ = try atlas.getOrInsert(&face, 'A'); | ||
| 345 | try std.testing.expect(atlas.cache.count() > 0); | ||
| 346 | |||
| 347 | atlas.reset(); | ||
| 348 | try std.testing.expectEqual(@as(u32, 0), atlas.cache.count()); | ||
| 349 | try std.testing.expectEqual(@as(u8, 255), atlas.pixels[0]); | ||
| 350 | try std.testing.expect(atlas.dirty); | ||
| 351 | |||
| 352 | // Re-inserting the same glyph should succeed after reset. | ||
| 353 | _ = try atlas.getOrInsert(&face, 'A'); | ||
| 354 | } | ||
| 355 | |||
| 356 | test "Face.reinit switches px_size and produces different cell metrics" { | ||
| 357 | var lookup = try lookupConfiguredFont(std.testing.allocator); | ||
| 358 | defer lookup.deinit(std.testing.allocator); | ||
| 359 | |||
| 360 | var face = try Face.init(std.testing.allocator, lookup.path, lookup.index, 14); | ||
| 361 | defer face.deinit(); | ||
| 362 | const small_cell = face.cellWidth(); | ||
| 363 | |||
| 364 | try face.reinit(lookup.path, lookup.index, 28); | ||
| 365 | const large_cell = face.cellWidth(); | ||
| 366 | |||
| 367 | try std.testing.expect(large_cell > small_cell); | ||
| 368 | } | ||