mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 17:19:03 -04:00
add notcurses_render_file() #491
This commit is contained in:
parent
8731b1191d
commit
b6330d142b
3
NEWS.md
3
NEWS.md
@ -1,6 +1,9 @@
|
|||||||
This document attempts to list user-visible changes and any major internal
|
This document attempts to list user-visible changes and any major internal
|
||||||
rearrangements of Notcurses.
|
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)
|
* 1.6.0 (2020-07-04)
|
||||||
* Behavior has changed regarding use of the provided `FILE*` (which, when
|
* Behavior has changed regarding use of the provided `FILE*` (which, when
|
||||||
`NULL`, is assumed to be `stdout`). Both Notcurses and `ncdirect` now
|
`NULL`, is assumed to be `stdout`). Both Notcurses and `ncdirect` now
|
||||||
|
4
USAGE.md
4
USAGE.md
@ -170,6 +170,10 @@ updated to reflect the changes:
|
|||||||
// successful call to notcurses_render().
|
// successful call to notcurses_render().
|
||||||
int notcurses_render(struct notcurses* nc);
|
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
|
// 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
|
||||||
// attrword and channels are written to 'attrword' and 'channels', respectively.
|
// 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);**
|
**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
|
# DESCRIPTION
|
||||||
|
|
||||||
**notcurses_render** syncs the physical display to the context's prepared
|
**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
|
While **notcurses_render** is called, you **must not call any other functions
|
||||||
on the same notcurses context**, with the one exception of **notcurses_getc**
|
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
|
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
|
||||||
@ -86,8 +88,9 @@ purposes of color blending.
|
|||||||
|
|
||||||
**notcurses(3)**,
|
**notcurses(3)**,
|
||||||
**notcurses_cell(3)**,
|
**notcurses_cell(3)**,
|
||||||
**notcurses_plane(3)**,
|
**notcurses_input(3)**,
|
||||||
**notcurses_output(3)**,
|
**notcurses_output(3)**,
|
||||||
|
**notcurses_plane(3)**,
|
||||||
**notcurses_refresh(3)**,
|
**notcurses_refresh(3)**,
|
||||||
**notcurses_stats(3)**,
|
**notcurses_stats(3)**,
|
||||||
**console_codes(4)**,
|
**console_codes(4)**,
|
||||||
|
@ -993,6 +993,10 @@ API int notcurses_stop(struct notcurses* nc);
|
|||||||
// successful call to notcurses_render().
|
// successful call to notcurses_render().
|
||||||
API int notcurses_render(struct notcurses* nc);
|
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.
|
// Return the topmost ncplane, of which there is always at least one.
|
||||||
API struct ncplane* notcurses_top(struct notcurses* n);
|
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_lex_margins(const char* op, notcurses_options* opts);
|
||||||
int notcurses_stop(struct notcurses*);
|
int notcurses_stop(struct notcurses*);
|
||||||
int notcurses_render(struct notcurses*);
|
int notcurses_render(struct notcurses*);
|
||||||
|
int notcurses_render_to_file(struct notcurses* nc, FILE* fp);
|
||||||
struct ncplane* notcurses_stdplane(struct notcurses*);
|
struct ncplane* notcurses_stdplane(struct notcurses*);
|
||||||
const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
|
const struct ncplane* notcurses_stdplane_const(const struct notcurses* nc);
|
||||||
int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);
|
int ncplane_set_base_cell(struct ncplane* ncp, const cell* c);
|
||||||
|
@ -35,14 +35,14 @@ unicode1emoji1(struct ncplane* title, int y){
|
|||||||
if(n == NULL){
|
if(n == NULL){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ncplane_putstr_yx(n, 1, 1, "\u2764 (\u2764\ufe0f) \u2709 (\u2709\ufe0f)"
|
ncplane_putstr_yx(n, 1, 1, "\u2764 \u2764\ufe0f \u2709 \u2709\ufe0f"
|
||||||
"\u270f (\u270f\ufe0f) \u2712 (\u2712\ufe0f)"
|
"\u270f \u270f\ufe0f \u2712 \u2712\ufe0f"
|
||||||
"\u2195 (\u2195\ufe0f) \u2194 (\u2194\ufe0f)"
|
"\u2195 \u2195\ufe0f \u2194 \u2194\ufe0f"
|
||||||
"\u2716 (\u2716\ufe0f) \u2733 (\u2733\ufe0f)"
|
"\u2716 \u2716\ufe0f \u2733 \u2733\ufe0f"
|
||||||
"\u2734 (\u2734\ufe0f) \u2747 (\u2747\ufe0f)");
|
"\u2734 \u2734\ufe0f \u2747 \u2747\ufe0f");
|
||||||
ncplane_putstr_yx(n, 2, 1, "\u2660 (\u2660\ufe0f) \u2665 (\u2665\ufe0f)"
|
ncplane_putstr_yx(n, 2, 1, "\u2660 \u2660\ufe0f \u2665 \u2665\ufe0f"
|
||||||
"\u2666 (\u2666\ufe0f) \u2663 (\u2663\ufe0f)"
|
"\u2666 \u2666\ufe0f \u2663 \u2663\ufe0f"
|
||||||
"\u260e (\u260e\ufe0f) \u27a1 (\u27a1\ufe0f)");
|
"\u260e \u260e\ufe0f \u27a1 \u27a1\ufe0f");
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,20 +54,20 @@ unicode52(struct ncplane* title, int y){
|
|||||||
if(n == NULL){
|
if(n == NULL){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ncplane_putstr_yx(n, 1, 1, "\u26ea (\u26ea\ufe0f) \u26f2 (\u26f2\ufe0f)"
|
ncplane_putstr_yx(n, 1, 1, "\u26ea \u26ea\ufe0f \u26f2 \u26f2\ufe0f"
|
||||||
"\u26fa (\u26fa\ufe0f) \u2668 (\u2668\ufe0f)"
|
"\u26fa \u26fa\ufe0f \u2668 \u2668\ufe0f"
|
||||||
"\u26fd (\u26fd\ufe0f) \u2693 (\u2693\ufe0f)"
|
"\u26fd \u26fd\ufe0f \u2693 \u2693\ufe0f"
|
||||||
"\u26f5 (\u26f5\ufe0f) \u2600 (\u2600\ufe0f)");
|
"\u26f5 \u26f5\ufe0f \u2600 \u2600\ufe0f");
|
||||||
ncplane_putstr_yx(n, 2, 1, "\u26c5 (\u26c5\ufe0f) \u2614 (\u2614\ufe0f)"
|
ncplane_putstr_yx(n, 2, 1, "\u26c5 \u26c5\ufe0f \u2614 \u2614\ufe0f"
|
||||||
"\u26a1 (\u26a1\ufe0f) \u26c4 (\u26c4\ufe0f)"
|
"\u26a1 \u26a1\ufe0f \u26c4 \u26c4\ufe0f"
|
||||||
"\u26be (\u26b3\ufe0f) \u26d4 (\u26d4\ufe0f)"
|
"\u26be \u26b3\ufe0f \u26d4 \u26d4\ufe0f"
|
||||||
"\u2b06 (\u2b06\ufe0f) \u2b07 (\u2b07\ufe0f)");
|
"\u2b06 \u2b06\ufe0f \u2b07 \u2b07\ufe0f");
|
||||||
ncplane_putstr_yx(n, 3, 1, "\u2b05 (\u2b05\ufe0f) \u26ce (\u26ce\ufe0f)"
|
ncplane_putstr_yx(n, 3, 1, "\u2b05 \u2b05\ufe0f \u26ce \u26ce\ufe0f"
|
||||||
"\u203c (\u203c\ufe0f) \u2049 (\u2049\ufe0f)"
|
"\u203c \u203c\ufe0f \u2049 \u2049\ufe0f"
|
||||||
"\xf0\x9f\x85\xbf (\xf0\x9f\x85\xbf\ufe0f)"
|
"\xf0\x9f\x85\xbf \xf0\x9f\x85\xbf\ufe0f"
|
||||||
"\xf0\x9f\x88\xaf (\xf0\x9f\x88\xaf\ufe0f)"
|
"\xf0\x9f\x88\xaf \xf0\x9f\x88\xaf\ufe0f"
|
||||||
"\xf0\x9f\x88\x9a (\xf0\x9f\x88\x9a\ufe0f)"
|
"\xf0\x9f\x88\x9a \xf0\x9f\x88\x9a\ufe0f"
|
||||||
"\u3299 (\u3299\ufe0f)");
|
"\u3299 \u3299\ufe0f");
|
||||||
return n;
|
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
|
// lastframe has *not yet been written to the screen*, i.e. it's only about to
|
||||||
// *become* the last frame rasterized.
|
// *become* the last frame rasterized.
|
||||||
static int
|
static int
|
||||||
notcurses_rasterize(notcurses* nc, const struct crender* rvec){
|
notcurses_rasterize(notcurses* nc, const struct crender* rvec, FILE* out){
|
||||||
FILE* out = nc->rstate.mstreamfp;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int y, x;
|
int y, x;
|
||||||
fseeko(out, 0, SEEK_SET);
|
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){
|
for(int i = 0 ; i < count ; ++i){
|
||||||
rvec[i].damaged = true;
|
rvec[i].damaged = true;
|
||||||
}
|
}
|
||||||
int ret = notcurses_rasterize(nc, rvec);
|
int ret = notcurses_rasterize(nc, rvec, nc->rstate.mstreamfp);
|
||||||
free(rvec);
|
free(rvec);
|
||||||
if(ret < 0){
|
if(ret < 0){
|
||||||
return -1;
|
return -1;
|
||||||
@ -1086,6 +1085,43 @@ int notcurses_refresh(notcurses* nc, int* restrict dimy, int* restrict dimx){
|
|||||||
return 0;
|
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
|
// 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
|
||||||
// which cells were changed. We solve for each coordinate's cell by walking
|
// 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);
|
struct crender* crender = malloc(crenderlen);
|
||||||
memset(crender, 0, crenderlen);
|
memset(crender, 0, crenderlen);
|
||||||
if(notcurses_render_internal(nc, crender) == 0){
|
if(notcurses_render_internal(nc, crender) == 0){
|
||||||
bytes = notcurses_rasterize(nc, crender);
|
bytes = notcurses_rasterize(nc, crender, nc->rstate.mstreamfp);
|
||||||
}
|
}
|
||||||
free(crender);
|
free(crender);
|
||||||
clock_gettime(CLOCK_MONOTONIC, &done);
|
clock_gettime(CLOCK_MONOTONIC, &done);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user