From 486374a6b0f950129d36ab2f3c05891dc947bb95 Mon Sep 17 00:00:00 2001 From: nick black Date: Mon, 15 Mar 2021 04:36:30 -0400 Subject: [PATCH] [pixels] build up the sprixel cache #1401 --- src/lib/direct.cpp | 6 +++++ src/lib/internal.h | 56 ++++++++++++++++++++++++++++++--------------- src/lib/notcurses.c | 1 + src/lib/sprite.c | 19 +++++++++++++++ 4 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/lib/direct.cpp b/src/lib/direct.cpp index d086dde45..08c481ae4 100644 --- a/src/lib/direct.cpp +++ b/src/lib/direct.cpp @@ -379,6 +379,12 @@ ncdirect_dump_plane(ncdirect* n, const ncplane* np, int xoff){ const int toty = ncdirect_dim_y(n); int dimy, dimx; ncplane_dim_yx(np, &dimy, &dimx); + if(np->sprite){ + if(fputs(np->sprite->glyph, n->ttyfp) == EOF){ + return -1; + } + return 0; + } //fprintf(stderr, "rasterizing %dx%d+%d\n", dimy, dimx, xoff); // save the existing style and colors const bool fgdefault = ncdirect_fg_default_p(n); diff --git a/src/lib/internal.h b/src/lib/internal.h index 075d8c6c1..e4ccd2665 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -45,6 +45,19 @@ struct ncvisual_details; // we can't define multipart ncvisual here, because OIIO requires C++ syntax, // and we can't go throwing C++ syntax into this header. so it goes. +// there is a context-wide set of displayed pixel glyphs ("sprixels"); i.e. +// these are independent of particular piles. there should never be very many +// associated with a context (a dozen or so at max). with the kitty protocol, +// we can register them, and then manipulate them by id. with the sixel +// protocol, we just have to rewrite them. +typedef struct sprixel { + char* glyph; // glyph; can be quite large + int id; // embedded into glusters field of nccell + struct ncplane* n; // associated ncplane, provides location and size + int invalidated; + struct sprixel* next; +} sprixel; + // A plane is memory for some rectilinear virtual window, plus current cursor // state for that window, and part of a pile. Each pile has a total order along // its z-axis. Functions update these virtual planes over a series of API @@ -86,6 +99,8 @@ typedef struct ncplane { struct ncplane* blist; // head of list of bound planes struct ncplane* boundto;// plane to which we are bound (ourself for roots) + sprixel* sprite; // pointer into the sprixel cache + void* userptr; // slot for the user to stick some opaque pointer int (*resizecb)(struct ncplane*); // callback after parent is resized nccell basecell; // cell written anywhere that fb[i].gcluster == 0 @@ -342,19 +357,6 @@ typedef struct ncpile { int dimy, dimx; // rows and cols at time of render } ncpile; -// there is a context-wide set of displayed pixel glyphs ("sprixels"); i.e. -// these are independent of particular piles. there should never be very many -// associated with a context (a dozen or so at max). with the kitty protocol, -// we can register them, and then manipulate them by id. with the sixel -// protocol, we just have to rewrite them. -typedef struct sprixel { - char* glyph; // glyph; can be quite large - int id; // embedded into glusters field of nccell - ncplane* n; // associated ncplane, provides location and size - int invalidated; - struct sprixel* next; -} sprixel; - // the standard pile can be reached through ->stdplane. typedef struct notcurses { ncplane* stdplane; // standard plane, covers screen @@ -387,6 +389,7 @@ typedef struct notcurses { bool suppress_banner; // from notcurses_options sprixel* sprixelcache; // list of pixel graphics currently displayed + int sprixelnonce; // next sprixel id FIXME ought be atomic // desired margins (best-effort only), copied in from notcurses_options int margin_t, margin_b, margin_r, margin_l; @@ -683,6 +686,7 @@ plane_debug(const ncplane* n, bool details){ } void sprixel_free(sprixel* s); +sprixel* sprixel_create(ncplane* n, const char* s, int bytes); static inline void pool_release(egcpool* pool, nccell* c){ @@ -1072,14 +1076,28 @@ egc_rtl(const char* egc, int* bytes){ return s; } +// a sprixel occupies the entirety of its associated plane. each cell contains +// a reference to the context-wide sprixel cache. this ought be an entirely +// new, purpose-specific plane. static inline int plane_blit_sixel(ncplane* n, const char* s, int bytes, int leny, int lenx){ - (void)n; - (void)s; - (void)bytes; - (void)leny; - (void)lenx; - // FIXME + sprixel* spx = sprixel_create(n, s, bytes); + if(spx == NULL){ + return -1; + } + char gcluster[4]; + gcluster[0] = 2; + gcluster[1] = spx->id; + gcluster[2] = 0; // FIXME + gcluster[3] = 0; // FIXME + for(int y = 0 ; y < leny ; ++y){ + for(int x = 0 ; x < lenx ; ++x){ + nccell* c = ncplane_cell_ref_yx(n, y, x); + memcpy(&c->gcluster, gcluster, sizeof(gcluster)); + c->width = lenx; + } + } + n->sprite = spx; return 0; } diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 7b543a8c1..40e4673e2 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -321,6 +321,7 @@ ncplane* ncplane_new_internal(notcurses* nc, ncplane* n, p->lenx = nopts->cols; p->x = p->y = 0; p->logrow = 0; + p->sprite = NULL; p->blist = NULL; p->name = strdup(nopts->name ? nopts->name : ""); p->align = NCALIGN_UNALIGNED; diff --git a/src/lib/sprite.c b/src/lib/sprite.c index 8eb8cb5aa..0cd34a1bd 100644 --- a/src/lib/sprite.c +++ b/src/lib/sprite.c @@ -6,3 +6,22 @@ void sprixel_free(sprixel* s){ free(s); } } + +sprixel* sprixel_create(ncplane* n, const char* s, int bytes){ + sprixel* ret = malloc(sizeof(sprixel)); + if(ret){ + if((ret->glyph = memdup(s, bytes + 1)) == NULL){ + free(ret); + return NULL; + } + ret->invalidated = 1; + ret->n = n; + if(ncplane_pile(n)){ + notcurses* nc = ncplane_notcurses(n); + ret->next = nc->sprixelcache; + nc->sprixelcache = ret; + ret->id = nc->sprixelnonce++; // FIXME should be atomic + } + } + return ret; +}