http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / glx / noof.c
1 /* noof, Copyright (c) 2004 Bill Torzewski <billt@worksitez.com>
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  * Originally a demo included with GLUT;
12  * (Apparently this was called "diatoms" on Irix.)
13  * ported to raw GL and xscreensaver by jwz, 12-Feb-2004.
14  */
15
16 #define DEFAULTS        "*delay:        10000       \n" \
17                         "*showFPS:      False       \n" \
18                         "*fpsSolid:     True        \n" \
19
20 # define refresh_noof 0
21 # define release_noof 0
22 # define noof_handle_event 0
23 #include "xlockmore.h"
24
25 #ifdef USE_GL /* whole file */
26
27 #define N_SHAPES 7
28
29 ENTRYPOINT ModeSpecOpt noof_opts = {0, NULL, 0, NULL, NULL};
30
31 typedef struct {
32   GLXContext *glx_context;
33
34   float pos[N_SHAPES * 3];
35   float dir[N_SHAPES * 3];
36   float acc[N_SHAPES * 3];
37   float col[N_SHAPES * 3];
38   float hsv[N_SHAPES * 3];
39   float hpr[N_SHAPES * 3];
40   float ang[N_SHAPES];
41   float spn[N_SHAPES];
42   float sca[N_SHAPES];
43   float geep[N_SHAPES];
44   float peep[N_SHAPES];
45   float speedsq[N_SHAPES];
46   int blad[N_SHAPES];
47
48   float ht, wd;
49
50   int tko;
51
52 } noof_configuration;
53
54 static noof_configuration *bps = NULL;
55
56
57 static void
58 initshapes(noof_configuration *bp, int i)
59 {
60   int k;
61   float f;
62
63   /* random init of pos, dir, color */
64   for (k = i * 3; k <= i * 3 + 2; k++) {
65     f = random() / (double) RAND_MAX;
66     bp->pos[k] = f;
67     f = random() / (double) RAND_MAX;
68     f = (f - 0.5) * 0.05;
69     bp->dir[k] = f;
70     f = random() / (double) RAND_MAX;
71     f = (f - 0.5) * 0.0002;
72     bp->acc[k] = f;
73     f = random() / (double) RAND_MAX;
74     bp->col[k] = f;
75   }
76
77   bp->speedsq[i] = bp->dir[i * 3] * bp->dir[i * 3] + bp->dir[i * 3 + 1] * bp->dir[i * 3 + 1];
78   f = random() / (double) RAND_MAX;
79   bp->blad[i] = 2 + (int) (f * 17.0);
80   f = random() / (double) RAND_MAX;
81   bp->ang[i] = f;
82   f = random() / (double) RAND_MAX;
83   bp->spn[i] = (f - 0.5) * 40.0 / (10 + bp->blad[i]);
84   f = random() / (double) RAND_MAX;
85   bp->sca[i] = (f * 0.1 + 0.08);
86   bp->dir[i * 3] *= bp->sca[i];
87   bp->dir[i * 3 + 1] *= bp->sca[i];
88
89   f = random() / (double) RAND_MAX;
90   bp->hsv[i * 3] = f * 360.0;
91
92   f = random() / (double) RAND_MAX;
93   bp->hsv[i * 3 + 1] = f * 0.6 + 0.4;
94
95   f = random() / (double) RAND_MAX;
96   bp->hsv[i * 3 + 2] = f * 0.7 + 0.3;
97
98   f = random() / (double) RAND_MAX;
99   bp->hpr[i * 3] = f * 0.005 * 360.0;
100   f = random() / (double) RAND_MAX;
101   bp->hpr[i * 3 + 1] = f * 0.03;
102   f = random() / (double) RAND_MAX;
103   bp->hpr[i * 3 + 2] = f * 0.02;
104
105   bp->geep[i] = 0;
106   f = random() / (double) RAND_MAX;
107   bp->peep[i] = 0.01 + f * 0.2;
108 }
109
110 static const float bladeratio[] =
111 {
112   /* nblades = 2..7 */
113   0.0, 0.0, 3.00000, 1.73205, 1.00000, 0.72654, 0.57735, 0.48157,
114   /* 8..13 */
115   0.41421, 0.36397, 0.19076, 0.29363, 0.26795, 0.24648,
116   /* 14..19 */
117   0.22824, 0.21256, 0.19891, 0.18693, 0.17633, 0.16687,
118 };
119
120 static void
121 drawleaf(noof_configuration *bp, int l)
122 {
123
124   int b, blades;
125   float x, y;
126   float wobble;
127
128   blades = bp->blad[l];
129
130   y = 0.10 * sin(bp->geep[l] * M_PI / 180.0) + 0.099 * sin(bp->geep[l] * 5.12 * M_PI / 180.0);
131   if (y < 0)
132     y = -y;
133   x = 0.15 * cos(bp->geep[l] * M_PI / 180.0) + 0.149 * cos(bp->geep[l] * 5.12 * M_PI / 180.0);
134   if (x < 0.0)
135     x = 0.0 - x;
136   if (y < 0.001 && x > 0.000002 && ((bp->tko & 0x1) == 0)) {
137     initshapes(bp, l);      /* let it become reborn as something
138                            else */
139     bp->tko++;
140     return;
141   } {
142     float w1 = sin(bp->geep[l] * 15.3 * M_PI / 180.0);
143     wobble = 3.0 + 2.00 * sin(bp->geep[l] * 0.4 * M_PI / 180.0) + 3.94261 * w1;
144   }
145
146   /**
147   if(blades == 2) if (y > 3.000*x) y = x*3.000;
148   if(blades == 3) if (y > 1.732*x) y = x*1.732;
149   if(blades == 4) if (y >       x) y = x;
150   if(blades == 5) if (y > 0.726*x) y = x*0.726;
151   if(blades == 6) if (y > 0.577*x) y = x*0.577;
152   if(blades == 7) if (y > 0.481*x) y = x*0.481;
153   if(blades == 8) if (y > 0.414*x) y = x*0.414;
154   */
155   if (y > x * bladeratio[blades])
156     y = x * bladeratio[blades];
157
158   for (b = 0; b < blades; b++) {
159     glPushMatrix();
160     glTranslatef(bp->pos[l * 3], bp->pos[l * 3 + 1], bp->pos[l * 3 + 2]);
161     glRotatef(bp->ang[l] + b * (360.0 / blades), 0.0, 0.0, 1.0);
162     glScalef(wobble * bp->sca[l], wobble * bp->sca[l], wobble * bp->sca[l]);
163     /**
164     if(tko & 0x40000) glColor3f(col[l*3], col[l*3+1], col[l*3+2]); 
165     else
166     */
167     glColor4ub(0, 0, 0, 0x60);
168
169     /* constrain geep cooridinates here XXX */
170     glEnable(GL_BLEND);
171
172     glBegin(GL_TRIANGLE_STRIP);
173     glVertex2f(x * bp->sca[l], 0.0);
174     glVertex2f(x, y);
175     glVertex2f(x, -y);  /* C */
176     glVertex2f(0.3, 0.0);  /* D */
177     glEnd();
178
179     /**
180     if(tko++ & 0x40000) glColor3f(0,0,0);
181     else
182     */
183     glColor3f(bp->col[l * 3], bp->col[l * 3 + 1], bp->col[l * 3 + 2]);
184     glBegin(GL_LINE_LOOP);
185     glVertex2f(x * bp->sca[l], 0.0);
186     glVertex2f(x, y);
187     glVertex2f(0.3, 0.0);  /* D */
188     glVertex2f(x, -y);  /* C */
189     glEnd();
190     glDisable(GL_BLEND);
191
192     glPopMatrix();
193   }
194 }
195
196 static void
197 motionUpdate(noof_configuration *bp, int t)
198 {
199   if (bp->pos[t * 3] < -bp->sca[t] * bp->wd && bp->dir[t * 3] < 0.0) {
200     bp->dir[t * 3] = -bp->dir[t * 3];
201   /**
202   acc[t*3+1] += 0.8*acc[t*3];
203   acc[t*3] = -0.8*acc[t*3];
204   */
205   } else if (bp->pos[t * 3] > (1 + bp->sca[t]) * bp->wd && bp->dir[t * 3] > 0.0) {
206     bp->dir[t * 3] = -bp->dir[t * 3];
207     /**
208     acc[t*3+1] += 0.8*acc[t*3];
209     acc[t*3] = -0.8*acc[t*3];
210     */
211   } else if (bp->pos[t * 3 + 1] < -bp->sca[t] * bp->ht && bp->dir[t * 3 + 1] < 0.0) {
212     bp->dir[t * 3 + 1] = -bp->dir[t * 3 + 1];
213     /**
214     acc[t*3] += 0.8*acc[t*3+1];
215     acc[t*3+1] = -0.8*acc[t*3+1];
216     */
217   } else if (bp->pos[t * 3 + 1] > (1 + bp->sca[t]) * bp->ht && bp->dir[t * 3 + 1] > 0.0) {
218     bp->dir[t * 3 + 1] = -bp->dir[t * 3 + 1];
219     /**
220     acc[t*3] += 0.8*acc[t*3+1];
221     acc[t*3+1] = -0.8*acc[t*3+1];
222     */
223   }
224
225   bp->pos[t * 3] += bp->dir[t * 3];
226   bp->pos[t * 3 + 1] += bp->dir[t * 3 + 1];
227   /**
228   dir[t*3]   += acc[t*3];
229   dir[t*3+1] += acc[t*3+1];
230   */
231   bp->ang[t] += bp->spn[t];
232   bp->geep[t] += bp->peep[t];
233   if (bp->geep[t] > 360 * 5.0)
234     bp->geep[t] -= 360 * 5.0;
235   if (bp->ang[t] < 0.0) {
236     bp->ang[t] += 360.0;
237   }
238   if (bp->ang[t] > 360.0) {
239     bp->ang[t] -= 360.0;
240   }
241 }
242
243 static void
244 colorUpdate(noof_configuration *bp, int i)
245 {
246   if (bp->hsv[i * 3 + 1] <= 0.5 && bp->hpr[i * 3 + 1] < 0.0)
247     bp->hpr[i * 3 + 1] = -bp->hpr[i * 3 + 1];  /* adjust s */
248   if (bp->hsv[i * 3 + 1] >= 1.0 && bp->hpr[i * 3 + 1] > 0.0)
249     bp->hpr[i * 3 + 1] = -bp->hpr[i * 3 + 1];  /* adjust s */
250   if (bp->hsv[i * 3 + 2] <= 0.4 && bp->hpr[i * 3 + 2] < 0.0)
251     bp->hpr[i * 3 + 2] = -bp->hpr[i * 3 + 2];  /* adjust s */
252   if (bp->hsv[i * 3 + 2] >= 1.0 && bp->hpr[i * 3 + 2] > 0.0)
253     bp->hpr[i * 3 + 2] = -bp->hpr[i * 3 + 2];  /* adjust s */
254
255   bp->hsv[i * 3] += bp->hpr[i * 3];
256   bp->hsv[i * 3 + 1] += bp->hpr[i * 3 + 1];
257   bp->hsv[i * 3 + 2] += bp->hpr[i * 3 + 2];
258
259   /* --- hsv -> rgb --- */
260 #define H(hhh) hhh[i*3  ]
261 #define S(hhh) hhh[i*3+1]
262 #define V(hhh) hhh[i*3+2]
263
264 #define R(hhh) hhh[i*3  ]
265 #define G(hhh) hhh[i*3+1]
266 #define B(hhh) hhh[i*3+2]
267
268   if (V(bp->hsv) < 0.0)
269     V(bp->hsv) = 0.0;
270   if (V(bp->hsv) > 1.0)
271     V(bp->hsv) = 1.0;
272   if (S(bp->hsv) <= 0.0) {
273     R(bp->col) = V(bp->hsv);
274     G(bp->col) = V(bp->hsv);
275     B(bp->col) = V(bp->hsv);
276   } else {
277     float f, h, p, q, t, v;
278     int hi;
279
280     while (H(bp->hsv) < 0.0)
281       H(bp->hsv) += 360.0;
282     while (H(bp->hsv) >= 360.0)
283       H(bp->hsv) -= 360.0;
284
285     if (S(bp->hsv) < 0.0)
286       S(bp->hsv) = 0.0;
287     if (S(bp->hsv) > 1.0)
288       S(bp->hsv) = 1.0;
289
290     h = H(bp->hsv) / 60.0;
291     hi = (int) (h);
292     f = h - hi;
293     v = V(bp->hsv);
294     p = V(bp->hsv) * (1 - S(bp->hsv));
295     q = V(bp->hsv) * (1 - S(bp->hsv) * f);
296     t = V(bp->hsv) * (1 - S(bp->hsv) * (1 - f));
297
298     if (hi <= 0) {
299       R(bp->col) = v;
300       G(bp->col) = t;
301       B(bp->col) = p;
302     } else if (hi == 1) {
303       R(bp->col) = q;
304       G(bp->col) = v;
305       B(bp->col) = p;
306     } else if (hi == 2) {
307       R(bp->col) = p;
308       G(bp->col) = v;
309       B(bp->col) = t;
310     } else if (hi == 3) {
311       R(bp->col) = p;
312       G(bp->col) = q;
313       B(bp->col) = v;
314     } else if (hi == 4) {
315       R(bp->col) = t;
316       G(bp->col) = p;
317       B(bp->col) = v;
318     } else {
319       R(bp->col) = v;
320       G(bp->col) = p;
321       B(bp->col) = q;
322     }
323   }
324 }
325
326 static void
327 gravity(noof_configuration *bp, float fx)
328 {
329   int a, b;
330
331   for (a = 0; a < N_SHAPES; a++) {
332     for (b = 0; b < a; b++) {
333       float t, d2;
334
335       t = bp->pos[b * 3] - bp->pos[a * 3];
336       d2 = t * t;
337       t = bp->pos[b * 3 + 1] - bp->pos[a * 3 + 1];
338       d2 += t * t;
339       if (d2 < 0.000001)
340         d2 = 0.00001;
341       if (d2 < 0.1) {
342
343         float v0, v1, z;
344         v0 = bp->pos[b * 3] - bp->pos[a * 3];
345         v1 = bp->pos[b * 3 + 1] - bp->pos[a * 3 + 1];
346
347         z = 0.00000001 * fx / (d2);
348
349         bp->dir[a * 3] += v0 * z * bp->sca[b];
350         bp->dir[b * 3] += -v0 * z * bp->sca[a];
351         bp->dir[a * 3 + 1] += v1 * z * bp->sca[b];
352         bp->dir[b * 3 + 1] += -v1 * z * bp->sca[a];
353
354       }
355     }
356     /** apply brakes
357     if(dir[a*3]*dir[a*3] + dir[a*3+1]*dir[a*3+1]
358       > 0.0001) {
359       dir[a*3] *= 0.9;
360       dir[a*3+1] *= 0.9;
361     }
362     */
363   }
364 }
365
366 ENTRYPOINT void
367 draw_noof (ModeInfo *mi)
368 {
369   int i;
370   noof_configuration *bp = &bps[MI_SCREEN(mi)];
371
372   if (!bp->glx_context)
373     return;
374   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
375
376   /**
377   if((random() & 0xff) == 0x34){
378     glClear(GL_COLOR_BUFFER_BIT);
379   }
380
381   if((tko & 0x1f) == 0x1f){
382     glEnable(GL_BLEND);
383     glColor4f(0.0, 0.0, 0.0, 0.09);
384     glRectf(0.0, 0.0, wd, ht);
385     glDisable(GL_BLEND);
386 #ifdef __sgi
387     sginap(0);
388 #endif
389   }
390   */
391
392   gravity(bp, -2.0);
393   for (i = 0; i < N_SHAPES; i++) {
394     motionUpdate(bp, i);
395     colorUpdate(bp, i);
396     drawleaf(bp, i);
397   }
398
399   if (mi->fps_p) do_fps (mi);
400   glFinish();
401
402 /* For some reason this hack screws up on Cocoa if we try to double-buffer it.
403    It looks fine single-buffered, so let's just do that. */
404 /*  glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi)); */
405 }
406
407
408 ENTRYPOINT void
409 reshape_noof(ModeInfo *mi, int w, int h)
410 {
411   noof_configuration *bp = &bps[MI_SCREEN(mi)];
412   glViewport(0, 0, w, h);
413   glMatrixMode(GL_PROJECTION);
414   glLoadIdentity();
415   if (w <= h) {
416     bp->wd = 1.0;
417     bp->ht = (GLfloat) h / (GLfloat) w;
418     glOrtho(0.0, 1.0,
419       0.0, 1.0 * (GLfloat) h / (GLfloat) w,
420       -16.0, 4.0);
421   } else {
422     bp->wd = (GLfloat) w / (GLfloat) h;
423     bp->ht = 1.0;
424     glOrtho(0.0, 1.0 * (GLfloat) w / (GLfloat) h,
425       0.0, 1.0,
426       -16.0, 4.0);
427   }
428   glMatrixMode(GL_MODELVIEW);
429   glLoadIdentity();
430
431   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
432 }
433
434 ENTRYPOINT void 
435 init_noof (ModeInfo *mi)
436 {
437   int i;
438   noof_configuration *bp;
439
440   if (!bps) {
441     bps = (noof_configuration *)
442       calloc (MI_NUM_SCREENS(mi), sizeof (noof_configuration));
443     if (!bps) {
444       fprintf(stderr, "%s: out of memory\n", progname);
445       exit(1);
446     }
447   }
448
449   bp = &bps[MI_SCREEN(mi)];
450
451   bp->glx_context = init_GL(mi);
452
453   glDrawBuffer(GL_FRONT);
454   glClearColor(0.0, 0.0, 0.0, 1.0);
455   glEnable(GL_LINE_SMOOTH);
456   glShadeModel(GL_FLAT);
457   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
458   for (i = 0; i < N_SHAPES; i++)
459     initshapes(bp, i);
460   reshape_noof (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
461 }
462
463
464 XSCREENSAVER_MODULE ("Noof", noof)
465
466 #endif /* USE_GL */