Commit 4975b416 authored by Deucе's avatar Deucе 👌🏾
Browse files

Add support for PPM graphics to SyncTERM

You can copy whole, or portions of a PPM file from the cache directory
to the screen, optionally applying a mask.  The mask can be specified
as a base64-encoded bitmap or as a PBM file in the cache directory.

You can also copy portions of the screen into an internal buffer, and
draw from that internal buffer.  There's plans to support loading an
image file from the cache directory into the buffer as well.

Portions of the buffer can be copied to the screen, optionally
applying a mask as with drawing PPMs.

There's also plans to support copying a PBM file into a mask buffer.

I've added the syncterm-bounce.js script which simply bounces the
SyncTERM icon around the screen like the classic screensaver we all
hate.  I initially wanted to replace the spinning cursor with it,
but there doesn't seem to be a way to replace that with a script. :(

To use the script, just add the text:
@EXEC:syncterm-bounce.js@ to the end of your logon.js script.

Log in to nix.synchro.net with the latest nightly build or build from
git to see the script in action.
parent e2cdd5fc
Pipeline #3516 passed with stage
in 5 minutes and 35 seconds
This diff is collapsed.
......@@ -1388,14 +1388,14 @@ int bitmap_setpixel(uint32_t x, uint32_t y, uint32_t colour)
return 1;
}
int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, struct ciolib_pixels *pixels, void *mask)
int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, uint32_t mx_off, uint32_t my_off, struct ciolib_pixels *pixels, struct ciolib_mask *mask)
{
uint32_t x, y;
uint32_t width,height;
char *m = mask;
int mask_bit;
size_t mask_byte;
size_t pos;
size_t mpos;
if (pixels == NULL)
return 0;
......@@ -1412,6 +1412,13 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_
if (height + y_off > pixels->height)
return 0;
if (mask != NULL) {
if (width + mx_off > mask->width)
return 0;
if (height + my_off > mask->height)
return 0;
}
pthread_mutex_lock(&blinker_lock);
pthread_mutex_lock(&screena.screenlock);
pthread_mutex_lock(&screenb.screenlock);
......@@ -1440,11 +1447,12 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_
}
}
else {
mpos = mask->width * (y - sy + my_off) + mx_off;
for (x = sx; x <= ex; x++) {
mask_byte = pos / 8;
mask_bit = pos % 8;
mask_byte = mpos / 8;
mask_bit = mpos % 8;
mask_bit = 0x80 >> mask_bit;
if (m[mask_byte] & mask_bit) {
if (mask->bits[mask_byte] & mask_bit) {
screena.screen[PIXEL_OFFSET(screena, x, y)] = pixels->pixels[pos];
screena.rect->data[PIXEL_OFFSET(screena, x, y)] = color_value(pixels->pixels[pos]);
if (pixels->pixelsb) {
......@@ -1457,6 +1465,7 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_
}
}
pos++;
mpos++;
}
}
}
......
......@@ -40,7 +40,7 @@ int bitmap_getvideoflags(void);
void bitmap_setvideoflags(int flags);
int bitmap_attr2palette(uint8_t attr, uint32_t *fgp, uint32_t *bgp);
int bitmap_setpixel(uint32_t x, uint32_t y, uint32_t colour);
int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, struct ciolib_pixels *, void *mask);
int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, uint32_t mx_off, uint32_t my_off, struct ciolib_pixels *, struct ciolib_mask *mask);
struct ciolib_pixels *bitmap_getpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, int force);
int bitmap_get_modepalette(uint32_t p[16]);
int bitmap_set_modepalette(uint32_t p[16]);
......
......@@ -129,8 +129,9 @@ CIOLIBEXPORT int ciolib_setpalette(uint32_t entry, uint16_t r, uint16_t g, uint1
CIOLIBEXPORT int ciolib_attr2palette(uint8_t attr, uint32_t *fg, uint32_t *bg);
CIOLIBEXPORT int ciolib_setpixel(uint32_t x, uint32_t y, uint32_t colour);
CIOLIBEXPORT struct ciolib_pixels * ciolib_getpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, int force);
CIOLIBEXPORT int ciolib_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, struct ciolib_pixels *pixels, void *mask);
CIOLIBEXPORT int ciolib_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, uint32_t mx_off, uint32_t my_off, struct ciolib_pixels *pixels, struct ciolib_mask *mask);
CIOLIBEXPORT void ciolib_freepixels(struct ciolib_pixels *pixels);
CIOLIBEXPORT void ciolib_freemask(struct ciolib_mask *mask);
CIOLIBEXPORT struct ciolib_screen * ciolib_savescreen(void);
CIOLIBEXPORT void ciolib_freescreen(struct ciolib_screen *);
CIOLIBEXPORT int ciolib_restorescreen(struct ciolib_screen *scrn);
......@@ -1630,12 +1631,12 @@ CIOLIBEXPORT struct ciolib_pixels * ciolib_getpixels(uint32_t sx, uint32_t sy, u
}
/* Returns non-zero on success */
CIOLIBEXPORT int ciolib_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, struct ciolib_pixels *pixels, void *mask)
CIOLIBEXPORT int ciolib_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, uint32_t mx_off, uint32_t my_off, struct ciolib_pixels *pixels, struct ciolib_mask *mask)
{
CIOLIB_INIT();
if (cio_api.setpixels)
return cio_api.setpixels(sx, sy, ex, ey, x_off, y_off, pixels, mask);
return cio_api.setpixels(sx, sy, ex, ey, x_off, y_off, mx_off, my_off, pixels, mask);
return 0;
}
......@@ -1649,6 +1650,15 @@ CIOLIBEXPORT void ciolib_freepixels(struct ciolib_pixels *pixels)
FREE_AND_NULL(pixels);
}
CIOLIBEXPORT void ciolib_freemask(struct ciolib_mask *mask)
{
if (mask == NULL)
return;
FREE_AND_NULL(mask->bits);
FREE_AND_NULL(mask);
}
/* Returns NULL on failure */
CIOLIBEXPORT struct ciolib_screen * ciolib_savescreen(void)
{
......@@ -1713,7 +1723,7 @@ CIOLIBEXPORT int ciolib_restorescreen(struct ciolib_screen *scrn)
ciolib_window(scrn->text_info.winleft, scrn->text_info.wintop, scrn->text_info.winright, scrn->text_info.winbottom);
vmode = find_vmode(scrn->text_info.currmode);
if (vmode != -1 && scrn->pixels != NULL)
ciolib_setpixels(0, 0, vparams[vmode].charwidth * vparams[vmode].cols - 1, vparams[vmode].charheight * vparams[vmode].rows - 1, 0, 0, scrn->pixels, NULL);
ciolib_setpixels(0, 0, vparams[vmode].charwidth * vparams[vmode].cols - 1, vparams[vmode].charheight * vparams[vmode].rows - 1, 0, 0, 0, 0, scrn->pixels, NULL);
for (i=0; i<5; i++)
ciolib_setfont(scrn->fonts[i], FALSE, i);
ciolib_setvideoflags(scrn->flags);
......
......@@ -270,6 +270,12 @@ struct ciolib_pixels {
uint32_t height;
};
struct ciolib_mask {
uint8_t *bits;
uint32_t width;
uint32_t height;
};
struct vmem_cell {
uint8_t legacy_attr;
uint8_t ch;
......@@ -370,7 +376,7 @@ typedef struct {
int (*attr2palette) (uint8_t attr, uint32_t *fg, uint32_t *bg);
int (*setpixel) (uint32_t x, uint32_t y, uint32_t colour);
struct ciolib_pixels *(*getpixels)(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, int force);
int (*setpixels)(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, struct ciolib_pixels *pixels, void *mask);
int (*setpixels)(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, uint32_t mx_off, uint32_t my_off, struct ciolib_pixels *pixels, struct ciolib_mask *mask);
int (*get_modepalette)(uint32_t[16]);
int (*set_modepalette)(uint32_t[16]);
uint32_t (*map_rgb)(uint16_t r, uint16_t g, uint16_t b);
......@@ -459,8 +465,9 @@ CIOLIBEXPORT int ciolib_setpalette(uint32_t entry, uint16_t r, uint16_t g, uint1
CIOLIBEXPORT int ciolib_attr2palette(uint8_t attr, uint32_t *fg, uint32_t *bg);
CIOLIBEXPORT int ciolib_setpixel(uint32_t x, uint32_t y, uint32_t colour);
CIOLIBEXPORT struct ciolib_pixels * ciolib_getpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, int force);
CIOLIBEXPORT int ciolib_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, struct ciolib_pixels *pixels, void *mask);
CIOLIBEXPORT int ciolib_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, uint32_t mx_off, uint32_t my_off, struct ciolib_pixels *pixels, struct ciolib_mask *mask);
CIOLIBEXPORT void ciolib_freepixels(struct ciolib_pixels *pixels);
CIOLIBEXPORT void ciolib_freemask(struct ciolib_mask *mask);
CIOLIBEXPORT struct ciolib_screen * ciolib_savescreen(void);
CIOLIBEXPORT void ciolib_freescreen(struct ciolib_screen *);
CIOLIBEXPORT int ciolib_restorescreen(struct ciolib_screen *scrn);
......@@ -544,8 +551,9 @@ CIOLIBEXPORT void ansi_ciolib_setdoorway(int enable);
#define attr2palette(a,b,c) ciolib_attr2palette(a,b,c)
#define setpixel(a,b,c) ciolib_setpixel(a,b,c)
#define getpixels(a,b,c,d, e) ciolib_getpixels(a,b,c,d, e)
#define setpixels(a,b,c,d,e,f,g,h) ciolib_setpixels(a,b,c,d,e,f,g,h)
#define setpixels(a,b,c,d,e,f,g,h,i,j) ciolib_setpixels(a,b,c,d,e,f,g,h,i,j)
#define freepixels(a) ciolib_freepixels(a)
#define freemask(a) ciolib_freemask(a)
#define savescreen() ciolib_savescreen()
#define freescreen(a) ciolib_freescreen(a)
#define restorescreen(a) ciolib_restorescreen(a)
......
......@@ -1674,8 +1674,9 @@ static void parse_sixel_string(struct cterminal *cterm, bool finish)
cterm->sx_pixels->pixelsb = NULL;
cterm->sx_pixels->width = ti.screenwidth * vparams[vmode].charwidth;
cterm->sx_pixels->height = cterm->sx_iv * 6;
cterm->sx_mask = malloc((cterm->sx_iv * 6 * ti.screenwidth * vparams[vmode].charwidth * 6 + 7)/8);
memset(cterm->sx_mask, 0, (cterm->sx_iv * 6 * ti.screenwidth * vparams[vmode].charwidth * 6 + 7)/8);
cterm->sx_mask = malloc(sizeof(struct ciolib_mask));
cterm->sx_mask->bits = malloc((cterm->sx_iv * 6 * ti.screenwidth * vparams[vmode].charwidth * 6 + 7)/8);
memset(cterm->sx_mask->bits, 0, (cterm->sx_iv * 6 * ti.screenwidth * vparams[vmode].charwidth * 6 + 7)/8);
}
if (cterm->sx_x == cterm->sx_left && cterm->sx_height && cterm->sx_width && cterm->sx_first_pass) {
/* Fill in the background of the line */
......@@ -1684,7 +1685,7 @@ static void parse_sixel_string(struct cterminal *cterm, bool finish)
for (k = 0; k < cterm->sx_ih; k++) {
pos = i * cterm->sx_iv * cterm->sx_pixels->width + j * cterm->sx_pixels->width + cterm->sx_x + k;
cterm->sx_pixels->pixels[pos] = cterm->sx_bg;
cterm->sx_mask[pos/8] |= (0x80 >> (pos % 8));
cterm->sx_mask->bits[pos/8] |= (0x80 >> (pos % 8));
}
}
}
......@@ -1696,7 +1697,7 @@ static void parse_sixel_string(struct cterminal *cterm, bool finish)
for (k = 0; k < cterm->sx_ih; k++) {
pos = i * cterm->sx_iv * cterm->sx_pixels->width + j * cterm->sx_pixels->width + cterm->sx_x + k;
cterm->sx_pixels->pixels[pos] = cterm->sx_fg;
cterm->sx_mask[pos/8] |= (0x80 >> (pos % 8));
cterm->sx_mask->bits[pos/8] |= (0x80 >> (pos % 8));
}
}
}
......@@ -1706,7 +1707,7 @@ static void parse_sixel_string(struct cterminal *cterm, bool finish)
for (k = 0; k < cterm->sx_ih; k++) {
pos = i * cterm->sx_iv * cterm->sx_pixels->width + j * cterm->sx_pixels->width + cterm->sx_x + k;
cterm->sx_pixels->pixels[pos] = cterm->sx_bg;
cterm->sx_mask[pos/8] |= (0x80 >> (pos % 8));
cterm->sx_mask->bits[pos/8] |= (0x80 >> (pos % 8));
}
}
}
......@@ -1715,7 +1716,7 @@ static void parse_sixel_string(struct cterminal *cterm, bool finish)
for (k = 0; k < cterm->sx_ih; k++) {
pos = i * cterm->sx_iv * cterm->sx_pixels->width + j * cterm->sx_pixels->width + cterm->sx_x + k;
if (cterm->sx_first_pass)
cterm->sx_mask[pos/8] &= ~(0x80 >> (pos % 8));
cterm->sx_mask->bits[pos/8] &= ~(0x80 >> (pos % 8));
}
}
}
......@@ -1804,7 +1805,7 @@ static void parse_sixel_string(struct cterminal *cterm, bool finish)
if (vmode == -1)
return;
setpixels(cterm->sx_left, cterm->sx_y, cterm->sx_row_max_x, cterm->sx_y + 6 * cterm->sx_iv - 1, cterm->sx_left, 0, cterm->sx_pixels, cterm->sx_mask);
setpixels(cterm->sx_left, cterm->sx_y, cterm->sx_row_max_x, cterm->sx_y + 6 * cterm->sx_iv - 1, cterm->sx_left, 0, cterm->sx_left, 0, cterm->sx_pixels, cterm->sx_mask);
cterm->sx_row_max_x = 0;
if ((!(cterm->extattr & CTERM_EXTATTR_SXSCROLL)) && (((cterm->sx_y + 6 * cterm->sx_iv) + 6*cterm->sx_iv - 1) >= (cterm->y + max_row - 1) * vparams[vmode].charheight)) {
......@@ -1839,7 +1840,7 @@ all_done:
vmode = find_vmode(ti.currmode);
if (cterm->sx_row_max_x) {
setpixels(cterm->sx_left, cterm->sx_y, cterm->sx_row_max_x, cterm->sx_y + 6 * cterm->sx_iv - 1, cterm->sx_left, 0, cterm->sx_pixels, cterm->sx_mask);
setpixels(cterm->sx_left, cterm->sx_y, cterm->sx_row_max_x, cterm->sx_y + 6 * cterm->sx_iv - 1, cterm->sx_left, 0, cterm->sx_left, 0, cterm->sx_pixels, cterm->sx_mask);
}
*cterm->hold_update=cterm->sx_hold_update;
......@@ -1860,7 +1861,7 @@ all_done:
for (j = 0; j < cterm->sx_width*cterm->sx_ih; j++)
px.pixels[i*cterm->sx_width*cterm->sx_ih + j] = cterm->sx_bg;
}
setpixels(cterm->sx_x, cterm->sx_y, cterm->sx_x + cterm->sx_width - 1, cterm->sx_y + cterm->sx_height - 1, 0, 0, &px, NULL);
setpixels(cterm->sx_x, cterm->sx_y, cterm->sx_x + cterm->sx_width - 1, cterm->sx_y + cterm->sx_height - 1, 0, 0, 0, 0, &px, NULL);
free(px.pixels);
}
......@@ -4398,7 +4399,7 @@ cterm_reset(struct cterminal *cterm)
struct cterminal* cterm_init(int height, int width, int xpos, int ypos, int backlines, int backcols, struct vmem_cell *scrollback, int emulation)
{
char *revision="$Revision: 1.314 $";
char *revision="$Revision: 1.315 $";
char *in;
char *out;
struct cterminal *cterm;
......
......@@ -186,7 +186,7 @@ struct cterminal {
struct ciolib_pixels *sx_pixels;
unsigned long sx_width; // Width from raster attributes
unsigned long sx_height; // REMAINING heigh from raster attributes
uint8_t *sx_mask;
struct ciolib_mask *sx_mask;
int sx_orig_cursor; // Original value of cterm->cursor
/* APC Handler */
......
......@@ -242,12 +242,12 @@ ESC _ Application Program String (APS)
SyncTERM implements the following APS commands:
APS SyncTERM:C;S;Ps1;Ps2 ST (Store file)
APS SyncTERM:C;S Ps1 Ps2 ST (Store file)
Where Ps1 is a filename and Ps2 is the base64 encoded
contents of the file. The named file is stored in the
cache directory for the current connection.
APS SyncTERM:C;L ST (List Files)
APS SyncTERM:C;L Ps ST (List Files)
List files in cache. SyncTERM responds with
an APS string with lines separated by newlines. The
first line is always "SyncTERM:C;L\n" and for each
......@@ -258,11 +258,93 @@ ESC _ Application Program String (APS)
And additional argument can be specified as a glob(3)
pattern (defaults to "*") in APS SyncTERM:C;L;Ps ST.
APS SyncTERM:C;SetFont;Pn;Ps
APS SyncTERM:C;SetFont Pn Ps
Where Pn is a font slot number (max 255) and Ps is a
filename in the cache. This sets font slot Pn to use
the specified font file.
APS SyncTERM:C;DrawPPM Ps... Ps2
Draws a PPM from the cache directory on the screen.
Ps2 is the filename and is required. Arguments for
Ps are optional. The following options can be included
(separated by semi-colons):
SX=#
Sets the left X position in the specified image
to copy from. Default = 0.
SY=#
Sets the top Y position in the specified image
to copy from. Default = 0.
SW=#
Sets the width of the portion of the image to
copy. Default = Image width - SX
SH=#
Sets the height of the portion of the image to
copy. Default = Image height - SH
DX=#
Sets the X position on the screen to draw the
image at. Default = 0.
DY=#
Sets the Y position on the screen to draw the
image at. Default = 0.
MX=#
Sets the X position in the mask to start
applying from. Default = 0.
MY=#
Sets the Y position in the mask to start
applying from. Default = 0.
MW=#
Sets the overall width of the mask (not the
width to apply). If MFILE is not specified,
and a mask is (ie: using MASK=), this is
required. If MFILE is specified, the width
is read from the file.
MH=#
Sets the overall height of the mask (not the
height to apply). If MFILE is not specified,
and a mask is (ie: using MASK=), this is
required. If MFILE is specified, the width
is read from the file.
MFILE=<filename>
Specifies a filename in the cache directory of
a PBM file specifying a mask of which pixels
to copy. Any pixel set to black (ie: 1) in the
PBM will be drawn from the source image. Pixels
set to white (ie: 0) will be left untouched.
MASK=<maskbits>
Specifies a base64-encoded bitmap, each set bit
will be drawn from the source image, cleared
bits will not be drawn. Requires MW= and MH=
to be specified.
The PPM file may be raw (preferred) or text. SyncTERM
does not support more than 255 values per colour channel
and assumes it is correctly using the BT.709 gamma
transfer.
APS SyncTERM:P;Copy Ps...
Copies a portion of the screen into an internal buffer
for use with the Paste function. Defaults to copying
the entire screen.
X=#
Sets the left X position on the screen to start
copying at. Default = 0.
Y=#
Sets the top Y position on the screen to start
copying at. Default = 0.
W=#
Sets the width to copy.
Default = Screen width - X.
H=#
Sets the height to copy.
Default = Screen height - X.
APS SyncTERM:P,Paste Ps...
Pastes from the copied buffer. Supports the same
options as the Cache DrawPPM command except for the
filename.
ESC c Reset to Initial State (RIS)
Resets all the terminal settings, clears the screen, and homes
the cursor.
......
......@@ -8200,7 +8200,7 @@ rv_paste(const char * const var, const void * const data)
rip.clipx + rip.clipboard->width - 1,
rip.clipy + rip.clipboard->height - 1,
0,
0,
0, 0, 0,
rip.clipboard,
NULL);
}
......@@ -9044,7 +9044,7 @@ invert_rect(int x1, int y1, int x2, int y2)
pixel++;
}
}
setpixels(x1, y1, x2, y2, 0, 0, pix, NULL);
setpixels(x1, y1, x2, y2, 0, 0, 0, 0, pix, NULL);
freepixels(pix);
}
 
