1 /* interference.c --- colored fields via decaying sinusoidal waves.
2 * An entry for the RHAD Labs Screensaver Contest.
4 * Author: Hannu Mallat <hmallat@cs.hut.fi>
6 * Copyright (C) 1998 Hannu Mallat.
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notice appear in all copies and that both that
11 * copyright notice and this permission notice appear in supporting
12 * documentation. No representations are made about the suitability of this
13 * software for any purpose. It is provided "as is" without express or
16 * decaying sinusoidal waves, which extend spherically from their
17 * respective origins, move around the plane. a sort of interference
18 * between them is calculated and the resulting twodimensional wave
19 * height map is plotted in a grid, using softly changing colours.
21 * not physically (or in any sense) accurate, but fun to look at for
22 * a while. you may tune the speed/resolution/interestingness tradeoff
23 * with X resources, see below.
25 * Created : Wed Apr 22 09:30:30 1998, hmallat
26 * Last modified: Wed Apr 22 09:30:30 1998, hmallat
27 * Last modified: Sun Aug 31 23:40:14 2003,
28 * david slimp <rock808@DavidSlimp.com>
29 * added -hue option to specify base color hue
30 * Last modified: Wed May 15 00:04:43 2013,
31 * Dave Odell <dmo2118@gmail.com>
32 * Tuned performance; double-buffering is now off by default.
33 * Made animation speed independent of FPS.
34 * Added cleanup code, fixed a few glitches.
35 * Added gratuitous #ifdefs.
41 #include "screenhack.h"
47 typedef unsigned int uint32_t;
48 typedef unsigned short uint16_t;
49 typedef unsigned char uint8_t;
54 Tested on an Intel(R) Pentium(R) 4 CPU 3.00GHz (family 15, model 6, 2 cores),
55 1 GB PC2-4200, nouveau - Gallium 0.4 on NV44, X.Org version: 1.13.3. A very
56 modest system by current standards.
58 Does double-buffering make sense? (gridsize = 2)
59 USE_XIMAGE is off: Yes (-db: 4.1 FPS, -no-db: 2.9 FPS)
60 XPutImage in strips: No (-db: 35.9 FPS, -no-db: 38.7 FPS)
61 XPutImage, whole image: No (-db: 32.3 FPS, -no-db: 33.7 FPS)
62 MIT-SHM, whole image: Doesn't work anyway: (37.3 FPS)
64 If gridsize = 1, XPutImage is slow when the XImage is one line at a time.
65 XPutImage in strips: -db: 21.2 FPS, -no-db: 19.7 FPS
66 XPutimage, whole image: -db: 23.2 FPS, -no-db: 23.4 FPS
69 So XPutImage in strips is very slightly faster when gridsize >= 2, but
70 quite a bit worse when gridsize = 1.
73 /* I thought it would be faster this way, but it turns out not to be... -jwz */
74 /* It's a lot faster for me, though - D.O. */
77 /* i.e. make the XImage the size of the screen. This is much faster when
78 * gridsize = 1. (And SHM is turned off.) */
79 #define USE_BIG_XIMAGE
81 /* Numbers are wave_table size, measured in unsigned integers.
82 * FPS/radius = 50/radius = 800/radius = 1500/Big-O memory usage
84 * Use at most one of the following:
85 * Both off = regular sqrt() - 13.5 FPS, 50/800/1500. */
87 /* #define USE_FAST_SQRT_HACKISH */ /* 17.8 FPS/2873/4921/5395/O(lg(radius)) */
88 #define USE_FAST_SQRT_BIGTABLE2 /* 26.1 FPS/156/2242/5386/O(radius^2) */
91 # undef HAVE_XSHM_EXTENSION /* only applicable when using XImages */
92 #endif /* USE_XIMAGE */
94 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
96 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
98 #ifdef HAVE_XSHM_EXTENSION
100 #endif /* HAVE_XSHM_EXTENSION */
102 static const char *interference_defaults [] = {
103 ".background: black",
104 ".foreground: white",
105 "*count: 3", /* number of waves */
106 "*gridsize: 4", /* pixel size, smaller values for better resolution */
107 "*ncolors: 128", /* number of colours used */
108 "*hue: 0", /* hue to use for base color (0-360) */
109 "*speed: 30", /* speed of wave origins moving around */
110 "*delay: 30000", /* or something */
111 "*color-shift: 60", /* h in hsv space, smaller values for smaller
113 "*radius: 800", /* wave extent */
114 "*gray: false", /* color or grayscale */
115 "*mono: false", /* monochrome, not very much fun */
117 "*doubleBuffer: False", /* doubleBuffer slows things down for me - D.O. */
118 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
119 "*useDBE: True", /* use double buffering extension */
120 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
122 #ifdef HAVE_XSHM_EXTENSION
123 "*useSHM: True", /* use shared memory extension */
124 #endif /* HAVE_XSHM_EXTENSION */
126 "*ignoreRotation: True",
131 static XrmOptionDescRec interference_options [] = {
132 { "-count", ".count", XrmoptionSepArg, 0 },
133 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
134 { "-gridsize", ".gridsize", XrmoptionSepArg, 0 },
135 { "-hue", ".hue", XrmoptionSepArg, 0 },
136 { "-speed", ".speed", XrmoptionSepArg, 0 },
137 { "-delay", ".delay", XrmoptionSepArg, 0 },
138 { "-color-shift", ".color-shift", XrmoptionSepArg, 0 },
139 { "-radius", ".radius", XrmoptionSepArg, 0 },
140 { "-gray", ".gray", XrmoptionNoArg, "True" },
141 { "-mono", ".mono", XrmoptionNoArg, "True" },
142 { "-db", ".doubleBuffer", XrmoptionNoArg, "True" },
143 { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" },
144 #ifdef HAVE_XSHM_EXTENSION
145 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
146 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
147 #endif /* HAVE_XSHM_EXTENSION */
151 struct inter_source {
158 struct inter_context {
160 * Display-related entries
165 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
166 XdbeBackBuffer back_buf;
167 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
173 #endif /* USE_XIMAGE */
175 #ifdef HAVE_XSHM_EXTENSION
176 Bool use_shm, shm_can_draw;
177 XShmSegmentInfo shm_info;
178 #endif /* HAVE_XSHM_EXTENSION */
192 * Drawing-related entries
202 int radius; /* Not always the same as the X resource. */
211 unsigned* wave_height;
214 * Interference sources
216 struct inter_source* source;
219 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
220 # define TARGET(c) ((c)->back_buf ? (c)->back_buf : \
221 (c)->pix_buf ? (c)->pix_buf : (c)->win)
222 #else /* HAVE_DOUBLE_BUFFER_EXTENSION */
223 # define TARGET(c) ((c)->pix_buf ? (c)->pix_buf : (c)->win)
224 #endif /* !HAVE_DOUBLE_BUFFER_EXTENSION */
226 #ifdef USE_FAST_SQRT_HACKISH
227 /* Based loosely on code from Wikipedia:
228 * https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Approximations_that_depend_on_IEEE_representation
231 /* FAST_SQRT_EXTRA_BITS = 3: Smallest useful value
232 * = 5/6: A little bit of banding, wave_height table is on par with regular
234 * = 7: No apparent difference with original @ radius = 800.
235 * = 8: One more just to be comfortable.
238 # define FAST_SQRT_EXTRA_BITS 8
246 static unsigned fast_log2(unsigned x)
252 return ((u.i - 0x3f800000) >> (23 - FAST_SQRT_EXTRA_BITS)) + 1;
255 static float fast_inv_log2(unsigned x)
260 u.i = ((x - 1) << (23 - FAST_SQRT_EXTRA_BITS)) + 0x3f800000;
266 #ifdef USE_FAST_SQRT_BIGTABLE2
268 /* I eyeballed these figures. They could be improved. - D.O. */
270 # define FAST_SQRT_DISCARD_BITS1 4
271 /* = 5: Dot in center is almost invisible at radius = 800. */
272 /* = 4: Dot in center looks OK at radius = 50. */
275 /* # define FAST_SQRT_DISCARD_BITS2 8 */
276 /* # define FAST_SQRT_CUTOFF 64 * 64 */
279 # define FAST_SQRT_DISCARD_BITS2 9
280 # define FAST_SQRT_CUTOFF 128 * 128
283 * This is a little faster:
284 * 44.5 FPS, 19/5000/17578
286 * # define FAST_SQRT_DISCARD_BITS1 7
287 * # define FAST_SQRT_DISCARD_BITS2 7
288 * # define FAST_SQRT_CUTOFF 0
290 * For radius = 800, FAST_SQRT_DISCARD_BITS2 =
291 * = 9/10: Approximately the original table size, some banding near origins.
292 * = 7: wave_height is 20 KB, and just fits inside a 32K L1 cache.
293 * = 6: Nearly indistinguishable from original
297 FAST_TABLE(x) is equivalent to, but slightly faster than:
298 x < FAST_SQRT_CUTOFF ?
299 (x >> FAST_SQRT_DISCARD_BITS1) :
300 ((x - FAST_SQRT_CUTOFF) >> FAST_SQRT_DISCARD_BITS2) +
301 (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1);
304 #define FAST_TABLE(x) \
305 ((x) < FAST_SQRT_CUTOFF ? \
306 ((x) >> FAST_SQRT_DISCARD_BITS1) : \
308 ((FAST_SQRT_CUTOFF << (FAST_SQRT_DISCARD_BITS2 - \
309 FAST_SQRT_DISCARD_BITS1)) - FAST_SQRT_CUTOFF)) >> \
310 FAST_SQRT_DISCARD_BITS2))
312 static double fast_inv_table(unsigned x)
314 return x < (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1) ?
315 (x << FAST_SQRT_DISCARD_BITS1) :
316 ((x - (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1)) <<
317 FAST_SQRT_DISCARD_BITS2) + FAST_SQRT_CUTOFF;
322 /* Also destroys c->row. */
323 static void destroy_image(Display* dpy, struct inter_context* c)
327 # ifdef HAVE_XSHM_EXTENSION
329 destroy_xshm_image(dpy, c->ximage, &c->shm_info);
333 /* Also frees c->ximage->data, which isn't allocated by XCreateImage. */
334 XDestroyImage(c->ximage);
342 static void inter_free(Display* dpy, struct inter_context* c)
349 XFreePixmap(dpy, c->pix_buf);
352 XFreeGC(dpy, c->copy_gc);
354 destroy_image(dpy, c);
359 free_colors(c->screen, c->cmap, c->pal, c->colors);
362 for(i = 0; i != c->colors; ++i)
363 XFreeGC(dpy, c->gcs[i]);
367 free(c->wave_height);
371 static void abort_no_mem(void)
373 fprintf(stderr, "interference: %s\n", strerror(ENOMEM));
377 static void check_no_mem(Display* dpy, struct inter_context* c, void* ptr)
385 /* On allocation error, c->row == NULL. */
386 static void create_image(
388 struct inter_context* c,
389 const XWindowAttributes* xgwa)
392 c->row = malloc((c->w / c->grid_size) * sizeof(uint32_t));
393 check_no_mem(dpy, c, c->row);
395 # ifdef HAVE_XSHM_EXTENSION
397 * interference used to put one row at a time to the X server. This changes
400 * XShmPutImage is asynchronous; the contents of the XImage must not be
401 * modified until the server has placed the data on the screen. Waiting for
402 * an XShmCompletionEvent after every line of pixels is a little nutty, so
403 * shared-memory XImages will cover the entire screen, and it only has to be
404 * sent once per frame.
406 * The non-SHM code, on the other hand is noticeably slower when
407 * gridsize = 1 with one row at a time. If, on the other hand, gridsize >= 2,
408 * there's a slight speed increase with one row at a time.
410 * This uses a lot more RAM than the single line approach. Users with only
411 * 4 MB of RAM may wish to disable USE_BIG_XIMAGE and specify -no-shm on the
412 * command line. Since this is 2013 and desktop computers are shipping with
413 * 8 GB of RAM, I doubt that this will be a major issue. - D.O.
418 c->ximage = create_xshm_image(dpy, xgwa->visual, xgwa->depth,
419 ZPixmap, 0, &c->shm_info,
420 xgwa->width, xgwa->height);
423 /* If create_xshm_image fails, it will not be attempted again. */
425 c->shm_can_draw = True;
427 # endif /* HAVE_XSHM_EXTENSION */
432 XCreateImage(dpy, xgwa->visual,
433 xgwa->depth, ZPixmap, 0, 0, /* depth, fmt, offset, data */
434 xgwa->width, /* width */
435 # ifdef USE_BIG_XIMAGE
436 xgwa->height, /* height */
438 c->grid_size, /* height */
440 8, 0); /* pad, bpl */
444 c->ximage->data = (char *)
445 calloc(c->ximage->height, c->ximage->bytes_per_line);
461 check_no_mem(dpy, c, c->row);
462 #endif /* USE_XIMAGE */
465 static void create_pix_buf(Display* dpy, Window win, struct inter_context *c,
466 const XWindowAttributes* xgwa)
468 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
471 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
472 c->pix_buf = XCreatePixmap(dpy, win, xgwa->width, xgwa->height, xgwa->depth);
475 static double float_time(void)
477 struct timeval result;
480 #ifdef GETTIMEOFDAY_TWO_ARGS
485 return result.tv_usec * 1.0e-6 + result.tv_sec;
488 static void inter_init(Display* dpy, Window win, struct inter_context* c)
490 XWindowAttributes xgwa;
491 double H[3], S[3], V[3];
497 Bool dbuf = get_boolean_resource (dpy, "doubleBuffer", "Boolean");
500 unsigned long valmask = 0;
503 # ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
507 memset (c, 0, sizeof(*c));
512 c->delay = get_integer_resource(dpy, "delay", "Integer");
514 XGetWindowAttributes(c->dpy, c->win, &xgwa);
517 c->cmap = xgwa.colormap;
518 c->screen = xgwa.screen;
520 #ifdef HAVE_XSHM_EXTENSION
521 c->use_shm = get_boolean_resource(dpy, "useSHM", "Boolean");
522 #endif /* HAVE_XSHM_EXTENSION */
524 val.function = GXcopy;
525 c->copy_gc = XCreateGC(c->dpy, TARGET(c), GCFunction, &val);
527 c->count = get_integer_resource(dpy, "count", "Integer");
530 c->grid_size = get_integer_resource(dpy, "gridsize", "Integer");
533 mono = get_boolean_resource(dpy, "mono", "Boolean");
535 c->colors = get_integer_resource(dpy, "ncolors", "Integer");
539 c->hue = get_integer_resource(dpy, "hue", "Float");
540 while (c->hue < 0 || c->hue >= 360)
541 c->hue = frand(360.0);
542 c->speed = get_integer_resource(dpy, "speed", "Integer");
543 c->shift = get_float_resource(dpy, "color-shift", "Float");
544 while(c->shift >= 360.0)
546 while(c->shift <= -360.0)
548 radius = get_integer_resource(dpy, "radius", "Integer");;
552 create_image(dpy, c, &xgwa);
555 c->pal = calloc(c->colors, sizeof(XColor));
556 check_no_mem(dpy, c, c->pal);
558 gray = get_boolean_resource(dpy, "gray", "Boolean");
561 H[1] = H[0] + c->shift < 360.0 ? H[0]+c->shift : H[0] + c->shift-360.0;
562 H[2] = H[1] + c->shift < 360.0 ? H[1]+c->shift : H[1] + c->shift-360.0;
563 S[0] = S[1] = S[2] = 1.0;
564 V[0] = V[1] = V[2] = 1.0;
566 H[0] = H[1] = H[2] = 0.0;
567 S[0] = S[1] = S[2] = 0.0;
568 V[0] = 1.0; V[1] = 0.5; V[2] = 0.0;
571 make_color_loop(c->screen, xgwa.visual, c->cmap,
575 c->pal, &(c->colors),
577 if(c->colors < 2) { /* color allocation failure */
583 if(mono) { /* DON'T else this with the previous if! */
585 c->pal = calloc(2, sizeof(XColor));
586 check_no_mem(dpy, c, c->pal);
587 c->pal[0].pixel = BlackPixel(c->dpy, DefaultScreen(c->dpy));
588 c->pal[1].pixel = WhitePixel(c->dpy, DefaultScreen(c->dpy));
591 #ifdef HAVE_XSHM_EXTENSION
594 /* Double-buffering doesn't work with MIT-SHM: XShmPutImage must draw to the
595 * window. Otherwise, XShmCompletion events will have the XAnyEvent::window
596 * field set to the back buffer, and XScreenSaver will ignore the event. */
601 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
602 c->back_buf = xdbe_get_backbuffer (c->dpy, c->win, XdbeUndefined);
603 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
605 create_pix_buf(dpy, win, c, &xgwa);
609 valmask = GCForeground;
610 c->gcs = calloc(c->colors, sizeof(GC));
611 check_no_mem(dpy, c, c->gcs);
612 for(i = 0; i < c->colors; i++) {
613 val.foreground = c->pal[i].pixel;
614 c->gcs[i] = XCreateGC(c->dpy, TARGET(c), valmask, &val);
618 #if defined USE_FAST_SQRT_HACKISH
619 c->radius = fast_log2(radius * radius);
620 #elif defined USE_FAST_SQRT_BIGTABLE2
621 c->radius = radius * radius;
622 c->radius = FAST_TABLE(c->radius);
627 c->wave_height = calloc(c->radius, sizeof(unsigned));
628 check_no_mem(dpy, c, c->wave_height);
630 for(i = 0; i < c->radius; i++) {
632 #if defined USE_FAST_SQRT_HACKISH
633 fi = sqrt(fast_inv_log2(i));
634 #elif defined USE_FAST_SQRT_BIGTABLE2
635 fi = sqrt(fast_inv_table(i));
641 ((float)radius - fi) /
645 ((max + max*cos(fi/50.0)) / 2.0);
648 c->source = calloc(c->count, sizeof(struct inter_source));
649 check_no_mem(dpy, c, c->source);
651 for(i = 0; i < c->count; i++) {
652 c->source[i].x_theta = frand(2.0)*3.14159;
653 c->source[i].y_theta = frand(2.0)*3.14159;
656 c->last_frame = float_time();
659 #define source_x(c, i) \
660 (c->w/2 + ((int)(cos(c->source[i].x_theta)*((float)c->w/2.0))))
661 #define source_y(c, i) \
662 (c->h/2 + ((int)(cos(c->source[i].y_theta)*((float)c->h/2.0))))
665 * This is rather suboptimal. Calculating the distance per-pixel is going to
666 * be a lot slower than using now-ubiquitous SIMD CPU instructions to do four
667 * or eight pixels at a time. Plus, this could be almost trivially
668 * parallelized, what with all the multi-core hardware nowadays.
673 _alloc_color(struct inter_context *c, uint16_t r, uint16_t g, uint16_t b)
679 XAllocColor(c->dpy, c->cmap, &color);
683 static void _copy_test(Display *dpy, Drawable src, Drawable dst, GC gc, int x, int y, uint32_t cells)
685 XCopyArea(dpy, src, dst, gc, 0, 0, 3, 2, x, y);
688 XImage *image = XGetImage(dpy, src, 0, 0, 3, 2, cells, ZPixmap);
689 XPutImage(dpy, dst, gc, image, 0, 0, x, y + 2, 3, 2);
690 XDestroyImage(image);
694 static void _test_pattern(Display *dpy, Drawable d, GC gc, const uint32_t *rgb)
697 for(x = 0; x != 3; ++x)
699 XSetForeground(dpy, gc, rgb[x]);
700 XDrawPoint(dpy, d, gc, x, 0);
701 XSetForeground(dpy, gc, rgb[2 - x]);
702 XFillRectangle(dpy, d, gc, x, 1, 1, 1);
705 _copy_test(dpy, d, d, gc, 0, 2, rgb[0] | rgb[1] | rgb[2]);
707 #endif /* TEST_PATTERN */
709 static unsigned long do_inter(struct inter_context* c)
714 int g = c->grid_size;
715 unsigned w_div_g = c->w/g;
722 void *scanline = c->ximage->data;
728 #if defined USE_XIMAGE && defined HAVE_XSHM_EXTENSION
729 /* Wait a little while for the XServer to become ready if necessary. */
730 if(c->use_shm && !c->shm_can_draw)
735 elapsed = (now - c->last_frame) * 10.0;
739 for(i = 0; i < c->count; i++) {
740 c->source[i].x_theta += (elapsed*c->speed/1000.0);
741 if(c->source[i].x_theta > 2.0*3.14159)
742 c->source[i].x_theta -= 2.0*3.14159;
743 c->source[i].y_theta += (elapsed*c->speed/1000.0);
744 if(c->source[i].y_theta > 2.0*3.14159)
745 c->source[i].y_theta -= 2.0*3.14159;
746 c->source[i].x = source_x(c, i);
747 c->source[i].y = source_y(c, i);
750 for(j = 0; j < c->h/g; j++) {
751 for(i = 0; i < w_div_g; i++) {
755 for(k = 0; k < c->count; k++) {
757 dx = px - c->source[k].x;
758 dy = py - c->source[k].y;
761 * Other possibilities for improving performance here:
762 * 1. Using octagon-based distance estimation
763 * (Which causes giant octagons to appear.)
764 * 2. Square root approximation by reinterpret-casting IEEE floats to
766 * (Which causes angles to appear when two waves interfere.)
771 u.i = (1 << 29) + (u.i >> 1) - (1 << 22);
774 #if defined USE_FAST_SQRT_BIGTABLE2
775 dist = dx*dx + dy*dy;
776 dist = FAST_TABLE(dist);
777 #elif defined USE_FAST_SQRT_HACKISH
778 dist = fast_log2(dx*dx + dy*dy);
780 dist = sqrt(dx*dx + dy*dy);
783 result += (dist >= c->radius ? 0 : c->wave_height[dist]);
786 /* It's slightly faster to do a subtraction or two before calculating the
788 if(result >= c->colors)
791 if(result >= c->colors)
792 result %= (unsigned)c->colors;
796 c->row[i] = c->pal[result].pixel;
798 XFillRectangle(c->dpy, TARGET(c), c->gcs[result], g*i, g*j, g, g);
799 #endif /* USE_XIMAGE */
803 /* Fill in these `gridsize' horizontal bits in the scanline */
804 if(c->ximage->bits_per_pixel == 32)
806 uint32_t *ptr = (uint32_t *)scanline;
807 for(i = 0; i < w_div_g; i++) {
808 for(k = 0; k < g; k++)
809 ptr[g*i+k] = c->row[i];
812 else if(c->ximage->bits_per_pixel == 24)
814 uint8_t *ptr = (uint8_t *)scanline;
815 for(i = 0; i < w_div_g; i++) {
816 for(k = 0; k < g; k++) {
817 uint32_t pixel = c->row[i];
818 /* Might not work on big-endian. */
820 ptr[1] = (pixel & 0x0000ff00) >> 8;
821 ptr[2] = (pixel & 0x00ff0000) >> 16;
826 else if(c->ximage->bits_per_pixel == 16)
828 uint16_t *ptr = (uint16_t *)scanline;
829 for(i = 0; i < w_div_g; i++) {
830 for(k = 0; k < g; k++)
831 ptr[g*i+k] = c->row[i];
834 else if(c->ximage->bits_per_pixel == 8)
836 uint8_t *ptr = (uint8_t *)scanline;
837 for(i = 0; i < w_div_g; i++) {
838 for(k = 0; k < g; k++)
839 ptr[g*i+k] = c->row[i];
844 for(i = 0; i < w_div_g; i++) {
845 for(k = 0; k < g; k++)
846 XPutPixel(c->ximage, (g*i)+k, img_y, c->row[i]);
850 /* Only the first scanline of the image has been filled in; clone that
851 scanline to the rest of the `gridsize' lines in the ximage */
852 for(k = 0; k < (g-1); k++)
853 memcpy(c->ximage->data + (c->ximage->bytes_per_line * (img_y + k + 1)),
854 c->ximage->data + (c->ximage->bytes_per_line * img_y),
855 c->ximage->bytes_per_line);
857 # ifndef USE_BIG_XIMAGE
858 /* Move the bits for this horizontal stripe to the server. */
859 # ifdef HAVE_XSHM_EXTENSION
861 # endif /* HAVE_XSHM_EXTENSION */
862 XPutImage(c->dpy, TARGET(c), c->copy_gc, c->ximage,
863 0, 0, 0, g*j, c->ximage->width, c->ximage->height);
866 # if defined HAVE_XSHM_EXTENSION && !defined USE_BIG_XIMAGE
870 # if defined HAVE_XSHM_EXTENSION || defined USE_BIG_XIMAGE
871 scanline = (char *)scanline + c->ximage->bytes_per_line * g;
876 #endif /* USE_XIMAGE */
879 #ifdef HAVE_XSHM_EXTENSION
882 XShmPutImage(c->dpy, c->win, c->copy_gc, c->ximage,
883 0, 0, 0, 0, c->ximage->width, c->ximage->height,
885 c->shm_can_draw = False;
888 #if defined HAVE_XSHM_EXTENSION && defined USE_BIG_XIMAGE
891 #ifdef USE_BIG_XIMAGE
893 XPutImage(c->dpy, TARGET(c), c->copy_gc, c->ximage,
894 0, 0, 0, 0, c->ximage->width, c->ximage->height);
900 /* XWindowAttributes xgwa;
901 XGetWindowAttributes(c->dpy, c->win, &xgwa); */
903 // if(xgwa.width >= 9 && xgwa.height >= 10)
905 Screen *screen = ScreenOfDisplay(c->dpy, DefaultScreen(c->dpy));
906 Visual *visual = DefaultVisualOfScreen(screen);
907 Pixmap pixmap = XCreatePixmap(c->dpy, TARGET(c), 3, 10, visual_depth(screen, visual));
910 XSetForeground(c->dpy, c->copy_gc, _alloc_color(c, 0xffff, 0x7fff, 0x7fff));
911 XDrawPoint(c->dpy, TARGET(c), c->copy_gc, 0, c->h - 1);
914 uint32_t rgb[3], cells;
915 rgb[0] = _alloc_color(c, 0xffff, 0, 0);
916 rgb[1] = _alloc_color(c, 0, 0xffff, 0);
917 rgb[2] = _alloc_color(c, 0, 0, 0xffff);
918 cells = rgb[0] | rgb[1] | rgb[2];
920 _test_pattern(c->dpy, TARGET(c), c->copy_gc, rgb);
921 _test_pattern(c->dpy, pixmap, c->copy_gc, rgb);
922 // Here's a good spot to verify that the pixmap contains the right colors at the top.
923 _copy_test(c->dpy, TARGET(c), pixmap, c->copy_gc, 0, 6, cells);
925 XCopyArea(c->dpy, pixmap, TARGET(c), c->copy_gc, 0, 0, 3, 10, 3, 0);
927 XImage *image = XGetImage(c->dpy, pixmap, 0, 0, 3, 10, cells, ZPixmap);
928 XPutImage(c->dpy, TARGET(c), c->copy_gc, image, 0, 0, 6, 0, 3, 10);
929 XDestroyImage(image);
932 XFreePixmap(c->dpy, pixmap);
933 XSync(c->dpy, False);
936 #endif /* TEST_PATTERN */
938 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
941 XdbeSwapInfo info[1];
942 info[0].swap_window = c->win;
943 info[0].swap_action = XdbeUndefined;
944 XdbeSwapBuffers(c->dpy, info, 1);
947 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
950 XCopyArea (c->dpy, c->pix_buf, c->win, c->copy_gc,
951 0, 0, c->w, c->h, 0, 0);
958 interference_init (Display *dpy, Window win)
960 struct inter_context *c = (struct inter_context *) calloc (1, sizeof(*c));
963 inter_init(dpy, win, c);
968 interference_draw (Display *dpy, Window win, void *closure)
970 struct inter_context *c = (struct inter_context *) closure;
975 interference_reshape (Display *dpy, Window window, void *closure,
976 unsigned int w, unsigned int h)
978 struct inter_context *c = (struct inter_context *) closure;
979 XWindowAttributes xgwa;
980 Bool dbuf = (c->pix_buf
981 # ifdef HAVE_DOUBLE_BUFFER_EXTENSION
990 destroy_image(dpy, c);
995 XFreePixmap(dpy, c->pix_buf);
998 XGetWindowAttributes(dpy, window, &xgwa);
1001 create_image(dpy, c, &xgwa);
1003 create_pix_buf(dpy, window, c, &xgwa);
1007 interference_event (Display *dpy, Window window, void *closure, XEvent *event)
1009 #if HAVE_XSHM_EXTENSION
1010 struct inter_context *c = (struct inter_context *) closure;
1012 if(c->use_shm && event->type == XShmGetEventBase(dpy) + ShmCompletion)
1014 c->shm_can_draw = True;
1022 interference_free (Display *dpy, Window window, void *closure)
1024 struct inter_context *c = (struct inter_context *) closure;
1028 XSCREENSAVER_MODULE ("Interference", interference)