mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-02 09:40:15 +00:00
break apart render/rasterize #155
This commit is contained in:
parent
d9b721971a
commit
56a54b5441
@ -1491,13 +1491,6 @@ cell_noforeground_p(const cell* c){
|
|||||||
return cell_simple_p(c) && isspace(c->gcluster);
|
return cell_simple_p(c) && isspace(c->gcluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
// True if the cell does not generate background pixels. Only the FULL BLOCK
|
|
||||||
// glyph has this property, AFAIK.
|
|
||||||
static inline bool
|
|
||||||
cell_nobackground_p(const struct ncplane* n, const cell* c){
|
|
||||||
return !cell_simple_p(c) && !strcmp(cell_extended_gcluster(n, c), "\xe2\x96\x88");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
cell_load_simple(struct ncplane* n, cell* c, char ch){
|
cell_load_simple(struct ncplane* n, cell* c, char ch){
|
||||||
cell_release(n, c);
|
cell_release(n, c);
|
||||||
|
@ -320,6 +320,14 @@ cell_debug(const ncplane* p, const cell* c){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// True if the cell does not generate background pixels. Only the FULL BLOCK
|
||||||
|
// glyph has this property, AFAIK.
|
||||||
|
// FIXME set a bit, doing this at load time
|
||||||
|
static inline bool
|
||||||
|
cell_nobackground_p(const egcpool* e, const cell* c){
|
||||||
|
return !cell_simple_p(c) && !strcmp(egcpool_extended_gcluster(e, c), "\xe2\x96\x88");
|
||||||
|
}
|
||||||
|
|
||||||
// no CLOCK_MONOTONIC_RAW on FreeBSD as of 12.0 :/
|
// no CLOCK_MONOTONIC_RAW on FreeBSD as of 12.0 :/
|
||||||
#ifndef CLOCK_MONOTONIC_RAW
|
#ifndef CLOCK_MONOTONIC_RAW
|
||||||
#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
|
#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
|
||||||
|
199
src/lib/render.c
199
src/lib/render.c
@ -11,6 +11,7 @@ mutex_unlock(void* vlock){
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
blocking_write(int fd, const char* buf, size_t buflen){
|
blocking_write(int fd, const char* buf, size_t buflen){
|
||||||
|
//fprintf(stderr, "writing %zu to %d...\n", buflen, fd);
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
do{
|
do{
|
||||||
ssize_t w = write(fd, buf + written, buflen - written);
|
ssize_t w = write(fd, buf + written, buflen - written);
|
||||||
@ -82,7 +83,7 @@ update_render_stats(const struct timespec* time1, const struct timespec* time0,
|
|||||||
// 256 colors, this is the 16 normal ones, 6x6x6 color cubes, and 32 greys.
|
// 256 colors, this is the 16 normal ones, 6x6x6 color cubes, and 32 greys.
|
||||||
// it's probably better to sample the darker regions rather than cover so much
|
// it's probably better to sample the darker regions rather than cover so much
|
||||||
// chroma, but whatever....FIXME
|
// chroma, but whatever....FIXME
|
||||||
static inline int
|
/*static inline int
|
||||||
prep_optimized_palette(notcurses* nc, FILE* out __attribute__ ((unused))){
|
prep_optimized_palette(notcurses* nc, FILE* out __attribute__ ((unused))){
|
||||||
if(nc->RGBflag){
|
if(nc->RGBflag){
|
||||||
return 0; // DirectColor, no need to write palette
|
return 0; // DirectColor, no need to write palette
|
||||||
@ -92,7 +93,7 @@ prep_optimized_palette(notcurses* nc, FILE* out __attribute__ ((unused))){
|
|||||||
}
|
}
|
||||||
// FIXME
|
// FIXME
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// reshape the shadow framebuffer to match the stdplane's dimensions, throwing
|
// reshape the shadow framebuffer to match the stdplane's dimensions, throwing
|
||||||
// away the old one.
|
// away the old one.
|
||||||
@ -244,7 +245,7 @@ visible_cell(cell* c, int y, int x, ncplane* n, int* previousz){
|
|||||||
// number of columns occupied by this EGC (only an approximation; it's actually
|
// number of columns occupied by this EGC (only an approximation; it's actually
|
||||||
// a property of the font being used).
|
// a property of the font being used).
|
||||||
static int
|
static int
|
||||||
term_putc(FILE* out, const ncplane* n, const cell* c){
|
term_putc(FILE* out, const egcpool* e, const cell* c){
|
||||||
if(cell_simple_p(c)){
|
if(cell_simple_p(c)){
|
||||||
if(c->gcluster == 0 || iscntrl(c->gcluster)){
|
if(c->gcluster == 0 || iscntrl(c->gcluster)){
|
||||||
// fprintf(stderr, "[ ]\n");
|
// fprintf(stderr, "[ ]\n");
|
||||||
@ -266,7 +267,7 @@ term_putc(FILE* out, const ncplane* n, const cell* c){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
const char* ext = extended_gcluster(n, c);
|
const char* ext = egcpool_extended_gcluster(e, c);
|
||||||
// fprintf(stderr, "[%s]\n", ext);
|
// fprintf(stderr, "[%s]\n", ext);
|
||||||
#ifdef __USE_GNU
|
#ifdef __USE_GNU
|
||||||
if(fputs_unlocked(ext, out) < 0){ // FIXME check for short write?
|
if(fputs_unlocked(ext, out) < 0){ // FIXME check for short write?
|
||||||
@ -483,93 +484,52 @@ cellcmp_and_dupfar(egcpool* dampool, cell* damcell, const ncplane* srcplane,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Producing the frame requires three steps:
|
||||||
|
// * render -- build up a flat framebuffer from a set of ncplanes
|
||||||
|
// * rasterize -- build up a UTF-8 stream of escapes and EGCs
|
||||||
|
// * refresh -- write the stream to the emulator
|
||||||
static inline int
|
static inline int
|
||||||
notcurses_render_internal(notcurses* nc){
|
notcurses_rasterize(notcurses* nc, unsigned char* damagemap){
|
||||||
|
FILE* out = nc->rstate.mstreamfp;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int y, x;
|
int y, x;
|
||||||
FILE* out = nc->rstate.mstreamfp;
|
|
||||||
fseeko(out, 0, SEEK_SET);
|
fseeko(out, 0, SEEK_SET);
|
||||||
|
// we only need to emit a coordinate if it was damaged. the damagemap is a
|
||||||
|
// bit per coordinate, rows by rows, column by column within a row, with the
|
||||||
|
// MSB being the first coordinate.
|
||||||
|
size_t damageidx = 0;
|
||||||
|
unsigned char damagemask = 0x80;
|
||||||
// don't write a clearscreen. we only update things that have been changed.
|
// don't write a clearscreen. we only update things that have been changed.
|
||||||
// we explicitly move the cursor at the beginning of each output line, so no
|
// we explicitly move the cursor at the beginning of each output line, so no
|
||||||
// need to home it expliticly.
|
// need to home it expliticly.
|
||||||
prep_optimized_palette(nc, out); // FIXME do what on failure?
|
|
||||||
// if this fails, struggle bravely on. we can live without a lastframe.
|
|
||||||
reshape_shadow_fb(nc);
|
|
||||||
for(y = 0 ; y < nc->stdscr->leny ; ++y){
|
for(y = 0 ; y < nc->stdscr->leny ; ++y){
|
||||||
// how many characters have we elided? it's not worthwhile to invoke a
|
// how many characters have we elided? it's not worthwhile to invoke a
|
||||||
// cursor movement with cup if we only elided one or two. set to INT_MAX
|
// cursor movement with cup if we only elided one or two. set to INT_MAX
|
||||||
// whenever we're on a new line.
|
// whenever we're on a new line.
|
||||||
int needmove = INT_MAX;
|
int needmove = INT_MAX;
|
||||||
// track the depth of our glyph, to see if we need need to stomp a wide
|
|
||||||
// glyph we're following.
|
|
||||||
int depth = 0;
|
|
||||||
// are we in the right half of a wide glyph? if so, we don't typically emit
|
|
||||||
// anything, *BUT* we must handle higher planes bisecting our wide glyph.
|
|
||||||
bool inright = false;
|
|
||||||
for(x = 0 ; x < nc->stdscr->lenx ; ++x){
|
for(x = 0 ; x < nc->stdscr->lenx ; ++x){
|
||||||
unsigned r, g, b, br, bg, bb;
|
unsigned r, g, b, br, bg, bb;
|
||||||
ncplane* p;
|
const cell* srccell = &nc->lastframe[y * nc->lfdimx + x];
|
||||||
cell c; // no need to initialize
|
// cell c;
|
||||||
p = visible_cell(&c, y, x, nc->top, &depth);
|
// memcpy(c, srccell, sizeof(*c)); // unsafe copy of gcluster
|
||||||
// don't try to print a wide character on the last column; it'll instead
|
//fprintf(stderr, "COPYING: %d from %p\n", c->gcluster, &nc->pool);
|
||||||
// be printed on the next line. they aren't output, but we can end up
|
// const char* egc = pool_egc_copy(&nc->pool, srccell);
|
||||||
// with one due to a resize. FIXME but...print what, exactly, instead?
|
// c->gcluster = 0; // otherwise cell_release() will blow up
|
||||||
if((x + 1 >= nc->stdscr->lenx && cell_double_wide_p(&c))){
|
//fprintf(stderr, "idx: %zu word: 0x%02x\n", damageidx, damagemap[damageidx]);
|
||||||
continue; // needmove will be reset as we restart the line
|
if((damagemap[damageidx] & damagemask) == 0){
|
||||||
}
|
|
||||||
bool damaged = false;
|
|
||||||
if(depth > 0){ // we are above the previous source plane
|
|
||||||
if(inright){ // wipe out the character to the left
|
|
||||||
// FIXME do this by keeping an offset for the memstream, and
|
|
||||||
// truncating it (via lseek()), methinks
|
|
||||||
cell* prev = &nc->lastframe[fbcellidx(nc->stdscr, y, x - 1)];
|
|
||||||
pool_release(&nc->pool, prev);
|
|
||||||
cell_init(prev);
|
|
||||||
// FIXME technically we need rerun the visible cell search...? gross
|
|
||||||
cell_load_simple(NULL, prev, ' ');
|
|
||||||
// FIXME this space will be the wrong color, methinks?
|
|
||||||
term_emit("cup", tiparm(nc->cup, y, x - 1), out, false);
|
|
||||||
fputc(' ', out);
|
|
||||||
inright = false;
|
|
||||||
//if(cell_simple_p(&c)){
|
|
||||||
//fprintf(stderr, "WENT BACK NOW FOR %c\n", c.gcluster);
|
|
||||||
//}else{
|
|
||||||
//fprintf(stderr, "WENT BACK NOW FOR %s\n", extended_gcluster(p, &c));
|
|
||||||
//}
|
|
||||||
damaged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// lastframe has already been sized to match the current size, so no need
|
|
||||||
// to check whether we're within its bounds. just check the cell.
|
|
||||||
if(nc->lastframe){
|
|
||||||
cell* oldcell = &nc->lastframe[fbcellidx(nc->stdscr, y, x)];
|
|
||||||
if(inright){
|
|
||||||
cell_set_wide(oldcell);
|
|
||||||
inright = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// check the damage map, unless we must repair damage done
|
|
||||||
if(cellcmp_and_dupfar(&nc->pool, oldcell, p, &c) == 0){
|
|
||||||
if(!damaged){
|
|
||||||
// no need to emit a cell; what we rendered appears to already be
|
// no need to emit a cell; what we rendered appears to already be
|
||||||
// here. no updates are performed to elision state nor lastframe.
|
// here. no updates are performed to elision state nor lastframe.
|
||||||
++nc->stats.cellelisions;
|
++nc->stats.cellelisions;
|
||||||
if(needmove < INT_MAX){
|
if(needmove < INT_MAX){
|
||||||
++needmove;
|
++needmove;
|
||||||
}
|
}
|
||||||
if(cell_double_wide_p(&c)){
|
if(cell_double_wide_p(srccell)){
|
||||||
if(needmove < INT_MAX){
|
if(needmove < INT_MAX){
|
||||||
++needmove;
|
++needmove;
|
||||||
}
|
}
|
||||||
++nc->stats.cellelisions;
|
++nc->stats.cellelisions;
|
||||||
inright = !inright;
|
}
|
||||||
}else{
|
}else{
|
||||||
inright = false;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++nc->stats.cellemissions;
|
++nc->stats.cellemissions;
|
||||||
if(needmove == 1 && nc->cuf1){
|
if(needmove == 1 && nc->cuf1){
|
||||||
ret |= term_emit("cuf1", tiparm(nc->cuf1), out, false);
|
ret |= term_emit("cuf1", tiparm(nc->cuf1), out, false);
|
||||||
@ -580,7 +540,7 @@ notcurses_render_internal(notcurses* nc){
|
|||||||
// set the style. this can change the color back to the default; if it
|
// set the style. this can change the color back to the default; if it
|
||||||
// does, we need update our elision possibilities.
|
// does, we need update our elision possibilities.
|
||||||
bool normalized;
|
bool normalized;
|
||||||
term_setstyles(nc, out, &nc->rstate.curattr, &c, &normalized);
|
ret |= term_setstyles(nc, out, &nc->rstate.curattr, srccell, &normalized);
|
||||||
if(normalized){
|
if(normalized){
|
||||||
nc->rstate.defaultelidable = true;
|
nc->rstate.defaultelidable = true;
|
||||||
nc->rstate.bgelidable = false;
|
nc->rstate.bgelidable = false;
|
||||||
@ -596,12 +556,12 @@ notcurses_render_internal(notcurses* nc){
|
|||||||
// * we are a partial glyph, and the previous was default on both, or
|
// * we are a partial glyph, and the previous was default on both, or
|
||||||
// * we are a no-foreground glyph, and the previous was default background, or
|
// * we are a no-foreground glyph, and the previous was default background, or
|
||||||
// * we are a no-background glyph, and the previous was default foreground
|
// * we are a no-background glyph, and the previous was default foreground
|
||||||
bool noforeground = cell_noforeground_p(&c);
|
bool noforeground = cell_noforeground_p(srccell);
|
||||||
bool nobackground = cell_nobackground_p(p, &c);
|
bool nobackground = cell_nobackground_p(&nc->pool, srccell);
|
||||||
if((!noforeground && cell_fg_default_p(&c)) || (!nobackground && cell_bg_default_p(&c))){
|
if((!noforeground && cell_fg_default_p(srccell)) || (!nobackground && cell_bg_default_p(srccell))){
|
||||||
if(!nc->rstate.defaultelidable){
|
if(!nc->rstate.defaultelidable){
|
||||||
++nc->stats.defaultemissions;
|
++nc->stats.defaultemissions;
|
||||||
term_emit("op", nc->op, out, false);
|
ret |= term_emit("op", nc->op, out, false);
|
||||||
}else{
|
}else{
|
||||||
++nc->stats.defaultelisions;
|
++nc->stats.defaultelisions;
|
||||||
}
|
}
|
||||||
@ -615,13 +575,13 @@ notcurses_render_internal(notcurses* nc){
|
|||||||
// foreground set iff either:
|
// foreground set iff either:
|
||||||
// * the previous was non-default, and matches what we have now, or
|
// * the previous was non-default, and matches what we have now, or
|
||||||
// * we are a no-foreground glyph (iswspace() is true)
|
// * we are a no-foreground glyph (iswspace() is true)
|
||||||
if(!cell_fg_default_p(&c)){
|
if(!cell_fg_default_p(srccell)){
|
||||||
if(!noforeground){
|
if(!noforeground){
|
||||||
cell_fg_rgb(&c, &r, &g, &b);
|
cell_fg_rgb(srccell, &r, &g, &b);
|
||||||
if(nc->rstate.fgelidable && nc->rstate.lastr == r && nc->rstate.lastg == g && nc->rstate.lastb == b){
|
if(nc->rstate.fgelidable && nc->rstate.lastr == r && nc->rstate.lastg == g && nc->rstate.lastb == b){
|
||||||
++nc->stats.fgelisions;
|
++nc->stats.fgelisions;
|
||||||
}else{
|
}else{
|
||||||
term_fg_rgb8(nc, out, r, g, b);
|
ret |= term_fg_rgb8(nc, out, r, g, b);
|
||||||
++nc->stats.fgemissions;
|
++nc->stats.fgemissions;
|
||||||
nc->rstate.fgelidable = true;
|
nc->rstate.fgelidable = true;
|
||||||
}
|
}
|
||||||
@ -631,13 +591,13 @@ notcurses_render_internal(notcurses* nc){
|
|||||||
++nc->stats.fgelisions;
|
++nc->stats.fgelisions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!cell_bg_default_p(&c)){
|
if(!cell_bg_default_p(srccell)){
|
||||||
if(!nobackground){
|
if(!nobackground){
|
||||||
cell_bg_rgb(&c, &br, &bg, &bb);
|
cell_bg_rgb(srccell, &br, &bg, &bb);
|
||||||
if(nc->rstate.bgelidable && nc->rstate.lastbr == br && nc->rstate.lastbg == bg && nc->rstate.lastbb == bb){
|
if(nc->rstate.bgelidable && nc->rstate.lastbr == br && nc->rstate.lastbg == bg && nc->rstate.lastbb == bb){
|
||||||
++nc->stats.bgelisions;
|
++nc->stats.bgelisions;
|
||||||
}else{
|
}else{
|
||||||
term_bg_rgb8(nc, out, br, bg, bb);
|
ret |= term_bg_rgb8(nc, out, br, bg, bb);
|
||||||
++nc->stats.bgemissions;
|
++nc->stats.bgemissions;
|
||||||
nc->rstate.bgelidable = true;
|
nc->rstate.bgelidable = true;
|
||||||
}
|
}
|
||||||
@ -647,9 +607,13 @@ notcurses_render_internal(notcurses* nc){
|
|||||||
++nc->stats.bgelisions;
|
++nc->stats.bgelisions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//fprintf(stderr, "[%02d/%02d] 0x%02x 0x%02x 0x%02x %p\n", y, x, r, g, b, p);
|
//fprintf(stderr, "[%02d/%02d] 0x%02x 0x%02x 0x%02x\n", y, x, r, g, b);
|
||||||
term_putc(out, p, &c);
|
ret |= term_putc(out, &nc->pool, srccell);
|
||||||
inright = cell_double_wide_p(&c);
|
}
|
||||||
|
if((damagemask >>= 1u) == 0){
|
||||||
|
damagemask = 0x80;
|
||||||
|
++damageidx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret |= fflush(out);
|
ret |= fflush(out);
|
||||||
@ -662,6 +626,71 @@ notcurses_render_internal(notcurses* nc){
|
|||||||
if(nc->renderfp){
|
if(nc->renderfp){
|
||||||
fprintf(nc->renderfp, "%s\n", nc->rstate.mstream);
|
fprintf(nc->renderfp, "%s\n", nc->rstate.mstream);
|
||||||
}
|
}
|
||||||
|
if(ret < 0){
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return nc->rstate.mstrsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
notcurses_render_internal(notcurses* nc, unsigned char* damagevec){
|
||||||
|
int ret = 0;
|
||||||
|
int y, x;
|
||||||
|
// if this fails, struggle bravely on. we can live without a lastframe.
|
||||||
|
reshape_shadow_fb(nc);
|
||||||
|
for(y = 0 ; y < nc->stdscr->leny ; ++y){
|
||||||
|
// track the depth of our glyph, to see if we need need to stomp a wide
|
||||||
|
// glyph we're following.
|
||||||
|
int depth = 0;
|
||||||
|
// are we in the right half of a wide glyph? if so, we don't typically emit
|
||||||
|
// anything, *BUT* we must handle higher planes bisecting our wide glyph.
|
||||||
|
bool inright = false;
|
||||||
|
for(x = 0 ; x < nc->stdscr->lenx ; ++x){
|
||||||
|
ncplane* p;
|
||||||
|
cell c; // no need to initialize
|
||||||
|
p = visible_cell(&c, y, x, nc->top, &depth);
|
||||||
|
// don't try to print a wide character on the last column; it'll instead
|
||||||
|
// be printed on the next line. they aren't output, but we can end up
|
||||||
|
// with one due to a resize. FIXME but...print what, exactly, instead?
|
||||||
|
if((x + 1 >= nc->stdscr->lenx && cell_double_wide_p(&c))){
|
||||||
|
continue; // needmove will be reset as we restart the line
|
||||||
|
}
|
||||||
|
if(depth > 0){ // we are above the previous source plane
|
||||||
|
if(inright){ // wipe out the character to the left
|
||||||
|
// FIXME do this by keeping an offset for the memstream, and
|
||||||
|
// truncating it (via lseek()), methinks
|
||||||
|
cell* prev = &nc->lastframe[fbcellidx(nc->stdscr, y, x - 1)];
|
||||||
|
pool_release(&nc->pool, prev);
|
||||||
|
cell_init(prev);
|
||||||
|
// FIXME technically we need rerun the visible cell search...? gross
|
||||||
|
cell_load_simple(NULL, prev, ' ');
|
||||||
|
inright = false;
|
||||||
|
//if(cell_simple_p(&c)){
|
||||||
|
//fprintf(stderr, "WENT BACK NOW FOR %c\n", c.gcluster);
|
||||||
|
//}else{
|
||||||
|
//fprintf(stderr, "WENT BACK NOW FOR %s\n", extended_gcluster(p, &c));
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// lastframe has already been sized to match the current size, so no need
|
||||||
|
// to check whether we're within its bounds. just check the cell.
|
||||||
|
if(nc->lastframe){
|
||||||
|
cell* oldcell = &nc->lastframe[fbcellidx(nc->stdscr, y, x)];
|
||||||
|
if(inright){
|
||||||
|
cell_set_wide(oldcell);
|
||||||
|
inright = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// check the damage map
|
||||||
|
if(cellcmp_and_dupfar(&nc->pool, oldcell, p, &c)){
|
||||||
|
//fprintf(stderr, "setting damagevec idx %d mask %u\n", (y * nc->stdscr->lenx + x) / CHAR_BIT, (0x80 >> ((y * nc->stdscr->lenx + x) % CHAR_BIT)));
|
||||||
|
damagevec[(y * nc->stdscr->lenx + x) / CHAR_BIT] |=
|
||||||
|
(0x80 >> ((y * nc->stdscr->lenx + x) % CHAR_BIT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inright = cell_double_wide_p(&c);
|
||||||
|
}
|
||||||
|
}
|
||||||
if(ret){
|
if(ret){
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -674,7 +703,15 @@ int notcurses_render(notcurses* nc){
|
|||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
|
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
|
||||||
pthread_mutex_lock(&nc->lock);
|
pthread_mutex_lock(&nc->lock);
|
||||||
pthread_cleanup_push(mutex_unlock, &nc->lock);
|
pthread_cleanup_push(mutex_unlock, &nc->lock);
|
||||||
int bytes = notcurses_render_internal(nc);
|
int bytes = -1;
|
||||||
|
size_t damagevecsize = nc->stdscr->leny * nc->stdscr->lenx / CHAR_BIT +
|
||||||
|
!!(nc->stdscr->leny * nc->stdscr->lenx % CHAR_BIT);
|
||||||
|
unsigned char* damagevec = malloc(damagevecsize);
|
||||||
|
memset(damagevec, 0, damagevecsize);
|
||||||
|
if(notcurses_render_internal(nc, damagevec) >= 0){
|
||||||
|
bytes = notcurses_rasterize(nc, damagevec);
|
||||||
|
}
|
||||||
|
free(damagevec);
|
||||||
int dimy, dimx;
|
int dimy, dimx;
|
||||||
notcurses_resize(nc, &dimy, &dimx);
|
notcurses_resize(nc, &dimy, &dimx);
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &done);
|
clock_gettime(CLOCK_MONOTONIC_RAW, &done);
|
||||||
|
Loading…
Reference in New Issue
Block a user