fade: move more reproduced code into common area #659

This commit is contained in:
nick black 2020-06-01 02:33:33 -04:00 committed by Nick Black
parent 0766dd08e7
commit 74e8e9c3d9
4 changed files with 94 additions and 92 deletions

View File

@ -9,12 +9,18 @@ rearrangements of Notcurses.
`ncblitter_e` field, allowing visuals to be mapped to various plotting
paradigms including Sixel, Braille and quadrants. Not all backends have
been implemented, and not all implementations are in their final form.
`CELL_ALPHA_BLEND` can now be used for translucent visuals.
* Added `ncvisual_geom()`, providing access to an `ncvisual` size and
its pixel-to-cell blitting ratios.
* Deprecated functions `ncvisual_open_plane()` and `ncplane_visual_open()`
have been removed. Their functionality is present in
`ncvisual_from_file()`. The function `ncvisual_plane()` no longer has
any meaning, and has been removed.
* The `fadecb` typedef now accepts as its third argument a `const struct
timespec`. This is the absolute deadline through which the frame ought
be displayed. Like the changes to `ncvisual_stream()`, this gives more
flexibility to the callback, and allows more precise timing. There will
be further changes to the Fade API before API freeze (see #659).
* 1.4.3 (2020-05-22)
* Plot: make 8x1 the default, instead of 1x1.

View File

@ -1200,8 +1200,7 @@ typedef int (*fadecb)(struct notcurses* nc, struct ncplane* ncp, void* curry);
// Fade the ncplane out over the provided time, calling the specified function
// when done. Requires a terminal which supports truecolor, or at least palette
// modification (if the terminal uses a palette, our ability to fade planes is
// limited, and affected by the complexity of the rest of the screen). It is
// not safe to resize or destroy the plane during the fadeout FIXME.
// limited, and affected by the complexity of the rest of the screen).
int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry);
// Fade the ncplane in over the specified time. Load the ncplane with the

View File

