diff --git a/NEWS.md b/NEWS.md index fd7ec25b7..be59704ae 100644 --- a/NEWS.md +++ b/NEWS.md @@ -18,7 +18,8 @@ rearrangements of Notcurses. `ncplane_as_rgba()`, `ncplane_contents()`, and `ncvisual_from_plane()`, which all used -1. A length of zero passed to line-drawing functions is now an error. Several line-drawing functions now reliably return errors - as opposed to short successes. + as opposed to short successes. Dimensions of 0 to `ncplane_mergedown()` + now mean "everything". * `ncvisual_geom()` has been introduced, using the `ncvgeom` struct introduced for direct mode. This allows complete statement of geometry for an `ncvisual`. It replaces `ncvisual_blitter_geom()`, which has been diff --git a/USAGE.md b/USAGE.md index 19324847c..b60a813ba 100644 --- a/USAGE.md +++ b/USAGE.md @@ -918,12 +918,18 @@ struct ncplane* ncplane_dup(struct ncplane* n, void* opaque); // Merge the ncplane 'src' down onto the ncplane 'dst'. This is most rigorously // defined as "write to 'dst' the frame that would be rendered were the entire -// stack made up only of 'src' and, below it, 'dst', and 'dst' was the entire -// rendering region." Merging is independent of the position of 'src' viz 'dst' -// on the z-axis. If 'src' does not intersect with 'dst', 'dst' will not be -// changed, but it is not an error. The source plane still exists following -// this operation. Do not supply the same plane for both 'src' and 'dst'. -int ncplane_mergedown(struct ncplane* restrict src, struct ncplane* restrict dst); +// stack made up only of the specified subregion of 'src' and, below it, the +// subregion of 'dst' having the specified origin. Merging is independent of +// the position of 'src' viz 'dst' on the z-axis. It is an error to define a +// subregion that is not entirely contained within 'src'. It is an error to +// define a target origin such that the projected subregion is not entirely +// contained within 'dst'. Behavior is undefined if 'src' and 'dst' are +// equivalent. 'dst' is modified, but 'src' remains unchanged. Neither 'src' +// nor 'dst' may have sprixels. Lengths of 0 mean "everything left". +int ncplane_mergedown(struct ncplane* restrict src, struct ncplane* restrict dst, + unsigned begsrcy, unsigned begsrcx, + unsigned leny, unsigned lenx, + unsigned dsty, unsigned dstx); // Merge the entirety of 'src' down onto the ncplane 'dst'. If 'src' does not // intersect with 'dst', 'dst' will not be changed, but it is not an error. diff --git a/doc/man/man3/notcurses_plane.3.md b/doc/man/man3/notcurses_plane.3.md index bc72b18e2..6cdf71f7b 100644 --- a/doc/man/man3/notcurses_plane.3.md +++ b/doc/man/man3/notcurses_plane.3.md @@ -205,7 +205,7 @@ typedef struct ncplane_options { **void notcurses_drop_planes(struct notcurses* ***nc***);** -**int ncplane_mergedown(struct ncplane* ***src***, struct ncplane* ***dst***, int ***begsrcy***, int ***begsrcx***, int ***leny***, int ***lenx***, int ***dsty***, int ***dstx***);** +**int ncplane_mergedown(struct ncplane* ***src***, struct ncplane* ***dst***, unsigned ***begsrcy***, unsigned ***begsrcx***, unsigned ***leny***, unsigned ***lenx***, unsigned ***dsty***, unsigned ***dstx***);** **int ncplane_mergedown_simple(struct ncplane* restrict ***src***, struct ncplane* restrict ***dst***);** diff --git a/include/ncpp/Plane.hh b/include/ncpp/Plane.hh index a988e5c5c..80bd1f9aa 100644 --- a/include/ncpp/Plane.hh +++ b/include/ncpp/Plane.hh @@ -452,17 +452,17 @@ namespace ncpp return move_above (*above); } - bool mergedown (Plane &dst, int begsrcy, int begsrcx, int leny, int lenx, int dsty, int dstx) const + bool mergedown (Plane &dst, unsigned begsrcy, unsigned begsrcx, unsigned leny, unsigned lenx, unsigned dsty, unsigned dstx) const { return mergedown (&dst, begsrcy, begsrcx, leny, lenx, dsty, dstx); } - bool mergedown (Plane *dst, int begsrcy, int begsrcx, int leny, int lenx, int dsty, int dstx) const + bool mergedown (Plane *dst, unsigned begsrcy, unsigned begsrcx, unsigned leny, unsigned lenx, unsigned dsty, unsigned dstx) const { - if (dst != nullptr && plane == dst->plane) + if (plane == dst->plane) throw invalid_argument ("'dst' must refer to a different plane than the one this method is called on"); - return error_guard (ncplane_mergedown (plane, dst != nullptr ? dst->plane : nullptr, begsrcy, begsrcx, leny, lenx, dsty, dstx), -1); + return error_guard (ncplane_mergedown (plane, dst->plane, begsrcy, begsrcx, leny, lenx, dsty, dstx), -1); } bool mergedown_simple (Plane &dst) const @@ -472,7 +472,7 @@ namespace ncpp bool mergedown_simple (Plane *dst) const { - if (dst == nullptr || plane == dst->plane) + if (plane == dst->plane) throw invalid_argument ("'dst' must refer to a different plane than the one this method is called on"); return error_guard (ncplane_mergedown_simple (plane, dst->plane), -1); diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 1ab7417f5..18cec13c1 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2302,28 +2302,32 @@ API int ncplane_stain(struct ncplane* n, int ystop, int xstop, uint64_t ul, // Merge the entirety of 'src' down onto the ncplane 'dst'. If 'src' does not // intersect with 'dst', 'dst' will not be changed, but it is not an error. API int ncplane_mergedown_simple(struct ncplane* RESTRICT src, - struct ncplane* RESTRICT dst); + struct ncplane* RESTRICT dst) + __attribute__ ((nonnull (1, 2))); // Merge the ncplane 'src' down onto the ncplane 'dst'. This is most rigorously // defined as "write to 'dst' the frame that would be rendered were the entire // stack made up only of the specified subregion of 'src' and, below it, the // subregion of 'dst' having the specified origin. Merging is independent of // the position of 'src' viz 'dst' on the z-axis. It is an error to define a -// subregion of zero area, or that is not entirely contained within 'src'. It -// is an error to define a target origin such that the projected subregion is -// not entirely contained within 'dst'. Behavior is undefined if 'src' and -// 'dst' are equivalent. 'dst' is modified, but 'src' remains unchanged. -// neither 'src' nor 'dst' may have sprixels. +// subregion that is not entirely contained within 'src'. It is an error to +// define a target origin such that the projected subregion is not entirely +// contained within 'dst'. Behavior is undefined if 'src' and 'dst' are +// equivalent. 'dst' is modified, but 'src' remains unchanged. Neither 'src' +// nor 'dst' may have sprixels. Lengths of 0 mean "everything left". API int ncplane_mergedown(struct ncplane* RESTRICT src, struct ncplane* RESTRICT dst, - int begsrcy, int begsrcx, int leny, int lenx, - int dsty, int dstx); + unsigned begsrcy, unsigned begsrcx, + unsigned leny, unsigned lenx, + unsigned dsty, unsigned dstx) + __attribute__ ((nonnull (1, 2))); // Erase every cell in the ncplane (each cell is initialized to the null glyph // and the default channels/styles). All cells associated with this ncplane are // invalidated, and must not be used after the call, *excluding* the base cell. // The cursor is homed. The plane's active attributes are unaffected. -API void ncplane_erase(struct ncplane* n); +API void ncplane_erase(struct ncplane* n) + __attribute__ ((nonnull (1))); // Erase every cell in the region starting at {ystart, xstart} and having size // {|ylen|x|xlen|} for non-zero lengths. If ystart and/or xstart are -1, the current diff --git a/src/lib/render.c b/src/lib/render.c index 479b20eb1..1dfaab899 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -526,31 +526,44 @@ postpaint(const tinfo* ti, nccell* lastframe, int dimy, int dimx, // merging one plane down onto another is basically just performing a render // using only these two planes, with the result written to the lower plane. int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst, - int begsrcy, int begsrcx, int leny, int lenx, - int dsty, int dstx){ + unsigned begsrcy, unsigned begsrcx, + unsigned leny, unsigned lenx, + unsigned dsty, unsigned dstx){ //fprintf(stderr, "Merging down %d/%d @ %d/%d to %d/%d\n", leny, lenx, begsrcy, begsrcx, dsty, dstx); - if(dsty >= dst->leny || dstx >= dst->lenx){ - logerror("Dest origin %d/%d ≥ dest dimensions %d/%d\n", + if(dsty >= (unsigned)dst->leny || dstx >= (unsigned)dst->lenx){ + logerror("dest origin %u/%u ≥ dest dimensions %d/%d\n", dsty, dstx, dst->leny, dst->lenx); return -1; } if(dst->leny - leny < dsty || dst->lenx - lenx < dstx){ - logerror("Dest len %d/%d ≥ dest dimensions %d/%d\n", + logerror("dest len %u/%u ≥ dest dimensions %d/%d\n", leny, lenx, dst->leny, dst->lenx); return -1; } - if(begsrcy >= src->leny || begsrcx >= src->lenx){ - logerror("Source origin %d/%d ≥ source dimensions %d/%d\n", + if(begsrcy >= (unsigned)src->leny || begsrcx >= (unsigned)src->lenx){ + logerror("source origin %u/%u ≥ source dimensions %d/%d\n", begsrcy, begsrcx, src->leny, src->lenx); return -1; } + if(leny == 0){ + if((leny = src->leny - begsrcy) == 0){ + logerror("source area was zero height\n"); + return -1; + } + } + if(lenx == 0){ + if((lenx = src->lenx - begsrcx) == 0){ + logerror("source area was zero width\n"); + return -1; + } + } if(src->leny - leny < begsrcy || src->lenx - lenx < begsrcx){ - logerror("Source len %d/%d ≥ source dimensions %d/%d\n", + logerror("source len %u/%u ≥ source dimensions %d/%d\n", leny, lenx, src->leny, src->lenx); return -1; } if(src->sprite || dst->sprite){ - logerror("Can't merge sprixel planes\n"); + logerror("can't merge sprixel planes\n"); return -1; } const int totalcells = dst->leny * dst->lenx; @@ -558,7 +571,7 @@ int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst, const size_t crenderlen = sizeof(struct crender) * totalcells; struct crender* rvec = malloc(crenderlen); if(!rendfb || !rvec){ - logerror("Error allocating render state for %dx%d\n", leny, lenx); + logerror("error allocating render state for %ux%u\n", leny, lenx); free(rendfb); free(rvec); return -1; @@ -580,14 +593,7 @@ int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst, } int ncplane_mergedown_simple(ncplane* restrict src, ncplane* restrict dst){ - // have to check dst, since we used to accept a NULL dst to mean the - // standard plane (this was unsafe, since src might be in another pile). - if(dst == NULL){ - return -1; - } - int dimy, dimx; - ncplane_dim_yx(dst, &dimy, &dimx); - return ncplane_mergedown(src, dst, 0, 0, ncplane_dim_y(src), ncplane_dim_x(src), 0, 0); + return ncplane_mergedown(src, dst, 0, 0, 0, 0, 0, 0); } // write the nccell's UTF-8 extended grapheme cluster to the provided FILE*. diff --git a/src/tetris/background.h b/src/tetris/background.h index ec85179bf..650fd2bbd 100644 --- a/src/tetris/background.h +++ b/src/tetris/background.h @@ -18,7 +18,7 @@ void DrawBoard() { // draw all fixed components of the game stdplane_->get_dim(&y, &x); board_top_y_ = y - (BOARD_HEIGHT + 2); board_ = std::make_unique(BOARD_HEIGHT, BOARD_WIDTH * 2, - board_top_y_, x / 2 - (BOARD_WIDTH + 1)); + board_top_y_, x / 2 - (BOARD_WIDTH + 1)); uint64_t channels = 0; ncchannels_set_fg_rgb(&channels, 0x00b040); ncchannels_set_bg_alpha(&channels, NCALPHA_TRANSPARENT);