source: trunk/third/xscreensaver/hacks/whirlwindwarp.c @ 20148

Revision 20148, 10.2 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* xscreensaver, Copyright (c) 2000 Paul "Joey" Clark <pclark@bris.ac.uk>
2 *
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
9 * implied warranty.
10 *
11 * 19971004: Johannes Keukelaar <johannes@nada.kth.se>: Use helix screen
12 *           eraser.
13 */
14
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.
18
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 */
27
28#include <math.h>
29
30#include "screenhack.h"
31#include "erase.h"
32#include "hsv.h"
33
34static GC draw_gc, erase_gc;
35static unsigned int default_fg_pixel;
36
37/* Maximum number of points, tails, and fields (hard-coded) */
38#define maxps 1000
39#define maxts 30
40#define fs 10
41
42/* Screen width and height */
43static int scrwid,scrhei;
44
45/* Current x,y of stars in realspace */
46static float cx[maxps];
47static float cy[maxps];
48/* Previous x,y plots in pixelspace for removal later */
49static int tx[maxps*maxts];
50static int ty[maxps*maxts];
51/* The force fields and their parameters */
52static char *name[fs];
53static int fon[fs];     /* Is field on or off? */
54static float var[fs];   /* Current parameter */
55static float op[fs];    /* Optimum (central/mean) value */
56static float damp[fs];  /* Dampening (how much drawn between current and optimal) */
57static float force[fs]; /* Amount of change per moment */
58static float acc[fs];
59
60/* Number of points and tails */
61static int ps=500;
62static int ts=5;
63
64/* Show meters or not? */
65static Bool meters;
66
67static Bool init_whirlwindwarp(Display *dpy, Window window) {
68  XGCValues gcv;
69  Colormap cmap;
70  XWindowAttributes xgwa;
71  XGetWindowAttributes (dpy, window, &xgwa);
72  cmap = xgwa.colormap;
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);
77
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)
82    return 0;
83  return 1;
84}
85
86static float myrnd(void) { /* between -1.0 and +1.0 */
87  return 2.0*((float)((random()%10000000)/10000000.0)-0.5);
88}
89
90float mysgn(float x) {
91  return ( x < 0 ? -1 :
92           x > 0 ? +1 :
93                    0 );
94}
95
96void stars_newp(int p) {
97  cx[p]=myrnd();
98  cy[p]=myrnd();
99}
100
101/* Adjust a variable var about optimum op,
102     with damp = dampening about op
103         force = force of random perturbation */
104float 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);*/
108  return var;
109}
110
111/* Get pixel coordinates of a star */
112int stars_scrpos_x(int p) {
113  return scrwid*(cx[p]+1.0)/2.0;
114}
115int stars_scrpos_y(int p) {
116  return scrhei*(cy[p]+1.0)/2.0;
117}
118
119/* Draw a meter of a forcefield's parameter */
120void stars_draw_meter(Display *dpy,Window window,GC draw_gc,int f) {
121  int x,y,w,h;
122  x=scrwid/2;
123  y=f*10;
124  w=(var[f]-op[f])*scrwid*4;
125  h=7;
126  if (w<0) {
127    w=-w;
128    x=x-w;
129  }
130  if (fon[f])
131    XFillRectangle(dpy,window,draw_gc,x,y,w,h);
132  else
133    XDrawRectangle(dpy,window,draw_gc,x,y,w,h);
134}
135
136/* Move a star according to acting forcefields */
137void stars_move(int p) {
138  float nx,ny;
139  float x=cx[p];
140  float y=cy[p];
141    if (fon[1]) {
142        x = x * var[1]; y = y * var[1];
143    }
144    if (fon[2]) {
145      nx=x*cos(var[2])+y*sin(var[2]);
146      ny=-x*sin(var[2])+y*cos(var[2]);
147      x=nx;
148      y=ny;
149    }
150    if (fon[3]) {
151      y=y*var[3];
152    }
153    if (fon[4]) {
154      x=(x-1.0)*var[3]+1.0;
155    }
156    if (fon[5]) {
157      x=x+var[5]*x;
158    }
159    if (fon[6]) {
160        x = mysgn(x) * pow(fabs(x),var[6]);
161        y = mysgn(y) * pow(fabs(y),var[6]);
162    }
163    if (fon[7]) {
164      if (fon[0]) {
165        if (fon[9]) {
166          x=x+var[7]*(-1.0+2.0*(float)(p%2));
167        } else {
168          x=x+var[7]*(-1.0+2.0*(float)((p%50)/49.0));
169        }
170      }
171    }
172    if (fon[8]) {
173      if (fon[0]) {
174        if (fon[9]) {
175          y=y+var[8]*(-1.0+2.0*(float)(p%2));
176        } else {
177          y=y+var[8]*(-1.0+2.0*(float)((p%50)/49.0));
178        }
179      }
180    }
181  cx[p]=x;
182  cy[p]=y;
183}
184
185static void do_whirlwindwarp(Display *dpy, Window window) {
186  Colormap cmap;
187  XWindowAttributes xgwa;
188  int got_color = 0;
189  XColor color[maxps];
190  XColor bgcolor;
191  int p,f,nt, sx,sy, resets,lastresets,cnt;
192
193  XClearWindow (dpy, window);
194  XGetWindowAttributes (dpy, window, &xgwa);
195  cmap = xgwa.colormap;
196  scrwid = xgwa.width;
197  scrhei = xgwa.height;
198
199  /* Setup colours */
200  hsv_to_rgb (0.0, 0.0, 0.0, &bgcolor.red, &bgcolor.green, &bgcolor.blue);
201  got_color = XAllocColor (dpy, cmap, &bgcolor);
202  for (p=0;p<ps;p++) {
203        if (!mono_p)
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]))) {
207        } else {
208          if (p>0)
209            color[p]=color[0];
210          else
211            color[p].pixel=default_fg_pixel;
212        }
213  }
214
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;
220  name[3] = "Drip";
221  op[3] = 1; damp[3] = .999; force[3] = .005;
222  name[4] = "Dribble";
223  op[4] = 1; damp[4] = .999; force[4] = .005;
224  name[5] = "Slide";
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] */
233  name[0] = "Split";
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;
237
238  /* Initialise parameters to optimum, all off */
239  for (f=0;f<fs;f++) {
240    var[f]=op[f];
241    fon[f]=0;
242    acc[f]=0;
243  }
244
245  /* Initialise stars */
246  for (p=0;p<ps;p++)
247    stars_newp(p);
248
249  /* tx[nt],ty[nt] remeber earlier screen plots (tails of stars)
250     which are deleted when nt comes round again */
251  nt=0;
252  resets=0;
253
254  while (1) {
255
256      /* Move current points */
257      lastresets=resets;
258      resets=0;
259      for (p=0;p<ps;p++) {
260        /* Erase old */
261        XSetForeground (dpy, draw_gc, bgcolor.pixel);
262        XDrawPoint(dpy,window,draw_gc,tx[nt],ty[nt]);
263
264        /* Move */
265        stars_move(p);
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) {
270          stars_newp(p);
271          resets++;
272        } else if (myrnd()>0.99) /* Reset at random */
273          stars_newp(p);
274
275        /* Draw point */
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);
280
281        /* Remember it for removal later */
282        tx[nt]=sx;
283        ty[nt]=sy;
284        nt=(nt+1)%(ps*ts);
285      }
286
287      /* Adjust force fields */
288      cnt=0;
289      for (f=0;f<fs;f++) {
290
291        if (meters) { /* Remove meter from display */
292          XSetForeground(dpy, draw_gc, bgcolor.pixel);
293          stars_draw_meter(dpy,window,draw_gc,f);
294        }
295
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];
299
300        if (myrnd()>0.998) /* Turn it on/off ? */
301          fon[f]=(myrnd()<0.0);
302          /* fon[f]=!fon[f]; */
303
304        if (meters) { /* Redraw the meter */
305          XSetForeground(dpy, draw_gc, color[f].pixel);
306          stars_draw_meter(dpy,window,draw_gc,f);
307        }
308
309        if (fon[f])
310          cnt++;
311      }
312      if (cnt==0) { /* Ensure at least one is on! */
313        f=random() % fs;
314        fon[f]=1;
315      }
316      if (meters) {
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);
321      }
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++)
327            if (fon[f])
328            printf("%i",f);
329          printf("\n");
330          XSync (dpy, False);
331          screenhack_handle_events (dpy);
332         sleep(1);
333        do { // In fact this bit might go wrong if
334          f=random() % fs; // we have not ensured at least one is on (above)
335        } while (!fon[f]);
336        fon[f]=0;
337      }            */
338
339      XSync (dpy, False);
340      screenhack_handle_events (dpy);
341
342  }
343
344}
345
346
347char *progclass = "WhirlwindWarp";
348
349char *defaults [] = {
350  ".background: black",
351  ".foreground: white",
352  "*points:     400",
353  "*tails:      10",
354  "*meters:     false",
355  0
356};
357
358XrmOptionDescRec options [] = {
359  { "-points",  ".points",      XrmoptionSepArg, 0 },
360  { "-tails",   ".tails",       XrmoptionSepArg, 0 },
361  { "-meters",  ".meters",      XrmoptionNoArg, "true" },
362  { 0, 0, 0, 0 }
363};
364
365void screenhack(Display *dpy, Window window) {
366  if (init_whirlwindwarp(dpy, window))
367    do_whirlwindwarp(dpy, window);
368}
Note: See TracBrowser for help on using the repository browser.