mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-18 03:25:55 +00:00
implement ncplane_mergedown() #361
This commit is contained in:
parent
38f4255dc0
commit
7e71ad8e11
@ -1749,6 +1749,28 @@ cell_simple_p(const cell* c){
|
||||
// is invalidated by any further operation on the plane 'n', so...watch out!
|
||||
API const char* cell_extended_gcluster(const struct ncplane* n, const cell* c);
|
||||
|
||||
// Returns true if the two cells are distinct EGCs, attributes, or channels.
|
||||
// The actual egcpool index needn't be the same--indeed, the planes needn't even
|
||||
// be the same. Only the expanded EGC must be equal. The EGC must be bit-equal;
|
||||
// it would probably be better to test whether they're Unicode-equal FIXME.
|
||||
static inline bool
|
||||
cellcmp(const struct ncplane* n1, const cell* RESTRICT c1,
|
||||
const struct ncplane* n2, const cell* RESTRICT c2){
|
||||
if(c1->attrword != c2->attrword){
|
||||
return true;
|
||||
}
|
||||
if(c1->channels != c2->channels){
|
||||
return true;
|
||||
}
|
||||
if(cell_simple_p(c1) && cell_simple_p(c2)){
|
||||
return c1->gcluster != c2->gcluster;
|
||||
}
|
||||
if(cell_simple_p(c1) || cell_simple_p(c2)){
|
||||
return true;
|
||||
}
|
||||
return strcmp(cell_extended_gcluster(n1, c1), cell_extended_gcluster(n2, c2));
|
||||
}
|
||||
|
||||
// True if the cell does not generate foreground pixels (i.e., the cell is
|
||||
// entirely whitespace or special characters).
|
||||
// FIXME do this at cell prep time and set a bit in the channels
|
||||
|
107
src/lib/render.c
107
src/lib/render.c
@ -205,9 +205,10 @@ lock_in_highcontrast(cell* targc, struct crender* crender){
|
||||
|
||||
// Paints a single ncplane into the provided framebuffer 'fb'. Whenever a cell
|
||||
// is locked in, it is compared against the last frame. If it is different, the
|
||||
// 'damagevec' bitmap is updated with a 1.
|
||||
// 'damagevec' bitmap is updated with a 1. 'pool' is typically nc->pool, but can
|
||||
// be whatever's backing fb.
|
||||
static int
|
||||
paint(notcurses* nc, ncplane* p, struct crender* rvec, cell* fb){
|
||||
paint(notcurses* nc, ncplane* p, cell* lastframe, struct crender* rvec, cell* fb, egcpool* pool){
|
||||
int y, x, dimy, dimx, offy, offx;
|
||||
// don't use ncplane_dim_yx()/ncplane_yx() here, lest we deadlock
|
||||
dimy = p->leny;
|
||||
@ -312,14 +313,14 @@ paint(notcurses* nc, ncplane* p, struct crender* rvec, cell* fb){
|
||||
// which were already locked in were skipped at the top of the loop)?
|
||||
if(cell_locked_p(targc)){
|
||||
lock_in_highcontrast(targc, crender);
|
||||
cell* prevcell = &nc->lastframe[fbcellidx(absy, nc->lfdimx, absx)];
|
||||
cell* prevcell = &lastframe[fbcellidx(absy, nc->lfdimx, absx)];
|
||||
/*if(cell_simple_p(targc)){
|
||||
fprintf(stderr, "WROTE %u [%c] to %d/%d (%d/%d)\n", targc->gcluster, prevcell->gcluster, y, x, absy, absx);
|
||||
}else{
|
||||
fprintf(stderr, "WROTE %u [%s] to %d/%d (%d/%d)\n", targc->gcluster, extended_gcluster(crender->p, targc), y, x, absy, absx);
|
||||
}
|
||||
fprintf(stderr, "POOL: %p NC: %p SRC: %p\n", nc->pool.pool, nc, crender->p);*/
|
||||
if(cellcmp_and_dupfar(&nc->pool, prevcell, crender->p, targc)){
|
||||
if(cellcmp_and_dupfar(pool, prevcell, crender->p, targc)){
|
||||
crender->damaged = true;
|
||||
if(cell_double_wide_p(targc)){
|
||||
ncplane* tmpp = crender->p;
|
||||
@ -331,7 +332,7 @@ fprintf(stderr, "POOL: %p NC: %p SRC: %p\n", nc->pool.pool, nc, crender->p);*/
|
||||
targc->gcluster = 0;
|
||||
targc->channels = targc[-1].channels;
|
||||
targc->attrword = targc[-1].attrword;
|
||||
if(cellcmp_and_dupfar(&nc->pool, prevcell, crender->p, targc)){
|
||||
if(cellcmp_and_dupfar(pool, prevcell, crender->p, targc)){
|
||||
crender->damaged = true;
|
||||
}
|
||||
}
|
||||
@ -342,12 +343,62 @@ fprintf(stderr, "POOL: %p NC: %p SRC: %p\n", nc->pool.pool, nc, crender->p);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst){
|
||||
if(paint(nc, src, rvec, fb)){
|
||||
static void
|
||||
init_fb(cell* fb, int dimy, int dimx){
|
||||
for(int y = 0 ; y < dimy ; ++y){
|
||||
for(int x = 0 ; x < dimx ; ++x){
|
||||
cell* c = &fb[fbcellidx(y, dimx, x)];
|
||||
c->gcluster = 0;
|
||||
c->channels = 0;
|
||||
c->attrword = 0;
|
||||
cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT);
|
||||
cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
postpaint(cell* fb, cell* lastframe, int dimy, int dimx,
|
||||
struct crender* rvec, egcpool* pool){
|
||||
for(int y = 0 ; y < dimy ; ++y){
|
||||
for(int x = 0 ; x < dimx ; ++x){
|
||||
cell* targc = &fb[fbcellidx(y, dimx, x)];
|
||||
if(!cell_locked_p(targc)){
|
||||
struct crender* crender = &rvec[fbcellidx(y, dimx, x)];
|
||||
lock_in_highcontrast(targc, crender);
|
||||
cell* prevcell = &lastframe[fbcellidx(y, dimx, x)];
|
||||
if(targc->gcluster == 0){
|
||||
targc->gcluster = ' ';
|
||||
}
|
||||
if(cellcmp_and_dupfar(pool, prevcell, crender->p, targc)){
|
||||
crender->damaged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME need handle a dst that isn't the standard plane! paint() will only
|
||||
// paint within the real viewport currently.
|
||||
int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst){
|
||||
notcurses* nc = src->nc;
|
||||
int dimy, dimx;
|
||||
ncplane_dim_yx(dst, &dimy, &dimx);
|
||||
cell* fb = malloc(sizeof(*fb) * dimy * dimx);
|
||||
const size_t crenderlen = sizeof(struct crender) * dimy * dimx;
|
||||
struct crender* rvec = malloc(crenderlen);
|
||||
memset(rvec, 0, crenderlen);
|
||||
init_fb(fb, dimy, dimx);
|
||||
if(paint(nc, src, dst->fb, rvec, fb, &dst->pool) || paint(nc, dst, dst->fb, rvec, fb, &dst->pool)){
|
||||
free(rvec);
|
||||
free(fb);
|
||||
return -1;
|
||||
}
|
||||
// if src is below dst, dst
|
||||
postpaint(fb, dst->fb, dimy, dimx, rvec, &dst->pool);
|
||||
free(dst->fb);
|
||||
dst->fb = fb;
|
||||
free(rvec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We execute the painter's algorithm, starting from our topmost plane. The
|
||||
@ -360,43 +411,19 @@ notcurses_render_internal(notcurses* nc, struct crender* rvec){
|
||||
if(reshape_shadow_fb(nc)){
|
||||
return -1;
|
||||
}
|
||||
// don't use ncplane_dim_yx()/ncplane_yx() here, lest we deadlock
|
||||
int dimy = nc->stdscr->leny;
|
||||
int dimx = nc->stdscr->lenx;
|
||||
int dimy, dimx;
|
||||
ncplane_dim_yx(nc->stdscr, &dimy, &dimx);
|
||||
cell* fb = malloc(sizeof(*fb) * dimy * dimx);
|
||||
for(int y = 0 ; y < dimy ; ++y){
|
||||
for(int x = 0 ; x < dimx ; ++x){
|
||||
cell* c = &fb[fbcellidx(y, dimx, x)];
|
||||
c->gcluster = 0;
|
||||
c->channels = 0;
|
||||
c->attrword = 0;
|
||||
cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT);
|
||||
cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT);
|
||||
}
|
||||
}
|
||||
init_fb(fb, dimy, dimx);
|
||||
ncplane* p = nc->top;
|
||||
while(p){
|
||||
if(paint(nc, p, rvec, fb)){
|
||||
if(paint(nc, p, nc->lastframe, rvec, fb, &nc->pool)){
|
||||
free(fb);
|
||||
return -1;
|
||||
}
|
||||
p = p->z;
|
||||
}
|
||||
for(int y = 0 ; y < dimy ; ++y){
|
||||
for(int x = 0 ; x < dimx ; ++x){
|
||||
cell* targc = &fb[fbcellidx(y, dimx, x)];
|
||||
if(!cell_locked_p(targc)){
|
||||
struct crender* crender = &rvec[fbcellidx(y, dimx, x)];
|
||||
lock_in_highcontrast(targc, crender);
|
||||
cell* prevcell = &nc->lastframe[fbcellidx(y, dimx, x)];
|
||||
if(targc->gcluster == 0){
|
||||
targc->gcluster = ' ';
|
||||
}
|
||||
if(cellcmp_and_dupfar(&nc->pool, prevcell, crender->p, targc)){
|
||||
crender->damaged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
postpaint(fb, nc->lastframe, dimy, dimx, rvec, &nc->pool);
|
||||
free(fb);
|
||||
return 0;
|
||||
}
|
||||
@ -979,7 +1006,7 @@ int notcurses_render(notcurses* nc){
|
||||
int ret;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
int bytes = -1;
|
||||
size_t crenderlen = sizeof(struct crender) * nc->stdscr->leny * nc->stdscr->lenx;
|
||||
const size_t crenderlen = sizeof(struct crender) * nc->stdscr->leny * nc->stdscr->lenx;
|
||||
struct crender* crender = malloc(crenderlen);
|
||||
memset(crender, 0, crenderlen);
|
||||
if(notcurses_render_internal(nc, crender) == 0){
|
||||
|
@ -311,6 +311,40 @@ TEST_CASE("Fills") {
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
}
|
||||
|
||||
SUBCASE("MergeDown") {
|
||||
auto p1 = ncplane_new(nc_, 1, 10, 0, 0, nullptr);
|
||||
REQUIRE(p1);
|
||||
// make sure glyphs replace nulls
|
||||
CHECK(0 < ncplane_putstr(p1, "0123456789"));
|
||||
CHECK(0 == ncplane_mergedown(p1, n_));
|
||||
cell cbase = CELL_TRIVIAL_INITIALIZER;
|
||||
cell cp = CELL_TRIVIAL_INITIALIZER;
|
||||
for(int i = 0 ; i < 10 ; ++i){
|
||||
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
|
||||
CHECK(0 < ncplane_at_yx(p1, 0, i, &cp));
|
||||
CHECK(0 == cellcmp(n_, &cbase, p1, &cp));
|
||||
}
|
||||
CHECK(0 == ncplane_cursor_move_yx(p1, 0, 0));
|
||||
// make sure glyphs replace glyps
|
||||
CHECK(0 < ncplane_putstr(p1, "9876543210"));
|
||||
CHECK(0 == ncplane_mergedown(p1, n_));
|
||||
for(int i = 0 ; i < 10 ; ++i){
|
||||
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
|
||||
CHECK(0 < ncplane_at_yx(p1, 0, i, &cp));
|
||||
CHECK(0 == cellcmp(n_, &cbase, p1, &cp));
|
||||
}
|
||||
// make sure nulls do not replace glyphs
|
||||
auto p2 = ncplane_new(nc_, 1, 10, 0, 0, nullptr);
|
||||
CHECK(0 == ncplane_mergedown(p2, n_));
|
||||
ncplane_destroy(p2);
|
||||
for(int i = 0 ; i < 10 ; ++i){
|
||||
CHECK(0 < ncplane_at_yx(n_, 0, i, &cbase));
|
||||
CHECK(0 < ncplane_at_yx(p1, 0, i, &cp));
|
||||
CHECK(0 == cellcmp(n_, &cbase, p1, &cp));
|
||||
}
|
||||
ncplane_destroy(p1);
|
||||
}
|
||||
|
||||
CHECK(0 == notcurses_stop(nc_));
|
||||
CHECK(0 == fclose(outfp_));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user