From ced4247e557bdd843e2701f4fd478ecbb34dc7e8 Mon Sep 17 00:00:00 2001 From: Qwerasd Date: Sun, 29 Sep 2024 23:05:28 -0600 Subject: [PATCH] font/sprite: refactor lines and fractional blocks, add ground truth for regression test Use a single unified function for intersection-style line drawing chars, and one for fractional block characters. Add a ground truth image based on this commit for the regression test (differences from before changes validated visually, 1 incorrect rendering actually fixed) --- src/font/sprite/Box.zig | 1871 ++++++++++-------------------- src/font/sprite/testdata/Box.ppm | Bin 0 -> 1048593 bytes 2 files changed, 619 insertions(+), 1252 deletions(-) create mode 100644 src/font/sprite/testdata/Box.ppm diff --git a/src/font/sprite/Box.zig b/src/font/sprite/Box.zig index 7feceeb6e..4478a38f7 100644 --- a/src/font/sprite/Box.zig +++ b/src/font/sprite/Box.zig @@ -3,12 +3,17 @@ //! characters that are provided by the terminal. //! //! The box drawing logic is based off similar logic in Kitty and Foot. -//! The primary drawing code was ported directly and slightly modified from Foot -//! (https://codeberg.org/dnkl/foot/). Foot is licensed under the MIT -//! license and is copyright 2019 Daniel Eklöf. +//! The primary drawing code was originally ported directly and slightly +//! modified from Foot (https://codeberg.org/dnkl/foot/). Foot is licensed +//! under the MIT license and is copyright 2019 Daniel Eklöf. //! -//! The modifications made are primarily around spacing, DPI calculations, -//! and adapting the code to our atlas model. +//! The modifications made were primarily around spacing, DPI calculations, +//! and adapting the code to our atlas model. Further, more extensive changes +//! were made, refactoring the line characters to all share a single unified +//! function (draw_lines), as well as many of the fractional block characters +//! which now use draw_block instead of dedicated separate functions. +//! +//! Additional characters from Unicode 16.0 and beyond are original work. const Box = @This(); const std = @import("std"); @@ -47,6 +52,59 @@ const Thickness = enum { } }; +/// Specification of a traditional intersection-style line/box-drawing char, +/// which can have a different style of line from each edge to the center. +const Lines = struct { + up: Style = .none, + right: Style = .none, + down: Style = .none, + left: Style = .none, + + const Style = enum { + none, + light, + heavy, + double, + }; +}; + +/// Alignment of a figure within a cell +const Alignment = struct { + horizontal: enum { + left, + right, + center, + } = .center, + + vertical: enum { + top, + bottom, + middle, + } = .middle, + + const upper: Alignment = .{ .vertical = .top }; + const lower: Alignment = .{ .vertical = .bottom }; + const left: Alignment = .{ .horizontal = .left }; + const right: Alignment = .{ .horizontal = .right }; + + const upper_left: Alignment = .{ .vertical = .top, .horizontal = .left }; + const upper_right: Alignment = .{ .vertical = .top, .horizontal = .right }; + const lower_left: Alignment = .{ .vertical = .bottom, .horizontal = .left }; + const lower_right: Alignment = .{ .vertical = .bottom, .horizontal = .right }; + + const top = upper; + const bottom = lower; +}; + +// Utility names for common fractions +const one_eighth: f64 = 0.125; +const one_quarter: f64 = 0.25; +const three_eighths: f64 = 0.375; +const half: f64 = 0.5; +const five_eighths: f64 = 0.625; +const three_quarters: f64 = 0.75; +const seven_eighths: f64 = 0.875; + pub fn renderGlyph( self: Box, alloc: Allocator, @@ -94,230 +152,427 @@ pub fn unadjustedCodepoint(cp: u32) bool { fn draw(self: Box, alloc: Allocator, canvas: *font.sprite.Canvas, cp: u32) !void { switch (cp) { - 0x2500 => self.draw_light_horizontal(canvas), - 0x2501 => self.draw_heavy_horizontal(canvas), - 0x2502 => self.draw_light_vertical(canvas), - 0x2503 => self.draw_heavy_vertical(canvas), + // '─' + 0x2500 => self.draw_lines(canvas, .{ .left = .light, .right = .light }), + // '━' + 0x2501 => self.draw_lines(canvas, .{ .left = .heavy, .right = .heavy }), + // '│' + 0x2502 => self.draw_lines(canvas, .{ .up = .light, .down = .light }), + // '┃' + 0x2503 => self.draw_lines(canvas, .{ .up = .heavy, .down = .heavy }), + // '┄' 0x2504 => self.draw_light_triple_dash_horizontal(canvas), + // '┅' 0x2505 => self.draw_heavy_triple_dash_horizontal(canvas), + // '┆' 0x2506 => self.draw_light_triple_dash_vertical(canvas), + // '┇' 0x2507 => self.draw_heavy_triple_dash_vertical(canvas), + // '┈' 0x2508 => self.draw_light_quadruple_dash_horizontal(canvas), + // '┉' 0x2509 => self.draw_heavy_quadruple_dash_horizontal(canvas), + // '┊' 0x250a => self.draw_light_quadruple_dash_vertical(canvas), + // '┋' 0x250b => self.draw_heavy_quadruple_dash_vertical(canvas), - 0x250c => self.draw_light_down_and_right(canvas), - 0x250d => self.draw_down_light_and_right_heavy(canvas), - 0x250e => self.draw_down_heavy_and_right_light(canvas), - 0x250f => self.draw_heavy_down_and_right(canvas), + // '┌' + 0x250c => self.draw_lines(canvas, .{ .down = .light, .right = .light }), + // '┍' + 0x250d => self.draw_lines(canvas, .{ .down = .light, .right = .heavy }), + // '┎' + 0x250e => self.draw_lines(canvas, .{ .down = .heavy, .right = .light }), + // '┏' + 0x250f => self.draw_lines(canvas, .{ .down = .heavy, .right = .heavy }), - 0x2510 => self.draw_light_down_and_left(canvas), - 0x2511 => self.draw_down_light_and_left_heavy(canvas), - 0x2512 => self.draw_down_heavy_and_left_light(canvas), - 0x2513 => self.draw_heavy_down_and_left(canvas), - 0x2514 => self.draw_light_up_and_right(canvas), - 0x2515 => self.draw_up_light_and_right_heavy(canvas), - 0x2516 => self.draw_up_heavy_and_right_light(canvas), - 0x2517 => self.draw_heavy_up_and_right(canvas), - 0x2518 => self.draw_light_up_and_left(canvas), - 0x2519 => self.draw_up_light_and_left_heavy(canvas), - 0x251a => self.draw_up_heavy_and_left_light(canvas), - 0x251b => self.draw_heavy_up_and_left(canvas), - 0x251c => self.draw_light_vertical_and_right(canvas), - 0x251d => self.draw_vertical_light_and_right_heavy(canvas), - 0x251e => self.draw_up_heavy_and_right_down_light(canvas), - 0x251f => self.draw_down_heavy_and_right_up_light(canvas), + // '┐' + 0x2510 => self.draw_lines(canvas, .{ .down = .light, .left = .light }), + // '┑' + 0x2511 => self.draw_lines(canvas, .{ .down = .light, .left = .heavy }), + // '┒' + 0x2512 => self.draw_lines(canvas, .{ .down = .heavy, .left = .light }), + // '┓' + 0x2513 => self.draw_lines(canvas, .{ .down = .heavy, .left = .heavy }), + // '└' + 0x2514 => self.draw_lines(canvas, .{ .up = .light, .right = .light }), + // '┕' + 0x2515 => self.draw_lines(canvas, .{ .up = .light, .right = .heavy }), + // '┖' + 0x2516 => self.draw_lines(canvas, .{ .up = .heavy, .right = .light }), + // '┗' + 0x2517 => self.draw_lines(canvas, .{ .up = .heavy, .right = .heavy }), + // '┘' + 0x2518 => self.draw_lines(canvas, .{ .up = .light, .left = .light }), + // '┙' + 0x2519 => self.draw_lines(canvas, .{ .up = .light, .left = .heavy }), + // '┚' + 0x251a => self.draw_lines(canvas, .{ .up = .heavy, .left = .light }), + // '┛' + 0x251b => self.draw_lines(canvas, .{ .up = .heavy, .left = .heavy }), + // '├' + 0x251c => self.draw_lines(canvas, .{ .up = .light, .down = .light, .right = .light }), + // '┝' + 0x251d => self.draw_lines(canvas, .{ .up = .light, .down = .light, .right = .heavy }), + // '┞' + 0x251e => self.draw_lines(canvas, .{ .up = .heavy, .right = .light, .down = .light }), + // '┟' + 0x251f => self.draw_lines(canvas, .{ .down = .heavy, .right = .light, .up = .light }), - 0x2520 => self.draw_vertical_heavy_and_right_light(canvas), - 0x2521 => self.draw_down_light_and_right_up_heavy(canvas), - 0x2522 => self.draw_up_light_and_right_down_heavy(canvas), - 0x2523 => self.draw_heavy_vertical_and_right(canvas), - 0x2524 => self.draw_light_vertical_and_left(canvas), - 0x2525 => self.draw_vertical_light_and_left_heavy(canvas), - 0x2526 => self.draw_up_heavy_and_left_down_light(canvas), - 0x2527 => self.draw_down_heavy_and_left_up_light(canvas), - 0x2528 => self.draw_vertical_heavy_and_left_light(canvas), - 0x2529 => self.draw_down_light_and_left_up_heavy(canvas), - 0x252a => self.draw_up_light_and_left_down_heavy(canvas), - 0x252b => self.draw_heavy_vertical_and_left(canvas), - 0x252c => self.draw_light_down_and_horizontal(canvas), - 0x252d => self.draw_left_heavy_and_right_down_light(canvas), - 0x252e => self.draw_right_heavy_and_left_down_light(canvas), - 0x252f => self.draw_down_light_and_horizontal_heavy(canvas), + // '┠' + 0x2520 => self.draw_lines(canvas, .{ .up = .heavy, .down = .heavy, .right = .light }), + // '┡' + 0x2521 => self.draw_lines(canvas, .{ .down = .light, .right = .heavy, .up = .heavy }), + // '┢' + 0x2522 => self.draw_lines(canvas, .{ .up = .light, .right = .heavy, .down = .heavy }), + // '┣' + 0x2523 => self.draw_lines(canvas, .{ .up = .heavy, .down = .heavy, .right = .heavy }), + // '┤' + 0x2524 => self.draw_lines(canvas, .{ .up = .light, .down = .light, .left = .light }), + // '┥' + 0x2525 => self.draw_lines(canvas, .{ .up = .light, .down = .light, .left = .heavy }), + // '┦' + 0x2526 => self.draw_lines(canvas, .{ .up = .heavy, .left = .light, .down = .light }), + // '┧' + 0x2527 => self.draw_lines(canvas, .{ .down = .heavy, .left = .light, .up = .light }), + // '┨' + 0x2528 => self.draw_lines(canvas, .{ .up = .heavy, .down = .heavy, .left = .light }), + // '┩' + 0x2529 => self.draw_lines(canvas, .{ .down = .light, .left = .heavy, .up = .heavy }), + // '┪' + 0x252a => self.draw_lines(canvas, .{ .up = .light, .left = .heavy, .down = .heavy }), + // '┫' + 0x252b => self.draw_lines(canvas, .{ .up = .heavy, .down = .heavy, .left = .heavy }), + // '┬' + 0x252c => self.draw_lines(canvas, .{ .down = .light, .left = .light, .right = .light }), + // '┭' + 0x252d => self.draw_lines(canvas, .{ .left = .heavy, .right = .light, .down = .light }), + // '┮' + 0x252e => self.draw_lines(canvas, .{ .right = .heavy, .left = .light, .down = .light }), + // '┯' + 0x252f => self.draw_lines(canvas, .{ .down = .light, .left = .heavy, .right = .heavy }), - 0x2530 => self.draw_down_heavy_and_horizontal_light(canvas), - 0x2531 => self.draw_right_light_and_left_down_heavy(canvas), - 0x2532 => self.draw_left_light_and_right_down_heavy(canvas), - 0x2533 => self.draw_heavy_down_and_horizontal(canvas), - 0x2534 => self.draw_light_up_and_horizontal(canvas), - 0x2535 => self.draw_left_heavy_and_right_up_light(canvas), - 0x2536 => self.draw_right_heavy_and_left_up_light(canvas), - 0x2537 => self.draw_up_light_and_horizontal_heavy(canvas), - 0x2538 => self.draw_up_heavy_and_horizontal_light(canvas), - 0x2539 => self.draw_right_light_and_left_up_heavy(canvas), - 0x253a => self.draw_left_light_and_right_up_heavy(canvas), - 0x253b => self.draw_heavy_up_and_horizontal(canvas), - 0x253c => self.draw_light_vertical_and_horizontal(canvas), - 0x253d => self.draw_left_heavy_and_right_vertical_light(canvas), - 0x253e => self.draw_right_heavy_and_left_vertical_light(canvas), - 0x253f => self.draw_vertical_light_and_horizontal_heavy(canvas), + // '┰' + 0x2530 => self.draw_lines(canvas, .{ .down = .heavy, .left = .light, .right = .light }), + // '┱' + 0x2531 => self.draw_lines(canvas, .{ .right = .light, .left = .heavy, .down = .heavy }), + // '┲' + 0x2532 => self.draw_lines(canvas, .{ .left = .light, .right = .heavy, .down = .heavy }), + // '┳' + 0x2533 => self.draw_lines(canvas, .{ .down = .heavy, .left = .heavy, .right = .heavy }), + // '┴' + 0x2534 => self.draw_lines(canvas, .{ .up = .light, .left = .light, .right = .light }), + // '┵' + 0x2535 => self.draw_lines(canvas, .{ .left = .heavy, .right = .light, .up = .light }), + // '┶' + 0x2536 => self.draw_lines(canvas, .{ .right = .heavy, .left = .light, .up = .light }), + // '┷' + 0x2537 => self.draw_lines(canvas, .{ .up = .light, .left = .heavy, .right = .heavy }), + // '┸' + 0x2538 => self.draw_lines(canvas, .{ .up = .heavy, .left = .light, .right = .light }), + // '┹' + 0x2539 => self.draw_lines(canvas, .{ .right = .light, .left = .heavy, .up = .heavy }), + // '┺' + 0x253a => self.draw_lines(canvas, .{ .left = .light, .right = .heavy, .up = .heavy }), + // '┻' + 0x253b => self.draw_lines(canvas, .{ .up = .heavy, .left = .heavy, .right = .heavy }), + // '┼' + 0x253c => self.draw_lines(canvas, .{ .up = .light, .down = .light, .left = .light, .right = .light }), + // '┽' + 0x253d => self.draw_lines(canvas, .{ .left = .heavy, .right = .light, .up = .light, .down = .light }), + // '┾' + 0x253e => self.draw_lines(canvas, .{ .right = .heavy, .left = .light, .up = .light, .down = .light }), + // '┿' + 0x253f => self.draw_lines(canvas, .{ .up = .light, .down = .light, .left = .heavy, .right = .heavy }), - 0x2540 => self.draw_up_heavy_and_down_horizontal_light(canvas), - 0x2541 => self.draw_down_heavy_and_up_horizontal_light(canvas), - 0x2542 => self.draw_vertical_heavy_and_horizontal_light(canvas), - 0x2543 => self.draw_left_up_heavy_and_right_down_light(canvas), - 0x2544 => self.draw_right_up_heavy_and_left_down_light(canvas), - 0x2545 => self.draw_left_down_heavy_and_right_up_light(canvas), - 0x2546 => self.draw_right_down_heavy_and_left_up_light(canvas), - 0x2547 => self.draw_down_light_and_up_horizontal_heavy(canvas), - 0x2548 => self.draw_up_light_and_down_horizontal_heavy(canvas), - 0x2549 => self.draw_right_light_and_left_vertical_heavy(canvas), - 0x254a => self.draw_left_light_and_right_vertical_heavy(canvas), - 0x254b => self.draw_heavy_vertical_and_horizontal(canvas), + // '╀' + 0x2540 => self.draw_lines(canvas, .{ .up = .heavy, .down = .light, .left = .light, .right = .light }), + // '╁' + 0x2541 => self.draw_lines(canvas, .{ .down = .heavy, .up = .light, .left = .light, .right = .light }), + // '╂' + 0x2542 => self.draw_lines(canvas, .{ .up = .heavy, .down = .heavy, .left = .light, .right = .light }), + // '╃' + 0x2543 => self.draw_lines(canvas, .{ .left = .heavy, .up = .heavy, .right = .light, .down = .light }), + // '╄' + 0x2544 => self.draw_lines(canvas, .{ .right = .heavy, .up = .heavy, .left = .light, .down = .light }), + // '╅' + 0x2545 => self.draw_lines(canvas, .{ .left = .heavy, .down = .heavy, .right = .light, .up = .light }), + // '╆' + 0x2546 => self.draw_lines(canvas, .{ .right = .heavy, .down = .heavy, .left = .light, .up = .light }), + // '╇' + 0x2547 => self.draw_lines(canvas, .{ .down = .light, .up = .heavy, .left = .heavy, .right = .heavy }), + // '╈' + 0x2548 => self.draw_lines(canvas, .{ .up = .light, .down = .heavy, .left = .heavy, .right = .heavy }), + // '╉' + 0x2549 => self.draw_lines(canvas, .{ .right = .light, .left = .heavy, .up = .heavy, .down = .heavy }), + // '╊' + 0x254a => self.draw_lines(canvas, .{ .left = .light, .right = .heavy, .up = .heavy, .down = .heavy }), + // '╋' + 0x254b => self.draw_lines(canvas, .{ .up = .heavy, .down = .heavy, .left = .heavy, .right = .heavy }), + // '╌' 0x254c => self.draw_light_double_dash_horizontal(canvas), + // '╍' 0x254d => self.draw_heavy_double_dash_horizontal(canvas), + // '╎' 0x254e => self.draw_light_double_dash_vertical(canvas), + // '╏' 0x254f => self.draw_heavy_double_dash_vertical(canvas), - 0x2550 => self.draw_double_horizontal(canvas), - 0x2551 => self.draw_double_vertical(canvas), - 0x2552 => self.draw_down_single_and_right_double(canvas), - 0x2553 => self.draw_down_double_and_right_single(canvas), - 0x2554 => self.draw_double_down_and_right(canvas), - 0x2555 => self.draw_down_single_and_left_double(canvas), - 0x2556 => self.draw_down_double_and_left_single(canvas), - 0x2557 => self.draw_double_down_and_left(canvas), - 0x2558 => self.draw_up_single_and_right_double(canvas), - 0x2559 => self.draw_up_double_and_right_single(canvas), - 0x255a => self.draw_double_up_and_right(canvas), - 0x255b => self.draw_up_single_and_left_double(canvas), - 0x255c => self.draw_up_double_and_left_single(canvas), - 0x255d => self.draw_double_up_and_left(canvas), - 0x255e => self.draw_vertical_single_and_right_double(canvas), - 0x255f => self.draw_vertical_double_and_right_single(canvas), + // '═' + 0x2550 => self.draw_lines(canvas, .{ .left = .double, .right = .double }), + // '║' + 0x2551 => self.draw_lines(canvas, .{ .up = .double, .down = .double }), + // '╒' + 0x2552 => self.draw_lines(canvas, .{ .down = .light, .right = .double }), + // '╓' + 0x2553 => self.draw_lines(canvas, .{ .down = .double, .right = .light }), + // '╔' + 0x2554 => self.draw_lines(canvas, .{ .down = .double, .right = .double }), + // '╕' + 0x2555 => self.draw_lines(canvas, .{ .down = .light, .left = .double }), + // '╖' + 0x2556 => self.draw_lines(canvas, .{ .down = .double, .left = .light }), + // '╗' + 0x2557 => self.draw_lines(canvas, .{ .down = .double, .left = .double }), + // '╘' + 0x2558 => self.draw_lines(canvas, .{ .up = .light, .right = .double }), + // '╙' + 0x2559 => self.draw_lines(canvas, .{ .up = .double, .right = .light }), + // '╚' + 0x255a => self.draw_lines(canvas, .{ .up = .double, .right = .double }), + // '╛' + 0x255b => self.draw_lines(canvas, .{ .up = .light, .left = .double }), + // '╜' + 0x255c => self.draw_lines(canvas, .{ .up = .double, .left = .light }), + // '╝' + 0x255d => self.draw_lines(canvas, .{ .up = .double, .left = .double }), + // '╞' + 0x255e => self.draw_lines(canvas, .{ .up = .light, .down = .light, .right = .double }), + // '╟' + 0x255f => self.draw_lines(canvas, .{ .up = .double, .down = .double, .right = .light }), - 0x2560 => self.draw_double_vertical_and_right(canvas), - 0x2561 => self.draw_vertical_single_and_left_double(canvas), - 0x2562 => self.draw_vertical_double_and_left_single(canvas), - 0x2563 => self.draw_double_vertical_and_left(canvas), - 0x2564 => self.draw_down_single_and_horizontal_double(canvas), - 0x2565 => self.draw_down_double_and_horizontal_single(canvas), - 0x2566 => self.draw_double_down_and_horizontal(canvas), - 0x2567 => self.draw_up_single_and_horizontal_double(canvas), - 0x2568 => self.draw_up_double_and_horizontal_single(canvas), - 0x2569 => self.draw_double_up_and_horizontal(canvas), - 0x256a => self.draw_vertical_single_and_horizontal_double(canvas), - 0x256b => self.draw_vertical_double_and_horizontal_single(canvas), - 0x256c => self.draw_double_vertical_and_horizontal(canvas), + // '╠' + 0x2560 => self.draw_lines(canvas, .{ .up = .double, .down = .double, .right = .double }), + // '╡' + 0x2561 => self.draw_lines(canvas, .{ .up = .light, .down = .light, .left = .double }), + // '╢' + 0x2562 => self.draw_lines(canvas, .{ .up = .double, .down = .double, .left = .light }), + // '╣' + 0x2563 => self.draw_lines(canvas, .{ .up = .double, .down = .double, .left = .double }), + // '╤' + 0x2564 => self.draw_lines(canvas, .{ .down = .light, .left = .double, .right = .double }), + // '╥' + 0x2565 => self.draw_lines(canvas, .{ .down = .double, .left = .light, .right = .light }), + // '╦' + 0x2566 => self.draw_lines(canvas, .{ .down = .double, .left = .double, .right = .double }), + // '╧' + 0x2567 => self.draw_lines(canvas, .{ .up = .light, .left = .double, .right = .double }), + // '╨' + 0x2568 => self.draw_lines(canvas, .{ .up = .double, .left = .light, .right = .light }), + // '╩' + 0x2569 => self.draw_lines(canvas, .{ .up = .double, .left = .double, .right = .double }), + // '╪' + 0x256a => self.draw_lines(canvas, .{ .up = .light, .down = .light, .left = .double, .right = .double }), + // '╫' + 0x256b => self.draw_lines(canvas, .{ .up = .double, .down = .double, .left = .light, .right = .light }), + // '╬' + 0x256c => self.draw_lines(canvas, .{ .up = .double, .down = .double, .left = .double, .right = .double }), 0x256d...0x2570 => try self.draw_light_arc(alloc, canvas, cp), + // '╱' 0x2571 => self.draw_light_diagonal_upper_right_to_lower_left(canvas), + // '╲' 0x2572 => self.draw_light_diagonal_upper_left_to_lower_right(canvas), + // '╳' 0x2573 => self.draw_light_diagonal_cross(canvas), - 0x2574 => self.draw_light_left(canvas), - 0x2575 => self.draw_light_up(canvas), - 0x2576 => self.draw_light_right(canvas), - 0x2577 => self.draw_light_down(canvas), - 0x2578 => self.draw_heavy_left(canvas), - 0x2579 => self.draw_heavy_up(canvas), - 0x257a => self.draw_heavy_right(canvas), - 0x257b => self.draw_heavy_down(canvas), - 0x257c => self.draw_light_left_and_heavy_right(canvas), - 0x257d => self.draw_light_up_and_heavy_down(canvas), - 0x257e => self.draw_heavy_left_and_light_right(canvas), - 0x257f => self.draw_heavy_up_and_light_down(canvas), + // '╴' + 0x2574 => self.draw_lines(canvas, .{ .left = .light }), + // '╵' + 0x2575 => self.draw_lines(canvas, .{ .up = .light }), + // '╶' + 0x2576 => self.draw_lines(canvas, .{ .right = .light }), + // '╷' + 0x2577 => self.draw_lines(canvas, .{ .down = .light }), + // '╸' + 0x2578 => self.draw_lines(canvas, .{ .left = .heavy }), + // '╹' + 0x2579 => self.draw_lines(canvas, .{ .up = .heavy }), + // '╺' + 0x257a => self.draw_lines(canvas, .{ .right = .heavy }), + // '╻' + 0x257b => self.draw_lines(canvas, .{ .down = .heavy }), + // '╼' + 0x257c => self.draw_lines(canvas, .{ .left = .light, .right = .heavy }), + // '╽' + 0x257d => self.draw_lines(canvas, .{ .up = .light, .down = .heavy }), + // '╾' + 0x257e => self.draw_lines(canvas, .{ .left = .heavy, .right = .light }), + // '╿' + 0x257f => self.draw_lines(canvas, .{ .up = .heavy, .down = .light }), - 0x2580 => self.draw_upper_half_block(canvas), - 0x2581 => self.draw_lower_one_eighth_block(canvas), - 0x2582 => self.draw_lower_one_quarter_block(canvas), - 0x2583 => self.draw_lower_three_eighths_block(canvas), - 0x2584 => self.draw_lower_half_block(canvas), - 0x2585 => self.draw_lower_five_eighths_block(canvas), - 0x2586 => self.draw_lower_three_quarters_block(canvas), - 0x2587 => self.draw_lower_seven_eighths_block(canvas), + // '▀' UPPER HALF BLOCK + 0x2580 => self.draw_block(canvas, Alignment.upper, 1, half), + // '▁' LOWER ONE EIGHTH BLOCK + 0x2581 => self.draw_block(canvas, Alignment.lower, 1, one_eighth), + // '▂' LOWER ONE QUARTER BLOCK + 0x2582 => self.draw_block(canvas, Alignment.lower, 1, one_quarter), + // '▃' LOWER THREE EIGHTHS BLOCK + 0x2583 => self.draw_block(canvas, Alignment.lower, 1, three_eighths), + // '▄' LOWER HALF BLOCK + 0x2584 => self.draw_block(canvas, Alignment.lower, 1, half), + // '▅' LOWER FIVE EIGHTHS BLOCK + 0x2585 => self.draw_block(canvas, Alignment.lower, 1, five_eighths), + // '▆' LOWER THREE QUARTERS BLOCK + 0x2586 => self.draw_block(canvas, Alignment.lower, 1, three_quarters), + // '▇' LOWER SEVEN EIGHTHS BLOCK + 0x2587 => self.draw_block(canvas, Alignment.lower, 1, seven_eighths), + // '█' FULL BLOCK 0x2588 => self.draw_full_block(canvas), - 0x2589 => self.draw_left_seven_eighths_block(canvas), - 0x258a => self.draw_left_three_quarters_block(canvas), - 0x258b => self.draw_left_five_eighths_block(canvas), - 0x258c => self.draw_left_half_block(canvas), - 0x258d => self.draw_left_three_eighths_block(canvas), - 0x258e => self.draw_left_one_quarter_block(canvas), - 0x258f => self.draw_left_one_eighth_block(canvas), + // '▉' LEFT SEVEN EIGHTHS BLOCK + 0x2589 => self.draw_block(canvas, Alignment.left, seven_eighths, 1), + // '▊' LEFT THREE QUARTERS BLOCK + 0x258a => self.draw_block(canvas, Alignment.left, three_quarters, 1), + // '▋' LEFT FIVE EIGHTHS BLOCK + 0x258b => self.draw_block(canvas, Alignment.left, five_eighths, 1), + // '▌' LEFT HALF BLOCK + 0x258c => self.draw_block(canvas, Alignment.left, half, 1), + // '▍' LEFT THREE EIGHTHS BLOCK + 0x258d => self.draw_block(canvas, Alignment.left, three_eighths, 1), + // '▎' LEFT ONE QUARTER BLOCK + 0x258e => self.draw_block(canvas, Alignment.left, one_quarter, 1), + // '▏' LEFT ONE EIGHTH BLOCK + 0x258f => self.draw_block(canvas, Alignment.left, one_eighth, 1), - 0x2590 => self.draw_right_half_block(canvas), + // '▐' RIGHT HALF BLOCK + 0x2590 => self.draw_block(canvas, Alignment.right, half, 1), + // '░' 0x2591 => self.draw_light_shade(canvas), + // '▒' 0x2592 => self.draw_medium_shade(canvas), + // '▓' 0x2593 => self.draw_dark_shade(canvas), - 0x2594 => self.draw_upper_one_eighth_block(canvas), - 0x2595 => self.draw_right_one_eighth_block(canvas), + // '▔' UPPER ONE EIGHTH BLOCK + 0x2594 => self.draw_block(canvas, Alignment.upper, 1, one_eighth), + // '▕' RIGHT ONE EIGHTH BLOCK + 0x2595 => self.draw_block(canvas, Alignment.right, one_eighth, 1), + + // ▖ ▗ ▘ ▙ ▚ ▛ ▜ ▝ ▞ ▟ 0x2596...0x259f => self.draw_quadrant(canvas, cp), - 0x2800...0x28FF => self.draw_braille(canvas, cp), + 0x2800...0x28ff => self.draw_braille(canvas, cp), - 0x1FB00...0x1FB3B => self.draw_sextant(canvas, cp), + 0x1fb00...0x1fb3b => self.draw_sextant(canvas, cp), - 0x1FB3C...0x1FB40, - 0x1FB47...0x1FB4B, - 0x1FB57...0x1FB5B, - 0x1FB62...0x1FB66, - 0x1FB6C...0x1FB6F, + 0x1fb3c...0x1fb40, + 0x1fb47...0x1fb4b, + 0x1fb57...0x1fb5b, + 0x1fb62...0x1fb66, + 0x1fb6c...0x1fb6f, => try self.draw_wedge_triangle(canvas, cp), - 0x1FB41...0x1FB45, - 0x1FB4C...0x1FB50, - 0x1FB52...0x1FB56, - 0x1FB5D...0x1FB61, - 0x1FB68...0x1FB6B, + 0x1fb41...0x1fb45, + 0x1fb4c...0x1fb50, + 0x1fb52...0x1fb56, + 0x1fb5d...0x1fb61, + 0x1fb68...0x1fb6b, => try self.draw_wedge_triangle_inverted(alloc, canvas, cp), - 0x1FB46, - 0x1FB51, - 0x1FB5C, - 0x1FB67, + // '🭆' + 0x1fb46, + // '🭑' + 0x1fb51, + // '🭜' + 0x1fb5c, + // '🭧' + 0x1fb67, => try self.draw_wedge_triangle_and_box(canvas, cp), - 0x1FB9A => { + // '🮚' + 0x1fb9a => { try self.draw_wedge_triangle(canvas, 0x1fb6d); try self.draw_wedge_triangle(canvas, 0x1fb6f); }, - 0x1FB9B => { + // '🮛' + 0x1fb9b => { try self.draw_wedge_triangle(canvas, 0x1fb6c); try self.draw_wedge_triangle(canvas, 0x1fb6e); }, - 0x1FB70 => self.draw_vertical_one_eighth_block_n(canvas, 1), - 0x1FB71 => self.draw_vertical_one_eighth_block_n(canvas, 2), - 0x1FB72 => self.draw_vertical_one_eighth_block_n(canvas, 3), - 0x1FB73 => self.draw_vertical_one_eighth_block_n(canvas, 4), - 0x1FB74 => self.draw_vertical_one_eighth_block_n(canvas, 5), - 0x1FB75 => self.draw_vertical_one_eighth_block_n(canvas, 6), + // '🭰' + 0x1fb70 => self.draw_vertical_one_eighth_block_n(canvas, 1), + // '🭱' + 0x1fb71 => self.draw_vertical_one_eighth_block_n(canvas, 2), + // '🭲' + 0x1fb72 => self.draw_vertical_one_eighth_block_n(canvas, 3), + // '🭳' + 0x1fb73 => self.draw_vertical_one_eighth_block_n(canvas, 4), + // '🭴' + 0x1fb74 => self.draw_vertical_one_eighth_block_n(canvas, 5), + // '🭵' + 0x1fb75 => self.draw_vertical_one_eighth_block_n(canvas, 6), - 0x1FB76 => self.draw_horizontal_one_eighth_block_n(canvas, 1), - 0x1FB77 => self.draw_horizontal_one_eighth_block_n(canvas, 2), - 0x1FB78 => self.draw_horizontal_one_eighth_block_n(canvas, 3), - 0x1FB79 => self.draw_horizontal_one_eighth_block_n(canvas, 4), - 0x1FB7A => self.draw_horizontal_one_eighth_block_n(canvas, 5), - 0x1FB7B => self.draw_horizontal_one_eighth_block_n(canvas, 6), + // '🭶' + 0x1fb76 => self.draw_horizontal_one_eighth_block_n(canvas, 1), + // '🭷' + 0x1fb77 => self.draw_horizontal_one_eighth_block_n(canvas, 2), + // '🭸' + 0x1fb78 => self.draw_horizontal_one_eighth_block_n(canvas, 3), + // '🭹' + 0x1fb79 => self.draw_horizontal_one_eighth_block_n(canvas, 4), + // '🭺' + 0x1fb7a => self.draw_horizontal_one_eighth_block_n(canvas, 5), + // '🭻' + 0x1fb7b => self.draw_horizontal_one_eighth_block_n(canvas, 6), - 0x1fb82 => self.draw_upper_one_quarter_block(canvas), - 0x1fb83 => self.draw_upper_three_eighths_block(canvas), - 0x1fb84 => self.draw_upper_five_eighths_block(canvas), - 0x1fb85 => self.draw_upper_three_quarters_block(canvas), - 0x1fb86 => self.draw_upper_seven_eighths_block(canvas), + // '🮂' UPPER ONE QUARTER BLOCK + 0x1fb82 => self.draw_block(canvas, Alignment.upper, 1, one_quarter), + // '🮃' UPPER THREE EIGHTHS BLOCK + 0x1fb83 => self.draw_block(canvas, Alignment.upper, 1, three_eighths), + // '🮄' UPPER FIVE EIGHTHS BLOCK + 0x1fb84 => self.draw_block(canvas, Alignment.upper, 1, five_eighths), + // '🮅' UPPER THREE QUARTERS BLOCK + 0x1fb85 => self.draw_block(canvas, Alignment.upper, 1, three_quarters), + // '🮆' UPPER SEVEN EIGHTHS BLOCK + 0x1fb86 => self.draw_block(canvas, Alignment.upper, 1, seven_eighths), - 0x1fb7c => self.draw_left_and_lower_one_eighth_block(canvas), - 0x1fb7d => self.draw_left_and_upper_one_eighth_block(canvas), - 0x1fb7e => self.draw_right_and_upper_one_eighth_block(canvas), - 0x1fb7f => self.draw_right_and_lower_one_eighth_block(canvas), - 0x1fb80 => self.draw_upper_and_lower_one_eighth_block(canvas), + // '🭼' LEFT AND LOWER ONE EIGHTH BLOCK + 0x1fb7c => { + self.draw_block(canvas, Alignment.left, one_eighth, 1); + self.draw_block(canvas, Alignment.lower, 1, one_eighth); + }, + // '🭽' LEFT AND UPPER ONE EIGHTH BLOCK + 0x1fb7d => { + self.draw_block(canvas, Alignment.left, one_eighth, 1); + self.draw_block(canvas, Alignment.upper, 1, one_eighth); + }, + // '🭾' RIGHT AND UPPER ONE EIGHTH BLOCK + 0x1fb7e => { + self.draw_block(canvas, Alignment.right, one_eighth, 1); + self.draw_block(canvas, Alignment.upper, 1, one_eighth); + }, + // '🭿' RIGHT AND LOWER ONE EIGHTH BLOCK + 0x1fb7f => { + self.draw_block(canvas, Alignment.right, one_eighth, 1); + self.draw_block(canvas, Alignment.lower, 1, one_eighth); + }, + // '🮀' UPPER AND LOWER ONE EIGHTH BLOCK + 0x1fb80 => { + self.draw_block(canvas, Alignment.upper, 1, one_eighth); + self.draw_block(canvas, Alignment.lower, 1, one_eighth); + }, + // '🮁' 0x1fb81 => self.draw_horizontal_one_eighth_1358_block(canvas), - 0x1fb87 => self.draw_right_one_quarter_block(canvas), - 0x1fb88 => self.draw_right_three_eighths_block(canvas), - 0x1fb89 => self.draw_right_five_eighths_block(canvas), - 0x1fb8a => self.draw_right_three_quarters_block(canvas), - 0x1fb8b => self.draw_right_seven_eighths_block(canvas), + // '🮇' RIGHT ONE QUARTER BLOCK + 0x1fb87 => self.draw_block(canvas, Alignment.right, one_quarter, 1), + // '🮈' RIGHT THREE EIGHTHS BLOCK + 0x1fb88 => self.draw_block(canvas, Alignment.right, three_eighths, 1), + // '🮉' RIGHT FIVE EIGHTHS BLOCK + 0x1fb89 => self.draw_block(canvas, Alignment.right, five_eighths, 1), + // '🮊' RIGHT THREE QUARTERS BLOCK + 0x1fb8a => self.draw_block(canvas, Alignment.right, three_quarters, 1), + // '🮋' RIGHT SEVEN EIGHTHS BLOCK + 0x1fb8b => self.draw_block(canvas, Alignment.right, seven_eighths, 1), // Not official box characters but special characters we hide // in the high bits of a unicode codepoint. @@ -329,20 +584,143 @@ fn draw(self: Box, alloc: Allocator, canvas: *font.sprite.Canvas, cp: u32) !void } } -fn draw_light_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); -} +fn draw_lines(self: Box, canvas: *font.sprite.Canvas, comptime lines: Lines) void { + const light_px = Thickness.light.height(self.thickness); + const heavy_px = Thickness.heavy.height(self.thickness); -fn draw_heavy_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .heavy); -} + // Top of light horizontal strokes + const h_light_top = (self.height -| light_px) / 2; + // Bottom of light horizontal strokes + const h_light_bottom = h_light_top +| light_px; -fn draw_light_vertical(self: Box, canvas: *font.sprite.Canvas) void { - self.vline_middle(canvas, .light); -} + // Top of heavy horizontal strokes + const h_heavy_top = (self.height -| heavy_px) / 2; + // Bottom of heavy horizontal strokes + const h_heavy_bottom = h_heavy_top +| heavy_px; -fn draw_heavy_vertical(self: Box, canvas: *font.sprite.Canvas) void { - self.vline_middle(canvas, .heavy); + // Top of the top doubled horizontal stroke (bottom is `h_light_top`) + const h_double_top = h_light_top -| light_px; + // Bottom of the bottom doubled horizontal stroke (top is `h_light_bottom`) + const h_double_bottom = h_light_bottom +| light_px; + + // Left of light vertical strokes + const v_light_left = (self.width -| light_px) / 2; + // Right of light vertical strokes + const v_light_right = v_light_left +| light_px; + + // Left of heavy vertical strokes + const v_heavy_left = (self.width -| heavy_px) / 2; + // Right of heavy vertical strokes + const v_heavy_right = v_heavy_left +| heavy_px; + + // Left of the left doubled vertical stroke (right is `v_light_left`) + const v_double_left = v_light_left -| light_px; + // Right of the right doubled vertical stroke (left is `v_light_right`) + const v_double_right = v_light_right +| light_px; + + // The bottom of the up line + const up_bottom = if (lines.left == .heavy or lines.right == .heavy) + h_heavy_bottom + else if (lines.left != lines.right or lines.down == lines.up) + if (lines.left == .double or lines.right == .double) + h_double_bottom + else + h_light_bottom + else if (lines.left == .none and lines.right == .none) + h_light_bottom + else + h_light_top; + + // The top of the down line + const down_top = if (lines.left == .heavy or lines.right == .heavy) + h_heavy_top + else if (lines.left != lines.right or lines.up == lines.down) + if (lines.left == .double or lines.right == .double) + h_double_top + else + h_light_top + else if (lines.left == .none and lines.right == .none) + h_light_top + else + h_light_bottom; + + // The right of the left line + const left_right = if (lines.up == .heavy or lines.down == .heavy) + v_heavy_right + else if (lines.up != lines.down or lines.left == lines.right) + if (lines.up == .double or lines.down == .double) + v_double_right + else + v_light_right + else if (lines.up == .none and lines.down == .none) + v_light_right + else + v_light_left; + + // The left of the right line + const right_left = if (lines.up == .heavy or lines.down == .heavy) + v_heavy_left + else if (lines.up != lines.down or lines.right == lines.left) + if (lines.up == .double or lines.down == .double) + v_double_left + else + v_light_left + else if (lines.up == .none and lines.down == .none) + v_light_left + else + v_light_right; + + switch (lines.up) { + .none => {}, + .light => self.rect(canvas, v_light_left, 0, v_light_right, up_bottom), + .heavy => self.rect(canvas, v_heavy_left, 0, v_heavy_right, up_bottom), + .double => { + const left_bottom = if (lines.left == .double) h_light_top else up_bottom; + const right_bottom = if (lines.right == .double) h_light_top else up_bottom; + + self.rect(canvas, v_double_left, 0, v_light_left, left_bottom); + self.rect(canvas, v_light_right, 0, v_double_right, right_bottom); + }, + } + + switch (lines.right) { + .none => {}, + .light => self.rect(canvas, right_left, h_light_top, self.width, h_light_bottom), + .heavy => self.rect(canvas, right_left, h_heavy_top, self.width, h_heavy_bottom), + .double => { + const top_left = if (lines.up == .double) v_light_right else right_left; + const bottom_left = if (lines.down == .double) v_light_right else right_left; + + self.rect(canvas, top_left, h_double_top, self.width, h_light_top); + self.rect(canvas, bottom_left, h_light_bottom, self.width, h_double_bottom); + }, + } + + switch (lines.down) { + .none => {}, + .light => self.rect(canvas, v_light_left, down_top, v_light_right, self.height), + .heavy => self.rect(canvas, v_heavy_left, down_top, v_heavy_right, self.height), + .double => { + const left_top = if (lines.left == .double) h_light_bottom else down_top; + const right_top = if (lines.right == .double) h_light_bottom else down_top; + + self.rect(canvas, v_double_left, left_top, v_light_left, self.height); + self.rect(canvas, v_light_right, right_top, v_double_right, self.height); + }, + } + + switch (lines.left) { + .none => {}, + .light => self.rect(canvas, 0, h_light_top, left_right, h_light_bottom), + .heavy => self.rect(canvas, 0, h_heavy_top, left_right, h_heavy_bottom), + .double => { + const top_right = if (lines.up == .double) v_light_left else left_right; + const bottom_right = if (lines.down == .double) v_light_left else left_right; + + self.rect(canvas, 0, h_double_top, top_right, h_light_top); + self.rect(canvas, 0, h_light_bottom, bottom_right, h_double_bottom); + }, + } } fn draw_light_triple_dash_horizontal(self: Box, canvas: *font.sprite.Canvas) void { @@ -417,358 +795,6 @@ fn draw_heavy_quadruple_dash_vertical(self: Box, canvas: *font.sprite.Canvas) vo ); } -fn draw_light_down_and_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_light_and_right_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_heavy_and_right_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .light); -} - -fn draw_heavy_down_and_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_light_down_and_left(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_light_and_left_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_heavy_and_left_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .light); -} - -fn draw_heavy_down_and_left(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_light_up_and_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_up(canvas, .light, .light); -} - -fn draw_up_light_and_right_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .heavy); - self.vline_middle_up(canvas, .light, .light); -} - -fn draw_up_heavy_and_right_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_up(canvas, .heavy, .light); -} - -fn draw_heavy_up_and_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .heavy, .heavy); -} - -fn draw_light_up_and_left(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.vline_middle_up(canvas, .light, .light); -} - -fn draw_up_light_and_left_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .heavy); - self.vline_middle_up(canvas, .light, .light); -} - -fn draw_up_heavy_and_left_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.vline_middle_up(canvas, .heavy, .light); -} - -fn draw_heavy_up_and_left(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .heavy, .heavy); -} - -fn draw_light_vertical_and_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); - self.vline_middle(canvas, .light); -} - -fn draw_vertical_light_and_right_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .heavy); - self.vline_middle(canvas, .light); -} - -fn draw_up_heavy_and_right_down_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_up(canvas, .heavy, .light); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_heavy_and_right_up_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .light); -} - -fn draw_vertical_heavy_and_right_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); - self.vline_middle(canvas, .heavy); -} - -fn draw_down_light_and_right_up_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_up_light_and_right_down_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_heavy_vertical_and_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle(canvas, .heavy); -} - -fn draw_light_vertical_and_left(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.vline_middle(canvas, .light); -} - -fn draw_vertical_light_and_left_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .heavy); - self.vline_middle(canvas, .light); -} - -fn draw_up_heavy_and_left_down_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.vline_middle_up(canvas, .heavy, .light); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_heavy_and_left_up_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .light); -} - -fn draw_vertical_heavy_and_left_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.vline_middle(canvas, .heavy); -} - -fn draw_down_light_and_left_up_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_up_light_and_left_down_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_heavy_vertical_and_left(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.vline_middle(canvas, .heavy); -} - -fn draw_light_down_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_left_heavy_and_right_down_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .heavy); - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_right_heavy_and_left_down_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .light, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_light_and_horizontal_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_heavy_and_horizontal_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle_down(canvas, .heavy, .light); -} - -fn draw_right_light_and_left_down_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_left_light_and_right_down_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_heavy_down_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .heavy); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_light_up_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle_up(canvas, .light, .light); -} - -fn draw_left_heavy_and_right_up_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .heavy); - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_up(canvas, .light, .light); -} - -fn draw_right_heavy_and_left_up_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .light, .heavy); - self.vline_middle_up(canvas, .light, .light); -} - -fn draw_up_light_and_horizontal_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle_up(canvas, .light, .light); -} - -fn draw_up_heavy_and_horizontal_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle_up(canvas, .heavy, .light); -} - -fn draw_right_light_and_left_up_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_up(canvas, .heavy, .heavy); -} - -fn draw_left_light_and_right_up_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .heavy, .heavy); -} - -fn draw_heavy_up_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .heavy); - self.vline_middle_up(canvas, .heavy, .heavy); -} - -fn draw_light_vertical_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle(canvas, .light); -} - -fn draw_left_heavy_and_right_vertical_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .heavy); - self.hline_middle_right(canvas, .light, .light); - self.vline_middle(canvas, .light); -} - -fn draw_right_heavy_and_left_vertical_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .light, .heavy); - self.vline_middle(canvas, .light); -} - -fn draw_vertical_light_and_horizontal_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .heavy); - self.vline_middle(canvas, .light); -} - -fn draw_up_heavy_and_down_horizontal_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle_up(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_down_heavy_and_up_horizontal_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .light); -} - -fn draw_vertical_heavy_and_horizontal_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .light); - self.vline_middle(canvas, .heavy); -} - -fn draw_left_up_heavy_and_right_down_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_up(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_right_up_heavy_and_left_down_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_left_down_heavy_and_right_up_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.hline_middle_right(canvas, .light, .light); - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_right_down_heavy_and_left_up_light(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_down_light_and_up_horizontal_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .heavy); - self.vline_middle_up(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_up_light_and_down_horizontal_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .heavy); - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_right_light_and_left_vertical_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.hline_middle_right(canvas, .light, .light); - self.vline_middle(canvas, .heavy); -} - -fn draw_left_light_and_right_vertical_heavy(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .heavy, .heavy); - self.vline_middle(canvas, .heavy); -} - -fn draw_heavy_vertical_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle(canvas, .heavy); - self.vline_middle(canvas, .heavy); -} - fn draw_light_double_dash_horizontal(self: Box, canvas: *font.sprite.Canvas) void { self.draw_dash_horizontal( canvas, @@ -805,275 +831,6 @@ fn draw_heavy_double_dash_vertical(self: Box, canvas: *font.sprite.Canvas) void ); } -fn draw_double_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const mid = (self.height -| thick_px * 3) / 2; - self.hline(canvas, 0, self.width, mid, thick_px); - self.hline(canvas, 0, self.width, mid + 2 * thick_px, thick_px); -} - -fn draw_double_vertical(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const mid = (self.width -| thick_px * 3) / 2; - self.vline(canvas, 0, self.height, mid, thick_px); - self.vline(canvas, 0, self.height, mid + 2 * thick_px, thick_px); -} - -fn draw_down_single_and_right_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px) / 2; - self.vline_middle_down(canvas, .light, .light); - self.hline(canvas, vmid, self.width, hmid, thick_px); - self.hline(canvas, vmid, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_down_double_and_right_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.hline_middle_right(canvas, .light, .light); - self.vline(canvas, hmid, self.height, vmid, thick_px); - self.vline(canvas, hmid, self.height, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_down_and_right(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.vline(canvas, hmid, self.height, vmid, thick_px); - self.vline(canvas, hmid + 2 * thick_px, self.height, vmid + 2 * thick_px, thick_px); - self.hline(canvas, vmid, self.width, hmid, thick_px); - self.hline(canvas, vmid + 2 * thick_px, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_down_single_and_left_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width + thick_px) / 2; - self.vline_middle_down(canvas, .light, .light); - self.hline(canvas, 0, vmid, hmid, thick_px); - self.hline(canvas, 0, vmid, hmid + 2 * thick_px, thick_px); -} - -fn draw_down_double_and_left_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.hline_middle_left(canvas, .light, .light); - self.vline(canvas, hmid, self.height, vmid, thick_px); - self.vline(canvas, hmid, self.height, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_down_and_left(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.vline(canvas, hmid + 2 * thick_px, self.height, vmid, thick_px); - self.vline(canvas, hmid, self.height, vmid + 2 * thick_px, thick_px); - self.hline(canvas, 0, vmid + 2 * thick_px, hmid, thick_px); - self.hline(canvas, 0, vmid, hmid + 2 * thick_px, thick_px); -} - -fn draw_up_single_and_right_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px) / 2; - self.vline_middle_up(canvas, .light, .light); - self.hline(canvas, vmid, self.width, hmid, thick_px); - self.hline(canvas, vmid, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_up_double_and_right_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height + thick_px) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.hline_middle_right(canvas, .light, .light); - self.vline(canvas, 0, hmid, vmid, thick_px); - self.vline(canvas, 0, hmid, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_up_and_right(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.vline(canvas, 0, hmid + 2 * thick_px, vmid, thick_px); - self.vline(canvas, 0, hmid, vmid + 2 * thick_px, thick_px); - self.hline(canvas, vmid + 2 * thick_px, self.width, hmid, thick_px); - self.hline(canvas, vmid, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_up_single_and_left_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width + thick_px) / 2; - self.vline_middle_up(canvas, .light, .light); - self.hline(canvas, 0, vmid, hmid, thick_px); - self.hline(canvas, 0, vmid, hmid + 2 * thick_px, thick_px); -} - -fn draw_up_double_and_left_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height + thick_px) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.hline_middle_left(canvas, .light, .light); - self.vline(canvas, 0, hmid, vmid, thick_px); - self.vline(canvas, 0, hmid, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_up_and_left(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.vline(canvas, 0, hmid + 0 * thick_px + thick_px, vmid, thick_px); - self.vline(canvas, 0, hmid + 2 * thick_px + thick_px, vmid + 2 * thick_px, thick_px); - self.hline(canvas, 0, vmid, hmid, thick_px); - self.hline(canvas, 0, vmid + 2 * thick_px, hmid + 2 * thick_px, thick_px); -} - -fn draw_vertical_single_and_right_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px) / 2; - self.vline_middle(canvas, .light); - self.hline(canvas, vmid, self.width, hmid, thick_px); - self.hline(canvas, vmid, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_vertical_double_and_right_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const vmid = (self.width -| thick_px * 3) / 2; - self.hline(canvas, vmid + 2 * thick_px, self.width, (self.height -| thick_px) / 2, thick_px); - self.vline(canvas, 0, self.height, vmid, thick_px); - self.vline(canvas, 0, self.height, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_vertical_and_right(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.vline(canvas, 0, self.height, vmid, thick_px); - self.vline(canvas, 0, hmid, vmid + 2 * thick_px, thick_px); - self.vline(canvas, hmid + 2 * thick_px, self.height, vmid + 2 * thick_px, thick_px); - self.hline(canvas, vmid + 2 * thick_px, self.width, hmid, thick_px); - self.hline(canvas, vmid + 2 * thick_px, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_vertical_single_and_left_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width + thick_px) / 2; - self.vline_middle(canvas, .light); - self.hline(canvas, 0, vmid, hmid, thick_px); - self.hline(canvas, 0, vmid, hmid + 2 * thick_px, thick_px); -} - -fn draw_vertical_double_and_left_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const vmid = (self.width -| thick_px * 3) / 2; - self.hline(canvas, 0, vmid, (self.height -| thick_px) / 2, thick_px); - self.vline(canvas, 0, self.height, vmid, thick_px); - self.vline(canvas, 0, self.height, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_vertical_and_left(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.vline(canvas, 0, self.height, vmid + 2 * thick_px, thick_px); - self.vline(canvas, 0, hmid, vmid, thick_px); - self.vline(canvas, hmid + 2 * thick_px, self.height, vmid, thick_px); - self.hline(canvas, 0, vmid + thick_px, hmid, thick_px); - self.hline(canvas, 0, vmid, hmid + 2 * thick_px, thick_px); -} - -fn draw_down_single_and_horizontal_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - self.vline(canvas, hmid + 2 * thick_px, self.height, (self.width -| thick_px) / 2, thick_px); - self.hline(canvas, 0, self.width, hmid, thick_px); - self.hline(canvas, 0, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_down_double_and_horizontal_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.hline_middle(canvas, .light); - self.vline(canvas, hmid, self.height, vmid, thick_px); - self.vline(canvas, hmid, self.height, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_down_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.hline(canvas, 0, self.width, hmid, thick_px); - self.hline(canvas, 0, vmid, hmid + 2 * thick_px, thick_px); - self.hline(canvas, vmid + 2 * thick_px, self.width, hmid + 2 * thick_px, thick_px); - self.vline(canvas, hmid + 2 * thick_px, self.height, vmid, thick_px); - self.vline(canvas, hmid + 2 * thick_px, self.height, vmid + 2 * thick_px, thick_px); -} - -fn draw_up_single_and_horizontal_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px) / 2; - self.vline(canvas, 0, hmid, vmid, thick_px); - self.hline(canvas, 0, self.width, hmid, thick_px); - self.hline(canvas, 0, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_up_double_and_horizontal_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.hline_middle(canvas, .light); - self.vline(canvas, 0, hmid, vmid, thick_px); - self.vline(canvas, 0, hmid, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_up_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.vline(canvas, 0, hmid, vmid, thick_px); - self.vline(canvas, 0, hmid, vmid + 2 * thick_px, thick_px); - self.hline(canvas, 0, vmid + thick_px, hmid, thick_px); - self.hline(canvas, vmid + 2 * thick_px, self.width, hmid, thick_px); - self.hline(canvas, 0, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_vertical_single_and_horizontal_double(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - self.vline_middle(canvas, .light); - self.hline(canvas, 0, self.width, hmid, thick_px); - self.hline(canvas, 0, self.width, hmid + 2 * thick_px, thick_px); -} - -fn draw_vertical_double_and_horizontal_single(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const vmid = (self.width -| thick_px * 3) / 2; - self.hline_middle(canvas, .light); - self.vline(canvas, 0, self.height, vmid, thick_px); - self.vline(canvas, 0, self.height, vmid + 2 * thick_px, thick_px); -} - -fn draw_double_vertical_and_horizontal(self: Box, canvas: *font.sprite.Canvas) void { - const thick_px = Thickness.light.height(self.thickness); - const hmid = (self.height -| thick_px * 3) / 2; - const vmid = (self.width -| thick_px * 3) / 2; - self.hline(canvas, 0, vmid, hmid, thick_px); - self.hline(canvas, vmid + 2 * thick_px, self.width, hmid, thick_px); - self.hline(canvas, 0, vmid, hmid + 2 * thick_px, thick_px); - self.hline(canvas, vmid + 2 * thick_px, self.width, hmid + 2 * thick_px, thick_px); - self.vline(canvas, 0, hmid + thick_px, vmid, thick_px); - self.vline(canvas, 0, hmid, vmid + 2 * thick_px, thick_px); - self.vline(canvas, hmid + 2 * thick_px, self.height, vmid, thick_px); - self.vline(canvas, hmid + 2 * thick_px, self.height, vmid + 2 * thick_px, thick_px); -} - fn draw_light_diagonal_upper_right_to_lower_left(self: Box, canvas: *font.sprite.Canvas) void { const thick_px = Thickness.light.height(self.thickness); canvas.trapezoid(.{ @@ -1139,254 +896,48 @@ fn draw_light_diagonal_cross(self: Box, canvas: *font.sprite.Canvas) void { self.draw_light_diagonal_upper_left_to_lower_right(canvas); } -fn draw_light_left(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); -} +fn draw_block( + self: Box, + canvas: *font.sprite.Canvas, + alignment: Alignment, + width: f64, + height: f64, +) void { + const float_width: f64 = @floatFromInt(self.width); + const float_height: f64 = @floatFromInt(self.height); -fn draw_light_up(self: Box, canvas: *font.sprite.Canvas) void { - self.vline_middle_up(canvas, .light, .light); -} + const w: u32 = @intFromFloat(@round(float_width * width)); + const h: u32 = @intFromFloat(@round(float_height * height)); -fn draw_light_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .light, .light); -} + const x = switch (alignment.horizontal) { + .left => 0, + .right => self.width - w, + .center => (self.width - w) / 2, + }; + const y = switch (alignment.vertical) { + .top => 0, + .bottom => self.height - h, + .middle => (self.height - h) / 2, + }; -fn draw_light_down(self: Box, canvas: *font.sprite.Canvas) void { - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_heavy_left(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); -} - -fn draw_heavy_up(self: Box, canvas: *font.sprite.Canvas) void { - self.vline_middle_up(canvas, .heavy, .heavy); -} - -fn draw_heavy_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_right(canvas, .heavy, .heavy); -} - -fn draw_heavy_down(self: Box, canvas: *font.sprite.Canvas) void { - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_light_left_and_heavy_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .light, .light); - self.hline_middle_right(canvas, .heavy, .heavy); -} - -fn draw_light_up_and_heavy_down(self: Box, canvas: *font.sprite.Canvas) void { - self.vline_middle_up(canvas, .light, .light); - self.vline_middle_down(canvas, .heavy, .heavy); -} - -fn draw_heavy_left_and_light_right(self: Box, canvas: *font.sprite.Canvas) void { - self.hline_middle_left(canvas, .heavy, .heavy); - self.hline_middle_right(canvas, .light, .light); -} - -fn draw_heavy_up_and_light_down(self: Box, canvas: *font.sprite.Canvas) void { - self.vline_middle_up(canvas, .heavy, .heavy); - self.vline_middle_down(canvas, .light, .light); -} - -fn draw_upper_half_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect(canvas, 0, 0, self.width, self.height / 2); -} - -fn draw_lower_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect(canvas, 0, self.height -| (self.height / 8), self.width, self.height); -} - -fn draw_lower_one_quarter_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect(canvas, 0, self.height -| (self.height / 4), self.width, self.height); -} - -fn draw_lower_three_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - self.height -| @as(u32, @intFromFloat(@round(3 * @as(f64, @floatFromInt(self.height)) / 8))), - self.width, - self.height, - ); -} - -fn draw_lower_half_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - self.height -| @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.height)) / 2))), - self.width, - self.height, - ); -} - -fn draw_lower_five_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - self.height -| @as(u32, @intFromFloat(@round(5 * @as(f64, @floatFromInt(self.height)) / 8))), - self.width, - self.height, - ); -} - -fn draw_lower_three_quarters_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - self.height -| @as(u32, @intFromFloat(@round(3 * @as(f64, @floatFromInt(self.height)) / 4))), - self.width, - self.height, - ); -} - -fn draw_lower_seven_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - self.height -| @as(u32, @intFromFloat(@round(7 * @as(f64, @floatFromInt(self.height)) / 8))), - self.width, - self.height, - ); -} - -fn draw_upper_one_quarter_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - self.width, - @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.height)) / 4))), - ); -} - -fn draw_upper_three_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - self.width, - @as(u32, @intFromFloat(@round(3 * @as(f64, @floatFromInt(self.height)) / 8))), - ); -} - -fn draw_upper_five_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - self.width, - @as(u32, @intFromFloat(@round(5 * @as(f64, @floatFromInt(self.height)) / 8))), - ); -} - -fn draw_upper_three_quarters_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - self.width, - @as(u32, @intFromFloat(@round(3 * @as(f64, @floatFromInt(self.height)) / 4))), - ); -} - -fn draw_upper_seven_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - self.width, - @as(u32, @intFromFloat(@round(7 * @as(f64, @floatFromInt(self.height)) / 8))), - ); + canvas.rect(.{ + .x = @intCast(x), + .y = @intCast(y), + .width = w, + .height = h, + }, .on); } fn draw_full_block(self: Box, canvas: *font.sprite.Canvas) void { self.rect(canvas, 0, 0, self.width, self.height); } -fn draw_left_seven_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - @as(u32, @intFromFloat(@round(7 * @as(f64, @floatFromInt(self.width)) / 8))), - self.height, - ); -} - -fn draw_left_three_quarters_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - @as(u32, @intFromFloat(@round(3 * @as(f64, @floatFromInt(self.width)) / 4))), - self.height, - ); -} - -fn draw_left_five_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - @as(u32, @intFromFloat(@round(5 * @as(f64, @floatFromInt(self.width)) / 8))), - self.height, - ); -} - -fn draw_left_half_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.width)) / 2))), - self.height, - ); -} - -fn draw_left_three_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - @as(u32, @intFromFloat(@round(3 * @as(f64, @floatFromInt(self.width)) / 8))), - self.height, - ); -} - -fn draw_left_one_quarter_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.width)) / 4))), - self.height, - ); -} - fn draw_vertical_one_eighth_block_n(self: Box, canvas: *font.sprite.Canvas, n: u32) void { const x = @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(n)) * @as(f64, @floatFromInt(self.width)) / 8))); const w = @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.width)) / 8))); self.rect(canvas, x, 0, x + w, self.height); } -fn draw_left_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.draw_vertical_one_eighth_block_n(canvas, 0); -} - -fn draw_right_half_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.width)) / 2))), - 0, - self.width, - self.height, - ); -} - fn draw_pixman_shade(self: Box, canvas: *font.sprite.Canvas, v: u16) void { canvas.rect((font.sprite.Box{ .x1 = 0, @@ -1409,145 +960,19 @@ fn draw_dark_shade(self: Box, canvas: *font.sprite.Canvas) void { } fn draw_horizontal_one_eighth_block_n(self: Box, canvas: *font.sprite.Canvas, n: u32) void { - const y = @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(n)) * @as(f64, @floatFromInt(self.height)) / 8))); const h = @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.height)) / 8))); + const y = @min( + self.height -| h, + @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(n)) * @as(f64, @floatFromInt(self.height)) / 8))), + ); self.rect(canvas, 0, y, self.width, y + h); } -fn draw_upper_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.draw_horizontal_one_eighth_block_n(canvas, 0); -} - -fn draw_right_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - self.width -| @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.width)) / 8))), - 0, - self.width, - self.height, - ); -} - -fn draw_left_and_lower_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.draw_left_one_eighth_block(canvas); - self.draw_lower_one_eighth_block(canvas); -} - -fn draw_left_and_upper_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.draw_left_one_eighth_block(canvas); - self.draw_upper_one_eighth_block(canvas); -} - -fn draw_right_and_upper_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.draw_right_one_eighth_block(canvas); - self.draw_upper_one_eighth_block(canvas); -} - -fn draw_right_and_lower_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.draw_right_one_eighth_block(canvas); - self.draw_lower_one_eighth_block(canvas); -} - -fn draw_upper_and_lower_one_eighth_block(self: Box, canvas: *font.sprite.Canvas) void { - self.draw_upper_one_eighth_block(canvas); - self.draw_lower_one_eighth_block(canvas); -} - fn draw_horizontal_one_eighth_1358_block(self: Box, canvas: *font.sprite.Canvas) void { - self.draw_upper_one_eighth_block(canvas); + self.draw_horizontal_one_eighth_block_n(canvas, 0); self.draw_horizontal_one_eighth_block_n(canvas, 2); self.draw_horizontal_one_eighth_block_n(canvas, 4); - self.draw_lower_one_eighth_block(canvas); -} - -fn draw_right_one_quarter_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - self.width -| @as(u32, @intFromFloat(@round(@as(f64, @floatFromInt(self.width)) / 4))), - 0, - self.width, - self.height, - ); -} - -fn draw_right_three_quarters_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - self.width -| @as(u32, @intFromFloat(@round(3 * @as(f64, @floatFromInt(self.width)) / 4))), - 0, - self.width, - self.height, - ); -} - -fn draw_right_three_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - self.width -| @as(u32, @intFromFloat(@round(3 * @as(f64, @floatFromInt(self.width)) / 8))), - 0, - self.width, - self.height, - ); -} - -fn draw_right_five_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - self.width -| @as(u32, @intFromFloat(@round(5 * @as(f64, @floatFromInt(self.width)) / 8))), - 0, - self.width, - self.height, - ); -} - -fn draw_right_seven_eighths_block(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - self.width -| @as(u32, @intFromFloat(@round(7 * @as(f64, @floatFromInt(self.width)) / 8))), - 0, - self.width, - self.height, - ); -} - -fn quad_upper_left(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - 0, - @as(u32, @intFromFloat(@ceil(@as(f64, @floatFromInt(self.width)) / 2))), - @as(u32, @intFromFloat(@ceil(@as(f64, @floatFromInt(self.height)) / 2))), - ); -} - -fn quad_upper_right(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - @as(u32, @intFromFloat(@floor(@as(f64, @floatFromInt(self.width)) / 2))), - 0, - self.width, - @as(u32, @intFromFloat(@ceil(@as(f64, @floatFromInt(self.height)) / 2))), - ); -} - -fn quad_lower_left(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - 0, - @as(u32, @intFromFloat(@floor(@as(f64, @floatFromInt(self.height)) / 2))), - @as(u32, @intFromFloat(@ceil(@as(f64, @floatFromInt(self.width)) / 2))), - self.height, - ); -} - -fn quad_lower_right(self: Box, canvas: *font.sprite.Canvas) void { - self.rect( - canvas, - @as(u32, @intFromFloat(@floor(@as(f64, @floatFromInt(self.width)) / 2))), - @as(u32, @intFromFloat(@floor(@as(f64, @floatFromInt(self.height)) / 2))), - self.width, - self.height, - ); + self.draw_horizontal_one_eighth_block_n(canvas, 7); } fn draw_quadrant(self: Box, canvas: *font.sprite.Canvas, cp: u32) void { @@ -1572,10 +997,10 @@ fn draw_quadrant(self: Box, canvas: *font.sprite.Canvas, cp: u32) void { const idx = cp - 0x2596; const encoded = matrix[idx]; - if (encoded & UPPER_LEFT == UPPER_LEFT) self.quad_upper_left(canvas); - if (encoded & UPPER_RIGHT == UPPER_RIGHT) self.quad_upper_right(canvas); - if (encoded & LOWER_LEFT == LOWER_LEFT) self.quad_lower_left(canvas); - if (encoded & LOWER_RIGHT == LOWER_RIGHT) self.quad_lower_right(canvas); + if (encoded & UPPER_LEFT == UPPER_LEFT) self.draw_block(canvas, .{ .horizontal = .left, .vertical = .top }, 0.5, 0.5); + if (encoded & UPPER_RIGHT == UPPER_RIGHT) self.draw_block(canvas, .{ .horizontal = .right, .vertical = .top }, 0.5, 0.5); + if (encoded & LOWER_LEFT == LOWER_LEFT) self.draw_block(canvas, .{ .horizontal = .left, .vertical = .bottom }, 0.5, 0.5); + if (encoded & LOWER_RIGHT == LOWER_RIGHT) self.draw_block(canvas, .{ .horizontal = .right, .vertical = .bottom }, 0.5, 0.5); } fn draw_braille(self: Box, canvas: *font.sprite.Canvas, cp: u32) void { @@ -2598,79 +2023,11 @@ fn vline_middle(self: Box, canvas: *font.sprite.Canvas, thickness: Thickness) vo self.vline(canvas, 0, self.height, (self.width -| thick_px) / 2, thick_px); } -fn vline_middle_up( - self: Box, - canvas: *font.sprite.Canvas, - vthickness: Thickness, - hthickness: Thickness, -) void { - const hthick_px = hthickness.height(self.thickness); - const vthick_px = vthickness.height(self.thickness); - self.vline( - canvas, - 0, - (self.height + hthick_px) / 2, - (self.width -| vthick_px) / 2, - vthick_px, - ); -} - -fn vline_middle_down( - self: Box, - canvas: *font.sprite.Canvas, - vthickness: Thickness, - hthickness: Thickness, -) void { - const hthick_px = hthickness.height(self.thickness); - const vthick_px = vthickness.height(self.thickness); - self.vline( - canvas, - (self.height -| hthick_px) / 2, - self.height, - (self.width -| vthick_px) / 2, - vthick_px, - ); -} - fn hline_middle(self: Box, canvas: *font.sprite.Canvas, thickness: Thickness) void { const thick_px = thickness.height(self.thickness); self.hline(canvas, 0, self.width, (self.height -| thick_px) / 2, thick_px); } -fn hline_middle_left( - self: Box, - canvas: *font.sprite.Canvas, - vthickness: Thickness, - hthickness: Thickness, -) void { - const hthick_px = hthickness.height(self.thickness); - const vthick_px = vthickness.height(self.thickness); - self.hline( - canvas, - 0, - (self.width + vthick_px) / 2, - (self.height -| hthick_px) / 2, - hthick_px, - ); -} - -fn hline_middle_right( - self: Box, - canvas: *font.sprite.Canvas, - vthickness: Thickness, - hthickness: Thickness, -) void { - const hthick_px = hthickness.height(self.thickness); - const vthick_px = vthickness.height(self.thickness); - self.hline( - canvas, - (self.width -| vthick_px) / 2, - self.width, - (self.height -| hthick_px) / 2, - hthick_px, - ); -} - fn vline( self: Box, canvas: *font.sprite.Canvas, @@ -2724,7 +2081,7 @@ test "all" { const alloc = testing.allocator; var cp: u32 = 0x2500; - const end = 0x2570; + const end = 0x259f; while (cp <= end) : (cp += 1) { var atlas_grayscale = try font.Atlas.init(alloc, 512, .grayscale); defer atlas_grayscale.deinit(alloc); @@ -2803,10 +2160,20 @@ test "render all sprites" { } } - // Dump to PPM file for visual examination - // Uncomment whenever a new ground truth needs to be created. - const ppm = try std.fs.cwd().createFile("Box.ppm", .{}); - defer ppm.close(); + const ground_truth = @embedFile("./testdata/Box.ppm"); - try atlas_grayscale.dump(ppm.writer()); + var stream = std.io.changeDetectionStream(ground_truth, std.io.null_writer); + try atlas_grayscale.dump(stream.writer()); + + if (stream.changeDetected()) { + log.err( + "Change detected from ground truth, dumping to ./Box_test.ppm for comparison.", + .{}, + ); + + const ppm = try std.fs.cwd().createFile("Box_test.ppm", .{}); + defer ppm.close(); + + try atlas_grayscale.dump(ppm.writer()); + } } diff --git a/src/font/sprite/testdata/Box.ppm b/src/font/sprite/testdata/Box.ppm new file mode 100644 index 0000000000000000000000000000000000000000..676b07ebea775e35eb23bf1d5095343bb53d5300 GIT binary patch literal 1048593 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