1 /* kaleidescope, Copyright (c) 1997, 2006 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.
29 #include "screenhack.h"
32 #define NEWX(x,y) ((x*g->costheta) + (y*g->sintheta))
33 #define NEWY(x,y) ((y*g->costheta) - (x*g->sintheta))
36 typedef struct state GLOBAL;
37 typedef struct Obj OBJECT;
41 void (*propigate) (GLOBAL *, OBJECT *);
42 void (*draw) (GLOBAL *, OBJECT *);
43 void (*init) (GLOBAL *, OBJECT *);
47 typedef struct KSEGMENT {
48 struct KSEGMENT *next;
51 short int x1,y1,x2,y2; /* these are in the natural coordinate system */
52 XSegment *xsegments; /* these are in the X coordinate system */
56 int xoff, yoff; /* offset of origin xmax/2, ymax/2 */
57 int xmax, ymax; /* width, height of window */
58 float costheta, sintheta;
70 unsigned int default_fg_pixel;
74 unsigned short redmin,redrange,greenmin,greenrange,bluemin,bluerange;
84 static const char *kaleidescope_defaults [] = {
93 "*local_rotation: -59",
94 "*global_rotation: 1",
95 "*spring_constant: 5",
100 "*greenrange: 20000",
106 static XrmOptionDescRec kaleidescope_options [] = {
107 { "-color_mode", ".color_mode", XrmoptionSepArg, 0 },
108 { "-symmetry", ".symmetry", XrmoptionSepArg, 0 },
109 { "-nsegments", ".nsegments", XrmoptionSepArg, 0 },
110 { "-ntrails", ".ntrails", XrmoptionSepArg, 0 },
111 { "-local_rotation", ".local_rotation", XrmoptionSepArg, 0 },
112 { "-global_rotation", ".global_rotation", XrmoptionSepArg, 0 },
113 { "-delay", ".delay", XrmoptionSepArg, 0 },
114 { "-spring_constant", ".spring_constant", XrmoptionSepArg, 0 },
115 { "-redmin", ".redmin", XrmoptionSepArg, 0 },
116 { "-redrange", ".redrange", XrmoptionSepArg, 0 },
117 { "-bluemin", ".bluemin", XrmoptionSepArg, 0 },
118 { "-bluerange", ".bluerange", XrmoptionSepArg, 0 },
119 { "-greenmin", ".greenmin", XrmoptionSepArg, 0 },
120 { "-greenrange", ".greenrange", XrmoptionSepArg, 0 },
124 /* END global variables */
127 krandom_color(GLOBAL *g, XColor *color)
132 if((g->color_mode == 0) || (g->color_mode == 1)) {
134 color->blue = ((r = random()) % g->bluerange) + g->bluemin;
135 color->green = ((r = random()) % g->greenrange) + g->greenmin;
136 color->red = ((r = random()) % g->redrange) + g->redmin;
138 if(!XAllocColor(g->dpy, g->cmap, color)) {
139 color->pixel = g->default_fg_pixel;
143 color->pixel = g->default_fg_pixel;
150 kcopy_color(XColor *to, XColor *from)
153 to->green = from->green;
154 to->blue = from->blue;
155 to->pixel = from->pixel;
159 kcycle_color(GLOBAL *g,
161 unsigned short redstep,
162 unsigned short greenstep,
163 unsigned short bluestep)
165 unsigned short red,green,blue;
167 if (! g->color_mode) {
169 color->flags = DoRed|DoGreen|DoBlue;
170 color->red = (red = color->red) - redstep;
171 color->green = (green = color->green) - greenstep;
172 color->blue = (blue = color->blue) - bluestep;
175 if(!XAllocColor(g->dpy, g->cmap, color)) {
176 /* printf("couldn't alloc color...\n"); */
177 color->pixel = g->default_fg_pixel;
179 copy.pixel = color->pixel;
182 color->red = red - redstep;
183 color->green = green- greenstep;
184 color->blue = blue - bluestep;
191 create_ksegment (GLOBAL *g)
193 Ksegment *seg, *prev;
196 unsigned short redstep,bluestep,greenstep;
198 krandom_color(g, &new_color);
200 redstep = new_color.red/(2 * g->ntrails);
201 greenstep = new_color.green/(2 * g->ntrails);
202 bluestep = new_color.blue/(2 * g->ntrails);
204 seg = (Ksegment *) malloc(sizeof(Ksegment));
205 seg->xsegments = (XSegment *) malloc(g->symmetry * sizeof(XSegment));
208 for(i=0; i< (g->ntrails - 1); i++) {
210 kcycle_color(g, &new_color,redstep,greenstep,bluestep);
212 kcopy_color(&(prev->color), &new_color);
214 prev->next = (Ksegment*)malloc(sizeof(Ksegment));
215 (prev->next)->xsegments = (XSegment*)malloc(g->symmetry * sizeof(XSegment));
222 kcopy_color(&(prev->color), &new_color);
228 init_ksegment (GLOBAL *g, OBJECT *obj)
231 /* Give the segment some random values */
232 ((Ksegment *)obj->cur)->x1 = (g->xoff ? random() % g->xoff : 0);
233 ((Ksegment *)obj->cur)->y1 = (g->yoff ? random() % g->yoff : 0);
234 ((Ksegment *)obj->cur)->x2 = (g->xoff ? random() % g->xoff : 0);
235 ((Ksegment *)obj->cur)->y2 = (g->yoff ? random() % g->yoff : 0);
240 draw_ksegment (GLOBAL *g, OBJECT *obj)
242 register short x1, y1, x2, y2;
248 x1 = ((Ksegment *)obj->cur)->x1; /* in the natural coordinate system */
249 y1 = ((Ksegment *)obj->cur)->y1;
250 x2 = ((Ksegment *)obj->cur)->x2;
251 y2 = ((Ksegment *)obj->cur)->y2;
256 /* maybe throw away values and start over */
257 if( ((dx*dx) + (dy * dy)) < 100) {
258 init_ksegment (g, obj);
259 x1 = ((Ksegment *)obj->cur)->x1; /* in the natural coordinate system */
260 y1 = ((Ksegment *)obj->cur)->y1;
261 x2 = ((Ksegment *)obj->cur)->x2;
262 y2 = ((Ksegment *)obj->cur)->y2;
265 for (i=0; i<g->symmetry; i++) {
266 (((Ksegment *)obj->cur)->xsegments)[i].x1 = NEWX(x1,y1);
267 (((Ksegment *)obj->cur)->xsegments)[i].y1 = NEWY(x1,y1);
268 (((Ksegment *)obj->cur)->xsegments)[i].x2 = NEWX(x2,y2);
269 (((Ksegment *)obj->cur)->xsegments)[i].y2 = NEWY(x2,y2);
271 (((Ksegment *)obj->cur)->xsegments)[i].x1 = (x1 = (((Ksegment *)obj->cur)->xsegments)[i].x1) + g->xoff;
272 (((Ksegment *)obj->cur)->xsegments)[i].y1 = (y1 = (((Ksegment *)obj->cur)->xsegments)[i].y1) + g->yoff;
273 (((Ksegment *)obj->cur)->xsegments)[i].x2 = (x2 = (((Ksegment *)obj->cur)->xsegments)[i].x2) + g->xoff;
274 (((Ksegment *)obj->cur)->xsegments)[i].y2 = (y2 = (((Ksegment *)obj->cur)->xsegments)[i].y2) + g->yoff;
277 XSetForeground(g->dpy, g->draw_gc, (((Ksegment *)obj->cur)->color).pixel);
279 XDrawSegments(g->dpy, g->window, g->draw_gc, ((Ksegment *)obj->cur)->xsegments, g->symmetry);
280 ((Ksegment *)obj->cur)->drawn = 1;
282 if (((((Ksegment *)obj->cur)->next)->drawn) != 0) {
283 XDrawSegments(g->dpy, g->window, g->erase_gc, ((Ksegment *)obj->cur)->next->xsegments, g->symmetry);
288 propigate_ksegment(GLOBAL *g, OBJECT *obj)
291 short int x1,y1,x2,y2;
292 short int midx,midy,nmidx,nmidy;
293 float lsin, lcos, gsin, gcos;
295 lsin = sin((2*M_PI/10000)*g->local_rotation);
296 lcos = cos((2*M_PI/10000)*g->local_rotation);
297 gsin = sin((2*M_PI/10000)*g->global_rotation);
298 gcos = cos((2*M_PI/10000)*g->global_rotation);
303 x1 = ((Ksegment *) obj->cur)->x1;
304 y1 = ((Ksegment *) obj->cur)->y1;
305 x2 = ((Ksegment *) obj->cur)->x2;
306 y2 = ((Ksegment *) obj->cur)->y2;
311 nmidx = midx*gcos + midy*gsin;
312 nmidy = midy*gcos - midx*gsin;
320 /* This is where we move to the next ksegment... */
321 obj->cur = ((Ksegment *)obj->cur)->next;
323 ((Ksegment *)obj->cur)->x1 = ((x1*lcos) + (y1*lsin)) + nmidx;
324 ((Ksegment *)obj->cur)->y1 = ((y1*lcos) - (x1*lsin)) + nmidy;
325 ((Ksegment *)obj->cur)->x2 = ((x2*lcos) + (y2*lsin)) + nmidx;
326 ((Ksegment *)obj->cur)->y2 = ((y2*lcos) - (x2*lsin)) + nmidy;
332 init_objects (GLOBAL *g)
335 for (i=0; i<g->nobjects; i++) {
336 (g->objects[i].init)(g, g->objects + i);
341 create_objects (GLOBAL *g)
345 g->objects = (OBJECT *) malloc(g->nobjects * sizeof(OBJECT));
347 for (i=0; i< g->nsegments; i++) {
348 g->objects[i].cur = create_ksegment(g);
349 g->objects[i].type = 1;
350 g->objects[i].time = 0;
351 g->objects[i].propigate = propigate_ksegment;
352 g->objects[i].draw = draw_ksegment;
353 g->objects[i].init = init_ksegment;
356 /* Here we can add creation functions for other object types. */
361 propigate_objects (GLOBAL *g)
365 for(i=0; i<g->nobjects; i++) {
366 g->objects[i].propigate(g, g->objects + i);
371 draw_objects (GLOBAL *g)
375 for(i=0; i<g->nobjects; i++) {
376 g->objects[i].draw(g, g->objects + i);
383 XWindowAttributes xgwa;
385 char *color_mode_str;
387 g->symmetry = get_integer_resource(g->dpy, "symmetry", "Integer");
388 g->ntrails = get_integer_resource(g->dpy, "ntrails" , "Integer");
389 g->nsegments = get_integer_resource(g->dpy, "nsegments", "Integer");
390 g->narcs = get_integer_resource(g->dpy, "narcs", "Integer");
391 g->local_rotation = get_integer_resource(g->dpy, "local_rotation", "Integer");
392 g->global_rotation = get_integer_resource(g->dpy, "global_rotation", "Integer");
393 g->spring_constant = get_integer_resource(g->dpy, "spring_constant", "Integer");
394 g->delay = get_integer_resource(g->dpy, "delay", "Integer");
395 g->nobjects = g->nsegments + g->narcs;
397 color_mode_str = get_string_resource(g->dpy, "color_mode", "color_mode");
399 /* make into an enum... */
400 if(!color_mode_str) {
402 } else if (!strcmp(color_mode_str, "greedy")) {
404 } else if (!strcmp(color_mode_str, "nice")) {
410 XGetWindowAttributes (g->dpy, g->window, &xgwa);
411 g->xmax = xgwa.width;
412 g->ymax = xgwa.height;
415 g->costheta = cos(2*M_PI/g->symmetry);
416 g->sintheta = sin(2*M_PI/g->symmetry);
417 g->cmap = xgwa.colormap;
419 g->redmin = get_integer_resource(g->dpy, "redmin", "Integer");
420 g->redrange = get_integer_resource(g->dpy, "redrange", "Integer");
421 g->greenmin = get_integer_resource(g->dpy, "greenmin", "Integer");
422 g->greenrange = get_integer_resource(g->dpy, "greenrange", "Integer");
423 g->bluemin = get_integer_resource(g->dpy, "bluemin", "Integer");
424 g->bluerange = get_integer_resource(g->dpy, "bluerange", "Integer");
427 gcv.cap_style = CapRound;
428 gcv.foreground = g->default_fg_pixel = get_pixel_resource (g->dpy, g->cmap, "foreground", "Foreground");
429 g->draw_gc = XCreateGC (g->dpy, g->window, GCForeground|GCLineWidth|GCCapStyle, &gcv);
431 gcv.foreground = get_pixel_resource (g->dpy, g->cmap, "background", "Background");
432 g->erase_gc = XCreateGC (g->dpy, g->window, GCForeground|GCLineWidth|GCCapStyle,&gcv);
435 jwxyz_XSetAntiAliasing (g->dpy, g->draw_gc, False);
436 jwxyz_XSetAntiAliasing (g->dpy, g->erase_gc, False);
443 kaleidescope_init (Display *dpy, Window window)
445 GLOBAL *g = (GLOBAL *) calloc (1, sizeof(*g));
455 kaleidescope_draw (Display *dpy, Window window, void *closure)
457 GLOBAL *g = (GLOBAL *) closure;
459 propigate_objects(g);
467 kaleidescope_reshape (Display *dpy, Window window, void *closure,
468 unsigned int w, unsigned int h)
470 GLOBAL *g = (GLOBAL *) closure;
478 kaleidescope_event (Display *dpy, Window window, void *closure, XEvent *event)
484 kaleidescope_free (Display *dpy, Window window, void *closure)
486 GLOBAL *g = (GLOBAL *) closure;
490 XSCREENSAVER_MODULE ("Kaleidescope", kaleidescope)