mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
fade: move more reproduced code into common area #659
This commit is contained in:
parent
0766dd08e7
commit
74e8e9c3d9
6
NEWS.md
6
NEWS.md
@ -9,12 +9,18 @@ rearrangements of Notcurses.
|
|||||||
`ncblitter_e` field, allowing visuals to be mapped to various plotting
|
`ncblitter_e` field, allowing visuals to be mapped to various plotting
|
||||||
paradigms including Sixel, Braille and quadrants. Not all backends have
|
paradigms including Sixel, Braille and quadrants. Not all backends have
|
||||||
been implemented, and not all implementations are in their final form.
|
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
|
* Added `ncvisual_geom()`, providing access to an `ncvisual` size and
|
||||||
its pixel-to-cell blitting ratios.
|
its pixel-to-cell blitting ratios.
|
||||||
* Deprecated functions `ncvisual_open_plane()` and `ncplane_visual_open()`
|
* Deprecated functions `ncvisual_open_plane()` and `ncplane_visual_open()`
|
||||||
have been removed. Their functionality is present in
|
have been removed. Their functionality is present in
|
||||||
`ncvisual_from_file()`. The function `ncvisual_plane()` no longer has
|
`ncvisual_from_file()`. The function `ncvisual_plane()` no longer has
|
||||||
any meaning, and has been removed.
|
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)
|
* 1.4.3 (2020-05-22)
|
||||||
* Plot: make 8x1 the default, instead of 1x1.
|
* Plot: make 8x1 the default, instead of 1x1.
|
||||||
|
3
USAGE.md
3
USAGE.md
@ -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
|
// Fade the ncplane out over the provided time, calling the specified function
|
||||||
// when done. Requires a terminal which supports truecolor, or at least palette
|
// 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
|
// 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
|
// limited, and affected by the complexity of the rest of the screen).
|
||||||
// not safe to resize or destroy the plane during the fadeout FIXME.
|
|
||||||
int ncplane_fadeout(struct ncplane* n, const struct timespec* ts, fadecb fader, void* curry);
|
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
|
// Fade the ncplane in over the specified time. Load the ncplane with the
|
||||||
|
@ -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
|
// Fade the ncplane out over the provided time, calling the specified function
|
||||||
// when done. Requires a terminal which supports truecolor, or at least palette
|
// 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
|
// 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
|
// limited, and affected by the complexity of the rest of the screen).
|
||||||
// not safe to resize or destroy the plane during the fadeout FIXME.
|
|
||||||
API int ncplane_fadeout(struct ncplane* n, const struct timespec* ts,
|
API int ncplane_fadeout(struct ncplane* n, const struct timespec* ts,
|
||||||
fadecb fader, void* curry);
|
fadecb fader, void* curry);
|
||||||
|
|
||||||
|
174
src/lib/fade.c
174
src/lib/fade.c
@ -6,6 +6,8 @@ typedef struct ncfadectx {
|
|||||||
int maxsteps; // maximum number of iterations
|
int maxsteps; // maximum number of iterations
|
||||||
unsigned maxr, maxg, maxb; // maxima across foreground channels
|
unsigned maxr, maxg, maxb; // maxima across foreground channels
|
||||||
unsigned maxbr, maxbg, maxbb; // maxima across background 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
|
uint64_t* channels; // all channels from the framebuffer
|
||||||
} ncfadectx;
|
} ncfadectx;
|
||||||
|
|
||||||
@ -13,7 +15,7 @@ typedef struct ncfadectx {
|
|||||||
// snapshot of all channels on the plane. While copying the snapshot, determine
|
// snapshot of all channels on the plane. While copying the snapshot, determine
|
||||||
// the maxima across each of the six components.
|
// the maxima across each of the six components.
|
||||||
static int
|
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);
|
ncplane_dim_yx(n, &pp->rows, &pp->cols);
|
||||||
// add an additional element for the background cell
|
// add an additional element for the background cell
|
||||||
int size = pp->rows * pp->cols + 1;
|
int size = pp->rows * pp->cols + 1;
|
||||||
@ -82,28 +84,28 @@ alloc_ncplane_palette(ncplane* n, ncfadectx* pp){
|
|||||||
if(pp->maxsteps == 0){
|
if(pp->maxsteps == 0){
|
||||||
pp->maxsteps = 1;
|
pp->maxsteps = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
uint64_t nanosecs_total = timespec_to_ns(ts);
|
||||||
}
|
pp->nanosecs_step = nanosecs_total / pp->maxsteps;
|
||||||
|
if(pp->nanosecs_step == 0){
|
||||||
static int
|
pp->nanosecs_step = 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
struct timespec times;
|
struct timespec times;
|
||||||
clock_gettime(CLOCK_MONOTONIC, ×);
|
clock_gettime(CLOCK_MONOTONIC, ×);
|
||||||
// Start time in absolute nanoseconds
|
// Start time in absolute nanoseconds
|
||||||
uint64_t startns = times.tv_sec * NANOSECS_IN_SEC + times.tv_nsec;
|
pp->startns = timespec_to_ns(×);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ncplane_fadein_internal(ncplane* n, fadecb fader, ncfadectx* pp, void* curry){
|
||||||
// Current time, sampled each iteration
|
// Current time, sampled each iteration
|
||||||
uint64_t curns;
|
uint64_t curns;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
do{
|
do{
|
||||||
|
struct timespec times;
|
||||||
clock_gettime(CLOCK_MONOTONIC, ×);
|
clock_gettime(CLOCK_MONOTONIC, ×);
|
||||||
curns = times.tv_sec * NANOSECS_IN_SEC + times.tv_nsec;
|
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){
|
if(iter > pp->maxsteps){
|
||||||
break;
|
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;
|
struct timespec sleepspec;
|
||||||
sleepspec.tv_sec = nextwake / NANOSECS_IN_SEC;
|
sleepspec.tv_sec = nextwake / NANOSECS_IN_SEC;
|
||||||
sleepspec.tv_nsec = nextwake % NANOSECS_IN_SEC;
|
sleepspec.tv_nsec = nextwake % NANOSECS_IN_SEC;
|
||||||
@ -152,89 +154,85 @@ ncplane_fadein_internal(ncplane* n, const struct timespec* ts,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ncplane_fadeout_iteration(ncplane* n, ncfadectx* nctx, int iter,
|
||||||
|
fadecb fader, void* curry){
|
||||||
|
unsigned br, bg, bb;
|
||||||
|
unsigned r, g, b;
|
||||||
|
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 < 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(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(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(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(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) * nctx->nanosecs_step + nctx->startns;
|
||||||
|
struct timespec sleepspec;
|
||||||
|
sleepspec.tv_sec = nextwake / NANOSECS_IN_SEC;
|
||||||
|
sleepspec.tv_nsec = nextwake % NANOSECS_IN_SEC;
|
||||||
|
int ret;
|
||||||
|
if(fader){
|
||||||
|
ret = fader(n->nc, n, &sleepspec, curry);
|
||||||
|
}else{
|
||||||
|
ret = notcurses_render(n->nc);
|
||||||
|
// clock_nanosleep() has no love for CLOCK_MONOTONIC_RAW, at least as
|
||||||
|
// of Glibc 2.29 + Linux 5.3 (or FreeBSD 12) :/.
|
||||||
|
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleepspec, NULL);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int ncplane_fadeout(ncplane* n, const struct timespec* ts, fadecb fader, void* curry){
|
int ncplane_fadeout(ncplane* n, const struct timespec* ts, fadecb fader, void* curry){
|
||||||
ncfadectx pp;
|
ncfadectx pp;
|
||||||
if(!n->nc->tcache.RGBflag && !n->nc->tcache.CCCflag){ // terminal can't fade
|
if(!n->nc->tcache.RGBflag && !n->nc->tcache.CCCflag){ // terminal can't fade
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(alloc_ncplane_palette(n, &pp)){
|
if(alloc_ncplane_palette(n, &pp, ts)){
|
||||||
return -1;
|
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, ×);
|
|
||||||
// Start time in absolute nanoseconds
|
|
||||||
uint64_t startns = timespec_to_ns(×);
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct timespec times;
|
||||||
|
ns_to_timespec(pp.startns, ×);
|
||||||
do{
|
do{
|
||||||
unsigned br, bg, bb;
|
|
||||||
unsigned r, g, b;
|
|
||||||
uint64_t curns = times.tv_sec * NANOSECS_IN_SEC + times.tv_nsec;
|
uint64_t 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){
|
if(iter > pp.maxsteps){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int y, x;
|
int r = ncplane_fadeout_iteration(n, &pp, iter, fader, curry);
|
||||||
// each time through, we need look each cell back up, due to the
|
if(r){
|
||||||
// possibility of a resize event :/
|
return r;
|
||||||
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){
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
cell_set_bg_rgb(&n->basecell, br, bg, bb);
|
|
||||||
}
|
|
||||||
uint64_t nextwake = (iter + 1) * nanosecs_step + startns;
|
|
||||||
struct timespec sleepspec;
|
|
||||||
sleepspec.tv_sec = nextwake / NANOSECS_IN_SEC;
|
|
||||||
sleepspec.tv_nsec = nextwake % NANOSECS_IN_SEC;
|
|
||||||
int rsleep;
|
|
||||||
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){
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
clock_gettime(CLOCK_MONOTONIC, ×);
|
clock_gettime(CLOCK_MONOTONIC, ×);
|
||||||
}while(true);
|
}while(true);
|
||||||
@ -254,10 +252,10 @@ int ncplane_fadein(ncplane* n, const struct timespec* ts, fadecb fader, void* cu
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(alloc_ncplane_palette(n, &pp)){
|
if(alloc_ncplane_palette(n, &pp, ts)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int ret = ncplane_fadein_internal(n, ts, fader, &pp, curry);
|
int ret = ncplane_fadein_internal(n, fader, &pp, curry);
|
||||||
free(pp.channels);
|
free(pp.channels);
|
||||||
return ret;
|
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
|
if(!n->nc->tcache.RGBflag && !n->nc->tcache.CCCflag){ // terminal can't fade
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(alloc_ncplane_palette(n, &pp)){
|
if(alloc_ncplane_palette(n, &pp, ts)){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for(;;){
|
for(;;){
|
||||||
ret = ncplane_fadein_internal(n, ts, fader, &pp, curry);
|
ret = ncplane_fadein_internal(n, fader, &pp, curry);
|
||||||
if(ret){
|
if(ret){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user