summaryrefslogtreecommitdiffstats
path: root/hacks/interference.c
diff options
context:
space:
mode:
authorSimon Rettberg2024-09-06 14:42:37 +0200
committerSimon Rettberg2024-09-06 14:42:37 +0200
commitbadef32037f52f79abc1f1440b786cd71afdf270 (patch)
tree412b792d4cab4a7a110db82fcf74fe8a1ac55ec1 /hacks/interference.c
parentDelete pre-6.00 files (diff)
downloadxscreensaver-master.tar.gz
xscreensaver-master.tar.xz
xscreensaver-master.zip
Diffstat (limited to 'hacks/interference.c')
-rw-r--r--hacks/interference.c1000
1 files changed, 0 insertions, 1000 deletions
diff --git a/hacks/interference.c b/hacks/interference.c
deleted file mode 100644
index 44a55ea..0000000
--- a/hacks/interference.c
+++ /dev/null
@@ -1,1000 +0,0 @@
-/* interference.c --- colored fields via decaying sinusoidal waves.
- * An entry for the RHAD Labs Screensaver Contest.
- *
- * Author: Hannu Mallat <hmallat@cs.hut.fi>
- *
- * Copyright (C) 1998 Hannu Mallat.
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. No representations are made about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * decaying sinusoidal waves, which extend spherically from their
- * respective origins, move around the plane. a sort of interference
- * between them is calculated and the resulting twodimensional wave
- * height map is plotted in a grid, using softly changing colours.
- *
- * not physically (or in any sense) accurate, but fun to look at for
- * a while. you may tune the speed/resolution/interestingness tradeoff
- * with X resources, see below.
- *
- * Created : Wed Apr 22 09:30:30 1998, hmallat
- * Last modified: Wed Apr 22 09:30:30 1998, hmallat
- * Last modified: Sun Aug 31 23:40:14 2003,
- * david slimp <rock808@DavidSlimp.com>
- * added -hue option to specify base color hue
- * Last modified: Wed May 15 00:04:43 2013,
- * Dave Odell <dmo2118@gmail.com>
- * Tuned performance; double-buffering is now off by default.
- * Made animation speed independent of FPS.
- * Added cleanup code, fixed a few glitches.
- * Added gratuitous #ifdefs.
- * Last modified: Fri Feb 21 02:14:29 2014, <dmo2118@gmail.com>
- * Added support for SMP rendering.
- * Tweaked math a bit re: performance.
- * Last modified: Tue Dec 30 16:43:33 2014, <dmo2118@gmail.com>
- * Killed the black margin on the right and bottom.
- * Reduced the default grid size to 2.
- * Last modified: Sun Oct 9 11:20:48 2016, <dmo2118@gmail.com>
- * Updated for new xshm.c.
- * Ditched USE_BIG_XIMAGE.
- */
-
-#include <math.h>
-#include <errno.h>
-
-#include "screenhack.h"
-
-#include "thread_util.h"
-
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#else
-
-typedef unsigned int uint32_t;
-typedef unsigned short uint16_t;
-typedef unsigned char uint8_t;
-
-#endif
-
-/*
-Tested on an Intel(R) Pentium(R) 4 CPU 3.00GHz (family 15, model 6, 2 cores),
-1 GB PC2-4200, nouveau - Gallium 0.4 on NV44, X.Org version: 1.13.3. A very
-modest system by current standards.
-
-Does double-buffering make sense? (gridsize = 2)
-USE_XIMAGE is off: Yes (-db: 4.1 FPS, -no-db: 2.9 FPS)
-XPutImage in strips: No (-db: 35.9 FPS, -no-db: 38.7 FPS)
-XPutImage, whole image: No (-db: 32.3 FPS, -no-db: 33.7 FPS)
-MIT-SHM, whole image: Doesn't work anyway: (-no-db: 37.3 FPS)
-
-If gridsize = 1, XPutImage is slow when the XImage is one line at a time.
-XPutImage in strips: -db: 21.2 FPS, -no-db: 19.7 FPS
-XPutimage, whole image: -db: 23.2 FPS, -no-db: 23.4 FPS
-MIT-SHM: 26.0 FPS
-
-So XPutImage in strips is very slightly faster when gridsize >= 2, but
-quite a bit worse when gridsize = 1.
-*/
-
-/* I thought it would be faster this way, but it turns out not to be... -jwz */
-/* It's a lot faster for me, though - D.O. */
-#define USE_XIMAGE
-
-/* Numbers are wave_table size, measured in # of unsigned integers.
- * FPS/radius = 50/radius = 800/radius = 1500/Big-O memory usage
- *
- * Use at most one of the following:
- * Both off = regular sqrt() - 13.5 FPS, 50/800/1500. */
-
-/* #define USE_FAST_SQRT_HACKISH */ /* 17.8 FPS/2873/4921/5395/O(lg(radius)) */
-#define USE_FAST_SQRT_BIGTABLE2 /* 26.1 FPS/156/2242/5386/O(radius^2) */
-
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
-# include "xdbe.h"
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-
-#ifdef USE_XIMAGE
-# include "xshm.h"
-#endif /* USE_XIMAGE */
-
-static const char *interference_defaults [] = {
- ".background: black",
- ".foreground: white",
- "*count: 3", /* number of waves */
- "*gridsize: 2", /* pixel size, smaller values for better resolution */
- "*ncolors: 192", /* number of colours used */
- "*hue: 0", /* hue to use for base color (0-360) */
- "*speed: 30", /* speed of wave origins moving around */
- "*delay: 30000", /* or something */
- "*color-shift: 60", /* h in hsv space, smaller values for smaller
- * color gradients */
- "*radius: 800", /* wave extent */
- "*gray: false", /* color or grayscale */
- "*mono: false", /* monochrome, not very much fun */
-
- "*doubleBuffer: False", /* doubleBuffer slows things down for me - D.O. */
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- "*useDBE: True", /* use double buffering extension */
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-
-#ifdef HAVE_XSHM_EXTENSION
- "*useSHM: True", /* use shared memory extension */
-#endif /* HAVE_XSHM_EXTENSION */
-#ifdef HAVE_MOBILE
- "*ignoreRotation: True",
-#endif
- THREAD_DEFAULTS
- 0
-};
-
-static XrmOptionDescRec interference_options [] = {
- { "-count", ".count", XrmoptionSepArg, 0 },
- { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
- { "-gridsize", ".gridsize", XrmoptionSepArg, 0 },
- { "-hue", ".hue", XrmoptionSepArg, 0 },
- { "-speed", ".speed", XrmoptionSepArg, 0 },
- { "-delay", ".delay", XrmoptionSepArg, 0 },
- { "-color-shift", ".color-shift", XrmoptionSepArg, 0 },
- { "-radius", ".radius", XrmoptionSepArg, 0 },
- { "-gray", ".gray", XrmoptionNoArg, "True" },
- { "-mono", ".mono", XrmoptionNoArg, "True" },
- { "-db", ".doubleBuffer", XrmoptionNoArg, "True" },
- { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" },
-#ifdef HAVE_XSHM_EXTENSION
- { "-shm", ".useSHM", XrmoptionNoArg, "True" },
- { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
-#endif /* HAVE_XSHM_EXTENSION */
- THREAD_OPTIONS
- { 0, 0, 0, 0 }
-};
-
-struct inter_source {
- int x;
- int y;
- double x_theta;
- double y_theta;
-};
-
-struct inter_context {
- /*
- * Display-related entries
- */
- Display* dpy;
- Window win;
-
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- XdbeBackBuffer back_buf;
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
- Pixmap pix_buf;
-
- GC copy_gc;
-#ifdef USE_XIMAGE
- XImage *ximage;
-
- Bool shm_can_draw;
- XShmSegmentInfo shm_info;
-#endif /* USE_XIMAGE */
-
- /*
- * Resources
- */
- int count;
- int grid_size;
- int colors;
- float hue;
- int speed;
- int delay;
- int shift;
-
- /*
- * Drawing-related entries
- */
- int w;
- int h;
- unsigned w_div_g, h_div_g;
- Colormap cmap;
- Screen *screen;
- unsigned bits_per_pixel;
- XColor* pal;
-#ifndef USE_XIMAGE
- GC* gcs;
-#endif
- int radius; /* Not always the same as the X resource. */
- double last_frame;
-
- struct threadpool threadpool;
-
- /*
- * lookup tables
- */
- unsigned* wave_height;
-
- /*
- * Interference sources
- */
- struct inter_source* source;
-};
-
-struct inter_thread
-{
- const struct inter_context *context;
- unsigned thread_id;
-
-#ifdef USE_XIMAGE
- uint32_t* row;
-#endif
-
- unsigned* result_row;
-};
-
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
-# define TARGET(c) ((c)->back_buf ? (c)->back_buf : \
- (c)->pix_buf ? (c)->pix_buf : (c)->win)
-#else /* HAVE_DOUBLE_BUFFER_EXTENSION */
-# define TARGET(c) ((c)->pix_buf ? (c)->pix_buf : (c)->win)
-#endif /* !HAVE_DOUBLE_BUFFER_EXTENSION */
-
-#ifdef USE_FAST_SQRT_HACKISH
-/* Based loosely on code from Wikipedia:
- * https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Approximations_that_depend_on_IEEE_representation
- */
-
-/* FAST_SQRT_EXTRA_BITS = 3: Smallest useful value
- * = 5/6: A little bit of banding, wave_height table is on par with regular
- * sqrt() code.
- * = 7: No apparent difference with original @ radius = 800.
- * = 8: One more just to be comfortable.
- */
-
-# define FAST_SQRT_EXTRA_BITS 8
-
-union int_float
-{
- uint32_t i;
- float f;
-};
-
-static unsigned fast_log2(unsigned x)
-{
- union int_float u;
- if(!x)
- return x;
- u.f = x;
- return ((u.i - 0x3f800000) >> (23 - FAST_SQRT_EXTRA_BITS)) + 1;
-}
-
-static float fast_inv_log2(unsigned x)
-{
- union int_float u;
- if(!x)
- return 0.0f;
- u.i = ((x - 1) << (23 - FAST_SQRT_EXTRA_BITS)) + 0x3f800000;
- return u.f;
-}
-
-#endif
-
-#ifdef USE_FAST_SQRT_BIGTABLE2
-
-/* I eyeballed these figures. They could be improved. - D.O. */
-
-# define FAST_SQRT_DISCARD_BITS1 4
-/* = 5: Dot in center is almost invisible at radius = 800. */
-/* = 4: Dot in center looks OK at radius = 50. */
-
-/* 156/2740/9029 */
-/* # define FAST_SQRT_DISCARD_BITS2 8 */
-/* # define FAST_SQRT_CUTOFF 64 * 64 */
-
-/* 156/2242/5386 */
-# define FAST_SQRT_DISCARD_BITS2 9
-# define FAST_SQRT_CUTOFF 128 * 128
-
-/*
- * This is a little faster:
- * 44.5 FPS, 19/5000/17578
- *
- * # define FAST_SQRT_DISCARD_BITS1 7
- * # define FAST_SQRT_DISCARD_BITS2 7
- * # define FAST_SQRT_CUTOFF 0
- *
- * For radius = 800, FAST_SQRT_DISCARD_BITS2 =
- * = 9/10: Approximately the original table size, some banding near origins.
- * = 7: wave_height is 20 KB, and just fits inside a 32K L1 cache.
- * = 6: Nearly indistinguishable from original
- */
-
-/*
- FAST_TABLE(x) is equivalent to, but slightly faster than:
- x < FAST_SQRT_CUTOFF ?
- (x >> FAST_SQRT_DISCARD_BITS1) :
- ((x - FAST_SQRT_CUTOFF) >> FAST_SQRT_DISCARD_BITS2) +
- (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1);
-*/
-
-#define FAST_TABLE(x) \
- ((x) < FAST_SQRT_CUTOFF ? \
- ((x) >> FAST_SQRT_DISCARD_BITS1) : \
- (((x) + \
- ((FAST_SQRT_CUTOFF << (FAST_SQRT_DISCARD_BITS2 - \
- FAST_SQRT_DISCARD_BITS1)) - FAST_SQRT_CUTOFF)) >> \
- FAST_SQRT_DISCARD_BITS2))
-
-static double fast_inv_table(unsigned x)
-{
- return x < (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1) ?
- (x << FAST_SQRT_DISCARD_BITS1) :
- ((x - (FAST_SQRT_CUTOFF >> FAST_SQRT_DISCARD_BITS1)) <<
- FAST_SQRT_DISCARD_BITS2) + FAST_SQRT_CUTOFF;
-}
-
-#endif
-
-static void destroy_image(Display* dpy, struct inter_context* c)
-{
-#ifdef USE_XIMAGE
- if(c->ximage) {
- destroy_xshm_image(dpy, c->ximage, &c->shm_info);
- }
-#endif
-
- if(c->threadpool.count)
- {
- threadpool_destroy(&c->threadpool);
- c->threadpool.count = 0;
- }
-}
-
-static void inter_free(Display* dpy, struct inter_context* c)
-{
-#ifndef USE_XIMAGE
- unsigned i;
-#endif
-
- if(c->pix_buf)
- XFreePixmap(dpy, c->pix_buf);
-
- if(c->copy_gc)
- XFreeGC(dpy, c->copy_gc);
-
- destroy_image(dpy, c);
-
- free_colors(c->screen, c->cmap, c->pal, c->colors);
- if (c->pal) free(c->pal);
-
-#ifndef USE_XIMAGE
- for(i = 0; i != c->colors; ++i)
- XFreeGC(dpy, c->gcs[i]);
- free(c->gcs);
-#endif
-
- free(c->wave_height);
- free(c->source);
-}
-
-static void abort_on_error(int error)
-{
- fprintf(stderr, "interference: %s\n", strerror(error));
- exit(1);
-}
-
-static void abort_no_mem(void)
-{
- abort_on_error(ENOMEM);
-}
-
-static void check_no_mem(Display* dpy, struct inter_context* c, void* ptr)
-{
- if(!ptr) {
- inter_free(dpy, c);
- abort_no_mem();
- }
-}
-
-static int inter_thread_create(
- void* self_raw,
- struct threadpool* pool,
- unsigned id)
-{
- struct inter_thread* self = (struct inter_thread*)self_raw;
- const struct inter_context* c = GET_PARENT_OBJ(struct inter_context, threadpool, pool);
-
- self->context = c;
- self->thread_id = id;
-
- self->result_row = malloc(c->w_div_g * sizeof(unsigned));
- if(!self->result_row)
- return ENOMEM;
-
-#ifdef USE_XIMAGE
- self->row = malloc(c->w_div_g * sizeof(uint32_t));
- if(!self->row) {
- free(self->result_row);
- return ENOMEM;
- }
-#endif
-
- return 0;
-}
-
-static void inter_thread_destroy(void* self_raw)
-{
- struct inter_thread* self = (struct inter_thread*)self_raw;
-#ifdef USE_XIMAGE
- free(self->row);
-#endif
- free(self->result_row);
-}
-
-/*
-A higher performance design would have input and output queues, so that when
-worker threads finish with one frame, they can pull the next work order from
-the queue and get started on it immediately, rather than going straight to
-sleep. The current "single-buffered" design still provides reasonable
-performance at low frame rates; high frame rates are noticeably less efficient.
-*/
-
-static void inter_thread_run(void* self_raw)
-{
- struct inter_thread* self = (struct inter_thread*)self_raw;
- const struct inter_context* c = self->context;
-
- int i, j, k;
- unsigned result;
- int dist1;
- int g = c->grid_size;
-
- int dx, dy, g2 = 2 * g * g;
- int px, py, px2g;
-
- int dist0, ddist;
-
-#ifdef USE_XIMAGE
- unsigned img_y = g * self->thread_id;
- void *scanline = c->ximage->data + c->ximage->bytes_per_line * g * self->thread_id;
-#endif
-
- for(j = self->thread_id; j < c->h_div_g; j += c->threadpool.count) {
- px = g/2;
- py = j*g + px;
-
- memset(self->result_row, 0, c->w_div_g * sizeof(unsigned));
-
- for(k = 0; k < c->count; k++) {
-
- dx = px - c->source[k].x;
- dy = py - c->source[k].y;
-
- dist0 = dx*dx + dy*dy;
- ddist = -2 * g * c->source[k].x;
-
- /* px2g = g*(px*2 + g); */
- px2g = g2;
-
- for(i = 0; i < c->w_div_g; i++) {
- /*
- * Discarded possibilities for improving performance here:
- * 1. Using octagon-based distance estimation
- * (Which causes giant octagons to appear.)
- * 2. Square root approximation by reinterpret-casting IEEE floats to
- * integers.
- * (Which causes angles to appear when two waves interfere.)
- */
-
-/* int_float u;
- u.f = dx*dx + dy*dy;
- u.i = (1 << 29) + (u.i >> 1) - (1 << 22);
- dist = u.f; */
-
-#if defined USE_FAST_SQRT_BIGTABLE2
- dist1 = FAST_TABLE(dist0);
-#elif defined USE_FAST_SQRT_HACKISH
- dist1 = fast_log2(dist0);
-#else
- dist1 = sqrt(dist0);
-#endif
-
- if(dist1 < c->radius)
- self->result_row[i] += c->wave_height[dist1];
-
- dist0 += px2g + ddist;
- px2g += g2;
- }
- }
-
- for(i = 0; i < c->w_div_g; i++) {
-
- result = self->result_row[i];
-
- /* It's slightly faster to do a subtraction or two before calculating the
- * modulus. - D.O. */
- if(result >= c->colors)
- {
- result -= c->colors;
- if(result >= c->colors)
- result %= (unsigned)c->colors;
- }
-
-#ifdef USE_XIMAGE
- self->row[i] = c->pal[result].pixel;
-#else
- XFillRectangle(c->dpy, TARGET(c), c->gcs[result], g*i, g*j, g, g);
-#endif /* USE_XIMAGE */
- }
-
-#ifdef USE_XIMAGE
- /* Fill in these `gridsize' horizontal bits in the scanline */
- if(c->ximage->bits_per_pixel == 32)
- {
- uint32_t *ptr = (uint32_t *)scanline;
- for(i = 0; i < c->w_div_g; i++) {
- for(k = 0; k < g; k++)
- ptr[g*i+k] = self->row[i];
- }
- }
- else if(c->ximage->bits_per_pixel == 24)
- {
- uint8_t *ptr = (uint8_t *)scanline;
- for(i = 0; i < c->w_div_g; i++) {
- for(k = 0; k < g; k++) {
- uint32_t pixel = self->row[i];
- /* Might not work on big-endian. */
- ptr[0] = pixel;
- ptr[1] = (pixel & 0x0000ff00) >> 8;
- ptr[2] = (pixel & 0x00ff0000) >> 16;
- ptr += 3;
- }
- }
- }
- else if(c->ximage->bits_per_pixel == 16)
- {
- uint16_t *ptr = (uint16_t *)scanline;
- for(i = 0; i < c->w_div_g; i++) {
- for(k = 0; k < g; k++)
- ptr[g*i+k] = self->row[i];
- }
- }
- else if(c->ximage->bits_per_pixel == 8)
- {
- uint8_t *ptr = (uint8_t *)scanline;
- for(i = 0; i < c->w_div_g; i++) {
- for(k = 0; k < g; k++)
- ptr[g*i+k] = self->row[i];
- }
- }
- else
- {
- for(i = 0; i < c->w_div_g; i++) {
- for(k = 0; k < g; k++)
- /* XPutPixel is thread safe as long as the XImage didn't have its
- * bits_per_pixel changed. */
- XPutPixel(c->ximage, (g*i)+k, img_y, self->row[i]);
- }
- }
-
- /* Only the first scanline of the image has been filled in; clone that
- scanline to the rest of the `gridsize' lines in the ximage */
- for(k = 0; k < (g-1); k++)
- memcpy(c->ximage->data + (c->ximage->bytes_per_line * (img_y + k + 1)),
- c->ximage->data + (c->ximage->bytes_per_line * img_y),
- c->ximage->bytes_per_line);
-
- scanline = (char *)scanline +
- c->ximage->bytes_per_line * g * c->threadpool.count;
- img_y += g * c->threadpool.count;
-
-#endif /* USE_XIMAGE */
- }
-}
-
-/* On allocation error, c->ximage == NULL. */
-static void create_image(
- Display* dpy,
- struct inter_context* c,
- const XWindowAttributes* xgwa)
-{
-#ifdef USE_XIMAGE
-
- /* Set the width so that each thread can work on a different line. */
- unsigned align = thread_memory_alignment(dpy) * 8 - 1;
- unsigned wbits, w, h;
-#endif /* USE_XIMAGE */
-
- c->w = xgwa->width;
- c->h = xgwa->height;
- c->w_div_g = (c->w + c->grid_size - 1) / c->grid_size;
- c->h_div_g = (c->h + c->grid_size - 1) / c->grid_size;
-
-#ifdef USE_XIMAGE
- w = c->w_div_g * c->grid_size;
- h = c->h_div_g * c->grid_size;
-
- /* The width of a scan line, in *bits*. */
- wbits = (w * c->bits_per_pixel + align) & ~align;
-
- /* This uses a lot more RAM than the single line approach. Users without
- * enough RAM to fit even a single framebuffer should consider an upgrade for
- * their 386. - D.O.
- */
-
- c->ximage = create_xshm_image(dpy, xgwa->visual, xgwa->depth,
- ZPixmap, &c->shm_info,
- wbits / c->bits_per_pixel, h);
-
- c->shm_can_draw = True;
-
- check_no_mem(dpy, c, c->ximage);
-#endif /* USE_XIMAGE */
-
- {
- static const struct threadpool_class cls =
- {
- sizeof(struct inter_thread),
- inter_thread_create,
- inter_thread_destroy
- };
-
- int error = threadpool_create(
- &c->threadpool,
- &cls,
- dpy,
-#ifdef USE_XIMAGE
- hardware_concurrency(dpy)
-#else
- 1
- /* At least two issues with threads without USE_XIMAGE:
- * 1. Most of Xlib isn't thread safe without XInitThreads.
- * 2. X(Un)LockDisplay would need to be called for each line, which is
- * terrible.
- */
-#endif
- );
-
- if(error) {
- c->threadpool.count = 0; /* See the note in thread_util.h. */
- inter_free(dpy, c);
- abort_on_error(error);
- }
- }
-}
-
-static void create_pix_buf(Display* dpy, Window win, struct inter_context *c,
- const XWindowAttributes* xgwa)
-{
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- if(c->back_buf)
- return;
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
- c->pix_buf = XCreatePixmap(dpy, win, xgwa->width, xgwa->height, xgwa->depth);
-}
-
-static double float_time(void)
-{
- struct timeval result;
- gettimeofday(
- &result
-#ifdef GETTIMEOFDAY_TWO_ARGS
- , NULL
-#endif
- );
-
- return result.tv_usec * 1.0e-6 + result.tv_sec;
-}
-
-static void inter_init(Display* dpy, Window win, struct inter_context* c)
-{
- XWindowAttributes xgwa;
- double H[3], S[3], V[3];
- int i;
- int mono;
- int gray;
- int radius;
- double scale = 1;
- XGCValues val;
- Bool dbuf = get_boolean_resource (dpy, "doubleBuffer", "Boolean");
-
-#ifndef USE_XIMAGE
- unsigned long valmask = 0;
-#endif
-
-# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
- dbuf = False;
-# endif
-
- memset (c, 0, sizeof(*c));
-
- c->dpy = dpy;
- c->win = win;
-
-
- c->delay = get_integer_resource(dpy, "delay", "Integer");
-
- XGetWindowAttributes(c->dpy, c->win, &xgwa);
- c->cmap = xgwa.colormap;
- c->screen = xgwa.screen;
- c->bits_per_pixel = visual_pixmap_depth(xgwa.screen, xgwa.visual);
- check_no_mem(dpy, c, (void *)(ptrdiff_t)c->bits_per_pixel);
-
- val.function = GXcopy;
- c->copy_gc = XCreateGC(c->dpy, TARGET(c), GCFunction, &val);
-
- c->count = get_integer_resource(dpy, "count", "Integer");
- if(c->count < 1)
- c->count = 1;
- c->grid_size = get_integer_resource(dpy, "gridsize", "Integer");
- if(c->grid_size < 1)
- c->grid_size = 1;
- mono = get_boolean_resource(dpy, "mono", "Boolean");
- if(!mono) {
- c->colors = get_integer_resource(dpy, "ncolors", "Integer");
- if(c->colors < 2)
- c->colors = 2;
- }
- c->hue = get_integer_resource(dpy, "hue", "Float");
- while (c->hue < 0 || c->hue >= 360)
- c->hue = frand(360.0);
- c->speed = get_integer_resource(dpy, "speed", "Integer");
- c->shift = get_float_resource(dpy, "color-shift", "Float");
- while(c->shift >= 360.0)
- c->shift -= 360.0;
- while(c->shift <= -360.0)
- c->shift += 360.0;
- radius = get_integer_resource(dpy, "radius", "Integer");;
- if(radius < 1)
- radius = 1;
-
- if (xgwa.width > 2560) scale = 3.5; /* Retina displays */
- radius *= scale;
-
- create_image(dpy, c, &xgwa);
-
- if(!mono) {
- c->pal = calloc(c->colors, sizeof(XColor));
- check_no_mem(dpy, c, c->pal);
-
- gray = get_boolean_resource(dpy, "gray", "Boolean");
- if(!gray) {
- H[0] = c->hue;
- H[1] = H[0] + c->shift < 360.0 ? H[0]+c->shift : H[0] + c->shift-360.0;
- H[2] = H[1] + c->shift < 360.0 ? H[1]+c->shift : H[1] + c->shift-360.0;
- S[0] = S[1] = S[2] = 1.0;
- V[0] = V[1] = V[2] = 1.0;
- } else {
- H[0] = H[1] = H[2] = 0.0;
- S[0] = S[1] = S[2] = 0.0;
- V[0] = 1.0; V[1] = 0.5; V[2] = 0.0;
- }
-
- make_color_loop(c->screen, xgwa.visual, c->cmap,
- H[0], S[0], V[0],
- H[1], S[1], V[1],
- H[2], S[2], V[2],
- c->pal, &(c->colors),
- True, False);
- if(c->colors < 2) { /* color allocation failure */
- mono = 1;
- free(c->pal);
- }
- }
-
- if(mono) { /* DON'T else this with the previous if! */
- c->colors = 2;
- c->pal = calloc(2, sizeof(XColor));
- check_no_mem(dpy, c, c->pal);
- c->pal[0].pixel = BlackPixel(c->dpy, DefaultScreen(c->dpy));
- c->pal[1].pixel = WhitePixel(c->dpy, DefaultScreen(c->dpy));
- }
-
-#ifdef USE_XIMAGE
- dbuf = False;
- /* Double-buffering doesn't work with MIT-SHM: XShmPutImage must draw to the
- * window. Otherwise, XShmCompletion events will have the XAnyEvent::window
- * field set to the back buffer, and XScreenSaver will ignore the event.
- */
-#endif
-
- if (dbuf)
- {
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- c->back_buf = xdbe_get_backbuffer (c->dpy, c->win, XdbeUndefined);
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-
- create_pix_buf(dpy, win, c, &xgwa);
- }
-
-#ifndef USE_XIMAGE
- valmask = GCForeground;
- c->gcs = calloc(c->colors, sizeof(GC));
- check_no_mem(dpy, c, c->gcs);
- for(i = 0; i < c->colors; i++) {
- val.foreground = c->pal[i].pixel;
- c->gcs[i] = XCreateGC(c->dpy, TARGET(c), valmask, &val);
- }
-#endif
-
-#if defined USE_FAST_SQRT_HACKISH
- c->radius = fast_log2(radius * radius);
-#elif defined USE_FAST_SQRT_BIGTABLE2
- c->radius = radius * radius;
- c->radius = FAST_TABLE(c->radius);
-#else
- c->radius = radius;
-#endif
-
- if (c->radius < 1) c->radius = 1;
- c->wave_height = calloc(c->radius, sizeof(unsigned));
- check_no_mem(dpy, c, c->wave_height);
-
- for(i = 0; i < c->radius; i++) {
- float max, fi;
-#if defined USE_FAST_SQRT_HACKISH
- fi = sqrt(fast_inv_log2(i));
-#elif defined USE_FAST_SQRT_BIGTABLE2
- fi = sqrt(fast_inv_table(i));
-#else
- fi = i;
-#endif
- max =
- ((float)c->colors) *
- ((float)radius - fi) /
- ((float)radius);
- c->wave_height[i] =
- (unsigned)
- ((max + max*cos(fi/(50.0 * scale))) / 2.0);
- }
-
- c->source = calloc(c->count, sizeof(struct inter_source));
- check_no_mem(dpy, c, c->source);
-
- for(i = 0; i < c->count; i++) {
- c->source[i].x_theta = frand(2.0)*M_PI;
- c->source[i].y_theta = frand(2.0)*M_PI;
- }
-
- c->last_frame = float_time();
-}
-
-#define source_x(c, i) \
- (c->w/2 + ((int)(cos(c->source[i].x_theta)*((float)c->w/2.0))))
-#define source_y(c, i) \
- (c->h/2 + ((int)(cos(c->source[i].y_theta)*((float)c->h/2.0))))
-
-/*
- * This is somewhat suboptimal. Calculating the distance per-pixel is going to
- * be a lot slower than using now-ubiquitous SIMD CPU instructions to do four
- * or eight pixels at a time.
- */
-
-static unsigned long do_inter(struct inter_context* c)
-{
- int i;
-
- double now;
- float elapsed;
-
-#ifdef USE_XIMAGE
- /* Wait a little while for the XServer to become ready if necessary. */
- if(!c->shm_can_draw)
- return 2000;
-#endif
-
- now = float_time();
- elapsed = (now - c->last_frame) * 10.0;
-
- c->last_frame = now;
-
- for(i = 0; i < c->count; i++) {
- c->source[i].x_theta += (elapsed*c->speed/1000.0);
- if(c->source[i].x_theta > 2.0*M_PI)
- c->source[i].x_theta -= 2.0*M_PI;
- c->source[i].y_theta += (elapsed*c->speed/1000.0);
- if(c->source[i].y_theta > 2.0*M_PI)
- c->source[i].y_theta -= 2.0*M_PI;
- c->source[i].x = source_x(c, i);
- c->source[i].y = source_y(c, i);
- }
-
- threadpool_run(&c->threadpool, inter_thread_run);
- threadpool_wait(&c->threadpool);
-
-#ifdef USE_XIMAGE
- put_xshm_image(c->dpy, c->win, c->copy_gc, c->ximage, 0, 0, 0, 0,
- c->ximage->width, c->ximage->height, &c->shm_info);
- /* c->shm_can_draw = False; */
-#endif
-
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- if (c->back_buf)
- {
- XdbeSwapInfo info[1];
- info[0].swap_window = c->win;
- info[0].swap_action = XdbeUndefined;
- XdbeSwapBuffers(c->dpy, info, 1);
- }
- else
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
- if (c->pix_buf)
- {
- XCopyArea (c->dpy, c->pix_buf, c->win, c->copy_gc,
- 0, 0, c->w, c->h, 0, 0);
- }
-
- return c->delay;
-}
-
-static void *
-interference_init (Display *dpy, Window win)
-{
- struct inter_context *c = (struct inter_context *) calloc (1, sizeof(*c));
- if(!c)
- abort_no_mem();
- inter_init(dpy, win, c);
- return c;
-}
-
-static unsigned long
-interference_draw (Display *dpy, Window win, void *closure)
-{
- struct inter_context *c = (struct inter_context *) closure;
- return do_inter(c);
-}
-
-static void
-interference_reshape (Display *dpy, Window window, void *closure,
- unsigned int w, unsigned int h)
-{
- struct inter_context *c = (struct inter_context *) closure;
- XWindowAttributes xgwa;
- Bool dbuf = (!!c->pix_buf
-# ifdef HAVE_DOUBLE_BUFFER_EXTENSION
- || c->back_buf
-# endif
- );
-
-#ifdef USE_XIMAGE
- destroy_image(dpy, c);
- c->ximage = 0;
-#endif
-
- if(c->pix_buf)
- XFreePixmap(dpy, c->pix_buf);
- c->pix_buf = None;
-
- XGetWindowAttributes(dpy, window, &xgwa);
- xgwa.width = w;
- xgwa.height = h;
- create_image(dpy, c, &xgwa);
- if(dbuf)
- create_pix_buf(dpy, window, c, &xgwa);
-}
-
-static Bool
-interference_event (Display *dpy, Window window, void *closure, XEvent *event)
-{
-#if HAVE_XSHM_EXTENSION
- struct inter_context *c = (struct inter_context *) closure;
-
- if(event->type == XShmGetEventBase(dpy) + ShmCompletion)
- {
- c->shm_can_draw = True;
- return True;
- }
-#endif
- return False;
-}
-
-static void
-interference_free (Display *dpy, Window window, void *closure)
-{
- struct inter_context *c = (struct inter_context *) closure;
- inter_free(dpy, c);
- free(c);
-}
-
-XSCREENSAVER_MODULE ("Interference", interference)
-