diff --git a/src/font/sprite/Box.zig b/src/font/sprite/Box.zig index ba7caa26a..2cd3d929b 100644 --- a/src/font/sprite/Box.zig +++ b/src/font/sprite/Box.zig @@ -184,6 +184,10 @@ const SmoothMosaic = packed struct(u10) { } }; +// Octant range, inclusive +const octant_min = 0x1cd00; +const octant_max = 0x1cde5; + // Utility names for common fractions const one_eighth: f64 = 0.125; const one_quarter: f64 = 0.25; @@ -581,6 +585,8 @@ fn draw(self: Box, alloc: Allocator, canvas: *font.sprite.Canvas, cp: u32) !void 0x1fb00...0x1fb3b => self.draw_sextant(canvas, cp), + octant_min...octant_max => self.draw_octant(canvas, cp), + // '🬼' 0x1fb3c => try self.draw_smooth_mosaic(canvas, SmoothMosaic.from( \\... @@ -2484,6 +2490,65 @@ fn draw_sextant(self: Box, canvas: *font.sprite.Canvas, cp: u32) void { if (sex.br) self.rect(canvas, x_halfs[1], y_thirds[1], self.metrics.cell_width, self.metrics.cell_height); } +fn draw_octant(self: Box, canvas: *font.sprite.Canvas, cp: u32) void { + assert(cp >= octant_min and cp <= octant_max); + + // Octant representation. We use the funny numeric string keys + // so its easier to parse the actual name used in the Symbols for + // Legacy Computing spec. + const Octant = packed struct(u8) { + @"1": bool = false, + @"2": bool = false, + @"3": bool = false, + @"4": bool = false, + @"5": bool = false, + @"6": bool = false, + @"7": bool = false, + @"8": bool = false, + }; + + // Parse the octant data. This is all done at comptime so this is + // static data that is embedded in the binary. + const octants_len = octant_max - octant_min + 1; + const octants: [octants_len]Octant = comptime octants: { + @setEvalBranchQuota(10_000); + + var result: [octants_len]Octant = .{.{}} ** octants_len; + var i: usize = 0; + + const data = @embedFile("octants.txt"); + var it = std.mem.splitScalar(u8, data, '\n'); + while (it.next()) |line| { + // Skip comments + if (line.len == 0 or line[0] == '#') continue; + + const current = &result[i]; + i += 1; + + // Octants are in the format "BLOCK OCTANT-1235". The numbers + // at the end are keys into our packed struct. Since we're + // at comptime we can metaprogram it all. + const idx = std.mem.indexOfScalar(u8, line, '-').?; + for (line[idx + 1 ..]) |c| @field(current, &.{c}) = true; + } + + assert(i == octants_len); + break :octants result; + }; + + const x_halfs = self.xHalfs(); + const y_quads = self.yQuads(); + const oct = octants[cp - octant_min]; + if (oct.@"1") self.rect(canvas, 0, 0, x_halfs[0], y_quads[0]); + if (oct.@"2") self.rect(canvas, x_halfs[1], 0, self.metrics.cell_width, y_quads[0]); + if (oct.@"3") self.rect(canvas, 0, y_quads[0], x_halfs[0], y_quads[1]); + if (oct.@"4") self.rect(canvas, x_halfs[1], y_quads[0], self.metrics.cell_width, y_quads[1]); + if (oct.@"5") self.rect(canvas, 0, y_quads[1], x_halfs[0], y_quads[2]); + if (oct.@"6") self.rect(canvas, x_halfs[1], y_quads[1], self.metrics.cell_width, y_quads[2]); + if (oct.@"7") self.rect(canvas, 0, y_quads[2], x_halfs[0], self.metrics.cell_height); + if (oct.@"8") self.rect(canvas, x_halfs[1], y_quads[2], self.metrics.cell_width, self.metrics.cell_height); +} + fn xHalfs(self: Box) [2]u32 { return .{ @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.metrics.cell_width)) / 2))), @@ -2500,6 +2565,21 @@ fn yThirds(self: Box) [2]u32 { }; } +// assume octants might be striped across multiple rows of cells. to maximize +// distance between excess pixellines, we want (1) an arbitrary region (there +// will be a pattern of 1'-3-1'-3-1'-3 no matter what), (2) discontiguous +// regions (0 and 2 or 1 and 3), and (3) an arbitrary three regions (there will +// be a pattern of 3-1-3-1-3-1 no matter what). +fn yQuads(self: Box) [3]u32 { + return switch (@mod(self.metrics.cell_height, 4)) { + 0 => .{ self.metrics.cell_height / 4, 2 * self.metrics.cell_height / 4, 3 * self.metrics.cell_height / 4 }, + 1 => .{ self.metrics.cell_height / 4, 2 * self.metrics.cell_height / 4 + 1, 3 * self.metrics.cell_height / 4 }, + 2 => .{ self.metrics.cell_height / 4 + 1, 2 * self.metrics.cell_height / 4, 3 * self.metrics.cell_height / 4 + 1 }, + 3 => .{ self.metrics.cell_height / 4 + 1, 2 * self.metrics.cell_height / 4 + 1, 3 * self.metrics.cell_height / 4 }, + else => unreachable, + }; +} + fn draw_smooth_mosaic( self: Box, canvas: *font.sprite.Canvas, @@ -3064,7 +3144,7 @@ fn testRenderAll(self: Box, alloc: Allocator, atlas: *font.Atlas) !void { ); } - // Symbols for Legacy Computing Supplement. + // Symbols for Legacy Computing Supplement: Quadrants // 𜰡 𜰢 𜰣 𜰤 𜰥 𜰦 𜰧 𜰨 𜰩 𜰪 𜰫 𜰬 𜰭 𜰮 𜰯 cp = 0x1cc21; while (cp <= 0x1cc2f) : (cp += 1) { @@ -3077,6 +3157,19 @@ fn testRenderAll(self: Box, alloc: Allocator, atlas: *font.Atlas) !void { else => {}, } } + + // Symbols for Legacy Computing Supplement: Octants + cp = 0x1CD00; + while (cp <= 0x1CDE5) : (cp += 1) { + switch (cp) { + 0x1CD00...0x1CDE5 => _ = try self.renderGlyph( + alloc, + atlas, + cp, + ), + else => {}, + } + } } test "render all sprites" { diff --git a/src/font/sprite/Face.zig b/src/font/sprite/Face.zig index cebf44429..f15423ada 100644 --- a/src/font/sprite/Face.zig +++ b/src/font/sprite/Face.zig @@ -236,6 +236,8 @@ const Kind = enum { // (Geometric Shapes) // 🯠 🯡 🯢 🯣 🯤 🯥 🯦 🯧 🯨 🯩 🯪 🯫 🯬 🯭 🯮 🯯 0x1FBCE...0x1FBEF, + // (Octants) + 0x1CD00...0x1CDE5, => .box, // Branch drawing character set, used for drawing git-like diff --git a/src/font/sprite/octants.txt b/src/font/sprite/octants.txt new file mode 100644 index 000000000..db79aa2c6 --- /dev/null +++ b/src/font/sprite/octants.txt @@ -0,0 +1,234 @@ +# This is the list of all the octants for the Symbols for Legacy +# Computing block. It is used at comptime to generate the lookup +# table for drawing them since we weren't able to discern a +# mathematical pattern for them. +BLOCK OCTANT-3 +BLOCK OCTANT-23 +BLOCK OCTANT-123 +BLOCK OCTANT-4 +BLOCK OCTANT-14 +BLOCK OCTANT-124 +BLOCK OCTANT-34 +BLOCK OCTANT-134 +BLOCK OCTANT-234 +BLOCK OCTANT-5 +BLOCK OCTANT-15 +BLOCK OCTANT-25 +BLOCK OCTANT-125 +BLOCK OCTANT-135 +BLOCK OCTANT-235 +BLOCK OCTANT-1235 +BLOCK OCTANT-45 +BLOCK OCTANT-145 +BLOCK OCTANT-245 +BLOCK OCTANT-1245 +BLOCK OCTANT-345 +BLOCK OCTANT-1345 +BLOCK OCTANT-2345 +BLOCK OCTANT-12345 +BLOCK OCTANT-6 +BLOCK OCTANT-16 +BLOCK OCTANT-26 +BLOCK OCTANT-126 +BLOCK OCTANT-36 +BLOCK OCTANT-136 +BLOCK OCTANT-236 +BLOCK OCTANT-1236 +BLOCK OCTANT-146 +BLOCK OCTANT-246 +BLOCK OCTANT-1246 +BLOCK OCTANT-346 +BLOCK OCTANT-1346 +BLOCK OCTANT-2346 +BLOCK OCTANT-12346 +BLOCK OCTANT-56 +BLOCK OCTANT-156 +BLOCK OCTANT-256 +BLOCK OCTANT-1256 +BLOCK OCTANT-356 +BLOCK OCTANT-1356 +BLOCK OCTANT-2356 +BLOCK OCTANT-12356 +BLOCK OCTANT-456 +BLOCK OCTANT-1456 +BLOCK OCTANT-2456 +BLOCK OCTANT-12456 +BLOCK OCTANT-3456 +BLOCK OCTANT-13456 +BLOCK OCTANT-23456 +BLOCK OCTANT-17 +BLOCK OCTANT-27 +BLOCK OCTANT-127 +BLOCK OCTANT-37 +BLOCK OCTANT-137 +BLOCK OCTANT-237 +BLOCK OCTANT-1237 +BLOCK OCTANT-47 +BLOCK OCTANT-147 +BLOCK OCTANT-247 +BLOCK OCTANT-1247 +BLOCK OCTANT-347 +BLOCK OCTANT-1347 +BLOCK OCTANT-2347 +BLOCK OCTANT-12347 +BLOCK OCTANT-157 +BLOCK OCTANT-257 +BLOCK OCTANT-1257 +BLOCK OCTANT-357 +BLOCK OCTANT-2357 +BLOCK OCTANT-12357 +BLOCK OCTANT-457 +BLOCK OCTANT-1457 +BLOCK OCTANT-12457 +BLOCK OCTANT-3457 +BLOCK OCTANT-13457 +BLOCK OCTANT-23457 +BLOCK OCTANT-67 +BLOCK OCTANT-167 +BLOCK OCTANT-267 +BLOCK OCTANT-1267 +BLOCK OCTANT-367 +BLOCK OCTANT-1367 +BLOCK OCTANT-2367 +BLOCK OCTANT-12367 +BLOCK OCTANT-467 +BLOCK OCTANT-1467 +BLOCK OCTANT-2467 +BLOCK OCTANT-12467 +BLOCK OCTANT-3467 +BLOCK OCTANT-13467 +BLOCK OCTANT-23467 +BLOCK OCTANT-123467 +BLOCK OCTANT-567 +BLOCK OCTANT-1567 +BLOCK OCTANT-2567 +BLOCK OCTANT-12567 +BLOCK OCTANT-3567 +BLOCK OCTANT-13567 +BLOCK OCTANT-23567 +BLOCK OCTANT-123567 +BLOCK OCTANT-4567 +BLOCK OCTANT-14567 +BLOCK OCTANT-24567 +BLOCK OCTANT-124567 +BLOCK OCTANT-34567 +BLOCK OCTANT-134567 +BLOCK OCTANT-234567 +BLOCK OCTANT-1234567 +BLOCK OCTANT-18 +BLOCK OCTANT-28 +BLOCK OCTANT-128 +BLOCK OCTANT-38 +BLOCK OCTANT-138 +BLOCK OCTANT-238 +BLOCK OCTANT-1238 +BLOCK OCTANT-48 +BLOCK OCTANT-148 +BLOCK OCTANT-248 +BLOCK OCTANT-1248 +BLOCK OCTANT-348 +BLOCK OCTANT-1348 +BLOCK OCTANT-2348 +BLOCK OCTANT-12348 +BLOCK OCTANT-58 +BLOCK OCTANT-158 +BLOCK OCTANT-258 +BLOCK OCTANT-1258 +BLOCK OCTANT-358 +BLOCK OCTANT-1358 +BLOCK OCTANT-2358 +BLOCK OCTANT-12358 +BLOCK OCTANT-458 +BLOCK OCTANT-1458 +BLOCK OCTANT-2458 +BLOCK OCTANT-12458 +BLOCK OCTANT-3458 +BLOCK OCTANT-13458 +BLOCK OCTANT-23458 +BLOCK OCTANT-123458 +BLOCK OCTANT-168 +BLOCK OCTANT-268 +BLOCK OCTANT-1268 +BLOCK OCTANT-368 +BLOCK OCTANT-2368 +BLOCK OCTANT-12368 +BLOCK OCTANT-468 +BLOCK OCTANT-1468 +BLOCK OCTANT-12468 +BLOCK OCTANT-3468 +BLOCK OCTANT-13468 +BLOCK OCTANT-23468 +BLOCK OCTANT-568 +BLOCK OCTANT-1568 +BLOCK OCTANT-2568 +BLOCK OCTANT-12568 +BLOCK OCTANT-3568 +BLOCK OCTANT-13568 +BLOCK OCTANT-23568 +BLOCK OCTANT-123568 +BLOCK OCTANT-4568 +BLOCK OCTANT-14568 +BLOCK OCTANT-24568 +BLOCK OCTANT-124568 +BLOCK OCTANT-34568 +BLOCK OCTANT-134568 +BLOCK OCTANT-234568 +BLOCK OCTANT-1234568 +BLOCK OCTANT-178 +BLOCK OCTANT-278 +BLOCK OCTANT-1278 +BLOCK OCTANT-378 +BLOCK OCTANT-1378 +BLOCK OCTANT-2378 +BLOCK OCTANT-12378 +BLOCK OCTANT-478 +BLOCK OCTANT-1478 +BLOCK OCTANT-2478 +BLOCK OCTANT-12478 +BLOCK OCTANT-3478 +BLOCK OCTANT-13478 +BLOCK OCTANT-23478 +BLOCK OCTANT-123478 +BLOCK OCTANT-578 +BLOCK OCTANT-1578 +BLOCK OCTANT-2578 +BLOCK OCTANT-12578 +BLOCK OCTANT-3578 +BLOCK OCTANT-13578 +BLOCK OCTANT-23578 +BLOCK OCTANT-123578 +BLOCK OCTANT-4578 +BLOCK OCTANT-14578 +BLOCK OCTANT-24578 +BLOCK OCTANT-124578 +BLOCK OCTANT-34578 +BLOCK OCTANT-134578 +BLOCK OCTANT-234578 +BLOCK OCTANT-1234578 +BLOCK OCTANT-678 +BLOCK OCTANT-1678 +BLOCK OCTANT-2678 +BLOCK OCTANT-12678 +BLOCK OCTANT-3678 +BLOCK OCTANT-13678 +BLOCK OCTANT-23678 +BLOCK OCTANT-123678 +BLOCK OCTANT-4678 +BLOCK OCTANT-14678 +BLOCK OCTANT-24678 +BLOCK OCTANT-124678 +BLOCK OCTANT-34678 +BLOCK OCTANT-134678 +BLOCK OCTANT-234678 +BLOCK OCTANT-1234678 +BLOCK OCTANT-15678 +BLOCK OCTANT-25678 +BLOCK OCTANT-125678 +BLOCK OCTANT-35678 +BLOCK OCTANT-235678 +BLOCK OCTANT-1235678 +BLOCK OCTANT-45678 +BLOCK OCTANT-145678 +BLOCK OCTANT-1245678 +BLOCK OCTANT-1345678 +BLOCK OCTANT-2345678 diff --git a/src/font/sprite/testdata/Box.ppm b/src/font/sprite/testdata/Box.ppm index 36519a1e9..0feb3ebe4 100644 Binary files a/src/font/sprite/testdata/Box.ppm and b/src/font/sprite/testdata/Box.ppm differ