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