1 /* xscreensaver, Copyright (c) 2000 Paul "Joey" Clark <pclark@bris.ac.uk>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * 19971004: Johannes Keukelaar <johannes@nada.kth.se>: Use helix screen
15 /* WhirlwindWarp: moving stars. Ported from QBasic by Joey.
16 Version 1.2. FF parameters now driven by a
17 dampened-walked velocity, making them smoother.
19 This code adapted from original program by jwz/jk above.
20 Freely distrubtable. Please keep this tag with
21 this code, and add your own if you contribute.
22 I would be delighted to hear if have made use of this code.
23 If you find this code useful or have any queries, please
24 contact me: pclark@cs.bris.ac.uk / joeyclark@usa.net
25 Paul "Joey" Clark, hacking for humanity, Feb 99
26 www.cs.bris.ac.uk/~pclark | www.changetheworld.org.uk */
30 #include "screenhack.h"
34 static GC draw_gc, erase_gc;
35 static unsigned int default_fg_pixel;
37 /* Maximum number of points, tails, and fields (hard-coded) */
42 /* Screen width and height */
43 static int scrwid,scrhei;
45 /* Current x,y of stars in realspace */
46 static float cx[maxps];
47 static float cy[maxps];
48 /* Previous x,y plots in pixelspace for removal later */
49 static int tx[maxps*maxts];
50 static int ty[maxps*maxts];
51 /* The force fields and their parameters */
52 static char *name[fs];
53 static int fon[fs]; /* Is field on or off? */
54 static float var[fs]; /* Current parameter */
55 static float op[fs]; /* Optimum (central/mean) value */
56 static float damp[fs]; /* Dampening (how much drawn between current and optimal) */
57 static float force[fs]; /* Amount of change per moment */
60 /* Number of points and tails */
64 /* Show meters or not? */
67 static Bool init_whirlwindwarp(Display *dpy, Window window) {
70 XWindowAttributes xgwa;
71 XGetWindowAttributes (dpy, window, &xgwa);
73 gcv.foreground = default_fg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
74 draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
75 gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
76 erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
78 ps = get_integer_resource ("points", "Integer");
79 ts = get_integer_resource ("tails", "Integer");
80 meters = get_boolean_resource ("meters", "Show meters");
81 if (ps>maxps || ts>maxts)
86 static float myrnd(void) { /* between -1.0 and +1.0 */
87 return 2.0*((float)((random()%10000000)/10000000.0)-0.5);
90 float mysgn(float x) {
96 void stars_newp(int p) {
101 /* Adjust a variable var about optimum op,
102 with damp = dampening about op
103 force = force of random perturbation */
104 float stars_perturb(float var,float op,float damp,float force) {
105 var=op+damp*(var-op)+force*myrnd()/4.0;
106 /* if (fabs(var-op)>0.1) // (to keep within bounds)
107 var=op+0.1*mysgn(var-op);*/
111 /* Get pixel coordinates of a star */
112 int stars_scrpos_x(int p) {
113 return scrwid*(cx[p]+1.0)/2.0;
115 int stars_scrpos_y(int p) {
116 return scrhei*(cy[p]+1.0)/2.0;
119 /* Draw a meter of a forcefield's parameter */
120 void stars_draw_meter(Display *dpy,Window window,GC draw_gc,int f) {
124 w=(var[f]-op[f])*scrwid*4;
131 XFillRectangle(dpy,window,draw_gc,x,y,w,h);
133 XDrawRectangle(dpy,window,draw_gc,x,y,w,h);
136 /* Move a star according to acting forcefields */
137 void stars_move(int p) {
142 x = x * var[1]; y = y * var[1];
145 nx=x*cos(var[2])+y*sin(var[2]);
146 ny=-x*sin(var[2])+y*cos(var[2]);
154 x=(x-1.0)*var[3]+1.0;
160 x = mysgn(x) * pow(fabs(x),var[6]);
161 y = mysgn(y) * pow(fabs(y),var[6]);
166 x=x+var[7]*(-1.0+2.0*(float)(p%2));
168 x=x+var[7]*(-1.0+2.0*(float)((p%50)/49.0));
175 y=y+var[8]*(-1.0+2.0*(float)(p%2));
177 y=y+var[8]*(-1.0+2.0*(float)((p%50)/49.0));
185 static void do_whirlwindwarp(Display *dpy, Window window) {
187 XWindowAttributes xgwa;
191 int p,f,nt, sx,sy, resets,lastresets,cnt;
193 XClearWindow (dpy, window);
194 XGetWindowAttributes (dpy, window, &xgwa);
195 cmap = xgwa.colormap;
197 scrhei = xgwa.height;
200 hsv_to_rgb (0.0, 0.0, 0.0, &bgcolor.red, &bgcolor.green, &bgcolor.blue);
201 got_color = XAllocColor (dpy, cmap, &bgcolor);
204 hsv_to_rgb (random()%360, .6+.4*myrnd(), .6+.4*myrnd(), &color[p].red, &color[p].green, &color[p].blue);
205 /* hsv_to_rgb (random()%360, 1.0, 1.0, &color[p].red, &color[p].green, &color[p].blue); for stronger colours! */
206 if ((!mono_p) && (got_color = XAllocColor (dpy, cmap, &color[p]))) {
211 color[p].pixel=default_fg_pixel;
215 /* Set up parameter movements for the different forcefields */
216 name[1] = "Velocity";
217 op[1] = 1; damp[1] = .999; force[1] = .002;
218 name[2] = "Rotation";
219 op[2] = 0; damp[2] = .999; force[2] = .002;
221 op[3] = 1; damp[3] = .999; force[3] = .005;
223 op[4] = 1; damp[4] = .999; force[4] = .005;
225 op[5] = 0; damp[5] = .999; force[5] = .002;
226 name[6] = "Accelerate";
227 op[6] = 1.0; damp[6] = .999; force[6] = .005;
228 name[7] = "xDisplace";
229 op[7] = 0; damp[7] = .999; force[7] = .005;
230 name[8] = "yDisplace";
231 op[8] = 0; damp[8] = .999; force[8] = .005;
232 /* 0 and 9 are options for splitting displacements [no var] */
234 op[0] = 0; damp[0] = 0; force[0] = 0;
235 name[9] = "2d/3d split";
236 op[9] = 0; damp[9] = 0; force[9] = 0;
238 /* Initialise parameters to optimum, all off */
245 /* Initialise stars */
249 /* tx[nt],ty[nt] remeber earlier screen plots (tails of stars)
250 which are deleted when nt comes round again */
256 /* Move current points */
261 XSetForeground (dpy, draw_gc, bgcolor.pixel);
262 XDrawPoint(dpy,window,draw_gc,tx[nt],ty[nt]);
266 /* If moved off screen, create a new one */
267 if (cx[p]<-1.0 || cx[p]>+1.0 ||
268 cy[p]<-1.0 || cy[p]>+1.0 ||
269 fabs(cx[p])<.0001 || fabs(cy[p])<.0001) {
272 } else if (myrnd()>0.99) /* Reset at random */
276 sx=stars_scrpos_x(p);
277 sy=stars_scrpos_y(p);
278 XSetForeground (dpy, draw_gc, color[p].pixel);
279 XDrawPoint(dpy,window,draw_gc,sx,sy);
281 /* Remember it for removal later */
287 /* Adjust force fields */
291 if (meters) { /* Remove meter from display */
292 XSetForeground(dpy, draw_gc, bgcolor.pixel);
293 stars_draw_meter(dpy,window,draw_gc,f);
296 /* Adjust forcefield's parameter */
297 acc[f]=stars_perturb(acc[f],0,0.98,0.009);
298 var[f]=op[f]+(var[f]-op[f])*damp[f]+force[f]*acc[f];
300 if (myrnd()>0.998) /* Turn it on/off ? */
301 fon[f]=(myrnd()<0.0);
302 /* fon[f]=!fon[f]; */
304 if (meters) { /* Redraw the meter */
305 XSetForeground(dpy, draw_gc, color[f].pixel);
306 stars_draw_meter(dpy,window,draw_gc,f);
312 if (cnt==0) { /* Ensure at least one is on! */
317 XSetForeground(dpy, draw_gc, bgcolor.pixel);
318 XDrawRectangle(dpy,window,draw_gc,0,0,lastresets*5,3);
319 XSetForeground(dpy, draw_gc, default_fg_pixel);
320 XDrawRectangle(dpy,window,draw_gc,0,0,resets*5,3);
322 /* if (resets*5>scrwid) {
323 Turn one off a field if too many points are flying off screen */
324 /* This was a problem when one of the force-fields was acting wrong,
325 but not really needed any more unless we need to debug new ones ...! */
326 /* for (f=0;f<fs;f++)
331 screenhack_handle_events (dpy);
333 do { // In fact this bit might go wrong if
334 f=random() % fs; // we have not ensured at least one is on (above)
340 screenhack_handle_events (dpy);
347 char *progclass = "WhirlwindWarp";
349 char *defaults [] = {
350 ".background: black",
351 ".foreground: white",
358 XrmOptionDescRec options [] = {
359 { "-points", ".points", XrmoptionSepArg, 0 },
360 { "-tails", ".tails", XrmoptionSepArg, 0 },
361 { "-meters", ".meters", XrmoptionNoArg, "true" },
365 void screenhack(Display *dpy, Window window) {
366 if (init_whirlwindwarp(dpy, window))
367 do_whirlwindwarp(dpy, window);