Open some whoopass on ncvisual rotation (#677)

Whip the ol' llama's ass (fix ncvisual rotation)

* notcurses: flush cursor change requests #673
* rotator: verify ncplane_rgba and ncblit_rgba
* ncblit: rename, accept ncblitter_e #674
* rotator: render from rgba
* rotator: get to rotation
* rotator: add a pi/4 turn at the end
* normal: reuse incoming plane for rendering #672
* rotator poc: rotate a fullplane gradient #672
* normal demo: place visual correctly
* rotator: verify ncplane_rgba and ncblit_rgba
* ncblit: rename, accept ncblitter_e #674
* rotator: render from rgba
* rotator: add a pi/4 turn at the end
* normal: reuse incoming plane for rendering #672
* rotator poc: rotate a fullplane gradient #672
* normal demo: place visual correctly
* rotator poc: throw some red into gradient
* rotator poc: done #662
* oiio: ncvisual_resize() needs set ibuf pointer #662
* normal: only need erase at top of loop
* visual poc: shorter delay
* normal demo: center rendered visual
* comment ncvisual_resize() call
* ncvisual_rotate: call ncvisual_details_seed()
* ffmpeg ncvisual: fix rotation #662
This commit is contained in:
Nick Black 2020-06-04 22:47:38 -04:00 committed by GitHub
parent dbe779365b
commit de23139111
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 359 additions and 74 deletions

View File

@ -1,6 +1,12 @@
This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 1.5.0 (not yet released)
* `ncblit_rgba()` and `ncblit_bgrx()` have been renamed `ncplane_blit_rgba()`
and `ncplane_blit_bgrx()`, to match every other existing ncplane function.
In addition, they both now accept an `ncblitter_e` to select the blitting
method. `NCBLIT_DEFAULT` will use `NCBLITTER_2x1`.
* 1.4.4.1 (2020-06-01)
* Got the `ncvisual` API ready for API freeze: `ncvisual_render()` and
`ncvisual_stream()` now take a `struct ncvisual_options`. `ncstyle_e`

View File

@ -1253,17 +1253,17 @@ Raw streams of RGBA or BGRx data can be blitted directly to an ncplane:
// from the upper left by 'placey' and 'placex'. Each row ought occupy
// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A
// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'.
int ncblit_bgrx(struct ncplane* nc, int placey, int placex, int linesize,
const unsigned char* data, int begy, int begx,
int leny, int lenx);
int ncplane_blit_bgrx(struct ncplane* nc, int placey, int placex, int linesize,
ncblitter_e blitter, const unsigned char* data,
int begy, int begx, int leny, int lenx);
// Blit a flat array 'data' of RGBA 32-bit values to the ncplane 'nc', offset
// from the upper left by 'placey' and 'placex'. Each row ought occupy
// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A
// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'.
int ncblit_rgba(struct ncplane* nc, int placey, int placex, int linesize,
const unsigned char* data, int begy, int begx,
int leny, int lenx);
int ncplane_blit_rgba(struct ncplane* nc, int placey, int placex, int linesize,
ncblitter_e blitter, const unsigned char* data,
int begy, int begx, int leny, int lenx);
```

View File

@ -128,9 +128,9 @@ notcurses_plane - operations on ncplanes
**void ncplane_greyscale(struct ncplane* n);**
**int ncblit_bgrx(struct ncplane* nc, int placey, int placex, int linesize, const unsigned char* data, int begy, int begx, int leny, int lenx);**
**int ncplane_blit_bgrx(struct ncplane* nc, int placey, int placex, int linesize, ncblitter_e blitter, const unsigned char* data, int begy, int begx, int leny, int lenx);**
**int ncblit_rgba(struct ncplane* nc, int placey, int placex, int linesize, const unsigned char* data, int begy, int begx, int leny, int lenx);**
**int ncplane_blit_rgba(struct ncplane* nc, int placey, int placex, int linesize, ncblitter_e blitter, const unsigned char* data, int begy, int begx, int leny, int lenx);**
**int ncplane_destroy(struct ncplane* ncp);**

View File

@ -1017,13 +1017,13 @@ namespace ncpp
bool blit_bgrx (int placey, int placex, int linesize, const void* data, int begy, int begx, int leny, int lenx) const NOEXCEPT_MAYBE
{
bool ret = ncblit_bgrx (plane, placey, placex, linesize, data, begy, begx, leny, lenx) < 0;
bool ret = ncplane_blit_bgrx (plane, placey, placex, linesize, NCBLIT_DEFAULT, data, begy, begx, leny, lenx) < 0;
return error_guard_cond<bool, bool> (ret, ret);
}
bool blit_rgba (int placey, int placex, int linesize, const void* data, int begy, int begx, int leny, int lenx) const NOEXCEPT_MAYBE
{
bool ret = ncblit_rgba (plane, placey, placex, linesize, data, begy, begx, leny, lenx) < 0;
bool ret = ncplane_blit_rgba (plane, placey, placex, linesize, NCBLIT_DEFAULT, data, begy, begx, leny, lenx) < 0;
return error_guard_cond<bool, bool> (ret, ret);
}

View File

@ -2236,15 +2236,17 @@ API int ncvisual_stream(struct notcurses* nc, struct ncvisual* ncv,
// from the upper left by 'placey' and 'placex'. Each row ought occupy
// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A
// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'.
API int ncblit_bgrx(struct ncplane* nc, int placey, int placex, int linesize,
const void* data, int begy, int begx, int leny, int lenx);
API int ncplane_blit_bgrx(struct ncplane* nc, int placey, int placex,
int linesize, ncblitter_e blitter, const void* data,
int begy, int begx, int leny, int lenx);
// Blit a flat array 'data' of RGBA 32-bit values to the ncplane 'nc', offset
// from the upper left by 'placey' and 'placex'. Each row ought occupy
// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A
// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'.
API int ncblit_rgba(struct ncplane* nc, int placey, int placex, int linesize,
const void* data, int begy, int begx, int leny, int lenx);
API int ncplane_blit_rgba(struct ncplane* nc, int placey, int placex,
int linesize, ncblitter_e blitter, const void* data,
int begy, int begx, int leny, int lenx);
// An ncreel is a notcurses region devoted to displaying zero or more
// line-oriented, contained panels between which the user may navigate. If at

View File

@ -323,8 +323,8 @@ struct ncvisual_options {
ncblitter_e blitter;
uint64_t flags;
};
int ncblit_bgrx(struct ncplane* nc, int placey, int placex, int linesize, const unsigned char* data, int begy, int begx, int leny, int lenx);
int ncblit_rgba(struct ncplane* nc, int placey, int placex, int linesize, const unsigned char* data, int begy, int begx, int leny, int lenx);
int ncplane_blit_bgrx(struct ncplane* nc, int placey, int placex, int linesize, ncblitter_e blitter, const unsigned char* data, int begy, int begx, int leny, int lenx);
int ncplane_blit_rgba(struct ncplane* nc, int placey, int placex, int linesize, ncblitter_e blitter, const unsigned char* data, int begy, int begx, int leny, int lenx);
struct ncselector_item {
char* option;
char* desc;

View File

@ -53,21 +53,27 @@ rotate_visual(struct notcurses* nc, struct ncplane* n, int dy, int dx){
ncvisual_destroy(ncv);
return -1;
}
ncplane_erase(n);
ncplane_destroy(n);
int dimy, dimx;
n = notcurses_stddim_yx(nc, &dimy, &dimx);
bool failed = false;
const int ROTATIONS = 128;
timespec_div(&demodelay, ROTATIONS, &scaled);
timespec_div(&demodelay, ROTATIONS / 8, &scaled);
struct ncvisual_options vopts = {
.n = n,
};
ncplane_erase(n);
for(double i = 0 ; i < ROTATIONS ; ++i){
demo_nanosleep(nc, &scaled);
if(ncvisual_rotate(ncv, M_PI / 16)){
if(ncvisual_rotate(ncv, M_PI / 2)){
failed = true;
break;
}
ncplane_cursor_move_yx(n, 0, 0);
if(ncvisual_render(nc, ncv, &vopts) == NULL){
int vy, vx, vyscale, vxscale;
ncvisual_geom(nc, ncv, NCBLIT_DEFAULT, &vy, &vx, &vyscale, &vxscale);
vopts.x = (dimx - (vx / vxscale)) / 2;
vopts.y = (dimy - (vy / vyscale)) / 2;
struct ncplane* newn;
if((newn = ncvisual_render(nc, ncv, &vopts)) == NULL){
failed = true;
break;
}
@ -75,6 +81,7 @@ rotate_visual(struct notcurses* nc, struct ncplane* n, int dy, int dx){
failed = true;
break;
}
ncplane_destroy(newn);
}
ncvisual_destroy(ncv);
return failed ? -1 : 0;
@ -117,7 +124,7 @@ int normal_demo(struct notcurses* nc){
int r = -1;
struct ncplane* nstd = notcurses_stddim_yx(nc, &dy, &dx);
ncplane_erase(nstd);
cell c = CELL_SIMPLE_INITIALIZER(' ');
cell c = CELL_TRIVIAL_INITIALIZER;
cell_set_fg_rgb(&c, 0xff, 0xff, 0xff);
cell_set_bg_rgb(&c, 0xff, 0xff, 0xff);
ncplane_set_base_cell(nstd, &c);
@ -151,7 +158,7 @@ int normal_demo(struct notcurses* nc){
goto err;
}
}
if(ncblit_rgba(nstd, 0, 0, dx * sizeof(*rgba), rgba, 0, 0, dy, dx) < 0){
if(ncplane_blit_rgba(nstd, 0, 0, dx * sizeof(*rgba), NCBLIT_DEFAULT, rgba, 0, 0, dy, dx) < 0){
goto err;
}
if( (r = demo_render(nc)) ){
@ -191,7 +198,6 @@ int normal_demo(struct notcurses* nc){
ncplane_set_base_cell(nstd, &c);
cell_release(nstd, &c);
bool failed = rotate_visual(nc, n, dy, dx);
ncplane_destroy(n);
return failed ? -1 : 0;
err:

View File

@ -447,25 +447,25 @@ const struct blitset notcurses_blitters[] = {
// from the upper left by 'placey' and 'placex'. Each row ought occupy
// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A
// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'.
int ncblit_bgrx(ncplane* nc, int placey, int placex,
int linesize, const void* data, int begy, int begx, int leny,
int lenx){
if(!nc->nc->utf8){
return tria_blit_ascii(nc, placey, placex, linesize, data, begy, begx,
leny, lenx, true, false);
int ncplane_blit_bgrx(ncplane* nc, int placey, int placex, int linesize,
ncblitter_e blitter, const void* data,
int begy, int begx, int leny, int lenx){
const struct blitset* bset = lookup_blitset(ncplane_notcurses(nc), blitter, true);
if(bset == NULL){
return -1;
}
return tria_blit(nc, placey, placex, linesize, data, begy, begx,
return bset->blit(nc, placey, placex, linesize, data, begy, begx,
leny, lenx, true, false);
}
int ncblit_rgba(ncplane* nc, int placey, int placex,
int linesize, const void* data, int begy, int begx, int leny,
int lenx){
if(!nc->nc->utf8){
return tria_blit_ascii(nc, placey, placex, linesize, data, begy, begx,
leny, lenx, false, false);
int ncplane_blit_rgba(ncplane* nc, int placey, int placex, int linesize,
ncblitter_e blitter, const void* data,
int begy, int begx, int leny, int lenx){
const struct blitset* bset = lookup_blitset(ncplane_notcurses(nc), blitter, true);
if(bset == NULL){
return -1;
}
return tria_blit(nc, placey, placex, linesize, data, begy, begx,
return bset->blit(nc, placey, placex, linesize, data, begy, begx,
leny, lenx, false, false);
}

View File

@ -5,6 +5,10 @@
static inline const struct blitset*
lookup_blitset(const struct notcurses* nc, ncblitter_e setid, bool may_degrade) {
if(setid == NCBLIT_DEFAULT){
setid = NCBLIT_2x1;
may_degrade = true;
}
// the only viable blitter in ASCII is NCBLIT_1x1
if(!notcurses_canutf8(nc) && setid != NCBLIT_1x1){
if(may_degrade){

View File

@ -170,14 +170,15 @@ nc_err_e ncvisual_decode(ncvisual* nc){
// resize frame to oframe, converting to RGBA (if necessary) along the way
nc_err_e ncvisual_resize(ncvisual* nc, int rows, int cols) {
if(nc->details.oframe){
const int targformat = AV_PIX_FMT_RGBA;
AVFrame* inf = nc->details.oframe ? nc->details.oframe : nc->details.frame;
//fprintf(stderr, "got format: %d (%d/%d) want format: %d (%d/%d)\n", inf->format, nc->rows, nc->cols, targformat, rows, cols);
if(inf->format == targformat && nc->rows == rows && nc->cols == cols){
return NCERR_SUCCESS;
}
const int targformat = AV_PIX_FMT_RGBA;
//fprintf(stderr, "got format: %d want format: %d\n", nc->details.frame->format, targformat);
auto swsctx = sws_getContext(nc->details.frame->width,
nc->details.frame->height,
static_cast<AVPixelFormat>(nc->details.frame->format),
auto swsctx = sws_getContext(inf->width,
inf->height,
static_cast<AVPixelFormat>(inf->format),
cols, rows,
static_cast<AVPixelFormat>(targformat),
SWS_LANCZOS, nullptr, nullptr, nullptr);
@ -185,42 +186,56 @@ nc_err_e ncvisual_resize(ncvisual* nc, int rows, int cols) {
//fprintf(stderr, "Error retrieving swsctx\n");
return NCERR_NOMEM;
}
if((nc->details.oframe = av_frame_alloc()) == nullptr){
AVFrame* sframe;
if((sframe = av_frame_alloc()) == nullptr){
// fprintf(stderr, "Couldn't allocate frame for %s\n", filename);
sws_freeContext(swsctx);
return NCERR_NOMEM; // no need to free swsctx
}
memcpy(nc->details.oframe, nc->details.frame, sizeof(*nc->details.oframe));
nc->details.oframe->format = targformat;
nc->details.oframe->width = cols;
nc->details.oframe->height = rows;
//fprintf(stderr, "SIZE DECODED: %d %d (%d) (want %d %d)\n", nc->rows, nc->cols, nc->details.frame->linesize[0], rows, cols);
int size = av_image_alloc(nc->details.oframe->data, nc->details.oframe->linesize,
nc->details.oframe->width, nc->details.oframe->height,
static_cast<AVPixelFormat>(nc->details.oframe->format),
memcpy(sframe, inf, sizeof(*sframe));
sframe->format = targformat;
sframe->width = cols;
sframe->height = rows;
//fprintf(stderr, "SIZE DECODED: %d %d (%d) (want %d %d)\n", nc->rows, nc->cols, inf->linesize[0], rows, cols);
int size = av_image_alloc(sframe->data, sframe->linesize,
sframe->width, sframe->height,
static_cast<AVPixelFormat>(sframe->format),
IMGALLOCALIGN);
if(size < 0){
//fprintf(stderr, "Error allocating visual data (%d)\n", size);
av_freep(&sframe);
sws_freeContext(swsctx);
return NCERR_NOMEM;
}
int height = sws_scale(swsctx, nc->details.frame->data,
nc->details.frame->linesize, 0,
nc->details.frame->height, nc->details.oframe->data,
nc->details.oframe->linesize);
int height = sws_scale(swsctx, inf->data,
inf->linesize, 0,
inf->height, sframe->data,
sframe->linesize);
sws_freeContext(swsctx);
if(height < 0){
//fprintf(stderr, "Error applying scaling (%s)\n", av_err2str(height));
av_freep(sframe->data);
av_freep(&sframe);
return NCERR_DECODE;
}
const AVFrame* f = nc->details.oframe;
const AVFrame* f = sframe;
int bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(static_cast<AVPixelFormat>(f->format)));
if(bpp != 32){
//fprintf(stderr, "Bad bits-per-pixel (wanted 32, got %d)\n", bpp);
av_freep(sframe->data);
av_freep(&sframe);
return NCERR_DECODE;
}
nc->rowstride = nc->details.oframe->linesize[0];
nc->rowstride = sframe->linesize[0];
nc->rows = rows;
nc->cols = cols;
ncvisual_set_data(nc, reinterpret_cast<uint32_t*>(nc->details.oframe->data[0]), true);
ncvisual_set_data(nc, reinterpret_cast<uint32_t*>(sframe->data[0]), true);
if(nc->details.oframe){
//av_freep(nc->details.oframe->data);
av_freep(&nc->details.oframe);
}
nc->details.oframe = sframe;
//fprintf(stderr, "SIZE SCALED: %d %d (%u)\n", nc->details.oframe->height, nc->details.oframe->width, nc->details.oframe->linesize[0]);
return NCERR_SUCCESS;
}
@ -396,6 +411,7 @@ nc_err_e ncvisual_blit(ncvisual* ncv, int rows, int cols, ncplane* n,
int begy, int begx, int leny, int lenx,
bool blendcolors) {
const AVFrame* inframe = ncv->details.oframe ? ncv->details.oframe : ncv->details.frame;
//fprintf(stderr, "inframe: %p oframe: %p frame: %p\n", inframe, ncv->details.oframe, ncv->details.frame);
void* data = nullptr;
int stride = 0;
AVFrame* sframe = nullptr;

View File

@ -100,6 +100,7 @@ nc_err_e ncvisual_resize(ncvisual* nc, int rows, int cols) {
nc->rowstride = cols * 4;
ncvisual_set_data(nc, static_cast<uint32_t*>(ibuf->localpixels()), false);
//fprintf(stderr, "HAVE SOME NEW DATA: %p\n", ibuf->localpixels());
nc->details.ibuf = std::move(ibuf);
}
return NCERR_SUCCESS;
}

View File

@ -272,6 +272,7 @@ rotate_bounding_box(double stheta, double ctheta, int* leny, int* lenx,
}
auto ncvisual_rotate(ncvisual* ncv, double rads) -> nc_err_e {
// done to force conversion into RGBA
nc_err_e err = ncvisual_resize(ncv, ncv->rows, ncv->cols);
if(err != NCERR_SUCCESS){
return err;
@ -329,7 +330,7 @@ auto ncvisual_rotate(ncvisual* ncv, double rads) -> nc_err_e {
ncv->cols = bbx;
ncv->rows = bby;
ncv->rowstride = bbx * 4;
//ncplane_erase(ncv->ncp);
ncvisual_details_seed(ncv);
return NCERR_SUCCESS;
}
@ -343,8 +344,8 @@ auto ncvisual_from_rgba(const void* rgba, int rows, int rowstride,
ncv->rowstride = rowstride;
ncv->cols = cols;
ncv->rows = rows;
//fprintf(stderr, "MADE INITIAL ONE %d/%d\n", disprows, ncv->cols);
auto data = static_cast<uint32_t*>(memdup(rgba, rowstride * ncv->rows));
//fprintf(stderr, "COPY US %zu (%d)\n", rowstride * ncv->rows, ncv->rows);
if(data == nullptr){
ncvisual_destroy(ncv);
return nullptr;
@ -390,7 +391,7 @@ auto ncvisual_render(notcurses* nc, ncvisual* ncv,
if(begy < 0 || begx < 0 || lenx < -1 || leny < -1){
return nullptr;
}
//fprintf(stderr, "OUR DATA: %p cols/rows: %d/%d\n", ncv->data, ncv->cols, ncv->rows);
//fprintf(stderr, "OUR DATA: %p rows/cols: %d/%d\n", ncv->data, ncv->rows, ncv->cols);
if(ncv->data == nullptr){
return nullptr;
}
@ -442,6 +443,7 @@ auto ncvisual_render(notcurses* nc, ncvisual* ncv,
}else{
return nullptr;
}
//fprintf(stderr, "PLACING NEW PLANE: %d/%d @ %d/%d\n", disprows, dispcols, placey, placex);
n = ncplane_new(nc, disprows, dispcols, placey, placex, nullptr);
if(n == nullptr){
return nullptr;
@ -483,9 +485,9 @@ auto ncvisual_from_plane(const ncplane* n, int begy, int begx,
lenx = n->lenx - begx;
}
if(leny == -1){
leny = n->leny - begy;
leny = (n->leny - begy);
}
auto* ncv = ncvisual_from_rgba(rgba, leny, lenx * 4, lenx);
auto* ncv = ncvisual_from_rgba(rgba, leny * 2, lenx * 4, lenx);
free(rgba);
if(ncv == nullptr){
return nullptr;

231
src/poc/rotator.c Normal file
View File

@ -0,0 +1,231 @@
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
#include <locale.h>
#include <notcurses/notcurses.h>
static int
rotate_grad(struct notcurses* nc){
struct timespec ts = {
.tv_sec = 0,
.tv_nsec = 750000000,
};
int dimy, dimx;
struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
ncplane_cursor_move_yx(n, 0, 0);
uint64_t tl = 0, tr = 0, bl = 0, br = 0;
channels_set_fg_rgb(&tl, 0xff, 0, 0);
channels_set_fg_rgb(&tr, 0, 0, 0xff);
channels_set_fg_rgb(&bl, 0, 0xff, 0);
channels_set_fg_rgb(&br, 0, 0xff, 0xff);
channels_set_bg_rgb(&tl, 0xff, 0, 0);
channels_set_bg_rgb(&tr, 0, 0xff, 0);
channels_set_bg_rgb(&bl, 0, 0, 0xff);
channels_set_bg_rgb(&br, 0, 0xff, 0xff);
if(ncplane_highgradient(n, tl, tr, bl, br, dimy - 1, dimx - 1) <= 0){
return -1;
}
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
uint32_t* rgba = ncplane_rgba(n, 0, 0, dimy, dimx);
if(rgba == NULL){
return -1;
}
ncplane_erase(n);
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
if(ncplane_blit_rgba(n, 0, 0, dimx * 4, NCBLIT_DEFAULT,
rgba, 0, 0, dimy * 2, dimx) < 0){
free(rgba);
return -1;
}
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
ncplane_erase(n);
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
// now promote it to a visual
struct ncvisual* v = ncvisual_from_rgba(rgba, dimy * 2, dimx * 4, dimx);
free(rgba);
if(v == NULL){
return -1;
}
struct ncvisual_options vopts = {
.n = n,
};
if(n != ncvisual_render(nc, v, &vopts)){
ncvisual_destroy(v);
return -1;
}
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
vopts.n = NULL;
ncplane_erase(n);
for(int i = 0 ; i < 4 ; ++i){
int vy, vx, scaley, scalex;
if(NCERR_SUCCESS != ncvisual_rotate(v, M_PI / 2)){
return -1;
}
ncvisual_geom(nc, v, NCBLIT_DEFAULT, &vy, &vx, &scaley, &scalex);
vopts.x = (dimx - (vx / scalex)) / 2;
vopts.y = (dimy - (vy / scaley)) / 2;
struct ncplane* newn = ncvisual_render(nc, v, &vopts);
if(newn == NULL){
return -1;
}
notcurses_render(nc);
ncplane_destroy(newn);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
}
for(int i = 0 ; i < 8 ; ++i){
int vy, vx, scaley, scalex;
ncvisual_geom(nc, v, NCBLIT_DEFAULT, &vy, &vx, &scaley, &scalex);
vopts.x = (dimx - (vx / scalex)) / 2;
vopts.y = (dimy - (vy / scaley)) / 2;
if(NCERR_SUCCESS != ncvisual_rotate(v, M_PI / 4)){
return -1;
}
ncplane_erase(n);
struct ncplane* newn = ncvisual_render(nc, v, &vopts);
if(newn == NULL){
return -1;
}
notcurses_render(nc);
ncplane_destroy(newn);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
}
ncvisual_destroy(v);
return 0;
}
static int
rotate(struct notcurses* nc){
struct timespec ts = {
.tv_sec = 0,
.tv_nsec = 250000000,
};
const int XSIZE = 16;
int dimy, dimx;
struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx);
if(dimy < XSIZE || dimx < 2){
return -1;
}
int r = 255;
int g = 0;
int b = 0;
for(int x = 0 ; x < XSIZE ; ++x){
if(ncplane_set_fg_rgb(n, r, g, b)){
return -1;
}
if(ncplane_set_bg_rgb(n, b, r, g)){
return -1;
}
if(ncplane_putegc_yx(n, dimy / 2, x, "", NULL) < 0){
return -1;
}
g += 15;
r -= 14;
}
g = 0;
b = 255;
for(int x = 0 ; x < XSIZE ; ++x){
if(ncplane_set_fg_rgb(n, r, g, b)){
return -1;
}
if(ncplane_set_bg_rgb(n, b, r, g)){
return -1;
}
if(ncplane_putegc_yx(n, dimy / 2 + 1, x, "", NULL) < 0){
return -1;
}
g += 14;
b -= 15;
}
notcurses_render(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);
if(rgba == NULL){
return -1;
}
/*
for(int y = 0 ; y < 4 ; ++y){
for(int x = 0 ; x < XSIZE ; ++x){
fprintf(stderr, "rgba %02d/%02d: %08x\n", y, x, rgba[y * XSIZE + x]);
}
}
*/
ncplane_erase(n);
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
if(ncplane_blit_rgba(n, dimy / 2, XSIZE, XSIZE * 4, NCBLIT_DEFAULT,
rgba, 0, 0, 4, XSIZE) < 0){
free(rgba);
return -1;
}
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
ncplane_erase(n);
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
// now promote it to a visual
struct ncvisual* v = ncvisual_from_rgba(rgba, 4, XSIZE * 4, XSIZE);
free(rgba);
if(v == NULL){
return -1;
}
struct ncvisual_options vopts = {
.x = (dimx - XSIZE) / 2,
.y = dimy / 2,
.n = n,
};
ncvisual_render(nc, v, &vopts);
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
for(int i = 0 ; i < 4 ; ++i){
if(NCERR_SUCCESS != ncvisual_rotate(v, M_PI / 2)){
return -1;
}
ncplane_erase(n);
ncvisual_render(nc, v, &vopts);
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
}
for(int i = 0 ; i < 8 ; ++i){
if(NCERR_SUCCESS != ncvisual_rotate(v, M_PI / 4)){
return -1;
}
ncplane_erase(n);
ncvisual_render(nc, v, &vopts);
notcurses_render(nc);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);;
}
ncvisual_destroy(v);
return 0;
}
int main(void){
setlocale(LC_ALL, "");
struct notcurses_options nopts = {
.inhibit_alternate_screen = true,
.flags = NCOPTION_INHIBIT_SETLOCALE,
};
struct notcurses* nc = notcurses_init(&nopts, NULL);
int r = 0;
r |= rotate(nc);
r |= rotate_grad(nc);
r |= notcurses_stop(nc);
return r ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@ -7,6 +7,10 @@
#include <notcurses/notcurses.h>
int main(int argc, char** argv){
struct timespec ts = {
.tv_sec = 0,
.tv_nsec = 250000000,
};
const char* file = "../data/changes.jpg";
setlocale(LC_ALL, "");
if(argc > 2){
@ -17,6 +21,7 @@ int main(int argc, char** argv){
}
notcurses_options opts{};
opts.inhibit_alternate_screen = true;
opts.loglevel = NCLOGLEVEL_TRACE;
opts.flags = NCOPTION_INHIBIT_SETLOCALE;
struct notcurses* nc;
if((nc = notcurses_init(&opts, nullptr)) == nullptr){
@ -43,7 +48,9 @@ int main(int argc, char** argv){
if(notcurses_render(nc)){
goto err;
}
sleep(1);
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
ncplane_erase(n);
ncvisual_geom(nc, ncv, NCBLIT_DEFAULT, nullptr, nullptr, &scaley, &scalex);
ncvisual_resize(ncv, dimy * scaley, dimx * scalex);
vopts.n = n;
@ -53,21 +60,31 @@ int main(int argc, char** argv){
if(notcurses_render(nc)){
goto err;
}
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
vopts.n = NULL;
ncplane_destroy(n);
for(double i = 0 ; i < 256 ; ++i){
sleep(1);
if(ncvisual_rotate(ncv, M_PI / 2)){
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
if(ncvisual_rotate(ncv, M_PI / ((i / 32) + 2))){
failed = true;
break;
}
ncplane_erase(n);
if(ncvisual_render(nc, ncv, &vopts) == nullptr){
int vy, vx;
ncvisual_geom(nc, ncv, NCBLIT_DEFAULT, &vy, &vx, &scaley, &scalex);
vopts.x = (dimx - (vx / scalex)) / 2;
vopts.y = (dimy - (vy / scaley)) / 2;
struct ncplane* newn;
if((newn = ncvisual_render(nc, ncv, &vopts)) == nullptr){
failed = true;
break;
}
if(notcurses_render(nc)){
ncplane_destroy(newn);
failed = true;
break;
}
ncplane_destroy(newn);
}
ncvisual_destroy(ncv);
return notcurses_stop(nc) || failed ? EXIT_FAILURE : EXIT_SUCCESS;