source: trunk/third/xscreensaver/hacks/kaleidescope.c @ 12203

Revision 12203, 12.3 KB checked in by ghudson, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12202, which included commits to RCS files with non-trunk default branches.
Line 
1/* kaleidescope, Copyright (c) 1997 Ron Tapia <tapia@nmia.com>
2 *
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation.  No representations are made about the suitability of this
8 * software for any purpose.  It is provided "as is" without express or
9 * implied warranty.
10 */
11
12/*
13 * The above, for lack of a better copyright statement in easy reach
14 * was just lifted from the xscreensaver source.
15 *
16 * One of the odd things about this hack is that the radial motion of the
17 * segments depends on roundoff error alone.
18 *
19 * I tried to make the source easy to add other shapes. So far, I've
20 * only messed with elipses and I couldn't do much with them that looked
21 * cool. A nice addition would be to add some sort of spline based shapes.
22 * Maybe rectangles would look nice.
23 *
24 */
25
26
27#include <stdio.h>
28#include <math.h>
29#include <time.h>
30#include <X11/Xlib.h>
31#include "spline.h"
32#include "screenhack.h"
33
34#define NEWX(x,y) ((x*g.costheta) + (y*g.sintheta))
35#define NEWY(x,y) ((y*g.costheta) - (x*g.sintheta))
36
37
38typedef struct {
39  int  xoff, yoff;                    /* offset of origin xmax/2, ymax/2 */
40  int  xmax, ymax;                    /* width, height of window */
41  float costheta, sintheta;           
42  int symmetry;                       
43  int ntrails;         
44  int nsegments;
45  int narcs;
46  int nobjects;
47  int local_rotation;
48  int global_rotation;
49  int spring_constant;
50  Colormap cmap;
51  GC  draw_gc;
52  GC  erase_gc;
53  unsigned int default_fg_pixel;
54  Display *dpy;
55  Window window;
56  unsigned long delay;
57  unsigned short redmin,redrange,greenmin,greenrange,bluemin,bluerange;
58  int color_mode;
59} GLOBAL;
60
61typedef struct Obj OBJECT;
62struct Obj {
63  int type;
64  int time;
65  void (*propogate) (OBJECT *);
66  void (*draw) (OBJECT *);
67  void (*init) (OBJECT *);
68  void *cur;
69};
70
71typedef struct KSEGMENT {
72  struct KSEGMENT *next;
73  XColor color;
74  int drawn;
75  short int x1,y1,x2,y2;  /* these are in the natural coordinate system */
76  XSegment  *xsegments;  /* these are in the X coordinate system */
77} Ksegment;
78
79/* BEGIN global variables */
80
81GLOBAL g;
82OBJECT *objects;
83
84char *progclass = "Kaleidescope";
85char *defaults [] = {
86  ".background:      black",
87  ".foreground:      white",
88  "*color_mode:      nice",
89  "*symmetry:          11",
90  "*ntrails:          100",
91  "*nsegments:          7",
92  "*local_rotation:   -59",
93  "*global_rotation:    1",
94  "*spring_constant:    5",
95  "*delay:          20000",
96  "*redmin:         30000",
97  "*redrange:       20000",
98  "*greenmin:       30000",
99  "*greenrange:     20000",
100  "*bluemin:        30000",
101  "*bluerange:      20000",
102  0
103};
104
105XrmOptionDescRec options [] = {
106  { "-color_mode",       ".color_mode",     XrmoptionSepArg, 0 },
107  { "-symmetry",        ".symmetry",        XrmoptionSepArg, 0 },
108  { "-nsegments",       ".nsegments",       XrmoptionSepArg, 0 },
109  { "-ntrails",         ".ntrails",         XrmoptionSepArg, 0 },
110  { "-local_rotation",  ".local_rotation",  XrmoptionSepArg, 0 },
111  { "-global_rotation", ".global_rotation", XrmoptionSepArg, 0 },
112  { "-delay",           ".delay",           XrmoptionSepArg, 0 },
113  { "-spring_constant", ".spring_constant", XrmoptionSepArg, 0 },
114  { "-redmin",          ".redmin",          XrmoptionSepArg, 0 },
115  { "-redrange",        ".redmin",          XrmoptionSepArg, 0 },
116  { "-bluemin",         ".bluemin",         XrmoptionSepArg, 0 },
117  { "-bluerange",       ".bluerange",       XrmoptionSepArg, 0 },
118  { "-greenmin",        ".greenmin",        XrmoptionSepArg, 0 },
119  { "-greenrange",      ".greenrange",      XrmoptionSepArg, 0 },
120  { 0, 0, 0, 0 }
121};
122
123/* END global variables */
124
125static void
126krandom_color(XColor *color)
127{
128  int r;
129  r = random() % 3;
130
131  if((g.color_mode == 0) || (g.color_mode == 1)) {
132
133    color->blue  = ((r = random()) % g.bluerange) + g.bluemin;
134    color->green = ((r = random()) % g.greenrange) + g.greenmin;
135    color->red   = ((r = random()) % g.redrange) + g.redmin;
136
137    if(!XAllocColor(g.dpy, g.cmap, color)) {
138      color->pixel = g.default_fg_pixel;
139    }
140    return;
141  } else {
142    color->pixel = g.default_fg_pixel;
143    return;
144  }
145}
146
147
148static void
149kcopy_color(XColor *to, XColor *from)
150{
151  to->red   = from->red;
152  to->green = from->green;
153  to->blue  = from->blue;
154  to->pixel = from->pixel;
155}
156
157static void
158kcycle_color(XColor *color,
159             unsigned short redstep,
160             unsigned short greenstep,
161             unsigned short bluestep)
162{
163  unsigned short red,green,blue;
164
165  if (! g.color_mode) {
166    XColor copy;
167    color->flags = DoRed|DoGreen|DoBlue;
168    color->red   = (red = color->red) - redstep;
169    color->green = (green = color->green) - greenstep;
170    color->blue  = (blue = color->blue)  - bluestep;
171    copy = *color;
172
173    if(!XAllocColor(g.dpy, g.cmap, color)) {
174      /* printf("couldn't alloc color...\n"); */
175      color->pixel = g.default_fg_pixel;
176    }
177    copy.pixel = color->pixel;
178    *color = copy;
179
180    color->red   = red   - redstep;
181    color->green = green- greenstep;
182    color->blue  = blue  - bluestep;
183    return;
184  }
185}
186
187
188static Ksegment *
189create_ksegment (void)
190{
191  Ksegment *seg, *prev;
192  XColor new_color;
193  int i;
194  unsigned short redstep,bluestep,greenstep;
195
196  krandom_color(&new_color);
197
198  redstep = new_color.red/(2 * g.ntrails);
199  greenstep = new_color.green/(2 * g.ntrails);
200  bluestep = new_color.blue/(2 * g.ntrails);
201
202  seg            = (Ksegment *) malloc(sizeof(Ksegment));
203  seg->xsegments = (XSegment  *) malloc(g.symmetry * sizeof(XSegment));
204
205  prev = seg;
206  for(i=0; i< (g.ntrails - 1); i++) {
207
208    kcycle_color(&new_color,redstep,greenstep,bluestep);
209
210    kcopy_color(&(prev->color), &new_color);
211
212    prev->next              = (Ksegment*)malloc(sizeof(Ksegment));
213    (prev->next)->xsegments = (XSegment*)malloc(g.symmetry * sizeof(XSegment));
214    prev->drawn             = 0;
215    prev = (prev->next);
216  }
217
218  prev->drawn = 0;
219  prev->next = seg;
220  kcopy_color(&(prev->color), &new_color);
221
222  return seg;
223}
224
225static void
226init_ksegment (OBJECT *obj)
227{
228
229  /* Give the segment some random values */
230  ((Ksegment *)obj->cur)->x1 = random() % g.xoff;
231  ((Ksegment *)obj->cur)->y1 = random() % g.yoff;
232  ((Ksegment *)obj->cur)->x2 = random() % g.xoff;
233  ((Ksegment *)obj->cur)->y2 = random() % g.yoff;
234}
235
236
237static void
238draw_ksegment (OBJECT *obj)
239{
240  register short x1, y1, x2, y2;
241  int dx, dy;
242  int i;
243  static int counter=0;
244
245  counter++;
246
247  x1 = ((Ksegment *)obj->cur)->x1;   /* in the natural coordinate system */
248  y1 = ((Ksegment *)obj->cur)->y1;
249  x2 = ((Ksegment *)obj->cur)->x2;
250  y2 = ((Ksegment *)obj->cur)->y2;
251
252  dx = x2 - x1;
253  dy = y2 - y1;
254
255  /* maybe throw away values and start over */
256  if( ((dx*dx) + (dy * dy)) < 100) {
257    init_ksegment (obj);
258    x1 = ((Ksegment *)obj->cur)->x1;   /* in the natural coordinate system */
259    y1 = ((Ksegment *)obj->cur)->y1;
260    x2 = ((Ksegment *)obj->cur)->x2;
261    y2 = ((Ksegment *)obj->cur)->y2;
262  }
263
264  for (i=0; i<g.symmetry; i++) {
265    (((Ksegment *)obj->cur)->xsegments)[i].x1 = NEWX(x1,y1);
266    (((Ksegment *)obj->cur)->xsegments)[i].y1 = NEWY(x1,y1);
267    (((Ksegment *)obj->cur)->xsegments)[i].x2 = NEWX(x2,y2);
268    (((Ksegment *)obj->cur)->xsegments)[i].y2 = NEWY(x2,y2);
269
270    (((Ksegment *)obj->cur)->xsegments)[i].x1 = (x1 = (((Ksegment *)obj->cur)->xsegments)[i].x1) + g.xoff;
271    (((Ksegment *)obj->cur)->xsegments)[i].y1 = (y1 = (((Ksegment *)obj->cur)->xsegments)[i].y1) + g.yoff;
272    (((Ksegment *)obj->cur)->xsegments)[i].x2 = (x2 = (((Ksegment *)obj->cur)->xsegments)[i].x2) + g.xoff;
273    (((Ksegment *)obj->cur)->xsegments)[i].y2 = (y2 = (((Ksegment *)obj->cur)->xsegments)[i].y2) + g.yoff;
274  }
275
276  XSetForeground(g.dpy, g.draw_gc, (((Ksegment *)obj->cur)->color).pixel);
277
278  XDrawSegments(g.dpy, g.window, g.draw_gc, ((Ksegment *)obj->cur)->xsegments, g.symmetry);
279  ((Ksegment *)obj->cur)->drawn = 1;
280
281  if (((((Ksegment *)obj->cur)->next)->drawn) != 0) {
282    XDrawSegments(g.dpy, g.window, g.erase_gc, ((Ksegment *)obj->cur)->next->xsegments, g.symmetry);
283  }
284}
285
286static void
287propogate_ksegment(OBJECT *obj)
288{
289  int t;
290  short int x1,y1,x2,y2;
291  short int midx,midy,nmidx,nmidy;
292  float lsin, lcos, gsin, gcos;
293
294  lsin = sin((2*M_PI/10000)*g.local_rotation);
295  lcos = cos((2*M_PI/10000)*g.local_rotation);
296  gsin = sin((2*M_PI/10000)*g.global_rotation);
297  gcos = cos((2*M_PI/10000)*g.global_rotation);
298
299  t=obj->time;
300  obj->time = t + 1;
301
302  x1 = ((Ksegment *) obj->cur)->x1;
303  y1 = ((Ksegment *) obj->cur)->y1;
304  x2 = ((Ksegment *) obj->cur)->x2;
305  y2 = ((Ksegment *) obj->cur)->y2;
306
307  midx = (x1 + x2)/2;
308  midy = (y1 + y2)/2;
309
310  nmidx = midx*gcos + midy*gsin;
311  nmidy = midy*gcos - midx*gsin;
312
313  x1 = x1 - midx;
314  x2 = x2 - midx;
315  y1 = y1 - midy;
316  y2 = y2 - midy;
317
318
319  /* This is where we move to the next ksegment... */
320  obj->cur = ((Ksegment *)obj->cur)->next;
321
322  ((Ksegment *)obj->cur)->x1 = ((x1*lcos) + (y1*lsin)) + nmidx;
323  ((Ksegment *)obj->cur)->y1 = ((y1*lcos) - (x1*lsin)) + nmidy;
324  ((Ksegment *)obj->cur)->x2 = ((x2*lcos) + (y2*lsin)) + nmidx;
325  ((Ksegment *)obj->cur)->y2 = ((y2*lcos) - (x2*lsin)) + nmidy;
326
327  return ;
328}
329
330static void
331init_objects (void)
332{
333  int i;
334  for (i=0; i<g.nobjects; i++) {
335    (objects[i].init)(objects + i);
336  }
337}
338
339static void
340create_objects (void)
341{
342  int i;
343
344  objects = (OBJECT *) malloc(g.nobjects * sizeof(OBJECT));
345
346  for (i=0; i< g.nsegments; i++) {
347    objects[i].cur = create_ksegment();
348    objects[i].type = 1;
349    objects[i].time = 0;
350    objects[i].propogate = propogate_ksegment;
351    objects[i].draw      = draw_ksegment;
352    objects[i].init      = init_ksegment;
353  }
354
355  /* Here we can add creation functions for other object types. */
356}
357
358
359static void
360propogate_objects (void)
361{
362  int i;
363
364  for(i=0; i<g.nobjects; i++) {
365    objects[i].propogate(objects + i);
366  }
367}
368
369static void
370draw_objects (void)
371{
372  int i;
373
374  for(i=0; i<g.nobjects; i++) {
375    objects[i].draw(objects + i);
376  }
377}
378
379static void
380init_g (Display *dpy, Window window)
381{
382  XWindowAttributes xgwa;
383  XGCValues gcv;
384  char *color_mode_str;
385
386  g.dpy    = dpy;
387  g.window = window;
388
389  g.symmetry        = get_integer_resource("symmetry",         "Integer");
390  g.ntrails         = get_integer_resource("ntrails"  ,        "Integer");
391  g.nsegments       = get_integer_resource("nsegments",        "Integer");
392  g.narcs           = get_integer_resource("narcs",            "Integer");
393  g.local_rotation  = get_integer_resource("local_rotation",   "Integer");
394  g.global_rotation = get_integer_resource("global_rotation",  "Integer");
395  g.spring_constant = get_integer_resource("sprint_constatnt", "Integer");
396  g.delay           = get_integer_resource("delay", "Integer");
397  g.nobjects        = g.nsegments + g.narcs;
398
399  color_mode_str = get_string_resource("color_mode", "color_mode");
400
401  /* make into an enum... */
402  if(!color_mode_str) {
403    g.color_mode = 0;
404  } else if (!strcmp(color_mode_str, "greedy")) {
405    g.color_mode = 0;
406  } else if (!strcmp(color_mode_str, "nice")) {
407    g.color_mode = 1;
408  } else {
409    g.color_mode = 2;
410  }
411
412  XGetWindowAttributes (dpy, (Drawable) window, &xgwa);
413  g.xmax     = xgwa.width;
414  g.ymax     = xgwa.height; 
415  g.xoff     = g.xmax/2;
416  g.yoff     = g.ymax/2;
417  g.costheta = cos(2*M_PI/g.symmetry);
418  g.sintheta  = sin(2*M_PI/g.symmetry);
419  g.cmap     = xgwa.colormap;
420
421  g.redmin     = get_integer_resource("redmin",     "Integer");
422  g.redrange   = get_integer_resource("redrange",   "Integer");
423  g.greenmin   = get_integer_resource("greenmin",   "Integer");
424  g.greenrange = get_integer_resource("greenrange", "Integer");
425  g.bluemin    = get_integer_resource("bluemin",    "Integer");
426  g.bluerange  = get_integer_resource("bluerange",  "Integer");
427
428  gcv.line_width = 1;
429  gcv.cap_style  = CapRound;
430  gcv.foreground = g.default_fg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, g.cmap);
431  g.draw_gc      = XCreateGC (dpy, (Drawable) window, GCForeground|GCLineWidth|GCCapStyle, &gcv);
432
433  gcv.foreground = get_pixel_resource ("background", "Background", g.dpy, g.cmap);
434  g.erase_gc     = XCreateGC (dpy, (Drawable) window, GCForeground|GCLineWidth|GCCapStyle,&gcv);
435}
436
437void
438screenhack (Display *dpy, Window window)
439{
440  init_g (dpy, window);
441  create_objects();
442  init_objects ();
443
444  while (1)
445    {
446     draw_objects ();
447     XSync (dpy, False);
448     if(g.delay) {
449       screenhack_handle_events (dpy);
450       usleep(g.delay);
451     }
452     propogate_objects();
453   }
454}
Note: See TracBrowser for help on using the repository browser.