diff --git a/examples/vga.c b/examples/vga.c index 262dc2a30..21f68017e 100644 --- a/examples/vga.c +++ b/examples/vga.c @@ -49,12 +49,12 @@ int main(int argc, char *argv[]) { printf("res = %d?\n", res); return -1; } - printf("Hello World! %.19Lg\n", atan2l(x, y)); + printf("\e[92;44mHello World!\e[0m %.19Lg\n", atan2l(x, y)); // read/print loop so machine doesn't reset on metal for (;;) { if ((res = readansi(0, buf, 16)) > 0) { - printf("got %`'.*s\r\n", res, buf); + printf("got \e[97m%`'.*s\e[0m\r\n", res, buf); } } } diff --git a/libc/integral/c.inc b/libc/integral/c.inc index bf1993d3e..2d5629fd5 100644 --- a/libc/integral/c.inc +++ b/libc/integral/c.inc @@ -448,6 +448,16 @@ typedef struct { #endif #endif +#ifndef unrollloops +#if !defined(__STRICT_ANSI__) && \ + ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0) >= 407 || \ + __has_attribute(__optimize__)) +#define unrollloops __attribute__((__optimize__("unroll-loops"))) +#else +#define unrollloops +#endif +#endif + #ifndef returnstwice #if !defined(__STRICT_ANSI__) && \ (__has_attribute(__returns_twice__) || \ diff --git a/libc/vga/rlinit-vesa.S b/libc/vga/rlinit-vesa.S index 691c04c76..fac5ad39b 100644 --- a/libc/vga/rlinit-vesa.S +++ b/libc/vga/rlinit-vesa.S @@ -62,9 +62,13 @@ _rlinit_vesa: testb $0b00000011,0x0417 # read keyboard shift state (as jnz .doit # given by BIOS's IRQ 1); if Shift # key pressed, activate code below + push %si # display brief message on magic key + mov $REAL(str.inform),%si + call .puts + pop %si mov $0x8300,%ax # wait for the magic key for a short - mov $(250000>>16),%cx # period of time... - mov $(250000&0xffff),%dx + mov $(1000000>>16),%cx # period of time... + mov $(1000000&0xffff),%dx push %ss pop %es mov %sp,%bx @@ -75,12 +79,14 @@ _rlinit_vesa: jnz .doit2 cmpb $0,%es:(%bx) jz .wait + call .done_inform stc .done: pop %ax pop %es ret .doit2: mov $0x8301,%ax # we got the magic key; cancel the - int $0x15 # wait timer + int $0x15 # wait timer, & erase message + call .done_inform .doit: pop %ax # we got the magic key; do stuff pop %es // fall through @@ -139,6 +145,14 @@ _rlinit_vesa: jmp 7b .endfn .do_vesa_rlinit +// Clear the informational message on the magic key. +.done_inform: + mov $0x0a00|' ',%ax + mov $7,%bx + mov $str.inform.end-str.inform-1,%cx + int $0x10 + ret + // Preliminarily choose a "default" VESA screen mode from a list of // gathered screen modes. // @@ -570,6 +584,12 @@ _rlinit_vesa: .endfn .putnl .previous +str.inform: +#define SHGLYPH "\x7f" + .ascii "\rinfo: press ",SHGLYPH,"Shift " + .asciz "to switch video mode\r" +str.inform.end: + .endobj str.inform str.no_vesa: .asciz "info: no VESA\r\n" .endobj str.no_vesa diff --git a/libc/vga/tty-graph.c b/libc/vga/tty-graph.c new file mode 100644 index 000000000..4cef1371f --- /dev/null +++ b/libc/vga/tty-graph.c @@ -0,0 +1,287 @@ +/*-*- 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│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ This is free and unencumbered software released into the public domain. │ +│ │ +│ Anyone is free to copy, modify, publish, use, compile, sell, or │ +│ distribute this software, either in source code form or as a compiled │ +│ binary, for any purpose, commercial or non-commercial, and by any │ +│ means. │ +│ │ +│ In jurisdictions that recognize copyright laws, the author or authors │ +│ of this software dedicate any and all copyright interest in the │ +│ software to the public domain. We make this dedication for the benefit │ +│ of the public at large and to the detriment of our heirs and │ +│ successors. We intend this dedication to be an overt act of │ +│ relinquishment in perpetuity of all present and future rights to this │ +│ software under copyright law. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, │ +│ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF │ +│ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. │ +│ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR │ +│ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │ +│ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR │ +│ OTHER DEALINGS IN THE SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/newbie.h" +#include "libc/macros.internal.h" +#include "libc/str/str.h" +#include "libc/vga/vga.internal.h" + +/** + * @fileoverview Routines to support output in graphical video modes for + * bare metal VGA. + * + * @see libc/vga/tty.c + */ + +static void TtyDirty(struct Tty *tty, size_t gy1, size_t gx1, + size_t gy2, size_t gx2) { + if (tty->updy1 > gy1) tty->updy1 = gy1; + if (tty->updx1 > gx1) tty->updx1 = gx1; + if (tty->updy2 < gy2) tty->updy2 = gy2; + if (tty->updx2 < gx2) tty->updx2 = gx2; +} + +static void TtyResetDirty(struct Tty *tty) { + tty->updy1 = tty->updx1 = tty->updy2 = tty->updx2 = 0; +} + +unrollloops void _TtyBgr565Update(struct Tty *tty) { + size_t gy1 = tty->updy1, gy2 = tty->updy2, + gx1 = tty->updx1, gx2 = tty->updx2, + xsfb = tty->xsfb, xs = tty->xs; + if (gy1 < gy2 && gx1 < gx2) { + size_t yleft = gy2 - gy1, xleft; + char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgr565Color); + const char *creader = tty->canvas + gy1 * xs + + gx1 * sizeof(TtyCanvasColor); + TtyResetDirty(tty); + while (yleft-- != 0) { + TtyBgr565Color *plotter = (TtyBgr565Color *)cplotter; + const TtyCanvasColor *reader = (const TtyCanvasColor *)creader; + TtyCanvasColor c; + xleft = gx2 - gx1; + while (xleft-- != 0) { + uint16_t w; + c.w = reader->w; + ++reader; + w = htole16(c.bgr.b >> 3 | c.bgr.g >> 2 << 5 | c.bgr.r >> 3 << 11); + *plotter++ = (TtyBgr565Color){w}; + } + cplotter += xsfb; + creader += xs; + } + } +} + +unrollloops void _TtyBgr555Update(struct Tty *tty) { + size_t gy1 = tty->updy1, gy2 = tty->updy2, + gx1 = tty->updx1, gx2 = tty->updx2, + xsfb = tty->xsfb, xs = tty->xs; + if (gy1 < gy2 && gx1 < gx2) { + size_t yleft = gy2 - gy1, xleft; + char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgr555Color); + const char *creader = tty->canvas + gy1 * xs + + gx1 * sizeof(TtyCanvasColor); + TtyResetDirty(tty); + while (yleft-- != 0) { + TtyBgr555Color *plotter = (TtyBgr555Color *)cplotter; + const TtyCanvasColor *reader = (const TtyCanvasColor *)creader; + TtyCanvasColor c; + xleft = gx2 - gx1; + while (xleft-- != 0) { + uint16_t w; + c.w = reader->w; + ++reader; + w = htole16(c.bgr.b >> 3 | c.bgr.g >> 3 << 5 | c.bgr.r >> 3 << 10); + *plotter++ = (TtyBgr555Color){w}; + } + cplotter += xsfb; + creader += xs; + } + } +} + +unrollloops void _TtyBgrxUpdate(struct Tty *tty) { + size_t gy1 = tty->updy1, gy2 = tty->updy2, + gx1 = tty->updx1, gx2 = tty->updx2, + xsfb = tty->xsfb, xs = tty->xs; + if (gy1 < gy2 && gx1 < gx2) { + size_t yleft = gy2 - gy1, xleft; + char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyBgrxColor); + const char *creader = tty->canvas + gy1 * xs + + gx1 * sizeof(TtyCanvasColor); + TtyResetDirty(tty); + while (yleft-- != 0) { + TtyBgrxColor *plotter = (TtyBgrxColor *)cplotter; + const TtyCanvasColor *reader = (const TtyCanvasColor *)creader; + xleft = gx2 - gx1; + while (xleft-- != 0) { + TtyCanvasColor c = *reader++; + c.bgr.x = 0xff; + *plotter++ = c; + } + cplotter += xsfb; + creader += xs; + } + } +} + +unrollloops void _TtyRgbxUpdate(struct Tty *tty) { + size_t gy1 = tty->updy1, gy2 = tty->updy2, + gx1 = tty->updx1, gx2 = tty->updx2, + xsfb = tty->xsfb, xs = tty->xs; + if (gy1 < gy2 && gx1 < gx2) { + size_t yleft = gy2 - gy1, xleft; + char *cplotter = tty->fb + gy1 * xsfb + gx1 * sizeof(TtyRgbxColor); + const char *creader = tty->canvas + gy1 * xs + + gx1 * sizeof(TtyCanvasColor); + TtyResetDirty(tty); + while (yleft-- != 0) { + TtyRgbxColor *plotter = (TtyRgbxColor *)cplotter; + const TtyCanvasColor *reader = (const TtyCanvasColor *)creader; + TtyCanvasColor ic; + TtyRgbxColor oc; + xleft = gx2 - gx1; + while (xleft-- != 0) { + ic.w = reader->w; + ++reader; + oc = (TtyRgbxColor){.rgb.r = ic.bgr.r, .rgb.g = ic.bgr.g, + .rgb.b = ic.bgr.b, .rgb.x = 0xff}; + plotter->w = oc.w; + ++plotter; + } + cplotter += xsfb; + creader += xs; + } + } +} + +static void TtyGraphDrawBitmap(struct Tty *tty, size_t gy, size_t gx, + TtyCanvasColor fg, TtyCanvasColor bg, + const uint8_t *bitmap, + size_t bm_ht, size_t bm_wid) { + size_t xs = tty->xs; + char *cplotter = tty->canvas + gy * xs + + gx * sizeof(TtyCanvasColor); + size_t yleft = bm_ht, xleft; + while (yleft-- != 0) { + TtyCanvasColor *plotter = (TtyCanvasColor *)cplotter; + xleft = bm_wid; + while (xleft >= 8) { + uint8_t bits = *bitmap++; + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + xleft -= 8; + } + if (xleft) { + uint8_t bits = *bitmap++; + switch (xleft) { + default: + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + /* fall through */ + case 6: + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + /* fall through */ + case 5: + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + /* fall through */ + case 4: + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + /* fall through */ + case 3: + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + /* fall through */ + case 2: + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + /* fall through */ + case 1: + *plotter++ = __builtin_add_overflow(bits, bits, &bits) ? fg : bg; + } + } + cplotter += xs; + } + TtyDirty(tty, gy, gx, gy + bm_ht, gx + bm_wid); +} + +static unrollloops void TtyGraphFillRect(struct Tty *tty, + size_t gy, size_t gx, + size_t fill_ht, size_t fill_wid, + TtyCanvasColor bg) { + size_t xs = tty->xs; + char *cplotter = tty->canvas + gy * xs + gx * sizeof(TtyCanvasColor); + size_t yleft = fill_ht, xleft; + while (yleft-- != 0) { + TtyCanvasColor *plotter = (TtyCanvasColor *)cplotter; + size_t i; + for (i = 0; i < fill_wid; ++i) + *plotter++ = bg; + cplotter += xs; + } + TtyDirty(tty, gy, gx, gy + fill_ht, gx + fill_wid); +} + +static void TtyGraphMoveRect(struct Tty *tty, size_t dgy, size_t dgx, + size_t sgy, size_t sgx, size_t ht, size_t wid) { + size_t xs = tty->xs, xm = wid * sizeof(TtyCanvasColor); + char *canvas = tty->canvas; + TtyDirty(tty, dgy, dgx, dgy + ht, dgx + wid); + if (dgy < sgy) { + while (ht-- != 0) { + memmove(canvas + dgy * xs + dgx * sizeof(TtyCanvasColor), + canvas + sgy * xs + sgx * sizeof(TtyCanvasColor), xm); + ++dgy; + ++sgy; + } + } else if (dgy > sgy) { + while (ht-- != 0) + memmove(canvas + (dgy + ht) * xs + dgx * sizeof(TtyCanvasColor), + canvas + (sgy + ht) * xs + sgx * sizeof(TtyCanvasColor), xm); + } +} + +void _TtyGraphDrawChar(struct Tty *tty, size_t y, size_t x, wchar_t wc) { + /* TODO: allow configuring a different font later. */ + const uint8_t *glyph; + const size_t glyph_ht = ARRAYLEN(_vga_font_default_direct[0]); + TtyCanvasColor fg = tty->fg, bg = tty->bg; + if ((tty->pr & kTtyFlip) != 0) + fg = bg, bg = tty->fg; + if (wc < L' ' || wc >= L' ' + ARRAYLEN(_vga_font_default_direct)) + glyph = _vga_font_default_direct[0]; + else + glyph = _vga_font_default_direct[wc - L' ']; + if (glyph_ht >= VGA_ASSUME_CHAR_HEIGHT_PX) + TtyGraphDrawBitmap(tty, y * tty->yc, x * tty->xc, fg, bg, + glyph, VGA_ASSUME_CHAR_HEIGHT_PX, 8); + else { + /* + * Glyph is not tall enough. Draw it out, then pad the bottom of the + * character cell with the background color. + */ + TtyGraphDrawBitmap(tty, y * tty->yc, x * tty->xc, fg, bg, + glyph, glyph_ht, 8); + TtyGraphFillRect(tty, y * tty->yc + glyph_ht, x * tty->xc, + VGA_ASSUME_CHAR_HEIGHT_PX - glyph_ht, 8, bg); + } +} + +void _TtyGraphEraseLineCells(struct Tty *tty, size_t y, size_t x, size_t n) { + size_t yc = tty->yc, xc = tty->xc; + TtyGraphFillRect(tty, y * yc, x * xc, yc, n * xc, tty->bg); +} + +void _TtyGraphMoveLineCells(struct Tty *tty, size_t dsty, size_t dstx, + size_t srcy, size_t srcx, size_t n) { + size_t yc = tty->yc, xc = tty->xc; + TtyGraphMoveRect(tty, dsty * yc, dstx * xc, srcy * yc, srcx * xc, + yc, n * xc); +} diff --git a/libc/vga/tty.c b/libc/vga/tty.greg.c similarity index 80% rename from libc/vga/tty.c rename to libc/vga/tty.greg.c index 23741ba99..e1a6c6a93 100644 --- a/libc/vga/tty.c +++ b/libc/vga/tty.greg.c @@ -20,10 +20,13 @@ #include "libc/fmt/itoa.h" #include "libc/intrin/bits.h" #include "libc/intrin/safemacros.internal.h" +#include "libc/runtime/directmap.internal.h" #include "libc/runtime/pc.internal.h" #include "libc/str/str.h" #include "libc/str/thompike.h" #include "libc/str/unicode.h" +#include "libc/sysv/consts/map.h" +#include "libc/sysv/consts/prot.h" #include "libc/sysv/errfuns.h" #include "libc/vga/vga.internal.h" @@ -37,45 +40,58 @@ * @see tool/build/lib/pty.c */ -#define DEFAULT_FG 7 -#define DEFAULT_BG 0 +#define DEFAULT_FG ((TtyCanvasColor) \ + {.bgr.r = 0xaa, .bgr.g = 0xaa, .bgr.b = 0xaa, \ + .bgr.x = 0xff}) +#define DEFAULT_BG ((TtyCanvasColor) \ + {.bgr.r = 0, .bgr.g = 0, .bgr.b = 0, .bgr.x = 0xff}) #define CRTPORT 0x3d4 static void SetYn(struct Tty *tty, unsigned short yn) { -#ifndef VGA_TTY_HEIGHT tty->yn = yn; -#endif } static void SetXn(struct Tty *tty, unsigned short xn) { -#ifndef VGA_TTY_WIDTH tty->xn = xn; -#endif } -static wchar_t *SetWcs(struct Tty *tty, wchar_t *wcs) { +static void SetYp(struct Tty *tty, unsigned short yp) { + tty->yp = yp; +} + +static void SetXp(struct Tty *tty, unsigned short xp) { + tty->xp = xp; +} + +static void SetXsFb(struct Tty *tty, unsigned short xsfb) { + tty->xsfb = xsfb; +} + +static bool SetWcs(struct Tty *tty, bool alloc_wcs) { #ifdef VGA_USE_WCS - tty->wcs = wcs; - return wcs; + struct DirectMap dm; + if (!alloc_wcs) + return false; + dm = sys_mmap_metal(NULL, Yn(tty) * Xn(tty) * sizeof(wchar_t), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (dm.addr == (void *)-1) { + tty->wcs = NULL; + return false; + } + tty->wcs = dm.addr; + return true; #else - return NULL; + return false; #endif } static size_t Yn(struct Tty *tty) { -#ifdef VGA_TTY_HEIGHT - return VGA_TTY_HEIGHT; -#else return tty->yn; -#endif } static size_t Xn(struct Tty *tty) { -#ifdef VGA_TTY_WIDTH - return VGA_TTY_WIDTH; -#else return tty->xn; -#endif } static wchar_t *Wcs(struct Tty *tty) { @@ -86,23 +102,82 @@ static wchar_t *Wcs(struct Tty *tty) { #endif } -void _StartTty(struct Tty *tty, unsigned short yn, unsigned short xn, +static void TtyTextDrawChar(struct Tty *, size_t, size_t, wchar_t); +static void TtyTextEraseLineCells(struct Tty *, size_t, size_t, size_t); +static void TtyTextMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t, + size_t); + +static void TtySetType(struct Tty *tty, unsigned char type) { + tty->type = type; + switch (type) { + case PC_VIDEO_BGR565: + tty->update = _TtyBgr565Update; + goto graphics_mode; + case PC_VIDEO_BGR555: + tty->update = _TtyBgr555Update; + goto graphics_mode; + case PC_VIDEO_BGRX8888: + tty->update = _TtyBgrxUpdate; + goto graphics_mode; + case PC_VIDEO_RGBX8888: + tty->update = _TtyRgbxUpdate; + graphics_mode: + tty->drawchar = _TtyGraphDrawChar; + tty->eraselinecells = _TtyGraphEraseLineCells; + tty->movelinecells = _TtyGraphMoveLineCells; + break; + default: + tty->drawchar = TtyTextDrawChar; + tty->eraselinecells = TtyTextEraseLineCells; + tty->movelinecells = TtyTextMoveLineCells; + } +} + +void _StartTty(struct Tty *tty, unsigned char type, + unsigned short yp, unsigned short xp, unsigned short xsfb, unsigned short starty, unsigned short startx, - unsigned char chr_ht, void *vccs, wchar_t *wcs) { - struct VgaTextCharCell *ccs = vccs; + unsigned char yc, unsigned char xc, void *fb, bool alloc_wcs) { + unsigned short yn, xn, xs = xp * sizeof(TtyCanvasColor); + struct DirectMap dm; memset(tty, 0, sizeof(struct Tty)); + SetYp(tty, yp); + SetXp(tty, xp); + SetXsFb(tty, xsfb); + tty->xs = xs; + if (type == PC_VIDEO_TEXT) { + yn = yp; + xn = xp; + tty->canvas = fb; + } else { + yn = yp / yc; + xn = xp / xc; + dm = sys_mmap_metal(NULL, (size_t)yp * xs, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (dm.addr == (void *)-1) { + /* We are a bit low on memory. Try to go on anyway. */ + tty->canvas = fb; + starty = startx = 0; + } else + tty->canvas = dm.addr; + } SetYn(tty, yn); SetXn(tty, xn); - tty->ccs = ccs; + tty->yc = yc; + tty->xc = xc; + tty->fb = fb; if (starty >= yn) starty = yn - 1; if (startx >= xn) startx = xn - 1; - if (chr_ht > 32) chr_ht = 32; tty->y = starty; tty->x = startx; - tty->chr_ht = chr_ht; - if (SetWcs(tty, wcs)) { + TtySetType(tty, type); + if (SetWcs(tty, alloc_wcs)) { + wchar_t *wcs = Wcs(tty); size_t n = (size_t)yn * xn, i; - for (i = 0; i < n; ++i) wcs[i] = bing(ccs[i].ch, 0); + if (type == PC_VIDEO_TEXT) { + struct VgaTextCharCell *ccs = fb; + for (i = 0; i < n; ++i) wcs[i] = bing(ccs[i].ch, 0); + } else + wmemset(wcs, L' ', n); } _TtyResetOutputMode(tty); } @@ -213,6 +288,25 @@ static void TtySetCodepage(struct Tty *tty, char id) { } } +/** + * Map the given direct color value to one of the 16 basic foreground colors + * or one of the 16 background colors. + * + * @see drivers/tty/vt/vt.c in Linux 5.9.14 source code + */ +static uint8_t TtyGetTextColor(TtyCanvasColor color) { + uint8_t r = color.bgr.r, g = color.bgr.g, b = color.bgr.b; + uint8_t hue = 0, max = MAX(MAX(r, g), b); + if (r > max / 2) hue |= 4; + if (g > max / 2) hue |= 2; + if (b > max / 2) hue |= 1; + if (hue == 7 && max <= 0x55) + hue = 8; + else if (max > 0xaa) + hue |= 8; + return hue; +} + /** * Map the currently active foreground & background colors & terminal * configuration to a VGA text character attribute byte. @@ -220,12 +314,13 @@ static void TtySetCodepage(struct Tty *tty, char id) { * @see VGA_USE_BLINK macro (libc/vga/vga.internal.h) * @see drivers/tty/vt/vt.c in Linux 5.9.14 source code */ -static uint8_t TtyGetVgaAttr(struct Tty *tty) { +static uint8_t TtyGetTextAttr(struct Tty *tty) { + uint8_t fg = TtyGetTextColor(tty->fg), bg = TtyGetTextColor(tty->bg); uint8_t attr; if ((tty->pr & kTtyFlip) == 0) - attr = tty->fg | tty->bg << 4; + attr = fg | bg << 4; else - attr = tty->bg | tty->fg << 4; + attr = bg | fg << 4; #ifdef VGA_USE_BLINK /* * If blinking is enabled, we can only have the 8 dark background color @@ -240,41 +335,73 @@ static uint8_t TtyGetVgaAttr(struct Tty *tty) { return attr; } -static void TtyErase(struct Tty *tty, size_t dst, size_t n) { - uint8_t attr = TtyGetVgaAttr(tty); - size_t i; +static void TtyTextDrawChar(struct Tty *tty, size_t y, size_t x, wchar_t wc) { + uint8_t attr = TtyGetTextAttr(tty); + struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas; + size_t i = tty->y * Xn(tty) + tty->x; + int c = unbing(wc); + if (c == -1) c = 0xFE; + ccs[i] = (struct VgaTextCharCell){c, attr}; +} + +static void TtyTextEraseLineCells(struct Tty *tty, size_t dsty, size_t dstx, + size_t n) { + uint8_t attr = TtyGetTextAttr(tty); + struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas; + size_t dst = dsty * Xn(tty) + dstx, i; for (i = 0; i < n; ++i) - tty->ccs[dst + i] = (struct VgaTextCharCell){' ', attr}; - if (Wcs(tty)) wmemset(Wcs(tty) + dst, L' ', n); + ccs[dst + i] = (struct VgaTextCharCell){' ', attr}; } void _TtyEraseLineCells(struct Tty *tty, size_t dsty, size_t dstx, size_t n) { - size_t xn = Xn(tty); - TtyErase(tty, dsty * xn + dstx, n); + tty->eraselinecells(tty, dsty, dstx, n); + if (Wcs(tty)) { + size_t i = dsty * Xn(tty) + dstx; + wmemset(Wcs(tty) + i, L' ', n); + } } void _TtyEraseLines(struct Tty *tty, size_t dsty, size_t n) { - size_t xn = Xn(tty); - TtyErase(tty, dsty * xn, n * xn); + size_t xn = Xn(tty), y; + y = dsty; + while (n-- != 0) { + _TtyEraseLineCells(tty, y, 0, xn); + ++y; + } } -static void TtyMemmove(struct Tty *tty, size_t dst, size_t src, size_t n) { - memmove(tty->ccs + dst, tty->ccs + src, n * sizeof(struct VgaTextCharCell)); - if (Wcs(tty)) wmemmove(Wcs(tty) + dst, Wcs(tty) + src, n); +static void TtyTextMoveLineCells(struct Tty *tty, size_t dsty, size_t dstx, + size_t srcy, size_t srcx, size_t n) { + size_t xn = Xn(tty); + size_t dst = dsty * xn + dstx, src = srcy * xn + srcx; + struct VgaTextCharCell *ccs = (struct VgaTextCharCell *)tty->canvas; + memmove(ccs + dst, ccs + src, n * sizeof(struct VgaTextCharCell)); } void _TtyMoveLineCells(struct Tty *tty, size_t dsty, size_t dstx, size_t srcy, size_t srcx, size_t n) { size_t xn = Xn(tty); - TtyMemmove(tty, dsty * xn + dstx, srcy * xn + srcx, n); + size_t dst = dsty * xn + dstx, src = srcy * xn + srcx; + tty->movelinecells(tty, dsty, dstx, srcy, srcx, n); + if (Wcs(tty)) wmemmove(Wcs(tty) + dst, Wcs(tty) + src, n); } void _TtyMoveLines(struct Tty *tty, size_t dsty, size_t srcy, size_t n) { size_t xn = Xn(tty); - TtyMemmove(tty, dsty * xn, srcy * xn, n * xn); + if (dsty < srcy) { + while (n-- != 0) { + _TtyMoveLineCells(tty, dsty, 0, srcy, 0, xn); + ++dsty; + ++srcy; + } + } else if (dsty > srcy) { + while (n-- != 0) + _TtyMoveLineCells(tty, dsty + n, 0, srcy + n, 0, xn); + } } void _TtyResetOutputMode(struct Tty *tty) { + tty->updy1 = tty->updx1 = tty->updy2 = tty->updx2 = 0; tty->pr = 0; tty->fg = DEFAULT_FG; tty->bg = DEFAULT_BG; @@ -354,18 +481,12 @@ static void TtyAdvance(struct Tty *tty) { } static void TtyWriteGlyph(struct Tty *tty, wint_t wc, int w) { - uint8_t attr = TtyGetVgaAttr(tty); - size_t i; - int c; if (w < 1) wc = L' ', w = 1; if ((tty->conf & kTtyRedzone) || tty->x + w > Xn(tty)) { TtyAdvance(tty); } - i = tty->y * Xn(tty) + tty->x; - c = unbing(wc); - if (c == -1) c = 0xFE; - tty->ccs[i] = (struct VgaTextCharCell){c, attr}; - if (Wcs(tty)) Wcs(tty)[i] = wc; + tty->drawchar(tty, tty->y, tty->x, wc); + if (Wcs(tty)) Wcs(tty)[tty->y * Xn(tty) + tty->x] = wc; if ((tty->x += w) >= Xn(tty)) { tty->x = Xn(tty) - 1; tty->conf |= kTtyRedzone; @@ -373,14 +494,13 @@ static void TtyWriteGlyph(struct Tty *tty, wint_t wc, int w) { } static void TtyWriteTab(struct Tty *tty) { - uint8_t attr = TtyGetVgaAttr(tty); unsigned x, x2; if (tty->conf & kTtyRedzone) { TtyAdvance(tty); } x2 = MIN(Xn(tty), ROUNDUP(tty->x + 1, 8)); for (x = tty->x; x < x2; ++x) { - tty->ccs[tty->y * Xn(tty) + x] = (struct VgaTextCharCell){' ', attr}; + tty->eraselinecells(tty, tty->y, x, 1); } if (Wcs(tty)) { for (x = tty->x; x < x2; ++x) { @@ -637,61 +757,13 @@ static void TtyCsiN(struct Tty *tty) { } } -/** - * Map the given ECMA-48 / VT100 SGR color code to a color code for a VGA - * character attribute. More precisely, map - * - * red──┐ - * green─┐│ - * blue┐││ - * intensity│││ - * ││││ - * 3210 - * - * to - * - * blue──┐ - * green─┐│ - * red┐││ - * intensity│││ - * ││││ - * 3210 - */ -static uint8_t TtyMapEcma48Color(uint8_t color) -{ - switch (color & 0b101) { - case 0b100: - case 0b001: - color ^= 0b101; - } - return color; +/** Create a direct color pixel value. */ +static TtyCanvasColor TtyMapTrueColor(uint8_t r, uint8_t g, uint8_t b) { + return (TtyCanvasColor){.bgr.r = r, .bgr.g = g, .bgr.b = b, .bgr.x = 0xff}; } -/** - * Map the given (R, G, B) triplet to one of the 16 basic foreground colors - * or one of the 16 background colors. - * - * @see drivers/tty/vt/vt.c in Linux 5.9.14 source code - */ -static uint8_t TtyMapTrueColor(uint8_t r, uint8_t g, uint8_t b) { - uint8_t hue = 0, max = MAX(MAX(r, g), b); - if (r > max / 2) hue |= 4; - if (g > max / 2) hue |= 2; - if (b > max / 2) hue |= 1; - if (hue == 7 && max <= 0x55) - hue = 8; - else if (max > 0xaa) - hue |= 8; - return hue; -} - -/** - * Map the given 256-color code one of the 16 basic foreground colors or one - * of the 8 background colors. - * - * @see drivers/tty/vt/vt.c in Linux 5.9.14 source code - */ -static uint8_t TtyMapXtermColor(uint8_t color) { +/** Map the given 256-color code to a direct color. */ +static TtyCanvasColor TtyMapXtermColor(uint8_t color) { uint8_t r, g, b; if (color < 8) { r = (color & 1) ? 0xaa : 0; @@ -713,6 +785,12 @@ static uint8_t TtyMapXtermColor(uint8_t color) { return TtyMapTrueColor(r, g, b); } +/** Map the given ECMA-48 / VT100 SGR color code to a direct color. */ +static TtyCanvasColor TtyMapEcma48Color(uint8_t color) +{ + return TtyMapXtermColor(color % 16); +} + static void TtySelectGraphicsRendition(struct Tty *tty) { char *p, c; unsigned x; @@ -983,10 +1061,10 @@ static void TtyCsi(struct Tty *tty) { } static void TtyScreenAlignmentDisplay(struct Tty *tty) { - uint8_t attr = TtyGetVgaAttr(tty); - size_t n = Yn(tty) * Xn(tty), i; - for (i = 0; i < n; ++i) tty->ccs[i] = (struct VgaTextCharCell){'E', attr}; - if (Wcs(tty)) wmemset(Wcs(tty), L'E', n); + size_t yn = Yn(tty), xn = Xn(tty), y, x; + for (y = 0; y < yn; ++y) + for (x = 0; x < xn; ++x) tty->drawchar(tty, y, x, 'E'); + if (Wcs(tty)) wmemset(Wcs(tty), L'E', yn * xn); } static void TtyEscHash(struct Tty *tty) { @@ -1083,18 +1161,21 @@ static void TtyEscAppend(struct Tty *tty, char c) { tty->esc.s[tty->esc.i - 0] = 0; } -static void TtyUpdateHwCursor(struct Tty *tty) { - unsigned char start = tty->chr_ht - 2, end = tty->chr_ht - 1; - unsigned short pos = tty->y * Xn(tty) + tty->x; - if ((tty->conf & kTtyNocursor)) start |= 1 << 5; - outb(CRTPORT, 0x0A); - outb(CRTPORT + 1, start); - outb(CRTPORT, 0x0B); - outb(CRTPORT + 1, end); - outb(CRTPORT, 0x0E); - outb(CRTPORT + 1, (unsigned char)(pos >> 8)); - outb(CRTPORT, 0x0F); - outb(CRTPORT + 1, (unsigned char)pos); +static void TtyUpdate(struct Tty *tty) { + if (tty->type == PC_VIDEO_TEXT) { + unsigned char start = tty->yc - 2, end = tty->yc - 1; + unsigned short pos = tty->y * Xn(tty) + tty->x; + if ((tty->conf & kTtyNocursor)) start |= 1 << 5; + outb(CRTPORT, 0x0A); + outb(CRTPORT + 1, start); + outb(CRTPORT, 0x0B); + outb(CRTPORT + 1, end); + outb(CRTPORT, 0x0E); + outb(CRTPORT + 1, (unsigned char)(pos >> 8)); + outb(CRTPORT, 0x0F); + outb(CRTPORT + 1, (unsigned char)pos); + } else + tty->update(tty); } ssize_t _TtyWrite(struct Tty *tty, const void *data, size_t n) { @@ -1184,7 +1265,7 @@ ssize_t _TtyWrite(struct Tty *tty, const void *data, size_t n) { unreachable; } } - TtyUpdateHwCursor(tty); + TtyUpdate(tty); return n; } diff --git a/libc/vga/vga-font-default.c b/libc/vga/vga-font-default.c new file mode 100644 index 000000000..4c74ebb03 --- /dev/null +++ b/libc/vga/vga-font-default.c @@ -0,0 +1,1441 @@ +/* ****** AUTOMATICALLY GENERATED ****** + * by bdf2c-in-awk https://gitlab.com/tkchia/bdf2c-in-awk + * + * Command line arguments: + * NONASCII=0 SPARSE=1 COSMO=1 X=_vga_ C=... .../8x13B.bdf + * + * Font information: + * COMMENT "$ucs-fonts: 8x13B.bdf,v 1.28 2002-11-15 18:23:23+00 mgk25 Rel $" + * COMMENT "Send bug reports to Markus Kuhn " + * COPYRIGHT "Public domain font. Share and enjoy." + * + * Extra comments: + * + xorg.freedesktop.org/releases/individual/font/font-misc-misc-1.1.1.tar.bz2 + */ +const uint8_t _vga_font_default_direct[95][13] = { + [0] = { /* 32 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [1] = { /* 33 */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [2] = { /* 34 */ + 0x00, /* ........ */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [3] = { /* 35 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0xfe, /* #######. */ + 0xfe, /* #######. */ + 0x6c, /* .##.##.. */ + 0xfe, /* #######. */ + 0xfe, /* #######. */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [4] = { /* 36 */ + 0x00, /* ........ */ + 0x10, /* ...#.... */ + 0x7c, /* .#####.. */ + 0xd6, /* ##.#.##. */ + 0xd0, /* ##.#.... */ + 0xf0, /* ####.... */ + 0x7c, /* .#####.. */ + 0x1e, /* ...####. */ + 0x16, /* ...#.##. */ + 0xd6, /* ##.#.##. */ + 0x7c, /* .#####.. */ + 0x10, /* ...#.... */ + 0x00, /* ........ */ + }, + [5] = { /* 37 */ + 0x00, /* ........ */ + 0xe6, /* ###..##. */ + 0xa6, /* #.#..##. */ + 0xec, /* ###.##.. */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x6e, /* .##.###. */ + 0xca, /* ##..#.#. */ + 0xce, /* ##..###. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [6] = { /* 38 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x78, /* .####... */ + 0xcc, /* ##..##.. */ + 0xcc, /* ##..##.. */ + 0x78, /* .####... */ + 0xce, /* ##..###. */ + 0xcc, /* ##..##.. */ + 0x7e, /* .######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [7] = { /* 39 */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [8] = { /* 40 */ + 0x00, /* ........ */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x18, /* ...##... */ + 0x0c, /* ....##.. */ + 0x00, /* ........ */ + }, + [9] = { /* 41 */ + 0x00, /* ........ */ + 0x60, /* .##..... */ + 0x30, /* ..##.... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x60, /* .##..... */ + 0x00, /* ........ */ + }, + [10] = { /* 42 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x10, /* ...#.... */ + 0x10, /* ...#.... */ + 0xfe, /* #######. */ + 0x38, /* ..###... */ + 0x38, /* ..###... */ + 0x6c, /* .##.##.. */ + 0x44, /* .#...#.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [11] = { /* 43 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x7e, /* .######. */ + 0x7e, /* .######. */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [12] = { /* 44 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x3c, /* ..####.. */ + 0x1c, /* ...###.. */ + 0x1c, /* ...###.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x00, /* ........ */ + }, + [13] = { /* 45 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7e, /* .######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [14] = { /* 46 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x3c, /* ..####.. */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [15] = { /* 47 */ + 0x00, /* ........ */ + 0x02, /* ......#. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x60, /* .##..... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0x80, /* #....... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [16] = { /* 48 */ + 0x00, /* ........ */ + 0x38, /* ..###... */ + 0x6c, /* .##.##.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x6c, /* .##.##.. */ + 0x38, /* ..###... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [17] = { /* 49 */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x38, /* ..###... */ + 0x78, /* .####... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x7e, /* .######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [18] = { /* 50 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x60, /* .##..... */ + 0xc0, /* ##...... */ + 0xfe, /* #######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [19] = { /* 51 */ + 0x00, /* ........ */ + 0xfe, /* #######. */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x3c, /* ..####.. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [20] = { /* 52 */ + 0x00, /* ........ */ + 0x0c, /* ....##.. */ + 0x1c, /* ...###.. */ + 0x3c, /* ..####.. */ + 0x6c, /* .##.##.. */ + 0xcc, /* ##..##.. */ + 0xcc, /* ##..##.. */ + 0xfe, /* #######. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [21] = { /* 53 */ + 0x00, /* ........ */ + 0xfe, /* #######. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xfc, /* ######.. */ + 0xe6, /* ###..##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [22] = { /* 54 */ + 0x00, /* ........ */ + 0x3c, /* ..####.. */ + 0x60, /* .##..... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xfc, /* ######.. */ + 0xe6, /* ###..##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xe6, /* ###..##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [23] = { /* 55 */ + 0x00, /* ........ */ + 0xfe, /* #######. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [24] = { /* 56 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [25] = { /* 57 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xce, /* ##..###. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xce, /* ##..###. */ + 0x7e, /* .######. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x78, /* .####... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [26] = { /* 58 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x3c, /* ..####.. */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x3c, /* ..####.. */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [27] = { /* 59 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x3c, /* ..####.. */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x3c, /* ..####.. */ + 0x1c, /* ...###.. */ + 0x1c, /* ...###.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x00, /* ........ */ + }, + [28] = { /* 60 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x60, /* .##..... */ + 0x30, /* ..##.... */ + 0x18, /* ...##... */ + 0x0c, /* ....##.. */ + 0x06, /* .....##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [29] = { /* 61 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7e, /* .######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7e, /* .######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [30] = { /* 62 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x60, /* .##..... */ + 0x30, /* ..##.... */ + 0x18, /* ...##... */ + 0x0c, /* ....##.. */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x60, /* .##..... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [31] = { /* 63 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [32] = { /* 64 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xfe, /* #######. */ + 0xce, /* ##..###. */ + 0xde, /* ##.####. */ + 0xd2, /* ##.#..#. */ + 0xd2, /* ##.#..#. */ + 0xde, /* ##.####. */ + 0xe0, /* ###..... */ + 0x7e, /* .######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [33] = { /* 65 */ + 0x00, /* ........ */ + 0x38, /* ..###... */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xfe, /* #######. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [34] = { /* 66 */ + 0x00, /* ........ */ + 0xfc, /* ######.. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x7c, /* .#####.. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0xfc, /* ######.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [35] = { /* 67 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xe6, /* ###..##. */ + 0xc6, /* ##...##. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc6, /* ##...##. */ + 0xe6, /* ###..##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [36] = { /* 68 */ + 0x00, /* ........ */ + 0xfc, /* ######.. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0xfc, /* ######.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [37] = { /* 69 */ + 0x00, /* ........ */ + 0xfe, /* #######. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xf8, /* #####... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xfe, /* #######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [38] = { /* 70 */ + 0x00, /* ........ */ + 0xfe, /* #######. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xf8, /* #####... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [39] = { /* 71 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xce, /* ##..###. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [40] = { /* 72 */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xfe, /* #######. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [41] = { /* 73 */ + 0x00, /* ........ */ + 0x3c, /* ..####.. */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x3c, /* ..####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [42] = { /* 74 */ + 0x00, /* ........ */ + 0x0e, /* ....###. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [43] = { /* 75 */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xcc, /* ##..##.. */ + 0xd8, /* ##.##... */ + 0xf0, /* ####.... */ + 0xf0, /* ####.... */ + 0xd8, /* ##.##... */ + 0xcc, /* ##..##.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [44] = { /* 76 */ + 0x00, /* ........ */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc2, /* ##....#. */ + 0xfe, /* #######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [45] = { /* 77 */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xee, /* ###.###. */ + 0xfe, /* #######. */ + 0xd6, /* ##.#.##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [46] = { /* 78 */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xe6, /* ###..##. */ + 0xe6, /* ###..##. */ + 0xf6, /* ####.##. */ + 0xde, /* ##.####. */ + 0xce, /* ##..###. */ + 0xce, /* ##..###. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [47] = { /* 79 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [48] = { /* 80 */ + 0x00, /* ........ */ + 0xfc, /* ######.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xfc, /* ######.. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [49] = { /* 81 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xde, /* ##.####. */ + 0x7c, /* .#####.. */ + 0x06, /* .....##. */ + 0x00, /* ........ */ + }, + [50] = { /* 82 */ + 0x00, /* ........ */ + 0xfc, /* ######.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xfc, /* ######.. */ + 0xf8, /* #####... */ + 0xcc, /* ##..##.. */ + 0xcc, /* ##..##.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [51] = { /* 83 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc0, /* ##...... */ + 0x7c, /* .#####.. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [52] = { /* 84 */ + 0x00, /* ........ */ + 0x7e, /* .######. */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [53] = { /* 85 */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [54] = { /* 86 */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x44, /* .#...#.. */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0x38, /* ..###... */ + 0x38, /* ..###... */ + 0x10, /* ...#.... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [55] = { /* 87 */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xd6, /* ##.#.##. */ + 0xd6, /* ##.#.##. */ + 0xfe, /* #######. */ + 0x6c, /* .##.##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [56] = { /* 88 */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0x38, /* ..###... */ + 0x38, /* ..###... */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [57] = { /* 89 */ + 0x00, /* ........ */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x66, /* .##..##. */ + 0x3c, /* ..####.. */ + 0x3c, /* ..####.. */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [58] = { /* 90 */ + 0x00, /* ........ */ + 0xfe, /* #######. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x60, /* .##..... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xfe, /* #######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [59] = { /* 91 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + }, + [60] = { /* 92 */ + 0x00, /* ........ */ + 0x80, /* #....... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0x60, /* .##..... */ + 0x30, /* ..##.... */ + 0x18, /* ...##... */ + 0x0c, /* ....##.. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x02, /* ......#. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [61] = { /* 93 */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + }, + [62] = { /* 94 */ + 0x00, /* ........ */ + 0x10, /* ...#.... */ + 0x38, /* ..###... */ + 0x6c, /* .##.##.. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [63] = { /* 95 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* #######. */ + 0x00, /* ........ */ + }, + [64] = { /* 96 */ + 0x00, /* ........ */ + 0x30, /* ..##.... */ + 0x18, /* ...##... */ + 0x0c, /* ....##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [65] = { /* 97 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0x06, /* .....##. */ + 0x7e, /* .######. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xce, /* ##..###. */ + 0x76, /* .###.##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [66] = { /* 98 */ + 0x00, /* ........ */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xdc, /* ##.###.. */ + 0xe6, /* ###..##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xe6, /* ###..##. */ + 0xdc, /* ##.###.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [67] = { /* 99 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xe6, /* ###..##. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xe6, /* ###..##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [68] = { /* 100 */ + 0x00, /* ........ */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x76, /* .###.##. */ + 0xce, /* ##..###. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xce, /* ##..###. */ + 0x76, /* .###.##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [69] = { /* 101 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xfe, /* #######. */ + 0xc0, /* ##...... */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [70] = { /* 102 */ + 0x00, /* ........ */ + 0x3c, /* ..####.. */ + 0x66, /* .##..##. */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0xfc, /* ######.. */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [71] = { /* 103 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7e, /* .######. */ + 0xcc, /* ##..##.. */ + 0xcc, /* ##..##.. */ + 0xcc, /* ##..##.. */ + 0x78, /* .####... */ + 0xf0, /* ####.... */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + }, + [72] = { /* 104 */ + 0x00, /* ........ */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xdc, /* ##.###.. */ + 0xe6, /* ###..##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [73] = { /* 105 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x38, /* ..###... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x3c, /* ..####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [74] = { /* 106 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x00, /* ........ */ + 0x0e, /* ....###. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + }, + [75] = { /* 107 */ + 0x00, /* ........ */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xcc, /* ##..##.. */ + 0xd8, /* ##.##... */ + 0xf0, /* ####.... */ + 0xf0, /* ####.... */ + 0xd8, /* ##.##... */ + 0xcc, /* ##..##.. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [76] = { /* 108 */ + 0x00, /* ........ */ + 0x38, /* ..###... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x3c, /* ..####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [77] = { /* 109 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x6c, /* .##.##.. */ + 0xfe, /* #######. */ + 0xd6, /* ##.#.##. */ + 0xd6, /* ##.#.##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [78] = { /* 110 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xdc, /* ##.###.. */ + 0xe6, /* ###..##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [79] = { /* 111 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [80] = { /* 112 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xdc, /* ##.###.. */ + 0xe6, /* ###..##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xe6, /* ###..##. */ + 0xdc, /* ##.###.. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + }, + [81] = { /* 113 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x76, /* .###.##. */ + 0xce, /* ##..###. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xce, /* ##..###. */ + 0x76, /* .###.##. */ + 0x06, /* .....##. */ + 0x06, /* .....##. */ + }, + [82] = { /* 114 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xdc, /* ##.###.. */ + 0xe6, /* ###..##. */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0xc0, /* ##...... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [83] = { /* 115 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x7c, /* .#####.. */ + 0xc6, /* ##...##. */ + 0x60, /* .##..... */ + 0x38, /* ..###... */ + 0x0c, /* ....##.. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [84] = { /* 116 */ + 0x00, /* ........ */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0xfc, /* ######.. */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x60, /* .##..... */ + 0x66, /* .##..##. */ + 0x3c, /* ..####.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [85] = { /* 117 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xce, /* ##..###. */ + 0x76, /* .###.##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [86] = { /* 118 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x6c, /* .##.##.. */ + 0x6c, /* .##.##.. */ + 0x38, /* ..###... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [87] = { /* 119 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xd6, /* ##.#.##. */ + 0xd6, /* ##.#.##. */ + 0xfe, /* #######. */ + 0x6c, /* .##.##.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [88] = { /* 120 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x6c, /* .##.##.. */ + 0x38, /* ..###... */ + 0x6c, /* .##.##.. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [89] = { /* 121 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xc6, /* ##...##. */ + 0xce, /* ##..###. */ + 0x76, /* .###.##. */ + 0x06, /* .....##. */ + 0xc6, /* ##...##. */ + 0x7c, /* .#####.. */ + }, + [90] = { /* 122 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0xfe, /* #######. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x60, /* .##..... */ + 0xc0, /* ##...... */ + 0xfe, /* #######. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [91] = { /* 123 */ + 0x00, /* ........ */ + 0x1e, /* ...####. */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x18, /* ...##... */ + 0x70, /* .###.... */ + 0x18, /* ...##... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x30, /* ..##.... */ + 0x1e, /* ...####. */ + 0x00, /* ........ */ + }, + [92] = { /* 124 */ + 0x00, /* ........ */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x18, /* ...##... */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, + [93] = { /* 125 */ + 0x00, /* ........ */ + 0x78, /* .####... */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x18, /* ...##... */ + 0x0e, /* ....###. */ + 0x18, /* ...##... */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x0c, /* ....##.. */ + 0x78, /* .####... */ + 0x00, /* ........ */ + }, + [94] = { /* 126 */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x72, /* .###..#. */ + 0xfe, /* #######. */ + 0x9c, /* #..###.. */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + 0x00, /* ........ */ + }, +}; diff --git a/libc/vga/vga.internal.h b/libc/vga/vga.internal.h index b33806489..bd9022aad 100644 --- a/libc/vga/vga.internal.h +++ b/libc/vga/vga.internal.h @@ -1,5 +1,6 @@ #ifndef COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_ #define COSMOPOLITAN_LIBC_VGA_VGA_INTERNAL_H_ +#include "libc/runtime/mman.internal.h" /** Preferred width of the video screen, in character units. */ #define VGA_PREFER_TTY_HEIGHT 30 @@ -111,6 +112,31 @@ struct VgaTextCharCell { uint8_t ch, attr; }; +typedef union { + uint32_t w; + struct { + uint8_t b, g, r, x; + } bgr; +} TtyBgrxColor; + +typedef union { + uint32_t w; + struct { + uint8_t r, g, b, x; + } rgb; +} TtyRgbxColor; + +typedef union { + uint16_t w; +} TtyBgr565Color; + +typedef union { + uint16_t w; +} TtyBgr555Color; + +typedef TtyBgrxColor TtyCanvasColor; +struct Tty; + struct Tty { /** * Cursor position. (y, x) = (0, 0) means the cursor is on the top left @@ -123,7 +149,12 @@ struct Tty { unsigned short yp, xp; /** * Number of bytes (NOTE) occupied by each row of pixels, including any - * invisible "pixels". + * invisible "pixels", in the video frame buffer. + */ + unsigned short xsfb; + /** + * Number of bytes (NOTE) occupied by each row of pixels, including any + * invisible "pixels", in the canvas. */ unsigned short xs; /** Type of video buffer (from mman::pc_video_type). */ @@ -131,10 +162,35 @@ struct Tty { uint32_t u8; uint32_t n8; uint32_t pr; - uint8_t fg, bg, chr_ht; + TtyCanvasColor fg, bg; + /** + * Height of each character in pixels. In text modes, this is used in + * setting the shape of the hardware cursor. + */ + uint8_t yc; + /** + * Width of each character in pixels. This is mostly useful only in + * graphics modes. + */ + uint8_t xc; uint32_t conf; unsigned short savey, savex; - struct VgaTextCharCell *ccs; + /** Actual video frame buffer as provided by the video card. */ + char *fb; + /** + * Canvas to draw into. In text modes, this is simply the frame buffer + * itself. In graphics modes, this should be separate from the frame + * buffer, & possibly allocated from main memory; we must arrange to + * update the frame buffer from the canvas every now & then. In general + * the canvas's pixel format — given by _TtyCanvasType() — may be + * different from the frame buffer's. + */ + char *canvas; + /** + * Which portions of the canvas have been updated & should later be drawn + * to screen with tty->update(). + */ + unsigned short updy1, updx1, updy2, updx2; #ifdef VGA_USE_WCS wchar_t *wcs; #endif @@ -153,11 +209,28 @@ struct Tty { size_t i; char p[256]; } input; + void (*update)(struct Tty *); + void (*drawchar)(struct Tty *, size_t, size_t, wchar_t); + void (*eraselinecells)(struct Tty *, size_t, size_t, size_t); + void (*movelinecells)(struct Tty *, size_t, size_t, size_t, size_t, size_t); }; -void _StartTty(struct Tty *, unsigned short, unsigned short, - unsigned short, unsigned short, unsigned char, - void *, wchar_t *); +forceinline unsigned char _TtyCanvasType(struct Tty *tty) { + return tty->type == PC_VIDEO_TEXT ? PC_VIDEO_TEXT : PC_VIDEO_BGRX8888; +} + +void _TtyBgrxUpdate(struct Tty *); +void _TtyRgbxUpdate(struct Tty *); +void _TtyBgr565Update(struct Tty *); +void _TtyBgr555Update(struct Tty *); +void _TtyGraphDrawChar(struct Tty *, size_t, size_t, wchar_t); +void _TtyGraphEraseLineCells(struct Tty *, size_t, size_t, size_t); +void _TtyGraphMoveLineCells(struct Tty *, size_t, size_t, size_t, size_t, + size_t); + +void _StartTty(struct Tty *, unsigned char, unsigned short, unsigned short, + unsigned short, unsigned short, unsigned short, + unsigned char, unsigned char, void *, bool); ssize_t _TtyRead(struct Tty *, void *, size_t); ssize_t _TtyWrite(struct Tty *, const void *, size_t); ssize_t _TtyWriteInput(struct Tty *, const void *, size_t); @@ -170,6 +243,7 @@ void _TtyEraseLines(struct Tty *, size_t, size_t); void _TtySetY(struct Tty *, unsigned short); void _TtySetX(struct Tty *, unsigned short); +extern const uint8_t _vga_font_default_direct[95][13]; extern struct Tty _vga_tty; ssize_t sys_readv_vga(struct Fd *, const struct iovec *, int); diff --git a/libc/vga/writev-vga.c b/libc/vga/writev-vga.c index 710820bad..b3ffbfda1 100644 --- a/libc/vga/writev-vga.c +++ b/libc/vga/writev-vga.c @@ -52,185 +52,6 @@ ssize_t sys_writev_vga(struct Fd *fd, const struct iovec *iov, int iovlen) { return wrote; } -static void _vga_init_test(void *vid_buf, unsigned char vid_type, - size_t stride) { - switch (vid_type) { - case PC_VIDEO_TEXT: - break; - case PC_VIDEO_BGR565: - { - char *row_buf = (char *)vid_buf + stride * 100; - uint16_t *row_pix = (uint16_t *)row_buf; - unsigned i; - row_pix[0] = 0x0000; - row_pix[1] = 0x0000; - row_pix[2] = 0x07fc; - row_pix[3] = 0x07fc; - row_pix[4] = 0x07fc; - row_pix[5] = 0x0000; - row_pix[6] = 0x0000; - row_pix[7] = 0x0000; - row_buf += stride; - row_pix = (uint16_t *)row_buf; - row_pix[0] = 0x0000; - row_pix[1] = 0x07fc; - row_pix[2] = 0x07fc; - row_pix[3] = 0x07fc; - row_pix[4] = 0x07fc; - row_pix[5] = 0x07fc; - row_pix[6] = 0x0000; - row_pix[7] = 0x0000; - row_buf += stride; - row_pix = (uint16_t *)row_buf; - row_pix[0] = 0x07fc; - row_pix[1] = 0x07fc; - row_pix[2] = 0x0000; - row_pix[3] = 0x0000; - row_pix[4] = 0x0000; - row_pix[5] = 0x07fc; - row_pix[6] = 0x07fc; - row_pix[7] = 0x0000; - row_buf += stride; - row_pix = (uint16_t *)row_buf; - row_pix[0] = 0x07fc; - row_pix[1] = 0x07fc; - row_pix[2] = 0x07fc; - row_pix[3] = 0x07fc; - row_pix[4] = 0x07fc; - row_pix[5] = 0x07fc; - row_pix[6] = 0x07fc; - row_pix[7] = 0x0000; - for (i = 0; i < 4; ++i) { - row_buf += stride; - row_pix = (uint16_t *)row_buf; - row_pix[0] = 0xf81f; - row_pix[1] = 0xf81f; - row_pix[2] = 0x0000; - row_pix[3] = 0x0000; - row_pix[4] = 0x0000; - row_pix[5] = 0xf81f; - row_pix[6] = 0xf81f; - row_pix[7] = 0x0000; - } - } - break; - case PC_VIDEO_BGR555: - { - char *row_buf = (char *)vid_buf + stride * 100; - uint16_t *row_pix = (uint16_t *)row_buf; - unsigned i; - row_pix[0] = 0x8000; - row_pix[1] = 0x8000; - row_pix[2] = 0x83fc; - row_pix[3] = 0x83fc; - row_pix[4] = 0x83fc; - row_pix[5] = 0x8000; - row_pix[6] = 0x8000; - row_pix[7] = 0x8000; - row_buf += stride; - row_pix = (uint16_t *)row_buf; - row_pix[0] = 0x8000; - row_pix[1] = 0x83fc; - row_pix[2] = 0x83fc; - row_pix[3] = 0x83fc; - row_pix[4] = 0x83fc; - row_pix[5] = 0x83fc; - row_pix[6] = 0x8000; - row_pix[7] = 0x8000; - row_buf += stride; - row_pix = (uint16_t *)row_buf; - row_pix[0] = 0x83fc; - row_pix[1] = 0x83fc; - row_pix[2] = 0x8000; - row_pix[3] = 0x8000; - row_pix[4] = 0x8000; - row_pix[5] = 0x83fc; - row_pix[6] = 0x83fc; - row_pix[7] = 0x8000; - row_buf += stride; - row_pix = (uint16_t *)row_buf; - row_pix[0] = 0x83fc; - row_pix[1] = 0x83fc; - row_pix[2] = 0x83fc; - row_pix[3] = 0x83fc; - row_pix[4] = 0x83fc; - row_pix[5] = 0x83fc; - row_pix[6] = 0x83fc; - row_pix[7] = 0x8000; - for (i = 0; i < 4; ++i) { - row_buf += stride; - row_pix = (uint16_t *)row_buf; - row_pix[0] = 0xfc1f; - row_pix[1] = 0xfc1f; - row_pix[2] = 0x8000; - row_pix[3] = 0x8000; - row_pix[4] = 0x8000; - row_pix[5] = 0xfc1f; - row_pix[6] = 0xfc1f; - row_pix[7] = 0x8000; - } - } - break; - default: - { - char *row_buf = (char *)vid_buf + stride * 100; - uint32_t *row_pix = (uint32_t *)row_buf; - unsigned i; - row_pix[0] = 0xff000000; - row_pix[1] = 0xff000000; - row_pix[2] = 0xff00ffe0; - row_pix[3] = 0xff00ffe0; - row_pix[4] = 0xff00ffe0; - row_pix[5] = 0xff000000; - row_pix[6] = 0xff000000; - row_pix[7] = 0xff000000; - row_buf += stride; - row_pix = (uint32_t *)row_buf; - row_pix[0] = 0xff000000; - row_pix[1] = 0xff00ffe0; - row_pix[2] = 0xff00ffe0; - row_pix[3] = 0xff00ffe0; - row_pix[4] = 0xff00ffe0; - row_pix[5] = 0xff00ffe0; - row_pix[6] = 0xff000000; - row_pix[7] = 0xff000000; - row_buf += stride; - row_pix = (uint32_t *)row_buf; - row_pix[0] = 0xff00ffe0; - row_pix[1] = 0xff00ffe0; - row_pix[2] = 0xff000000; - row_pix[3] = 0xff000000; - row_pix[4] = 0xff000000; - row_pix[5] = 0xff00ffe0; - row_pix[6] = 0xff00ffe0; - row_pix[7] = 0xff000000; - row_buf += stride; - row_pix = (uint32_t *)row_buf; - row_pix[0] = 0xff00ffe0; - row_pix[1] = 0xff00ffe0; - row_pix[2] = 0xff00ffe0; - row_pix[3] = 0xff00ffe0; - row_pix[4] = 0xff00ffe0; - row_pix[5] = 0xff00ffe0; - row_pix[6] = 0xff00ffe0; - row_pix[7] = 0xff000000; - for (i = 0; i < 4; ++i) { - row_buf += stride; - row_pix = (uint32_t *)row_buf; - row_pix[0] = 0xffff00ff; - row_pix[1] = 0xffff00ff; - row_pix[2] = 0xff000000; - row_pix[3] = 0xff000000; - row_pix[4] = 0xff000000; - row_pix[5] = 0xffff00ff; - row_pix[6] = 0xffff00ff; - row_pix[7] = 0xff000000; - } - } - break; - } -} - __attribute__((__constructor__)) static textstartup void _vga_init(void) { if (IsMetal()) { struct mman *mm = (struct mman *)(BANE + 0x0500); @@ -249,21 +70,22 @@ __attribute__((__constructor__)) static textstartup void _vga_init(void) { unsigned char col, row; } bios_curs_pos_t; bios_curs_pos_t pos = *(bios_curs_pos_t *)(BANE + 0x0450ull); - uint8_t chr_ht = *(uint8_t *)(BANE + 0x0485ull), - chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull); - if (chr_ht_hi != 0 || chr_ht > 32) - chr_ht = 32; + uint8_t chr_ht, chr_ht_hi, chr_wid; + if (vid_type == PC_VIDEO_TEXT) { + chr_ht = *(uint8_t *)(BANE + 0x0485ull), + chr_ht_hi = *(uint8_t *)(BANE + 0x0486ull); + if (chr_ht_hi != 0 || chr_ht > 32 || chr_ht < 2) + chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX; + } else + chr_ht = VGA_ASSUME_CHAR_HEIGHT_PX; + chr_wid = VGA_ASSUME_CHAR_WIDTH_PX; /* Make sure the video buffer is mapped into virtual memory. */ __invert_memory_area(mm, __get_pml4t(), vid_buf_phy, vid_buf_sz, PAGE_RW); -#if 1 - /* Test video frame buffer output. */ - _vga_init_test(vid_buf, vid_type, stride); -#endif /* * Initialize our tty structure from the current screen geometry, - * screen contents, cursor position, & character height. + * screen contents, cursor position, & character dimensions. */ - _StartTty(&_vga_tty, height, width, pos.row, pos.col, chr_ht, - vid_buf, NULL); + _StartTty(&_vga_tty, vid_type, height, width, stride, pos.row, pos.col, + chr_ht, chr_wid, vid_buf, false); } }