diff options
author | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
---|---|---|
committer | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
commit | d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch) | |
tree | cbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/kaleidescope.c | |
download | xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip |
Original 5.40
Diffstat (limited to 'hacks/kaleidescope.c')
-rw-r--r-- | hacks/kaleidescope.c | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/hacks/kaleidescope.c b/hacks/kaleidescope.c new file mode 100644 index 0000000..87a8236 --- /dev/null +++ b/hacks/kaleidescope.c @@ -0,0 +1,490 @@ +/* kaleidescope, Copyright (c) 1997, 2006 Ron Tapia <tapia@nmia.com> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +/* + * The above, for lack of a better copyright statement in easy reach + * was just lifted from the xscreensaver source. + * + * One of the odd things about this hack is that the radial motion of the + * segments depends on roundoff error alone. + * + * I tried to make the source easy to add other shapes. So far, I've + * only messed with elipses and I couldn't do much with them that looked + * cool. A nice addition would be to add some sort of spline based shapes. + * Maybe rectangles would look nice. + * + */ + +#include <stdio.h> +#include <math.h> +#include <time.h> +#include "screenhack.h" +#include "spline.h" + +#define NEWX(x,y) ((x*g->costheta) + (y*g->sintheta)) +#define NEWY(x,y) ((y*g->costheta) - (x*g->sintheta)) + + +typedef struct state GLOBAL; +typedef struct Obj OBJECT; +struct Obj { + int type; + int time; + void (*propigate) (GLOBAL *, OBJECT *); + void (*draw) (GLOBAL *, OBJECT *); + void (*init) (GLOBAL *, OBJECT *); + void *cur; +}; + +typedef struct KSEGMENT { + struct KSEGMENT *next; + XColor color; + int drawn; + short int x1,y1,x2,y2; /* these are in the natural coordinate system */ + XSegment *xsegments; /* these are in the X coordinate system */ +} Ksegment; + +struct state { + int xoff, yoff; /* offset of origin xmax/2, ymax/2 */ + int xmax, ymax; /* width, height of window */ + float costheta, sintheta; + int symmetry; + int ntrails; + int nsegments; + int narcs; + int nobjects; + int local_rotation; + int global_rotation; + int spring_constant; + Colormap cmap; + GC draw_gc; + GC erase_gc; + unsigned int default_fg_pixel; + Display *dpy; + Window window; + unsigned long delay; + unsigned short redmin,redrange,greenmin,greenrange,bluemin,bluerange; + int color_mode; + + OBJECT *objects; + int counter; + + int done_once; +}; + + +static const char *kaleidescope_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*color_mode: nice", + "*symmetry: 11", + "*ntrails: 100", + "*nsegments: 7", + "*narcs: 0", + "*local_rotation: -59", + "*global_rotation: 1", + "*spring_constant: 5", + "*delay: 20000", + "*redmin: 30000", + "*redrange: 20000", + "*greenmin: 30000", + "*greenrange: 20000", + "*bluemin: 30000", + "*bluerange: 20000", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec kaleidescope_options [] = { + { "-color_mode", ".color_mode", XrmoptionSepArg, 0 }, + { "-symmetry", ".symmetry", XrmoptionSepArg, 0 }, + { "-nsegments", ".nsegments", XrmoptionSepArg, 0 }, + { "-ntrails", ".ntrails", XrmoptionSepArg, 0 }, + { "-local_rotation", ".local_rotation", XrmoptionSepArg, 0 }, + { "-global_rotation", ".global_rotation", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-spring_constant", ".spring_constant", XrmoptionSepArg, 0 }, + { "-redmin", ".redmin", XrmoptionSepArg, 0 }, + { "-redrange", ".redrange", XrmoptionSepArg, 0 }, + { "-bluemin", ".bluemin", XrmoptionSepArg, 0 }, + { "-bluerange", ".bluerange", XrmoptionSepArg, 0 }, + { "-greenmin", ".greenmin", XrmoptionSepArg, 0 }, + { "-greenrange", ".greenrange", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +/* END global variables */ + +static void +krandom_color(GLOBAL *g, XColor *color) +{ + if((g->color_mode == 0) || (g->color_mode == 1)) { + + color->blue = (random() % g->bluerange) + g->bluemin; + color->green = (random() % g->greenrange) + g->greenmin; + color->red = (random() % g->redrange) + g->redmin; + + if(!XAllocColor(g->dpy, g->cmap, color)) { + color->pixel = g->default_fg_pixel; + } + return; + } else { + color->pixel = g->default_fg_pixel; + return; + } +} + + +static void +kcopy_color(XColor *to, XColor *from) +{ + to->red = from->red; + to->green = from->green; + to->blue = from->blue; + to->pixel = from->pixel; +} + +static void +kcycle_color(GLOBAL *g, + XColor *color, + unsigned short redstep, + unsigned short greenstep, + unsigned short bluestep) +{ + unsigned short red,green,blue; + + if (! g->color_mode) { + XColor copy; + color->flags = DoRed|DoGreen|DoBlue; + color->red = (red = color->red) - redstep; + color->green = (green = color->green) - greenstep; + color->blue = (blue = color->blue) - bluestep; + copy = *color; + + if(!XAllocColor(g->dpy, g->cmap, color)) { + /* printf("couldn't alloc color...\n"); */ + color->pixel = g->default_fg_pixel; + } + copy.pixel = color->pixel; + *color = copy; + + color->red = red - redstep; + color->green = green- greenstep; + color->blue = blue - bluestep; + return; + } +} + + +static Ksegment * +create_ksegment (GLOBAL *g) +{ + Ksegment *seg, *prev; + XColor new_color; + int i; + unsigned short redstep,bluestep,greenstep; + + krandom_color(g, &new_color); + + redstep = new_color.red/(2 * g->ntrails); + greenstep = new_color.green/(2 * g->ntrails); + bluestep = new_color.blue/(2 * g->ntrails); + + seg = (Ksegment *) malloc(sizeof(Ksegment)); + seg->xsegments = (XSegment *) malloc(g->symmetry * sizeof(XSegment)); + + prev = seg; + for(i=0; i< (g->ntrails - 1); i++) { + + kcycle_color(g, &new_color,redstep,greenstep,bluestep); + + kcopy_color(&(prev->color), &new_color); + + prev->next = (Ksegment*)malloc(sizeof(Ksegment)); + (prev->next)->xsegments = (XSegment*)malloc(g->symmetry * sizeof(XSegment)); + prev->drawn = 0; + prev = (prev->next); + } + + prev->drawn = 0; + prev->next = seg; + kcopy_color(&(prev->color), &new_color); + + return seg; +} + +static void +init_ksegment (GLOBAL *g, OBJECT *obj) +{ + + /* Give the segment some random values */ + ((Ksegment *)obj->cur)->x1 = (g->xoff ? random() % g->xoff : 0); + ((Ksegment *)obj->cur)->y1 = (g->yoff ? random() % g->yoff : 0); + ((Ksegment *)obj->cur)->x2 = (g->xoff ? random() % g->xoff : 0); + ((Ksegment *)obj->cur)->y2 = (g->yoff ? random() % g->yoff : 0); +} + + +static void +draw_ksegment (GLOBAL *g, OBJECT *obj) +{ + register short x1, y1, x2, y2; + int dx, dy; + int i; + + g->counter++; + + x1 = ((Ksegment *)obj->cur)->x1; /* in the natural coordinate system */ + y1 = ((Ksegment *)obj->cur)->y1; + x2 = ((Ksegment *)obj->cur)->x2; + y2 = ((Ksegment *)obj->cur)->y2; + + dx = x2 - x1; + dy = y2 - y1; + + /* maybe throw away values and start over */ + if( ((dx*dx) + (dy * dy)) < 100) { + init_ksegment (g, obj); + x1 = ((Ksegment *)obj->cur)->x1; /* in the natural coordinate system */ + y1 = ((Ksegment *)obj->cur)->y1; + x2 = ((Ksegment *)obj->cur)->x2; + y2 = ((Ksegment *)obj->cur)->y2; + } + + for (i=0; i<g->symmetry; i++) { + (((Ksegment *)obj->cur)->xsegments)[i].x1 = NEWX(x1,y1); + (((Ksegment *)obj->cur)->xsegments)[i].y1 = NEWY(x1,y1); + (((Ksegment *)obj->cur)->xsegments)[i].x2 = NEWX(x2,y2); + (((Ksegment *)obj->cur)->xsegments)[i].y2 = NEWY(x2,y2); + + (((Ksegment *)obj->cur)->xsegments)[i].x1 = (x1 = (((Ksegment *)obj->cur)->xsegments)[i].x1) + g->xoff; + (((Ksegment *)obj->cur)->xsegments)[i].y1 = (y1 = (((Ksegment *)obj->cur)->xsegments)[i].y1) + g->yoff; + (((Ksegment *)obj->cur)->xsegments)[i].x2 = (x2 = (((Ksegment *)obj->cur)->xsegments)[i].x2) + g->xoff; + (((Ksegment *)obj->cur)->xsegments)[i].y2 = (y2 = (((Ksegment *)obj->cur)->xsegments)[i].y2) + g->yoff; + } + + XSetForeground(g->dpy, g->draw_gc, (((Ksegment *)obj->cur)->color).pixel); + + XDrawSegments(g->dpy, g->window, g->draw_gc, ((Ksegment *)obj->cur)->xsegments, g->symmetry); + ((Ksegment *)obj->cur)->drawn = 1; + + if (((((Ksegment *)obj->cur)->next)->drawn) != 0) { + XDrawSegments(g->dpy, g->window, g->erase_gc, ((Ksegment *)obj->cur)->next->xsegments, g->symmetry); + } +} + +static void +propigate_ksegment(GLOBAL *g, OBJECT *obj) +{ + int t; + short int x1,y1,x2,y2; + short int midx,midy,nmidx,nmidy; + float lsin, lcos, gsin, gcos; + + lsin = sin((2*M_PI/10000)*g->local_rotation); + lcos = cos((2*M_PI/10000)*g->local_rotation); + gsin = sin((2*M_PI/10000)*g->global_rotation); + gcos = cos((2*M_PI/10000)*g->global_rotation); + + t=obj->time; + obj->time = t + 1; + + x1 = ((Ksegment *) obj->cur)->x1; + y1 = ((Ksegment *) obj->cur)->y1; + x2 = ((Ksegment *) obj->cur)->x2; + y2 = ((Ksegment *) obj->cur)->y2; + + midx = (x1 + x2)/2; + midy = (y1 + y2)/2; + + nmidx = midx*gcos + midy*gsin; + nmidy = midy*gcos - midx*gsin; + + x1 = x1 - midx; + x2 = x2 - midx; + y1 = y1 - midy; + y2 = y2 - midy; + + + /* This is where we move to the next ksegment... */ + obj->cur = ((Ksegment *)obj->cur)->next; + + ((Ksegment *)obj->cur)->x1 = ((x1*lcos) + (y1*lsin)) + nmidx; + ((Ksegment *)obj->cur)->y1 = ((y1*lcos) - (x1*lsin)) + nmidy; + ((Ksegment *)obj->cur)->x2 = ((x2*lcos) + (y2*lsin)) + nmidx; + ((Ksegment *)obj->cur)->y2 = ((y2*lcos) - (x2*lsin)) + nmidy; + + return ; +} + +static void +init_objects (GLOBAL *g) +{ + int i; + for (i=0; i<g->nobjects; i++) { + (g->objects[i].init)(g, g->objects + i); + } +} + +static void +create_objects (GLOBAL *g) +{ + int i; + + g->objects = (OBJECT *) malloc(g->nobjects * sizeof(OBJECT)); + + for (i=0; i< g->nsegments; i++) { + g->objects[i].cur = create_ksegment(g); + g->objects[i].type = 1; + g->objects[i].time = 0; + g->objects[i].propigate = propigate_ksegment; + g->objects[i].draw = draw_ksegment; + g->objects[i].init = init_ksegment; + } + + /* Here we can add creation functions for other object types. */ +} + + +static void +propigate_objects (GLOBAL *g) +{ + int i; + + for(i=0; i<g->nobjects; i++) { + g->objects[i].propigate(g, g->objects + i); + } +} + +static void +draw_objects (GLOBAL *g) +{ + int i; + + for(i=0; i<g->nobjects; i++) { + g->objects[i].draw(g, g->objects + i); + } +} + +static void +init_g (GLOBAL *g) +{ + XWindowAttributes xgwa; + XGCValues gcv; + char *color_mode_str; + + g->symmetry = get_integer_resource(g->dpy, "symmetry", "Integer"); + g->ntrails = get_integer_resource(g->dpy, "ntrails" , "Integer"); + g->nsegments = get_integer_resource(g->dpy, "nsegments", "Integer"); + g->narcs = get_integer_resource(g->dpy, "narcs", "Integer"); + g->local_rotation = get_integer_resource(g->dpy, "local_rotation", "Integer"); + g->global_rotation = get_integer_resource(g->dpy, "global_rotation", "Integer"); + g->spring_constant = get_integer_resource(g->dpy, "spring_constant", "Integer"); + g->delay = get_integer_resource(g->dpy, "delay", "Integer"); + g->nobjects = g->nsegments + g->narcs; + + color_mode_str = get_string_resource(g->dpy, "color_mode", "color_mode"); + + /* make into an enum... */ + if(!color_mode_str) { + g->color_mode = 0; + } else if (!strcmp(color_mode_str, "greedy")) { + g->color_mode = 0; + } else if (!strcmp(color_mode_str, "nice")) { + g->color_mode = 1; + } else { + g->color_mode = 2; + } + + XGetWindowAttributes (g->dpy, g->window, &xgwa); + g->xmax = xgwa.width; + g->ymax = xgwa.height; + g->xoff = g->xmax/2; + g->yoff = g->ymax/2; + g->costheta = cos(2*M_PI/g->symmetry); + g->sintheta = sin(2*M_PI/g->symmetry); + g->cmap = xgwa.colormap; + + g->redmin = get_integer_resource(g->dpy, "redmin", "Integer"); + g->redrange = get_integer_resource(g->dpy, "redrange", "Integer"); + g->greenmin = get_integer_resource(g->dpy, "greenmin", "Integer"); + g->greenrange = get_integer_resource(g->dpy, "greenrange", "Integer"); + g->bluemin = get_integer_resource(g->dpy, "bluemin", "Integer"); + g->bluerange = get_integer_resource(g->dpy, "bluerange", "Integer"); + + gcv.line_width = 1; + gcv.cap_style = CapRound; + gcv.foreground = g->default_fg_pixel = get_pixel_resource (g->dpy, g->cmap, "foreground", "Foreground"); + g->draw_gc = XCreateGC (g->dpy, g->window, GCForeground|GCLineWidth|GCCapStyle, &gcv); + + gcv.foreground = get_pixel_resource (g->dpy, g->cmap, "background", "Background"); + g->erase_gc = XCreateGC (g->dpy, g->window, GCForeground|GCLineWidth|GCCapStyle,&gcv); + +# ifdef HAVE_JWXYZ + jwxyz_XSetAntiAliasing (g->dpy, g->draw_gc, False); + jwxyz_XSetAntiAliasing (g->dpy, g->erase_gc, False); +# endif + + +} + +static void * +kaleidescope_init (Display *dpy, Window window) +{ + GLOBAL *g = (GLOBAL *) calloc (1, sizeof(*g)); + g->dpy = dpy; + g->window = window; + init_g (g); + create_objects(g); + init_objects (g); + return g; +} + +static unsigned long +kaleidescope_draw (Display *dpy, Window window, void *closure) +{ + GLOBAL *g = (GLOBAL *) closure; + if (g->done_once) + propigate_objects(g); + else + g->done_once = 1; + draw_objects (g); + return g->delay; +} + +static void +kaleidescope_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + GLOBAL *g = (GLOBAL *) closure; + g->xmax = w; + g->ymax = h; + g->xoff = g->xmax/2; + g->yoff = g->ymax/2; +} + +static Bool +kaleidescope_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +kaleidescope_free (Display *dpy, Window window, void *closure) +{ + GLOBAL *g = (GLOBAL *) closure; + free (g); +} + +XSCREENSAVER_MODULE ("Kaleidescope", kaleidescope) |