1 /* -*- Mode: C; tab-width: 4 c-basic-offset: 4 indent-tabs-mode: t -*- */
8 Copyright (c) 2002, Calum Robinson
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice, this
15 list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright notice,
18 this list of conditions and the following disclaimer in the documentation
19 and/or other materials provided with the distribution.
21 * Neither the name of the author nor the names of its contributors may be used
22 to endorse or promote products derived from this software without specific
23 prior written permission.
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
29 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
32 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 static const char sccsid[] = "@(#)flurry.c 4.07 97/11/24 xlockmore";
44 #define DEF_PRESET "random"
45 #define DEF_BRIGHTNESS "8"
47 # define DEFAULTS "*delay: 10000 \n" \
50 # define refresh_flurry 0
51 # define flurry_handle_event 0
52 # include "xlockmore.h" /* from the xscreensaver distribution */
56 static char *preset_str;
58 static XrmOptionDescRec opts[] = {
59 { "-preset", ".preset", XrmoptionSepArg, 0 }
62 static argtype vars[] = {
63 {&preset_str, "preset", "Preset", DEF_PRESET, t_String},
66 #define countof(x) (sizeof((x))/sizeof((*x)))
68 ENTRYPOINT ModeSpecOpt flurry_opts = {countof(opts), opts, countof(vars), vars, NULL};
71 ModStruct flurry_description = {
80 1000, 1, 2, 1, 4, 1.0,
91 global_info_t *flurry_info = NULL;
93 static double gTimeCounter = 0.0;
96 double currentTime(void) {
98 # ifdef GETTIMEOFDAY_TWO_ARGS
100 gettimeofday(&tv, &tzp);
105 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
108 void OTSetup (void) {
109 if (gTimeCounter == 0.0) {
110 gTimeCounter = currentTime();
114 double TimeInSecondsSinceStart (void) {
115 return currentTime() - gTimeCounter;
120 static int IsAltiVecAvailable(void)
129 void delete_flurry_info(flurry_info_t *flurry)
135 for (i=0;i<MAX_SPARKS;i++)
137 free(flurry->spark[i]);
143 flurry_info_t *new_flurry_info(global_info_t *global, int streams, ColorModes colour, float thickness, float speed, double bf)
146 flurry_info_t *flurry = (flurry_info_t *)malloc(sizeof(flurry_info_t));
148 if (!flurry) return NULL;
150 flurry->flurryRandomSeed = RandFlt(0.0, 300.0);
152 flurry->fOldTime = 0;
153 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
154 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
156 flurry->numStreams = streams;
157 flurry->streamExpansion = thickness;
158 flurry->currentColorMode = colour;
159 flurry->briteFactor = bf;
161 flurry->s = malloc(sizeof(SmokeV));
162 InitSmoke(flurry->s);
164 flurry->star = malloc(sizeof(Star));
165 InitStar(flurry->star);
166 flurry->star->rotSpeed = speed;
168 for (i = 0;i < MAX_SPARKS; i++)
170 flurry->spark[i] = malloc(sizeof(Spark));
171 InitSpark(flurry->spark[i]);
172 flurry->spark[i]->mystery = 1800 * (i + 1) / 13; /* 100 * (i + 1) / (flurry->numStreams + 1); */
173 UpdateSpark(global, flurry, flurry->spark[i]);
176 for (i=0;i<NUMSMOKEPARTICLES/4;i++) {
178 flurry->s->p[i].dead.i[k] = 1;
188 void GLSetupRC(global_info_t *global)
190 /* setup the defaults for OpenGL */
191 glDisable(GL_DEPTH_TEST);
192 glAlphaFunc(GL_GREATER,0.0f);
193 glEnable(GL_ALPHA_TEST);
194 glShadeModel(GL_FLAT);
195 glDisable(GL_LIGHTING);
196 glDisable(GL_CULL_FACE);
199 glViewport(0,0,(int) global->sys_glWidth,(int) global->sys_glHeight);
200 glMatrixMode(GL_PROJECTION);
202 gluOrtho2D(0,global->sys_glWidth,0,global->sys_glHeight);
203 glMatrixMode(GL_MODELVIEW);
206 glClearColor(0.0,0.0,0.0,1.0);
207 glClear(GL_COLOR_BUFFER_BIT);
209 glEnableClientState(GL_COLOR_ARRAY);
210 glEnableClientState(GL_VERTEX_ARRAY);
211 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
215 global->optMode = OPT_MODE_SCALAR_FRSQRTE;
218 if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
222 global->optMode = OPT_MODE_SCALAR_BASE;
228 void GLRenderScene(global_info_t *global, flurry_info_t *flurry, double b)
234 flurry->fOldTime = flurry->fTime;
235 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
236 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
238 flurry->drag = (float) pow(0.9965,flurry->fDeltaTime*85.0);
240 UpdateStar(global, flurry, flurry->star);
243 glShadeModel(GL_SMOOTH);
245 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
248 for (i=0;i<flurry->numStreams;i++) {
249 flurry->spark[i]->color[0]=1.0;
250 flurry->spark[i]->color[1]=1.0;
251 flurry->spark[i]->color[2]=1.0;
252 flurry->spark[i]->color[2]=1.0;
253 UpdateSpark(global, flurry, flurry->spark[i]);
255 DrawSpark(global, flurry, flurry->spark[i]);
259 switch(global->optMode) {
260 case OPT_MODE_SCALAR_BASE:
261 UpdateSmoke_ScalarBase(global, flurry, flurry->s);
265 case OPT_MODE_SCALAR_FRSQRTE:
266 UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
270 case OPT_MODE_VECTOR_SIMPLE:
271 UpdateSmoke_VectorBase(global, flurry, flurry->s);
273 case OPT_MODE_VECTOR_UNROLLED:
274 UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
283 /* glDisable(GL_BLEND); */
285 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
286 glEnable(GL_TEXTURE_2D);
288 switch(global->optMode) {
289 case OPT_MODE_SCALAR_BASE:
292 case OPT_MODE_SCALAR_FRSQRTE:
295 DrawSmoke_Scalar(global, flurry, flurry->s, b);
299 case OPT_MODE_VECTOR_SIMPLE:
300 case OPT_MODE_VECTOR_UNROLLED:
301 DrawSmoke_Vector(global, flurry, flurry->s, b);
309 glDisable(GL_TEXTURE_2D);
313 void GLResize(global_info_t *global, float w, float h)
315 global->sys_glWidth = w;
316 global->sys_glHeight = h;
319 /* new window size or exposure */
320 ENTRYPOINT void reshape_flurry(ModeInfo *mi, int width, int height)
322 global_info_t *global = flurry_info + MI_SCREEN(mi);
324 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
326 glViewport(0.0, 0.0, width, height);
327 glMatrixMode(GL_PROJECTION);
329 gluOrtho2D(0, width, 0, height);
330 glMatrixMode(GL_MODELVIEW);
332 glClearColor(0.0, 0.0, 0.0, 1.0);
333 glClear(GL_COLOR_BUFFER_BIT);
337 GLResize(global, (float)width, (float)height);
341 init_flurry(ModeInfo * mi)
343 int screen = MI_SCREEN(mi);
345 global_info_t *global;
357 if (flurry_info == NULL) {
359 if ((flurry_info = (global_info_t *) calloc(MI_NUM_SCREENS(mi),
360 sizeof (global_info_t))) == NULL)
364 global = &flurry_info[screen];
366 global->window = MI_WINDOW(mi);
368 global->flurry = NULL;
370 if (!preset_str || !*preset_str) preset_str = DEF_PRESET;
371 if (!strcmp(preset_str, "random")) {
372 preset_num = random() % PRESET_MAX;
373 } else if (!strcmp(preset_str, "water")) {
374 preset_num = PRESET_WATER;
375 } else if (!strcmp(preset_str, "fire")) {
376 preset_num = PRESET_FIRE;
377 } else if (!strcmp(preset_str, "psychedelic")) {
378 preset_num = PRESET_PSYCHEDELIC;
379 } else if (!strcmp(preset_str, "rgb")) {
380 preset_num = PRESET_RGB;
381 } else if (!strcmp(preset_str, "binary")) {
382 preset_num = PRESET_BINARY;
383 } else if (!strcmp(preset_str, "classic")) {
384 preset_num = PRESET_CLASSIC;
385 } else if (!strcmp(preset_str, "insane")) {
386 preset_num = PRESET_INSANE;
388 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
392 switch (preset_num) {
394 for (i = 0; i < 9; i++) {
395 flurry_info_t *flurry;
397 flurry = new_flurry_info(global, 1, blueColorMode, 100.0, 2.0, 2.0);
398 flurry->next = global->flurry;
399 global->flurry = flurry;
404 flurry_info_t *flurry;
406 flurry = new_flurry_info(global, 12, slowCyclicColorMode, 10000.0, 0.0, 1.0);
407 flurry->next = global->flurry;
408 global->flurry = flurry;
411 case PRESET_PSYCHEDELIC: {
412 flurry_info_t *flurry;
414 flurry = new_flurry_info(global, 10, rainbowColorMode, 200.0, 2.0, 1.0);
415 flurry->next = global->flurry;
416 global->flurry = flurry;
420 flurry_info_t *flurry;
422 flurry = new_flurry_info(global, 3, redColorMode, 100.0, 0.8, 1.0);
423 flurry->next = global->flurry;
424 global->flurry = flurry;
426 flurry = new_flurry_info(global, 3, greenColorMode, 100.0, 0.8, 1.0);
427 flurry->next = global->flurry;
428 global->flurry = flurry;
430 flurry = new_flurry_info(global, 3, blueColorMode, 100.0, 0.8, 1.0);
431 flurry->next = global->flurry;
432 global->flurry = flurry;
435 case PRESET_BINARY: {
436 flurry_info_t *flurry;
438 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 0.5, 1.0);
439 flurry->next = global->flurry;
440 global->flurry = flurry;
442 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 1.5, 1.0);
443 flurry->next = global->flurry;
444 global->flurry = flurry;
447 case PRESET_CLASSIC: {
448 flurry_info_t *flurry;
450 flurry = new_flurry_info(global, 5, tiedyeColorMode, 10000.0, 1.0, 1.0);
451 flurry->next = global->flurry;
452 global->flurry = flurry;
455 case PRESET_INSANE: {
456 flurry_info_t *flurry;
458 flurry = new_flurry_info(global, 64, tiedyeColorMode, 1000.0, 0.5, 0.5);
459 flurry->next = global->flurry;
460 global->flurry = flurry;
465 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
470 if ((global->glx_context = init_GL(mi)) != NULL) {
471 reshape_flurry(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
479 draw_flurry(ModeInfo * mi)
481 static int first = 1;
482 static double oldFrameTime = -1;
484 double deltaFrameTime = 0;
488 global_info_t *global = flurry_info + MI_SCREEN(mi);
489 flurry_info_t *flurry;
490 Display *display = MI_DISPLAY(mi);
491 Window window = MI_WINDOW(mi);
493 newFrameTime = currentTime();
494 if (oldFrameTime == -1) {
495 /* special case the first frame -- clear to black */
499 * this clamps the speed at below 60fps and, here
500 * at least, produces a reasonably accurate 50fps.
501 * (probably part CPU speed and part scheduler).
503 * Flurry is designed to run at this speed; much higher
504 * than that and the blending causes the display to
505 * saturate, which looks really ugly.
507 if (newFrameTime - oldFrameTime < 1/60.0) {
508 usleep(MAX_(1,(int)(20000 * (newFrameTime - oldFrameTime))));
512 deltaFrameTime = newFrameTime - oldFrameTime;
513 alpha = 5.0 * deltaFrameTime;
515 oldFrameTime = newFrameTime;
517 if (alpha > 0.2) alpha = 0.2;
519 if (!global->glx_context)
526 glDrawBuffer(GL_BACK);
527 glXMakeCurrent(display, window, *(global->glx_context));
530 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
532 glColor4f(0.0, 0.0, 0.0, alpha);
533 glRectd(0, 0, global->sys_glWidth, global->sys_glHeight);
535 brite = pow(deltaFrameTime,0.75) * 10;
536 for (flurry = global->flurry; flurry; flurry=flurry->next) {
537 GLRenderScene(global, flurry, brite * flurry->briteFactor);
540 if (mi->fps_p) do_fps (mi);
543 glXSwapBuffers(display, window);
547 release_flurry(ModeInfo * mi)
549 if (flurry_info != NULL) {
552 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
553 global_info_t *global = &flurry_info[screen];
554 flurry_info_t *flurry;
556 if (global->glx_context) {
557 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
560 for (flurry = global->flurry; flurry; flurry=flurry->next) {
561 delete_flurry_info(flurry);
564 (void) free((void *) flurry_info);
570 XSCREENSAVER_MODULE ("Flurry", flurry)