source: trunk/third/xscreensaver/hacks/interference.c @ 20148

Revision 20148, 12.7 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* interference.c --- colored fields via decaying sinusoidal waves.
2 * An entry for the RHAD Labs Screensaver Contest.
3 *
4 * Author: Hannu Mallat <hmallat@cs.hut.fi>
5 *
6 * Copyright (C) 1998 Hannu Mallat.
7 *
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
14 * implied warranty.
15 *
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.
20 *
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.
24 *
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 *
31 * TODO:
32 *
33 *    This really needs to be sped up.
34 *
35 *    I've tried making it use XPutPixel/XPutImage instead of XFillRectangle,
36 *    but that doesn't seem to help (it's the same speed at gridsize=1, and
37 *    it actually makes it slower at larger sizes.)
38 *
39 *    I played around with shared memory, but clearly I still don't know how
40 *    to use the XSHM extension properly, because it doesn't work yet.
41 *
42 *    Hannu had put in code to use the double-buffering extension, but that
43 *    code didn't work for me on Irix.  I don't think it would help anyway,
44 *    since it's not the swapping of frames that is the bottleneck (or a source
45 *    of visible flicker.)
46 *
47 *     -- jwz, 4-Jun-98
48 */
49
50#include <math.h>
51
52#include "screenhack.h"
53
54# include <X11/Xutil.h>
55
56/* I thought it would be faster this way, but it turns out not to be... -jwz */
57#undef USE_XIMAGE
58
59#ifndef USE_XIMAGE
60# undef HAVE_XSHM_EXTENSION  /* only applicable when using XImages */
61#endif /* USE_XIMAGE */
62
63
64#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
65# include "xdbe.h"
66#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
67
68#ifdef HAVE_XSHM_EXTENSION
69# include "xshm.h"
70#endif /* HAVE_XSHM_EXTENSION */
71
72char *progclass="Interference";
73
74char *defaults [] = {
75  ".background:  black",
76  ".foreground:  white",
77  "*count:       3",     /* number of waves */
78  "*gridsize:    4",     /* pixel size, smaller values for better resolution */
79  "*ncolors:     128",   /* number of colours used */
80  "*hue:         0",     /* hue to use for base color (0-360) */
81  "*speed:       30",    /* speed of wave origins moving around */
82  "*delay:       30000", /* or something */
83  "*color-shift: 60",    /* h in hsv space, smaller values for smaller
84                          * color gradients */
85  "*radius:      800",   /* wave extent */
86  "*gray:        false", /* color or grayscale */
87  "*mono:        false", /* monochrome, not very much fun */
88
89  "*doubleBuffer: True",
90#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
91  "*useDBE:      True", /* use double buffering extension */
92#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
93
94#ifdef HAVE_XSHM_EXTENSION
95  "*useSHM:      True", /* use shared memory extension */
96#endif /*  HAVE_XSHM_EXTENSION */
97  0
98};
99
100XrmOptionDescRec options [] = {
101  { "-count",       ".count",       XrmoptionSepArg, 0 },
102  { "-ncolors",     ".ncolors",     XrmoptionSepArg, 0 },
103  { "-gridsize",    ".gridsize",    XrmoptionSepArg, 0 },
104  { "-hue",         ".hue",         XrmoptionSepArg, 0 },
105  { "-speed",       ".speed",       XrmoptionSepArg, 0 },
106  { "-delay",       ".delay",       XrmoptionSepArg, 0 },
107  { "-color-shift", ".color-shift", XrmoptionSepArg, 0 },
108  { "-radius",      ".radius",      XrmoptionSepArg, 0 },
109  { "-gray",        ".gray",        XrmoptionNoArg,  "True" },
110  { "-mono",        ".mono",        XrmoptionNoArg,  "True" },
111  { "-db",          ".doubleBuffer", XrmoptionNoArg,  "True" },
112  { "-no-db",       ".doubleBuffer", XrmoptionNoArg,  "False" },
113#ifdef HAVE_XSHM_EXTENSION
114  { "-shm",     ".useSHM",      XrmoptionNoArg, "True" },
115  { "-no-shm",  ".useSHM",      XrmoptionNoArg, "False" },
116#endif /*  HAVE_XSHM_EXTENSION */
117  { 0, 0, 0, 0 }
118};
119
120int options_size = (sizeof (options) / sizeof (XrmOptionDescRec));
121
122struct inter_source {
123  int x;
124  int y;
125  double x_theta;
126  double y_theta;
127};
128
129struct inter_context {
130  /*
131   * Display-related entries
132   */
133  Display* dpy;
134  Window   win;
135
136#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
137  XdbeBackBuffer back_buf;
138#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
139  Pixmap   pix_buf;
140
141  GC       copy_gc;
142#ifdef USE_XIMAGE
143  XImage  *ximage;
144#endif /* USE_XIMAGE */
145
146#ifdef HAVE_XSHM_EXTENSION
147  Bool use_shm;
148  XShmSegmentInfo shm_info;
149#endif /* HAVE_XSHM_EXTENSION */
150
151  /*
152   * Resources
153   */
154  int count;
155  int grid_size;
156  int colors;
157  float hue;
158  int speed;
159  int delay;
160  int shift;
161  int radius;
162
163  /*
164   * Drawing-related entries
165   */
166  int w;
167  int h;
168  Colormap cmap;
169  XColor* pal;
170  GC* gcs;
171
172  /*
173   * lookup tables
174   */
175  int* wave_height;
176   
177  /*
178   * Interference sources
179   */
180  struct inter_source* source;
181};
182
183#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
184# define TARGET(c) ((c)->back_buf ? (c)->back_buf : \
185                    (c)->pix_buf ? (c)->pix_buf : (c)->win)
186#else  /* HAVE_DOUBLE_BUFFER_EXTENSION */
187# define TARGET(c) ((c)->pix_buf ? (c)->pix_buf : (c)->win)
188#endif /* !HAVE_DOUBLE_BUFFER_EXTENSION */
189
190void inter_init(Display* dpy, Window win, struct inter_context* c)
191{
192  XWindowAttributes xgwa;
193  double H[3], S[3], V[3];
194  int i;
195  int mono;
196  int gray;
197  XGCValues val;
198  unsigned long valmask = 0;
199  Bool dbuf = get_boolean_resource ("doubleBuffer", "Boolean");
200
201  memset (c, 0, sizeof(*c));
202
203  c->dpy = dpy;
204  c->win = win;
205
206  XGetWindowAttributes(c->dpy, c->win, &xgwa);
207  c->w = xgwa.width;
208  c->h = xgwa.height;
209  c->cmap = xgwa.colormap;
210
211#ifdef HAVE_XSHM_EXTENSION
212  c->use_shm = get_boolean_resource("useSHM", "Boolean");
213#endif /*  HAVE_XSHM_EXTENSION */
214
215  if (dbuf)
216    {
217#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
218      c->back_buf = xdbe_get_backbuffer (c->dpy, c->win, XdbeUndefined);
219#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
220
221#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
222      if (!c->back_buf)
223#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
224        c->pix_buf = XCreatePixmap (dpy, win, xgwa.width, xgwa.height,
225                                    xgwa.depth);
226    }
227
228  val.function = GXcopy;
229  c->copy_gc = XCreateGC(c->dpy, TARGET(c), GCFunction, &val);
230
231  c->count = get_integer_resource("count", "Integer");
232  if(c->count < 1)
233    c->count = 1;
234  c->grid_size = get_integer_resource("gridsize", "Integer");
235  if(c->grid_size < 1)
236    c->grid_size = 1;
237  mono = get_boolean_resource("mono", "Boolean");
238  if(!mono) {
239    c->colors = get_integer_resource("ncolors", "Integer");
240    if(c->colors < 2)
241      c->colors = 2;
242  }
243  c->hue = get_integer_resource("hue", "Float");
244  while (c->hue < 0 || c->hue >= 360)
245    c->hue = frand(360.0);
246  c->speed = get_integer_resource("speed", "Integer");
247  c->shift = get_float_resource("color-shift", "Float");
248  while(c->shift >= 360.0)
249    c->shift -= 360.0;
250  while(c->shift <= -360.0)
251    c->shift += 360.0;
252  c->radius = get_integer_resource("radius", "Integer");;
253  if(c->radius < 1)
254    c->radius = 1;
255
256#ifdef USE_XIMAGE
257
258  c->ximage = 0;
259
260# ifdef HAVE_XSHM_EXTENSION
261  if (c->use_shm)
262    {
263      c->ximage = create_xshm_image(dpy, xgwa.visual, xgwa.depth,
264                                    ZPixmap, 0, &c->shm_info,
265                                    xgwa.width, c->grid_size);
266      if (!c->ximage)
267        c->use_shm = False;
268    }
269# endif /* HAVE_XSHM_EXTENSION */
270
271  if (!c->ximage)
272    {
273      c->ximage =
274        XCreateImage (dpy, xgwa.visual,
275                      xgwa.depth, ZPixmap, 0, 0, /* depth, fmt, offset, data */
276                      xgwa.width, c->grid_size,  /* width, height */
277                      8, 0);                     /* pad, bpl */
278      c->ximage->data = (unsigned char *)
279        calloc(c->ximage->height, c->ximage->bytes_per_line);
280    }
281#endif /* USE_XIMAGE */
282
283  if(!mono) {
284    c->pal = calloc(c->colors, sizeof(XColor));
285
286    gray = get_boolean_resource("gray", "Boolean");
287    if(!gray) {
288      H[0] = c->hue;
289      H[1] = H[0] + c->shift < 360.0 ? H[0]+c->shift : H[0] + c->shift-360.0;
290      H[2] = H[1] + c->shift < 360.0 ? H[1]+c->shift : H[1] + c->shift-360.0;
291      S[0] = S[1] = S[2] = 1.0;
292      V[0] = V[1] = V[2] = 1.0;
293    } else {
294      H[0] = H[1] = H[2] = 0.0;
295      S[0] = S[1] = S[2] = 0.0;
296      V[0] = 1.0; V[1] = 0.5; V[2] = 0.0;
297    }
298
299    make_color_loop(c->dpy, c->cmap,
300                    H[0], S[0], V[0],
301                    H[1], S[1], V[1],
302                    H[2], S[2], V[2],
303                    c->pal, &(c->colors),
304                    True, False);
305    if(c->colors < 2) { /* color allocation failure */
306      mono = 1;
307      free(c->pal);
308    }
309  }
310
311  if(mono) { /* DON'T else this with the previous if! */
312    c->colors = 2;
313    c->pal = calloc(2, sizeof(XColor));
314    c->pal[0].pixel = BlackPixel(c->dpy, DefaultScreen(c->dpy));
315    c->pal[1].pixel = WhitePixel(c->dpy, DefaultScreen(c->dpy));
316  }   
317
318  valmask = GCForeground;
319  c->gcs = calloc(c->colors, sizeof(GC));
320  for(i = 0; i < c->colors; i++) {
321    val.foreground = c->pal[i].pixel;   
322    c->gcs[i] = XCreateGC(c->dpy, TARGET(c), valmask, &val);
323  }
324
325  c->wave_height = calloc(c->radius, sizeof(int));
326  for(i = 0; i < c->radius; i++) {
327    float max =
328      ((float)c->colors) *
329      ((float)c->radius - (float)i) /
330      ((float)c->radius);
331    c->wave_height[i] =
332      (int)
333      ((max + max*cos((double)i/50.0)) / 2.0);
334  }
335
336  c->source = calloc(c->count, sizeof(struct inter_source));
337  for(i = 0; i < c->count; i++) {
338    c->source[i].x_theta = frand(2.0)*3.14159;
339    c->source[i].y_theta = frand(2.0)*3.14159;
340  }
341
342}
343
344#define source_x(c, i) \
345  (c->w/2 + ((int)(cos(c->source[i].x_theta)*((float)c->w/2.0))))
346#define source_y(c, i) \
347  (c->h/2 + ((int)(cos(c->source[i].y_theta)*((float)c->h/2.0))))
348
349/*
350 * this is rather suboptimal. the sqrt() doesn't seem to be a big
351 * performance hit, but all those separate XFillRectangle()'s are.
352 * hell, it's just a quick hack anyway -- if someone wishes to tune
353 * it, go ahead!
354 */
355
356void do_inter(struct inter_context* c)
357{
358  int i, j, k;
359  int result;
360  int dist;
361  int g;
362
363  int dx, dy;
364
365  for(i = 0; i < c->count; i++) {
366    c->source[i].x_theta += (c->speed/1000.0);
367    if(c->source[i].x_theta > 2.0*3.14159)
368      c->source[i].x_theta -= 2.0*3.14159;
369    c->source[i].y_theta += (c->speed/1000.0);
370    if(c->source[i].y_theta > 2.0*3.14159)
371      c->source[i].y_theta -= 2.0*3.14159;
372    c->source[i].x = source_x(c, i);
373    c->source[i].y = source_y(c, i);
374  }
375
376  g = c->grid_size;
377
378  for(j = 0; j < c->h/g; j++) {
379    for(i = 0; i < c->w/g; i++) {
380      result = 0;
381      for(k = 0; k < c->count; k++) {
382        dx = i*g + g/2 - c->source[k].x;
383        dy = j*g + g/2 - c->source[k].y;
384        dist = sqrt(dx*dx + dy*dy); /* what's the performance penalty here? */
385        result += (dist > c->radius ? 0 : c->wave_height[dist]);
386      }
387      result %= c->colors;
388
389#ifdef USE_XIMAGE
390      /* Fill in these `gridsize' horizontal bits in the scanline */
391      for(k = 0; k < g; k++)
392        XPutPixel(c->ximage, (g*i)+k, 0, c->pal[result].pixel);
393
394#else  /* !USE_XIMAGE */
395      XFillRectangle(c->dpy, TARGET(c), c->gcs[result], g*i, g*j, g, g);
396#endif /* !USE_XIMAGE */
397    }
398
399#ifdef USE_XIMAGE
400
401    /* Only the first scanline of the image has been filled in; clone that
402       scanline to the rest of the `gridsize' lines in the ximage */
403    for(k = 0; k < (g-1); k++)
404      memcpy(c->ximage->data + (c->ximage->bytes_per_line * (k + 1)),
405             c->ximage->data + (c->ximage->bytes_per_line * k),
406             c->ximage->bytes_per_line);
407
408    /* Move the bits for this horizontal stripe to the server. */
409# ifdef HAVE_XSHM_EXTENSION
410    if (c->use_shm)
411      XShmPutImage(c->dpy, TARGET(c), c->copy_gc, c->ximage,
412                   0, 0, 0, g*j, c->ximage->width, c->ximage->height,
413                   False);
414    else
415# endif /*  HAVE_XSHM_EXTENSION */
416      XPutImage(c->dpy, TARGET(c), c->copy_gc, c->ximage,
417                0, 0, 0, g*j, c->ximage->width, c->ximage->height);
418
419#endif /* USE_XIMAGE */
420  }
421
422#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
423  if (c->back_buf)
424    {
425      XdbeSwapInfo info[1];
426      info[0].swap_window = c->win;
427      info[0].swap_action = XdbeUndefined;
428      XdbeSwapBuffers(c->dpy, info, 1);
429    }
430  else
431#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
432    if (c->pix_buf)
433      {
434        XCopyArea (c->dpy, c->pix_buf, c->win, c->copy_gc,
435                   0, 0, c->w, c->h, 0, 0);
436      }
437
438  XSync(c->dpy, False);
439}
440
441void screenhack(Display *dpy, Window win)
442{
443  struct inter_context c;
444  int delay;
445
446  delay = get_integer_resource("delay", "Integer");
447
448  inter_init(dpy, win, &c);
449  while(1) {
450    do_inter(&c);
451    screenhack_handle_events (dpy);
452    if(delay) usleep(delay);
453  }
454}
Note: See TracBrowser for help on using the repository browser.