Notcurses 3.0.16
a blingful library for TUIs and character graphics
Loading...
Searching...
No Matches
sprite.c
Go to the documentation of this file.
1#include "internal.h"
2#include "visual-details.h"
3#include <stdatomic.h>
4
5static atomic_uint_fast32_t sprixelid_nonce;
6
7void sprixel_debug(const sprixel* s, FILE* out){
8 fprintf(out, "sprixel %d (%p) %" PRIu64 "B %dx%d (%dx%d) @%d/%d state: %d\n",
9 s->id, s, s->glyph.used, s->dimy, s->dimx, s->pixy, s->pixx,
10 s->n ? s->n->absy : 0, s->n ? s->n->absx : 0,
11 s->invalidated);
12 if(s->n){
13 int idx = 0;
14 for(unsigned y = 0 ; y < s->dimy ; ++y){
15 for(unsigned x = 0 ; x < s->dimx ; ++x){
16 fprintf(out, "%d", s->n->tam[idx].state);
17 ++idx;
18 }
19 fprintf(out, "\n");
20 }
21 idx = 0;
22 for(unsigned y = 0 ; y < s->dimy ; ++y){
23 for(unsigned x = 0 ; x < s->dimx ; ++x){
25 if(s->n->tam[idx].auxvector){
26 fprintf(out, "%03d] %p\n", idx, s->n->tam[idx].auxvector);
27 }else{
28 fprintf(out, "%03d] missing!\n", idx);
29 }
30 }
31 ++idx;
32 }
33 }
34 }
35}
36
37// doesn't splice us out of any lists, just frees
39 if(s){
40 loginfo("destroying sprixel %u", s->id);
41 if(s->n){
42 s->n->sprite = NULL;
43 }
45 free(s->needs_refresh);
46 fbuf_free(&s->glyph);
47 free(s);
48 }
49}
50
52 assert(n->sprite);
55 sprixel* hides = n->sprite;
56 int dimy = hides->dimy;
57 int dimx = hides->dimx;
58 sprixel_hide(hides);
59 return sprixel_alloc(n, dimy, dimx);
60 }
61 sixelmap_free(n->sprite->smap);
62 n->sprite->smap = NULL;
63 return n->sprite;
64}
65
66// store the original (absolute) coordinates from which we moved, so that
67// we can invalidate them in sprite_draw().
68void sprixel_movefrom(sprixel* s, int y, int x){
70 if(s->invalidated != SPRIXEL_MOVED){
71 // FIXME if we're Sixel, we need to effect any wipes that were run
72 // (we normally don't because redisplaying sixel doesn't change
73 // what's there--you can't "write transparency"). this is probably
74 // best done by conditionally reblitting the sixel(?).
75//fprintf(stderr, "SETTING TO MOVE: %d/%d was: %d\n", y, x, s->invalidated);
77 s->movedfromy = y;
78 s->movedfromx = x;
79 }
80 }
81}
82
84 if(ncplane_pile(s->n) == NULL){ // ncdirect case; destroy now
85 sprixel_free(s);
86 return;
87 }
88 // otherwise, it'll be killed in the next rendering cycle.
89 if(s->invalidated != SPRIXEL_HIDE){
90 loginfo("marking sprixel %u hidden", s->id);
92 s->movedfromy = ncplane_abs_y(s->n);
93 s->movedfromx = ncplane_abs_x(s->n);
94 // guard; might have already been replaced
95 if(s->n){
96 s->n->sprite = NULL;
97 s->n = NULL;
98 }
99 }
100}
101
102// y and x are absolute coordinates.
103void sprixel_invalidate(sprixel* s, int y, int x){
104//fprintf(stderr, "INVALIDATING AT %d/%d\n", y, x);
105 if(s->invalidated == SPRIXEL_QUIESCENT && s->n){
106 int localy = y - s->n->absy;
107 int localx = x - s->n->absx;
108//fprintf(stderr, "INVALIDATING AT %d/%d (%d/%d) TAM: %d\n", y, x, localy, localx, s->n->tam[localy * s->dimx + localx].state);
109 if(s->n->tam[localy * s->dimx + localx].state != SPRIXCELL_TRANSPARENT &&
110 s->n->tam[localy * s->dimx + localx].state != SPRIXCELL_ANNIHILATED &&
111 s->n->tam[localy * s->dimx + localx].state != SPRIXCELL_ANNIHILATED_TRANS){
113 }
114 }
115}
116
117sprixel* sprixel_alloc(ncplane* n, int dimy, int dimx){
118 sprixel* ret = malloc(sizeof(sprixel));
119 if(ret == NULL){
120 return NULL;
121 }
122 memset(ret, 0, sizeof(*ret));
123 if(fbuf_init(&ret->glyph)){
124 free(ret);
125 return NULL;
126 }
127 ret->n = n;
128 ret->dimy = dimy;
129 ret->dimx = dimx;
130 ret->id = ++sprixelid_nonce;
131 ret->needs_refresh = NULL;
132 if(ret->id >= 0x1000000){
133 ret->id = 1;
134 sprixelid_nonce = 1;
135 }
136//fprintf(stderr, "LOOKING AT %p (p->n = %p)\n", ret, ret->n);
137 if(ncplane_pile(ret->n)){ // rendered mode
138 ncpile* np = ncplane_pile(ret->n);
139 if( (ret->next = np->sprixelcache) ){
140 ret->next->prev = ret;
141 }
142 np->sprixelcache = ret;
143 ret->prev = NULL;
144//fprintf(stderr, "%p %p %p\n", nc->sprixelcache, ret, nc->sprixelcache->next);
145 }else{ // ncdirect case
146 ret->next = ret->prev = NULL;
147 }
148 return ret;
149}
150
151// |pixy| and |pixx| are the output pixel geometry (i.e. |pixy| must be a
152// multiple of 6 for sixel). output coverage ought already have been loaded.
153// takes ownership of 's' on success. frees any existing glyph.
154int sprixel_load(sprixel* spx, fbuf* f, unsigned pixy, unsigned pixx,
155 int parse_start, sprixel_e state){
156 assert(spx->n);
157 if(&spx->glyph != f){
158 fbuf_free(&spx->glyph);
159 memcpy(&spx->glyph, f, sizeof(*f));
160 }
161 spx->invalidated = state;
162 spx->pixx = pixx;
163 spx->pixy = pixy;
164 spx->parse_start = parse_start;
165 return 0;
166}
167
168// returns 1 if already annihilated, 0 if we successfully annihilated the cell,
169// or -1 if we could not annihilate the cell (i.e. we're sixel).
170int sprite_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell){
171 assert(s->n);
172 int idx = s->dimx * ycell + xcell;
173 if(s->n->tam[idx].state == SPRIXCELL_TRANSPARENT){
174 // need to make a transparent auxvec, because a reload will force us to
175 // update said auxvec, but needn't actually change the glyph. auxvec will
176 // be entirely 0s coming from pixel_trans_auxvec().
177 if(s->n->tam[idx].auxvector == NULL){
179 s->n->tam[idx].auxvector = nc->tcache.pixel_trans_auxvec(ncplane_pile(s->n));
180 if(s->n->tam[idx].auxvector == NULL){
181 return -1;
182 }
183 }
184 }
185 // no need to update to INVALIDATED; no redraw is necessary
187 return 1;
188 }
191//fprintf(stderr, "CACHED WIPE %d %d/%d\n", s->id, ycell, xcell);
192 return 0;
193 }
194 logdebug("wiping %p %d %d/%d", s->n->tam, idx, ycell, xcell);
195 int r = nc->tcache.pixel_wipe(s, ycell, xcell);
196//fprintf(stderr, "WIPED %d %d/%d ret=%d\n", s->id, ycell, xcell, r);
197 // mark the cell as annihilated whether we actually scrubbed it or not,
198 // so that we use this fact should we move to another frame
200 assert(s->n->tam[idx].auxvector);
201 return r;
202}
203
204int sprite_clear_all(const tinfo* t, fbuf* f){
205 if(t->pixel_clear_all == NULL){
206 return 0;
207 }
208 return t->pixel_clear_all(f);
209}
210
211// we don't want to seed the process-wide prng, but we do want to stir in a
212// bit of randomness for our purposes. we probably ought just use platform-
213// specific APIs, but for now, throw the timestamp in there, lame FIXME.
214int sprite_init(tinfo* t, int fd){
215 struct timeval tv;
216 gettimeofday(&tv, NULL);
217 int stir = (tv.tv_sec >> 3) ^ tv.tv_usec;
218 sprixelid_nonce = (rand() ^ stir) % 0xffffffu;
219 if(t->pixel_init == NULL){
220 return 0;
221 }
222 return t->pixel_init(t, fd);
223}
224
225int sprixel_rescale(sprixel* spx, unsigned ncellpxy, unsigned ncellpxx){
226 assert(spx->n);
227 loginfo("rescaling -> %ux%u", ncellpxy, ncellpxx);
228 // FIXME need adjust for sixel (scale_height)
229 int nrows = (spx->pixy + (ncellpxy - 1)) / ncellpxy;
230 int ncols = (spx->pixx + (ncellpxx - 1)) / ncellpxx;
231 tament* ntam = create_tam(nrows, ncols);
232 if(ntam == NULL){
233 return -1;
234 }
235 for(unsigned y = 0 ; y < spx->dimy ; ++y){
236 for(unsigned x = 0 ; x < spx->dimx ; ++x){
237 sprite_rebuild(ncplane_notcurses(spx->n), spx, y, x);
238 }
239 }
240 ncplane* ncopy = spx->n;
241 destroy_tam(spx->n);
242 // spx->n->tam has been reset, so it will not be resized herein
243 ncplane_resize_simple(spx->n, nrows, ncols);
244 spx->n = ncopy;
245 spx->n->sprite = spx;
246 spx->n->tam = ntam;
247 spx->dimy = nrows;
248 spx->dimx = ncols;
249 return 0;
250}
uint32_t idx
Definition egcpool.h:209
int r
Definition fbuf.h:226
assert(r >=0)
void sixelmap_free(struct sixelmap *s)
Definition sixel.c:216
#define loginfo(fmt,...)
Definition logging.h:42
#define logdebug(fmt,...)
Definition logging.h:52
int ncplane_abs_x(const ncplane *n)
Definition notcurses.c:2643
int ncplane_abs_y(const ncplane *n)
Definition notcurses.c:2639
const notcurses * ncplane_notcurses_const(const ncplane *n)
Definition notcurses.c:2635
notcurses * ncplane_notcurses(const ncplane *n)
Definition notcurses.c:2631
int y
Definition notcurses.h:1905
vopts n
Definition notcurses.h:3506
int int x
Definition notcurses.h:1905
@ NCPIXEL_KITTY_STATIC
Definition notcurses.h:1680
sprixel * sprixel_recycle(ncplane *n)
Definition sprite.c:51
void sprixel_movefrom(sprixel *s, int y, int x)
Definition sprite.c:68
void sprixel_hide(sprixel *s)
Definition sprite.c:83
int sprixel_load(sprixel *spx, fbuf *f, unsigned pixy, unsigned pixx, int parse_start, sprixel_e state)
Definition sprite.c:154
int sprite_wipe(const notcurses *nc, sprixel *s, int ycell, int xcell)
Definition sprite.c:170
void sprixel_invalidate(sprixel *s, int y, int x)
Definition sprite.c:103
int sprite_init(tinfo *t, int fd)
Definition sprite.c:214
int sprixel_rescale(sprixel *spx, unsigned ncellpxy, unsigned ncellpxx)
Definition sprite.c:225
void sprixel_free(sprixel *s)
Definition sprite.c:38
int sprite_clear_all(const tinfo *t, fbuf *f)
Definition sprite.c:204
void sprixel_debug(const sprixel *s, FILE *out)
Definition sprite.c:7
sprixel * sprixel_alloc(ncplane *n, int dimy, int dimx)
Definition sprite.c:117
@ SPRIXCELL_ANNIHILATED
Definition sprite.h:120
@ SPRIXCELL_TRANSPARENT
Definition sprite.h:115
@ SPRIXCELL_ANNIHILATED_TRANS
Definition sprite.h:121
sprixel_e
Definition sprite.h:20
@ SPRIXEL_UNSEEN
Definition sprite.h:22
@ SPRIXEL_QUIESCENT
Definition sprite.h:21
@ SPRIXEL_INVALIDATED
Definition sprite.h:24
@ SPRIXEL_HIDE
Definition sprite.h:25
@ SPRIXEL_MOVED
Definition sprite.h:26
Definition fbuf.h:25
uint64_t used
Definition fbuf.h:27
sprixel * sprixelcache
Definition internal.h:328
sprixel * sprite
Definition internal.h:105
int absy
Definition internal.h:83
tament * tam
Definition internal.h:106
int absx
Definition internal.h:83
tinfo tcache
Definition internal.h:360
int parse_start
Definition sprite.h:153
struct sprixel * prev
Definition sprite.h:145
unsigned dimx
Definition sprite.h:146
int movedfromx
Definition sprite.h:151
int pixx
Definition sprite.h:147
int movedfromy
Definition sprite.h:150
int pixy
Definition sprite.h:147
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
ncpixelimpl_e pixel_implementation
Definition termdesc.h:134
int(* pixel_init)(struct tinfo *ti, int fd)
Definition termdesc.h:146
int(* pixel_wipe)(struct sprixel *s, int y, int x)
Definition termdesc.h:138
uint8_t *(* pixel_trans_auxvec)(const struct ncpile *p)
Definition termdesc.h:159
int(* pixel_clear_all)(fbuf *f)
Definition termdesc.h:153
return NULL
Definition termdesc.h:229