add notcurses_render_file() #491

pull/783/head
nick black 4 years ago
parent 8731b1191d
commit b6330d142b
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -1,6 +1,9 @@
This document attempts to list user-visible changes and any major internal
rearrangements of Notcurses.
* 1.6.1 (not yet released)
* Added `notcurses_render_file()` to dump last rendered frame to a `FILE*`.
* 1.6.0 (2020-07-04)
* Behavior has changed regarding use of the provided `FILE*` (which, when
`NULL`, is assumed to be `stdout`). Both Notcurses and `ncdirect` now

@ -170,6 +170,10 @@ updated to reflect the changes:
// successful call to notcurses_render().
int notcurses_render(struct notcurses* nc);
// Write the last rendered frame, in its entirety, to 'fp'. This is not valid
// until notcurses_render() has been successfully called at least once.
int notcurses_render_to_file(struct notcurses* nc, 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
// attrword and channels are written to 'attrword' and 'channels', respectively.

@ -14,6 +14,8 @@ notcurses_render - sync the physical display to the virtual ncplanes
**char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff, uint32_t* attrword, uint64_t* channels);**
**int notcurses_render_to_file(struct notcurses* nc, FILE* fp);**
# DESCRIPTION
**notcurses_render** syncs the physical display to the context's prepared
@ -25,7 +27,7 @@ render (see notcurses_stats(3)), and screen geometry is refreshed (similarly to
While **notcurses_render** is called, you **must not call any other functions
on the same notcurses context**, with the one exception of **notcurses_getc**
(and its input-related helpers).
(and its input-related helpers; see **notcurses_input(3)**.).
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
@ -86,8 +88,9 @@ purposes of color blending.
**notcurses(3)**,
**notcurses_cell(3)**,
**notcurses_plane(3)**,
**notcurses_input(3)**,
**notcurses_output(3)**,
**notcurses_plane(3)**,
**notcurses_refresh(3)**,
**notcurses_stats(3)**,
**console_codes(4)**,

@ -993,6 +993,10 @@ API int notcurses_stop(struct notcurses* nc);
// successful call to notcurses_render().
API int notcurses_render(struct notcurses* nc);
// Write the last rendered frame, in its entirety, to 'fp'. This is not valid
// until notcurses_render() has been successfully called at least once.
API int notcurses_render_to_file(struct notcurses* nc, FILE* fp);
// Return the topmost ncplane, of which there is always at least one.
API struct ncplane* notcurses_top(struct notcurses* n);

@ -85,6 +85,7 @@ struct notcurses* notcurses_init(const notcurses_options*, FILE*);
int notcurses_lex_margins(const char* op, notcurses_options* opts);
int notcurses_stop(struct notcurses*);
int notcurses_render(struct notcurses*);
int notcurses_render_to_file(struct notcurses* nc, FILE* fp);
struct ncplane* notcurses_stdplane(struct notcurses*);
const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);