......@@ -9878,7 +9878,7 @@ do_popup(const char * const str)
rip.color = oc;
rip.x = ox;
rip.y = oy;
setpixels(x1, y1, x2, y2, 0, 0, pix, NULL);
setpixels(x1, y1, x2, y2, 0, 0, 0, 0, pix, NULL);
if (ret < 0)
return NULL;
return p;
......@@ -10145,7 +10145,7 @@ reinit_screen(uint8_t *font, int fx, int fy)
 
// This is to force a vmem flush...
freepixels(getpixels(0, 0, 1, 1, true));
setpixels(0, 0, rip.x_max - 1, rip.y_max - 1, 0, 0, pix, NULL);
setpixels(0, 0, rip.x_max - 1, rip.y_max - 1, 0, 0, 0, 0, pix, NULL);
setwindow(cterm);
hold_update = old_hold;
freepixels(pix);
......@@ -10977,7 +10977,7 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
rip.viewport.ex,
arg2,
0,
0,
0, 0, 0,
pix,
NULL);
freepixels(pix);
......@@ -13849,7 +13849,7 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
x1 + rip.viewport.sx + pix->width - 1,
y1 + rip.viewport.sy + pix->height - 1,
0,
0,
0, 0, 0,
pix,
NULL);
if (arg2) {
......@@ -14048,7 +14048,7 @@ do_rip_command(int level, int sublevel, int cmd, const char *rawargs)
x1 + rip.viewport.sx + rip.clipboard->width - 1,
bline,
0,
0,
0, 0, 0,
rip.clipboard,
NULL);
break;
......@@ -15045,7 +15045,7 @@ draw_glyph(uint8_t ch)
 
