1 /* kaleidescope, Copyright (c) 1997 Ron Tapia <tapia@nmia.com>
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
13 * The above, for lack of a better copyright statement in easy reach
14 * was just lifted from the xscreensaver source.
16 * One of the odd things about this hack is that the radial motion of the
17 * segments depends on roundoff error alone.
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.
32 #include "screenhack.h"
34 #define NEWX(x,y) ((x*g.costheta) + (y*g.sintheta))
35 #define NEWY(x,y) ((y*g.costheta) - (x*g.sintheta))
39 int xoff, yoff; /* offset of origin xmax/2, ymax/2 */
40 int xmax, ymax; /* width, height of window */
41 float costheta, sintheta;
53 unsigned int default_fg_pixel;
57 unsigned short redmin,redrange,greenmin,greenrange,bluemin,bluerange;
61 typedef struct Obj OBJECT;
65 void (*propogate) (OBJECT *);
66 void (*draw) (OBJECT *);
67 void (*init) (OBJECT *);
71 typedef struct KSEGMENT {
72 struct KSEGMENT *next;
75 short int x1,y1,x2,y2; /* these are in the natural coordinate system */
76 XSegment *xsegments; /* these are in the X coordinate system */
79 /* BEGIN global variables */
84 char *progclass = "Kaleidescope";
92 "*local_rotation: -59",
93 "*global_rotation: 1",
94 "*spring_constant: 5",
105 XrmOptionDescRec 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 },
123 /* END global variables */
126 krandom_color(XColor *color)
131 if((g.color_mode == 0) || (g.color_mode == 1)) {
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;
137 if(!XAllocColor(g.dpy, g.cmap, color)) {
138 color->pixel = g.default_fg_pixel;
142 color->pixel = g.default_fg_pixel;
149 kcopy_color(XColor *to, XColor *from)
152 to->green = from->green;
153 to->blue = from->blue;
154 to->pixel = from->pixel;
158 kcycle_color(XColor *color,
159 unsigned short redstep,
160 unsigned short greenstep,
161 unsigned short bluestep)
163 unsigned short red,green,blue;
165 if (! g.color_mode) {
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;
173 if(!XAllocColor(g.dpy, g.cmap, color)) {
174 /* printf("couldn't alloc color...\n"); */
175 color->pixel = g.default_fg_pixel;
177 copy.pixel = color->pixel;
180 color->red = red - redstep;
181 color->green = green- greenstep;
182 color->blue = blue - bluestep;
189 create_ksegment (void)
191 Ksegment *seg, *prev;
194 unsigned short redstep,bluestep,greenstep;
196 krandom_color(&new_color);
198 redstep = new_color.red/(2 * g.ntrails);
199 greenstep = new_color.green/(2 * g.ntrails);
200 bluestep = new_color.blue/(2 * g.ntrails);
202 seg = (Ksegment *) malloc(sizeof(Ksegment));
203 seg->xsegments = (XSegment *) malloc(g.symmetry * sizeof(XSegment));
206 for(i=0; i< (g.ntrails - 1); i++) {
208 kcycle_color(&new_color,redstep,greenstep,bluestep);
210 kcopy_color(&(prev->color), &new_color);
212 prev->next = (Ksegment*)malloc(sizeof(Ksegment));
213 (prev->next)->xsegments = (XSegment*)malloc(g.symmetry * sizeof(XSegment));
220 kcopy_color(&(prev->color), &new_color);
226 init_ksegment (OBJECT *obj)
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;
238 draw_ksegment (OBJECT *obj)
240 register short x1, y1, x2, y2;
243 static int counter=0;
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;
255 /* maybe throw away values and start over */
256 if( ((dx*dx) + (dy * dy)) < 100) {
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;
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);
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;
276 XSetForeground(g.dpy, g.draw_gc, (((Ksegment *)obj->cur)->color).pixel);
278 XDrawSegments(g.dpy, g.window, g.draw_gc, ((Ksegment *)obj->cur)->xsegments, g.symmetry);
279 ((Ksegment *)obj->cur)->drawn = 1;
281 if (((((Ksegment *)obj->cur)->next)->drawn) != 0) {
282 XDrawSegments(g.dpy, g.window, g.erase_gc, ((Ksegment *)obj->cur)->next->xsegments, g.symmetry);
287 propogate_ksegment(OBJECT *obj)
290 short int x1,y1,x2,y2;
291 short int midx,midy,nmidx,nmidy;
292 float lsin, lcos, gsin, gcos;
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);
302 x1 = ((Ksegment *) obj->cur)->x1;
303 y1 = ((Ksegment *) obj->cur)->y1;
304 x2 = ((Ksegment *) obj->cur)->x2;
305 y2 = ((Ksegment *) obj->cur)->y2;
310 nmidx = midx*gcos + midy*gsin;
311 nmidy = midy*gcos - midx*gsin;
319 /* This is where we move to the next ksegment... */
320 obj->cur = ((Ksegment *)obj->cur)->next;
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;
334 for (i=0; i<g.nobjects; i++) {
335 (objects[i].init)(objects + i);
340 create_objects (void)
344 objects = (OBJECT *) malloc(g.nobjects * sizeof(OBJECT));
346 for (i=0; i< g.nsegments; i++) {
347 objects[i].cur = create_ksegment();
350 objects[i].propogate = propogate_ksegment;
351 objects[i].draw = draw_ksegment;
352 objects[i].init = init_ksegment;
355 /* Here we can add creation functions for other object types. */
360 propogate_objects (void)
364 for(i=0; i<g.nobjects; i++) {
365 objects[i].propogate(objects + i);
374 for(i=0; i<g.nobjects; i++) {
375 objects[i].draw(objects + i);
380 init_g (Display *dpy, Window window)
382 XWindowAttributes xgwa;
384 char *color_mode_str;
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;
399 color_mode_str = get_string_resource("color_mode", "color_mode");
401 /* make into an enum... */
402 if(!color_mode_str) {
404 } else if (!strcmp(color_mode_str, "greedy")) {
406 } else if (!strcmp(color_mode_str, "nice")) {
412 XGetWindowAttributes (dpy, (Drawable) window, &xgwa);
414 g.ymax = xgwa.height;
417 g.costheta = cos(2*M_PI/g.symmetry);
418 g.sintheta = sin(2*M_PI/g.symmetry);
419 g.cmap = xgwa.colormap;
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");
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);
433 gcv.foreground = get_pixel_resource ("background", "Background", g.dpy, g.cmap);
434 g.erase_gc = XCreateGC (dpy, (Drawable) window, GCForeground|GCLineWidth|GCCapStyle,&gcv);
438 screenhack (Display *dpy, Window window)
440 init_g (dpy, window);
449 screenhack_usleep(g.delay);