From 17b06b1180b459f53110cb7f09438ee298ad6a4a Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 31 Oct 2021 09:54:42 -0400 Subject: [PATCH] [ncvgeom] add begy/begx and leny/lenx to ncvgeom --- USAGE.md | 2 + doc/man/man3/notcurses_visual.3.md | 2 + include/notcurses/notcurses.h | 2 + src/demo/luigi.c | 1 + src/lib/blitset.h | 8 ++- src/lib/direct.c | 18 +---- src/lib/internal.h | 10 ++- src/lib/visual.c | 112 ++++++++++++++++++----------- 8 files changed, 90 insertions(+), 65 deletions(-) diff --git a/USAGE.md b/USAGE.md index 76b492f70..6c4054ca2 100644 --- a/USAGE.md +++ b/USAGE.md @@ -3322,6 +3322,8 @@ typedef struct ncvgeom { int rcelly, rcellx; // rendered cell geometry (per visual_options) int scaley, scalex; // pixels per filled cell (scale == c for bitmaps) int maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL + int begy, begx; // upper-left corner of used section + int leny, lenx; // geometry of used section ncblitter_e blitter;// blitter that will be used } ncvgeom; diff --git a/doc/man/man3/notcurses_visual.3.md b/doc/man/man3/notcurses_visual.3.md index 4d5abbbde..424def918 100644 --- a/doc/man/man3/notcurses_visual.3.md +++ b/doc/man/man3/notcurses_visual.3.md @@ -59,6 +59,8 @@ typedef struct ncvgeom { int rcelly, rcellx; // rendered cell geometry (per visual_options) int scaley, scalex; // pixels per filled cell (scale == c for bitmaps) int maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL + int begy, begx; // upper-left corner of used section + int leny, lenx; // geometry of used section ncblitter_e blitter;// blitter that will be used } ncvgeom; ``` diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 9d9494d10..679998221 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2904,6 +2904,8 @@ typedef struct ncvgeom { int rcelly, rcellx; // rendered cell geometry (per visual_options) int scaley, scalex; // pixels per filled cell (scale == c for bitmaps) int maxpixely, maxpixelx; // only defined for NCBLIT_PIXEL + int begy, begx; // upper-left corner of used section + int leny, lenx; // geometry of used section ncblitter_e blitter;// blitter that will be used } ncvgeom; diff --git a/src/demo/luigi.c b/src/demo/luigi.c index 8fedf0022..ec13d2639 100644 --- a/src/demo/luigi.c +++ b/src/demo/luigi.c @@ -222,6 +222,7 @@ int luigi_demo(struct notcurses* nc){ ncvgeom geom; ncvisual_geom(nc, wmncv, NULL, &geom); geom.pixy /= geom.scaley; + // FIXME what the fuck is this ncplane_move_yx(wmplane, rows * 4 / 5 - geom.pixy + 1 + (i % 2), i - 60); DEMO_RENDER(nc); demo_nanosleep(nc, &stepdelay); diff --git a/src/lib/blitset.h b/src/lib/blitset.h index 6980e3b89..eb564c9cc 100644 --- a/src/lib/blitset.h +++ b/src/lib/blitset.h @@ -1,7 +1,9 @@ #ifndef NOTCURSES_BLITSET #define NOTCURSES_BLITSET -#include "notcurses/notcurses.h" +#ifdef __cplusplus +extern "C" { +#endif // number of pixels that map to a single cell, height-wise static inline int @@ -50,4 +52,8 @@ ncplot_defblitter(const notcurses* nc){ void set_pixel_blitter(ncblitter blitfxn); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/lib/direct.c b/src/lib/direct.c index 82c24540d..91f94ea29 100644 --- a/src/lib/direct.c +++ b/src/lib/direct.c @@ -1590,24 +1590,8 @@ ncdirectv* ncdirectf_render(ncdirect* n, ncdirectf* frame, const struct ncvisual int ncdirectf_geom(ncdirect* n, ncdirectf* frame, const struct ncvisual_options* vopts, ncvgeom* geom){ - geom->cdimy = n->tcache.cellpixy; - geom->cdimx = n->tcache.cellpixx; - geom->maxpixely = n->tcache.sixel_maxy; - geom->maxpixelx = n->tcache.sixel_maxx; const struct blitset* bset; - int r = ncvisual_blitset_geom(NULL, &n->tcache, frame, vopts, - &geom->pixy, &geom->pixx, - &geom->scaley, &geom->scalex, - &geom->rpixy, &geom->rpixx, &bset); - if(r == 0){ - // FIXME ncvisual_blitset_geom() ought calculate these two for us; until - // then, derive them ourselves. the row count might be short by one if - // we're using sixel, and we're not a multiple of 6 - geom->rcelly = geom->pixy / geom->scaley; - geom->rcellx = geom->pixx / geom->scalex; - geom->blitter = bset->geom; - } - return r; + return ncvisual_geom_inner(&n->tcache, frame, vopts, geom, &bset); } unsigned ncdirect_supported_styles(const ncdirect* nc){ diff --git a/src/lib/internal.h b/src/lib/internal.h index ce089bb9f..d68ace653 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -388,12 +388,6 @@ struct blitset { #include "blitset.h" -int ncvisual_blitset_geom(const notcurses* nc, const tinfo* tcache, - const struct ncvisual* n, - const struct ncvisual_options* vopts, - int* y, int* x, int* scaley, int* scalex, - int* leny, int* lenx, const struct blitset** blitter); - void reset_stats(ncstats* stats); void summarize_stats(notcurses* nc); @@ -1561,6 +1555,10 @@ rgba_blit_dispatch(ncplane* nc, const struct blitset* bset, return bset->blit(nc, linesize, data, leny, lenx, bargs); } +int ncvisual_geom_inner(const tinfo* ti, const struct ncvisual* n, + const struct ncvisual_options* vopts, ncvgeom* geom, + const struct blitset** bset); + static inline const struct blitset* rgba_blitter_low(const tinfo* tcache, ncscale_e scale, bool maydegrade, ncblitter_e blitrec) { diff --git a/src/lib/visual.c b/src/lib/visual.c index 93d0c5d61..8866e4603 100644 --- a/src/lib/visual.c +++ b/src/lib/visual.c @@ -128,14 +128,13 @@ ncvisual_origin(const struct ncvisual_options* vopts, int* restrict begy, int* r // 'leny' and 'lenx' get the number of pixels to actually be rendered, 'y' and // 'x' get the original size of the visual in pixels, and 'scaley' and 'scalex' -// get the number of pixels per cell with the selected 'blitter'. -// FIXME we ought also do the output calculations here (how many rows x cols, -// given the input plane vopts->n and scaling vopts->scaling)--but do not -// perform any actual scaling, nor create any planes! -int ncvisual_blitset_geom(const notcurses* nc, const tinfo* tcache, - const ncvisual* n, const struct ncvisual_options* vopts, - int* y, int* x, int* scaley, int* scalex, - int* leny, int* lenx, const struct blitset** blitter){ +// get the number of pixels per cell with the selected 'blitter'. this is the +// first part of real geometry calculation. +static int +ncvisual_blitset_geom(const notcurses* nc, const tinfo* tcache, + const ncvisual* n, const struct ncvisual_options* vopts, + int* y, int* x, int* scaley, int* scalex, + int* leny, int* lenx, const struct blitset** blitter){ int fakeleny, fakelenx; if(leny == NULL){ leny = &fakeleny; @@ -288,7 +287,8 @@ int ncvisual_blitter_geom(const notcurses* nc, const ncvisual* n, } int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n, - const struct ncvisual_options* vopts, ncvgeom* geom){ + const struct ncvisual_options* vopts, ncvgeom* geom, + const struct blitset** bset){ if(ti == NULL && n == NULL){ logerror("got NULL for both sources\n"); return -1; @@ -301,34 +301,65 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n, return 0; } // determine our blitter - const struct blitset* bset = rgba_blitter(ti, vopts); - if(!bset){ + *bset = rgba_blitter(ti, vopts); + if(!*bset){ logerror("Couldn't get a blitter for %d\n", vopts ? vopts->blitter : NCBLIT_DEFAULT); return -1; } geom->cdimy = ti->cellpixy; geom->cdimx = ti->cellpixx; - if((geom->blitter = bset->geom) == NCBLIT_PIXEL){ + if((geom->blitter = (*bset)->geom) == NCBLIT_PIXEL){ geom->maxpixely = ti->sixel_maxy_pristine; geom->maxpixelx = ti->sixel_maxx; geom->scaley = ti->cellpixy; geom->scalex = ti->cellpixx; }else{ - geom->scaley = bset->height; - geom->scalex = bset->width; + geom->scaley = (*bset)->height; + geom->scalex = (*bset)->width; } // when n is NULL, we only report properties unrelated to the ncvisual, // i.e. the cell-pixel geometry, max bitmap geometry, blitter, and scaling. if(n == NULL){ return 0; } - // FIXME now work with full variant + // determine how much of the original image we're using (leny/lenx) + ncvisual_origin(vopts, &geom->begy, &geom->begx); + geom->lenx = vopts ? vopts->lenx : 0; + geom->leny = vopts ? vopts->leny : 0; + logdebug("blit %dx%d+%dx%d %p\n", geom->begy, geom->begx, geom->leny, geom->lenx, n->data); + if(geom->begy < 0 || geom->begx < 0){ + logerror("invalid geometry for visual %d %d %d %d\n", geom->begy, geom->begx, geom->leny, geom->lenx); + return -1; + } + if(n->data == NULL){ + logerror("no data in visual\n"); + return -1; + } + if(geom->begx >= n->pixx || geom->begy >= n->pixy){ + logerror("visual too large %d > %d or %d > %d\n", geom->begy, n->pixy, geom->begx, n->pixx); + return -1; + } + if(geom->lenx == 0){ // 0 means "to the end"; use all available source material + geom->lenx = n->pixx - geom->begx; + } + if(geom->leny == 0){ + geom->leny = n->pixy - geom->begy; + } + if(geom->lenx <= 0 || geom->leny <= 0){ // no need to draw zero-size object, exit + logerror("zero-size object %d %d\n", geom->leny, geom->lenx); + return -1; + } + if(geom->begx + geom->lenx > n->pixx || geom->begy + geom->leny > n->pixy){ + logerror("geometry too large %d > %d or %d > %d\n", geom->begy + geom->leny, n->pixy, geom->begx + geom->lenx, n->pixx); + return -1; + } return 0; } int ncvisual_geom(const notcurses* nc, const ncvisual* n, const struct ncvisual_options* vopts, ncvgeom* geom){ - return ncvisual_geom_inner(nc ? &nc->tcache : NULL, n, vopts, geom); + const struct blitset* bset; + return ncvisual_geom_inner(nc ? &nc->tcache : NULL, n, vopts, geom, &bset); } void* rgb_loose_to_rgba(const void* data, int rows, int* rowstride, int cols, int alpha){ @@ -845,7 +876,8 @@ int ncvisual_resize_noninterpolative(ncvisual* n, int rows, int cols){ // the origin of the source region to draw (in pixels). leny/lenx define the // geometry of the source region to draw, again in pixels. ncv->pixy and // ncv->pixx define the source geometry in pixels. -ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitset* bset, +ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, int scaley, int scalex, + const struct blitset* bset, int placey, int placex, int begy, int begx, int leny, int lenx, ncplane* n, ncscale_e scaling, uint64_t flags, uint32_t transcolor){ @@ -862,8 +894,8 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse }else{ ncplane_dim_yx(n, &disprows, &dispcols); } - dispcols *= encoding_x_scale(&nc->tcache, bset); - disprows *= encoding_y_scale(&nc->tcache, bset); + dispcols *= scalex; + disprows *= scaley; if(scaling == NCSCALE_SCALE || scaling == NCSCALE_SCALE_HIRES){ scale_visual(ncv, &disprows, &dispcols); } // else stretch @@ -872,10 +904,8 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse struct ncplane_options nopts = { .y = placey, .x = placex, - .rows = disprows / encoding_y_scale(&nc->tcache, bset) + - !!(disprows % encoding_y_scale(&nc->tcache, bset)), - .cols = dispcols / encoding_x_scale(&nc->tcache, bset) + - !!(dispcols % encoding_x_scale(&nc->tcache, bset)), + .rows = disprows / scaley + !!(disprows % scaley), + .cols = dispcols / scalex + !!(dispcols % scalex), .userptr = NULL, .name = "cvis", .resizecb = NULL, @@ -904,8 +934,8 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse disprows = leny; }else{ ncplane_dim_yx(n, &disprows, &dispcols); - dispcols *= encoding_x_scale(&nc->tcache, bset); - disprows *= encoding_y_scale(&nc->tcache, bset); + dispcols *= scalex; + disprows *= scaley; if(!(flags & NCVISUAL_OPTION_HORALIGNED)){ dispcols -= placex; } @@ -917,10 +947,10 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse } // else stretch } if(flags & NCVISUAL_OPTION_HORALIGNED){ - placex = ncplane_halign(n, placex, dispcols / encoding_x_scale(&nc->tcache, bset)); + placex = ncplane_halign(n, placex, dispcols / scalex); } if(flags & NCVISUAL_OPTION_VERALIGNED){ - placey = ncplane_valign(n, placey, disprows / encoding_y_scale(&nc->tcache, bset)); + placey = ncplane_valign(n, placey, disprows / scaley); } } //fprintf(stderr, "blit: %dx%d:%d+%d of %d/%d stride %u %p\n", begy, begx, leny, lenx, ncv->pixy, ncv->pixx, ncv->rowstride, ncv->data); @@ -1187,32 +1217,32 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits } ncplane* ncvisual_blit(notcurses* nc, ncvisual* ncv, const struct ncvisual_options* vopts){ +//fprintf(stderr, "beg/len: %d %d %d %d place: %d/%d scale: %d/%d\n", begy, leny, begx, lenx, placey, placex, encoding_y_scale(&nc->tcache, bset), encoding_x_scale(&nc->tcache, bset)); +//fprintf(stderr, "%p tacache: %p\n", n, n->tacache); + ncvgeom geom; const struct blitset* bset; - int leny, lenx; - if(ncvisual_blitset_geom(nc, &nc->tcache, ncv, vopts, NULL, NULL, NULL, NULL, - &leny, &lenx, &bset) < 0){ + if(ncvisual_geom_inner(&nc->tcache, ncv, vopts, &geom, &bset)){ // ncvisual_blitset_geom() emits its own diagnostics, no need for an error here return NULL; } - int begy, begx; - ncvisual_origin(vopts, &begy, &begx); - int placey = vopts ? vopts->y : 0; - int placex = vopts ? vopts->x : 0; -//fprintf(stderr, "beg/len: %d %d %d %d place: %d/%d scale: %d/%d\n", begy, leny, begx, lenx, placey, placex, encoding_y_scale(&nc->tcache, bset), encoding_x_scale(&nc->tcache, bset)); ncplane* n = (vopts ? vopts->n : NULL); -//fprintf(stderr, "%p tacache: %p\n", n, n->tacache); ncscale_e scaling = vopts ? vopts->scaling : NCSCALE_NONE; uint32_t transcolor = 0; if(vopts && vopts->flags & NCVISUAL_OPTION_ADDALPHA){ transcolor = 0x1000000ull | vopts->transcolor; } - if(bset->geom != NCBLIT_PIXEL){ - n = ncvisual_render_cells(nc, ncv, bset, placey, placex, begy, begx, - leny, lenx, n, scaling, + int placey = vopts ? vopts->y : 0; + int placex = vopts ? vopts->x : 0; + if(geom.blitter != NCBLIT_PIXEL){ + n = ncvisual_render_cells(nc, ncv, geom.scaley, geom.scalex, + bset, placey, placex, + geom.begy, geom.begx, + geom.leny, geom.lenx, n, scaling, vopts ? vopts->flags : 0, transcolor); }else{ - n = ncvisual_render_pixels(nc, ncv, bset, placey, placex, begy, begx, - leny, lenx, n, scaling, + n = ncvisual_render_pixels(nc, ncv, bset, placey, placex, + geom.begy, geom.begx, + geom.leny, geom.lenx, n, scaling, vopts ? vopts->flags : 0, transcolor, vopts ? vopts->pxoffy : 0, vopts ? vopts->pxoffx : 0);