X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fanalogtv.c;h=1ff995d2ccef12ac4f2f52cb5abc860cce45418b;hb=f8cf5ac7b2f53510f80a0eaf286a25298be17bfe;hp=86761b7d3656e8a9d31a57b9f9b8534800725eec;hpb=96a411663168b0ba5432b407a83be55f3df0c802;p=xscreensaver diff --git a/hacks/analogtv.c b/hacks/analogtv.c index 86761b7d..1ff995d2 100644 --- a/hacks/analogtv.c +++ b/hacks/analogtv.c @@ -1,4 +1,4 @@ -/* analogtv, Copyright (c) 2003 Trevor Blackwell +/* analogtv, Copyright (c) 2003, 2004 Trevor Blackwell * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -51,8 +51,13 @@ Trevor Blackwell */ -#include -#include +#ifdef HAVE_COCOA +# include "jwxyz.h" +#else /* !HAVE_COCOA */ +# include +# include +#endif + #include #include "utils.h" #include "resources.h" @@ -173,13 +178,13 @@ analogtv_set_defaults(analogtv *it, char *prefix) char buf[256]; sprintf(buf,"%sTVTint",prefix); - it->tint_control = get_float_resource(buf,"TVTint"); + it->tint_control = get_float_resource(it->dpy, buf,"TVTint"); sprintf(buf,"%sTVColor",prefix); - it->color_control = get_float_resource(buf,"TVColor")/100.0; + it->color_control = get_float_resource(it->dpy, buf,"TVColor")/100.0; sprintf(buf,"%sTVBrightness",prefix); - it->brightness_control = get_float_resource(buf,"TVBrightness") / 100.0; + it->brightness_control = get_float_resource(it->dpy, buf,"TVBrightness") / 100.0; sprintf(buf,"%sTVContrast",prefix); - it->contrast_control = get_float_resource(buf,"TVContrast") / 100.0; + it->contrast_control = get_float_resource(it->dpy, buf,"TVContrast") / 100.0; it->height_control = 1.0; it->width_control = 1.0; it->squish_control = 0.0; @@ -235,7 +240,7 @@ analogtv_set_defaults(analogtv *it, char *prefix) extern Bool mono_p; /* shoot me */ -void +static void analogtv_free_image(analogtv *it) { if (it->image) { @@ -250,7 +255,7 @@ analogtv_free_image(analogtv *it) } } -void +static void analogtv_alloc_image(analogtv *it) { if (it->use_shm) { @@ -263,40 +268,95 @@ analogtv_alloc_image(analogtv *it) if (!it->image) { it->image = XCreateImage(it->dpy, it->xgwa.visual, it->xgwa.depth, ZPixmap, 0, 0, it->usewidth, it->useheight, 8, 0); - it->image->data = (char *)calloc(it->image->height, it->image->bytes_per_line); + it->image->data = (char *)malloc(it->image->height * it->image->bytes_per_line); } + memset (it->image->data, 0, it->image->height * it->image->bytes_per_line); } -void +static void analogtv_configure(analogtv *it) { int oldwidth=it->usewidth; int oldheight=it->useheight; - int wlim,hlim,ohlim; + int wlim,hlim,height_diff; + + /* If the window is very small, don't let the image we draw get lower + than the actual TV resolution (266x200.) - hlim=it->xgwa.height; - if (hlim 1000. + */ + float percent = 0.15; /* jwz: 20% caused severe top/bottom clipping + in Pong on 1680x1050 iMac screen. */ + float min_ratio = 4.0 / 3.0 * (1 - percent); + float max_ratio = 4.0 / 3.0 * (1 + percent); + float ratio; + float height_snap=0.025; + + hlim = it->xgwa.height; wlim = it->xgwa.width; - if (wlim<300) wlim = 300; + ratio = wlim / (float) hlim; + +#ifdef USE_IPHONE + /* Fill the whole iPhone screen, even though that distorts the image. */ + min_ratio = 320.0 / 480.0 * (1 - percent); + max_ratio = 480.0 / 320.0 * (1 + percent); +#endif - /* require 3:4 aspect ratio */ - if (wlim > hlim*4/3) wlim=hlim*4/3; - if (hlim > wlim*3/4) hlim=wlim*3/4; + if (wlim < 266 || hlim < 200) + { + wlim = 266; + hlim = 200; +# ifdef DEBUG + fprintf (stderr, + "size: minimal: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, it->xgwa.width, it->xgwa.height, + min_ratio, ratio, max_ratio); +# endif + } + else if (ratio > min_ratio && ratio < max_ratio) + { +# ifdef DEBUG + fprintf (stderr, + "size: close enough: %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, min_ratio, ratio, max_ratio); +# endif + } + else if (ratio > max_ratio) + { + wlim = hlim*max_ratio; +# ifdef DEBUG + fprintf (stderr, + "size: center H: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, it->xgwa.width, it->xgwa.height, + min_ratio, ratio, max_ratio); +# endif + } + else /* ratio < min_ratio */ + { + hlim = wlim/min_ratio; +# ifdef DEBUG + fprintf (stderr, + "size: center V: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n", + wlim, hlim, it->xgwa.width, it->xgwa.height, + min_ratio, ratio, max_ratio); +# endif + } - /* height must be a multiple of VISLINES */ - ohlim=hlim; - hlim = (hlim/ANALOGTV_VISLINES)*ANALOGTV_VISLINES; - /* Scale width proportionally */ - wlim=wlim*hlim/ohlim; + height_diff = ((hlim + ANALOGTV_VISLINES/2) % ANALOGTV_VISLINES) - ANALOGTV_VISLINES/2; + if (height_diff != 0 && fabs(height_diff) < hlim * height_snap) + { + hlim -= height_diff; + } - { - FILE *fp=fopen("/tmp/analogtv.size","w"); - fprintf(fp,"wlim=%d hlim=%d\n", wlim, hlim); - fclose(fp); - } /* Most times this doesn't change */ if (wlim != oldwidth || hlim != oldheight) { @@ -334,6 +394,7 @@ analogtv_allocate(Display *dpy, Window window) analogtv_init(); it=(analogtv *)calloc(1,sizeof(analogtv)); + if (!it) return 0; it->dpy=dpy; it->window=window; @@ -355,7 +416,7 @@ analogtv_allocate(Display *dpy, Window window) it->visbits=it->xgwa.visual->bits_per_rgb; it->visdepth=it->xgwa.depth; if (it->visclass == TrueColor || it->visclass == DirectColor) { - if (get_integer_resource ("use_cmap", "Integer")) { + if (get_integer_resource (it->dpy, "use_cmap", "Integer")) { it->use_cmap=1; } else { it->use_cmap=0; @@ -381,7 +442,7 @@ analogtv_allocate(Display *dpy, Window window) /* Is there a standard way to do this? Does this handle all cases? */ int shift, prec; for (shift=0; shift<32; shift++) { - for (prec=1; prec<16 && prec<32-shift; prec++) { + for (prec=1; prec<16 && prec<40-shift; prec++) { unsigned long mask=(0xffffUL>>(16-prec)) << shift; if (it->red_shift<0 && mask==it->red_mask) it->red_shift=shift, it->red_invprec=16-prec; @@ -406,8 +467,8 @@ analogtv_allocate(Display *dpy, Window window) } - gcv.background=get_pixel_resource("background", "Background", - it->dpy, it->colormap); + gcv.background=get_pixel_resource(it->dpy, it->colormap, + "background", "Background"); it->gc = XCreateGC(it->dpy, it->window, GCBackground, &gcv); XSetWindowBackground(it->dpy, it->window, gcv.background); @@ -439,6 +500,7 @@ analogtv_release(analogtv *it) it->gc=NULL; if (it->n_colors) XFreeColors(it->dpy, it->colormap, it->colors, it->n_colors, 0L); it->n_colors=0; + free(it); } @@ -766,7 +828,7 @@ analogtv_setup_frame(analogtv *it) it->hashnoise_rpm -= 100 + 0.01*it->hashnoise_rpm; if (it->hashnoise_rpm<0.0) it->hashnoise_rpm=0.0; } - if (it->hashnoise_rpm >= 0.0) { + if (it->hashnoise_rpm > 0.0) { int hni; int hnc=it->hashnoise_counter; /* in 24.8 format */ @@ -783,10 +845,11 @@ analogtv_setup_frame(analogtv *it) } hnc += hni + (int)(random()%65536)-32768; } - hnc -= (ANALOGTV_V * ANALOGTV_H)<<8; +/* hnc -= (ANALOGTV_V * ANALOGTV_H)<<8;*/ } - it->agclevel = 1.0/it->rx_signal_level; + if (it->rx_signal_level != 0.0) + it->agclevel = 1.0/it->rx_signal_level; #ifdef DEBUG2 @@ -802,7 +865,7 @@ void analogtv_setup_sync(analogtv_input *input, int do_cb, int do_ssavi) { int i,lineno,vsync; - char *sig; + signed char *sig; int synclevel = do_ssavi ? ANALOGTV_WHITE_LEVEL : ANALOGTV_SYNC_LEVEL; @@ -832,18 +895,18 @@ analogtv_setup_sync(analogtv_input *input, int do_cb, int do_ssavi) } } -void +static void analogtv_sync(analogtv *it) { int cur_hsync=it->cur_hsync; int cur_vsync=it->cur_vsync; - int lineno; + int lineno = 0; int i,j; double osc,filt; double *sp; double cbfc=1.0/128.0; - sp = it->rx_signal + lineno*ANALOGTV_H + cur_hsync; +/* sp = it->rx_signal + lineno*ANALOGTV_H + cur_hsync;*/ for (i=-32; i<32; i++) { lineno = (cur_vsync + i + ANALOGTV_V) % ANALOGTV_V; sp = it->rx_signal + lineno*ANALOGTV_H; @@ -922,7 +985,7 @@ analogtv_sync(analogtv *it) static double analogtv_levelmult(analogtv *it, int level) { - static double levelfac[3]={-7.5, 5.5, 24.5}; + static const double levelfac[3]={-7.5, 5.5, 24.5}; return (40.0 + levelfac[level]*puramp(it, 3.0, 6.0, 1.0))/256.0; } @@ -949,6 +1012,46 @@ analogtv_level(analogtv *it, int y, int ytop, int ybot) return level; } +/* + The point of this stuff is to ensure that when useheight is not a + multiple of VISLINES so that TV scan lines map to different numbers + of vertical screen pixels, the total brightness of each scan line + remains the same. + ANALOGTV_MAX_LINEHEIGHT corresponds to 2400 vertical pixels, beyond which + it interpolates extra black lines. + */ + +static void +analogtv_setup_levels(analogtv *it, double avgheight) +{ + int i,height; + static const double levelfac[3]={-7.5, 5.5, 24.5}; + + for (height=0; heightleveltable[height][i].index = 2; + } + + if (avgheight>=3) { + it->leveltable[height][0].index=0; + } + if (avgheight>=5) { + if (height >= 1) it->leveltable[height][height-1].index=0; + } + if (avgheight>=7) { + it->leveltable[height][1].index=1; + if (height >= 2) it->leveltable[height][height-2].index=1; + } + + for (i=0; ileveltable[height][i].value = + (40.0 + levelfac[it->leveltable[height][i].index]*puramp(it, 3.0, 6.0, 1.0)) / 256.0; + } + + } +} + static void analogtv_blast_imagerow(analogtv *it, float *rgbf, float *rgbf_end, @@ -961,7 +1064,8 @@ analogtv_blast_imagerow(analogtv *it, for (i=0; i<3; i++) level_copyfrom[i]=NULL; for (y=ytop; yleveltable[ybot-ytop][y-ytop].index; + double levelmult=it->leveltable[ybot-ytop][y-ytop].value; char *rowdata; rowdata=it->image->data + y*it->image->bytes_per_line; @@ -978,7 +1082,6 @@ analogtv_blast_imagerow(analogtv *it, memcpy(rowdata, level_copyfrom[level], it->image->bytes_per_line); } else { - double levelmult=analogtv_levelmult(it, level); level_copyfrom[level] = rowdata; if (0) { @@ -1085,7 +1188,7 @@ analogtv_draw(analogtv *it) float *rgb_start, *rgb_end; double pixbright; int pixmultinc; - int bigloadchange,drawcount; + int /*bigloadchange,*/drawcount; double baseload; double puheight; int overall_top, overall_bot; @@ -1094,6 +1197,7 @@ analogtv_draw(analogtv *it) float *raw_rgb_end=raw_rgb_start+3*it->subwidth; float *rrp; + if (! raw_rgb_start) return; analogtv_setup_frame(it); analogtv_set_demod(it); @@ -1109,12 +1213,14 @@ analogtv_draw(analogtv *it) baseload=0.5; /* if (it->hashnoise_on) baseload=0.5; */ - bigloadchange=1; + /*bigloadchange=1;*/ drawcount=0; it->crtload[ANALOGTV_TOP-1]=baseload; puheight = puramp(it, 2.0, 1.0, 1.3) * it->height_control * (1.125 - 0.125*puramp(it, 2.0, 2.0, 1.1)); + analogtv_setup_levels(it, puheight * (double)it->useheight/(double)ANALOGTV_VISLINES); + overall_top=it->useheight; overall_bot=0; @@ -1137,12 +1243,14 @@ analogtv_draw(analogtv *it) if (ytop<0) ytop=0; if (ybot>it->useheight) ybot=it->useheight; + if (ybot > ytop+ANALOGTV_MAX_LINEHEIGHT) ybot=ytop+ANALOGTV_MAX_LINEHEIGHT; + if (ytop < overall_top) overall_top=ytop; if (ybot > overall_bot) overall_bot=ybot; if (lineno==it->shrinkpulse) { baseload += 0.4; - bigloadchange=1; + /*bigloadchange=1;*/ it->shrinkpulse=-1; } @@ -1195,7 +1303,7 @@ analogtv_draw(analogtv *it) { int totsignal=0; - double ncl,diff; + double ncl/*,diff*/; for (i=0; i184 ? (slineno-184)*(lineno-184)*0.001 * it->squeezebottom : 0.0)); - diff=ncl - it->crtload[lineno]; - bigloadchange = (diff>0.01 || diff<-0.01); + /*diff=ncl - it->crtload[lineno];*/ + /*bigloadchange = (diff>0.01 || diff<-0.01);*/ it->crtload[lineno]=ncl; } @@ -1464,8 +1572,6 @@ analogtv_draw(analogtv *it) it->last_display_time=tv; } #endif - - XSync(it->dpy,0); } analogtv_input * @@ -1493,19 +1599,21 @@ analogtv_load_ximage(analogtv *it, analogtv_input *input, XImage *pic_im) XColor col1[ANALOGTV_PIC_LEN]; XColor col2[ANALOGTV_PIC_LEN]; int multiq[ANALOGTV_PIC_LEN+4]; + 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; - + for (i=0; i>14) + ANALOGTV_BLACK_LEVEL; if (composite>125) composite=125; if (composite<0) composite=0; - input->signal[y+ANALOGTV_TOP][x+ANALOGTV_PIC_START] = composite; + input->signal[y-y_overscan+ANALOGTV_TOP][x+ANALOGTV_PIC_START] = composite; } } @@ -1618,9 +1726,9 @@ void analogtv_add_signal(analogtv *it, analogtv_reception *rec) double *ps=it->rx_signal; double *pe=it->rx_signal + ANALOGTV_SIGNAL_LEN; double *p=ps; - char *ss=&inp->signal[0][0]; - char *se=&inp->signal[0][0] + ANALOGTV_SIGNAL_LEN; - char *s=ss + ((unsigned)rec->ofs % ANALOGTV_SIGNAL_LEN); + signed char *ss=&inp->signal[0][0]; + signed char *se=&inp->signal[0][0] + ANALOGTV_SIGNAL_LEN; + signed char *s=ss + ((unsigned)rec->ofs % ANALOGTV_SIGNAL_LEN); int i; int ec=it->channel_change_cycles; double level=rec->level; @@ -1783,6 +1891,11 @@ analogtv_reception_update(analogtv_reception *rec) } +/* jwz: since MacOS doesn't have "6x10", I dumped this font to an XBM... + */ + +#include "images/6x10font.xbm" + void analogtv_make_font(Display *dpy, Window window, analogtv_font *f, int w, int h, char *fontname) @@ -1799,7 +1912,18 @@ analogtv_make_font(Display *dpy, Window window, analogtv_font *f, XGetWindowAttributes (dpy, window, &xgwa); - if (fontname) { + 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); + + } else if (fontname) { font = XLoadQueryFont (dpy, fontname); if (!font) { @@ -1807,7 +1931,7 @@ analogtv_make_font(Display *dpy, Window window, analogtv_font *f, abort(); } - text_pm=XCreatePixmap(dpy, window, 128*f->char_w, f->char_h, xgwa.depth); + text_pm=XCreatePixmap(dpy, window, 256*f->char_w, f->char_h, 1); memset(&gcv, 0, sizeof(gcv)); gcv.foreground=1; @@ -1816,23 +1940,25 @@ analogtv_make_font(Display *dpy, Window window, analogtv_font *f, gc=XCreateGC(dpy, text_pm, GCFont|GCBackground|GCForeground, &gcv); XSetForeground(dpy, gc, 0); - XFillRectangle(dpy, text_pm, gc, 0, 0, 128*f->char_w, f->char_h); + XFillRectangle(dpy, text_pm, gc, 0, 0, 256*f->char_w, f->char_h); XSetForeground(dpy, gc, 1); - /* Just ASCII */ - for (i=0; i<128; i++) { + for (i=0; i<256; i++) { char c=i; int x=f->char_w*i+1; int y=f->char_h*8/10; XDrawString(dpy, text_pm, gc, x, y, &c, 1); } - f->text_im = XGetImage(dpy, text_pm, 0, 0, 128*f->char_w, f->char_h, - ~0L, ZPixmap); + f->text_im = XGetImage(dpy, text_pm, 0, 0, 256*f->char_w, f->char_h, + 1, XYPixmap); +# if 0 + XWriteBitmapFile(dpy, "/tmp/tvfont.xbm", text_pm, + 256*f->char_w, f->char_h, -1, -1); +# endif XFreeGC(dpy, gc); XFreePixmap(dpy, text_pm); } else { - f->text_im = XCreateImage(dpy, xgwa.visual, xgwa.depth, - ZPixmap, 0, 0, - 128*f->char_w, f->char_h, 8, 0); + f->text_im = XCreateImage(dpy, xgwa.visual, 1, XYPixmap, 0, 0, + 256*f->char_w, f->char_h, 8, 0); f->text_im->data = (char *)calloc(f->text_im->height, f->text_im->bytes_per_line); @@ -1846,7 +1972,7 @@ analogtv_font_pixel(analogtv_font *f, int c, int x, int y) { if (x<0 || x>=f->char_w) return 0; if (y<0 || y>=f->char_h) return 0; - if (c<0 || c>=128) return 0; + if (c<0 || c>=256) return 0; return XGetPixel(f->text_im, c*f->char_w + x, y) ? 1 : 0; } @@ -1855,7 +1981,7 @@ analogtv_font_set_pixel(analogtv_font *f, int c, int x, int y, int value) { if (x<0 || x>=f->char_w) return; if (y<0 || y>=f->char_h) return; - if (c<0 || c>=128) return; + if (c<0 || c>=256) return; XPutPixel(f->text_im, c*f->char_w + x, y, value); } @@ -1865,7 +1991,7 @@ analogtv_font_set_char(analogtv_font *f, int c, char *s) { int value,x,y; - if (c<0 || c>=128) return; + if (c<0 || c>=256) return; for (y=0; ychar_h; y++) { for (x=0; xchar_w; x++) { @@ -2081,58 +2207,3 @@ analogtv_draw_xpm(analogtv *tv, analogtv_input *input, } } } - -extern XtAppContext app; - -int -analogtv_handle_events (analogtv *it) -{ - XSync(it->dpy, False); - if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput)) - XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput); - - while (XPending (it->dpy)) - { - XEvent event; - XNextEvent (it->dpy, &event); - switch (event.xany.type) - { - case ButtonPress: - return 1; - - case KeyPress: - { - KeySym keysym; - char c = 0; - XLookupString (&event.xkey, &c, 1, &keysym, 0); - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - return 1; - } - break; - - /* I don't seem to get an event when clicking the "full - screen" window manager icon, at least when using - metacity. Thus, it doesn't change the video size. Is this - some separate WM_* message I have to deal with? - */ - case ConfigureNotify: - if (event.xconfigure.width != it->xgwa.width || - event.xconfigure.height != it->xgwa.height) - analogtv_reconfigure(it); - break; - - case Expose: - case GraphicsExpose: - it->need_clear=1; - break; - - default: - break; - } - if (it->event_handler) { - (*it->event_handler) (it->dpy, &event); - } - } - return 0; -} -