Notcurses 3.0.13
a blingful library for TUIs and character graphics
Loading...
Searching...
No Matches
sprite.h
Go to the documentation of this file.
1#ifndef NOTCURSES_SPRITE
2#define NOTCURSES_SPRITE
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8#include <stdint.h>
9#include <stdbool.h>
10#include "fbuf.h"
11
12#define SIXEL_MAX_REGISTERS 65534 // 65535 is used for transparent
13
14struct tinfo;
15struct ncpile;
16struct ncplane;
17struct sixelmap;
18struct blitterargs;
19
20typedef enum {
21 SPRIXEL_QUIESCENT, // up-to-date and visible at the proper place
22 SPRIXEL_UNSEEN, // not yet loaded, invisible, but wants loading
23 SPRIXEL_LOADED, // loaded, but not yet made visible (kitty-only)
24 SPRIXEL_INVALIDATED, // not up-to-date, need reload
25 SPRIXEL_HIDE, // queued for destruction
26 SPRIXEL_MOVED, // visible, up-to-date, but in the wrong place
27} sprixel_e;
28
29// elements of the T-A matrix describe transparency and annihilation at a
30// per-cell basis, making up something of a state machine. when a sprixel
31// plane is first created, the TAM is (meaninglessly) initialized to all
32// zeroes (SPRIXCELL_OPAQUE). during the construction of the sprixel from
33// an RGBA frame, OPAQUE entries are possibly marked MIXED or TRANSPARENT.
34// subsequent sprixels blitted to the same plane will reuse the TAM, and
35// retain any SPRIXCELL_ANNIHILATED entries, cutting them out of the
36// sprixel.
37//
38// sixel can transition to ANNIHILATED via a no-op; kitty can transition
39// to ANNIHILATED only by wiping the cell (removing it from the sprixel via
40// all-0 alphas), deleting the bitmap, and displaying it once more. sixel
41// bitmaps are removed by obliterating them with new output, while kitty
42// bitmaps are removed by a fixed-length terminal escape. an important
43// implication is that sixels cannot be progressively reduced by emitting
44// progressively more transparent sixels atop one another--to remove a
45// cell from a Sixel sprixel, it is necessary to print a glyph. the same
46// goes for Kitty sprixels, but there we delete and rerender bitmaps
47// in toto without glyph involvement.
48//
49// a glyph above an OPAQUE sprixel requires annihilating the underlying cell,
50// and emitting the glyph only after annihilation is complete. a glyph below
51// an OPAQUE sprixel should never be emitted (update the lastframe to
52// contain it, but do not mark the cell damaged). should the sprixel be
53// removed, the cell will be marked damaged, and the glyph will be updated.
54//
55// a glyph above a MIXED sprixcell requires the same process as one above an
56// OPAQUE sprixcell. a glyph below a MIXED sprixcell can be emitted, but a
57// Sixel-based sprixel must then be printed afresh. a Kitty-based sprixel
58// needn't be touched in this case.
59//
60// a glyph above a TRANSPARENT sprixcell requires annihilating the underlying
61// cell, but this is a special annihilation which never requires a wipe nor
62// redisplay, just the O(1) state transition. a glyph below a TRANSPARENT
63// sprixcell can be emitted with no change to the sprixcell. TRANSPARENT
64// sprixcells move to ANNIHILATED_TRANS upon annihilation.
65//
66// a glyph above an ANNIHILATED sprixcell can be emitted with no change to
67// the sprixcell. it does not make sense to emit a glyph below an ANNIHILATED
68// sprixcell; if there is no longer a glyph above the sprixcell, the sprixcell
69// must transition back to its original state (see below).
70//
71// rendering a new RGBA frame into the same sprixel plane can result in changes
72// between OPAQUE, MIXED, and TRANSPARENT. an OPAQUE sprixcell which becomes
73// TRANSPARENT or MIXED upon rendering a new RGBA frame must damage its cell,
74// since the glyph underneath might have changed without being emitted. the
75// new glyph must be emitted prior to redisplay of the sprixel.
76//
77// an ANNIHILATED sprixcell with no glyph above it must be restored to its
78// original form (from the most recent RGBA frame). this requires the original
79// pixel data. for Sixel, we must keep the palette indices in an auxiliary
80// vector, hung off the TAM, updated each time we convert an RGBA frame into a
81// partially- or wholly-ANNIHILATED sprixel. for Kitty, we must keep the
82// original alpha values. the new state can be solved from this data. if the
83// new state is either OPAQUE or MIXED, the sprixel must be redisplayed. if the
84// new state is TRANSPARENT, this cell requires no such redisplay, and the
85// payload needn't be modified. to special-case this O(1) conversion, we keep a
86// distinct state, ANNIHILATED_TRANS. only a TRANSPARENT sprixcell can enter
87// into this state.
88//
89// when a sprixel is removed from the rendering pile, in Sixel all cells it
90// covered must be marked damaged, so that they are rendered, obliterating
91// the bitmap. in Kitty the bitmap can simply be deleted, except for those
92// cells which were SPRIXCELL_OPAQUE (they must be damaged).
93//
94// when a sprixel is moved, its TAM must be updated. OPAQUE, MIXED, and
95// TRANSPARENT cells retain their entries. ANNIHILATED cells remain
96// ANNIHILATED if their new absolute position corresponds to an ANNIHILATED
97// cell; they otherwise transition back as outlined above. this is because
98// ANNIHILATION is a property of those glyphs above us, while the other
99// three are internal, intrinsic properties. for Sixel, all cells no longer
100// covered must be damaged for rerendering, and the sprixel must subsequently
101// be displayed at its new position. for Kitty, the sprixel must be deleted,
102// and all cells no longer covered but which were previously under an OPAQUE
103// cell must be damaged for rerendering (not to erase the bitmap, but because
104// they might have changed without being emitted while obstructed by the
105// sprixel). the sprixel should be displayed at its new position. using Kitty's
106// bitmap movement is also acceptable, rather than a deletion and rerender.
107// whichever method is used, it is necessary to recover any ANNIHILATED cells
108// before moving or redisplaying the sprixel.
109//
110// all emissions take place at rasterization time. cell wiping happens at
111// rendering time. cell reconstruction happens at rendering time (for
112// ANNIHILATED cells which are no longer ANNIHILATED), or at blittime for
113// a new RGBA frame.
114typedef enum {
115 SPRIXCELL_TRANSPARENT, // all pixels are naturally transparent
116 SPRIXCELL_OPAQUE_SIXEL, // no transparent pixels in this cell
118 SPRIXCELL_MIXED_SIXEL, // this cell has both opaque and transparent pixels
120 SPRIXCELL_ANNIHILATED, // this cell has been wiped (all trans)
121 SPRIXCELL_ANNIHILATED_TRANS, // this transparent cell is covered
123
124// a TAM entry is a sprixcell_e state plus a possible auxiliary vector for
125// reconstruction of annihilated cells, valid only for SPRIXCELL_ANNIHILATED.
126typedef struct tament {
128 void* auxvector; // palette entries for sixel, alphas for kitty
130
131// a sprixel represents a bitmap, using whatever local protocol is available.
132// there is a list of sprixels per ncpile. there ought never be very many
133// associated with a context (a dozen or so at max). with the kitty protocol,
134// we can register them, and then manipulate them by id. with the sixel
135// protocol, we just have to rewrite them. there's a doubly-linked list of
136// sprixels per ncpile, to which the pile keeps a head link.
137typedef struct sprixel {
139 uint32_t id; // embedded into gcluster field of nccell, 24 bits
140 // both the plane and visual can die before the sprixel does. they are
141 // responsible in such a case for NULLing out this link themselves.
142 struct ncplane* n; // associated ncplane
143 sprixel_e invalidated;// sprixel invalidation state
144 struct sprixel* next;
145 struct sprixel* prev;
146 unsigned dimy, dimx; // cell geometry
147 int pixy, pixx; // pixel geometry (might be smaller than cell geo)
148 // each tacache entry is one of 0 (standard opaque cell), 1 (cell with
149 // some transparency), 2 (annihilated, excised)
150 int movedfromy; // for SPRIXEL_MOVED, the starting absolute position,
151 int movedfromx; // so that we can damage old cells when redrawn
152 // only used for kitty-based sprixels
153 int parse_start; // where to start parsing for cell wipes
154 int pxoffy, pxoffx; // X and Y parameters to display command
155 // only used for sixel-based sprixels
156 unsigned char* needs_refresh; // one per cell, whether new frame needs damage
157 struct sixelmap* smap; // copy of palette indices + transparency bits
158 bool wipes_outstanding; // do we need rebuild the sixel next render?
159 bool animating; // do we have an active animation?
161
162static inline tament*
163create_tam(int rows, int cols){
164 // need cast for c++ callers
165 tament* tam = (tament*)malloc(sizeof(*tam) * rows * cols);
166 if(tam){
167 memset(tam, 0, sizeof(*tam) * rows * cols);
168 }
169 return tam;
170}
171
172int sprite_init(struct tinfo* t, int fd);
173int sixel_wipe(sprixel* s, int ycell, int xcell);
174// nulls out a cell from a kitty bitmap via changing the alpha value
175// throughout to 0. the same trick doesn't work on sixel, but there we
176// can just print directly over the bitmap.
177int kitty_wipe(sprixel* s, int ycell, int xcell);
178// wipes out a cell by animating an all-transparent cell, and integrating
179// it with the original image using the animation protocol of 0.20.0+.
180int kitty_wipe_animation(sprixel* s, int ycell, int xcell);
181int kitty_wipe_selfref(sprixel* s, int ycell, int xcell);
182// wipes out a cell by changing the alpha value throughout the PNG cell to 0.
183int fbcon_wipe(sprixel* s, int ycell, int xcell);
184int sixel_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec);
185int kitty_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec);
186int fbcon_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec);
187int kitty_rebuild_animation(sprixel* s, int ycell, int xcell, uint8_t* auxvec);
188int kitty_rebuild_selfref(sprixel* s, int ycell, int xcell, uint8_t* auxvec);
189int sixel_draw(const struct tinfo* ti, const struct ncpile *p, sprixel* s,
190 fbuf* f, int yoff, int xoff);
191int kitty_draw(const struct tinfo* ti, const struct ncpile *p, sprixel* s,
192 fbuf* f, int yoff, int xoff);
193int kitty_move(sprixel* s, fbuf* f, unsigned noscroll, int yoff, int xoff);
194int sixel_scrub(const struct ncpile* p, sprixel* s);
195int kitty_scrub(const struct ncpile* p, sprixel* s);
196int fbcon_scrub(const struct ncpile* p, sprixel* s);
197int kitty_remove(int id, fbuf* f);
198int kitty_clear_all(fbuf* f);
199int sixel_init_forcesdm(struct tinfo* ti, int fd);
200int sixel_init_inverted(struct tinfo* ti, int fd);
201int sixel_init(struct tinfo* ti, int fd);
202uint8_t* sixel_trans_auxvec(const struct ncpile* p);
203uint8_t* kitty_trans_auxvec(const struct ncpile* p);
204int kitty_commit(fbuf* f, sprixel* s, unsigned noscroll);
205int sixel_blit(struct ncplane* nc, int linesize, const void* data,
206 int leny, int lenx, const struct blitterargs* bargs);
207int kitty_blit(struct ncplane* nc, int linesize, const void* data,
208 int leny, int lenx, const struct blitterargs* bargs);
209int kitty_blit_animated(struct ncplane* n, int linesize, const void* data,
210 int leny, int lenx, const struct blitterargs* bargs);
211int kitty_blit_selfref(struct ncplane* nc, int linesize, const void* data,
212 int leny, int lenx, const struct blitterargs* bargs);
213int fbcon_blit(struct ncplane* nc, int linesize, const void* data,
214 int leny, int lenx, const struct blitterargs* bargs);
215int fbcon_draw(const struct tinfo* ti, sprixel* s, int yoff, int xoff);
216void fbcon_scroll(const struct ncpile* p, struct tinfo* ti, int rows);
217void sixel_refresh(const struct ncpile* p, sprixel* s);
218
219// takes ownership of s on success.
220int sprixel_load(sprixel* spx, fbuf* f, unsigned pixy, unsigned pixx,
221 int parse_start, sprixel_e state);
222
223// called when a sprixel's cell-pixel geometry needs to change to |ncellpxy,ncellpxx|.
224int sprixel_rescale(sprixel* spx, unsigned ncellpixy, unsigned ncellpixx);
225
226// cleans up the sixel worker threads
227void sixel_cleanup(struct tinfo* ti);
228
229#ifdef __cplusplus
230}
231#endif
232
233#endif
vopts n
Definition notcurses.h:3502
int kitty_remove(int id, fbuf *f)
Definition kitty.c:1130
int sixel_init(struct tinfo *ti, int fd)
Definition sixel.c:1602
int fbcon_scrub(const struct ncpile *p, sprixel *s)
Definition linux.c:113
int kitty_move(sprixel *s, fbuf *f, unsigned noscroll, int yoff, int xoff)
Definition kitty.c:1194
int kitty_draw(const struct tinfo *ti, const struct ncpile *p, sprixel *s, fbuf *f, int yoff, int xoff)
sprixcell_e
Definition sprite.h:114
@ SPRIXCELL_ANNIHILATED
Definition sprite.h:120
@ SPRIXCELL_TRANSPARENT
Definition sprite.h:115
@ SPRIXCELL_ANNIHILATED_TRANS
Definition sprite.h:121
@ SPRIXCELL_MIXED_SIXEL
Definition sprite.h:118
@ SPRIXCELL_MIXED_KITTY
Definition sprite.h:119
@ SPRIXCELL_OPAQUE_SIXEL
Definition sprite.h:116
@ SPRIXCELL_OPAQUE_KITTY
Definition sprite.h:117
int sixel_scrub(const struct ncpile *p, sprixel *s)
int kitty_wipe(sprixel *s, int ycell, int xcell)
Definition kitty.c:448
int kitty_blit_animated(struct ncplane *n, int linesize, const void *data, int leny, int lenx, const struct blitterargs *bargs)
int sprixel_load(sprixel *spx, fbuf *f, unsigned pixy, unsigned pixx, int parse_start, sprixel_e state)
Definition sprite.c:154
int sprixel_rescale(sprixel *spx, unsigned ncellpixy, unsigned ncellpixx)
Definition sprite.c:225
int sixel_rebuild(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
Definition sixel.c:1724
uint8_t * kitty_trans_auxvec(const struct ncpile *p)
int kitty_scrub(const struct ncpile *p, sprixel *s)
int kitty_rebuild_selfref(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
Definition kitty.c:950
int sixel_init_inverted(struct tinfo *ti, int fd)
Definition sixel.c:1592
int sprite_init(struct tinfo *t, int fd)
Definition sprite.c:214
int kitty_clear_all(fbuf *f)
Definition kitty.c:1210
int sixel_blit(struct ncplane *nc, int linesize, const void *data, int leny, int lenx, const struct blitterargs *bargs)
void fbcon_scroll(const struct ncpile *p, struct tinfo *ti, int rows)
Definition linux.c:807
int kitty_rebuild(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
Definition kitty.c:219
int kitty_blit_selfref(struct ncplane *nc, int linesize, const void *data, int leny, int lenx, const struct blitterargs *bargs)
uint8_t * sixel_trans_auxvec(const struct ncpile *p)
int kitty_rebuild_animation(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
Definition kitty.c:972
int sixel_wipe(sprixel *s, int ycell, int xcell)
Definition sixel.c:655
void sixel_refresh(const struct ncpile *p, sprixel *s)
void sixel_cleanup(struct tinfo *ti)
Definition sixel.c:1764
int fbcon_wipe(sprixel *s, int ycell, int xcell)
Definition linux.c:16
int fbcon_draw(const struct tinfo *ti, sprixel *s, int yoff, int xoff)
int fbcon_rebuild(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
Definition linux.c:791
int kitty_wipe_animation(sprixel *s, int ycell, int xcell)
Definition kitty.c:394
int kitty_commit(fbuf *f, sprixel *s, unsigned noscroll)
Definition kitty.c:534
sprixel_e
Definition sprite.h:20
@ SPRIXEL_UNSEEN
Definition sprite.h:22
@ SPRIXEL_LOADED
Definition sprite.h:23
@ SPRIXEL_QUIESCENT
Definition sprite.h:21
@ SPRIXEL_INVALIDATED
Definition sprite.h:24
@ SPRIXEL_HIDE
Definition sprite.h:25
@ SPRIXEL_MOVED
Definition sprite.h:26
int sixel_draw(const struct tinfo *ti, const struct ncpile *p, sprixel *s, fbuf *f, int yoff, int xoff)
int kitty_blit(struct ncplane *nc, int linesize, const void *data, int leny, int lenx, const struct blitterargs *bargs)
int sixel_init_forcesdm(struct tinfo *ti, int fd)
Definition sixel.c:1588
int fbcon_blit(struct ncplane *nc, int linesize, const void *data, int leny, int lenx, const struct blitterargs *bargs)
Definition linux.c:44
int kitty_wipe_selfref(sprixel *s, int ycell, int xcell)
Definition kitty.c:410
Definition fbuf.h:25
int parse_start
Definition sprite.h:153
int pxoffx
Definition sprite.h:154
struct sprixel * prev
Definition sprite.h:145
bool animating
Definition sprite.h:159
unsigned dimx
Definition sprite.h:146
int movedfromx
Definition sprite.h:151
int pxoffy
Definition sprite.h:154
int pixx
Definition sprite.h:147
int movedfromy
Definition sprite.h:150
int pixy
Definition sprite.h:147
bool wipes_outstanding
Definition sprite.h:158
unsigned dimy
Definition sprite.h:146
fbuf glyph
Definition sprite.h:138
struct sprixel * next
Definition sprite.h:144
struct ncplane * n
Definition sprite.h:142
unsigned char * needs_refresh
Definition sprite.h:156
uint32_t id
Definition sprite.h:139
struct sixelmap * smap
Definition sprite.h:157
sprixel_e invalidated
Definition sprite.h:143
void * auxvector
Definition sprite.h:128
sprixcell_e state
Definition sprite.h:127