yield demo: punch up with polyfills

pull/684/head
nick black 4 years ago
parent cb521e3de7
commit 2c417ddb0c
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -759,8 +759,9 @@ int ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c);
// Start at the plane's 'begy'x'begx' coordinate (which must lie on the
// plane), continuing for 'leny'x'lenx' cells. Either or both of 'leny' and
// 'lenx' can be specified as -1 to go through the boundary of the plane.
uint32_t* ncplane_rgba(const struct ncplane* nc, int begy, int begx,
int leny, int lenx);
// Only glyphs from the specified blitset may be present.
uint32_t* ncplane_rgba(const struct ncplane* nc, ncblitter_e blit,
int begy, int begx, int leny, int lenx);
// return a nul-terminated, heap copy of the current (UTF-8) contents.
char* ncplane_contents(const struct ncplane* nc, int begy, int begx,
@ -2507,6 +2508,12 @@ nc_err_e ncvisual_rotate(struct ncvisual* n, double rads);
// transformation, unless the size is unchanged.
nc_err_e ncvisual_resize(struct ncvisual* n, int rows, int cols);
// Polyfill at the specified location within the ncvisual 'n', using 'rgba'.
int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba);
// Get the specified pixel from the specified ncvisual.
int ncvisual_at_yx(const struct ncvisual* n, int y, int x, uint32_t* pixel);
// If a subtitle ought be displayed at this time, return a heap-allocated copy
// of the UTF8 text.
char* ncvisual_subtitle(const struct ncvisual* ncv);

@ -72,6 +72,12 @@ typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*);
**int ncvisual_rotate(struct ncvisual* n, double rads);**
**int ncvisual_resize(struct ncvisual* n, int rows, int cols);**
**int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba);**
**int ncvisual_at_yx(const struct ncvisual* n, int y, int x, uint32_t* pixel);**
**char* ncvisual_subtitle(const struct ncvisual* ncv);**
# DESCRIPTION

@ -621,9 +621,9 @@ namespace ncpp
return error_guard<int> (ncplane_polyfill_yx (plane, y, x, c), -1);
}
uint32_t* rgba(int begy, int begx, int leny, int lenx) const noexcept
uint32_t* rgba(ncblitter_e blit, int begy, int begx, int leny, int lenx) const noexcept
{
return ncplane_rgba (plane, begy, begx, leny, lenx);
return ncplane_rgba (plane, blit, begy, begx, leny, lenx);
}
char* content(int begy, int begx, int leny, int lenx) const noexcept

@ -32,10 +32,10 @@ namespace ncpp
throw init_error ("Notcurses failed to create a new visual");
}
explicit Visual (const Plane& p, int begy, int begx, int leny, int lenx)
explicit Visual (const Plane& p, ncblitter_e blit, int begy, int begx, int leny, int lenx)
: Root(NotCurses::get_instance())
{
visual = ncvisual_from_plane (p, begy, begx, leny, lenx);
visual = ncvisual_from_plane (p, blit, begy, begx, leny, lenx);
if (visual == nullptr)
throw init_error ("Notcurses failed to create a new visual");
}

