Partial visual renders #170 (#193)

* ncvisual_render() accept four bounding dims #175
* ncvisual_render(): partial renders #175
This commit is contained in:
Nick Black 2019-12-21 16:02:27 -05:00 committed by GitHub
parent 84aefd65e8
commit 3ad2124246
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 215 additions and 172 deletions

View File

@ -964,7 +964,9 @@ typedef struct cell {
#define CELL_BG_MASK 0x0000000000ffffffull
#define CELL_ALPHA_MASK 0x0000000030000000ull
#define CELL_ALPHA_SHIFT 28u
#define CELL_ALPHA_TRANS 3
#define CELL_ALPHA_HIGHCONTRAST 3
#define CELL_ALPHA_TRANSPARENT 2
#define CELL_ALPHA_BLEND 1
#define CELL_ALPHA_OPAQUE 0
```
@ -1293,9 +1295,14 @@ struct ncvisual* ncvisual_open_plane(struct notcurses* nc, const char* file,
// can be neither decoded nor rendered any further.
void ncvisual_destroy(struct ncvisual* ncv);
// render the decoded frame to the associated ncplane. the frame will be scaled
// to the size of the ncplane at ncplane_visual_open() time.
int ncvisual_render(const struct ncvisual* ncv);
// Render the decoded frame to the associated ncplane. The frame will be scaled
// to the size of the ncplane per the ncscale_e style. A subregion of the
// frame can be specified using 'begx', 'begy', 'lenx', and 'leny'. To render
// the rectangle formed by begy x begx and the lower-right corner, zero can be
// supplied to 'leny' and 'lenx'. Zero for all four values will thus render the
// entire visual. Negative values for any of the four parameters are an error.
// It is an error to specify any region beyond the boundaries of the frame.
int ncvisual_render(const struct ncvisual* ncv, int begy, int begx, int leny, int lenx);
// Called for each frame rendered from 'ncv'. If anything but 0 is returned,
// the streaming operation ceases immediately, and that value is propagated out.
@ -1888,6 +1895,9 @@ channels_set_fg_alpha(uint64_t* channels, int alpha){
// Set the 2-bit alpha component of the background channel.
static inline int
channels_set_bg_alpha(uint64_t* channels, int alpha){
if(alpha == CELL_ALPHA_HIGHCONTRAST){ // forbidden for background alpha
return -1;
}
unsigned channel = channels_get_bchannel(*channels);
if(channel_set_alpha(&channel, alpha) < 0){
return -1;
@ -2003,6 +2013,15 @@ Four binaries are built as part of notcurses:
* `notcurses-planereels`: play around with panelreels
* `notcurses-tester`: unit testing
To run `notcurses-demo` from a checkout, provide the `tests/` directory via
the `-p` argument. Demos requiring data files will otherwise abort. The base
delay used in `notcurses-demo` can be changed with `-d`, accepting a
floating-point multiplier. Values less than 1 will speed up the demo, while
values greater than 1 will slow it down.
`notcurses-tester` expects `../tests/` to exist, and be populated with the
necessary data files. It can be run by itself, or via `make test`.
## Differences from NCURSES
The biggest difference, of course, is that notcurses is not an implementation

View File

@ -66,12 +66,14 @@ struct notcurses; // notcurses state for a given terminal, composed of ncplanes
// We implement some small alpha compositing. Foreground and background both
// have two bits of inverted alpha. The actual grapheme written to a cell is
// the topmost non-zero grapheme. If its alpha is 00, its foreground color is
// used unchanged. If its alpha is 11, its foreground color is derived entirely
// used unchanged. If its alpha is 10, its foreground color is derived entirely
// from cells underneath it. Otherwise, the result will be a composite.
// Likewise for the background. If the bottom of a coordinate's zbuffer is
// reached with a cumulative alpha of zero, the default is used. In this way,
// a terminal configured with transparent background can be supported through
// multiple occluding ncplanes.
// multiple occluding ncplanes. A foreground alpha of 11 requests high-contrast
// text (relative to the computed background). A background alpha of 11 is
// currently forbidden.
typedef struct cell {
// These 32 bits are either a single-byte, single-character grapheme cluster
// (values 0--0x7f), or an offset into a per-ncplane attached pool of
@ -678,7 +680,9 @@ API void ncplane_erase(struct ncplane* n);
#define CELL_BG_MASK 0x0000000000ffffffull
#define CELL_ALPHA_MASK 0x0000000030000000ull
#define CELL_ALPHA_SHIFT 28u
#define CELL_ALPHA_TRANS 3
#define CELL_ALPHA_HIGHCONTRAST 3
#define CELL_ALPHA_TRANSPARENT 2
#define CELL_ALPHA_BLEND 1
#define CELL_ALPHA_OPAQUE 0
// These lowest-level functions manipulate a 64-bit channel encoding directly.
@ -749,7 +753,7 @@ channel_get_alpha(unsigned channel){
// Set the 2-bit alpha component of the 32-bit channel.
static inline int
channel_set_alpha(unsigned* channel, int alpha){
if(alpha < CELL_ALPHA_OPAQUE || alpha > CELL_ALPHA_TRANS){
if(alpha < CELL_ALPHA_OPAQUE || alpha > CELL_ALPHA_HIGHCONTRAST){
return -1;
}
*channel = (alpha << CELL_ALPHA_SHIFT) | (*channel & ~CELL_ALPHA_MASK);
@ -887,6 +891,9 @@ channels_set_fg_alpha(uint64_t* channels, int alpha){
// Set the 2-bit alpha component of the background channel.
static inline int
channels_set_bg_alpha(uint64_t* channels, int alpha){
if(alpha == CELL_ALPHA_HIGHCONTRAST){ // forbidden for background alpha
return -1;
}
unsigned channel = channels_get_bchannel(*channels);
if(channel_set_alpha(&channel, alpha) < 0){
return -1;
@ -1382,9 +1389,15 @@ API void ncvisual_destroy(struct ncvisual* ncv);
// subsequent call to ncvisual_decode(), and should not be freed by the caller.
API struct AVFrame* ncvisual_decode(struct ncvisual* nc, int* averr);
// render the decoded frame to the associated ncplane. the frame will be scaled
// to the size of the ncplane at ncplane_visual_open() time.
API int ncvisual_render(const struct ncvisual* ncv);
// Render the decoded frame to the associated ncplane. The frame will be scaled
// to the size of the ncplane per the ncscale_e style. A subregion of the
// frame can be specified using 'begx', 'begy', 'lenx', and 'leny'. To render
// the rectangle formed by begy x begx and the lower-right corner, zero can be
// supplied to 'leny' and 'lenx'. Zero for all four values will thus render the
// entire visual. Negative values for any of the four parameters are an error.
// It is an error to specify any region beyond the boundaries of the frame.
API int ncvisual_render(const struct ncvisual* ncv, int begy, int begx,
int leny, int lenx);
// Called for each frame rendered from 'ncv'. If anything but 0 is returned,
// the streaming operation ceases immediately, and that value is propagated out.

View File

@ -1,5 +1,7 @@
#include <libavutil/frame.h>
#include "demo.h"
// display the level map scaled to fit entirely within the visual area
static struct ncvisual*
outzoomed_map(struct notcurses* nc, const char* map){
int averr;
@ -10,7 +12,7 @@ outzoomed_map(struct notcurses* nc, const char* map){
if(ncvisual_decode(ncv, &averr) == NULL){
return NULL;
}
if(ncvisual_render(ncv)){
if(ncvisual_render(ncv, 0, 0, 0, 0)){
return NULL;
}
if(notcurses_render(nc)){
@ -23,7 +25,7 @@ outzoomed_map(struct notcurses* nc, const char* map){
static int
zoom_map(struct notcurses* nc, const char* map){
int averr;
// FIXME determine size that will be represented on screen at once, and how
// determine size that will be represented on screen at once, and how
// large that section has been rendered in the outzoomed map. take the map
// and begin opening it on larger and larger planes that fit on the screen
// less and less. eventually, reach our natural NCSCALE_NONE size and begin
@ -32,61 +34,46 @@ zoom_map(struct notcurses* nc, const char* map){
if(ncv == NULL){
return -1;
}
if(ncvisual_decode(ncv, &averr) == NULL){
struct AVFrame* frame;
if((frame = ncvisual_decode(ncv, &averr)) == NULL){
ncvisual_destroy(ncv);
return -1;
}
ncvisual_destroy(ncv);
// we start at the lower left corner of the outzoomed map
int truex, truey; // dimensions of true display
notcurses_term_dim_yx(nc, &truey, &truex);
struct ncplane* ncp = ncvisual_plane(ncv);
int vx, vy; // dimensions of unzoomed map
ncplane_dim_yx(ncp, &vy, &vx);
ncplane_move_yx(ncp, truey - vy, truex - vx);
if(ncvisual_render(ncv)){
ncvisual_destroy(ncv);
return -1;
}
ncplane_move_bottom(ncp);
int vwidth = frame->width;
int vx = vwidth;
int vheight = frame->height; // dimensions of unzoomed map
int vy = vheight / 2;
int zoomy = truey;
int zoomx = truex;
while(zoomy < vy && zoomx < vx){
zoomy += 2;
zoomx += 2;
struct ncplane* zncp = notcurses_newplane(nc, zoomy, zoomx, truey - zoomy, 0, NULL);
if(zncp == NULL){
ncvisual_destroy(ncv);
return -1;
}
struct ncplane* zncp = notcurses_newplane(nc, zoomy, zoomx, 0, 0, NULL);
struct ncvisual* zncv = ncplane_visual_open(zncp, map, &averr);
if(zncv == NULL){
ncplane_destroy(zncp);
ncvisual_destroy(ncv);
return -1;
}
if(ncvisual_decode(zncv, &averr) == NULL){
ncvisual_destroy(zncv);
ncplane_destroy(zncp);
ncvisual_destroy(ncv);
return -1;
}
if(ncvisual_render(zncv)){
if(ncvisual_render(zncv, (zoomy - truey) * 2, 0, 0, ((float)truex / zoomx) * zoomx)){
ncvisual_destroy(zncv);
ncplane_destroy(zncp);
ncvisual_destroy(ncv);
return -1;
}
if(notcurses_render(nc)){
ncvisual_destroy(zncv);
ncplane_destroy(zncp);
ncvisual_destroy(ncv);
return -1;
}
ncvisual_destroy(zncv);
ncplane_destroy(zncp);
}
nanosleep(&demodelay, NULL);
ncvisual_destroy(ncv);
return 0;
}

View File

@ -112,7 +112,7 @@ static const char* luigis[] = {
static int
draw_luigi(struct ncplane* n, const char* sprite){
cell bgc = CELL_TRIVIAL_INITIALIZER;
cell_set_bg_alpha(&bgc, CELL_ALPHA_TRANS);
cell_set_bg_alpha(&bgc, CELL_ALPHA_TRANSPARENT);
ncplane_set_default(n, &bgc);
cell_release(n, &bgc);
size_t s;
@ -156,7 +156,7 @@ int luigi_demo(struct notcurses* nc){
if(ncvisual_decode(nv, &averr) == NULL){
return -1;
}
if(ncvisual_render(nv)){
if(ncvisual_render(nv, 0, 0, 0, 0)){
return -1;
}
int rows, cols;

View File

@ -27,7 +27,7 @@ outro_message(struct notcurses* nc, int* rows, int* cols){
ncplane_dim_yx(on, rows, cols);
int ybase = 0;
// bevel the upper corners
if(ncplane_set_bg_alpha(on, CELL_ALPHA_TRANS)){
if(ncplane_set_bg_alpha(on, CELL_ALPHA_TRANSPARENT)){
return NULL;
}
if(ncplane_cursor_move_yx(on, ybase, 0)){
@ -101,7 +101,7 @@ int outro(struct notcurses* nc){
ncvisual_destroy(ncv);
return -1;
}
if(ncvisual_render(ncv)){
if(ncvisual_render(ncv, 0, 0, 0, 0)){
ncvisual_destroy(ncv);
return -1;
}

View File

@ -272,7 +272,7 @@ panelreel_demo_core(struct notcurses* nc, int efd, tabletctx** tctxs){
channels_set_fg_rgb(&popts.tabletchan, 19, 161, 14);
channels_set_fg_rgb(&popts.borderchan, 136, 23, 152);
channels_set_bg_rgb(&popts.borderchan, 0, 0, 0);
if(channels_set_bg_alpha(&popts.bgchannel, CELL_ALPHA_TRANS)){
if(channels_set_bg_alpha(&popts.bgchannel, CELL_ALPHA_TRANSPARENT)){
return NULL;
}
struct ncplane* w = notcurses_stdplane(nc);

View File

@ -165,7 +165,7 @@ int sliding_puzzle_demo(struct notcurses* nc){
struct ncplane* n = notcurses_stdplane(nc);
ncplane_erase(n);
int averr = 0;
char* path = find_data("changes.jpg");
char* path = find_data("lamepatents.jpg");
struct ncvisual* ncv = ncplane_visual_open(n, path, &averr);
free(path);
if(ncv == NULL){
@ -175,7 +175,7 @@ int sliding_puzzle_demo(struct notcurses* nc){
ncvisual_destroy(ncv);
return -1;
}
if(ncvisual_render(ncv)){
if(ncvisual_render(ncv, 0, 0, 0, 0)){
ncvisual_destroy(ncv);
return -1;
}

View File

@ -23,10 +23,10 @@ draw_block(struct ncplane* nn, uint32_t blockstart){
cell ll = CELL_TRIVIAL_INITIALIZER, lr = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER, vl = CELL_TRIVIAL_INITIALIZER;
cells_rounded_box(nn, 0, 0, &ul, &ur, &ll, &lr, &hl, &vl);
cell_set_bg_alpha(&ul, CELL_ALPHA_TRANS);
cell_set_bg_alpha(&ur, CELL_ALPHA_TRANS);
cell_set_bg_alpha(&ll, CELL_ALPHA_TRANS);
cell_set_bg_alpha(&lr, CELL_ALPHA_TRANS);
cell_set_bg_alpha(&ul, CELL_ALPHA_TRANSPARENT);
cell_set_bg_alpha(&ur, CELL_ALPHA_TRANSPARENT);
cell_set_bg_alpha(&ll, CELL_ALPHA_TRANSPARENT);
cell_set_bg_alpha(&lr, CELL_ALPHA_TRANSPARENT);
cell_set_fg_rgb(&ll, 255, 255, 255);
cell_set_fg_rgb(&lr, 255, 255, 255);
cell_set_fg_rgb(&ul, 255, 255, 255);

View File

@ -40,9 +40,9 @@ view_video_demo(struct notcurses* nc){
static struct ncplane*
legend(struct notcurses* nc, int dimy, int dimx){
struct ncplane* n = notcurses_newplane(nc, 3, 25, dimy / 8, dimx / 12, NULL);
ncplane_set_bg_alpha(n, CELL_ALPHA_TRANS);
ncplane_set_bg_alpha(n, CELL_ALPHA_TRANSPARENT);
uint64_t channels = 0;
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANS);
channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT);
cell c = CELL_INITIALIZER(' ', 0, channels);
ncplane_set_default(n, &c);
ncplane_set_fg_rgb(n, 0x0, 0x0, 0x0);
@ -101,7 +101,7 @@ int view_demo(struct notcurses* nc){
ncplane_destroy(dsplane);
return -1;
}
if(ncvisual_render(ncv2)){
if(ncvisual_render(ncv2, 0, 0, 0, 0)){
ncvisual_destroy(ncv);
ncvisual_destroy(ncv2);
ncplane_destroy(dsplane);
@ -110,7 +110,7 @@ int view_demo(struct notcurses* nc){
notcurses_render(nc);
ncplane_move_bottom(dsplane);
nanosleep(&demodelay, NULL);
if(ncvisual_render(ncv)){
if(ncvisual_render(ncv, 0, 0, 0, 0)){
ncvisual_destroy(ncv);
ncvisual_destroy(ncv2);
ncplane_destroy(dsplane);

View File

@ -286,8 +286,8 @@ message(struct ncplane* n, int maxy, int maxx, int num, int total,
int bytes_out, int egs_out, int cols_out){
cell c = CELL_TRIVIAL_INITIALIZER;
cell_load(n, &c, " ");
cell_set_fg_alpha(&c, CELL_ALPHA_TRANS);
cell_set_bg_alpha(&c, CELL_ALPHA_TRANS);
cell_set_fg_alpha(&c, CELL_ALPHA_TRANSPARENT);
cell_set_bg_alpha(&c, CELL_ALPHA_TRANSPARENT);
ncplane_set_default(n, &c);
cell_release(n, &c);
uint64_t channels = 0;

View File

@ -275,6 +275,122 @@ ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename,
return ncv;
}
int ncvisual_render(const ncvisual* ncv, int begy, int begx, int leny, int lenx){
//fprintf(stderr, "render %dx%d+%dx%d\n", begy, begx, leny, lenx);
if(begy < 0 || begx < 0 || lenx < 0 || leny < 0){
return -1;
}
const AVFrame* f = ncv->oframe;
if(f == NULL){
return -1;
}
//fprintf(stderr, "render %d/%d to %dx%d+%dx%d\n", f->height, f->width, begy, begx, leny, lenx);
if(begx >= f->width || begy >= f->height){
return -1;
}
if(begx + lenx > f->width || begy + leny > f->height){
return -1;
}
if(lenx == 0){
lenx = f->width - begx;
}
if(leny == 0){
leny = f->height - begy;
}
int x, y;
int dimy, dimx;
ncplane_dim_yx(ncv->ncp, &dimy, &dimx);
ncplane_cursor_move_yx(ncv->ncp, 0, 0);
const int linesize = f->linesize[0];
const unsigned char* data = f->data[0];
// y and x are actual plane coordinates. each row corresponds to two rows of
// the input (scaled) frame (columns are 1:1). we track the row of the
// visual via visy.
int visy = begy;
//fprintf(stderr, "render: %dx%d:%d+%d of %d/%d -> %dx%d\n", begy, begx, leny, lenx, f->height, f->width, dimy, dimx);
for(y = ncv->placey ; visy < (begy + leny) && y < dimy ; ++y, visy += 2){
if(ncplane_cursor_move_yx(ncv->ncp, y, ncv->placex)){
return -1;
}
int visx = begx;
for(x = ncv->placex ; visx < (begx + lenx) && x < dimx ; ++x, ++visx){
int bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(f->format));
const unsigned char* rgbbase_up = data + (linesize * visy) + (visx * bpp / CHAR_BIT);
const unsigned char* rgbbase_down = data + (linesize * (visy + 1)) + (visx * bpp / CHAR_BIT);
/*fprintf(stderr, "[%04d/%04d] %p bpp: %d lsize: %d %02x %02x %02x %02x\n",
y, x, rgbbase, bpp, linesize, rgbbase[0], rgbbase[1], rgbbase[2], rgbbase[3]);*/
cell c = CELL_TRIVIAL_INITIALIZER;
// use the default for the background, as that's the only way it's
// effective in that case anyway
if(!rgbbase_up[3] || !rgbbase_down[3]){
cell_set_bg_alpha(&c, CELL_ALPHA_TRANSPARENT);
if(!rgbbase_up[3] && !rgbbase_down[3]){
if(cell_load(ncv->ncp, &c, " ") <= 0){
return -1;
}
cell_set_fg_alpha(&c, CELL_ALPHA_TRANSPARENT);
}else if(!rgbbase_up[3]){ // down has the color
if(cell_load(ncv->ncp, &c, "\u2584") <= 0){ // lower half block
return -1;
}
cell_set_fg_rgb(&c, rgbbase_down[0], rgbbase_down[1], rgbbase_down[2]);
}else{ // up has the color
if(cell_load(ncv->ncp, &c, "\u2580") <= 0){ // upper half block
return -1;
}
cell_set_fg_rgb(&c, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2]);
}
}else{
cell_set_fg_rgb(&c, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2]);
cell_set_bg_rgb(&c, rgbbase_down[0], rgbbase_down[1], rgbbase_down[2]);
if(cell_load(ncv->ncp, &c, "\u2580") <= 0){ // upper half block
return -1;
}
}
if(ncplane_putc(ncv->ncp, &c) <= 0){
cell_release(ncv->ncp, &c);
return -1;
}
cell_release(ncv->ncp, &c);
}
}
flash_damage_map(ncv->ncp->damage + ncv->placey, y - ncv->placey, true);
return 0;
}
int ncvisual_stream(notcurses* nc, ncvisual* ncv, int* averr, streamcb streamer){
ncplane* n = ncv->ncp;
int frame = 1;
AVFrame* avf;
struct timespec start;
// FIXME should keep a start time and cumulative time; this will push things
// out on a loaded machine
while(clock_gettime(CLOCK_MONOTONIC, &start),
(avf = ncvisual_decode(ncv, averr)) ){
ncplane_cursor_move_yx(n, 0, 0);
if(ncvisual_render(ncv, 0, 0, 0, 0)){
return -1;
}
if(streamer){
int r = streamer(nc, ncv);
if(r){
return r;
}
}
++frame;
uint64_t ns = avf->pkt_duration * 1000000;
struct timespec interval = {
.tv_sec = start.tv_sec + (long)(ns / 1000000000),
.tv_nsec = start.tv_nsec + (long)(ns % 1000000000),
};
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &interval, NULL);
}
if(*averr == AVERROR_EOF){
return 0;
}
return -1;
}
int ncvisual_init(void){
av_log_set_level(AV_LOG_QUIET); // FIXME make this configurable?
// FIXME could also use av_log_set_callback() and capture the message...

View File

@ -1605,99 +1605,6 @@ void ncplane_erase(ncplane* n){
ncplane_unlock(n);
}
int ncvisual_render(const ncvisual* ncv){
const AVFrame* f = ncv->oframe;
if(f == NULL){
return -1;
}
int x, y;
int dimy, dimx;
ncplane_dim_yx(ncv->ncp, &dimy, &dimx);
ncplane_cursor_move_yx(ncv->ncp, 0, 0);
const int linesize = f->linesize[0];
const unsigned char* data = f->data[0];
for(y = 0 ; y < f->height / 2 && y < dimy ; ++y){
if(ncplane_cursor_move_yx(ncv->ncp, y, 0)){
return -1;
}
for(x = 0 ; x < f->width && x < dimx ; ++x){
int bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(f->format));
const unsigned char* rgbbase_up = data + (linesize * (y * 2)) + (x * bpp / CHAR_BIT);
const unsigned char* rgbbase_down = data + (linesize * (y * 2 + 1)) + (x * bpp / CHAR_BIT);
/*fprintf(stderr, "[%04d/%04d] %p bpp: %d lsize: %d %02x %02x %02x %02x\n",
y, x, rgbbase, bpp, linesize, rgbbase[0], rgbbase[1], rgbbase[2], rgbbase[3]);*/
cell c = CELL_TRIVIAL_INITIALIZER;
// use the default for the background, as that's the only way it's
// effective in that case anyway
if(!rgbbase_up[3] || !rgbbase_down[3]){
cell_set_bg_alpha(&c, CELL_ALPHA_TRANS);
if(!rgbbase_up[3] && !rgbbase_down[3]){
if(cell_load(ncv->ncp, &c, " ") <= 0){
return -1;
}
cell_set_fg_alpha(&c, CELL_ALPHA_TRANS);
}else if(!rgbbase_up[3]){ // down has the color
if(cell_load(ncv->ncp, &c, "\u2584") <= 0){ // lower half block
return -1;
}
cell_set_fg_rgb(&c, rgbbase_down[0], rgbbase_down[1], rgbbase_down[2]);
}else{ // up has the color
if(cell_load(ncv->ncp, &c, "\u2580") <= 0){ // upper half block
return -1;
}
cell_set_fg_rgb(&c, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2]);
}
}else{
cell_set_fg_rgb(&c, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2]);
cell_set_bg_rgb(&c, rgbbase_down[0], rgbbase_down[1], rgbbase_down[2]);
if(cell_load(ncv->ncp, &c, "\u2580") <= 0){ // upper half block
return -1;
}
}
if(ncplane_putc(ncv->ncp, &c) <= 0){
cell_release(ncv->ncp, &c);
return -1;
}
cell_release(ncv->ncp, &c);
}
}
flash_damage_map(ncv->ncp->damage, y, true);
return 0;
}
int ncvisual_stream(notcurses* nc, ncvisual* ncv, int* averr, streamcb streamer){
ncplane* n = ncv->ncp;
int frame = 1;
AVFrame* avf;
struct timespec start;
// FIXME should keep a start time and cumulative time; this will push things
// out on a loaded machine
while(clock_gettime(CLOCK_MONOTONIC, &start),
(avf = ncvisual_decode(ncv, averr)) ){
ncplane_cursor_move_yx(n, 0, 0);
if(ncvisual_render(ncv)){
return -1;
}
if(streamer){
int r = streamer(nc, ncv);
if(r){
return r;
}
}
++frame;
uint64_t ns = avf->pkt_duration * 1000000;
struct timespec interval = {
.tv_sec = start.tv_sec + (long)(ns / 1000000000),
.tv_nsec = start.tv_nsec + (long)(ns % 1000000000),
};
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &interval, NULL);
}
if(*averr == AVERROR_EOF){
return 0;
}
return -1;
}
// if "retain_cursor" was set, we don't have these definitions FIXME
void notcurses_cursor_enable(notcurses* nc){
if(nc->cnorm){

View File

@ -157,13 +157,13 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha,
vis = &p->defcell;
}
int nalpha;
if(falpha > 0 && (nalpha = cell_get_fg_alpha(vis)) < CELL_ALPHA_TRANS){
if(falpha > 0 && (nalpha = cell_get_fg_alpha(vis)) < CELL_ALPHA_TRANSPARENT){
if(c->gcluster == 0){ // never write fully trans glyphs, never replace
if( (c->gcluster = vis->gcluster) ){ // index copy only
glyphplane = p; // must return this ncplane for this glyph
c->attrword = vis->attrword;
cell_set_fchannel(c, cell_get_fchannel(vis)); // FIXME blend it in
falpha -= (CELL_ALPHA_TRANS - nalpha); // FIXME blend it in
falpha -= (CELL_ALPHA_TRANSPARENT - nalpha); // FIXME blend it in
if(p->damage[poffy]){
*damage = true;
p->damage[poffy] = false;
@ -171,9 +171,9 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha,
}
}
}
if(balpha > 0 && (nalpha = cell_get_bg_alpha(vis)) < CELL_ALPHA_TRANS){
if(balpha > 0 && (nalpha = cell_get_bg_alpha(vis)) < CELL_ALPHA_TRANSPARENT){
cell_set_bchannel(c, cell_get_bchannel(vis)); // FIXME blend it in
balpha -= (CELL_ALPHA_TRANS - nalpha);
balpha -= (CELL_ALPHA_TRANSPARENT - nalpha);
if(p->damage[poffy]){
*damage = true;
p->damage[poffy] = false;
@ -193,7 +193,8 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha,
static inline ncplane*
visible_cell(cell* c, int y, int x, ncplane* n, bool* damage){
cell_init(c);
return dig_visible_cell(c, y, x, n, CELL_ALPHA_TRANS, CELL_ALPHA_TRANS, damage);
return dig_visible_cell(c, y, x, n, CELL_ALPHA_TRANSPARENT,
CELL_ALPHA_TRANSPARENT, damage);
}
// write the cell's UTF-8 grapheme cluster to the provided FILE*. returns the

View File

@ -25,7 +25,7 @@ int ncview(struct notcurses* nc, struct ncvisual* ncv, int* averr){
(avf = ncvisual_decode(ncv, averr)) ){
ncplane_cursor_move_yx(n, 0, 0);
ncplane_printf(n, "Got frame %05d\u2026", frame);
if(ncvisual_render(ncv)){
if(ncvisual_render(ncv, 0, 0, 0, 0)){
return -1;
}
if(notcurses_render(nc)){

View File

@ -45,7 +45,7 @@ TEST_F(LibavTest, LoadImage) {
ASSERT_EQ(0, averr);
EXPECT_EQ(dimy * 2, frame->height);
EXPECT_EQ(dimx, frame->width);
EXPECT_EQ(0, ncvisual_render(ncv));
EXPECT_EQ(0, ncvisual_render(ncv, 0, 0, 0, 0));
EXPECT_EQ(0, notcurses_render(nc_));
frame = ncvisual_decode(ncv, &averr);
ASSERT_EQ(nullptr, frame);
@ -66,7 +66,7 @@ TEST_F(LibavTest, LoadVideo) {
EXPECT_EQ(0, averr);
EXPECT_EQ(dimy * 2, frame->height);
EXPECT_EQ(dimx, frame->width);
EXPECT_EQ(0, ncvisual_render(ncv));
EXPECT_EQ(0, ncvisual_render(ncv, 0, 0, 0, 0));
EXPECT_EQ(0, notcurses_render(nc_));
ncvisual_destroy(ncv);
}
@ -83,7 +83,7 @@ TEST_F(LibavTest, LoadVideoCreatePlane) {
EXPECT_EQ(0, averr);
EXPECT_EQ(dimy * 2, frame->height);
EXPECT_EQ(dimx, frame->width);
EXPECT_EQ(0, ncvisual_render(ncv));
EXPECT_EQ(0, ncvisual_render(ncv, 0, 0, 0, 0));
EXPECT_EQ(0, notcurses_render(nc_));
ncvisual_destroy(ncv);
}