Even More Sprite Glyphs (#7761)

Follow-on to #7755, adds the sixteenth blocks from the Symbols for
Legacy Computing Supplement and a few circle/ellipse glyphs that connect
to existing glyphs.

In order to add the one sixteenth blocks I reworked block element
alignment to not use the `yHalfs`, `yThirds`, etc. functions, but
instead a more versatile `Fraction` type I introduced, and making these
changes slightly affected how the vertical/horizontal eighths glyphs are
sized, and the horizontal center-point alignment of the smooth mosaic
glyphs for odd cell widths (shifted by half a pixel), but I believe both
of these to be improvements.

### Circle/ellipse glyphs
```
Existing sprites:
🯠 🯡 🯢 🯣

Which connect like so:
🯢🯡🯣
🯠

New sprites:
𜸀 𜸁 𜸋 𜸌

Which connect like so:
🯡𜸀𜸀🯣 🯢 𜸋𜸌
    𜸁
    𜸁
    🯠
```
|Main (via font)|This PR (via sprites)|
|-|-|
|![image](https://github.com/user-attachments/assets/b0102f7e-1cb3-4842-a8c6-352df6d5264f)|![image](https://github.com/user-attachments/assets/9a35d444-39ff-41e1-a632-597f195090a8)|

### Diffs
|Range|||||
|-|-|-|-|-|
|U+1CE00...U+1CEFF|![sprite_face_diff-U+1CE00 U+1CEFF-9x17+1](https://github.com/user-attachments/assets/632daca9-9d1e-458b-b645-3841de9f4915)|![sprite_face_diff-U+1CE00 U+1CEFF-11x21+2](https://github.com/user-attachments/assets/47731d99-9e1a-4005-a56c-dc9af3c38160)|![sprite_face_diff-U+1CE00 U+1CEFF-12x24+3](https://github.com/user-attachments/assets/2a4fd0d7-4114-480d-91e8-f8182ef0ff2b)|![sprite_face_diff-U+1CE00 U+1CEFF-18x36+4](https://github.com/user-attachments/assets/17b886b8-ad6d-4503-85dd-10ea2f734c09)|
|U+1FB00...U+1FBFF|![sprite_face_diff-U+1FB00 U+1FBFF-9x17+1](https://github.com/user-attachments/assets/c24814ea-67ef-4030-819b-a3f3d6ddac0c)|![sprite_face_diff-U+1FB00 U+1FBFF-11x21+2](https://github.com/user-attachments/assets/354ebadf-5d9c-4681-86c8-f6c21f82932e)|![sprite_face_diff-U+1FB00 U+1FBFF-12x24+3](https://github.com/user-attachments/assets/9fbb2c21-9ccd-466c-9bde-b8ce63e5df8b)|![sprite_face_diff-U+1FB00 U+1FBFF-18x36+4](https://github.com/user-attachments/assets/f76866ab-21c4-43b8-a591-009c4399ce17)|
pull/7783/head
Qwerasd 2025-07-01 17:42:51 -06:00 committed by GitHub
commit 776d25b065
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 407 additions and 185 deletions

View File

@ -15,9 +15,7 @@ const common = @import("common.zig");
const Shade = common.Shade; const Shade = common.Shade;
const Quads = common.Quads; const Quads = common.Quads;
const Alignment = common.Alignment; const Alignment = common.Alignment;
const xHalfs = common.xHalfs; const fill = common.fill;
const yHalfs = common.yHalfs;
const rect = common.rect;
const font = @import("../../main.zig"); const font = @import("../../main.zig");
const Sprite = @import("../../sprite.zig").Sprite; const Sprite = @import("../../sprite.zig").Sprite;
@ -176,11 +174,8 @@ fn quadrant(
canvas: *font.sprite.Canvas, canvas: *font.sprite.Canvas,
comptime quads: Quads, comptime quads: Quads,
) void { ) void {
const x_halfs = xHalfs(metrics); if (quads.tl) fill(metrics, canvas, .zero, .half, .zero, .half);
const y_halfs = yHalfs(metrics); if (quads.tr) fill(metrics, canvas, .half, .full, .zero, .half);
if (quads.bl) fill(metrics, canvas, .zero, .half, .half, .full);
if (quads.tl) rect(metrics, canvas, 0, 0, x_halfs[0], y_halfs[0]); if (quads.br) fill(metrics, canvas, .half, .full, .half, .full);
if (quads.tr) rect(metrics, canvas, x_halfs[1], 0, metrics.cell_width, y_halfs[0]);
if (quads.bl) rect(metrics, canvas, 0, y_halfs[1], x_halfs[0], metrics.cell_height);
if (quads.br) rect(metrics, canvas, x_halfs[1], y_halfs[1], metrics.cell_width, metrics.cell_height);
} }

View File

@ -24,7 +24,6 @@ const Quads = common.Quads;
const Corner = common.Corner; const Corner = common.Corner;
const Edge = common.Edge; const Edge = common.Edge;
const Alignment = common.Alignment; const Alignment = common.Alignment;
const rect = common.rect;
const hline = common.hline; const hline = common.hline;
const vline = common.vline; const vline = common.vline;
const hlineMiddle = common.hlineMiddle; const hlineMiddle = common.hlineMiddle;
@ -695,20 +694,6 @@ pub fn lightDiagonalCross(
lightDiagonalUpperLeftToLowerRight(metrics, canvas); lightDiagonalUpperLeftToLowerRight(metrics, canvas);
} }
fn quadrant(
metrics: font.Metrics,
canvas: *font.sprite.Canvas,
comptime quads: Quads,
) void {
const center_x = metrics.cell_width / 2 + metrics.cell_width % 2;
const center_y = metrics.cell_height / 2 + metrics.cell_height % 2;
if (quads.tl) rect(metrics, canvas, 0, 0, center_x, center_y);
if (quads.tr) rect(metrics, canvas, center_x, 0, metrics.cell_width, center_y);
if (quads.bl) rect(metrics, canvas, 0, center_y, center_x, metrics.cell_height);
if (quads.br) rect(metrics, canvas, center_x, center_y, metrics.cell_width, metrics.cell_height);
}
pub fn arc( pub fn arc(
metrics: font.Metrics, metrics: font.Metrics,
canvas: *font.sprite.Canvas, canvas: *font.sprite.Canvas,

View File

@ -122,22 +122,203 @@ pub const Alignment = struct {
pub const bottom_right = lower_right; pub const bottom_right = lower_right;
}; };
/// Fill a rect, clamped to within the cell boundaries. /// A value that indicates some fraction across
/// the cell either horizontally or vertically.
/// ///
/// TODO: Eliminate usages of this, prefer `canvas.box`. /// This has some redundant names in it so that you can
pub fn rect( /// use whichever one feels most semantically appropriate.
pub const Fraction = enum {
// Names for the min edge
start,
left,
top,
zero,
// Names based on eighths
eighth,
one_eighth,
two_eighths,
three_eighths,
four_eighths,
five_eighths,
six_eighths,
seven_eighths,
// Names based on quarters
quarter,
one_quarter,
two_quarters,
three_quarters,
// Names based on thirds
third,
one_third,
two_thirds,
// Names based on halves
half,
one_half,
// Alternative names for 1/2
center,
middle,
// Names for the max edge
end,
right,
bottom,
one,
full,
/// This can be indexed to get the fraction for `i/8`.
pub const eighths: [9]Fraction = .{
.zero,
.one_eighth,
.two_eighths,
.three_eighths,
.four_eighths,
.five_eighths,
.six_eighths,
.seven_eighths,
.one,
};
/// This can be indexed to get the fraction for `i/4`.
pub const quarters: [5]Fraction = .{
.zero,
.one_quarter,
.two_quarters,
.three_quarters,
.one,
};
/// This can be indexed to get the fraction for `i/3`.
pub const thirds: [4]Fraction = .{
.zero,
.one_third,
.two_thirds,
.one,
};
/// This can be indexed to get the fraction for `i/2`.
pub const halves: [3]Fraction = .{
.zero,
.one_half,
.one,
};
/// Get the x position for this fraction across a particular
/// size (width or height), assuming it will be used as the
/// min (left/top) coordinate for a block.
///
/// `size` can be any integer type, since it will be coerced
pub inline fn min(self: Fraction, size: anytype) i32 {
const s: f64 = @as(f64, @floatFromInt(size));
// For min coordinates, we want to align with the complementary
// fraction taken from the end, this ensures that rounding evens
// out, so that for example, if `size` is `7`, and we're looking
// at the `half` line, `size - round((1 - 0.5) * size)` => `3`;
// whereas the max coordinate directly rounds, which means that
// both `start` -> `half` and `half` -> `end` will be 4px, from
// `0` -> `4` and `3` -> `7`.
return @intFromFloat(s - @round((1.0 - self.fraction()) * s));
}
/// Get the x position for this fraction across a particular
/// size (width or height), assuming it will be used as the
/// max (right/bottom) coordinate for a block.
///
/// `size` can be any integer type, since it will be coerced
/// with `@floatFromInt`.
pub inline fn max(self: Fraction, size: anytype) i32 {
const s: f64 = @as(f64, @floatFromInt(size));
// See explanation of why these are different in `min`.
return @intFromFloat(@round(self.fraction() * s));
}
/// Get this fraction across a particular size (width/height).
/// If you need an integer, use `min` or `max` instead, since
/// they contain special logic for consistent alignment. This
/// is for when you're drawing with paths and don't care about
/// pixel alignment.
///
/// `size` can be any integer type, since it will be coerced
/// with `@floatFromInt`.
pub inline fn float(self: Fraction, size: anytype) f64 {
return self.fraction() * @as(f64, @floatFromInt(size));
}
/// Get a float for the fraction this represents.
pub inline fn fraction(self: Fraction) f64 {
return switch (self) {
.start,
.left,
.top,
.zero,
=> 0.0,
.eighth,
.one_eighth,
=> 0.125,
.quarter,
.one_quarter,
.two_eighths,
=> 0.25,
.third,
.one_third,
=> 1.0 / 3.0,
.three_eighths,
=> 0.375,
.half,
.one_half,
.two_quarters,
.four_eighths,
.center,
.middle,
=> 0.5,
.five_eighths,
=> 0.625,
.two_thirds,
=> 2.0 / 3.0,
.three_quarters,
.six_eighths,
=> 0.75,
.seven_eighths,
=> 0.875,
.end,
.right,
.bottom,
.one,
.full,
=> 1.0,
};
}
};
/// Fill a section of the cell, specified by a
/// horizontal and vertical pair of fraction lines.
pub fn fill(
metrics: font.Metrics, metrics: font.Metrics,
canvas: *font.sprite.Canvas, canvas: *font.sprite.Canvas,
x1: u32, x0: Fraction,
y1: u32, x1: Fraction,
x2: u32, y0: Fraction,
y2: u32, y1: Fraction,
) void { ) void {
canvas.box( canvas.box(
@intCast(@min(@max(x1, 0), metrics.cell_width)), x0.min(metrics.cell_width),
@intCast(@min(@max(y1, 0), metrics.cell_height)), y0.min(metrics.cell_height),
@intCast(@min(@max(x2, 0), metrics.cell_width)), x1.max(metrics.cell_width),
@intCast(@min(@max(y2, 0), metrics.cell_height)), y1.max(metrics.cell_height),
.on, .on,
); );
} }
@ -195,58 +376,3 @@ pub fn hline(
) void { ) void {
canvas.box(x1, y, x2, y + @as(i32, @intCast(thickness_px)), .on); canvas.box(x1, y, x2, y + @as(i32, @intCast(thickness_px)), .on);
} }
/// xHalfs[0] should be used as the right edge of a left-aligned half.
/// xHalfs[1] should be used as the left edge of a right-aligned half.
pub fn xHalfs(metrics: font.Metrics) [2]u32 {
const float_width: f64 = @floatFromInt(metrics.cell_width);
const half_width: u32 = @intFromFloat(@round(0.5 * float_width));
return .{ half_width, metrics.cell_width - half_width };
}
/// yHalfs[0] should be used as the bottom edge of a top-aligned half.
/// yHalfs[1] should be used as the top edge of a bottom-aligned half.
pub fn yHalfs(metrics: font.Metrics) [2]u32 {
const float_height: f64 = @floatFromInt(metrics.cell_height);
const half_height: u32 = @intFromFloat(@round(0.5 * float_height));
return .{ half_height, metrics.cell_height - half_height };
}
/// Use these values as such:
/// yThirds[0] bottom edge of the first third.
/// yThirds[1] top edge of the second third.
/// yThirds[2] bottom edge of the second third.
/// yThirds[3] top edge of the final third.
pub fn yThirds(metrics: font.Metrics) [4]u32 {
const float_height: f64 = @floatFromInt(metrics.cell_height);
const one_third_height: u32 = @intFromFloat(@round(one_third * float_height));
const two_thirds_height: u32 = @intFromFloat(@round(two_thirds * float_height));
return .{
one_third_height,
metrics.cell_height - two_thirds_height,
two_thirds_height,
metrics.cell_height - one_third_height,
};
}
/// Use these values as such:
/// yQuads[0] bottom edge of first quarter.
/// yQuads[1] top edge of second quarter.
/// yQuads[2] bottom edge of second quarter.
/// yQuads[3] top edge of third quarter.
/// yQuads[4] bottom edge of third quarter
/// yQuads[5] top edge of fourth quarter.
pub fn yQuads(metrics: font.Metrics) [6]u32 {
const float_height: f64 = @floatFromInt(metrics.cell_height);
const quarter_height: u32 = @intFromFloat(@round(0.25 * float_height));
const half_height: u32 = @intFromFloat(@round(0.50 * float_height));
const three_quarters_height: u32 = @intFromFloat(@round(0.75 * float_height));
return .{
quarter_height,
metrics.cell_height - three_quarters_height,
half_height,
metrics.cell_height - half_height,
three_quarters_height,
metrics.cell_height - quarter_height,
};
}

View File

@ -28,13 +28,12 @@ const z2d = @import("z2d");
const common = @import("common.zig"); const common = @import("common.zig");
const Thickness = common.Thickness; const Thickness = common.Thickness;
const Alignment = common.Alignment; const Alignment = common.Alignment;
const Fraction = common.Fraction;
const Corner = common.Corner; const Corner = common.Corner;
const Quads = common.Quads; const Quads = common.Quads;
const Edge = common.Edge; const Edge = common.Edge;
const Shade = common.Shade; const Shade = common.Shade;
const xHalfs = common.xHalfs; const fill = common.fill;
const yThirds = common.yThirds;
const rect = common.rect;
const box = @import("box.zig"); const box = @import("box.zig");
const block = @import("block.zig"); const block = @import("block.zig");
@ -121,16 +120,12 @@ pub fn draw1FB00_1FB3B(
const sex: Sextants = @bitCast(@as(u6, @intCast( const sex: Sextants = @bitCast(@as(u6, @intCast(
idx + (idx / 0x14) + 1, idx + (idx / 0x14) + 1,
))); )));
if (sex.tl) fill(metrics, canvas, .zero, .half, .zero, .one_third);
const x_halfs = xHalfs(metrics); if (sex.tr) fill(metrics, canvas, .half, .full, .zero, .one_third);
const y_thirds = yThirds(metrics); if (sex.ml) fill(metrics, canvas, .zero, .half, .one_third, .two_thirds);
if (sex.mr) fill(metrics, canvas, .half, .full, .one_third, .two_thirds);
if (sex.tl) rect(metrics, canvas, 0, 0, x_halfs[0], y_thirds[0]); if (sex.bl) fill(metrics, canvas, .zero, .half, .two_thirds, .end);
if (sex.tr) rect(metrics, canvas, x_halfs[1], 0, metrics.cell_width, y_thirds[0]); if (sex.br) fill(metrics, canvas, .half, .full, .two_thirds, .end);
if (sex.ml) rect(metrics, canvas, 0, y_thirds[1], x_halfs[0], y_thirds[2]);
if (sex.mr) rect(metrics, canvas, x_halfs[1], y_thirds[1], metrics.cell_width, y_thirds[2]);
if (sex.bl) rect(metrics, canvas, 0, y_thirds[3], x_halfs[0], metrics.cell_height);
if (sex.br) rect(metrics, canvas, x_halfs[1], y_thirds[3], metrics.cell_width, metrics.cell_height);
} }
/// Smooth Mosaics /// Smooth Mosaics
@ -465,17 +460,12 @@ pub fn draw1FB3C_1FB67(
else => unreachable, else => unreachable,
}; };
const y_thirds = yThirds(metrics);
const top: f64 = 0.0; const top: f64 = 0.0;
// We average the edge positions for the y_thirds boundaries here const upper: f64 = Fraction.one_third.float(metrics.cell_height);
// rather than having to deal with varying alignments depending on const lower: f64 = Fraction.two_thirds.float(metrics.cell_height);
// the surrounding pieces. The most this will be off by is half of
// a pixel, so hopefully it's not noticeable.
const upper: f64 = 0.5 * (@as(f64, @floatFromInt(y_thirds[0])) + @as(f64, @floatFromInt(y_thirds[1])));
const lower: f64 = 0.5 * (@as(f64, @floatFromInt(y_thirds[2])) + @as(f64, @floatFromInt(y_thirds[3])));
const bottom: f64 = @floatFromInt(metrics.cell_height); const bottom: f64 = @floatFromInt(metrics.cell_height);
const left: f64 = 0.0; const left: f64 = 0.0;
const center: f64 = @round(@as(f64, @floatFromInt(metrics.cell_width)) / 2); const center: f64 = Fraction.half.float(metrics.cell_width);
const right: f64 = @floatFromInt(metrics.cell_width); const right: f64 = @floatFromInt(metrics.cell_width);
var path = canvas.staticPath(12); // nodes.len = 0 var path = canvas.staticPath(12); // nodes.len = 0
@ -571,13 +561,14 @@ pub fn draw1FB70_1FB75(
const n = cp + 1 - 0x1fb70; const n = cp + 1 - 0x1fb70;
const x: u32 = @intFromFloat( fill(
@round(@as(f64, @floatFromInt(n)) * @as(f64, @floatFromInt(metrics.cell_width)) / 8), metrics,
canvas,
Fraction.eighths[n],
Fraction.eighths[n + 1],
.top,
.bottom,
); );
const w: u32 = @intFromFloat(
@round(@as(f64, @floatFromInt(metrics.cell_width)) / 8),
);
rect(metrics, canvas, x, 0, x + w, metrics.cell_height);
} }
/// Horizontal one eighth blocks /// Horizontal one eighth blocks
@ -593,21 +584,14 @@ pub fn draw1FB76_1FB7B(
const n = cp + 1 - 0x1fb76; const n = cp + 1 - 0x1fb76;
const h = @as( fill(
u32, metrics,
@intFromFloat(@round(@as(f64, @floatFromInt(metrics.cell_height)) / 8)), canvas,
.left,
.right,
Fraction.eighths[n],
Fraction.eighths[n + 1],
); );
const y = @min(
metrics.cell_height -| h,
@as(
u32,
@intFromFloat(
@round(@as(f64, @floatFromInt(n)) *
@as(f64, @floatFromInt(metrics.cell_height)) / 8),
),
),
);
rect(metrics, canvas, 0, y, metrics.cell_width, y + h);
} }
pub fn draw1FB7C_1FB97( pub fn draw1FB7C_1FB97(
@ -1383,7 +1367,7 @@ fn checkerboardFill(
} }
} }
fn circle( pub fn circle(
metrics: font.Metrics, metrics: font.Metrics,
canvas: *font.sprite.Canvas, canvas: *font.sprite.Canvas,
comptime position: Alignment, comptime position: Alignment,

View File

@ -55,13 +55,13 @@ const z2d = @import("z2d");
const common = @import("common.zig"); const common = @import("common.zig");
const Thickness = common.Thickness; const Thickness = common.Thickness;
const Fraction = common.Fraction;
const Corner = common.Corner; const Corner = common.Corner;
const Shade = common.Shade; const Shade = common.Shade;
const xHalfs = common.xHalfs; const fill = common.fill;
const yQuads = common.yQuads;
const rect = common.rect;
const box = @import("box.zig"); const box = @import("box.zig");
const sflc = @import("symbols_for_legacy_computing.zig");
const font = @import("../../main.zig"); const font = @import("../../main.zig");
@ -122,17 +122,15 @@ pub fn draw1CD00_1CDE5(
break :octants result; break :octants result;
}; };
const x_halfs = xHalfs(metrics);
const y_quads = yQuads(metrics);
const oct = octants[cp - octant_min]; const oct = octants[cp - octant_min];
if (oct.@"1") rect(metrics, canvas, 0, 0, x_halfs[0], y_quads[0]); if (oct.@"1") fill(metrics, canvas, .zero, .half, .zero, .one_quarter);
if (oct.@"2") rect(metrics, canvas, x_halfs[1], 0, metrics.cell_width, y_quads[0]); if (oct.@"2") fill(metrics, canvas, .half, .full, .zero, .one_quarter);
if (oct.@"3") rect(metrics, canvas, 0, y_quads[1], x_halfs[0], y_quads[2]); if (oct.@"3") fill(metrics, canvas, .zero, .half, .one_quarter, .two_quarters);
if (oct.@"4") rect(metrics, canvas, x_halfs[1], y_quads[1], metrics.cell_width, y_quads[2]); if (oct.@"4") fill(metrics, canvas, .half, .full, .one_quarter, .two_quarters);
if (oct.@"5") rect(metrics, canvas, 0, y_quads[3], x_halfs[0], y_quads[4]); if (oct.@"5") fill(metrics, canvas, .zero, .half, .two_quarters, .three_quarters);
if (oct.@"6") rect(metrics, canvas, x_halfs[1], y_quads[3], metrics.cell_width, y_quads[4]); if (oct.@"6") fill(metrics, canvas, .half, .full, .two_quarters, .three_quarters);
if (oct.@"7") rect(metrics, canvas, 0, y_quads[5], x_halfs[0], metrics.cell_height); if (oct.@"7") fill(metrics, canvas, .zero, .half, .three_quarters, .end);
if (oct.@"8") rect(metrics, canvas, x_halfs[1], y_quads[5], metrics.cell_width, metrics.cell_height); if (oct.@"8") fill(metrics, canvas, .half, .full, .three_quarters, .end);
} }
// Separated Block Quadrants // Separated Block Quadrants
@ -213,37 +211,37 @@ pub fn draw1CC30_1CC3F(
) !void { ) !void {
switch (cp) { switch (cp) {
// 𜰰 UPPER LEFT TWELFTH CIRCLE // 𜰰 UPPER LEFT TWELFTH CIRCLE
0x1CC30 => try circlePiece(canvas, width, height, metrics, 0, 0, 2, 2), 0x1CC30 => try circlePiece(canvas, width, height, metrics, 0, 0, 2, 2, .tl),
// 𜰱 UPPER CENTRE LEFT TWELFTH CIRCLE // 𜰱 UPPER CENTRE LEFT TWELFTH CIRCLE
0x1CC31 => try circlePiece(canvas, width, height, metrics, 1, 0, 2, 2), 0x1CC31 => try circlePiece(canvas, width, height, metrics, 1, 0, 2, 2, .tl),
// 𜰲 UPPER CENTRE RIGHT TWELFTH CIRCLE // 𜰲 UPPER CENTRE RIGHT TWELFTH CIRCLE
0x1CC32 => try circlePiece(canvas, width, height, metrics, 2, 0, 2, 2), 0x1CC32 => try circlePiece(canvas, width, height, metrics, 2, 0, 2, 2, .tr),
// 𜰳 UPPER RIGHT TWELFTH CIRCLE // 𜰳 UPPER RIGHT TWELFTH CIRCLE
0x1CC33 => try circlePiece(canvas, width, height, metrics, 3, 0, 2, 2), 0x1CC33 => try circlePiece(canvas, width, height, metrics, 3, 0, 2, 2, .tr),
// 𜰴 UPPER MIDDLE LEFT TWELFTH CIRCLE // 𜰴 UPPER MIDDLE LEFT TWELFTH CIRCLE
0x1CC34 => try circlePiece(canvas, width, height, metrics, 0, 1, 2, 2), 0x1CC34 => try circlePiece(canvas, width, height, metrics, 0, 1, 2, 2, .tl),
// 𜰵 UPPER LEFT QUARTER CIRCLE // 𜰵 UPPER LEFT QUARTER CIRCLE
0x1CC35 => try circlePiece(canvas, width, height, metrics, 0, 0, 1, 1), 0x1CC35 => try circlePiece(canvas, width, height, metrics, 0, 0, 1, 1, .tl),
// 𜰶 UPPER RIGHT QUARTER CIRCLE // 𜰶 UPPER RIGHT QUARTER CIRCLE
0x1CC36 => try circlePiece(canvas, width, height, metrics, 1, 0, 1, 1), 0x1CC36 => try circlePiece(canvas, width, height, metrics, 1, 0, 1, 1, .tr),
// 𜰷 UPPER MIDDLE RIGHT TWELFTH CIRCLE // 𜰷 UPPER MIDDLE RIGHT TWELFTH CIRCLE
0x1CC37 => try circlePiece(canvas, width, height, metrics, 3, 1, 2, 2), 0x1CC37 => try circlePiece(canvas, width, height, metrics, 3, 1, 2, 2, .tr),
// 𜰸 LOWER MIDDLE LEFT TWELFTH CIRCLE // 𜰸 LOWER MIDDLE LEFT TWELFTH CIRCLE
0x1CC38 => try circlePiece(canvas, width, height, metrics, 0, 2, 2, 2), 0x1CC38 => try circlePiece(canvas, width, height, metrics, 0, 2, 2, 2, .bl),
// 𜰹 LOWER LEFT QUARTER CIRCLE // 𜰹 LOWER LEFT QUARTER CIRCLE
0x1CC39 => try circlePiece(canvas, width, height, metrics, 0, 1, 1, 1), 0x1CC39 => try circlePiece(canvas, width, height, metrics, 0, 1, 1, 1, .bl),
// 𜰺 LOWER RIGHT QUARTER CIRCLE // 𜰺 LOWER RIGHT QUARTER CIRCLE
0x1CC3A => try circlePiece(canvas, width, height, metrics, 1, 1, 1, 1), 0x1CC3A => try circlePiece(canvas, width, height, metrics, 1, 1, 1, 1, .br),
// 𜰻 LOWER MIDDLE RIGHT TWELFTH CIRCLE // 𜰻 LOWER MIDDLE RIGHT TWELFTH CIRCLE
0x1CC3B => try circlePiece(canvas, width, height, metrics, 3, 2, 2, 2), 0x1CC3B => try circlePiece(canvas, width, height, metrics, 3, 2, 2, 2, .br),
// 𜰼 LOWER LEFT TWELFTH CIRCLE // 𜰼 LOWER LEFT TWELFTH CIRCLE
0x1CC3C => try circlePiece(canvas, width, height, metrics, 0, 3, 2, 2), 0x1CC3C => try circlePiece(canvas, width, height, metrics, 0, 3, 2, 2, .bl),
// 𜰽 LOWER CENTRE LEFT TWELFTH CIRCLE // 𜰽 LOWER CENTRE LEFT TWELFTH CIRCLE
0x1CC3D => try circlePiece(canvas, width, height, metrics, 1, 3, 2, 2), 0x1CC3D => try circlePiece(canvas, width, height, metrics, 1, 3, 2, 2, .bl),
// 𜰾 LOWER CENTRE RIGHT TWELFTH CIRCLE // 𜰾 LOWER CENTRE RIGHT TWELFTH CIRCLE
0x1CC3E => try circlePiece(canvas, width, height, metrics, 2, 3, 2, 2), 0x1CC3E => try circlePiece(canvas, width, height, metrics, 2, 3, 2, 2, .br),
// 𜰿 LOWER RIGHT TWELFTH CIRCLE // 𜰿 LOWER RIGHT TWELFTH CIRCLE
0x1CC3F => try circlePiece(canvas, width, height, metrics, 3, 3, 2, 2), 0x1CC3F => try circlePiece(canvas, width, height, metrics, 3, 3, 2, 2, .br),
else => unreachable, else => unreachable,
} }
} }
@ -288,6 +286,62 @@ pub fn draw1CC1B_1CC1E(
} }
} }
/// 𜸀 RIGHT HALF AND LEFT HALF WHITE CIRCLE
pub fn draw1CE00(
cp: u32,
canvas: *font.sprite.Canvas,
width: u32,
height: u32,
metrics: font.Metrics,
) !void {
_ = cp;
_ = width;
_ = height;
sflc.circle(metrics, canvas, .left, false);
sflc.circle(metrics, canvas, .right, false);
}
/// 𜸁 LOWER HALF AND UPPER HALF WHITE CIRCLE
pub fn draw1CE01(
cp: u32,
canvas: *font.sprite.Canvas,
width: u32,
height: u32,
metrics: font.Metrics,
) !void {
_ = cp;
_ = width;
_ = height;
sflc.circle(metrics, canvas, .top, false);
sflc.circle(metrics, canvas, .bottom, false);
}
/// 𜸋 LEFT HALF WHITE ELLIPSE
pub fn draw1CE0B(
cp: u32,
canvas: *font.sprite.Canvas,
width: u32,
height: u32,
metrics: font.Metrics,
) !void {
_ = cp;
try circlePiece(canvas, width, height, metrics, 0, 0, 1, 0.5, .tl);
try circlePiece(canvas, width, height, metrics, 0, 0, 1, 0.5, .bl);
}
/// 𜸌 RIGHT HALF WHITE ELLIPSE
pub fn draw1CE0C(
cp: u32,
canvas: *font.sprite.Canvas,
width: u32,
height: u32,
metrics: font.Metrics,
) !void {
_ = cp;
try circlePiece(canvas, width, height, metrics, 1, 0, 1, 0.5, .tr);
try circlePiece(canvas, width, height, metrics, 1, 0, 1, 0.5, .br);
}
pub fn draw1CE16_1CE19( pub fn draw1CE16_1CE19(
cp: u32, cp: u32,
canvas: *font.sprite.Canvas, canvas: *font.sprite.Canvas,
@ -403,6 +457,88 @@ pub fn draw1CE51_1CE8F(
); );
} }
/// Sixteenth Blocks
pub fn draw1CE90_1CEAF(
cp: u32,
canvas: *font.sprite.Canvas,
width: u32,
height: u32,
metrics: font.Metrics,
) !void {
_ = width;
_ = height;
const q = Fraction.quarters;
switch (cp) {
// 𜺐 UPPER LEFT ONE SIXTEENTH BLOCK
0x1CE90 => fill(metrics, canvas, q[0], q[1], q[0], q[1]),
// 𜺑 UPPER CENTRE LEFT ONE SIXTEENTH BLOCK
0x1CE91 => fill(metrics, canvas, q[1], q[2], q[0], q[1]),
// 𜺒 UPPER CENTRE RIGHT ONE SIXTEENTH BLOCK
0x1CE92 => fill(metrics, canvas, q[2], q[3], q[0], q[1]),
// 𜺓 UPPER RIGHT ONE SIXTEENTH BLOCK
0x1CE93 => fill(metrics, canvas, q[3], q[4], q[0], q[1]),
// 𜺔 UPPER MIDDLE LEFT ONE SIXTEENTH BLOCK
0x1CE94 => fill(metrics, canvas, q[0], q[1], q[1], q[2]),
// 𜺕 UPPER MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCK
0x1CE95 => fill(metrics, canvas, q[1], q[2], q[1], q[2]),
// 𜺖 UPPER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCK
0x1CE96 => fill(metrics, canvas, q[2], q[3], q[1], q[2]),
// 𜺗 UPPER MIDDLE RIGHT ONE SIXTEENTH BLOCK
0x1CE97 => fill(metrics, canvas, q[3], q[4], q[1], q[2]),
// 𜺘 LOWER MIDDLE LEFT ONE SIXTEENTH BLOCK
0x1CE98 => fill(metrics, canvas, q[0], q[1], q[2], q[3]),
// 𜺙 LOWER MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCK
0x1CE99 => fill(metrics, canvas, q[1], q[2], q[2], q[3]),
// 𜺚 LOWER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCK
0x1CE9A => fill(metrics, canvas, q[2], q[3], q[2], q[3]),
// 𜺛 LOWER MIDDLE RIGHT ONE SIXTEENTH BLOCK
0x1CE9B => fill(metrics, canvas, q[3], q[4], q[2], q[3]),
// 𜺜 LOWER LEFT ONE SIXTEENTH BLOCK
0x1CE9C => fill(metrics, canvas, q[0], q[1], q[3], q[4]),
// 𜺝 LOWER CENTRE LEFT ONE SIXTEENTH BLOCK
0x1CE9D => fill(metrics, canvas, q[1], q[2], q[3], q[4]),
// 𜺞 LOWER CENTRE RIGHT ONE SIXTEENTH BLOCK
0x1CE9E => fill(metrics, canvas, q[2], q[3], q[3], q[4]),
// 𜺟 LOWER RIGHT ONE SIXTEENTH BLOCK
0x1CE9F => fill(metrics, canvas, q[3], q[4], q[3], q[4]),
// 𜺠 RIGHT HALF LOWER ONE QUARTER BLOCK
0x1CEA0 => fill(metrics, canvas, q[2], q[4], q[3], q[4]),
// 𜺡 RIGHT THREE QUARTERS LOWER ONE QUARTER BLOCK
0x1CEA1 => fill(metrics, canvas, q[1], q[4], q[3], q[4]),
// 𜺢 LEFT THREE QUARTERS LOWER ONE QUARTER BLOCK
0x1CEA2 => fill(metrics, canvas, q[0], q[3], q[3], q[4]),
// 𜺣 LEFT HALF LOWER ONE QUARTER BLOCK
0x1CEA3 => fill(metrics, canvas, q[0], q[2], q[3], q[4]),
// 𜺤 LOWER HALF LEFT ONE QUARTER BLOCK
0x1CEA4 => fill(metrics, canvas, q[0], q[1], q[2], q[4]),
// 𜺥 LOWER THREE QUARTERS LEFT ONE QUARTER BLOCK
0x1CEA5 => fill(metrics, canvas, q[0], q[1], q[1], q[4]),
// 𜺦 UPPER THREE QUARTERS LEFT ONE QUARTER BLOCK
0x1CEA6 => fill(metrics, canvas, q[0], q[1], q[0], q[3]),
// 𜺧 UPPER HALF LEFT ONE QUARTER BLOCK
0x1CEA7 => fill(metrics, canvas, q[0], q[1], q[0], q[2]),
// 𜺨 LEFT HALF UPPER ONE QUARTER BLOCK
0x1CEA8 => fill(metrics, canvas, q[0], q[2], q[0], q[1]),
// 𜺩 LEFT THREE QUARTERS UPPER ONE QUARTER BLOCK
0x1CEA9 => fill(metrics, canvas, q[0], q[3], q[0], q[1]),
// 𜺪 RIGHT THREE QUARTERS UPPER ONE QUARTER BLOCK
0x1CEAA => fill(metrics, canvas, q[1], q[4], q[0], q[1]),
// 𜺫 RIGHT HALF UPPER ONE QUARTER BLOCK
0x1CEAB => fill(metrics, canvas, q[2], q[4], q[0], q[1]),
// 𜺬 UPPER HALF RIGHT ONE QUARTER BLOCK
0x1CEAC => fill(metrics, canvas, q[3], q[4], q[0], q[2]),
// 𜺭 UPPER THREE QUARTERS RIGHT ONE QUARTER BLOCK
0x1CEAD => fill(metrics, canvas, q[3], q[4], q[0], q[3]),
// 𜺮 LOWER THREE QUARTERS RIGHT ONE QUARTER BLOCK
0x1CEAE => fill(metrics, canvas, q[3], q[4], q[1], q[4]),
// 𜺯 LOWER HALF RIGHT ONE QUARTER BLOCK
0x1CEAF => fill(metrics, canvas, q[3], q[4], q[2], q[4]),
else => unreachable,
}
}
fn circlePiece( fn circlePiece(
canvas: *font.sprite.Canvas, canvas: *font.sprite.Canvas,
width: u32, width: u32,
@ -412,6 +548,7 @@ fn circlePiece(
y: f64, y: f64,
w: f64, w: f64,
h: f64, h: f64,
corner: Corner,
) !void { ) !void {
// Radius in pixels of the arc we need to draw. // Radius in pixels of the arc we need to draw.
const wdth: f64 = @as(f64, @floatFromInt(width)) * w; const wdth: f64 = @as(f64, @floatFromInt(width)) * w;
@ -437,9 +574,8 @@ fn circlePiece(
var path = canvas.staticPath(2); var path = canvas.staticPath(2);
if (xp < wdth) { switch (corner) {
if (yp < hght) { .tl => {
// Upper left arc.
path.moveTo(wdth - xp, ht - yp); path.moveTo(wdth - xp, ht - yp);
path.curveTo( path.curveTo(
wdth - cw - xp, wdth - cw - xp,
@ -449,8 +585,19 @@ fn circlePiece(
ht - xp, ht - xp,
hght - yp, hght - yp,
); );
} else { },
// Lower left arc. .tr => {
path.moveTo(wdth - xp, ht - yp);
path.curveTo(
wdth + cw - xp,
ht - yp,
wdth * 2 - ht - xp,
hght - ch - yp,
wdth * 2 - ht - xp,
hght - yp,
);
},
.bl => {
path.moveTo(ht - xp, hght - yp); path.moveTo(ht - xp, hght - yp);
path.curveTo( path.curveTo(
ht - xp, ht - xp,
@ -460,21 +607,8 @@ fn circlePiece(
wdth - xp, wdth - xp,
hght * 2 - ht - yp, hght * 2 - ht - yp,
); );
} },
} else { .br => {
if (yp < hght) {
// Upper right arc.
path.moveTo(wdth - xp, ht - yp);
path.curveTo(
wdth + cw - xp,
ht - yp,
wdth * 2 - ht - xp,
hght - ch - yp,
wdth * 2 - ht - xp,
hght - yp,
);
} else {
// Lower right arc.
path.moveTo(wdth * 2 - ht - xp, hght - yp); path.moveTo(wdth * 2 - ht - xp, hght - yp);
path.curveTo( path.curveTo(
wdth * 2 - ht - xp, wdth * 2 - ht - xp,
@ -484,7 +618,7 @@ fn circlePiece(
wdth - xp, wdth - xp,
hght * 2 - ht - yp, hght * 2 - ht - yp,
); );
} },
} }
try canvas.strokePath(path.wrapped_path, .{ try canvas.strokePath(path.wrapped_path, .{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 632 B

After

Width:  |  Height:  |  Size: 1006 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -39,8 +39,6 @@ extend-ignore-re = [
[default.extend-words] [default.extend-words]
Pn = "Pn" Pn = "Pn"
thr = "thr" thr = "thr"
# Should be "halves", but for now skip it as it would make diff huge
halfs = "halfs"
# Swift oddities # Swift oddities
Requestor = "Requestor" Requestor = "Requestor"
iterm = "iterm" iterm = "iterm"