ncplane_as_rgba(), returns pixel geometry along with bitmap #1508

This commit is contained in:
nick black 2021-04-08 04:12:01 -04:00
parent 4996bebad0
commit 05082fc277
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
9 changed files with 64 additions and 17 deletions

View File

@ -1,6 +1,11 @@
This document attempts to list user-visible changes and any major internal This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses. rearrangements of Notcurses.
* 2.2.6 (not yet released)
* `ncplane_rgba()` has been deprecated in favor of the new function
`ncplane_as_rgba()`, which the former now wraps. It will be removed
in ABI3. The new function can report the synthesized pixel geometry.
* 2.2.5 (2021-04-04) * 2.2.5 (2021-04-04)
* Bugfix release, no user-visible changes. * Bugfix release, no user-visible changes.

View File

@ -1017,9 +1017,11 @@ int ncplane_at_yx_cell(struct ncplane* n, int y, int x, nccell* c);
// Start at the plane's 'begy'x'begx' coordinate (which must lie on the // 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 // 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. // 'lenx' can be specified as -1 to go through the boundary of the plane.
// Only glyphs from the specified blitset may be present. // Only glyphs from the specified blitset may be present. If 'pxdimy' and/or
uint32_t* ncplane_rgba(const struct ncplane* nc, ncblitter_e blit, // 'pxdimx' are non-NULL, they will be filled in with the pixel geometry.
int begy, int begx, int leny, int lenx); uint32_t* ncplane_as_rgba(const struct ncplane* n, ncblitter_e blit,
int begy, int begx, int leny, int lenx,
int *pxdimy, int *pxdimx);
// return a nul-terminated, heap copy of the current (UTF-8) contents. // return a nul-terminated, heap copy of the current (UTF-8) contents.
char* ncplane_contents(const struct ncplane* nc, int begy, int begx, char* ncplane_contents(const struct ncplane* nc, int begy, int begx,

View File

@ -104,7 +104,7 @@ typedef struct ncplane_options {
**int ncplane_at_yx_cell(struct ncplane* ***n***, int ***y***, int ***x***, nccell* ***c***);** **int ncplane_at_yx_cell(struct ncplane* ***n***, int ***y***, int ***x***, nccell* ***c***);**
**uint32_t* ncplane_rgba(const struct ncplane* ***nc***, int ***begy***, int ***begx***, int ***leny***, int ***lenx***);** **uint32_t* ncplane_as_rgba(const struct ncplane* ***nc***, int ***begy***, int ***begx***, int ***leny***, int ***lenx***, int* ***pxdimy***, int* ***pxdimx***);**
**char* ncplane_contents(const struct ncplane* ***nc***, int ***begy***, int ***begx***, int ***leny***, int ***lenx***);** **char* ncplane_contents(const struct ncplane* ***nc***, int ***begy***, int ***begx***, int ***leny***, int ***lenx***);**
@ -373,6 +373,9 @@ this result. **ncplane_at_yx_cell** and **ncplane_at_cursor_cell** instead load
these values into an **nccell**, which is invalidated if the associated plane is these values into an **nccell**, which is invalidated if the associated plane is
destroyed. The caller should release this **nccell** with **cell_release**. destroyed. The caller should release this **nccell** with **cell_release**.
**ncplane_as_rgba** returns a heap-allocated array of **uint32_t** values,
each representing a single RGBA pixel, or **NULL** on failure.
Functions returning **int** return 0 on success, and non-zero on error. Functions returning **int** return 0 on success, and non-zero on error.
All other functions cannot fail (and return **void**). All other functions cannot fail (and return **void**).

View File

@ -805,7 +805,7 @@ namespace ncpp
uint32_t* rgba(ncblitter_e blit, 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, blit, begy, begx, leny, lenx); return ncplane_as_rgba (plane, blit, begy, begx, leny, lenx, nullptr, nullptr);
} }
char* content(int begy, int begx, int leny, int lenx) const noexcept char* content(int begy, int begx, int leny, int lenx) const noexcept

View File

@ -2450,9 +2450,20 @@ struct ncvisual_options {
// Start at the plane's 'begy'x'begx' coordinate (which must lie on the // 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 // 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. // 'lenx' can be specified as -1 to go through the boundary of the plane.
// Only glyphs from the specified blitset may be present. // Only glyphs from the specified blitset may be present. If 'pxdimy' and/or
API ALLOC uint32_t* ncplane_rgba(const struct ncplane* n, ncblitter_e blit, // 'pxdimx' are non-NULL, they will be filled in with the pixel geometry.
int begy, int begx, int leny, int lenx); API ALLOC uint32_t* ncplane_as_rgba(const struct ncplane* n, ncblitter_e blit,
int begy, int begx, int leny, int lenx,
int *pxdimy, int *pxdimx)
__attribute__ ((nonnull (1)));
// Deprecated in favor of ncplane_as_rgba. This will be removed in ABI3.
ALLOC __attribute__ ((deprecated)) __attribute__ ((nonnull (1)))
static inline uint32_t*
ncplane_rgba(const struct ncplane* n, ncblitter_e blit,
int begy, int begx, int leny, int lenx){
return ncplane_as_rgba(n, blit, begy, begx, leny, lenx, NULL, NULL);
}
// Get the size and ratio of ncvisual pixels to output cells along the y // 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 // ('toy') and x ('tox') axes. A ncvisual of '*y'X'*x' pixels will require

View File

@ -2424,12 +2424,16 @@ int ncdirect_inputready_fd(ncdirect* n){
return n->input.ttyinfd; return n->input.ttyinfd;
} }
uint32_t* ncplane_rgba(const ncplane* nc, ncblitter_e blit, uint32_t* ncplane_as_rgba(const ncplane* nc, ncblitter_e blit,
int begy, int begx, int leny, int lenx){ int begy, int begx, int leny, int lenx,
int *pxdimy, int *pxdimx){
const notcurses* ncur = ncplane_notcurses_const(nc);
if(begy < 0 || begx < 0){ if(begy < 0 || begx < 0){
logerror(ncur, "Nil offset (%d,%d)\n", begy, begx);
return NULL; return NULL;
} }
if(begx >= nc->lenx || begy >= nc->leny){ if(begx >= nc->lenx || begy >= nc->leny){
logerror(ncur, "Invalid offset (%d,%d)\n", begy, begx);
return NULL; return NULL;
} }
if(lenx == -1){ // -1 means "to the end"; use all space available if(lenx == -1){ // -1 means "to the end"; use all space available
@ -2439,13 +2443,27 @@ uint32_t* ncplane_rgba(const ncplane* nc, ncblitter_e blit,
leny = nc->leny - begy; leny = nc->leny - begy;
} }
if(lenx < 0 || leny < 0){ // no need to draw zero-size object, exit if(lenx < 0 || leny < 0){ // no need to draw zero-size object, exit
logerror(ncur, "Nil geometry (%dx%d)\n", leny, lenx);
return NULL; return NULL;
} }
//fprintf(stderr, "sum: %d/%d avail: %d/%d\n", begy + leny, begx + lenx, nc->leny, nc->lenx); //fprintf(stderr, "sum: %d/%d avail: %d/%d\n", begy + leny, begx + lenx, nc->leny, nc->lenx);
if(begx + lenx > nc->lenx || begy + leny > nc->leny){ if(begx + lenx > nc->lenx || begy + leny > nc->leny){
logerror(ncur, "Invalid specs %d + %d > %d or %d + %d > %d\n",
begx, lenx, nc->lenx, begy, leny, nc->leny);
return NULL;
}
if(blit > NCBLIT_2x1){
logerror(ncur, "Blitter %d is not yet supported\n", blit);
return NULL; return NULL;
} }
//fprintf(stderr, "ALLOCATING %zu\n", 4u * lenx * leny * 2); //fprintf(stderr, "ALLOCATING %zu\n", 4u * lenx * leny * 2);
// FIXME this all assumes NCBLIT_2x1, need blitter-specific scaling
if(pxdimy){
*pxdimy = leny * 2;
}
if(pxdimx){
*pxdimx = lenx;
}
uint32_t* ret = malloc(sizeof(*ret) * lenx * leny * 2); uint32_t* ret = malloc(sizeof(*ret) * lenx * leny * 2);
if(ret){ if(ret){
for(int y = begy, targy = 0 ; y < begy + leny ; ++y, targy += 2){ for(int y = begy, targy = 0 ; y < begy + leny ; ++y, targy += 2){
@ -2466,8 +2484,6 @@ uint32_t* ncplane_rgba(const ncplane* nc, ncblitter_e blit,
// FIXME how do we deal with transparency? // FIXME how do we deal with transparency?
uint32_t frgba = (fr) + (fg << 16u) + (fb << 8u) + 0xff000000; uint32_t frgba = (fr) + (fg << 16u) + (fb << 8u) + 0xff000000;
uint32_t brgba = (br) + (bg << 16u) + (bb << 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! // FIXME need to be able to pick up quadrants!
if((strcmp(c, " ") == 0) || (strcmp(c, "") == 0)){ if((strcmp(c, " ") == 0) || (strcmp(c, "") == 0)){
*top = *bot = brgba; *top = *bot = brgba;

View File

@ -698,7 +698,7 @@ ncplane* ncvisual_render(notcurses* nc, ncvisual* ncv, const struct ncvisual_opt
ncvisual* ncvisual_from_plane(const ncplane* n, ncblitter_e blit, int begy, int begx, ncvisual* ncvisual_from_plane(const ncplane* n, ncblitter_e blit, int begy, int begx,
int leny, int lenx){ int leny, int lenx){
uint32_t* rgba = ncplane_rgba(n, blit, begy, begx, leny, lenx); uint32_t* rgba = ncplane_as_rgba(n, blit, begy, begx, leny, lenx, NULL, NULL);
//fprintf(stderr, "snarg: %d/%d @ %d/%d (%p)\n", leny, lenx, begy, begx, rgba); //fprintf(stderr, "snarg: %d/%d @ %d/%d (%p)\n", leny, lenx, begy, begx, rgba);
//fprintf(stderr, "RGBA %p\n", rgba); //fprintf(stderr, "RGBA %p\n", rgba);
if(rgba == NULL){ if(rgba == NULL){

View File

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

View File

@ -173,8 +173,12 @@ TEST_CASE("Rotate") {
ncvisual_options opts{}; ncvisual_options opts{};
auto rendered = ncvisual_render(nc_, ncv, &opts); auto rendered = ncvisual_render(nc_, ncv, &opts);
REQUIRE(rendered); REQUIRE(rendered);
uint32_t* rgbaret = ncplane_rgba(rendered, NCBLIT_DEFAULT, 0, 0, -1, -1); int pxdimy, pxdimx;
uint32_t* rgbaret = ncplane_as_rgba(rendered, NCBLIT_DEFAULT,
0, 0, -1, -1, &pxdimy, &pxdimx);
REQUIRE(rgbaret); REQUIRE(rgbaret);
CHECK(pxdimx == width);
CHECK(pxdimy == height);
for(int i = 0 ; i < height * width / 2 ; ++i){ for(int i = 0 ; i < height * width / 2 ; ++i){
if(rgbaret[i] & CELL_BG_RGB_MASK){ if(rgbaret[i] & CELL_BG_RGB_MASK){
CHECK(htole(rgbaret[i]) == rgba[i]); CHECK(htole(rgbaret[i]) == rgba[i]);
@ -226,8 +230,12 @@ TEST_CASE("Rotate") {
ncvisual_options opts{}; ncvisual_options opts{};
auto rendered = ncvisual_render(nc_, ncv, &opts); auto rendered = ncvisual_render(nc_, ncv, &opts);
REQUIRE(rendered); REQUIRE(rendered);
uint32_t* rgbaret = ncplane_rgba(rendered, NCBLIT_DEFAULT, 0, 0, -1, -1); int pxdimy, pxdimx;
uint32_t* rgbaret = ncplane_as_rgba(rendered, NCBLIT_DEFAULT,
0, 0, -1, -1, &pxdimy, &pxdimx);
REQUIRE(rgbaret); REQUIRE(rgbaret);
CHECK(pxdimy == height);
CHECK(pxdimx == width);
for(int i = 0 ; i < height * width / 2 ; ++i){ for(int i = 0 ; i < height * width / 2 ; ++i){
if(rgbaret[i] & CELL_BG_RGB_MASK){ if(rgbaret[i] & CELL_BG_RGB_MASK){
CHECK(htole(rgbaret[i]) == rgba[i]); CHECK(htole(rgbaret[i]) == rgba[i]);