@ -1213,14 +1213,6 @@ ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c){
return r;
}
// Create an RGBA flat array from the selected region of the ncplane 'nc'.
// Start at the plane's 'begy'x'begx' coordinate (which must lie on the
// plane), continuing for 'leny'x'lenx' cells. Either or both of 'leny' and
// 'lenx' can be specified as -1 to go through the boundary of the plane.
// Only spaces, half blocks, and full blocks may be present.
API uint32_t* ncplane_rgba(const struct ncplane* nc, int begy, int begx,
int leny, int lenx);
// Create a flat string from the EGCs of the selected region of the ncplane
// 'nc'. Start at the plane's 'begy'x'begx' coordinate (which must lie on the
// plane), continuing for 'leny'x'lenx' cells. Either or both of 'leny' and
@ -2119,15 +2111,6 @@ API struct ncvisual* ncvisual_from_rgba(const void* rgba, int rows,
API struct ncvisual* ncvisual_from_bgra(const void* rgba, int rows,
int rowstride, int cols);
// Promote an ncplane 'n' to an ncvisual. The plane may contain only spaces,
// half blocks, and full blocks. The latter will be checked, and any other
// glyph will result in a NULL being returned. This function exists so that
// planes can be subjected to ncvisual transformations. If possible, it's
// better to create the ncvisual from memory using ncvisual_from_rgba().
API struct ncvisual* ncvisual_from_plane(const struct ncplane* n,
int begy, int begx,
int leny, int lenx);
// each has the empty cell in addition to the product of its dimensions. i.e.
// NCBLIT_1x1 has two states: empty and full block. NCBLIT_1x1x4 has five
// states: empty, the three shaded blocks, and the full block.
@ -2143,6 +2126,24 @@ typedef enum {
NCBLIT_SIXEL, // 6 rows, 1 col (RGB), spotty support among terminals
} ncblitter_e;
// Promote an ncplane 'n' to an ncvisual. The plane may contain only spaces,
// half blocks, and full blocks. The latter will be checked, and any other
// glyph will result in a NULL being returned. This function exists so that
// planes can be subjected to ncvisual transformations. If possible, it's
// better to create the ncvisual from memory using ncvisual_from_rgba().
API struct ncvisual* ncvisual_from_plane(const struct ncplane* n,
ncblitter_e blit,
int begy, int begx,
int leny, int lenx);
// Create an RGBA flat array from the selected region of the ncplane 'nc'.
// Start at the plane's 'begy'x'begx' coordinate (which must lie on the
// plane), continuing for 'leny'x'lenx' cells. Either or both of 'leny' and
// 'lenx' can be specified as -1 to go through the boundary of the plane.
// Only glyphs from the specified blitset may be present.
API uint32_t* ncplane_rgba(const struct ncplane* nc, ncblitter_e blit,
int begy, int begx, int leny, int lenx);
// Get the size and ratio of ncvisual pixels to output cells along the y
// ('toy') and x ('tox') axes. A ncvisual of '*y'X'*x' pixels will require
// ('*y' * '*toy')X('x' * 'tox') cells for full output. Returns non-zero
@ -2166,6 +2167,12 @@ API nc_err_e ncvisual_rotate(struct ncvisual* n, double rads);
// transformation, unless the size is unchanged.
API nc_err_e ncvisual_resize(struct ncvisual* n, int rows, int cols);
// Polyfill at the specified location within the ncvisual 'n', using 'rgba'.
API int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba);
// Get the specified pixel from the specified ncvisual.
API int ncvisual_at_yx(const struct ncvisual* n, int y, int x, uint32_t* pixel);
#define NCVISUAL_OPTION_NODEGRADE 0x0001 // fail rather than degrading
#define NCVISUAL_OPTION_BLEND 0x0002 // use CELL_ALPHA_BLEND with visual

