From 08b65a86994241fa841785d61a7d17bd9f0290ec Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 14 Mar 2021 17:54:36 -0400 Subject: [PATCH] sprixels: introduce sprixel cache #1401 --- src/lib/internal.h | 17 +++++++++++++++++ src/lib/notcurses.c | 11 +++++++++++ src/lib/sprite.c | 8 ++++++++ src/tests/pixel.cpp | 17 +++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 src/lib/sprite.c create mode 100644 src/tests/pixel.cpp diff --git a/src/lib/internal.h b/src/lib/internal.h index 84b0a845a..c97e61f6d 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -346,6 +346,19 @@ 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 + int cols; + int rows; + struct sprixel* next; +} sprixel; + // the standard pile can be reached through ->stdplane. typedef struct notcurses { ncplane* stdplane; // standard plane, covers screen @@ -377,6 +390,8 @@ typedef struct notcurses { pthread_mutex_t pilelock; // guards pile list, locks resize in render bool suppress_banner; // from notcurses_options + sprixel* sprixelcache; // list of pixel graphics currently displayed + // desired margins (best-effort only), copied in from notcurses_options int margin_t, margin_b, margin_r, margin_l; int loglevel; @@ -666,6 +681,8 @@ plane_debug(const ncplane* n, bool details){ } } +void sprixel_free(sprixel* s); + static inline unsigned channels_pixel_p(uint64_t channels){ return channels & CELL_PIXEL_GRAPHICS; diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index f816f7de8..7b543a8c1 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -946,6 +946,7 @@ notcurses* notcurses_core_init(const notcurses_options* opts, FILE* outfp){ ret->margin_l = opts->margin_l; ret->margin_r = opts->margin_r; ret->cursory = ret->cursorx = -1; + ret->sprixelcache = NULL; memset(&ret->stats, 0, sizeof(ret->stats)); memset(&ret->stashed_stats, 0, sizeof(ret->stashed_stats)); reset_stats(&ret->stats); @@ -1102,6 +1103,15 @@ ncpile_drop(notcurses* nc, ncpile** pile){ } } +static void +free_sprixels(notcurses* nc){ + while(nc->sprixelcache){ + sprixel* tmp = nc->sprixelcache->next; + sprixel_free(nc->sprixelcache); + nc->sprixelcache = tmp; + } +} + // drop all piles and all planes, save the standard plane and its pile void notcurses_drop_planes(notcurses* nc){ pthread_mutex_lock(&nc->pilelock); @@ -1137,6 +1147,7 @@ int notcurses_stop(notcurses* nc){ if(nc->ttyfd >= 0){ ret |= close(nc->ttyfd); } + free_sprixels(nc); egcpool_dump(&nc->pool); free(nc->lastframe); free(nc->rstate.mstream); diff --git a/src/lib/sprite.c b/src/lib/sprite.c new file mode 100644 index 000000000..8eb8cb5aa --- /dev/null +++ b/src/lib/sprite.c @@ -0,0 +1,8 @@ +#include "internal.h" + +void sprixel_free(sprixel* s){ + if(s){ + free(s->glyph); + free(s); + } +} diff --git a/src/tests/pixel.cpp b/src/tests/pixel.cpp new file mode 100644 index 000000000..e43203204 --- /dev/null +++ b/src/tests/pixel.cpp @@ -0,0 +1,17 @@ +#include "main.h" + +TEST_CASE("Pixel") { + auto nc_ = testing_notcurses(); + REQUIRE(nullptr != nc_); + ncplane* ncp_ = notcurses_stdplane(nc_); + REQUIRE(ncp_); + auto n_ = notcurses_stdplane(nc_); + REQUIRE(n_); + + if(!notcurses_check_pixel_support(nc_)){ + CHECK(!notcurses_stop(nc_)); + return; + } + + CHECK(!notcurses_stop(nc_)); +}