diff --git a/src/lib/render.c b/src/lib/render.c index ed614bc94..ffbd4fa9f 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -931,10 +931,6 @@ int sprite_kitty_annihilate(notcurses* nc, const ncpile* p, FILE* out, sprixel* return 0; } -int sprite_sixel_cell_wipe(notcurses* nc, sprixel* s, int y, int x){ - return 0; // FIXME -} - int sprite_sixel_annihilate(notcurses* nc, const ncpile* p, FILE* out, sprixel* s){ (void)out; struct crender* rvec = p->crender; diff --git a/src/lib/sixel.c b/src/lib/sixel.c index b3edfbbaa..b5253b9bc 100644 --- a/src/lib/sixel.c +++ b/src/lib/sixel.c @@ -1,5 +1,52 @@ #include "internal.h" +// sixel is in a sense simpler to edit in-place than kitty, as it has neither +// chunking nor base64 to worry about. in another sense, it's waaay suckier, +// because you effectively have to lex through a byte at a time (since the +// color bands have varying size). le sigh! we work geometrically here, +// blasting through each band and scrubbing the necessary cells therein. +// define a rectangle that will be scrubbed. +int sprite_sixel_cell_wipe(notcurses* nc, sprixel* s, int ycell, int xcell){ + if(ycell >= s->dimy){ + return -1; + } + if(xcell >= s->dimx){ + return -1; + } + const int xpixels = nc->tcache.cellpixx; + const int ypixels = nc->tcache.cellpixy; + const int top = ypixels * ycell; // start scrubbing on this row + int bottom = ypixels * (ycell + 1); // do *not* scrub this row + const int left = xpixels * xcell; // start scrubbing on this column + int right = xpixels * (xcell + 1); // do *not* scrub this column + // if the cell is on the right or bottom borders, it might only be partially + // filled by actual graphic data, and we need to cap our target area. + if(right > s->pixx){ + right = s->pixx; + } + if(bottom > s->pixy){ + bottom = s->pixy; + } +fprintf(stderr, "TARGET AREA: [ %dx%d -> %dx%d ] of %dx%d\n", top, left, bottom - 1, right - 1, s->pixy, s->pixx); + char* c = s->glyph; + // lines of sixels are broken by a hyphen. if we were guaranteed to already + // be in the meat of the sixel, it would be sufficient to count hyphens, but + // we must distinguish the introductory material from the sixmap, alas + // (after that, simply count hyphens). FIXME store loc in sprixel metadata? + // it seems sufficient to look for the first #d not followed by a semicolon. + // remember, these are sixels *we've* created internally, not random ones. + do{ + while(*c != '#'){ + ++c; + } + while(isdigit(*c)){ + ++c; + } + }while(*c == ';'); +fprintf(stderr, "FOUND SIXMAP AT %zd\n", c - s->glyph); + return 0; // FIXME +} + #define RGBSIZE 3 #define CENTSIZE (RGBSIZE + 1) // size of a color table entry diff --git a/src/media/ffmpeg.cpp b/src/media/ffmpeg.cpp index a3b4a44c4..fb2cb6411 100644 --- a/src/media/ffmpeg.cpp +++ b/src/media/ffmpeg.cpp @@ -269,27 +269,21 @@ int ffmpeg_resize(ncvisual* nc, int rows, int cols) { } auto ffmpeg_details_init(void) -> ncvisual_details* { - auto deets = static_cast(malloc(sizeof(ncvisual_details))); - if(deets){ - memset(deets, 0, sizeof(*deets)); - deets->stream_index = -1; - deets->sub_stream_index = -1; - if((deets->frame = av_frame_alloc()) == nullptr){ - free(deets); - return nullptr; - } + auto deets = new ncvisual_details{}; + deets->stream_index = -1; + deets->sub_stream_index = -1; + if((deets->frame = av_frame_alloc()) == nullptr){ + delete deets; + return nullptr; } return deets; } auto ffmpeg_create() -> ncvisual* { - auto nc = static_cast(malloc(sizeof(ncvisual))); - if(nc){ - memset(nc, 0, sizeof(*nc)); - if((nc->details = ffmpeg_details_init()) == nullptr){ - free(nc); - return nullptr; - } + auto nc = new ncvisual{}; + if((nc->details = ffmpeg_details_init()) == nullptr){ + delete nc; + return nullptr; } return nc; } @@ -595,14 +589,14 @@ auto ffmpeg_details_destroy(ncvisual_details* deets) -> void { av_packet_free(&deets->packet); avformat_close_input(&deets->fmtctx); avsubtitle_free(&deets->subtitle); - free(deets); + delete deets; } auto ffmpeg_destroy(ncvisual* ncv) -> void { if(ncv){ ffmpeg_details_destroy(ncv->details); if(ncv->owndata){ - delete ncv->data; + free(ncv->data); } delete ncv; } diff --git a/src/media/oiio.cpp b/src/media/oiio.cpp index 628d72e71..72347d895 100644 --- a/src/media/oiio.cpp +++ b/src/media/oiio.cpp @@ -191,7 +191,7 @@ auto oiio_destroy(ncvisual* ncv) -> void { if(ncv){ oiio_details_destroy(ncv->details); if(ncv->owndata){ - delete ncv->data; + free(ncv->data); } delete ncv; } diff --git a/src/tests/pixel.cpp b/src/tests/pixel.cpp index 692d535a1..a42c777f8 100644 --- a/src/tests/pixel.cpp +++ b/src/tests/pixel.cpp @@ -71,5 +71,41 @@ TEST_CASE("Pixel") { CHECK(0 == notcurses_render(nc_)); } + SUBCASE("PixelCellWipePolychromatic") { + // first, assemble a visual equivalent to 4 cells + auto y = 2 * nc_->tcache.cellpixy; + auto x = 2 * nc_->tcache.cellpixx; + std::vector v(x * y, 0xffffffff); + for(auto& e : v){ + e -= random() % 0x1000000; + } + auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x); + REQUIRE(nullptr != ncv); + struct ncvisual_options vopts = { + .n = nullptr, + .scaling = NCSCALE_NONE, + .y = 0, .x = 0, + .begy = 0, .begx = 0, + .leny = y, .lenx = x, + .blitter = NCBLIT_PIXEL, + .flags = NCVISUAL_OPTION_NODEGRADE, + }; + auto n = ncvisual_render(nc_, ncv, &vopts); + REQUIRE(nullptr != n); + auto s = n->sprite; + REQUIRE(nullptr != s); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 0, 0)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 1, 1)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 1, 0)); + CHECK(0 == notcurses_render(nc_)); + CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 0, 1)); + CHECK(0 == notcurses_render(nc_)); + ncplane_destroy(n); + ncvisual_destroy(ncv); + CHECK(0 == notcurses_render(nc_)); + } CHECK(!notcurses_stop(nc_)); }