if (pix) {
setpixels(0, 0, vparams[vmode].charwidth * vparams[vmode].cols - 1,
(vparams[vmode].charheight - 1) * vparams[vmode].rows - 1, 0, 0, pix, NULL);
(vparams[vmode].charheight - 1) * vparams[vmode].rows - 1, 0, 0, 0, 0, pix, NULL);
freepixels(pix);
amiga_y -= (amiga_font->height << doubled);
for (int ypos = (vparams[vmode].charheight - 1) * vparams[vmode].rows;
......@@ -15125,7 +15125,7 @@ draw_glyph(uint8_t ch)
vparams[vmode].charwidth * vparams[vmode].cols - 1,
(vparams[vmode].charheight - 1) * vparams[vmode].rows - 1,
0,
0,
0, 0, 0,
pix,
NULL);
freepixels(pix);
......@@ -15253,7 +15253,7 @@ do_skypix(char *buf, size_t len)
argv[3] + argv[5] - 1,
argv[4] + argv[6] - 1,
argv[1],
argv[2],
argv[2], 0, 0,
rip.clipboard,
NULL);
break;
......@@ -2,6 +2,7 @@
/* $Id: term.c,v 1.387 2020/06/27 00:04:50 deuce Exp $ */
#include <assert.h>
#include <ciolib.h>
#include <cterm.h>
#include <genwrap.h>
......@@ -53,6 +54,10 @@ static struct vmem_cell winbuf[(TRANSFER_WIN_WIDTH + 2) * (TRANSFER_WIN_HEIGHT +
static struct text_info trans_ti;
static struct text_info log_ti;
static struct ciolib_pixels *pixmap_buffer;
static uint8_t pnm_gamma[256];
bool pnm_gamma_initialized = false;
void
get_cterm_size(int *cols, int *rows, int ns)
{
......@@ -2360,13 +2365,790 @@ clean_path(char *fn, size_t fnsz)
return 1;
}
// ============ This section taken from pnmgamma.c ============
/* pnmgamma.c - perform gamma correction on a PNM image
**
** Copyright (C) 1991 by Bill Davidson and Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation. This software is provided "as is" without express or
** implied warranty.
*/
static void
buildBt709ToSrgbGamma(void) {
uint8_t const maxval = 255;
uint8_t const newMaxval = 255;
double const gammaSrgb = 2.4;
/*----------------------------------------------------------------------------
Build a gamma table of size maxval+1 for the combination of the
inverse of ITU Rec BT.709 and the forward SRGB gamma transfer
functions. I.e. this converts from Rec 709 to SRGB.
'gammaSrgb' must be 2.4 for true SRGB.
-----------------------------------------------------------------------------*/
double const oneOverGamma709 = 0.45;
double const gamma709 = 1.0 / oneOverGamma709;
double const oneOverGammaSrgb = 1.0 / gammaSrgb;
double const normalizer = 1.0 / maxval;
if (pnm_gamma_initialized)
return;
/* This transfer function is linear for sample values 0
.. maxval*.018 and an exponential for larger sample values.
The exponential is slightly stretched and translated, though,
unlike the popular pure exponential gamma transfer function.
*/
uint8_t const linearCutoff709 = (uint8_t) (maxval * 0.018 + 0.5);
double const linearCompression709 =
0.018 / (1.099 * pow(0.018, oneOverGamma709) - 0.099);
double const linearCutoffSrgb = 0.0031308;
double const linearExpansionSrgb =
(1.055 * pow(0.0031308, oneOverGammaSrgb) - 0.055) / 0.0031308;
int i;
for (i = 0; i <= maxval; ++i) {
double const normalized = i * normalizer;
/* Xel sample value normalized to 0..1 */
double radiance;
double srgb;
if (i < linearCutoff709 / linearCompression709)
radiance = normalized * linearCompression709;
else
radiance = pow((normalized + 0.099) / 1.099, gamma709);
assert(radiance <= 1.0);
if (radiance < linearCutoffSrgb * normalizer)
srgb = radiance * linearExpansionSrgb;
else
srgb = 1.055 * pow(normalized, oneOverGammaSrgb) - 0.055;
assert(srgb <= 1.0);
pnm_gamma[i] = srgb * newMaxval + 0.5;
}
pnm_gamma_initialized = true;
}
// ====================== End of section ======================
bool
is_pbm_whitespace(char c)
{
switch(c) {
case ' ':
case '\t':
case '\r':
case '\n':
return true;
}
return false;
}
bool
read_pbm_char(FILE *f, off_t *lastpos, char *ch)
{
if (lastpos != NULL) {
*lastpos = ftello(f);
if (*lastpos == -1)
return false;
}
if (fread(ch, 1, 1, f) != 1)
return false;
return true;
}
bool
skip_pbm_whitespace(FILE *f)
{
char ch;
off_t lastpos;
bool start = true;
for (;;) {
if (!read_pbm_char(f, &lastpos, &ch)) {
return false;
}
if (start) {
if (!is_pbm_whitespace(ch)) {
return false;
}
start = false;
}
if (ch == '#') {
do {
if (!read_pbm_char(f, &lastpos, &ch)) {
return false;
}
} while (ch != '\r' && ch != '\n');
}
if (!is_pbm_whitespace(ch)) {
if (fseeko(f, lastpos, SEEK_SET) != 0)
return false;
return true;
}
}
}
uintmax_t
read_pbm_number(FILE *f)
{
char value[256]; // Should be big enough ;)