source: trunk/third/xscreensaver/hacks/qix.c @ 15683

Revision 15683, 14.8 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15682, which included commits to RCS files with non-trunk default branches.
Line 
1/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998
2 *  Jamie Zawinski <jwz@jwz.org>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation.  No representations are made about the suitability of this
9 * software for any purpose.  It is provided "as is" without express or
10 * implied warranty.
11 */
12
13#include "screenhack.h"
14#include "alpha.h"
15#include <stdio.h>
16
17#define MAXPOLY 16
18#define SCALE   6
19
20struct qpoint {
21  int x, y;
22  int dx, dy;
23};
24
25struct qline {
26  struct qpoint *p;
27  XColor color;
28  Bool dead;
29};
30
31struct qix {
32  int id;
33  int fp;
34  int nlines;
35  int npoly;
36  struct qline *lines;
37};
38
39static GC draw_gc, erase_gc;
40static unsigned int default_fg_pixel;
41static long maxx, maxy, max_spread, max_size;
42static int color_shift;
43static Bool random_p, solid_p, xor_p, transparent_p, gravity_p;
44static int delay;
45static int count;
46static Colormap cmap;
47static int npoly;
48static Bool additive_p;
49static Bool cmap_p;
50
51
52static GC *gcs[2];
53
54static void
55get_geom (Display *dpy, Window window)
56{
57  XWindowAttributes xgwa;
58  XGetWindowAttributes (dpy, window, &xgwa);
59  maxx = ((long)(xgwa.width+1)<<SCALE)  - 1;
60  maxy = ((long)(xgwa.height+1)<<SCALE) - 1;
61}
62
63static struct qix *
64init_one_qix (Display *dpy, Window window, int nlines, int npoly)
65{
66  int i, j;
67  struct qix *qix = (struct qix *) calloc (1, sizeof (struct qix));
68  qix->nlines = nlines;
69  qix->lines = (struct qline *) calloc (qix->nlines, sizeof (struct qline));
70  qix->npoly = npoly;
71  for (i = 0; i < qix->nlines; i++)
72    qix->lines[i].p = (struct qpoint *)
73      calloc(qix->npoly, sizeof(struct qpoint));
74
75  if (!mono_p && !transparent_p)
76    {
77      hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
78                  &qix->lines[0].color.red, &qix->lines[0].color.green,
79                  &qix->lines[0].color.blue);
80      if (!XAllocColor (dpy, cmap, &qix->lines[0].color))
81        {
82          qix->lines[0].color.pixel = default_fg_pixel;
83          XQueryColor (dpy, cmap, &qix->lines[0].color);
84          if (!XAllocColor (dpy, cmap, &qix->lines[0].color))
85            abort ();
86        }
87    }
88
89  if (max_size == 0)
90    {
91      for (i = 0; i < qix->npoly; i++)
92        {
93          qix->lines[0].p[i].x = random () % maxx;
94          qix->lines[0].p[i].y = random () % maxy;
95        }
96    }
97  else
98    {
99      /*assert(qix->npoly == 2);*/
100      qix->lines[0].p[0].x = random () % maxx;
101      qix->lines[0].p[0].y = random () % maxy;
102      qix->lines[0].p[1].x = qix->lines[0].p[0].x + (random () % (max_size/2));
103      qix->lines[0].p[1].y = qix->lines[0].p[0].y + (random () % (max_size/2));
104      if (qix->lines[0].p[1].x > maxx) qix->lines[0].p[1].x = maxx;
105      if (qix->lines[0].p[1].y > maxy) qix->lines[0].p[1].y = maxy;
106    }
107
108  for (i = 0; i < qix->npoly; i++)
109    {
110      qix->lines[0].p[i].dx = (random () % (max_spread + 1)) - (max_spread /2);
111      qix->lines[0].p[i].dy = (random () % (max_spread + 1)) - (max_spread /2);
112    }
113  qix->lines[0].dead = True;
114
115  for (i = 1; i < qix->nlines; i++)
116    {
117      for(j=0; j<qix->npoly; j++)
118        qix->lines[i].p[j] = qix->lines[0].p[j];
119      qix->lines[i].color = qix->lines[0].color;
120      qix->lines[i].dead = qix->lines[0].dead;
121 
122      if (!mono_p && !transparent_p)
123        if (!XAllocColor (dpy, cmap, &qix->lines[i].color))
124          abort ();
125    }
126  return qix;
127}
128
129
130
131
132static struct qix **
133init_qix (Display *dpy, Window window)
134{
135  int nlines;
136  struct qix **qixes;
137  XGCValues gcv;
138  XWindowAttributes xgwa;
139  XGetWindowAttributes (dpy, window, &xgwa);
140  cmap = xgwa.colormap;
141  count = get_integer_resource ("count", "Integer");
142  if (count <= 0) count = 1;
143  nlines = get_integer_resource ("segments", "Integer");
144  if (nlines <= 0) nlines = 20;
145  npoly = get_integer_resource("poly", "Integer");
146  if (npoly <= 2) npoly = 2;
147  if (npoly > MAXPOLY) npoly = MAXPOLY;
148  get_geom (dpy, window);
149  max_spread = get_integer_resource ("spread", "Integer");
150  if (max_spread <= 0) max_spread = 10;
151  max_spread <<= SCALE;
152  max_size = get_integer_resource ("size", "Integer");
153  if (max_size < 0) max_size = 0;
154  max_size <<= SCALE;
155  random_p = get_boolean_resource ("random", "Boolean");
156  solid_p = get_boolean_resource ("solid", "Boolean");
157  xor_p = get_boolean_resource ("xor", "Boolean");
158  transparent_p = get_boolean_resource ("transparent", "Boolean");
159  gravity_p = get_boolean_resource("gravity", "Boolean");
160  delay = get_integer_resource ("delay", "Integer");
161  color_shift = get_integer_resource ("colorShift", "Integer");
162  if (color_shift < 0 || color_shift >= 360) color_shift = 5;
163  if (delay < 0) delay = 0;
164
165  /* Clear up ambiguities regarding npoly */
166  if (solid_p)
167    {
168      if (npoly != 2)
169        fprintf(stderr, "%s: Can't have -solid and -poly; using -poly 2\n",
170                progname);
171      npoly = 2;
172    }     
173  if (npoly > 2)
174    {
175      if (max_size)
176        fprintf(stderr, "%s: Can't have -poly and -size; using -size 0\n",
177                progname);
178      max_size = 0;
179    }
180
181  if (count == 1 && transparent_p)
182    transparent_p = False; /* it's a no-op */
183
184  if (transparent_p && CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
185    {
186      fprintf (stderr, "%s: -transparent only works on color displays.\n",
187               progname);
188      transparent_p = False;
189    }
190
191  if (xor_p && !transparent_p)
192    mono_p = True;
193
194  gcs[0] = gcs[1] = 0;
195  gcv.foreground = default_fg_pixel =
196    get_pixel_resource ("foreground", "Foreground", dpy, cmap);
197
198  additive_p = get_boolean_resource ("additive", "Boolean");
199  cmap_p = has_writable_cells (xgwa.screen, xgwa.visual);
200
201  if (transparent_p)
202    {
203      unsigned long *plane_masks = 0;
204      unsigned long base_pixel;
205      int nplanes = count;
206      int i;
207
208      allocate_alpha_colors (xgwa.screen, xgwa.visual, cmap,
209                             &nplanes, additive_p, &plane_masks,
210                             &base_pixel);
211
212      if (nplanes <= 1)
213        {
214          fprintf (stderr,
215         "%s: couldn't allocate any color planes; turning -transparent off.\n",
216                   progname);
217          transparent_p = False;
218          if (xor_p)
219            goto NON_TRANSPARENT_XOR;
220          else
221            goto NON_TRANSPARENT;
222        }
223      else if (nplanes != count)
224        {
225          fprintf (stderr,
226                   "%s: only allocated %d color planes (instead of %d).\n",
227                   progname, nplanes, count);
228          count = nplanes;
229        }
230
231      gcs[0] = (GC *) malloc (count * sizeof (GC));
232      gcs[1] = xor_p ? gcs[0] : (GC *) malloc (count * sizeof (GC));
233
234
235      for (i = 0; i < count; i++)
236        {
237          gcv.plane_mask = plane_masks [i];
238          gcv.foreground = ~0;
239
240/*  argh, I'm not sure how to make "-subtractive" work in truecolor...
241          if (!cmap_p && !additive_p)
242            gcv.function = GXclear;
243 */
244
245          if (xor_p)
246            {
247              gcv.function = GXxor;
248              gcs [0][i] = XCreateGC (dpy, window,
249                                      GCForeground|GCFunction|GCPlaneMask,
250                                      &gcv);
251            }
252          else
253            {
254              gcs [0][i] = XCreateGC (dpy, window, GCForeground|GCPlaneMask,
255                                      &gcv);
256              gcv.foreground = 0;
257              gcs [1][i] = XCreateGC (dpy, window, GCForeground|GCPlaneMask,
258                                      &gcv);
259            }
260        }
261
262      XSetWindowBackground (dpy, window, base_pixel);
263      XClearWindow (dpy, window);
264    }
265  else if (xor_p)
266    {
267    NON_TRANSPARENT_XOR:
268      gcv.function = GXxor;
269      gcv.foreground =
270        (default_fg_pixel ^ get_pixel_resource ("background", "Background",
271                                                dpy, cmap));
272      draw_gc = erase_gc = XCreateGC(dpy,window,GCForeground|GCFunction,&gcv);
273    }
274  else
275    {
276    NON_TRANSPARENT:
277      draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
278      gcv.foreground = get_pixel_resource ("background", "Background",
279                                           dpy, cmap);
280      erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
281    }
282
283  qixes = (struct qix **) malloc ((count + 1) * sizeof (struct qix *));
284  qixes [count] = 0;
285  while (count--)
286    {
287      qixes [count] = init_one_qix (dpy, window, nlines, npoly);
288      qixes [count]->id = count;
289    }
290  return qixes;
291}
292
293static void
294free_qline (Display *dpy, Window window, Colormap cmap,
295            struct qline *qline,
296            struct qline *prev,
297            struct qix *qix)
298{
299  int i;
300  if (qline->dead || !prev)
301    ;
302  else if (solid_p)
303    {
304      XPoint points [4];
305      /*assert(qix->npoly == 2);*/
306      points [0].x = qline->p[0].x >> SCALE;
307      points [0].y = qline->p[0].y >> SCALE;
308      points [1].x = qline->p[1].x >> SCALE;
309      points [1].y = qline->p[1].y >> SCALE;
310      points [2].x = prev->p[1].x >> SCALE;
311      points [2].y = prev->p[1].y >> SCALE;
312      points [3].x = prev->p[0].x >> SCALE;
313      points [3].y = prev->p[0].y >> SCALE;
314      XFillPolygon (dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
315                    points, 4, Complex, CoordModeOrigin);
316    }
317  else
318    {
319      /*  XDrawLine (dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
320                     qline->p1.x, qline->p1.y, qline->p2.x, qline->p2.y);*/
321      static XPoint points[MAXPOLY+1];
322      for(i = 0; i < qix->npoly; i++)
323        {
324          points[i].x = qline->p[i].x >> SCALE;
325          points[i].y = qline->p[i].y >> SCALE;
326        }
327      points[qix->npoly] = points[0];
328      XDrawLines(dpy, window, (transparent_p ? gcs[1][qix->id] : erase_gc),
329                 points, qix->npoly+1, CoordModeOrigin);
330    }
331
332  if (!mono_p && !transparent_p)
333    XFreeColors (dpy, cmap, &qline->color.pixel, 1, 0);
334
335  qline->dead = True;
336}
337
338static void
339add_qline (Display *dpy, Window window, Colormap cmap,
340           struct qline *qline,
341           struct qline *prev_qline,
342           struct qix *qix)
343{
344  int i;
345
346  for(i=0; i<qix->npoly; i++)
347    qline->p[i] = prev_qline->p[i];
348  qline->color = prev_qline->color;
349  qline->dead = prev_qline->dead;
350
351#define wiggle(point,delta,max)                                         \
352  if (random_p) delta += (random () % (1 << (SCALE+1))) - (1 << SCALE); \
353  if (delta > max_spread) delta = max_spread;                           \
354  else if (delta < -max_spread) delta = -max_spread;                    \
355  point += delta;                                                       \
356  if (point < 0) point = 0, delta = -delta, point += delta<<1;          \
357  else if (point > max) point = max, delta = -delta, point += delta<<1;
358
359  if (gravity_p)
360    for(i=0; i<qix->npoly; i++)
361      qline->p[i].dy += 3;
362
363  for (i = 0; i < qix->npoly; i++)
364    {
365      wiggle (qline->p[i].x, qline->p[i].dx, maxx);
366      wiggle (qline->p[i].y, qline->p[i].dy, maxy);
367    }
368
369  if (max_size)
370    {
371      /*assert(qix->npoly == 2);*/
372      if (qline->p[0].x - qline->p[1].x > max_size)
373        qline->p[0].x = qline->p[1].x + max_size
374          - (random_p ? random() % max_spread : 0);
375      else if (qline->p[1].x - qline->p[0].x > max_size)
376        qline->p[1].x = qline->p[0].x + max_size
377          - (random_p ? random() % max_spread : 0);
378      if (qline->p[0].y - qline->p[1].y > max_size)
379        qline->p[0].y = qline->p[1].y + max_size
380          - (random_p ? random() % max_spread : 0);
381      else if (qline->p[1].y - qline->p[0].y > max_size)
382        qline->p[1].y = qline->p[0].y + max_size
383          - (random_p ? random() % max_spread : 0);
384    }
385
386  if (!mono_p && !transparent_p)
387    {
388      XColor desired;
389
390      int h;
391      double s, v;
392      rgb_to_hsv (qline->color.red, qline->color.green, qline->color.blue,
393                  &h, &s, &v);
394      h = (h + color_shift) % 360;
395      hsv_to_rgb (h, s, v,
396                  &qline->color.red, &qline->color.green, &qline->color.blue);
397
398      qline->color.flags = DoRed | DoGreen | DoBlue;
399      desired = qline->color;
400      if (XAllocColor (dpy, cmap, &qline->color))
401        {
402          /* XAllocColor returns the actual RGB that the hardware let us
403             allocate.  Restore the requested values into the XColor struct
404             so that limited-resolution hardware doesn't cause the cycle to
405             get "stuck". */
406          qline->color.red = desired.red;
407          qline->color.green = desired.green;
408          qline->color.blue = desired.blue;
409        }
410      else
411        {
412          qline->color = prev_qline->color;
413          if (!XAllocColor (dpy, cmap, &qline->color))
414            abort (); /* same color should work */
415        }
416      XSetForeground (dpy, draw_gc, qline->color.pixel);
417    }
418  if (! solid_p)
419    {
420      /*  XDrawLine (dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
421                     qline->p1.x, qline->p1.y, qline->p2.x, qline->p2.y);*/
422      static XPoint points[MAXPOLY+1];
423      for (i = 0; i < qix->npoly; i++)
424        {
425          points[i].x = qline->p[i].x >> SCALE;
426          points[i].y = qline->p[i].y >> SCALE;
427        }
428      points[qix->npoly] = points[0];
429      XDrawLines(dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
430                 points, qix->npoly+1, CoordModeOrigin);
431    }
432  else if (!prev_qline->dead)
433    {
434      XPoint points [4];
435      points [0].x = qline->p[0].x >> SCALE;
436      points [0].y = qline->p[0].y >> SCALE;
437      points [1].x = qline->p[1].x >> SCALE;
438      points [1].y = qline->p[1].y >> SCALE;
439      points [2].x = prev_qline->p[1].x >> SCALE;
440      points [2].y = prev_qline->p[1].y >> SCALE;
441      points [3].x = prev_qline->p[0].x >> SCALE;
442      points [3].y = prev_qline->p[0].y >> SCALE;
443      XFillPolygon (dpy, window, (transparent_p ? gcs[0][qix->id] : draw_gc),
444                    points, 4, Complex, CoordModeOrigin);
445    }
446
447  qline->dead = False;
448}
449
450static void
451qix1 (Display *dpy, Window window, struct qix *qix)
452{
453  int ofp = qix->fp - 1;
454  static int gtick = 0;
455  if (ofp < 0) ofp = qix->nlines - 1;
456  if (gtick++ == 500)
457    get_geom (dpy, window), gtick = 0;
458  free_qline (dpy, window, cmap, &qix->lines [qix->fp],
459              &qix->lines[(qix->fp + 1) % qix->nlines], qix);
460  add_qline (dpy, window, cmap, &qix->lines[qix->fp], &qix->lines[ofp], qix);
461  if ((++qix->fp) >= qix->nlines)
462    qix->fp = 0;
463}
464
465
466char *progclass = "Qix";
467
468char *defaults [] = {
469  ".background: black",
470  ".foreground: white",
471  "*count:      1",
472  "*segments:   50",
473  "*poly:       2",
474  "*spread:     8",
475  "*size:       0",
476  "*colorShift: 3",
477  "*solid:      false",
478  "*delay:      10000",
479  "*random:     true",
480  "*xor:        false",
481  "*transparent:false",
482  "*gravity:    false",
483  "*additive:   true",
484  0
485};
486
487XrmOptionDescRec options [] = {
488  { "-count",           ".count",       XrmoptionSepArg, 0 },
489  { "-segments",        ".segments",    XrmoptionSepArg, 0 },
490  { "-poly",            ".poly",        XrmoptionSepArg, 0 },
491  { "-spread",          ".spread",      XrmoptionSepArg, 0 },
492  { "-size",            ".size",        XrmoptionSepArg, 0 },
493  { "-delay",           ".delay",       XrmoptionSepArg, 0 },
494  { "-color-shift",     ".colorShift",  XrmoptionSepArg, 0 },
495  { "-random",          ".random",      XrmoptionNoArg, "true" },
496  { "-linear",          ".random",      XrmoptionNoArg, "false" },
497  { "-solid",           ".solid",       XrmoptionNoArg, "true" },
498  { "-hollow",          ".solid",       XrmoptionNoArg, "false" },
499  { "-xor",             ".xor",         XrmoptionNoArg, "true" },
500  { "-no-xor",          ".xor",         XrmoptionNoArg, "false" },
501  { "-transparent",     ".transparent", XrmoptionNoArg, "true" },
502  { "-non-transparent", ".transparent", XrmoptionNoArg, "false" },
503  { "-gravity",         ".gravity",     XrmoptionNoArg, "true" },
504  { "-no-gravity",      ".gravity",     XrmoptionNoArg, "false" },
505  { "-additive",        ".additive",    XrmoptionNoArg, "true" },
506  { "-subtractive",     ".additive",    XrmoptionNoArg, "false" },
507  { 0, 0, 0, 0 }
508};
509
510void
511screenhack (Display *dpy, Window window)
512{
513  struct qix **q1 = init_qix (dpy, window);
514  struct qix **qn;
515  while (1)
516    for (qn = q1; *qn; qn++)
517      {
518        qix1 (dpy, window, *qn);
519        XSync (dpy, False);
520        screenhack_handle_events (dpy);
521        if (delay) usleep (delay);
522      }
523}
Note: See TracBrowser for help on using the repository browser.