@ -1974,8 +1974,7 @@ typedef int (*fadecb)(struct notcurses* nc, struct ncplane* ncp,
// Fade the ncplane out over the provided time, calling the specified function
// when done. Requires a terminal which supports truecolor, or at least palette
// modification (if the terminal uses a palette, our ability to fade planes is
// limited, and affected by the complexity of the rest of the screen). It is
// not safe to resize or destroy the plane during the fadeout FIXME.
// limited, and affected by the complexity of the rest of the screen).
API int ncplane_fadeout(struct ncplane* n, const struct timespec* ts,
fadecb fader, void* curry);

View File

@ -6,6 +6,8 @@ typedef struct ncfadectx {
int maxsteps; // maximum number of iterations
unsigned maxr, maxg, maxb; // maxima across foreground channels
unsigned maxbr, maxbg, maxbb; // maxima across background channels
uint64_t nanosecs_step; // nanoseconds per iteration
uint64_t startns; // time fade started
uint64_t* channels; // all channels from the framebuffer
} ncfadectx;
@ -13,7 +15,7 @@ typedef struct ncfadectx {
// snapshot of all channels on the plane. While copying the snapshot, determine
// the maxima across each of the six components.
static int
alloc_ncplane_palette(ncplane* n, ncfadectx* pp){
alloc_ncplane_palette(ncplane* n, ncfadectx* pp, const struct timespec* ts){
ncplane_dim_yx(n, &pp->rows, &pp->cols);
// add an additional element for the background cell
int size = pp->rows * pp->cols + 1;
@ -82,28 +84,28 @@ alloc_ncplane_palette(ncplane* n, ncfadectx* pp){
if(pp->maxsteps == 0){
pp->maxsteps = 1;
}
return 0;
}
static int
ncplane_fadein_internal(ncplane* n, const struct timespec* ts,
fadecb fader, ncfadectx* pp, void* curry){
uint64_t nanosecs_total = ts->tv_sec * NANOSECS_IN_SEC + ts->tv_nsec;
uint64_t nanosecs_step = nanosecs_total / pp->maxsteps;
if(nanosecs_step == 0){
nanosecs_step = 1;
uint64_t nanosecs_total = timespec_to_ns(ts);
pp->nanosecs_step = nanosecs_total / pp->maxsteps;
if(pp->nanosecs_step == 0){
pp->nanosecs_step = 1;
}
struct timespec times;
clock_gettime(CLOCK_MONOTONIC, &times);
// Start time in absolute nanoseconds
uint64_t startns = times.tv_sec * NANOSECS_IN_SEC + times.tv_nsec;
pp->startns = timespec_to_ns(&times);
return 0;
}
static int
ncplane_fadein_internal(ncplane* n, fadecb fader, ncfadectx* pp, void* curry){
// Current time, sampled each iteration
uint64_t curns;
int ret = 0;
do{
struct timespec times;
clock_gettime(CLOCK_MONOTONIC, &times);
curns = times.tv_sec * NANOSECS_IN_SEC + times.tv_nsec;
int iter = (curns - startns) / nanosecs_step + 1;
int iter = (curns - pp->startns) / pp->nanosecs_step + 1;
if(iter > pp->maxsteps){
break;
}
@ -133,7 +135,7 @@ ncplane_fadein_internal(ncplane* n, const struct timespec* ts,
}
}
}
uint64_t nextwake = (iter + 1) * nanosecs_step + startns;
uint64_t nextwake = (iter + 1) * pp->nanosecs_step + pp->startns;
struct timespec sleepspec;
sleepspec.tv_sec = nextwake / NANOSECS_IN_SEC;
sleepspec.tv_nsec = nextwake % NANOSECS_IN_SEC;
@ -152,90 +154,86 @@ ncplane_fadein_internal(ncplane* n, const struct timespec* ts,
return ret;
}
int ncplane_fadeout(ncplane* n, const struct timespec* ts, fadecb fader, void* curry){
ncfadectx pp;
if(!n->nc->tcache.RGBflag && !n->nc->tcache.CCCflag){ // terminal can't fade
return -1;
}
if(alloc_ncplane_palette(n, &pp)){
return -1;
}
uint64_t nanosecs_total = timespec_to_ns(ts);
uint64_t nanosecs_step = nanosecs_total / pp.maxsteps;
if(nanosecs_step == 0){
nanosecs_step = 1;
}
struct timespec times;
clock_gettime(CLOCK_MONOTONIC, &times);
// Start time in absolute nanoseconds
uint64_t startns = timespec_to_ns(&times);
int ret = 0;
do{
int ncplane_fadeout_iteration(ncplane* n, ncfadectx* nctx, int iter,
fadecb fader, void* curry){
unsigned br, bg, bb;
unsigned r, g, b;
uint64_t curns = times.tv_sec * NANOSECS_IN_SEC + times.tv_nsec;
int iter = (curns - startns) / nanosecs_step + 1;
if(iter > pp.maxsteps){
break;
}
int y, x;
// each time through, we need look each cell back up, due to the
// possibility of a resize event :/
int dimy, dimx;
ncplane_dim_yx(n, &dimy, &dimx);
for(y = 0 ; y < pp.rows && y < dimy ; ++y){
for(x = 0 ; x < pp.cols && x < dimx; ++x){
for(y = 0 ; y < nctx->rows && y < dimy ; ++y){
for(x = 0 ; x < nctx->cols && x < dimx; ++x){
cell* c = &n->fb[dimx * y + x];
if(!cell_fg_default_p(c)){
channels_fg_rgb(pp.channels[pp.cols * y + x], &r, &g, &b);
r = r * (pp.maxsteps - iter) / pp.maxsteps;
g = g * (pp.maxsteps - iter) / pp.maxsteps;
b = b * (pp.maxsteps - iter) / pp.maxsteps;
channels_fg_rgb(nctx->channels[nctx->cols * y + x], &r, &g, &b);
r = r * (nctx->maxsteps - iter) / nctx->maxsteps;
g = g * (nctx->maxsteps - iter) / nctx->maxsteps;
b = b * (nctx->maxsteps - iter) / nctx->maxsteps;
cell_set_fg_rgb(c, r, g, b);
}
if(!cell_bg_default_p(c)){
channels_bg_rgb(pp.channels[pp.cols * y + x], &br, &bg, &bb);
br = br * (pp.maxsteps - iter) / pp.maxsteps;
bg = bg * (pp.maxsteps - iter) / pp.maxsteps;
bb = bb * (pp.maxsteps - iter) / pp.maxsteps;
channels_bg_rgb(nctx->channels[nctx->cols * y + x], &br, &bg, &bb);
br = br * (nctx->maxsteps - iter) / nctx->maxsteps;
bg = bg * (nctx->maxsteps - iter) / nctx->maxsteps;
bb = bb * (nctx->maxsteps - iter) / nctx->maxsteps;
cell_set_bg_rgb(c, br, bg, bb);
}
}
}
cell* c = &n->basecell;
if(!cell_fg_default_p(c)){
channels_fg_rgb(pp.channels[pp.cols * y], &r, &g, &b);
r = r * (pp.maxsteps - iter) / pp.maxsteps;
g = g * (pp.maxsteps - iter) / pp.maxsteps;
b = b * (pp.maxsteps - iter) / pp.maxsteps;
channels_fg_rgb(nctx->channels[nctx->cols * y], &r, &g, &b);
r = r * (nctx->maxsteps - iter) / nctx->maxsteps;
g = g * (nctx->maxsteps - iter) / nctx->maxsteps;
b = b * (nctx->maxsteps - iter) / nctx->maxsteps;
cell_set_fg_rgb(&n->basecell, r, g, b);
}
if(!cell_bg_default_p(c)){
channels_bg_rgb(pp.channels[pp.cols * y], &br, &bg, &bb);
br = br * (pp.maxsteps - iter) / pp.maxsteps;
bg = bg * (pp.maxsteps - iter) / pp.maxsteps;
bb = bb * (pp.maxsteps - iter) / pp.maxsteps;
channels_bg_rgb(nctx->channels[nctx->cols * y], &br, &bg, &bb);
br = br * (nctx->maxsteps - iter) / nctx->maxsteps;
bg = bg * (nctx->maxsteps - iter) / nctx->maxsteps;
bb = bb * (nctx->maxsteps - iter) / nctx->maxsteps;
cell_set_bg_rgb(&n->basecell, br, bg, bb);
}
uint64_t nextwake = (iter + 1) * nanosecs_step + startns;
uint64_t nextwake = (iter + 1) * nctx->nanosecs_step + nctx->startns;
struct timespec sleepspec;
sleepspec.tv_sec = nextwake / NANOSECS_IN_SEC;
sleepspec.tv_nsec = nextwake % NANOSECS_IN_SEC;
int rsleep;
int ret;
if(fader){
ret = fader(n->nc, n, &sleepspec, curry);
}else{
ret = notcurses_render(n->nc);
}
if(ret){
break;
}
// clock_nanosleep() has no love for CLOCK_MONOTONIC_RAW, at least as
// of Glibc 2.29 + Linux 5.3 (or FreeBSD 12) :/.
rsleep = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleepspec, NULL);
if(rsleep){
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleepspec, NULL);
}
return ret;
}
int ncplane_fadeout(ncplane* n, const struct timespec* ts, fadecb fader, void* curry){
ncfadectx pp;
if(!n->nc->tcache.RGBflag && !n->nc->tcache.CCCflag){ // terminal can't fade
return -1;
}
if(alloc_ncplane_palette(n, &pp, ts)){
return -1;
}
int ret = 0;
struct timespec times;
ns_to_timespec(pp.startns, &times);
do{
uint64_t curns = times.tv_sec * NANOSECS_IN_SEC + times.tv_nsec;
int iter = (curns - pp.startns) / pp.nanosecs_step + 1;
if(iter > pp.maxsteps){
break;
}
int r = ncplane_fadeout_iteration(n, &pp, iter, fader, curry);
if(r){
return r;
}
clock_gettime(CLOCK_MONOTONIC, &times);
}while(true);
free(pp.channels);
@ -254,10 +252,10 @@ int ncplane_fadein(ncplane* n, const struct timespec* ts, fadecb fader, void* cu
}
return -1;
}
if(alloc_ncplane_palette(n, &pp)){
if(alloc_ncplane_palette(n, &pp, ts)){
return -1;
}
int ret = ncplane_fadein_internal(n, ts, fader, &pp, curry);
int ret = ncplane_fadein_internal(n, fader, &pp, curry);
free(pp.channels);
return ret;
}
@ -268,11 +266,11 @@ int ncplane_pulse(ncplane* n, const struct timespec* ts, fadecb fader, void* cur
if(!n->nc->tcache.RGBflag && !n->nc->tcache.CCCflag){ // terminal can't fade
return -1;
}
if(alloc_ncplane_palette(n, &pp)){
if(alloc_ncplane_palette(n, &pp, ts)){
return -1;
}
for(;;){
ret = ncplane_fadein_internal(n, ts, fader, &pp, curry);
ret = ncplane_fadein_internal(n, fader, &pp, curry);
if(ret){
break;
}