render piles to file/buffer

Replace notcurses_render_to_file() and
notcurses_render_to_buffer() with variants that work
on arbitrary piles (the former only worked on the standard
pile). Rewrite the former as trivial wrappers around the
latter, and deprecate the former. Closes #1770.
This commit is contained in:
nick black 2021-06-22 01:17:55 -04:00
parent 921c2ce033
commit 379453c8ea
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
7 changed files with 52 additions and 47 deletions

View File

@ -28,6 +28,10 @@ rearrangements of Notcurses.
They map to `NCLOGLEVEL_WARNING` and `NCLOGLEVEL_TRACE`, respectively.
* New functions `ncvisual_from_rgb_packed()` and `ncvisual_from_rgb_loose()`.
* New stat `sprixelbytes`.
* Added new functions `ncpile_render_to_buffer()` and
`ncpile_render_to_file()`. Rewrote `notcurses_render_to_buffer()` and
`notcurses_render_to_file()` as trivial wrappers around these functions,
and deprecated the latter. They will be removed in ABI3.
* 2.3.4 (2021-06-12)
* Added the flag `NCVISUAL_OPTION_NOINTERPOLATE` to use non-interpolative

View File

@ -191,14 +191,13 @@ int ncpile_rasterize(struct ncplane* n);
int notcurses_render(struct notcurses* nc);
// Perform the rendering and rasterization portion of notcurses_render(), but
// do not write the resulting buffer out to the terminal. Using this function,
// the user can control the writeout process, and render a second frame while
// writing another. The returned buffer must be freed by the caller.
int notcurses_render_to_buffer(struct notcurses* nc, char** buf, size_t* buflen);
// do not write the resulting buffer out to the terminal. The returned buffer
// must be freed by the caller.
int ncpile_render_to_buffer(struct ncplane* p, char** buf, size_t* buflen);
// Write the last rendered frame, in its entirety, to 'fp'. If
// notcurses_render() has not yet been called, nothing will be written.
int notcurses_render_to_file(struct notcurses* nc, FILE* fp);
int ncpile_render_to_file(struct ncplane* p, FILE* fp);
// Retrieve the contents of the specified cell as last rendered. The EGC is
// returned, or NULL on error. This EGC must be free()d by the caller. The

View File

@ -18,9 +18,9 @@ notcurses_render - sync the physical display to a virtual pile
**char* notcurses_at_yx(struct notcurses* ***nc***, int ***yoff***, int ***xoff***, uint16_t* ***styles***, uint64_t* ***channels***);**
**int notcurses_render_to_file(struct notcurses* ***nc***, FILE* ***fp***);**
**int ncpile_render_to_file(struct ncplane* ***p***, FILE* ***fp***);**
**int notcurses_render_to_buffer(struct notcurses* ***nc***, char\*\* ***buf***, size_t* ***buflen***);**
**int ncpile_render_to_buffer(struct ncplane* ***p***, char\*\* ***buf***, size_t* ***buflen***);**
# DESCRIPTION
@ -50,11 +50,11 @@ While **notcurses_render** is called, you **must not call any other functions
modifying the same pile**. Other piles may be freely accessed and modified.
The pile being rendered may be accessed, but not modified.
**notcurses_render_to_buffer** performs the render and raster processes of
**notcurses_render**, but does not write the resulting buffer to the
terminal. The user is responsible for writing the buffer to the terminal in
its entirety. If there is an error, subsequent frames will be out of sync,
and **notcurses_refresh(3)** must be called.
**ncpile_render_to_buffer** performs the render and raster processes of
**ncpile_render** and **ncpile_rasterize**, but does not write the resulting
buffer to the terminal. The user is responsible for writing the buffer to the
terminal in its entirety. If there is an error, subsequent frames will be out
of sync, and **notcurses_refresh(3)** must be called.
A render operation consists of two logical phases: generation of the rendered
scene, and blitting this scene to the terminal (these two phases might actually

View File

@ -66,7 +66,7 @@ also resets all cumulative stats (immediate stats such as **fbbytes** are not
reset).
**renders** is the number of successful calls to **notcurses_render(3)**
or **notcurses_render_to_buffer(3)**. **failed_renders** is the number of
or **ncpile_render_to_buffer(3)**. **failed_renders** is the number of
unsuccessful calls to these functions. **failed_renders** should be 0;
renders are not expected to fail except under exceptional circumstances.
should **notcurses_render(3)** fail while writing out a frame to the terminal,
@ -81,12 +81,12 @@ ingest and reflect a frame is dependent on the size of the rasterized frame.
**render_ns**, **render_max_ns**, and **render_min_ns** track the total
amount of time spent rendering frames in nanoseconds. Rendering
takes place in **ncpile_render** (called by **notcurses_render(3)** and
**notcurses_render_to_buffer**). This step is independent of the terminal.
**ncpile_render_to_buffer**). This step is independent of the terminal.
**raster_ns**, **raster_max_ns**, and **raster_min_ns** track the total
amount of time spent rasterizing frames in nanoseconds. Rasterizing
takes place in **ncpile_raster** (called by **notcurses_raster(3)** and
**notcurses_render_to_buffer**). This step depends on the terminal definitions.
**ncpile_render_to_buffer**). This step depends on the terminal definitions.
The same frame might not rasterize to the same bytes for different terminals.
**writeout_ns**, **writeout_max_ns**, and **writeout_min_ns** track the total

