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 "classic"
45 #define DEF_BRIGHTNESS "8"
47 #include <X11/Intrinsic.h>
49 # define PROGCLASS "Flurry"
50 # define HACK_INIT init_flurry
51 # define HACK_DRAW draw_flurry
52 # define HACK_RESHAPE reshape_flurry
53 # define flurry_opts xlockmore_opts
54 # define DEFAULTS "*showFPS: False \n" \
55 "*preset: " DEF_PRESET " \n"
57 # include "xlockmore.h" /* from the xscreensaver distribution */
61 static char *preset_str;
63 static XrmOptionDescRec opts[] = {
64 { "-preset", ".preset", XrmoptionSepArg, 0 }
67 static argtype vars[] = {
68 {&preset_str, "preset", "Preset", DEF_PRESET, t_String},
71 #define countof(x) (sizeof((x))/sizeof((*x)))
73 ModeSpecOpt flurry_opts = {countof(opts), opts, countof(vars), vars, NULL};
76 ModStruct flurry_description = {
85 1000, 1, 2, 1, 4, 1.0,
98 global_info_t *flurry_info = NULL;
100 static double gTimeCounter = 0.0;
102 double currentTime(void) {
104 # ifdef GETTIMEOFDAY_TWO_ARGS
106 gettimeofday(&tv, &tzp);
111 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
114 void OTSetup (void) {
115 if (gTimeCounter == 0.0) {
116 gTimeCounter = currentTime();
120 double TimeInSecondsSinceStart (void) {
121 return currentTime() - gTimeCounter;
126 static int IsAltiVecAvailable(void)
133 void delete_flurry_info(flurry_info_t *flurry)
139 for (i=0;i<MAX_SPARKS;i++)
141 free(flurry->spark[i]);
146 flurry_info_t *new_flurry_info(global_info_t *global, int streams, ColorModes colour, float thickness, float speed, double bf)
149 flurry_info_t *flurry = (flurry_info_t *)malloc(sizeof(flurry_info_t));
151 if (!flurry) return NULL;
153 flurry->flurryRandomSeed = RandFlt(0.0, 300.0);
155 flurry->fOldTime = 0;
156 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
157 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
159 flurry->numStreams = streams;
160 flurry->streamExpansion = thickness;
161 flurry->currentColorMode = colour;
162 flurry->briteFactor = bf;
164 flurry->s = malloc(sizeof(SmokeV));
165 InitSmoke(flurry->s);
167 flurry->star = malloc(sizeof(Star));
168 InitStar(flurry->star);
169 flurry->star->rotSpeed = speed;
171 for (i = 0;i < MAX_SPARKS; i++)
173 flurry->spark[i] = malloc(sizeof(Spark));
174 InitSpark(flurry->spark[i]);
175 flurry->spark[i]->mystery = 1800 * (i + 1) / 13; /* 100 * (i + 1) / (flurry->numStreams + 1); */
176 UpdateSpark(global, flurry, flurry->spark[i]);
179 for (i=0;i<NUMSMOKEPARTICLES/4;i++) {
181 flurry->s->p[i].dead.i[k] = 1;
190 void GLSetupRC(global_info_t *global)
192 /* setup the defaults for OpenGL */
193 glDisable(GL_DEPTH_TEST);
194 glAlphaFunc(GL_GREATER,0.0f);
195 glEnable(GL_ALPHA_TEST);
196 glShadeModel(GL_FLAT);
197 glDisable(GL_LIGHTING);
198 glDisable(GL_CULL_FACE);
201 glViewport(0,0,(int) global->sys_glWidth,(int) global->sys_glHeight);
202 glMatrixMode(GL_PROJECTION);
204 gluOrtho2D(0,global->sys_glWidth,0,global->sys_glHeight);
205 glMatrixMode(GL_MODELVIEW);
208 glClearColor(0.0,0.0,0.0,1.0);
209 glClear(GL_COLOR_BUFFER_BIT);
211 glEnableClientState(GL_COLOR_ARRAY);
212 glEnableClientState(GL_VERTEX_ARRAY);
213 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
217 global->optMode = OPT_MODE_SCALAR_FRSQRTE;
220 if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
224 global->optMode = OPT_MODE_SCALAR_BASE;
229 void GLRenderScene(global_info_t *global, flurry_info_t *flurry, double b)
235 flurry->fOldTime = flurry->fTime;
236 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
237 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
239 flurry->drag = (float) pow(0.9965,flurry->fDeltaTime*85.0);
241 UpdateStar(global, flurry, flurry->star);
244 glShadeModel(GL_SMOOTH);
246 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
249 for (i=0;i<flurry->numStreams;i++) {
250 flurry->spark[i]->color[0]=1.0;
251 flurry->spark[i]->color[1]=1.0;
252 flurry->spark[i]->color[2]=1.0;
253 flurry->spark[i]->color[2]=1.0;
254 UpdateSpark(global, flurry, flurry->spark[i]);
256 DrawSpark(global, flurry, flurry->spark[i]);
260 switch(global->optMode) {
261 case OPT_MODE_SCALAR_BASE:
262 UpdateSmoke_ScalarBase(global, flurry, flurry->s);
266 case OPT_MODE_SCALAR_FRSQRTE:
267 UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
271 case OPT_MODE_VECTOR_SIMPLE:
272 UpdateSmoke_VectorBase(global, flurry, flurry->s);
274 case OPT_MODE_VECTOR_UNROLLED:
275 UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
284 /* glDisable(GL_BLEND); */
286 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
287 glEnable(GL_TEXTURE_2D);
289 switch(global->optMode) {
290 case OPT_MODE_SCALAR_BASE:
293 case OPT_MODE_SCALAR_FRSQRTE:
296 DrawSmoke_Scalar(global, flurry, flurry->s, b);
300 case OPT_MODE_VECTOR_SIMPLE:
301 case OPT_MODE_VECTOR_UNROLLED:
302 DrawSmoke_Vector(global, flurry, flurry->s, b);
310 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 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);