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 glClear(GL_COLOR_BUFFER_BIT);
208 glEnableClientState(GL_COLOR_ARRAY);
209 glEnableClientState(GL_VERTEX_ARRAY);
210 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
214 global->optMode = OPT_MODE_SCALAR_FRSQRTE;
217 if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
221 global->optMode = OPT_MODE_SCALAR_BASE;
227 void GLRenderScene(global_info_t *global, flurry_info_t *flurry, double b)
233 flurry->fOldTime = flurry->fTime;
234 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
235 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
237 flurry->drag = (float) pow(0.9965,flurry->fDeltaTime*85.0);
239 UpdateStar(global, flurry, flurry->star);
242 glShadeModel(GL_SMOOTH);
244 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
247 for (i=0;i<flurry->numStreams;i++) {
248 flurry->spark[i]->color[0]=1.0;
249 flurry->spark[i]->color[1]=1.0;
250 flurry->spark[i]->color[2]=1.0;
251 flurry->spark[i]->color[2]=1.0;
252 UpdateSpark(global, flurry, flurry->spark[i]);
254 DrawSpark(global, flurry, flurry->spark[i]);
258 switch(global->optMode) {
259 case OPT_MODE_SCALAR_BASE:
260 UpdateSmoke_ScalarBase(global, flurry, flurry->s);
264 case OPT_MODE_SCALAR_FRSQRTE:
265 UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
269 case OPT_MODE_VECTOR_SIMPLE:
270 UpdateSmoke_VectorBase(global, flurry, flurry->s);
272 case OPT_MODE_VECTOR_UNROLLED:
273 UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
282 /* glDisable(GL_BLEND); */
284 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
285 glEnable(GL_TEXTURE_2D);
287 switch(global->optMode) {
288 case OPT_MODE_SCALAR_BASE:
291 case OPT_MODE_SCALAR_FRSQRTE:
294 DrawSmoke_Scalar(global, flurry, flurry->s, b);
298 case OPT_MODE_VECTOR_SIMPLE:
299 case OPT_MODE_VECTOR_UNROLLED:
300 DrawSmoke_Vector(global, flurry, flurry->s, b);
308 glDisable(GL_TEXTURE_2D);
312 void GLResize(global_info_t *global, float w, float h)
314 global->sys_glWidth = w;
315 global->sys_glHeight = h;
318 /* new window size or exposure */
319 ENTRYPOINT void reshape_flurry(ModeInfo *mi, int width, int height)
321 global_info_t *global = flurry_info + MI_SCREEN(mi);
323 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
325 glViewport(0.0, 0.0, width, height);
326 glMatrixMode(GL_PROJECTION);
328 gluOrtho2D(0, width, 0, height);
329 glMatrixMode(GL_MODELVIEW);
330 glClear(GL_COLOR_BUFFER_BIT);
332 GLResize(global, (float)width, (float)height);
336 init_flurry(ModeInfo * mi)
338 int screen = MI_SCREEN(mi);
340 global_info_t *global;
352 if (flurry_info == NULL) {
354 if ((flurry_info = (global_info_t *) calloc(MI_NUM_SCREENS(mi),
355 sizeof (global_info_t))) == NULL)
359 global = &flurry_info[screen];
361 global->window = MI_WINDOW(mi);
363 global->flurry = NULL;
365 if (!preset_str || !*preset_str) preset_str = DEF_PRESET;
366 if (!strcmp(preset_str, "random")) {
367 preset_num = random() % PRESET_MAX;
368 } else if (!strcmp(preset_str, "water")) {
369 preset_num = PRESET_WATER;
370 } else if (!strcmp(preset_str, "fire")) {
371 preset_num = PRESET_FIRE;
372 } else if (!strcmp(preset_str, "psychedelic")) {
373 preset_num = PRESET_PSYCHEDELIC;
374 } else if (!strcmp(preset_str, "rgb")) {
375 preset_num = PRESET_RGB;
376 } else if (!strcmp(preset_str, "binary")) {
377 preset_num = PRESET_BINARY;
378 } else if (!strcmp(preset_str, "classic")) {
379 preset_num = PRESET_CLASSIC;
380 } else if (!strcmp(preset_str, "insane")) {
381 preset_num = PRESET_INSANE;
383 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
387 switch (preset_num) {
389 for (i = 0; i < 9; i++) {
390 flurry_info_t *flurry;
392 flurry = new_flurry_info(global, 1, blueColorMode, 100.0, 2.0, 2.0);
393 flurry->next = global->flurry;
394 global->flurry = flurry;
399 flurry_info_t *flurry;
401 flurry = new_flurry_info(global, 12, slowCyclicColorMode, 10000.0, 0.2, 1.0);
402 flurry->next = global->flurry;
403 global->flurry = flurry;
406 case PRESET_PSYCHEDELIC: {
407 flurry_info_t *flurry;
409 flurry = new_flurry_info(global, 10, rainbowColorMode, 200.0, 2.0, 1.0);
410 flurry->next = global->flurry;
411 global->flurry = flurry;
415 flurry_info_t *flurry;
417 flurry = new_flurry_info(global, 3, redColorMode, 100.0, 0.8, 1.0);
418 flurry->next = global->flurry;
419 global->flurry = flurry;
421 flurry = new_flurry_info(global, 3, greenColorMode, 100.0, 0.8, 1.0);
422 flurry->next = global->flurry;
423 global->flurry = flurry;
425 flurry = new_flurry_info(global, 3, blueColorMode, 100.0, 0.8, 1.0);
426 flurry->next = global->flurry;
427 global->flurry = flurry;
430 case PRESET_BINARY: {
431 flurry_info_t *flurry;
433 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 0.5, 1.0);
434 flurry->next = global->flurry;
435 global->flurry = flurry;
437 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 1.5, 1.0);
438 flurry->next = global->flurry;
439 global->flurry = flurry;
442 case PRESET_CLASSIC: {
443 flurry_info_t *flurry;
445 flurry = new_flurry_info(global, 5, tiedyeColorMode, 10000.0, 1.0, 1.0);
446 flurry->next = global->flurry;
447 global->flurry = flurry;
450 case PRESET_INSANE: {
451 flurry_info_t *flurry;
453 flurry = new_flurry_info(global, 64, tiedyeColorMode, 1000.0, 0.5, 0.5);
454 flurry->next = global->flurry;
455 global->flurry = flurry;
460 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
465 if ((global->glx_context = init_GL(mi)) != NULL) {
466 reshape_flurry(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
474 draw_flurry(ModeInfo * mi)
476 static int first = 1;
477 static double oldFrameTime = -1;
479 double deltaFrameTime = 0;
483 global_info_t *global = flurry_info + MI_SCREEN(mi);
484 flurry_info_t *flurry;
485 Display *display = MI_DISPLAY(mi);
486 Window window = MI_WINDOW(mi);
488 newFrameTime = currentTime();
489 if (oldFrameTime == -1) {
490 /* special case the first frame -- clear to black */
494 * this clamps the speed at below 60fps and, here
495 * at least, produces a reasonably accurate 50fps.
496 * (probably part CPU speed and part scheduler).
498 * Flurry is designed to run at this speed; much higher
499 * than that and the blending causes the display to
500 * saturate, which looks really ugly.
502 if (newFrameTime - oldFrameTime < 1/60.0) {
503 usleep(MAX_(1,(int)(20000 * (newFrameTime - oldFrameTime))));
507 deltaFrameTime = newFrameTime - oldFrameTime;
508 alpha = 5.0 * deltaFrameTime;
510 oldFrameTime = newFrameTime;
512 if (alpha > 0.2) alpha = 0.2;
514 if (!global->glx_context)
521 glDrawBuffer(GL_BACK);
522 glXMakeCurrent(display, window, *(global->glx_context));
525 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
527 glColor4f(0.0, 0.0, 0.0, alpha);
528 glRectd(0, 0, global->sys_glWidth, global->sys_glHeight);
530 brite = pow(deltaFrameTime,0.75) * 10;
531 for (flurry = global->flurry; flurry; flurry=flurry->next) {
532 GLRenderScene(global, flurry, brite * flurry->briteFactor);
535 if (mi->fps_p) do_fps (mi);
538 glXSwapBuffers(display, window);
542 release_flurry(ModeInfo * mi)
544 if (flurry_info != NULL) {
547 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
548 global_info_t *global = &flurry_info[screen];
549 flurry_info_t *flurry;
551 if (global->glx_context) {
552 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
555 for (flurry = global->flurry; flurry; flurry=flurry->next) {
556 delete_flurry_info(flurry);
559 (void) free((void *) flurry_info);
565 XSCREENSAVER_MODULE ("Flurry", flurry)