9bb3c44de356b7780f5c49c62445ded7e8302a93
[xscreensaver] / hacks / fuzzyflakes.c
1 /* fuzzyflakes, Copyright (c) 2004
2  *  Barry Dmytro <badcherry@mailc.net>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 #include <math.h>
14 #include "screenhack.h"
15 #define PI 3.14159265359
16
17 typedef struct _flake_var
18 {
19   double Ticks;
20   double XPos, YPos;
21   double TrueX;
22   double XOffset;
23   double Angle;
24 } FlakeVariable;
25
26 static struct _flake
27 { /* Struct containing the atrributes to our flakes */
28   int Arms;
29   int Thickness;
30   int BorderThickness;
31   int Radius;
32   unsigned long BordColor;
33   unsigned long ForeColor;
34   unsigned long BackColor;
35   int Layers;
36   int Density;
37   int Delay;
38   int FallingSpeed;
39   FlakeVariable *** Flakes; /* a dynamic array containing positions of all the flakes */
40   XGCValues GCValues;
41   unsigned long GCFlags;
42   GC GCVar;
43   Display * DisplayVar;
44   Window WindowVar;
45   XWindowAttributes XGWA;
46   struct _dbevar
47   {
48     Bool dbuf;
49     Pixmap b,ba,bb;
50   } DB;
51 } Flake;
52
53 static void
54 InitFuzzyFlakes (Display *dpy, Window window)
55 {
56   int i,j;
57   XWindowAttributes xgwa;
58   Colormap cmap;
59   
60   XGetWindowAttributes (dpy, window, &xgwa);
61   cmap = xgwa.colormap;
62   Flake.XGWA = xgwa;
63   Flake.DB.b = Flake.DB.ba = Flake.DB.bb = 0;
64   Flake.DB.dbuf         = get_boolean_resource ("doubleBuffer", "Boolean");
65   
66
67   if (Flake.DB.dbuf)
68     {
69       Flake.DB.ba = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
70       Flake.DB.bb = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
71       Flake.DB.b = Flake.DB.ba;
72     }
73   else
74     {
75       Flake.DB.b = window;
76     }
77
78
79   Flake.DisplayVar      = dpy;
80   Flake.WindowVar       = window;
81   Flake.Arms            = get_integer_resource ("arms", "Integer");
82   Flake.Thickness       = get_integer_resource ("thickness", "Integer");
83   Flake.BorderThickness = get_integer_resource ("bthickness", "Integer");
84   Flake.Radius          = get_integer_resource ("radius", "Integer");
85   Flake.BordColor       = get_pixel_resource   ("border","Border",dpy,cmap);
86   Flake.ForeColor       = get_pixel_resource   ("foreground","Foreground",dpy,cmap);
87   Flake.BackColor       = get_pixel_resource   ("background","Background",dpy,cmap);
88   Flake.Density         = get_integer_resource ("density", "Integer");
89   Flake.Layers          = get_integer_resource ("layers", "Integer");
90   Flake.FallingSpeed    = get_integer_resource ("fallingspeed", "Integer");
91   Flake.Delay           = get_integer_resource ("delay", "Integer");
92   
93   if (Flake.Delay < 0) Flake.Delay = 0;
94
95   Flake.GCValues.foreground = get_pixel_resource("foreground","Foreground", dpy, cmap);
96   Flake.GCValues.background = get_pixel_resource("background","Background", dpy, cmap);
97   Flake.GCValues.line_width = Flake.Thickness;
98   Flake.GCValues.line_style = LineSolid;
99   Flake.GCValues.cap_style  = CapProjecting;
100   Flake.GCValues.join_style = JoinMiter;
101   Flake.GCFlags |= (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
102
103   Flake.GCVar = XCreateGC (Flake.DisplayVar, Flake.WindowVar, Flake.GCFlags, &Flake.GCValues);
104
105   Flake.Density = Flake.XGWA.width/200*Flake.Density;
106   Flake.Flakes = malloc(sizeof(FlakeVariable**)*Flake.Layers);
107   for(i=1;i<=Flake.Layers;i++)
108   {
109      Flake.Flakes[i-1] = malloc(sizeof(FlakeVariable*)*Flake.Density);
110      for(j=0;j<Flake.Density;j++)
111      {
112        Flake.Flakes[i-1][j] = malloc(sizeof(FlakeVariable));
113        Flake.Flakes[i-1][j]->XPos = random()%Flake.XGWA.width;
114        Flake.Flakes[i-1][j]->YPos = random()%Flake.XGWA.height;
115        Flake.Flakes[i-1][j]->Angle = random()%360*(PI/180);
116        Flake.Flakes[i-1][j]->Ticks = random()%360;
117        Flake.Flakes[i-1][j]->XOffset = random()%Flake.XGWA.height;
118      }
119   }
120 }
121
122 static void
123 FuzzyFlakesMove(void)
124 {
125   int i,j;
126   for(i=1;i<=Flake.Layers;i++)
127   {
128      for(j=0;j<Flake.Density;j++)
129      {
130        FlakeVariable * FlakeVar;
131        FlakeVar = Flake.Flakes[i-1][j];
132        FlakeVar->Ticks++;
133        FlakeVar->YPos = FlakeVar->YPos + ((double)Flake.FallingSpeed)/10/i;
134        FlakeVar->TrueX = (sin(FlakeVar->XOffset + FlakeVar->Ticks*(PI/180)*((double)Flake.FallingSpeed/10)))*10 + FlakeVar->XPos;
135        FlakeVar->Angle = FlakeVar->Angle + 0.005*((double)Flake.FallingSpeed/10);
136        if(FlakeVar->YPos - Flake.Radius > Flake.XGWA.height)
137        {
138          FlakeVar->Ticks = 0;
139          FlakeVar->YPos = 0 - Flake.Radius;
140        }
141      }
142   }
143 }
144
145 static void
146 FuzzyFlakesDrawFlake(int XPos, int YPos, double AngleOffset, int Layer)
147 {
148   int i;
149   double x,y,Angle,Radius;
150   
151   /* calculate the shrink factor debending on which layer we are drawing atm */
152   Radius = (double)(Flake.Radius - Layer * 5);
153   
154   /* draw the flake one arm at a time */
155   for(i=1;i<=Flake.Arms;i++)
156   {
157     int Diameter;
158     Diameter = (Flake.BorderThickness*2 + Flake.Thickness)/Layer;
159     /* compute the angle of this arm of the flake */
160     Angle = ((2*PI)/Flake.Arms)*i + AngleOffset;
161     /* calculate the x and y dispositions for this arm */
162     y=(int)(sin(Angle)*Radius);
163     x=(int)(cos(Angle)*Radius);
164     /* draw the base for the arm */
165     Flake.GCValues.line_width = Diameter;
166     XFreeGC(Flake.DisplayVar,Flake.GCVar);
167     Flake.GCVar = XCreateGC (Flake.DisplayVar, Flake.DB.b, Flake.GCFlags, &Flake.GCValues);
168     XSetForeground(Flake.DisplayVar,Flake.GCVar,Flake.BordColor);
169     XDrawLine(Flake.DisplayVar, Flake.DB.b, Flake.GCVar, XPos,YPos,XPos+x,YPos+y);
170     
171   }
172   /* draw the flake one arm at a time */
173   for(i=1;i<=Flake.Arms;i++)
174   {
175     /* compute the angle of this arm of the flake */
176     Angle = ((2*PI)/Flake.Arms)*i + AngleOffset;
177     /* calculate the x and y dispositions for this arm */
178     y=(int)(sin(Angle)*Radius);
179     x=(int)(cos(Angle)*Radius);
180     /* draw the inside of the arm */
181     Flake.GCValues.line_width = Flake.Thickness/Layer;
182     XFreeGC(Flake.DisplayVar,Flake.GCVar);
183     Flake.GCVar = XCreateGC (Flake.DisplayVar, Flake.DB.b, Flake.GCFlags, &Flake.GCValues);
184     XSetForeground(Flake.DisplayVar,Flake.GCVar,Flake.ForeColor);
185     XDrawLine(Flake.DisplayVar, Flake.DB.b, Flake.GCVar, XPos,YPos,XPos+x,YPos+y);
186   }
187 }
188
189 static void
190 FuzzyFlakes (Display *dpy, Window window)
191 {
192   int i,j;
193   
194   FuzzyFlakesMove();
195
196   XSetForeground(Flake.DisplayVar,Flake.GCVar,Flake.BackColor);
197   XFillRectangle(Flake.DisplayVar,Flake.DB.b,Flake.GCVar,0,0,Flake.XGWA.width,Flake.XGWA.height);
198
199   for(i=Flake.Layers;i>=1;i--)
200   {
201      for(j=0;j<Flake.Density;j++)
202      {
203        FuzzyFlakesDrawFlake(
204                 Flake.Flakes[i-1][j]->TrueX,
205                 Flake.Flakes[i-1][j]->YPos,
206                 Flake.Flakes[i-1][j]->Angle,i);
207      }
208   }
209
210 }
211
212 \f
213 char *progclass = "FuzzyFlakes";
214
215 char *defaults [] = {
216   ".background: pale green",
217   ".foreground: pink",
218   ".border:     snow4",
219   "*arms:       5",
220   "*thickness:  10",
221   "*bthickness: 3",
222   "*radius:     20",
223   "*layers:     3",
224   "*density:    5",
225   "*fallingspeed:       10",
226   "*delay:      10000",
227   "*doubleBuffer:       True",
228   0
229 };
230
231 XrmOptionDescRec options [] = {
232   { "-arms",            ".arms",        XrmoptionSepArg, 0 },
233   { "-thickness",       ".thickness",   XrmoptionSepArg, 0 },
234   { "-bthickness",      ".bthickness",  XrmoptionSepArg, 0 },
235   { "-radius",          ".radius",      XrmoptionSepArg, 0 },
236   { "-layers",          ".layers",      XrmoptionSepArg, 0 },
237   { "-density",         ".density",     XrmoptionSepArg, 0 },
238   { "-speed",           ".fallingspeed",XrmoptionSepArg, 0 },
239   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
240   { "-db",              ".doubleBuffer", XrmoptionNoArg,  "True" },
241   { "-no-db",           ".doubleBuffer", XrmoptionNoArg,  "False" },
242   { 0, 0, 0, 0 }
243 };
244
245 void
246 screenhack (Display *dpy, Window window)
247 {
248   InitFuzzyFlakes (dpy, window);
249   while (1)
250     {
251       FuzzyFlakes (dpy, Flake.DB.b);
252       if (Flake.DB.dbuf)
253         {
254           XCopyArea (Flake.DisplayVar, Flake.DB.b, Flake.WindowVar, Flake.GCVar, 0, 0,
255                      Flake.XGWA.width, Flake.XGWA.height, 0, 0);
256           Flake.DB.b = (Flake.DB.b == Flake.DB.ba ? Flake.DB.bb : Flake.DB.ba);
257         }
258       screenhack_handle_events (dpy);
259       XSync (dpy, False);
260       if (Flake.Delay) usleep (Flake.Delay);
261     }
262 }