began for maemo
[xscreensaver] / xscreensaver / hacks / xspirograph.c
diff --git a/xscreensaver/hacks/xspirograph.c b/xscreensaver/hacks/xspirograph.c
new file mode 100644 (file)
index 0000000..11bfff1
--- /dev/null
@@ -0,0 +1,326 @@
+/* The Spiral Generator, Copyright (c) 2000 
+ * by Rohit Singh <rohit_singh@hotmail.com>
+ * 
+ * Contains code from / To be used with:
+ * xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
+ * Jamie Zawinski <jwz@jwz.org>
+ *
+ * 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 notices appear in all copies and that both that
+ * copyright notices 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.
+ *
+ * Modified (Dec 2001) by Matthew Strait <straitm@mathcs.carleton.edu>
+ * Added -subdelay and -alwaysfinish
+ * Prevented redrawing over existing lines
+ */
+
+#include <math.h>
+#include "screenhack.h"
+#include "erase.h"
+
+struct state {
+  Display *dpy;
+  Window window;
+  XWindowAttributes xgwa;
+
+  GC   draw_gc;
+  int  long_delay;
+  int  sub_sleep_time;
+  int  num_layers;
+  unsigned int default_fg_pixel;
+  Bool always_finish_p;
+  XColor       color;
+  int got_color;
+
+  int theta;
+  float firstx, firsty;
+  int x1, y1, x2, y2;
+
+  int counter;
+  int distance;
+  int radius1, radius2;
+  double divisor;
+
+  int new_layer;
+  int erasing;
+  eraser_state *eraser;
+};
+
+
+static void
+init_tsg (struct state *st)
+{
+  XGCValues    gcv;
+  Colormap     cmap;
+
+  XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+  cmap = st->xgwa.colormap;
+  gcv.foreground = st->default_fg_pixel =
+    get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
+  st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
+  gcv.foreground = get_pixel_resource (st->dpy, cmap, "background", "Background");
+}
+
+
+static Bool
+go (struct state *st, int radius1, int radius2, int d)
+{
+  int width, height;
+  int xmid, ymid;
+  float tmpx, tmpy;
+  int delta;
+
+  width  = st->xgwa.width;
+  height = st->xgwa.height;
+  delta = 1;
+  xmid = width / 2;
+  ymid = height / 2;
+
+  if (st->theta == 1) {
+    st->x1 = xmid + radius1 - radius2 + d;
+    st->y1 = ymid;
+  }
+
+/*  for (theta = 1; / * theta < ( 360 * 100 ) * /; theta++) */
+                  /* see below about alwaysfinish */
+    {
+       tmpx = xmid + ((       radius1            /* * * * *            */
+                  - radius2        )            /* This algo simulates */
+                  * cos((      st->theta               /* the rotation of a    */
+                  * M_PI           )           /* circular disk inside */
+                  / 180           ))           /* a hollow circular    */
+                  + (              d           /* rim. A point on the  */
+                  * cos((((  radius1           /* disk dist d from the */
+                  * st->theta      )           /* centre, traces the   */
+                  - delta          )           /* path given by this   */
+                  / radius2        )           /* equation.            */
+                  *             M_PI           /* A deviation (error)  */
+                  / 180            )            /* of delta needs to be */
+                                   );           /* given, which greatly */
+                                               /* adds to the beauty   */
+       tmpy = ymid + (                         /* of the figure.       */
+                     ( radius1 - radius2       /*                      */
+                      ) * sin                  /* Imperfection adds to */
+                       (                       /* beauty, symbolically */
+                        ( st->theta * M_PI             /* ...                  */
+                         ) / 180               /* Algo deduced by      */
+                          )                    /* Rohit Singh, Jan'00  */
+                           ) +                  /* based on a toy he    */
+                            ( d * sin           /* used to play with    */
+                             (                  /* when he was a kid.  */
+                              (                 /*            * * * * */
+                               (               
+                                ( radius1 * st->theta
+                                 ) - delta
+                                  ) / radius2
+                                   ) * M_PI / 180
+                                    )
+                                     );
+        
+       /*makes integers from the calculated values to do the drawing*/
+       st->x2 = tmpx;
+       st->y2 = tmpy;
+
+       /*stores the first values for later reference*/
+       if(st->theta == 1)
+       {
+               st->firstx = tmpx;
+               st->firsty = tmpy;
+       }
+
+        if (st->theta != 1)
+          XDrawLine (st->dpy, st->window, st->draw_gc, 
+                     st->x1, st->y1, st->x2, st->y2);
+
+       st->x1 = st->x2;
+       st->y1 = st->y2;
+
+       /* compares the exact values calculated to the first
+          exact values calculated */
+       /* this will break when nothing new is being drawn */
+       if(tmpx == st->firstx && tmpy == st->firsty && st->theta != 1) {
+          st->firstx = st->firsty = 0;
+          st->theta = 1;
+          return True;
+        }
+
+       /* this will break after 36000 iterations if 
+          the -alwaysfinish option is not specified */
+       if(!st->always_finish_p && st->theta > ( 360 * 100 ) ) {
+          st->firstx = st->firsty = 0;
+          st->theta = 1;
+          return True;
+        }
+    }
+
+    st->theta++;
+
+    return False;
+}
+
+
+#define min(a,b) ((a)<(b)?(a):(b))
+
+
+static void
+pick_new (struct state *st)
+{
+  int radius = min (st->xgwa.width, st->xgwa.height) / 2;
+  st->divisor = ((frand (3.0) + 1) * (((random() & 1) * 2) - 1));
+  st->radius1 = radius;
+  st->radius2 = radius / st->divisor + 5;
+  st->distance = 100 + (random() % 200);
+  st->theta = 1;
+}
+
+
+static void *
+xspirograph_init (Display *dpy, Window window)
+{
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
+  st->dpy = dpy;
+  st->window = window;
+  st->long_delay = get_integer_resource(st->dpy, "delay", "Integer");
+  st->sub_sleep_time = get_integer_resource(st->dpy, "subdelay", "Integer");
+  st->num_layers = get_integer_resource(st->dpy, "layers", "Integer");
+  st->always_finish_p = get_boolean_resource (st->dpy, "alwaysfinish", "Boolean");
+  
+  XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+
+  init_tsg (st);
+  st->theta = 1;
+  st->new_layer = 1;
+
+  return st;
+}
+
+
+static void
+new_colors (struct state *st)
+{
+  if (mono_p)
+    XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel);
+  else
+    {
+      hsv_to_rgb (random () % 360, frand (1.0), frand (0.5) + 0.5,
+                 &st->color.red, &st->color.green, &st->color.blue);
+      if ((st->got_color = XAllocColor (st->dpy, st->xgwa.colormap,
+                                        &st->color)))
+       XSetForeground (st->dpy, st->draw_gc, st->color.pixel);
+      else
+       XSetForeground (st->dpy, st->draw_gc, st->default_fg_pixel);
+    }
+}
+
+
+
+static unsigned long
+xspirograph_draw (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  Bool free_color = False;
+  Bool flip_p;
+
+  /* 5 sec delay before starting the erase */
+  if (st->erasing == 2) {
+    st->erasing--;
+    return (st->long_delay == 0 ? 0 : 5000000);
+  }
+
+  /* erase, delaying 1/50th sec between frames */
+  if (st->erasing || st->eraser) {
+    st->erasing = 0;
+    st->eraser = erase_window (st->dpy, st->window, st->eraser);
+    if (st->eraser)
+      return 20000;
+    else
+      /* just finished erasing -- leave screen black for 1 sec */
+      return (st->long_delay == 0 ? 0 : 1000000);
+  }
+
+  flip_p = (st->counter & 1);
+
+  if (st->new_layer) {
+
+    st->new_layer = 0;
+    st->counter++;
+
+    if (st->counter > (2 * st->num_layers))
+      {
+        st->counter = 0;
+
+        if (free_color)
+          XFreeColors (st->dpy, st->xgwa.colormap, &st->color.pixel, 1, 0);
+
+        st->erasing = 2;
+      }
+
+    if (! flip_p)
+      pick_new (st);
+
+    new_colors (st);
+    st->new_layer = 0;
+  }
+
+  {
+    int i;
+    for (i = 0; i < 1000; i++) {
+      if (go (st, st->radius1, 
+              (flip_p ? st->radius2 : -st->radius2),
+              st->distance)) {
+        st->new_layer = 1;
+        break;
+      }
+    }
+  }
+
+  return st->sub_sleep_time;
+}
+
+
+static void
+xspirograph_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+  struct state *st = (struct state *) closure;
+  XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+}
+
+static Bool
+xspirograph_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  return False;
+}
+
+static void
+xspirograph_free (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  free (st);
+}
+
+
+static const char *xspirograph_defaults [] = {
+  ".background:                black",
+  ".foreground:                white",
+  "*delay:             5",
+  "*subdelay:          20000",
+  "*layers:            2",
+  "*alwaysfinish:      false",
+  0
+};
+
+static XrmOptionDescRec xspirograph_options [] = {   
+  { "-delay",           ".delay",               XrmoptionSepArg, 0 },
+  { "-subdelay",        ".subdelay",            XrmoptionSepArg, 0 },
+  { "-layers",          ".layers",             XrmoptionSepArg, 0 },
+  { "-alwaysfinish",    ".alwaysfinish",       XrmoptionNoArg, "true"},
+  { "-noalwaysfinish",  ".alwaysfinish",       XrmoptionNoArg, "false"},
+  { 0, 0, 0, 0 }
+};
+
+XSCREENSAVER_MODULE ("XSpiroGraph", xspirograph)