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

Revision 15683, 14.3 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, 1998, 2000
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 * This code derived from TI Explorer Lisp code by Joe Keane, Fritz Mueller,
13 * and Jamie Zawinski.
14 */
15
16#include <math.h>
17#include "screenhack.h"
18
19#define POINT_COUNT 16
20#define LINE_COUNT 32
21
22#define ANGLE_SCALE 0.001
23
24struct line_info
25{
26  char li_ip;
27  char li_iq;
28  char li_color;
29  char li_pad;
30};
31
32struct point_state
33{
34  short old_x, old_y;
35  short new_x, new_y;
36};
37
38struct hyper_state
39{
40  char hs_stop;
41  char hs_icon;
42  char hs_resize;
43  char hs_redraw;
44  Display *hs_display;
45  Window hs_window;
46  float hs_two_observer_z;
47  float hs_offset_x;
48  float hs_offset_y;
49  float hs_unit_scale;
50  int hs_delay;
51  GC hs_color_gcs[8];
52#if 0
53  double hs_angle_xy;
54  double hs_angle_xz;
55  double hs_angle_yz;
56  double hs_angle_xw;
57  double hs_angle_yw;
58  double hs_angle_zw;
59#endif
60  double hs_cos_xy, hs_sin_xy;
61  double hs_cos_xz, hs_sin_xz;
62  double hs_cos_yz, hs_sin_yz;
63  double hs_cos_xw, hs_sin_xw;
64  double hs_cos_yw, hs_sin_yw;
65  double hs_cos_zw, hs_sin_zw;
66  double hs_ref_ax, hs_ref_ay, hs_ref_az, hs_ref_aw;
67  double hs_ref_bx, hs_ref_by, hs_ref_bz, hs_ref_bw;
68  double hs_ref_cx, hs_ref_cy, hs_ref_cz, hs_ref_cw;
69  double hs_ref_dx, hs_ref_dy, hs_ref_dz, hs_ref_dw;
70  struct point_state hs_points[POINT_COUNT];
71};
72
73static const struct line_info line_table[LINE_COUNT];
74
75static void init (struct hyper_state *hs);
76static void hyper (struct hyper_state *hs);
77static void check_events (struct hyper_state *hs);
78static void set_sizes (struct hyper_state *hs, int width, int height);
79
80static struct hyper_state hyper_state;
81
82
83char *progclass = "Hypercube";
84
85char *defaults[] =
86{
87  "*observer-z: 3",
88  "*delay: 10000",
89  "*xy: 3",
90  "*xz: 5",
91  "*yw: 10",
92  "*yz: 0",
93  "*xw: 0",
94  "*zw: 0",
95  ".background: black",
96  ".foreground: white",
97  "*color0:     magenta",
98  "*color3:     #FF0093",
99  "*color1:     yellow",
100  "*color2:     #FF9300",
101  "*color4:     green",
102  "*color7:     #00FFD0",
103  "*color5:     #8080FF",
104  "*color6:     #00D0FF",
105
106  0
107};
108
109XrmOptionDescRec options [] =
110{
111  { "-color0",          ".color0",      XrmoptionSepArg, 0 },
112  { "-color1",          ".color1",      XrmoptionSepArg, 0 },
113  { "-color2",          ".color2",      XrmoptionSepArg, 0 },
114  { "-color3",          ".color3",      XrmoptionSepArg, 0 },
115  { "-color4",          ".color4",      XrmoptionSepArg, 0 },
116  { "-color5",          ".color5",      XrmoptionSepArg, 0 },
117  { "-color6",          ".color6",      XrmoptionSepArg, 0 },
118  { "-color7",          ".color7",      XrmoptionSepArg, 0 },
119
120  { "-xw",              ".xw",          XrmoptionSepArg, 0 },
121  { "-xy",              ".xy",          XrmoptionSepArg, 0 },
122  { "-xz",              ".xz",          XrmoptionSepArg, 0 },
123  { "-yw",              ".yw",          XrmoptionSepArg, 0 },
124  { "-yz",              ".yz",          XrmoptionSepArg, 0 },
125  { "-zw",              ".zw",          XrmoptionSepArg, 0 },
126
127  { "-observer-z",      ".observer-z",  XrmoptionSepArg, 0 },
128  { "-delay",           ".delay",       XrmoptionSepArg, 0 },
129  { 0, 0, 0, 0 }
130};
131
132
133void
134screenhack (Display *d, Window w)
135{
136  struct hyper_state *hs;
137
138  hs = &hyper_state;
139  hs->hs_display = d;
140  hs->hs_window = w;
141
142  init (hs);
143
144  hyper (hs);
145}
146
147
148static void
149init (struct hyper_state *hs)
150{
151  Display *dpy;
152  Window win;
153  XGCValues gcv;
154  Colormap cmap;
155  unsigned long bg_pixel;
156  int delay;
157  float observer_z;
158
159  dpy = hs->hs_display;
160  win = hs->hs_window;
161
162  observer_z = get_float_resource ("observer-z", "Float");
163  if (observer_z < 1.125)
164    observer_z = 1.125;
165  /* hs->hs_observer_z = observer_z; */
166  hs->hs_two_observer_z = 2.0 * observer_z;
167
168  {
169    int root;
170    XWindowAttributes wa;
171    int width;
172    int height;
173
174    root = get_boolean_resource("root", "Boolean");
175    XGetWindowAttributes (dpy, win, &wa);
176    XSelectInput(dpy, win, root ? ExposureMask :
177                 wa.your_event_mask | ExposureMask |
178                 ButtonPressMask | StructureNotifyMask);
179   
180    width = wa.width;
181    height = wa.height;
182    cmap = wa.colormap;
183    set_sizes (hs, width, height);
184  }
185
186  delay = get_integer_resource ("delay", "Integer");
187  hs->hs_delay = delay;
188
189  bg_pixel = get_pixel_resource ("background", "Background", dpy, cmap);
190
191  if (mono_p)
192    {
193      GC black_gc;
194      unsigned long fg_pixel;
195      GC white_gc;
196
197      gcv.function = GXcopy;
198      gcv.foreground = bg_pixel;
199      black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv);
200      fg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
201      gcv.foreground = fg_pixel ^ bg_pixel;
202      white_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv);
203      hs->hs_color_gcs[0] = black_gc;
204      hs->hs_color_gcs[1] = white_gc;
205    }
206  else
207    {
208      int col;
209
210      gcv.function = GXxor;
211      for (col = 0; col < 8; col++)
212        {
213          char buffer[16];
214          unsigned long fg_pixel;
215          GC color_gc;
216
217          sprintf (buffer, "color%d", col);
218          fg_pixel = get_pixel_resource (buffer, "Foreground", dpy, cmap);
219          gcv.foreground = fg_pixel ^ bg_pixel;
220          color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv);
221          hs->hs_color_gcs[col] = color_gc;
222        }
223    }
224
225  hs->hs_ref_ax = 1.0, hs->hs_ref_ay = 0.0, hs->hs_ref_az = 0.0, hs->hs_ref_aw = 0.0;
226  hs->hs_ref_bx = 0.0, hs->hs_ref_by = 1.0, hs->hs_ref_bz = 0.0, hs->hs_ref_bw = 0.0;
227  hs->hs_ref_cx = 0.0, hs->hs_ref_cy = 0.0, hs->hs_ref_cz = 1.0, hs->hs_ref_cw = 0.0;
228  hs->hs_ref_dx = 0.0, hs->hs_ref_dy = 0.0, hs->hs_ref_dz = 0.0, hs->hs_ref_dw = 1.0;
229
230  {
231  double xy;
232  double xz;
233  double yz;
234  double xw;
235  double yw;
236  double zw;
237  double cos_xy, sin_xy;
238  double cos_xz, sin_xz;
239  double cos_yz, sin_yz;
240  double cos_xw, sin_xw;
241  double cos_yw, sin_yw;
242  double cos_zw, sin_zw;
243
244  xy = get_float_resource ("xy", "Float") * ANGLE_SCALE;
245  xz = get_float_resource ("xz", "Float") * ANGLE_SCALE;
246  yz = get_float_resource ("yz", "Float") * ANGLE_SCALE;
247  xw = get_float_resource ("xw", "Float") * ANGLE_SCALE;
248  yw = get_float_resource ("yw", "Float") * ANGLE_SCALE;
249  zw = get_float_resource ("zw", "Float") * ANGLE_SCALE;
250
251  cos_xy = cos (xy), sin_xy = sin (xy);
252  hs->hs_cos_xy = cos_xy, hs->hs_sin_xy = sin_xy;
253  cos_xz = cos (xz), sin_xz = sin (xz);
254  hs->hs_cos_xz = cos_xz, hs->hs_sin_xz = sin_xz;
255  cos_yz = cos (yz), sin_yz = sin (yz);
256  hs->hs_cos_yz = cos_yz, hs->hs_sin_yz = sin_yz;
257  cos_xw = cos (xw), sin_xw = sin (xw);
258  hs->hs_cos_xw = cos_xw, hs->hs_sin_xw = sin_xw;
259  cos_yw = cos (yw), sin_yw = sin (yw);
260  hs->hs_cos_yw = cos_yw, hs->hs_sin_yw = sin_yw;
261  cos_zw = cos (zw), sin_zw = sin (zw);
262  hs->hs_cos_zw = cos_zw, hs->hs_sin_zw = sin_zw;
263  }
264}
265
266
267static void
268hyper (struct hyper_state *hs)
269{
270  int roted;
271
272  roted = 0;
273
274  for (;;)
275    {
276      int icon;
277      int resize;
278      char moved[POINT_COUNT];
279      int redraw;
280      int stop;
281      int delay;
282
283      check_events (hs);
284
285      icon = hs->hs_icon;
286      resize = hs->hs_resize;
287      if (icon || !(roted | resize))
288        goto skip1;
289
290      {
291        float observer_z;
292        float unit_scale;
293        float offset_x;
294        float offset_y;
295        double az, bz, cz, dz;
296        double sum_z;
297        double ax, bx, cx, dx;
298        double sum_x;
299        double ay, by, cy, dy;
300        double sum_y;
301        struct point_state *ps;
302        int old_x;
303        int old_y;
304        double mul;
305        double xf;
306        double yf;
307        int new_x;
308        int new_y;
309        int mov;
310
311
312#define compute(as,bs,cs,ds,i) \
313  az = hs->hs_ref_az; bz = hs->hs_ref_bz; cz = hs->hs_ref_cz; dz = hs->hs_ref_dz; \
314  ax = hs->hs_ref_ax; bx = hs->hs_ref_bx; cx = hs->hs_ref_cx; dx = hs->hs_ref_dx; \
315  ay = hs->hs_ref_ay; by = hs->hs_ref_by; cy = hs->hs_ref_cy; dy = hs->hs_ref_dy; \
316  sum_z = as az bs bz cs cz ds dz; \
317  observer_z = hs->hs_two_observer_z; \
318  unit_scale = hs->hs_unit_scale; \
319  sum_x = as ax bs bx cs cx ds dx; \
320  sum_y = as ay bs by cs cy ds dy; \
321  ps = &hs->hs_points[i]; \
322  mul = unit_scale / (observer_z - sum_z); \
323  offset_x = hs->hs_offset_x; \
324  offset_y = hs->hs_offset_y; \
325  old_x = ps->new_x; \
326  old_y = ps->new_y; \
327  xf = sum_x * mul + offset_x; \
328  yf = sum_y * mul + offset_y; \
329  new_x = (int)rint(xf); \
330  new_y = (int)rint(yf); \
331  ps->old_x = old_x; \
332  ps->old_y = old_y; \
333  ps->new_x = new_x; \
334  ps->new_y = new_y; \
335  mov = old_x != new_x || old_y != new_y; \
336  moved[i] = mov;
337
338        compute (-, -, -, -, 0);
339        compute (-, -, -, +, 1);
340        compute (-, -, +, -, 2);
341        compute (-, -, +, +, 3);
342        compute (-, +, -, -, 4);
343        compute (-, +, -, +, 5);
344        compute (-, +, +, -, 6);
345        compute (-, +, +, +, 7);
346        compute (+, -, -, -, 8);
347        compute (+, -, -, +, 9);
348        compute (+, -, +, -, 10);
349        compute (+, -, +, +, 11);
350        compute (+, +, -, -, 12);
351        compute (+, +, -, +, 13);
352        compute (+, +, +, -, 14);
353        compute (+, +, +, +, 15);
354      }
355
356    skip1:
357      icon = hs->hs_icon;
358      redraw = hs->hs_redraw;
359      if (icon || !(roted | redraw))
360        goto skip2;
361
362      {
363        int lc;
364        const struct line_info *lip;
365        int mono;
366        Display *dpy;
367        Window win;
368
369        lc = LINE_COUNT;
370        lip = &line_table[0];
371        mono = mono_p;
372        dpy = hs->hs_display;
373        win = hs->hs_window;
374
375        while (--lc >= 0)
376          {
377            int ip;
378            int iq;
379            int col;
380            struct point_state *sp;
381            struct point_state *sq;
382            int mov_p;
383            int mov_q;
384            GC erase_gc;
385            GC draw_gc;
386            int p_x;
387            int p_y;
388            int q_x;
389            int q_y;
390
391            ip = lip->li_ip;
392            iq = lip->li_iq;
393            col = lip->li_color;
394            lip++;
395            mov_p = moved[ip];
396            mov_q = moved[iq];
397            if (!(redraw | mov_p | mov_q))
398              continue;
399
400            sp = &hs->hs_points[ip];
401            sq = &hs->hs_points[iq];
402
403            if (mono)
404              {
405                erase_gc = hs->hs_color_gcs[0];
406                draw_gc = hs->hs_color_gcs[1];
407              }
408            else
409              {
410                GC color_gc;
411
412                color_gc = hs->hs_color_gcs[col];
413                erase_gc = color_gc;
414                draw_gc = color_gc;
415              }
416
417            if (!redraw)
418              {
419                p_x = sp->old_x;
420                p_y = sp->old_y;
421                q_x = sq->old_x;
422                q_y = sq->old_y;
423                XDrawLine (dpy, win, erase_gc, p_x, p_y, q_x, q_y);
424              }
425
426            p_x = sp->new_x;
427            p_y = sp->new_y;
428            q_x = sq->new_x;
429            q_y = sq->new_y;
430            XDrawLine (dpy, win, draw_gc, p_x, p_y, q_x, q_y);
431          }
432
433        XFlush (dpy);
434      }
435
436    skip2:
437      stop = hs->hs_stop;
438      roted = 0;
439      if (stop)
440        goto skip3;
441
442      roted = 1;
443
444      {
445        double cos_a;
446        double sin_a;
447        double old_u;
448        double old_v;
449        double new_u;
450        double new_v;
451
452 /* If you get error messages about the following forms, and you think you're
453    using an ANSI C conforming compiler, then you're mistaken.  Possibly you're
454    mixing an ANSI compiler with a non-ANSI preprocessor, or vice versa.
455    Regardless, your system is broken; it's not a bug in this program.
456  */
457#if defined(__STDC__) || defined(__ANSI_CPP__)
458
459#define rotate(name,dim0,dim1) \
460  old_u = hs->hs_ref_##name##dim0; \
461  old_v = hs->hs_ref_##name##dim1; \
462  new_u = old_u * cos_a + old_v * sin_a; \
463  new_v = old_v * cos_a - old_u * sin_a; \
464  hs->hs_ref_##name##dim0 = new_u; \
465  hs->hs_ref_##name##dim1 = new_v;
466
467#define rotates(dim0,dim1) \
468  if (hs->hs_sin_##dim0##dim1 != 0) { \
469    cos_a = hs->hs_cos_##dim0##dim1; \
470    sin_a = hs->hs_sin_##dim0##dim1; \
471    rotate(a,dim0,dim1); \
472    rotate(b,dim0,dim1); \
473    rotate(c,dim0,dim1); \
474    rotate(d,dim0,dim1); \
475  }
476
477#else /* !__STDC__, courtesy of Andreas Luik <luik@isa.de> */
478
479#define rotate(name,dim0,dim1) \
480  old_u = hs->hs_ref_/**/name/**/dim0; \
481  old_v = hs->hs_ref_/**/name/**/dim1; \
482  new_u = old_u * cos_a + old_v * sin_a; \
483  new_v = old_v * cos_a - old_u * sin_a; \
484  hs->hs_ref_/**/name/**/dim0 = new_u; \
485  hs->hs_ref_/**/name/**/dim1 = new_v;
486
487#define rotates(dim0,dim1) \
488  if (hs->hs_sin_/**/dim0/**/dim1 != 0) { \
489    cos_a = hs->hs_cos_/**/dim0/**/dim1; \
490    sin_a = hs->hs_sin_/**/dim0/**/dim1; \
491    rotate(a,dim0,dim1); \
492    rotate(b,dim0,dim1); \
493    rotate(c,dim0,dim1); \
494    rotate(d,dim0,dim1); \
495  }
496
497#endif /* !__STDC__ */
498
499        rotates (x,y);
500        rotates (x,z);
501        rotates (y,z);
502        rotates (x,w);
503        rotates (y,w);
504        rotates (z,w);
505      }
506
507    skip3:
508      /* stop = hs->hs_stop; */
509      delay = hs->hs_delay;
510      if (stop && delay < 10000)
511        delay = 10000;
512      if (delay > 0)
513        usleep (delay);
514    }
515}
516
517
518static void
519check_events (struct hyper_state *hs)
520{
521  Display *dpy;
522  int count;
523  int ic;
524  int resize;
525  Window win;
526  int redraw;
527
528  dpy = hs->hs_display;
529  count = XEventsQueued (dpy, QueuedAfterReading);
530  ic = count;
531  hs->hs_resize = 0;
532  hs->hs_redraw = 0;
533
534  while (--ic >= 0)
535    {
536      XEvent    e;
537
538      XNextEvent (dpy, &e);
539
540      switch (e.type)
541        {
542        case Expose:
543          hs->hs_icon = 0;
544          hs->hs_redraw = 1;
545          break;
546
547        case ConfigureNotify:
548          hs->hs_icon = 0;
549          hs->hs_resize = 1;
550          hs->hs_redraw = 1;
551          break;
552
553        case ButtonPress:
554          switch (e.xbutton.button)
555            {
556            case 2:
557              hs->hs_stop = !hs->hs_stop;
558              break;
559            default:
560              break;
561            }
562          break;
563
564        case UnmapNotify:
565          hs->hs_icon = 1;
566          hs->hs_redraw = 0;
567          break;
568
569        default:
570          screenhack_handle_event(dpy, &e);
571          break;
572        }
573    }
574
575  resize = hs->hs_resize;
576  win = hs->hs_window;
577  if (resize)
578    {
579      XWindowAttributes wa;
580      int width;
581      int height;
582
583      XGetWindowAttributes (dpy, win, &wa);
584      width = wa.width;
585      height = wa.height;
586      set_sizes (&hyper_state, width, height);
587    }
588
589  redraw = hs->hs_redraw;
590  if (redraw)
591    XClearWindow (dpy, win);
592}
593
594
595static void
596set_sizes (struct hyper_state *hs, int width, int height)
597{
598  double observer_z;
599  int min_dim;
600  double var;
601  double offset_x;
602  double offset_y;
603  double unit_scale;
604
605  observer_z = 0.5 * hs->hs_two_observer_z;
606  min_dim = width < height ? width : height;
607  var = sqrt(observer_z * observer_z - 1.0);
608  offset_x = 0.5 * (double)(width - 1);
609  offset_y = 0.5 * (double)(height - 1);
610  unit_scale = 0.4 * min_dim * var;
611  hs->hs_offset_x = (float)offset_x;
612  hs->hs_offset_y = (float)offset_y;
613  hs->hs_unit_scale = (float)unit_scale;
614}
615
616
617/* data */
618
619static const struct line_info line_table[LINE_COUNT] =
620{
621    { 0, 1, 0, },
622    { 0, 2, 0, },
623    { 1, 3, 0, },
624    { 2, 3, 0, },
625    { 4, 5, 1, },
626    { 4, 6, 1, },
627    { 5, 7, 1, },
628    { 6, 7, 1, },
629    { 0, 4, 4, },
630    { 0, 8, 4, },
631    { 4, 12, 4, },
632    { 8, 12, 4, },
633    { 1, 5, 5, },
634    { 1, 9, 5, },
635    { 5, 13, 5, },
636    { 9, 13, 5, },
637    { 2, 6, 6, },
638    { 2, 10, 6, },
639    { 6, 14, 6, },
640    { 10, 14, 6, },
641    { 3, 7, 7, },
642    { 3, 11, 7, },
643    { 7, 15, 7, },
644    { 11, 15, 7, },
645    { 8, 9, 2, },
646    { 8, 10, 2, },
647    { 9, 11, 2, },
648    { 10, 11, 2, },
649    { 12, 13, 3, },
650    { 12, 14, 3, },
651    { 13, 15, 3, },
652    { 14, 15, 3, },
653};
654
Note: See TracBrowser for help on using the repository browser.