-/* analogtv, Copyright (c) 2003, 2004 Trevor Blackwell <tlb@tlb.org>
+/* analogtv, Copyright (c) 2003-2018 Trevor Blackwell <tlb@tlb.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
#include "yarandom.h"
#include "grabscreen.h"
#include "visual.h"
+#include "font-retry.h"
+#include "ximage-loader.h"
/* #define DEBUG 1 */
"background", "Background");
it->gc = XCreateGC(it->dpy, it->window, GCBackground, &gcv);
+# ifdef HAVE_JWXYZ
+ jwxyz_XSetAntiAliasing (it->dpy, it->gc, False);
+# endif
XSetWindowBackground(it->dpy, it->window, gcv.background);
XClearWindow(dpy,window);
This takes a screen image and encodes it as a video camera would,
including all the bandlimiting and YIQ modulation.
This isn't especially tuned for speed.
+
+ xoff, yoff: top left corner of rendered image, in window pixels.
+ w, h: scaled size of rendered image, in window pixels.
+ mask: BlackPixel means don't render (it's not full alpha)
*/
int
-analogtv_load_ximage(analogtv *it, analogtv_input *input, XImage *pic_im)
+analogtv_load_ximage(analogtv *it, analogtv_input *input,
+ XImage *pic_im, XImage *mask_im,
+ int xoff, int yoff, int target_w, int target_h)
{
int i,x,y;
int img_w,img_h;
int fqx[4],fqy[4];
XColor col1[ANALOGTV_PIC_LEN];
XColor col2[ANALOGTV_PIC_LEN];
+ char mask[ANALOGTV_PIC_LEN];
int multiq[ANALOGTV_PIC_LEN+4];
+ unsigned long black = 0; /* not BlackPixelOfScreen (it->xgwa.screen); */
+
+ int x_length=ANALOGTV_PIC_LEN;
int y_overscan=5; /* overscan this much top and bottom */
int y_scanlength=ANALOGTV_VISLINES+2*y_overscan;
- img_w=pic_im->width;
- img_h=pic_im->height;
+ if (target_w > 0) x_length = x_length * target_w / it->xgwa.width;
+ if (target_h > 0) y_scanlength = y_scanlength * target_h / it->xgwa.height;
+
+ img_w = pic_im->width;
+ img_h = pic_im->height;
- for (i=0; i<ANALOGTV_PIC_LEN+4; i++) {
+ xoff = ANALOGTV_PIC_LEN * xoff / it->xgwa.width;
+ yoff = ANALOGTV_VISLINES * yoff / it->xgwa.height;
+
+ for (i=0; i<x_length+4; i++) {
double phase=90.0-90.0*i;
double ampl=1.0;
multiq[i]=(int)(-cos(3.1415926/180.0*(phase-303)) * 4096.0 * ampl);
int picy1=(y*img_h)/y_scanlength;
int picy2=(y*img_h + y_scanlength/2)/y_scanlength;
- for (x=0; x<ANALOGTV_PIC_LEN; x++) {
- int picx=(x*img_w)/ANALOGTV_PIC_LEN;
+ for (x=0; x<x_length; x++) {
+ int picx=(x*img_w)/x_length;
col1[x].pixel=XGetPixel(pic_im, picx, picy1);
col2[x].pixel=XGetPixel(pic_im, picx, picy2);
+ if (mask_im)
+ mask[x] = (XGetPixel(mask_im, picx, picy1) != black);
+ else
+ mask[x] = 1;
}
- XQueryColors(it->dpy, it->colormap, col1, ANALOGTV_PIC_LEN);
- XQueryColors(it->dpy, it->colormap, col2, ANALOGTV_PIC_LEN);
-
+ XQueryColors(it->dpy, it->colormap, col1, x_length);
+ XQueryColors(it->dpy, it->colormap, col2, x_length);
for (i=0; i<7; i++) fyx[i]=fyy[i]=0;
for (i=0; i<4; i++) fix[i]=fiy[i]=fqx[i]=fqy[i]=0.0;
- for (x=0; x<ANALOGTV_PIC_LEN; x++) {
+ for (x=0; x<x_length; x++) {
int rawy,rawi,rawq;
int filty,filti,filtq;
int composite;
+
+ if (!mask[x]) continue;
+
/* Compute YIQ as:
y=0.30 r + 0.59 g + 0.11 b
i=0.60 r - 0.28 g - 0.32 b
composite = ((composite*100)>>14) + ANALOGTV_BLACK_LEVEL;
if (composite>125) composite=125;
if (composite<0) composite=0;
- input->signal[y-y_overscan+ANALOGTV_TOP][x+ANALOGTV_PIC_START] = composite;
+
+ input->signal[y-y_overscan+ANALOGTV_TOP+yoff][x+ANALOGTV_PIC_START+xoff] = composite;
}
}
}
-/* jwz: since MacOS doesn't have "6x10", I dumped this font to an XBM...
+/* jwz: since MacOS doesn't have "6x10", I dumped this font to a PNG...
*/
-#include "images/6x10font.xbm"
+#include "images/gen/6x10font_png.h"
void
analogtv_make_font(Display *dpy, Window window, analogtv_font *f,
if (fontname && !strcmp (fontname, "6x10")) {
- text_pm = XCreatePixmapFromBitmapData (dpy, window,
- (char *) font6x10_bits,
- font6x10_width,
- font6x10_height,
- 1, 0, 1);
- f->text_im = XGetImage(dpy, text_pm, 0, 0, font6x10_width, font6x10_height,
- 1, XYPixmap);
- XFreePixmap(dpy, text_pm);
+ int pix_w, pix_h;
+ XWindowAttributes xgwa;
+ Pixmap m = 0;
+ Pixmap p = image_data_to_pixmap (dpy, window,
+ _6x10font_png, sizeof(_6x10font_png),
+ &pix_w, &pix_h, &m);
+ XImage *im = XGetImage (dpy, p, 0, 0, pix_w, pix_h, ~0L, ZPixmap);
+ XImage *mm = XGetImage (dpy, m, 0, 0, pix_w, pix_h, 1, XYPixmap);
+ unsigned long black = BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
+ int x, y;
+
+ XFreePixmap (dpy, p);
+ XFreePixmap (dpy, m);
+ if (pix_w != 256*7) abort();
+ if (pix_h != 10) abort();
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ f->text_im = XCreateImage (dpy, xgwa.visual, 1, XYBitmap, 0, 0,
+ pix_w, pix_h, 8, 0);
+ f->text_im->data = malloc (f->text_im->bytes_per_line * f->text_im->height);
+
+ /* Convert deep image to 1 bit */
+ for (y = 0; y < pix_h; y++)
+ for (x = 0; x < pix_w; x++)
+ XPutPixel (f->text_im, x, y,
+ (XGetPixel (mm, x, y)
+ ? XGetPixel (im, x, y) == black
+ : 0));
+ XDestroyImage (im);
+ XDestroyImage (mm);
} else if (fontname) {
- font = XLoadQueryFont (dpy, fontname);
+ font = load_font_retry (dpy, fontname);
if (!font) {
fprintf(stderr, "analogtv: can't load font %s\n", fontname);
abort();
gcv.background=0;
gcv.font=font->fid;
gc=XCreateGC(dpy, text_pm, GCFont|GCBackground|GCForeground, &gcv);
+# ifdef HAVE_JWXYZ
+ jwxyz_XSetAntiAliasing (dpy, gc, False);
+# endif
XSetForeground(dpy, gc, 0);
XFillRectangle(dpy, text_pm, gc, 0, 0, 256*f->char_w, f->char_h);
analogtv_draw_string(input, f, s, x, y, ntsc);
}
-
-
-static const char hextonib[128] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
- 0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-/*
- Much of this function was adapted from logo.c
- */
-void
-analogtv_draw_xpm(analogtv *tv, analogtv_input *input,
- const char * const *xpm, int left, int top)
-{
- int xpmw,xpmh;
- int x,y,tvx,tvy,i;
- int rawy,rawi,rawq;
- int ncolors, nbytes;
- char dummyc;
- struct {
- int r; int g; int b;
- } cmap[256];
-
-
- if (4 != sscanf ((const char *) *xpm,
- "%d %d %d %d %c",
- &xpmw, &xpmh, &ncolors, &nbytes, &dummyc))
- abort();
- if (ncolors < 1 || ncolors > 255)
- abort();
- if (nbytes != 1) /* a serious limitation */
- abort();
- xpm++;
-
- for (i = 0; i < ncolors; i++) {
- const char *line = *xpm;
- int colori = ((unsigned char)*line++)&0xff;
- while (*line)
- {
- int r, g, b;
- char which;
- while (*line == ' ' || *line == '\t')
- line++;
- which = *line++;
- if (which != 'c' && which != 'm')
- abort();
- while (*line == ' ' || *line == '\t')
- line++;
- if (!strncasecmp(line, "None", 4))
- {
- r = g = b = -1;
- line += 4;
- }
- else
- {
- if (*line == '#')
- line++;
- r = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
- line += 2;
- g = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
- line += 2;
- b = (hextonib[(int) line[0]] << 4) | hextonib[(int) line[1]];
- line += 2;
- }
-
- if (which == 'c')
- {
- cmap[colori].r = r;
- cmap[colori].g = g;
- cmap[colori].b = b;
- }
- }
-
- xpm++;
- }
-
- for (y=0; y<xpmh; y++) {
- const char *line = *xpm++;
- tvy=y+top;
- if (tvy<ANALOGTV_TOP || tvy>=ANALOGTV_BOT) continue;
-
- for (x=0; x<xpmw; x++) {
- int cbyte=((unsigned char)line[x])&0xff;
- int ntsc[4];
- tvx=x*4+left;
- if (tvx<ANALOGTV_PIC_START || tvx+4>ANALOGTV_PIC_END) continue;
-
- rawy=( 5*cmap[cbyte].r + 11*cmap[cbyte].g + 2*cmap[cbyte].b) / 64;
- rawi=(10*cmap[cbyte].r - 4*cmap[cbyte].g - 5*cmap[cbyte].b) / 64;
- rawq=( 3*cmap[cbyte].r - 8*cmap[cbyte].g + 5*cmap[cbyte].b) / 64;
-
- ntsc[0]=rawy+rawq;
- ntsc[1]=rawy-rawi;
- ntsc[2]=rawy-rawq;
- ntsc[3]=rawy+rawi;
-
- for (i=0; i<4; i++) {
- if (ntsc[i]>ANALOGTV_WHITE_LEVEL) ntsc[i]=ANALOGTV_WHITE_LEVEL;
- if (ntsc[i]<ANALOGTV_BLACK_LEVEL) ntsc[i]=ANALOGTV_BLACK_LEVEL;
- }
-
- input->signal[tvy][tvx+0]= ntsc[(tvx+0)&3];
- input->signal[tvy][tvx+1]= ntsc[(tvx+1)&3];
- input->signal[tvy][tvx+2]= ntsc[(tvx+2)&3];
- input->signal[tvy][tvx+3]= ntsc[(tvx+3)&3];
- }
- }
-}