diff --git a/data/aidsrobots.jpeg b/data/aidsrobots.jpeg index fa9a976fc..596b7c80e 100644 Binary files a/data/aidsrobots.jpeg and b/data/aidsrobots.jpeg differ diff --git a/data/dsscaw-purp.png b/data/dsscaw-purp.png index 96f0047db..4d8a04129 100644 Binary files a/data/dsscaw-purp.png and b/data/dsscaw-purp.png differ diff --git a/data/tetris-background.jpg b/data/tetris-background.jpg index b650943d6..2034ad67f 100644 Binary files a/data/tetris-background.jpg and b/data/tetris-background.jpg differ diff --git a/data/tetris-background.xcf b/data/tetris-background.xcf index c2e5f8714..d02def8a4 100644 Binary files a/data/tetris-background.xcf and b/data/tetris-background.xcf differ diff --git a/src/lib/internal.h b/src/lib/internal.h index 485ff3e36..7ce82a5f9 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -804,7 +804,7 @@ nc_err_e ncvisual_blit(struct ncvisual* ncv, int rows, int cols, void nclog(const char* fmt, ...); -bool is_linux_console(const notcurses* nc); +bool is_linux_console(const notcurses* nc, unsigned no_font_changes); // get a file descriptor for the controlling tty device, -1 on error int get_controlling_tty(void); @@ -830,6 +830,11 @@ int get_controlling_tty(void); if((nc)->loglevel >= NCLOGLEVEL_DEBUG){ \ nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } }while(0); +#define logtrace(nc, fmt, ...) do{ \ + if((nc)->loglevel >= NCLOGLEVEL_TRACE){ \ + nclog("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); } }while(0); + + // Convert a notcurses log level to some multimedia library equivalent. int ffmpeg_log_level(ncloglevel_e level); diff --git a/src/lib/linux.c b/src/lib/linux.c index 4de3805f6..51ed1d96b 100644 --- a/src/lib/linux.c +++ b/src/lib/linux.c @@ -4,19 +4,294 @@ #include #include +static unsigned char* +get_glyph(struct consolefontdesc* cfd, unsigned idx){ + if(idx >= cfd->charcount){ + return NULL; + } + return (unsigned char*)cfd->chardata + 32 * idx; +} + +static int // insert U+2580 (upper half block) +shim_upper_half_block(struct consolefontdesc* cfd, unsigned idx){ + unsigned char* glyph = get_glyph(cfd, idx); + if(glyph == NULL){ + return -1; + } + unsigned r; + for(r = 0 ; r < cfd->charheight / 2 ; ++r, ++glyph){ + *glyph = 0xff; + } + while(r < cfd->charheight){ + *glyph = 0; + ++glyph; + ++r; + } + return 0; +} + +static int // insert U+2584 (lower half block) +shim_lower_half_block(struct consolefontdesc* cfd, unsigned idx){ + unsigned char* glyph = get_glyph(cfd, idx); + if(glyph == NULL){ + return -1; + } + unsigned r; + for(r = 0 ; r < cfd->charheight / 2 ; ++r, ++glyph){ + *glyph = 0; + } + while(r < cfd->charheight){ + *glyph = 0xff; + ++glyph; + ++r; + } + return 0; +} + +static int // insert U+258c (left half block) +shim_left_half_block(struct consolefontdesc* cfd, unsigned idx){ + unsigned char* glyph = get_glyph(cfd, idx); + if(glyph == NULL){ + return -1; + } + for(unsigned r = 0 ; r < cfd->charheight ; ++r, ++glyph){ + *glyph = 0xf0; + } + return 0; +} + +static int // insert U+2590 (right half block) +shim_right_half_block(struct consolefontdesc* cfd, unsigned idx){ + unsigned char* glyph = get_glyph(cfd, idx); + if(glyph == NULL){ + return -1; + } + for(unsigned r = 0 ; r < cfd->charheight ; ++r, ++glyph){ + *glyph = 0x0f; + } + return 0; +} + +static int // insert U+2598 (quadrant upper left) +shim_upper_left_quad(struct consolefontdesc* cfd, unsigned idx){ + unsigned char* glyph = get_glyph(cfd, idx); + if(glyph == NULL){ + return -1; + } + for(unsigned r = cfd->charheight / 2 ; r < cfd->charheight ; ++r, ++glyph){ + *glyph = 0; + } + return 0; +} + +static int // insert U+259D (quadrant upper right) +shim_upper_right_quad(struct consolefontdesc* cfd, unsigned idx){ + unsigned char* glyph = get_glyph(cfd, idx); + if(glyph == NULL){ + return -1; + } + for(unsigned r = 0 ; r < cfd->charheight / 2 ; ++r, ++glyph){ + *glyph = 0x0f; + } + for(unsigned r = cfd->charheight / 2 ; r < cfd->charheight ; ++r, ++glyph){ + *glyph = 0; + } + return 0; +} + +static int // insert U+2598 (quadrant lower left) +shim_lower_left_quad(struct consolefontdesc* cfd, unsigned idx){ + unsigned char* glyph = get_glyph(cfd, idx); + if(glyph == NULL){ + return -1; + } + for(unsigned r = 0 ; r < cfd->charheight / 2 ; ++r, ++glyph){ + *glyph = 0; + } + for(unsigned r = cfd->charheight / 2 ; r < cfd->charheight ; ++r, ++glyph){ + *glyph = 0xf0; + } + return 0; +} + +static int // insert U+2597 (quadrant lower right) +shim_lower_right_quad(struct consolefontdesc* cfd, unsigned idx){ + unsigned char* glyph = get_glyph(cfd, idx); + if(glyph == NULL){ + return -1; + } + for(unsigned r = 0 ; r < cfd->charheight / 2 ; ++r, ++glyph){ + *glyph = 0; + } + for(unsigned r = cfd->charheight / 2 ; r < cfd->charheight ; ++r, ++glyph){ + *glyph = 0x0f; + } + return 0; +} + +static int +program_line_drawing_chars(const notcurses* nc, struct unimapdesc* map){ + struct simset { + wchar_t* ws; + } sets[] = { + { + .ws = L"/╱", + }, { + .ws = L"\\╲", + }, { + .ws = L"X╳", + }, { + .ws = L"└┕┖┗╘╙╚╰", + }, { + .ws = L"┘┙┚┛╛╜╝╯", + }, { + .ws = L"┌┍┎┏╒╓╔╭", + }, { + .ws = L"┐┑┒┓╕╖╗╮", + }, { + .ws = L"─━┄┅┈┉╌╍═╼╾", + }, { + .ws = L"│┃┆┇┊┋╎╏║╽╿", + }, { + .ws = L"├┝┞┟┠┡┢┣╞╟╠", + }, { + .ws = L"┤┥┦┧┨┩┪┫╡╢╣", + }, { + .ws = L"┬┭┮┯┰┱┲┳╤╥╦", + }, { + .ws = L"┴┵┶┷┸┹┺┻╧╨╩", + }, { + .ws = L"┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋╪╫╬", + }, + }; + int toadd = 0; + for(size_t sidx = 0 ; sidx < sizeof(sets) / sizeof(*sets) ; ++sidx){ + int fontidx = -1; + struct simset* s = &sets[sidx]; + bool found[wcslen(s->ws)]; + memset(found, 0, sizeof(found)); + for(unsigned idx = 0 ; idx < map->entry_ct ; ++idx){ + for(size_t widx = 0 ; widx < wcslen(s->ws) ; ++widx){ + if(map->entries[idx].unicode == s->ws[widx]){ + logtrace(nc, "Found desired character U+%04x -> %03u\n", + map->entries[idx].unicode, map->entries[idx].fontpos); + found[widx] = true; + if(fontidx == -1){ + fontidx = map->entries[idx].fontpos; + } + } + } + } + if(fontidx > -1){ + for(size_t widx = 0 ; widx < wcslen(s->ws) ; ++widx){ + if(!found[widx]){ + logdebug(nc, "Adding mapping U+%04x -> %03u\n", s->ws[widx], fontidx); + struct unipair* tmp = realloc(map->entries, sizeof(*map->entries) * (map->entry_ct + 1)); + if(tmp == NULL){ + return -1; + } + map->entries = tmp; + map->entries[map->entry_ct].unicode = s->ws[widx]; + map->entries[map->entry_ct].fontpos = fontidx; + ++map->entry_ct; + ++toadd; + } + } + }else{ + logwarning(nc, "Couldn't find any glyphs for set %zu\n", sidx); + } + } + if(toadd == 0){ + return 0; + } + if(ioctl(nc->ttyfd, PIO_UNIMAP, map)){ + logwarning(nc, "Error setting kernel unicode map (%s)\n", strerror(errno)); + return -1; + } + loginfo(nc, "Successfully added %d kernel unicode mapping%s\n", + toadd, toadd == 1 ? "" : "s"); + return 0; +} + +static int +reprogram_linux_font(const notcurses* nc, struct consolefontdesc* cfd, + struct unimapdesc* map){ + if(ioctl(nc->ttyfd, GIO_FONTX, cfd)){ + logwarning(nc, "Error reading Linux kernelfont (%s)\n", strerror(errno)); + return -1; + } + loginfo(nc, "Kernel font size (glyphcount): %hu\n", cfd->charcount); + loginfo(nc, "Kernel font character geometry: 8x%hu\n", cfd->charheight); + if(cfd->charcount > 512){ + logwarning(nc, "Warning: kernel returned excess charcount\n"); + return -1; + } + if(ioctl(nc->ttyfd, GIO_UNIMAP, map)){ + logwarning(nc, "Error reading Linux unimap (%s)\n", strerror(errno)); + return -1; + } + loginfo(nc, "Kernel Unimap size: %hu/%hu\n", map->entry_ct, USHRT_MAX); + // for certain sets of characters, we're not going to draw them in, but we + // do want to ensure they map to something plausible... + if(program_line_drawing_chars(nc, map)){ + return -1; + } + for(unsigned idx = 0 ; idx < map->entry_ct ; ++idx){ + // FIXME check to see if our desired codepoints already map + // if already declared, trust it? + // if not, see if we ought add one or reuse something + // if we want to add, find a good place + } + return 0; +} + +static int +reprogram_console_font(const notcurses* nc){ + struct consolefontdesc cfd = {}; + cfd.charcount = 512; + size_t totsize = 32 * cfd.charcount; + cfd.chardata = malloc(totsize); + if(cfd.chardata == NULL){ + logwarning(nc, "Error acquiring %zub for font descriptors (%s)\n", totsize, strerror(errno)); + return -1; + } + struct unimapdesc map = {}; + map.entry_ct = USHRT_MAX; + totsize = map.entry_ct * sizeof(struct unipair); + map.entries = malloc(totsize); + if(map.entries == NULL){ + logwarning(nc, "Error acquiring %zub for Unicode font map (%s)\n", totsize, strerror(errno)); + free(cfd.chardata); + return -1; + } + int r = reprogram_linux_font(nc, &cfd, &map); + free(cfd.chardata); + free(map.entries); + return r; +} + // is the provided fd a Linux console? -bool is_linux_console(const notcurses* nc){ +bool is_linux_console(const notcurses* nc, unsigned no_font_changes){ + if(nc->ttyfd < 0){ + return false; + } int mode, r; if( (r = ioctl(nc->ttyfd, KDGETMODE, &mode)) ){ logdebug(nc, "Not a Linux console, KDGETMODE failed\n"); return false; } loginfo(nc, "Verified Linux console, mode %d\n", mode); + if(no_font_changes){ + logdebug(nc, "Not reprogramming the console font due to option\n"); + return true; + } + reprogram_console_font(nc); return true; } #else -bool is_linux_console(const notcurses* nc){ +bool is_linux_console(const notcurses* nc, unsigned no_font_changes){ (void)nc; + (void)no_font_changes; return false; } #endif diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 96e79ee94..f54b097f7 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -822,7 +822,7 @@ notcurses* notcurses_init(const notcurses_options* opts, FILE* outfp){ return NULL; } ret->ttyfd = get_tty_fd(ret, ret->ttyfp); - is_linux_console(ret); + is_linux_console(ret, !!(opts->flags & NCOPTION_NO_FONT_CHANGES)); notcurses_mouse_disable(ret); if(ret->ttyfd >= 0){ if(tcgetattr(ret->ttyfd, &ret->tpreserved)){ diff --git a/src/tetris/background.h b/src/tetris/background.h index 7dc9d7793..852c47c49 100644 --- a/src/tetris/background.h +++ b/src/tetris/background.h @@ -4,8 +4,7 @@ void DrawBackground(const std::string& s) { // drawn to the standard plane backg_->decode(); ncvisual_options opts{}; opts.scaling = NCSCALE_STRETCH; - auto p = backg_->render(&opts); - ncplane_greyscale(p); + backg_->render(&opts); } void DrawBoard() { // draw all fixed components of the game