cosmopolitan/tool/viz/lib/glyphs.c

546 lines
14 KiB
C

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
// The modes below use various unicodes for 'progresssive' pixelization:
// each mode supersets the previous to increase resolution more and more.
// Ideally, a fully dense mapping of the (Y*X) space defined by kGlyph size
// would produce a picture perfect image, but at the cost of sampling speed.
// Therefore, supersets are parcimonious: they only add the minimal set of
// missing shapes that can increase resolution.
// Ideally, this should be based on a study of the residual, but some logic
// can go a long way: after some block pixelization, will need diagonals
// FIXME: then shouldn't box drawing go right after braille?
// TODO: explain the differences between each mode:
// Mode A is full, empty, half blocks top and bottom: , █,▄,▀
// Mode B superset: with quadrants: ▐,▌,▝,▙,▗,▛,▖,▜,▘,▟,▞,▚,
// Mode C superset: with fractional eights along X and Y
// _,▁,▂,▃,▄,▅,▆,▇ :█:▉,▊,▋,▌,▍,▎,▏
// Mode X use box drawing, mode X use diagonal blocks, mode X use braille etc
#define W(B, S) B##U << S
#define G(AA, AB, AC, AD, BA, BB, BC, BD, CA, CB, CC, CD, DA, DB, DC, DD, EA, \
EB, EC, ED, FA, FB, FC, FD, GA, GB, GC, GD, HA, HB, HC, HD) \
(W(AA, 000) | W(AB, 001) | W(AC, 002) | W(AD, 003) | W(BA, 004) | \
W(BB, 005) | W(BC, 006) | W(BD, 007) | W(CA, 010) | W(CB, 011) | \
W(CC, 012) | W(CD, 013) | W(DA, 014) | W(DB, 015) | W(DC, 016) | \
W(DD, 017) | W(EA, 020) | W(EB, 021) | W(EC, 022) | W(ED, 023) | \
W(FA, 024) | W(FB, 025) | W(FC, 026) | W(FD, 027) | W(GA, 030) | \
W(GB, 031) | W(GC, 032) | W(GD, 033) | W(HA, 034) | W(HB, 035) | \
W(HC, 036) | W(HD, 037))
// The glyph size it set by the resolution of the most precise mode, ex:
// - Mode C: along the X axis, need >= 8 steps for the 8 fractional width
// FIXME: now we can only use 4 chars instead of the extra ▉,▊,▋,▌,▍,▎,▏
//
// - Mode X: along the Y axis, need >= 8 steps to separate the maximal 6 dots
// from the space left below, seen by overimposing an underline ⠿_
// along the 3 dots, the Y axis is least 1,0,1,0,1,0,0,1 so 8 steps
//
// Problem: fonts are taller than wider, and terminals are tradionally 80x24, so
// - we shouldn't use square glyphs, 8x16 seems to be the minimal size
// - we should adapt the conversion to BMP to avoid accidental Y downsampling
const uint32_t kGlyphs[] = /* clang-format off */ {
/* U+0020 ' ' empty block [ascii:20,cp437:20] */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* U+2588 '█' full block [cp437] */
G(1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2584 '▄' lower half block [cp437:dc] */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2580 '▀' upper half block [cp437] */
G(1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
// Mode B
/* U+2590 '▐' right half block [cp437:de] */
G(0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1),
/* U+258c '▌' left half block [cp437] */
G(1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0),
/* U+259d '▝' quadrant upper right */
G(0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* U+2599 '▙' quadrant upper left and lower left and lower right */
G(1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,0),
/* U+2597 '▗' quadrant lower right */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1),
/* U+259b '▛' quadrant upper left and upper right and lower left */
G(1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,1),
/* U+2596 '▖' quadrant lower left */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0),
/* U+259c '▜' quadrant upper left and upper right and lower right */
G(1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,0),
/* U+2598 '▘' quadrant upper left */
G(1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* U+259F '▟' quadrant upper right and lower left and lower right */
G(0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,0),
/* U+259e '▞' quadrant upper right and lower left */
G(0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,1,
1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0),
/* U+259a '▚' quadrant upper left and lower right */
G(1,1,0,0,
1,1,0,0,
1,1,0,0,
1,1,0,0,
0,0,1,1,
0,0,1,1,
0,0,1,1,
0,0,1,0),
// Mode C
/* U+2594 '▔' upper one eighth block */
G(1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* U+2581 '▁' lower one eighth block */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1),
/* U+2582 '▂' lower one quarter block */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1),
/* U+2583 '▃' lower three eighths block */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2585 '▃' lower five eighths block */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2586 '▆' lower three quarters block */
G(0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+2587 '▇' lower seven eighths block */
G(0,0,0,0,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1),
/* U+258e '▎' left one quarter block */
G(1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0,
1,0,0,0),
/* U+258a '▊' left three quarters block */
G(1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0,
1,1,1,0),
/* ▁ *\
2501▕━▎box drawings heavy horizontal
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25019▕┉▎box drawings heavy quadruple dash horizontal
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,0,1,0,
0,1,0,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
2503▕┃▎box drawings heavy vertical
\* ▔ */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
254b▕╋▎box drawings heavy vertical and horizontal
\* ▔ */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
1,1,1,1,
1,1,1,1,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
2579▕╹▎box drawings heavy up
\* ▔ */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
257a▕╺▎box drawings heavy right
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,1,1,
0,0,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
257b▕╻▎box drawings heavy down
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
2578▕╸▎box drawings heavy left
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,0,0,
1,1,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
250f▕┏▎box drawings heavy down and right
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,1,1,1,
0,1,1,1,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
251b▕┛▎box drawings heavy up and left
\* ▔ */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
1,1,1,0,
1,1,1,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
2513▕┓▎box drawings heavy down and left
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,0,
1,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,0),
/* ▁ *\
2517▕┗▎box drawings heavy up and right
\* ▔ */
G(0,1,1,0,
0,1,1,0,
0,1,1,0,
0,1,1,1,
0,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25E2▕◢▎black lower right triangle
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,1,
0,0,1,1,
1,1,1,1,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25E3▕◣▎black lower left triangle
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,0,0,0,
1,1,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25E4▕◥▎black upper right triangle
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,1,1,
0,0,0,1,
0,0,0,0,
0,0,0,0),
/* ▁ *\
25E5▕◤▎black upper left triangle
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
1,1,0,0,
1,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
2500▕═▎box drawings double horizontal
\* ▔ */
G(0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
23BB▕⎻▎horizontal scan line 3
\* ▔ */
G(0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0),
/* ▁ *\
23BD▕⎼▎horizontal scan line 9
\* ▔ */
G(0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
1,1,1,1,
0,0,0,0,
0,0,0,0),
} /* clang-format on */;
const char16_t kRunes[] = {
u' ', /* 0020 empty block [ascii:20,cp437:20] */
u'', /* 2588 full block [cp437] */
u'', /* 2584 lower half block [cp437:dc] */
u'', /* 2580 upper half block [cp437] */
u'', /* 2590 right half block [cp437:de] */
u'', /* 258C left half block */
u'', /* 259D quadrant upper right */
u'', /* 2599 quadrant upper left and lower left and lower right */
u'', /* 2597 quadrant lower right */
u'', /* 259B quadrant upper left and upper right and lower left */
u'', /* 2596 quadrant lower left */
u'', /* 259C quadrant upper left and upper right and lower right */
u'', /* 2598 quadrant upper left */
u'', /* 259F quadrant upper right and lower left and lower right */
u'', /* 259E quadrant upper right and lower left */
u'', /* 259A quadrant upper left and lower right */
u'', /* 2594 upper one eighth block */
u'', /* 2581 lower one eighth block */
u'', /* 2582 lower one quarter block */
u'', /* 2583 lower three eighths block */
u'', /* 2585 lower five eighths block */
u'', /* 2586 lower three quarters block */
u'', /* 2587 lower seven eighths block */
u'', /* 258E left one quarter block */
u'', /* 258A left three quarters block */
u'', /* 2501 box drawings heavy horizontal */
u'', /* 2509 box drawings heavy quadruple dash horizontal */
u'', /* 2503 box drawings heavy vertical */
u'', /* 254B box drawings heavy vertical & horiz. */
u'', /* 2579 box drawings heavy up */
u'', /* 257A box drawings heavy right */
u'', /* 257B box drawings heavy down */
u'', /* 2578 box drawings heavy left */
u'', /* 250F box drawings heavy down and right */
u'', /* 251B box drawings heavy up and left */
u'', /* 2513 box drawings heavy down and left */
u'', /* 2517 box drawings heavy up and right */
u'', /* 25E2 black lower right triangle */
u'', /* 25E3 black lower left triangle */
u'', /* 25E4 black upper right triangle */
u'', /* 25E5 black upper left triangle */
u'', /* 2550 box drawings double horizontal */
u'', /* 23BB horizontal scan line 3 */
u'', /* 23BD horizontal scan line 9 */
};