summaryrefslogtreecommitdiffstats
path: root/hacks/kaleidescope.c
diff options
context:
space:
mode:
authorSimon Rettberg2018-10-16 10:08:48 +0200
committerSimon Rettberg2018-10-16 10:08:48 +0200
commitd3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch)
treecbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/kaleidescope.c
downloadxscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip
Original 5.40
Diffstat (limited to 'hacks/kaleidescope.c')
-rw-r--r--hacks/kaleidescope.c490
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)