From http://www.jwz.org/xscreensaver/xscreensaver-5.40.tar.gz
[xscreensaver] / hacks / glx / noof.c
1 /* noof, Copyright (c) 2004-2018 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 free_noof 0
23 # define release_noof 0
24 # define noof_handle_event 0
25 #include "xlockmore.h"
26 #include "pow2.h"
27
28 #ifdef USE_GL /* whole file */
29
30 #define N_SHAPES 7
31
32 ENTRYPOINT ModeSpecOpt noof_opts = {0, NULL, 0, NULL, NULL};
33
34 typedef struct {
35   GLXContext *glx_context;
36
37   float pos[N_SHAPES * 3];
38   float dir[N_SHAPES * 3];
39   float acc[N_SHAPES * 3];
40   float col[N_SHAPES * 3];
41   float hsv[N_SHAPES * 3];
42   float hpr[N_SHAPES * 3];
43   float ang[N_SHAPES];
44   float spn[N_SHAPES];
45   float sca[N_SHAPES];
46   float geep[N_SHAPES];
47   float peep[N_SHAPES];
48   float speedsq[N_SHAPES];
49   int blad[N_SHAPES];
50
51   float ht, wd;
52
53   int tko;
54
55   GLuint screenshot_texture, tex_w, tex_h;
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
384   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
385
386   /* In the olden days, one could just render directly into the front buffer,
387      or fail to clear the back buffer and assume that one's bits were still
388      there. Not so on modern devices, particularly mobile.  So to achieve
389      the effect of frame N+1 accumulating atop frame N, we must save and
390      restore a screenshot of frame N.
391    */
392   if (bp->screenshot_texture)
393     {
394       GLfloat tw = MI_WIDTH(mi)  / (GLfloat) bp->tex_w;
395       GLfloat th = MI_HEIGHT(mi) / (GLfloat) bp->tex_h;
396       glDisable (GL_BLEND);
397       glEnable (GL_TEXTURE_2D);
398       glBindTexture (GL_TEXTURE_2D, bp->screenshot_texture);
399       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
400       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
401       glBegin (GL_QUADS);
402       glTexCoord2f (0,  0);  glVertex3f (0, 0, 0);
403       glTexCoord2f (tw, 0);  glVertex3f (bp->wd, 0, 0);
404       glTexCoord2f (tw, th); glVertex3f (bp->wd, bp->ht, 0);
405       glTexCoord2f (0,  th); glVertex3f (0, bp->ht, 0);
406       glEnd();
407       glDisable (GL_TEXTURE_2D);
408       glClear (GL_DEPTH_BUFFER_BIT);
409     }
410
411   mi->polygon_count = 0;
412
413   /**
414   if((random() & 0xff) == 0x34){
415     glClear(GL_COLOR_BUFFER_BIT);
416   }
417
418   if((tko & 0x1f) == 0x1f){
419     glEnable(GL_BLEND);
420     glColor4f(0.0, 0.0, 0.0, 0.09);
421     glRectf(0.0, 0.0, wd, ht);
422     glDisable(GL_BLEND);
423 #ifdef __sgi
424     sginap(0);
425 #endif
426   }
427   */
428
429   gravity(bp, -2.0);
430   for (i = 0; i < N_SHAPES; i++) {
431     motionUpdate(bp, i);
432     colorUpdate(bp, i);
433       mi->polygon_count += drawleaf(bp, i);
434   }
435
436   if (bp->screenshot_texture)   /* Store a screenshot into the texture. */
437     {
438       glDisable (GL_BLEND);
439       glEnable (GL_TEXTURE_2D);
440       glBindTexture (GL_TEXTURE_2D, bp->screenshot_texture);
441       glCopyTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 0, 0,
442                            MI_WIDTH(mi), MI_HEIGHT(mi));
443       check_gl_error("screenshot texture");
444       glDisable (GL_TEXTURE_2D);
445     }
446
447   if (mi->fps_p) do_fps (mi);
448   glFinish();
449
450   glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi));
451 }
452
453
454 ENTRYPOINT void
455 reshape_noof(ModeInfo *mi, int w, int h)
456 {
457   noof_configuration *bp = &bps[MI_SCREEN(mi)];
458   char *s;
459   glViewport(0, 0, w, h);
460   glMatrixMode(GL_PROJECTION);
461   glLoadIdentity();
462   if (w <= h) {
463     bp->wd = 1.0;
464     bp->ht = (GLfloat) h / (GLfloat) w;
465     glOrtho(0.0, 1.0,
466       0.0, 1.0 * (GLfloat) h / (GLfloat) w,
467       -16.0, 4.0);
468   } else {
469     bp->wd = (GLfloat) w / (GLfloat) h;
470     bp->ht = 1.0;
471     glOrtho(0.0, 1.0 * (GLfloat) w / (GLfloat) h,
472       0.0, 1.0,
473       -16.0, 4.0);
474   }
475   glMatrixMode(GL_MODELVIEW);
476   glLoadIdentity();
477
478   if (!bp->screenshot_texture)
479     glGenTextures (1, &bp->screenshot_texture);
480
481   glEnable (GL_TEXTURE_2D);
482   glBindTexture (GL_TEXTURE_2D, bp->screenshot_texture);
483
484   bp->tex_w = to_pow2 (MI_WIDTH(mi));
485   bp->tex_h = to_pow2 (MI_HEIGHT(mi));
486   s = calloc (4, bp->tex_w * bp->tex_h);  /* init with black */
487   glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, bp->tex_w, bp->tex_h, 0,
488                 GL_RGBA, GL_UNSIGNED_BYTE, s);
489   check_gl_error ("texture generation");
490   free (s);
491   glDisable (GL_TEXTURE_2D);
492   glClear (GL_COLOR_BUFFER_BIT);
493 }
494
495 ENTRYPOINT void 
496 init_noof (ModeInfo *mi)
497 {
498   int i;
499   noof_configuration *bp;
500
501   MI_INIT (mi, bps);
502
503   bp = &bps[MI_SCREEN(mi)];
504
505   bp->glx_context = init_GL(mi);
506
507   glEnable(GL_LINE_SMOOTH);
508   glShadeModel(GL_FLAT);
509   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
510   for (i = 0; i < N_SHAPES; i++)
511     initshapes(bp, i);
512
513   reshape_noof (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
514 }
515
516
517 XSCREENSAVER_MODULE ("Noof", noof)
518
519 #endif /* USE_GL */