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