@ -35,14 +35,14 @@ unicode1emoji1(struct ncplane* title, int y){
if(n == NULL){
return NULL;
}
ncplane_putstr_yx(n, 1, 1, "\u2764 (\u2764\ufe0f) \u2709 (\u2709\ufe0f)"
"\u270f (\u270f\ufe0f) \u2712 (\u2712\ufe0f)"
"\u2195 (\u2195\ufe0f) \u2194 (\u2194\ufe0f)"
"\u2716 (\u2716\ufe0f) \u2733 (\u2733\ufe0f)"
"\u2734 (\u2734\ufe0f) \u2747 (\u2747\ufe0f)");
ncplane_putstr_yx(n, 2, 1, "\u2660 (\u2660\ufe0f) \u2665 (\u2665\ufe0f)"
"\u2666 (\u2666\ufe0f) \u2663 (\u2663\ufe0f)"
"\u260e (\u260e\ufe0f) \u27a1 (\u27a1\ufe0f)");
ncplane_putstr_yx(n, 1, 1, "\u2764 \u2764\ufe0f \u2709 \u2709\ufe0f"
"\u270f \u270f\ufe0f \u2712 \u2712\ufe0f"
"\u2195 \u2195\ufe0f \u2194 \u2194\ufe0f"
"\u2716 \u2716\ufe0f \u2733 \u2733\ufe0f"
"\u2734 \u2734\ufe0f \u2747 \u2747\ufe0f");
ncplane_putstr_yx(n, 2, 1, "\u2660 \u2660\ufe0f \u2665 \u2665\ufe0f"
"\u2666 \u2666\ufe0f \u2663 \u2663\ufe0f"
"\u260e \u260e\ufe0f \u27a1 \u27a1\ufe0f");
return n;
}
@ -54,20 +54,20 @@ unicode52(struct ncplane* title, int y){
if(n == NULL){
return NULL;
}
ncplane_putstr_yx(n, 1, 1, "\u26ea (\u26ea\ufe0f) \u26f2 (\u26f2\ufe0f)"
"\u26fa (\u26fa\ufe0f) \u2668 (\u2668\ufe0f)"
"\u26fd (\u26fd\ufe0f) \u2693 (\u2693\ufe0f)"
"\u26f5 (\u26f5\ufe0f) \u2600 (\u2600\ufe0f)");
ncplane_putstr_yx(n, 2, 1, "\u26c5 (\u26c5\ufe0f) \u2614 (\u2614\ufe0f)"
"\u26a1 (\u26a1\ufe0f) \u26c4 (\u26c4\ufe0f)"
"\u26be (\u26b3\ufe0f) \u26d4 (\u26d4\ufe0f)"
"\u2b06 (\u2b06\ufe0f) \u2b07 (\u2b07\ufe0f)");
ncplane_putstr_yx(n, 3, 1, "\u2b05 (\u2b05\ufe0f) \u26ce (\u26ce\ufe0f)"
"\u203c (\u203c\ufe0f) \u2049 (\u2049\ufe0f)"
"\xf0\x9f\x85\xbf (\xf0\x9f\x85\xbf\ufe0f)"
"\xf0\x9f\x88\xaf (\xf0\x9f\x88\xaf\ufe0f)"
"\xf0\x9f\x88\x9a (\xf0\x9f\x88\x9a\ufe0f)"
"\u3299 (\u3299\ufe0f)");
ncplane_putstr_yx(n, 1, 1, "\u26ea \u26ea\ufe0f \u26f2 \u26f2\ufe0f"
"\u26fa \u26fa\ufe0f \u2668 \u2668\ufe0f"
"\u26fd \u26fd\ufe0f \u2693 \u2693\ufe0f"
"\u26f5 \u26f5\ufe0f \u2600 \u2600\ufe0f");
ncplane_putstr_yx(n, 2, 1, "\u26c5 \u26c5\ufe0f \u2614 \u2614\ufe0f"
"\u26a1 \u26a1\ufe0f \u26c4 \u26c4\ufe0f"
"\u26be \u26b3\ufe0f \u26d4 \u26d4\ufe0f"
"\u2b06 \u2b06\ufe0f \u2b07 \u2b07\ufe0f");
ncplane_putstr_yx(n, 3, 1, "\u2b05 \u2b05\ufe0f \u26ce \u26ce\ufe0f"
"\u203c \u203c\ufe0f \u2049 \u2049\ufe0f"
"\xf0\x9f\x85\xbf \xf0\x9f\x85\xbf\ufe0f"
"\xf0\x9f\x88\xaf \xf0\x9f\x88\xaf\ufe0f"
"\xf0\x9f\x88\x9a \xf0\x9f\x88\x9a\ufe0f"
"\u3299 \u3299\ufe0f");
return n;
}

@ -865,8 +865,7 @@ stage_cursor(notcurses* nc, FILE* out, int y, int x){
// lastframe has *not yet been written to the screen*, i.e. it's only about to
// *become* the last frame rasterized.
static int
notcurses_rasterize(notcurses* nc, const struct crender* rvec){
FILE* out = nc->rstate.mstreamfp;
notcurses_rasterize(notcurses* nc, const struct crender* rvec, FILE* out){
int ret = 0;
int y, x;
fseeko(out, 0, SEEK_SET);
@ -1078,7 +1077,7 @@ int notcurses_refresh(notcurses* nc, int* restrict dimy, int* restrict dimx){
for(int i = 0 ; i < count ; ++i){
rvec[i].damaged = true;
}
int ret = notcurses_rasterize(nc, rvec);
int ret = notcurses_rasterize(nc, rvec, nc->rstate.mstreamfp);
free(rvec);
if(ret < 0){
return -1;
@ -1086,6 +1085,43 @@ int notcurses_refresh(notcurses* nc, int* restrict dimy, int* restrict dimx){
return 0;
}
int notcurses_render_to_file(struct notcurses* nc, FILE* fp){
if(nc->lfdimx == 0 || nc->lfdimy == 0){
return 0;
}
char* rastered = NULL;
size_t rastbytes = 0;
FILE* out = open_memstream(&rastered, &rastbytes);
if(out == NULL){
return -1;
}
const int count = (nc->lfdimx > nc->stdscr->lenx ? nc->lfdimx : nc->stdscr->lenx) *
(nc->lfdimy > nc->stdscr->leny ? nc->lfdimy : nc->stdscr->leny);
struct crender* rvec = malloc(count * sizeof(*rvec));
if(rvec == NULL){
fclose(out);
free(rastered);
return -1;
}
memset(rvec, 0, count * sizeof(*rvec));
for(int i = 0 ; i < count ; ++i){
rvec[i].damaged = true;
}
int ret = notcurses_rasterize(nc, rvec, out);
free(rvec);
if(ret > 0){
if(fprintf(fp, "%s", rastered) == ret){
ret = 0;
}else{
ret = -1;
}
}
fclose(out);
free(rastered);
return 0;
}
// We execute the painter's algorithm, starting from our topmost plane. The
// damagevector should be all zeros on input. On success, it will reflect
// which cells were changed. We solve for each coordinate's cell by walking
@ -1123,7 +1159,7 @@ int notcurses_render(notcurses* nc){
struct crender* crender = malloc(crenderlen);
memset(crender, 0, crenderlen);
if(notcurses_render_internal(nc, crender) == 0){
bytes = notcurses_rasterize(nc, crender);
bytes = notcurses_rasterize(nc, crender, nc->rstate.mstreamfp);
}
free(crender);
clock_gettime(CLOCK_MONOTONIC, &done);

Loading…
Cancel
Save