View File

@ -200,16 +200,6 @@ namespace ncpp
return error_guard (notcurses_render (nc), -1);
}
bool render_to_buffer (char** buf, size_t* buflen) const NOEXCEPT_MAYBE
{
return error_guard (notcurses_render_to_buffer (nc, buf, buflen), -1);
}
bool render_to_file (FILE* fp) const NOEXCEPT_MAYBE
{
return error_guard (notcurses_render_to_file (nc, fp), -1);
}
void get_term_dim (int *rows, int *cols) const noexcept
{
notcurses_term_dim_yx (nc, rows, cols);

View File

@ -941,15 +941,15 @@ API int ncpile_rasterize(struct ncplane* n);
// Renders and rasterizes the standard pile in one shot. Blocking call.
API int notcurses_render(struct notcurses* nc);
// Perform the rendering and rasterization portion of notcurses_render(), but
// do not write the resulting buffer out to the terminal. Using this function,
// the user can control the writeout process, and render a second frame while
// writing another. The returned buffer must be freed by the caller.
API int notcurses_render_to_buffer(struct notcurses* nc, char** buf, size_t* buflen);
// Perform the rendering and rasterization portion of ncpile_render() and
// ncpile_rasterize(), but do not write the resulting buffer out to the
// terminal. Using this function, the user can control the writeout process.
// The returned buffer must be freed by the caller.
API int ncpile_render_to_buffer(struct ncplane* p, char** buf, size_t* buflen);
// Write the last rendered frame, in its entirety, to 'fp'. If
// notcurses_render() has not yet been called, nothing will be written.
API int notcurses_render_to_file(struct notcurses* nc, FILE* fp);
API int ncpile_render_to_file(struct ncplane* p, FILE* fp);
// Return the topmost ncplane of the standard pile.
API struct ncplane* notcurses_top(struct notcurses* n);
@ -4349,6 +4349,12 @@ channels_set_bg_default(uint64_t* channels){
API __attribute__ ((deprecated)) int ncvisual_inflate(struct ncvisual* n, int scale)
__attribute__ ((nonnull (1)));
API int notcurses_render_to_buffer(struct notcurses* nc, char** buf, size_t* buflen)
__attribute__ ((deprecated));
API int notcurses_render_to_file(struct notcurses* nc, FILE* fp)
__attribute__ ((deprecated));
typedef nccell cell; // FIXME backwards-compat, remove in ABI3
#define CELL_ALPHA_HIGHCONTRAST NCALPHA_HIGHCONTRAST

View File

@ -1231,7 +1231,9 @@ int notcurses_refresh(notcurses* nc, int* restrict dimy, int* restrict dimx){
return 0;
}
int notcurses_render_to_file(notcurses* nc, FILE* fp){
int ncpile_render_to_file(ncplane* n, FILE* fp){
notcurses* nc = ncplane_notcurses(n);
ncpile* p = ncplane_pile(n);
if(nc->lfdimx == 0 || nc->lfdimy == 0){
return 0;
}
@ -1241,23 +1243,20 @@ int notcurses_render_to_file(notcurses* nc, FILE* fp){
if(out == NULL){
return -1;
}
ncpile p;
p.dimy = nc->margin_t;
p.dimx = nc->margin_l;
const int count = (nc->lfdimx > p.dimx ? nc->lfdimx : p.dimx) *
(nc->lfdimy > p.dimy ? nc->lfdimy : p.dimy);
p.crender = malloc(count * sizeof(*p.crender));
if(p.crender == NULL){
const int count = (nc->lfdimx > p->dimx ? nc->lfdimx : p->dimx) *
(nc->lfdimy > p->dimy ? nc->lfdimy : p->dimy);
p->crender = malloc(count * sizeof(*p->crender));
if(p->crender == NULL){
fclose(out);
free(rastered);
return -1;
}
init_rvec(p.crender, count);
init_rvec(p->crender, count);
for(int i = 0 ; i < count ; ++i){
p.crender[i].s.damaged = 1;
p->crender[i].s.damaged = 1;
}
int ret = raster_and_write(nc, &p, out);
free(p.crender);
int ret = raster_and_write(nc, p, out);
free(p->crender);
if(ret > 0){
if(fprintf(fp, "%s", rastered) == ret){
ret = 0;
@ -1270,6 +1269,9 @@ int notcurses_render_to_file(notcurses* nc, FILE* fp){
return ret;
}
int notcurses_render_to_file(notcurses* nc, FILE* fp){
return ncpile_render_to_file(notcurses_stdplane(nc), fp);
}
// We execute the painter's algorithm, starting from our topmost plane. The
// damagevector should be all zeros on input. On success, it will reflect
@ -1377,12 +1379,12 @@ int notcurses_render(notcurses* nc){
// for now, we just run the top half of notcurses_render(), and copy out the
// memstream from within rstate. we want to allocate our own here, and return
// it, to avoid the copy, but we need feed the params through to do so FIXME.
int notcurses_render_to_buffer(notcurses* nc, char** buf, size_t* buflen){
ncplane* stdn = notcurses_stdplane(nc);
if(ncpile_render(stdn)){
int ncpile_render_to_buffer(ncplane* p, char** buf, size_t* buflen){
if(ncpile_render(p)){
return -1;
}
int bytes = notcurses_rasterize_inner(nc, ncplane_pile(stdn), nc->rstate.mstreamfp);
notcurses* nc = ncplane_notcurses(p);
int bytes = notcurses_rasterize_inner(nc, ncplane_pile(p), nc->rstate.mstreamfp);
pthread_mutex_lock(&nc->statlock);
update_render_bytes(&nc->stats, bytes);
pthread_mutex_unlock(&nc->statlock);
@ -1397,6 +1399,10 @@ int notcurses_render_to_buffer(notcurses* nc, char** buf, size_t* buflen){
return 0;
}
int notcurses_render_to_buffer(notcurses* nc, char** buf, size_t* buflen){
return ncpile_render_to_buffer(notcurses_stdplane(nc), buf, buflen);
}
// copy the UTF8-encoded EGC out of the cell, whether simple or complex. the
// result is not tied to the ncplane, and persists across erases / destruction.
static inline char*