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