ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-2.07.tar.gz
[xscreensaver] / hacks / strange.c
diff --git a/hacks/strange.c b/hacks/strange.c
new file mode 100644 (file)
index 0000000..71cd89c
--- /dev/null
@@ -0,0 +1,404 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ * strange --- Strange attractors are not so hard to find...
+ */
+#if !defined( lint ) && !defined( SABER )
+static const char sccsid[] = "@(#)strange.c       4.02 97/04/01 xlockmore";
+#endif
+
+/* Copyright (c) 1997 by Massimino Pascal (Pascal.Massimon@ens.fr)
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind.  The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof.  In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Revision History:
+ * 10-May-97: jwz@netscape.com: turned into a standalone program.
+ *                       Made it render into an offscreen bitmap and then copy
+ *                       that onto the screen, to reduce flicker.
+ */
+
+#ifdef STANDALONE
+# define PROGCLASS                                     "Strange"
+# define HACK_INIT                                     init_strange
+# define HACK_DRAW                                     draw_strange
+# define strange_opts                          xlockmore_opts
+# define DEFAULTS      "*delay:                2000  \n"                       \
+                                       "*ncolors:              100   \n"
+# define SMOOTH_COLORS
+# include "xlockmore.h"                                /* from the xscreensaver distribution */
+#else  /* !STANDALONE */
+# include "xlock.h"                                    /* from the xlockmore distribution */
+#endif /* !STANDALONE */
+
+ModeSpecOpt strange_opts = {
+  0, NULL, 0, NULL, NULL };
+
+/*****************************************************/
+/*****************************************************/
+
+typedef float DBL;
+typedef int PRM;
+
+#define UNIT (1<<12)
+#define UNIT2 (1<<14)
+/* #define UNIT2 (3140*UNIT/1000) */
+
+#define SKIP_FIRST      100
+#define MAX_POINTS      5500
+#define DBL_To_PRM(x)  (PRM)( (DBL)(UNIT)*(x) )
+
+
+#define DO_FOLD(a) (a)<0 ? -Fold[ (-(a))&(UNIT2-1) ] : Fold[ (a)&(UNIT2-1) ]
+
+/* 
+   #define DO_FOLD(a) (a)<-UNIT2 ? -Fold[(-(a))%UNIT2] : (a)<0 ? -Fold[ -(a) ] 
+
+   :  \ (a)>UNIT2 ? Fold[ (a)%UNIT2 ] : Fold[ (a) ] */
+/* #define DO_FOLD(a) DBL_To_PRM( sin( (DBL)(a)/UNIT ) ) */
+/* 
+   #define DO_FOLD(a) (a)<0 ? DBL_To_PRM( exp( 16.0*(a)/UNIT2 ) )-1.0 : \
+   DBL_To_PRM( 1.0-exp( -16.0*(a)/UNIT2 ) ) */
+
+/******************************************************************/
+
+#define MAX_PRM 3*5
+
+typedef struct {
+       DBL         Prm1[MAX_PRM], Prm2[MAX_PRM];
+       void        (*Iterate) (PRM, PRM, PRM *, PRM *);
+       XPoint     *Buffer1, *Buffer2;
+       int         Cur_Pt, Max_Pt;
+       int         Col, Count, Speed;
+       int         Width, Height;
+    Pixmap      dbuf;  /* jwz */
+    GC          dbuf_gc;
+} ATTRACTOR;
+
+static ATTRACTOR *Root;
+static PRM  xmin, xmax, ymin, ymax;
+static PRM  Prm[MAX_PRM];
+static PRM *Fold = NULL;
+
+/******************************************************************/
+/******************************************************************/
+
+static DBL  Amp_Prm[MAX_PRM] =
+{
+       1.0, 3.5, 3.5, 2.5, 4.7,
+       1.0, 3.5, 3.6, 2.5, 4.7,
+       1.0, 1.5, 2.2, 2.1, 3.5
+};
+static DBL  Mid_Prm[MAX_PRM] =
+{
+       0.0, 1.5, 0.0, .5, 1.5,
+       0.0, 1.5, 0.0, .5, 1.5,
+       0.0, 1.5, -1.0, -.5, 2.5,
+};
+
+static      DBL
+Gauss_Rand(DBL c, DBL A, DBL S)
+{
+       DBL         y;
+
+       y = (DBL) LRAND() / MAXRAND;
+       y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
+       if (NRAND(2))
+               return (c + y);
+       else
+               return (c - y);
+}
+
+static void
+Random_Prm(DBL * Prm)
+{
+       int         i;
+
+       for (i = 0; i < MAX_PRM; ++i)
+               Prm[i] = Gauss_Rand(Mid_Prm[i], Amp_Prm[i], 4.0);
+}
+
+/***************************************************************/
+
+   /* 2 examples of non-linear map */
+
+static void
+Iterate_X2(PRM x, PRM y, PRM * xo, PRM * yo)
+{
+       PRM         xx, yy, xy, x2y, y2x, Tmp;
+
+       xx = (x * x) / UNIT;
+       x2y = (xx * y) / UNIT;
+       yy = (y * y) / UNIT;
+       y2x = (yy * x) / UNIT;
+       xy = (x * y) / UNIT;
+
+       Tmp = Prm[1] * xx + Prm[2] * xy + Prm[3] * yy + Prm[4] * x2y;
+       Tmp = Prm[0] - y + (Tmp / UNIT);
+       *xo = DO_FOLD(Tmp);
+       Tmp = Prm[6] * xx + Prm[7] * xy + Prm[8] * yy + Prm[9] * y2x;
+       Tmp = Prm[5] + x + (Tmp / UNIT);
+       *yo = DO_FOLD(Tmp);
+}
+
+static void
+Iterate_X3(PRM x, PRM y, PRM * xo, PRM * yo)
+{
+       PRM         xx, yy, xy, x2y, y2x, Tmp_x, Tmp_y, Tmp_z;
+
+       xx = (x * x) / UNIT;
+       x2y = (xx * y) / UNIT;
+       yy = (y * y) / UNIT;
+       y2x = (yy * x) / UNIT;
+       xy = (x * y) / UNIT;
+
+       Tmp_x = Prm[1] * xx + Prm[2] * xy + Prm[3] * yy + Prm[4] * x2y;
+       Tmp_x = Prm[0] - y + (Tmp_x / UNIT);
+       Tmp_x = DO_FOLD(Tmp_x);
+
+       Tmp_y = Prm[6] * xx + Prm[7] * xy + Prm[8] * yy + Prm[9] * y2x;
+       Tmp_y = Prm[5] + x + (Tmp_y / UNIT);
+
+       Tmp_y = DO_FOLD(Tmp_y);
+
+       Tmp_z = Prm[11] * xx + Prm[12] * xy + Prm[13] * yy + Prm[14] * y2x;
+       Tmp_z = Prm[10] + x + (Tmp_z / UNIT);
+       Tmp_z = UNIT + Tmp_z * Tmp_z / UNIT;
+
+       *xo = (Tmp_x * UNIT) / Tmp_z;
+       *yo = (Tmp_y * UNIT) / Tmp_z;
+}
+
+static void (*Funcs[2]) (PRM, PRM, PRM *, PRM *) = {
+       Iterate_X2, Iterate_X3
+};
+
+/***************************************************************/
+
+void
+draw_strange(ModeInfo * mi)
+{
+       int         i, j, n, Max_Colors, Cur_Pt;
+       PRM         x, y, xo, yo;
+       DBL         u;
+       ATTRACTOR  *A;
+       XPoint     *Buf;
+       Display    *display;
+       GC          gc;
+       Window      window;
+       DBL         Lx, Ly;
+       void        (*Iterate) (PRM, PRM, PRM *, PRM *);
+
+       display = MI_DISPLAY(mi);
+       window = MI_WINDOW(mi);
+       gc = MI_GC(mi);
+       Max_Colors = MI_NPIXELS(mi);
+
+       A = &Root[MI_SCREEN(mi)];
+
+       Cur_Pt = A->Cur_Pt;
+       Iterate = A->Iterate;
+
+       u = (DBL) (A->Count) / 1000.0;
+       for (j = MAX_PRM - 1; j >= 0; --j)
+               Prm[j] = DBL_To_PRM((1.0 - u) * A->Prm1[j] + u * A->Prm2[j]);
+
+       x = y = DBL_To_PRM(.0);
+       for (n = SKIP_FIRST; n; --n) {
+               (*Iterate) (x, y, &xo, &yo);
+               x = xo + NRAND(8) - 4;
+               y = yo + NRAND(8) - 4;
+       }
+
+       xmax = 0;
+       xmin = UNIT * 4;
+       ymax = 0;
+       ymin = UNIT * 4;
+       A->Cur_Pt = 0;
+       Buf = A->Buffer2;
+       Lx = (DBL) A->Width / UNIT / 2.2;
+       Ly = (DBL) A->Height / UNIT / 2.2;
+       for (n = A->Max_Pt; n; --n) {
+               (*Iterate) (x, y, &xo, &yo);
+               Buf->x = (short) (Lx * (x + DBL_To_PRM(1.1)));
+               Buf->y = (short) (Ly * (DBL_To_PRM(1.1) - y));
+               /* (void) fprintf( stderr, "X,Y: %d %d    ", Buf->x, Buf->y ); */
+               Buf++;
+               A->Cur_Pt++;
+               if (xo > xmax)
+                       xmax = xo;
+               else if (xo < xmin)
+                       xmin = xo;
+               if (yo > ymax)
+                       ymax = yo;
+               else if (yo < ymin)
+                       ymin = yo;
+               x = xo + NRAND(8) - 4;
+               y = yo + NRAND(8) - 4;
+       }
+
+       XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
+
+       if (A->dbuf)    /* jwz */
+         {
+               XSetForeground(display, A->dbuf_gc, 0);
+/*         XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer1,
+                                   Cur_Pt,CoordModeOrigin);*/
+               XFillRectangle(display, A->dbuf, A->dbuf_gc, 0,0, A->Width, A->Height);
+         }
+       else
+         XDrawPoints(display, window, gc, A->Buffer1, Cur_Pt, CoordModeOrigin);
+
+       if (Max_Colors < 2)
+               XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
+       else
+               XSetForeground(display, gc, MI_PIXEL(mi, A->Col % Max_Colors));
+
+       if (A->dbuf)
+         {
+               XSetForeground(display, A->dbuf_gc, 1);
+               XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer2, A->Cur_Pt,
+                                       CoordModeOrigin);
+         }
+       else
+         XDrawPoints(display, window, gc, A->Buffer2, A->Cur_Pt, CoordModeOrigin);
+
+       if (A->dbuf)
+         XCopyPlane(display, A->dbuf, window, gc, 0,0,A->Width,A->Height,0,0, 1);
+
+       Buf = A->Buffer1;
+       A->Buffer1 = A->Buffer2;
+       A->Buffer2 = Buf;
+
+       if ((xmax - xmin < DBL_To_PRM(.2)) && (ymax - ymin < DBL_To_PRM(.2)))
+               A->Count += 4 * A->Speed;
+       else
+               A->Count += A->Speed;
+       if (A->Count >= 1000) {
+               for (i = MAX_PRM - 1; i >= 0; --i)
+                       A->Prm1[i] = A->Prm2[i];
+               Random_Prm(A->Prm2);
+               A->Count = 0;
+       }
+       A->Col++;
+}
+
+
+/***************************************************************/
+
+void
+init_strange(ModeInfo * mi)
+{
+       ATTRACTOR  *Attractor;
+
+       if (Root == NULL) {
+               Root = (ATTRACTOR *) calloc(
+                                    MI_NUM_SCREENS(mi), sizeof (ATTRACTOR));
+               if (Root == NULL)
+                       return;
+       }
+       if (Fold == NULL) {
+               int         i;
+
+               Fold = (PRM *) calloc(UNIT2 + 1, sizeof (PRM));
+               if (Fold == NULL)
+                       return;
+               for (i = 0; i <= UNIT2; ++i) {
+                       DBL         x;
+
+                       /* x = ( DBL )(i)/UNIT2; */
+                       /* x = sin( M_PI/2.0*x ); */
+                       /* x = sqrt( x ); */
+                       /* x = x*x; */
+                       /* x = x*(1.0-x)*4.0; */
+                       x = (DBL) (i) / UNIT;
+                       x = sin(x);
+                       Fold[i] = DBL_To_PRM(x);
+               }
+       }
+       Attractor = &Root[MI_SCREEN(mi)];
+
+       Attractor->Buffer1 = (XPoint *) calloc(MAX_POINTS, sizeof (XPoint));
+       if (Attractor->Buffer1 == NULL)
+               goto Abort;
+       Attractor->Buffer2 = (XPoint *) calloc(MAX_POINTS, sizeof (XPoint));
+       if (Attractor->Buffer2 == NULL)
+               goto Abort;
+       Attractor->Max_Pt = MAX_POINTS;
+
+       Attractor->Width = MI_WIN_WIDTH(mi);
+       Attractor->Height = MI_WIN_HEIGHT(mi);
+       Attractor->Cur_Pt = 0;
+       Attractor->Count = 0;
+       Attractor->Col = NRAND(MI_NPIXELS(mi));
+       Attractor->Speed = 4;
+
+       Attractor->Iterate = Funcs[NRAND(2)];
+       Random_Prm(Attractor->Prm1);
+       Random_Prm(Attractor->Prm2);
+
+       Attractor->dbuf = XCreatePixmap(MI_DISPLAY(mi), MI_WINDOW(mi),
+                                                                       Attractor->Width, Attractor->Height, 1);
+       if (Attractor->dbuf)
+         {
+               XGCValues gcv;
+               gcv.foreground = 0;
+               gcv.background = 0;
+               gcv.function = GXcopy;
+               Attractor->dbuf_gc = XCreateGC(MI_DISPLAY(mi), Attractor->dbuf,
+                                                                          GCForeground|GCBackground|GCFunction,
+                                                                          &gcv);
+               XFillRectangle(MI_DISPLAY(mi), Attractor->dbuf,
+                                          Attractor->dbuf_gc, 0,0, Attractor->Width,
+                                          Attractor->Height);
+               XSetBackground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
+               XSetFunction(MI_DISPLAY(mi), MI_GC(mi), GXcopy);
+         }
+
+       XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
+       return;
+
+      Abort:
+       if (Attractor->Buffer1 != NULL)
+               free(Attractor->Buffer1);
+       if (Attractor->Buffer2 != NULL)
+               free(Attractor->Buffer2);
+       Attractor->Buffer1 = NULL;
+       Attractor->Buffer2 = NULL;
+       Attractor->Cur_Pt = 0;
+       return;
+}
+
+/***************************************************************/
+
+void
+release_strange(ModeInfo * mi)
+{
+       int         i;
+
+       if (Root == NULL)
+               return;
+
+       for (i = 0; i < MI_NUM_SCREENS(mi); ++i) {
+               if (Root[i].Buffer1 != NULL)
+                       free(Root[i].Buffer1);
+               if (Root[i].Buffer2 != NULL)
+                       free(Root[i].Buffer2);
+               if (Root[i].dbuf)
+                   XFreePixmap(MI_DISPLAY(mi), Root[i].dbuf);
+               if (Root[i].dbuf_gc)
+                   XFreeGC(MI_DISPLAY(mi), Root[i].dbuf_gc);
+       }
+       free(Root);
+       Root = NULL;
+       if (Fold != NULL)
+               free(Fold);
+       Fold = NULL;
+}