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. They map to `NCLOGLEVEL_WARNING` and `NCLOGLEVEL_TRACE`, respectively.
* New functions `ncvisual_from_rgb_packed()` and `ncvisual_from_rgb_loose()`. * New functions `ncvisual_from_rgb_packed()` and `ncvisual_from_rgb_loose()`.
* New stat `sprixelbytes`. * 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) * 2.3.4 (2021-06-12)
* Added the flag `NCVISUAL_OPTION_NOINTERPOLATE` to use non-interpolative * 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); int notcurses_render(struct notcurses* nc);
// Perform the rendering and rasterization portion of notcurses_render(), but // Perform the rendering and rasterization portion of notcurses_render(), but
// do not write the resulting buffer out to the terminal. Using this function, // do not write the resulting buffer out to the terminal. The returned buffer
// the user can control the writeout process, and render a second frame while // must be freed by the caller.
// writing another. The returned buffer must be freed by the caller. int ncpile_render_to_buffer(struct ncplane* p, char** buf, size_t* buflen);
int notcurses_render_to_buffer(struct notcurses* nc, char** buf, size_t* buflen);
// Write the last rendered frame, in its entirety, to 'fp'. If // Write the last rendered frame, in its entirety, to 'fp'. If
// notcurses_render() has not yet been called, nothing will be written. // 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 // 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 // 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***);** **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 # 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. modifying the same pile**. Other piles may be freely accessed and modified.
The pile being rendered may be accessed, but not modified. The pile being rendered may be accessed, but not modified.
**notcurses_render_to_buffer** performs the render and raster processes of **ncpile_render_to_buffer** performs the render and raster processes of
**notcurses_render**, but does not write the resulting buffer to the **ncpile_render** and **ncpile_rasterize**, but does not write the resulting
terminal. The user is responsible for writing the buffer to the terminal in buffer to the terminal. The user is responsible for writing the buffer to the
its entirety. If there is an error, subsequent frames will be out of sync, terminal in its entirety. If there is an error, subsequent frames will be out
and **notcurses_refresh(3)** must be called. of sync, and **notcurses_refresh(3)** must be called.
A render operation consists of two logical phases: generation of the rendered 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 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). reset).
**renders** is the number of successful calls to **notcurses_render(3)** **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; unsuccessful calls to these functions. **failed_renders** should be 0;
renders are not expected to fail except under exceptional circumstances. renders are not expected to fail except under exceptional circumstances.
should **notcurses_render(3)** fail while writing out a frame to the terminal, 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 **render_ns**, **render_max_ns**, and **render_min_ns** track the total
amount of time spent rendering frames in nanoseconds. Rendering amount of time spent rendering frames in nanoseconds. Rendering
takes place in **ncpile_render** (called by **notcurses_render(3)** and 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 **raster_ns**, **raster_max_ns**, and **raster_min_ns** track the total
amount of time spent rasterizing frames in nanoseconds. Rasterizing amount of time spent rasterizing frames in nanoseconds. Rasterizing
takes place in **ncpile_raster** (called by **notcurses_raster(3)** and 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. 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 **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); 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 void get_term_dim (int *rows, int *cols) const noexcept
{ {
notcurses_term_dim_yx (nc, rows, cols); 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. // Renders and rasterizes the standard pile in one shot. Blocking call.
API int notcurses_render(struct notcurses* nc); API int notcurses_render(struct notcurses* nc);
// Perform the rendering and rasterization portion of notcurses_render(), but // Perform the rendering and rasterization portion of ncpile_render() and
// do not write the resulting buffer out to the terminal. Using this function, // ncpile_rasterize(), but do not write the resulting buffer out to the
// the user can control the writeout process, and render a second frame while // terminal. Using this function, the user can control the writeout process.
// writing another. The returned buffer must be freed by the caller. // The returned buffer must be freed by the caller.
API int notcurses_render_to_buffer(struct notcurses* nc, char** buf, size_t* buflen); 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 // Write the last rendered frame, in its entirety, to 'fp'. If
// notcurses_render() has not yet been called, nothing will be written. // 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. // Return the topmost ncplane of the standard pile.
API struct ncplane* notcurses_top(struct notcurses* n); 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) API __attribute__ ((deprecated)) int ncvisual_inflate(struct ncvisual* n, int scale)
__attribute__ ((nonnull (1))); __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 typedef nccell cell; // FIXME backwards-compat, remove in ABI3
#define CELL_ALPHA_HIGHCONTRAST NCALPHA_HIGHCONTRAST #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; 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){ if(nc->lfdimx == 0 || nc->lfdimy == 0){
return 0; return 0;
} }
@ -1241,23 +1243,20 @@ int notcurses_render_to_file(notcurses* nc, FILE* fp){
if(out == NULL){ if(out == NULL){
return -1; return -1;
} }
ncpile p; const int count = (nc->lfdimx > p->dimx ? nc->lfdimx : p->dimx) *
p.dimy = nc->margin_t; (nc->lfdimy > p->dimy ? nc->lfdimy : p->dimy);
p.dimx = nc->margin_l; p->crender = malloc(count * sizeof(*p->crender));
const int count = (nc->lfdimx > p.dimx ? nc->lfdimx : p.dimx) * if(p->crender == NULL){
(nc->lfdimy > p.dimy ? nc->lfdimy : p.dimy);
p.crender = malloc(count * sizeof(*p.crender));
if(p.crender == NULL){
fclose(out); fclose(out);
free(rastered); free(rastered);
return -1; return -1;
} }
init_rvec(p.crender, count); init_rvec(p->crender, count);
for(int i = 0 ; i < count ; ++i){ 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); int ret = raster_and_write(nc, p, out);
free(p.crender); free(p->crender);
if(ret > 0){ if(ret > 0){
if(fprintf(fp, "%s", rastered) == ret){ if(fprintf(fp, "%s", rastered) == ret){
ret = 0; ret = 0;
@ -1270,6 +1269,9 @@ int notcurses_render_to_file(notcurses* nc, FILE* fp){
return ret; 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 // We execute the painter's algorithm, starting from our topmost plane. The
// damagevector should be all zeros on input. On success, it will reflect // 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 // 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 // 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. // 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){ int ncpile_render_to_buffer(ncplane* p, char** buf, size_t* buflen){
ncplane* stdn = notcurses_stdplane(nc); if(ncpile_render(p)){
if(ncpile_render(stdn)){
return -1; 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); pthread_mutex_lock(&nc->statlock);
update_render_bytes(&nc->stats, bytes); update_render_bytes(&nc->stats, bytes);
pthread_mutex_unlock(&nc->statlock); pthread_mutex_unlock(&nc->statlock);
@ -1397,6 +1399,10 @@ int notcurses_render_to_buffer(notcurses* nc, char** buf, size_t* buflen){
return 0; 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 // 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. // result is not tied to the ncplane, and persists across erases / destruction.
static inline char* static inline char*