1 /* noof, Copyright (c) 2004-2018 Bill Torzewski <billt@worksitez.com>
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
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.
16 #define DEFAULTS "*delay: 10000 \n" \
17 "*showFPS: False \n" \
18 "*fpsSolid: True \n" \
19 "*doubleBuffer: False \n" \
20 "*suppressRotationAnimation: True\n" \
23 # define release_noof 0
24 # define noof_handle_event 0
25 #include "xlockmore.h"
28 #ifdef USE_GL /* whole file */
32 ENTRYPOINT ModeSpecOpt noof_opts = {0, NULL, 0, NULL, NULL};
35 GLXContext *glx_context;
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];
48 float speedsq[N_SHAPES];
55 GLuint screenshot_texture, tex_w, tex_h;
59 static noof_configuration *bps = NULL;
63 initshapes(noof_configuration *bp, int i)
68 /* random init of pos, dir, color */
69 for (k = i * 3; k <= i * 3 + 2; k++) {
70 f = random() / (double) RAND_MAX;
72 f = random() / (double) RAND_MAX;
75 f = random() / (double) RAND_MAX;
76 f = (f - 0.5) * 0.0002;
78 f = random() / (double) RAND_MAX;
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;
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];
94 f = random() / (double) RAND_MAX;
95 bp->hsv[i * 3] = f * 360.0;
97 f = random() / (double) RAND_MAX;
98 bp->hsv[i * 3 + 1] = f * 0.6 + 0.4;
100 f = random() / (double) RAND_MAX;
101 bp->hsv[i * 3 + 2] = f * 0.7 + 0.3;
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;
111 f = random() / (double) RAND_MAX;
112 bp->peep[i] = 0.01 + f * 0.2;
115 static const float bladeratio[] =
118 0.0, 0.0, 3.00000, 1.73205, 1.00000, 0.72654, 0.57735, 0.48157,
120 0.41421, 0.36397, 0.19076, 0.29363, 0.26795, 0.24648,
122 0.22824, 0.21256, 0.19891, 0.18693, 0.17633, 0.16687,
126 drawleaf(noof_configuration *bp, int l)
133 blades = bp->blad[l];
135 y = 0.10 * sin(bp->geep[l] * M_PI / 180.0) + 0.099 * sin(bp->geep[l] * 5.12 * M_PI / 180.0);
138 x = 0.15 * cos(bp->geep[l] * M_PI / 180.0) + 0.149 * cos(bp->geep[l] * 5.12 * M_PI / 180.0);
141 if (y < 0.001 && x > 0.000002 && ((bp->tko & 0x1) == 0)) {
142 initshapes(bp, l); /* let it become reborn as something
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;
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;
160 if (y > x * bladeratio[blades])
161 y = x * bladeratio[blades];
163 for (b = 0; b < blades; b++) {
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]);
169 if(tko & 0x40000) glColor3f(col[l*3], col[l*3+1], col[l*3+2]);
172 glColor4ub(0, 0, 0, 0x60);
174 /* constrain geep cooridinates here XXX */
177 glBegin(GL_TRIANGLE_STRIP);
178 glVertex2f(x * bp->sca[l], 0.0);
180 glVertex2f(x, -y); /* C */
181 glVertex2f(0.3, 0.0); /* D */
186 if(tko++ & 0x40000) glColor3f(0,0,0);
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);
193 glVertex2f(0.3, 0.0); /* D */
194 glVertex2f(x, -y); /* C */
205 motionUpdate(noof_configuration *bp, int t)
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];
210 acc[t*3+1] += 0.8*acc[t*3];
211 acc[t*3] = -0.8*acc[t*3];
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];
216 acc[t*3+1] += 0.8*acc[t*3];
217 acc[t*3] = -0.8*acc[t*3];
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];
222 acc[t*3] += 0.8*acc[t*3+1];
223 acc[t*3+1] = -0.8*acc[t*3+1];
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];
228 acc[t*3] += 0.8*acc[t*3+1];
229 acc[t*3+1] = -0.8*acc[t*3+1];
233 bp->pos[t * 3] += bp->dir[t * 3];
234 bp->pos[t * 3 + 1] += bp->dir[t * 3 + 1];
236 dir[t*3] += acc[t*3];
237 dir[t*3+1] += acc[t*3+1];
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) {
246 if (bp->ang[t] > 360.0) {
252 colorUpdate(noof_configuration *bp, int i)
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 */
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];
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]
272 #define R(hhh) hhh[i*3 ]
273 #define G(hhh) hhh[i*3+1]
274 #define B(hhh) hhh[i*3+2]
276 if (V(bp->hsv) < 0.0)
278 if (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);
285 float f, h, p, q, t, v;
288 while (H(bp->hsv) < 0.0)
290 while (H(bp->hsv) >= 360.0)
293 if (S(bp->hsv) < 0.0)
295 if (S(bp->hsv) > 1.0)
298 h = H(bp->hsv) / 60.0;
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));
310 } else if (hi == 1) {
314 } else if (hi == 2) {
318 } else if (hi == 3) {
322 } else if (hi == 4) {
335 gravity(noof_configuration *bp, float fx)
339 for (a = 0; a < N_SHAPES; a++) {
340 for (b = 0; b < a; b++) {
343 t = bp->pos[b * 3] - bp->pos[a * 3];
345 t = bp->pos[b * 3 + 1] - bp->pos[a * 3 + 1];
352 v0 = bp->pos[b * 3] - bp->pos[a * 3];
353 v1 = bp->pos[b * 3 + 1] - bp->pos[a * 3 + 1];
355 z = 0.00000001 * fx / (d2);
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];
365 if(dir[a*3]*dir[a*3] + dir[a*3+1]*dir[a*3+1]
375 draw_noof (ModeInfo *mi)
378 noof_configuration *bp = &bps[MI_SCREEN(mi)];
380 if (!bp->glx_context)
382 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
384 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
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.
392 if (bp->screenshot_texture)
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);
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);
407 glDisable (GL_TEXTURE_2D);
408 glClear (GL_DEPTH_BUFFER_BIT);
411 mi->polygon_count = 0;
414 if((random() & 0xff) == 0x34){
415 glClear(GL_COLOR_BUFFER_BIT);
418 if((tko & 0x1f) == 0x1f){
420 glColor4f(0.0, 0.0, 0.0, 0.09);
421 glRectf(0.0, 0.0, wd, ht);
430 for (i = 0; i < N_SHAPES; i++) {
433 mi->polygon_count += drawleaf(bp, i);
436 if (bp->screenshot_texture) /* Store a screenshot into the texture. */
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);
447 if (mi->fps_p) do_fps (mi);
450 glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi));
455 reshape_noof(ModeInfo *mi, int w, int h)
457 noof_configuration *bp = &bps[MI_SCREEN(mi)];
459 glViewport(0, 0, w, h);
460 glMatrixMode(GL_PROJECTION);
464 bp->ht = (GLfloat) h / (GLfloat) w;
466 0.0, 1.0 * (GLfloat) h / (GLfloat) w,
469 bp->wd = (GLfloat) w / (GLfloat) h;
471 glOrtho(0.0, 1.0 * (GLfloat) w / (GLfloat) h,
475 glMatrixMode(GL_MODELVIEW);
478 if (!bp->screenshot_texture)
479 glGenTextures (1, &bp->screenshot_texture);
481 glEnable (GL_TEXTURE_2D);
482 glBindTexture (GL_TEXTURE_2D, bp->screenshot_texture);
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");
491 glDisable (GL_TEXTURE_2D);
492 glClear (GL_COLOR_BUFFER_BIT);
496 init_noof (ModeInfo *mi)
499 noof_configuration *bp;
503 bp = &bps[MI_SCREEN(mi)];
505 bp->glx_context = init_GL(mi);
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++)
513 reshape_noof (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
517 XSCREENSAVER_MODULE ("Noof", noof)