@ -147,7 +147,17 @@ char* ncplane_at_cursor(struct ncplane* n, uint32_t* attrword, uint64_t* channel
int ncplane_at_cursor_cell(struct ncplane* n, cell* c);
char* ncplane_at_yx(const struct ncplane* n, int y, int x, uint32_t* attrword, uint64_t* channels);
int ncplane_at_yx_cell(struct ncplane* n, int y, int x, cell* c);
uint32_t* ncplane_rgba(const struct ncplane* nc, int begy, int begx, int leny, int lenx);
typedef enum {
NCBLIT_1x1, // full block
NCBLIT_2x1, // full/(upper|left) blocks
NCBLIT_1x1x4, // shaded full blocks
NCBLIT_2x2, // quadrants
NCBLIT_4x1, // four vert/horz levels /
NCBLIT_BRAILLE, // 4 rows, 2 cols (braille)
NCBLIT_8x1, // eight vert/horz levels /
NCBLIT_SIXEL, // 6 rows, 1 col (RGB)
} ncblitter_e;
uint32_t* ncplane_rgba(const struct ncplane* nc, ncblitter_e blit, int begy, int begx, int leny, int lenx);
char* ncplane_contents(const struct ncplane* nc, int begy, int begx, int leny, int lenx);
void* ncplane_set_userptr(struct ncplane* n, void* opaque);
void* ncplane_userptr(struct ncplane* n);
@ -292,16 +302,6 @@ typedef enum {
NCSCALE_SCALE,
NCSCALE_STRETCH,
} ncscale_e;
typedef enum {
NCBLIT_1x1, // full block
NCBLIT_2x1, // full/(upper|left) blocks
NCBLIT_1x1x4, // shaded full blocks
NCBLIT_2x2, // quadrants
NCBLIT_4x1, // four vert/horz levels /
NCBLIT_BRAILLE, // 4 rows, 2 cols (braille)
NCBLIT_8x1, // eight vert/horz levels /
NCBLIT_SIXEL, // 6 rows, 1 col (RGB)
} ncblitter_e;
struct ncvisual* ncvisual_from_file(const char* file, nc_err_e* ncerr);
struct ncvisual* ncvisual_from_rgba(const void* rgba, int rows, int rowstride, int cols);
struct ncvisual* ncvisual_from_bgra(const void* rgba, int rows, int rowstride, int cols);
@ -310,6 +310,8 @@ int ncvisual_geom(const struct notcurses* nc, const struct ncvisual* n, ncblitte
void ncvisual_destroy(struct ncvisual* ncv);
nc_err_e ncvisual_decode(struct ncvisual* nc);
int ncvisual_rotate(struct ncvisual* n, double rads);
int ncvisual_resize(struct ncvisual* n, int rows, int cols);
int ncvisual_polyfill_yx(struct ncvisual* n, int y, int x, uint32_t rgba);
struct ncplane* ncvisual_render(struct notcurses* nc, struct ncvisual* ncv, const struct ncvisual_options* vopts);
char* ncvisual_subtitle(const struct ncvisual* ncv);
typedef int (*streamcb)(struct ncvisual*, struct ncvisual_options*, const struct timespec*, void*);

@ -62,7 +62,7 @@ rotate_visual(struct notcurses* nc, struct ncplane* n, int dy, int dx){
dx = dy * 2;
}
//fprintf(stderr, "ASK %d/%d @ %d/%d: %p\n", dy, dx, fromy, fromx);
struct ncvisual* ncv = ncvisual_from_plane(n, fromy, fromx, dy, dx);
struct ncvisual* ncv = ncvisual_from_plane(n, NCBLIT_DEFAULT, fromy, fromx, dy, dx);
//fprintf(stderr, "%d/%d @ %d/%d: %p\n", dy, dx, fromy, fromx, ncv);
if(!ncv){
ncvisual_destroy(ncv);

@ -22,17 +22,46 @@ int yield_demo(struct notcurses* nc){
ncvisual_destroy(wmv);
return -1;
}
DEMO_RENDER(nc);
demo_nanosleep(nc, &demodelay);
cell c = CELL_SIMPLE_INITIALIZER('*');
cell_set_fg_rgb(&c, 0xff, 0, 0);
cell_set_bg_rgb(&c, 0xff, 0, 0);
for(int i = 0 ; i < 128 ; ++i){
// FIXME
// don't try to use polyfill; work directly on the ncvisual instead
ncplane_erase(std);
int vy, vx, vscaley, vscalex;
ncvisual_geom(nc, wmv, vopts.blitter, &vy, &vx, &vscaley, &vscalex);
struct timespec scaled;
int threshold_painted = vy * vx * 10 / 9;
const int ITER = 128;
timespec_div(&demodelay, ITER, &scaled);
int tfilled = 0;
for(int i = 0 ; i < ITER ; ++i){
int pfilled;
do{
int x = random() % (vx);
int y = random() % (vy);
uint32_t pixel = 0;
ncvisual_at_yx(wmv, y, x, &pixel);
uint32_t channel = 0;
channel_set_rgb(&channel, 0x80, channel_g(pixel), channel_b(pixel));
//fprintf(stderr, "POLY: %d/%d\n", y, x);
pfilled = ncvisual_polyfill_yx(wmv, y, x, channel);
if(pfilled < 0){
ncvisual_destroy(wmv);
return -1;
}
}while(pfilled == 0);
tfilled += pfilled;
if(ncvisual_render(nc, wmv, &vopts) == NULL){
ncvisual_destroy(wmv);
return -1;
}
DEMO_RENDER(nc);
demo_nanosleep(nc, &scaled);
if(tfilled >= threshold_painted){
break;
}
}
cell_release(std, &c);
ncvisual_destroy(wmv);
return 0;

@ -1938,7 +1938,8 @@ int notcurses_inputready_fd(notcurses* n){
return fileno(n->ttyinfp);
}
uint32_t* ncplane_rgba(const ncplane* nc, int begy, int begx, int leny, int lenx){
uint32_t* ncplane_rgba(const ncplane* nc, ncblitter_e blit,
int begy, int begx, int leny, int lenx){
if(begy < 0 || begx < 0){
return NULL;
}
@ -1979,6 +1980,9 @@ uint32_t* ncplane_rgba(const ncplane* nc, int begy, int begx, int leny, int lenx
// FIXME how do we deal with transparency?
uint32_t frgba = (fr) + (fg << 16u) + (fb << 8u) + 0xff000000;
uint32_t brgba = (br) + (bg << 16u) + (bb << 8u) + 0xff000000;
// FIXME integrate 'blit'
(void)blit;
// FIXME need to be able to pick up quadrants!
if((strcmp(c, " ") == 0) || (strcmp(c, "") == 0)){
*top = *bot = brgba;
}else if(strcmp(c, "") == 0){
@ -1992,6 +1996,7 @@ uint32_t* ncplane_rgba(const ncplane* nc, int begy, int begx, int leny, int lenx
}else{
free(c);
free(ret);
//fprintf(stderr, "bad rgba character: %s\n", c);
return NULL;
}
free(c);

@ -473,10 +473,11 @@ auto ncvisual_render(notcurses* nc, ncvisual* ncv,
return n;
}
auto ncvisual_from_plane(const ncplane* n, int begy, int begx,
auto ncvisual_from_plane(const ncplane* n, ncblitter_e blit, int begy, int begx,
int leny, int lenx) -> ncvisual* {
uint32_t* rgba = ncplane_rgba(n, begy, begx, leny, lenx);
uint32_t* rgba = ncplane_rgba(n, blit, begy, begx, leny, lenx);
//fprintf(stderr, "snarg: %d/%d @ %d/%d (%p)\n", leny, lenx, begy, begx, rgba);
//fprintf(stderr, "RGBA %p\n", rgba);
if(rgba == nullptr){
return nullptr;
}
@ -490,9 +491,7 @@ auto ncvisual_from_plane(const ncplane* n, int begy, int begx,
}
auto* ncv = ncvisual_from_rgba(rgba, leny * 2, lenx * 4, lenx);
free(rgba);
if(ncv == nullptr){
return nullptr;
}
//fprintf(stderr, "RETURNING %p\n", ncv);
return ncv;
}
@ -527,6 +526,50 @@ auto ncvisual_simple_streamer(ncvisual* ncv, struct ncvisual_options* vopts,
return ret;
}
auto ncvisual_polyfill_recurse(ncvisual* n, int y, int x,
uint32_t rgba, uint32_t match) -> int {
if(y < 0 || y >= n->rows){
return 0;
}
if(x < 0 || x >= n->cols){
return 0;
}
uint32_t* pixel = &n->data[y * (n->rowstride / 4) + x];
if(*pixel != match || *pixel == rgba){
return 0;
}
//fprintf(stderr, "%d/%d: %08x -> %08x\n", y, x, *pixel, rgba);
*pixel = rgba;
int ret = 1;
ret += ncvisual_polyfill_recurse(n, y - 1, x, rgba, match);
ret += ncvisual_polyfill_recurse(n, y + 1, x, rgba, match);
ret += ncvisual_polyfill_recurse(n, y, x - 1, rgba, match);
ret += ncvisual_polyfill_recurse(n, y, x + 1, rgba, match);
return ret;
}
auto ncvisual_at_yx(const ncvisual* n, int y, int x, uint32_t* pixel) -> int {
if(y >= n->rows || y < 0){
return -1;
}
if(x >= n->cols || x < 0){
return -1;
}
*pixel = n->data[y * (n->rowstride / 4) + x];
return 0;
}
auto ncvisual_polyfill_yx(ncvisual* n, int y, int x, uint32_t rgba) -> int {
if(y >= n->rows || y < 0){
return -1;
}
if(x >= n->cols || x < 0){
return -1;
}
uint32_t* pixel = &n->data[y * (n->rowstride / 4) + x];
return ncvisual_polyfill_recurse(n, y, x, rgba, *pixel);
}
#ifndef USE_OIIO // built without ffmpeg or oiio
#ifndef USE_FFMPEG
auto ncvisual_from_file(const char* filename, nc_err_e* err) -> ncvisual* {

@ -23,7 +23,7 @@ rotate_grad(struct notcurses* nc){
}
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
uint32_t* rgba = ncplane_rgba(n, 0, 0, dimy, dimx);
uint32_t* rgba = ncplane_rgba(n, NCBLIT_DEFAULT, 0, 0, dimy, dimx);
if(rgba == NULL){
return -1;
}
@ -149,7 +149,7 @@ rotate(struct notcurses* nc){
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
// we now have 2 rows of 20 cells each, with gradients. load 'em.
uint32_t* rgba = ncplane_rgba(n, dimy / 2, 0, 2, XSIZE);
uint32_t* rgba = ncplane_rgba(n, NCBLIT_DEFAULT, dimy / 2, 0, 2, XSIZE);
if(rgba == NULL){
return -1;
}

@ -59,7 +59,7 @@ TEST_CASE("Ncpp"
// FIXME load something onto standard plane, load it into visual, erase
// plane, render visual, check for equivalence...
{
Visual v = Visual(*n, 0, 0, -1, -1);
Visual v = Visual(*n, NCBLIT_DEFAULT, 0, 0, -1, -1);
}
}
CHECK(nc.stop());

@ -119,7 +119,7 @@ TEST_CASE("Rotate") {
ncvisual_options opts{};
auto rendered = ncvisual_render(nc_, ncv, &opts);
REQUIRE(rendered);
uint32_t* rgbaret = ncplane_rgba(rendered, 0, 0, -1, -1);
uint32_t* rgbaret = ncplane_rgba(rendered, NCBLIT_DEFAULT, 0, 0, -1, -1);
REQUIRE(rgbaret);
for(int i = 0 ; i < height * width / 2 ; ++i){
if(rgbaret[i] & CELL_BG_MASK){
@ -170,7 +170,7 @@ TEST_CASE("Rotate") {
ncvisual_options opts{};
auto rendered = ncvisual_render(nc_, ncv, &opts);
REQUIRE(rendered);
uint32_t* rgbaret = ncplane_rgba(rendered, 0, 0, -1, -1);
uint32_t* rgbaret = ncplane_rgba(rendered, NCBLIT_DEFAULT, 0, 0, -1, -1);
REQUIRE(rgbaret);
for(int i = 0 ; i < height * width / 2 ; ++i){
if(rgbaret[i] & CELL_BG_MASK){

Loading…
Cancel
Save