diff --git a/README.md b/README.md index 6f0b1edfc..219bee58b 100644 --- a/README.md +++ b/README.md @@ -420,6 +420,8 @@ up someday **FIXME**. make the Internet great. It probably violates any number of copyrights. C'est la vie. * Mark Ferrari, master of the pixel, for no good reason allowed me to reproduce his incredible and groundbreaking color-cycling artwork. Thanks Mark! +* The world map image was made by [Vecteezy](https://www.vecteezy.com/free-vector/world-map), + and is used according to the terms of their License. * Finally, the [demoscene](https://en.wikipedia.org/wiki/Demoscene) and general l33t scene of the 90s and early twenty-first century endlessly inspired a young hax0r. There is great joy in computing; no one will drive us from diff --git a/USAGE.md b/USAGE.md index 237446829..119feec2b 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1130,11 +1130,11 @@ ncplane_double_box_sized(struct ncplane* n, uint32_t attr, uint64_t channels, Similarly, areas can be filled with a cell. ```c -// Starting at the specified coordinate, if it has no glyph, 'c' is copied into -// it. We do the same to all cardinally-connected glyphless cells, filling in -// everything behind a boundary. Returns the number of cells polyfilled. An -// invalid initial y, x is an error. Returns the number of cells filled, or -// -1 on error. +// Starting at the specified coordinate, if its glyph is different from that of +// 'c', 'c' is copied into it, and the original glyph is considered the fill +// target. We do the same to all cardinally-connected cells having this same +// fill target. Returns the number of cells polyfilled. An invalid initial y, x +// is an error. Returns the number of cells filled, or -1 on error. int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const cell* c); // Draw a gradient with its upper-left corner at the current cursor position, diff --git a/data/worldmap.png b/data/worldmap.png new file mode 100644 index 000000000..6ab04615a Binary files /dev/null and b/data/worldmap.png differ diff --git a/doc/man/man1/notcurses-demo.1.md b/doc/man/man1/notcurses-demo.1.md index a71b10c74..3480abc05 100644 --- a/doc/man/man1/notcurses-demo.1.md +++ b/doc/man/man1/notcurses-demo.1.md @@ -22,17 +22,18 @@ a way that is going to prevent notcurses from working. The demonstrations include (see NOTES below): -* (i)ntro—a setting of tone +* (a)ll—scroll all the glyphs of your font * (b)oxes—pulsating boxes with a transparent center * (c)hunli—the strongest woman in the world * (e)agle—they took some time off my life, back in the day -* (a)ll—scroll all the glyphs of your font * (f)allin'—the screen falls apart under heavy blows * (g)rid—a gradient of color lain atop a great grid * (h)ighcon—high contrast text atop various colors +* (i)ntro—a setting of tone * (j)ungle—low-bandwidth color cycling reveals ancient ruins * (l)uigi—a dashing Apennine plumber in a world of fire * (n)ormal—a normal map of a friend, with effects +* (o)utro—a message of hope from the library's author * (q)rcode—quick response codes (from ISO/IEC 18004:2015) * (r)eel—demonstration of the ncreel high-level widget * (s)liders—a missing-piece puzzle made up of colorful blocks @@ -41,7 +42,7 @@ The demonstrations include (see NOTES below): * (v)iew—images and a video are rendered as text * (w)hiteout—a great Nothing slowly robs the world of color * (x)ray—stimulate a logo with energy -* (o)utro—a message of hope from the library's author +* (y)ield—the best laid schemes o' mice an'men gang aft agley At any time, press 'q' to quit. The demo is best run in at least an 80x45 terminal. @@ -70,7 +71,7 @@ At any time, press 'q' to quit. The demo is best run in at least an 80x45 termin **-V**: Print the program name and version, and exit with success. demospec: Select which demos to run, and what order to run them in. The -default is **ixeathnbcgrwuvlsfjqo**. See above for a list of demos. +default is **ixeaythnbcgrwuvlsfjqo**. See above for a list of demos. Default margins are all 0, and thus the full screen will be rendered. Using **-m**, margins can be supplied. Provide a single number to set all four margins @@ -91,7 +92,7 @@ non-free under the Debian Free Software Guidelines. As a result, the are unavailable through the Debian package. If notcurses is built without multimedia support, the **chunli**, **eagle**, -**outro**, **view**, and **xray** demos will be partially or wholly +**outro**, **view**, **xray**, and **yield** demos will be partially or wholly unavailable. If notcurses is built without libqrcodegen, the **qrcode** demo will be unavailable. diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 6a1aeb2fe..c02cf2207 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1574,11 +1574,11 @@ ncplane_perimeter(struct ncplane* n, const cell* ul, const cell* ur, return ncplane_box_sized(n, ul, ur, ll, lr, hline, vline, dimy, dimx, ctlword); } -// Starting at the specified coordinate, if it has no glyph, 'c' is copied into -// it. We do the same to all cardinally-connected glyphless cells, filling in -// everything behind a boundary. Returns the number of cells polyfilled. An -// invalid initial y, x is an error. Returns the number of cells filled, or -// -1 on error. +// Starting at the specified coordinate, if its glyph is different from that of +// 'c', 'c' is copied into it, and the original glyph is considered the fill +// target. We do the same to all cardinally-connected cells having this same +// fill target. Returns the number of cells polyfilled. An invalid initial y, x +// is an error. Returns the number of cells filled, or -1 on error. API int ncplane_polyfill_yx(struct ncplane* n, int y, int x, const cell* c); // Draw a gradient with its upper-left corner at the current cursor position, diff --git a/src/demo/demo.c b/src/demo/demo.c index acc875c4f..4081849a9 100644 --- a/src/demo/demo.c +++ b/src/demo/demo.c @@ -19,7 +19,7 @@ static int democount; static demoresult* results; static char *datadir = NOTCURSES_SHARE; -static const char DEFAULT_DEMO[] = "ixeathnbcgrwuvlsfjqo"; +static const char DEFAULT_DEMO[] = "ixeaythnbcgrwuvlsfjqo"; atomic_bool interrupted = ATOMIC_VAR_INIT(false); // checked following demos, whether aborted, failed, or otherwise @@ -96,8 +96,8 @@ static struct { { "uniblock", unicodeblocks_demo, false, }, { "view", view_demo, true, }, { "whiteout", witherworm_demo, false, }, - {"xray", xray_demo, false, }, - { NULL, NULL, false, }, + { "xray", xray_demo, false, }, + { "yield", yield_demo, false, }, { NULL, NULL, false, }, }; diff --git a/src/demo/demo.h b/src/demo/demo.h index c55bd92ee..50637b8a6 100644 --- a/src/demo/demo.h +++ b/src/demo/demo.h @@ -43,6 +43,7 @@ int grid_demo(struct notcurses* nc); int fallin_demo(struct notcurses* nc); int highcontrast_demo(struct notcurses* nc); int jungle_demo(struct notcurses* nc); +int yield_demo(struct notcurses* nc); int normal_demo(struct notcurses* nc); int sliding_puzzle_demo(struct notcurses* nc); int view_demo(struct notcurses* nc); diff --git a/src/demo/yield.c b/src/demo/yield.c new file mode 100644 index 000000000..8f605da32 --- /dev/null +++ b/src/demo/yield.c @@ -0,0 +1,39 @@ +#include "demo.h" + +int yield_demo(struct notcurses* nc){ + if(!notcurses_canopen_images(nc)){ + return 0; + } + int dimy, dimx; + struct ncplane* std = notcurses_stddim_yx(nc, &dimy, &dimx); + char* pic = find_data("worldmap.png"); + nc_err_e err; + struct ncvisual* wmv = ncvisual_from_file(pic, &err); + free(pic); + if(wmv == NULL){ + return -1; + } + struct ncvisual_options vopts = { + .n = std, + .scaling = NCSCALE_STRETCH, + .blitter = NCBLIT_2x2, + }; + if(ncvisual_render(nc, wmv, &vopts) == NULL){ + ncvisual_destroy(wmv); + return -1; + } + DEMO_RENDER(nc); + demo_nanosleep(nc, &demodelay); + + cell c = CELL_SIMPLE_INITIALIZER('*'); + cell_set_fg_rgb(&c, 0xff, 0, 0); + cell_set_bg_rgb(&c, 0xff, 0, 0); + for(int i = 0 ; i < 128 ; ++i){ + // FIXME + // don't try to use polyfill; work directly on the ncvisual instead + } + cell_release(std, &c); + + ncvisual_destroy(wmv); + return 0; +} diff --git a/src/lib/fill.c b/src/lib/fill.c index 017d0e524..208a55feb 100644 --- a/src/lib/fill.c +++ b/src/lib/fill.c @@ -20,7 +20,7 @@ void ncplane_greyscale(ncplane *n){ // success. so a return of 0 means there's no work to be done here, and N means // we did some work here, filling everything we could reach. out-of-plane is 0. static int -ncplane_polyfill_recurse(ncplane* n, int y, int x, const cell* c){ +ncplane_polyfill_recurse(ncplane* n, int y, int x, const cell* c, const char* targ){ if(y >= n->leny || x >= n->lenx){ return 0; // not fillable } @@ -28,26 +28,29 @@ ncplane_polyfill_recurse(ncplane* n, int y, int x, const cell* c){ return 0; // not fillable } cell* cur = &n->fb[nfbcellidx(n, y, x)]; - if(cur->gcluster){ - return 0; // glyph, not polyfillable + char* glust = cell_strdup(n, cur); + if(strcmp(glust, targ)){ + free(glust); + return 0; } + free(glust); if(cell_duplicate(n, cur, c) < 0){ return -1; } int r, ret = 1; - if((r = ncplane_polyfill_recurse(n, y - 1, x, c)) < 0){ + if((r = ncplane_polyfill_recurse(n, y - 1, x, c, targ)) < 0){ return -1; } ret += r; - if((r = ncplane_polyfill_recurse(n, y + 1, x, c)) < 0){ + if((r = ncplane_polyfill_recurse(n, y + 1, x, c, targ)) < 0){ return -1; } ret += r; - if((r = ncplane_polyfill_recurse(n, y, x - 1, c)) < 0){ + if((r = ncplane_polyfill_recurse(n, y, x - 1, c, targ)) < 0){ return -1; } ret += r; - if((r = ncplane_polyfill_recurse(n, y, x + 1, c)) < 0){ + if((r = ncplane_polyfill_recurse(n, y, x + 1, c, targ)) < 0){ return -1; } ret += r; @@ -57,11 +60,25 @@ ncplane_polyfill_recurse(ncplane* n, int y, int x, const cell* c){ // at the initial step only, invalid y, x is an error, so explicitly check. int ncplane_polyfill_yx(ncplane* n, int y, int x, const cell* c){ int ret = -1; - if(c->gcluster){ // can't polyfill with a null EGC - if(y < n->leny && x < n->lenx){ - if(y >= 0 && x >= 0){ - ret = ncplane_polyfill_recurse(n, y, x, c); + if(y < n->leny && x < n->lenx){ + if(y >= 0 && x >= 0){ + if(y >= n->leny || x >= n->lenx){ + return -1; // not fillable } + if(y < 0 || x < 0){ + return -1; // not fillable + } + cell* cur = &n->fb[nfbcellidx(n, y, x)]; + char* targ = cell_strdup(n, cur); + char* fillegc = cell_strdup(n, c); + if(strcmp(fillegc, targ) == 0){ + free(targ); + free(fillegc); + return 0; + } + free(fillegc); + ret = ncplane_polyfill_recurse(n, y, x, c, targ); + free(targ); } } return ret; diff --git a/src/view/view.cpp b/src/view/view.cpp index 4f132ed25..4c1e0b61d 100644 --- a/src/view/view.cpp +++ b/src/view/view.cpp @@ -99,7 +99,6 @@ auto perframe(struct ncvisual* ncv, struct ncvisual_options* vopts, clock_gettime(CLOCK_MONOTONIC, &interval); uint64_t nsnow = timespec_to_ns(&interval); uint64_t absnow = timespec_to_ns(abstime); - bool paused = false; if(absnow > nsnow){ ns_to_timespec(absnow - nsnow, &interval); char32_t keyp; diff --git a/tests/fills.cpp b/tests/fills.cpp index 6964a54ed..0e846ac60 100644 --- a/tests/fills.cpp +++ b/tests/fills.cpp @@ -40,8 +40,8 @@ TEST_CASE("Fills") { REQUIRE(nullptr != pfn); CHECK(16 == ncplane_polyfill_yx(pfn, 0, 0, &c)); CHECK(0 < ncplane_putc_yx(pfn, 0, 0, &c)); - // Trying to fill the origin ought fill zero cells - CHECK(0 == ncplane_polyfill_yx(pfn, 0, 0, &c)); + // Trying to fill the origin ought now be rejected + CHECK(0 > ncplane_polyfill_yx(pfn, 0, 0, &c)); CHECK(0 == notcurses_render(nc_)); CHECK(0 == ncplane_destroy(pfn)); }