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 release_flurry 0
52 # define flurry_handle_event 0
53 # include "xlockmore.h" /* from the xscreensaver distribution */
57 static char *preset_str;
59 static XrmOptionDescRec opts[] = {
60 { "-preset", ".preset", XrmoptionSepArg, 0 }
63 static argtype vars[] = {
64 {&preset_str, "preset", "Preset", DEF_PRESET, t_String},
67 #define countof(x) (sizeof((x))/sizeof((*x)))
69 ENTRYPOINT ModeSpecOpt flurry_opts = {countof(opts), opts, countof(vars), vars, NULL};
72 ModStruct flurry_description = {
81 1000, 1, 2, 1, 4, 1.0,
92 global_info_t *flurry_info = NULL;
95 double currentTime(void) {
97 # ifdef GETTIMEOFDAY_TWO_ARGS
99 gettimeofday(&tv, &tzp);
104 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
107 double TimeInSecondsSinceStart (const global_info_t *global) {
108 return currentTime() - global->gTimeCounter;
113 static int IsAltiVecAvailable(void)
122 void delete_flurry_info(flurry_info_t *flurry)
128 for (i=0;i<MAX_SPARKS;i++)
130 free(flurry->spark[i]);
136 flurry_info_t *new_flurry_info(global_info_t *global, int streams, ColorModes colour, float thickness, float speed, double bf)
139 flurry_info_t *flurry = (flurry_info_t *)malloc(sizeof(flurry_info_t));
141 if (!flurry) return NULL;
143 flurry->flurryRandomSeed = RandFlt(0.0, 300.0);
145 flurry->fOldTime = 0;
147 flurry->fTime = TimeInSecondsSinceStart(global) + flurry->flurryRandomSeed;
148 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
150 flurry->numStreams = streams;
151 flurry->streamExpansion = thickness;
152 flurry->currentColorMode = colour;
153 flurry->briteFactor = bf;
155 flurry->s = malloc(sizeof(SmokeV));
156 InitSmoke(flurry->s);
158 flurry->star = malloc(sizeof(Star));
159 InitStar(flurry->star);
160 flurry->star->rotSpeed = speed;
162 for (i = 0;i < MAX_SPARKS; i++)
164 flurry->spark[i] = malloc(sizeof(Spark));
165 InitSpark(flurry->spark[i]);
166 flurry->spark[i]->mystery = 1800 * (i + 1) / 13; /* 100 * (i + 1) / (flurry->numStreams + 1); */
167 UpdateSpark(global, flurry, flurry->spark[i]);
170 for (i=0;i<NUMSMOKEPARTICLES/4;i++) {
172 flurry->s->p[i].dead.i[k] = 1;
182 void GLSetupRC(global_info_t *global)
184 /* setup the defaults for OpenGL */
185 glDisable(GL_DEPTH_TEST);
186 glAlphaFunc(GL_GREATER,0.0f);
187 glEnable(GL_ALPHA_TEST);
188 glShadeModel(GL_FLAT);
189 glDisable(GL_LIGHTING);
190 glDisable(GL_CULL_FACE);
193 glViewport(0,0,(int) global->sys_glWidth,(int) global->sys_glHeight);
194 glMatrixMode(GL_PROJECTION);
196 glOrtho(0,global->sys_glWidth,0,global->sys_glHeight,-1,1);
197 glMatrixMode(GL_MODELVIEW);
200 glClear(GL_COLOR_BUFFER_BIT);
202 glEnableClientState(GL_COLOR_ARRAY);
203 glEnableClientState(GL_VERTEX_ARRAY);
204 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
208 global->optMode = OPT_MODE_SCALAR_FRSQRTE;
211 if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
215 global->optMode = OPT_MODE_SCALAR_BASE;
221 void GLRenderScene(global_info_t *global, flurry_info_t *flurry, double b)
227 flurry->fOldTime = flurry->fTime;
228 flurry->fTime = TimeInSecondsSinceStart(global) + flurry->flurryRandomSeed;
229 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
231 flurry->drag = (float) pow(0.9965,flurry->fDeltaTime*85.0);
233 UpdateStar(global, flurry, flurry->star);
236 glShadeModel(GL_SMOOTH);
238 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
241 for (i=0;i<flurry->numStreams;i++) {
242 flurry->spark[i]->color[0]=1.0;
243 flurry->spark[i]->color[1]=1.0;
244 flurry->spark[i]->color[2]=1.0;
245 flurry->spark[i]->color[2]=1.0;
246 UpdateSpark(global, flurry, flurry->spark[i]);
248 DrawSpark(global, flurry, flurry->spark[i]);
252 switch(global->optMode) {
253 case OPT_MODE_SCALAR_BASE:
254 UpdateSmoke_ScalarBase(global, flurry, flurry->s);
258 case OPT_MODE_SCALAR_FRSQRTE:
259 UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
263 case OPT_MODE_VECTOR_SIMPLE:
264 UpdateSmoke_VectorBase(global, flurry, flurry->s);
266 case OPT_MODE_VECTOR_UNROLLED:
267 UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
276 /* glDisable(GL_BLEND); */
278 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
279 glEnable(GL_TEXTURE_2D);
281 switch(global->optMode) {
282 case OPT_MODE_SCALAR_BASE:
285 case OPT_MODE_SCALAR_FRSQRTE:
288 DrawSmoke_Scalar(global, flurry, flurry->s, b);
292 case OPT_MODE_VECTOR_SIMPLE:
293 case OPT_MODE_VECTOR_UNROLLED:
294 DrawSmoke_Vector(global, flurry, flurry->s, b);
302 glDisable(GL_TEXTURE_2D);
306 void GLResize(global_info_t *global, float w, float h)
308 global->sys_glWidth = w;
309 global->sys_glHeight = h;
312 /* new window size or exposure */
313 ENTRYPOINT void reshape_flurry(ModeInfo *mi, int width, int height)
315 global_info_t *global = flurry_info + MI_SCREEN(mi);
317 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
319 glViewport(0.0, 0.0, width, height);
320 glMatrixMode(GL_PROJECTION);
322 glOrtho(0, width, 0, height,-1,1);
323 glMatrixMode(GL_MODELVIEW);
324 glClear(GL_COLOR_BUFFER_BIT);
326 GLResize(global, (float)width, (float)height);
329 static void free_flurry(ModeInfo * mi);
332 init_flurry(ModeInfo * mi)
334 int screen = MI_SCREEN(mi);
336 global_info_t *global;
348 MI_INIT (mi, flurry_info, free_flurry);
350 global = &flurry_info[screen];
352 global->gTimeCounter = currentTime();
354 global->window = MI_WINDOW(mi);
356 global->flurry = NULL;
358 if (!preset_str || !*preset_str) preset_str = DEF_PRESET;
359 if (!strcmp(preset_str, "random")) {
360 preset_num = random() % PRESET_MAX;
361 } else if (!strcmp(preset_str, "water")) {
362 preset_num = PRESET_WATER;
363 } else if (!strcmp(preset_str, "fire")) {
364 preset_num = PRESET_FIRE;
365 } else if (!strcmp(preset_str, "psychedelic")) {
366 preset_num = PRESET_PSYCHEDELIC;
367 } else if (!strcmp(preset_str, "rgb")) {
368 preset_num = PRESET_RGB;
369 } else if (!strcmp(preset_str, "binary")) {
370 preset_num = PRESET_BINARY;
371 } else if (!strcmp(preset_str, "classic")) {
372 preset_num = PRESET_CLASSIC;
373 } else if (!strcmp(preset_str, "insane")) {
374 preset_num = PRESET_INSANE;
376 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
380 switch (preset_num) {
382 for (i = 0; i < 9; i++) {
383 flurry_info_t *flurry;
385 flurry = new_flurry_info(global, 1, blueColorMode, 100.0, 2.0, 2.0);
386 flurry->next = global->flurry;
387 global->flurry = flurry;
392 flurry_info_t *flurry;
394 flurry = new_flurry_info(global, 12, slowCyclicColorMode, 10000.0, 0.2, 1.0);
395 flurry->next = global->flurry;
396 global->flurry = flurry;
399 case PRESET_PSYCHEDELIC: {
400 flurry_info_t *flurry;
402 flurry = new_flurry_info(global, 10, rainbowColorMode, 200.0, 2.0, 1.0);
403 flurry->next = global->flurry;
404 global->flurry = flurry;
408 flurry_info_t *flurry;
410 flurry = new_flurry_info(global, 3, redColorMode, 100.0, 0.8, 1.0);
411 flurry->next = global->flurry;
412 global->flurry = flurry;
414 flurry = new_flurry_info(global, 3, greenColorMode, 100.0, 0.8, 1.0);
415 flurry->next = global->flurry;
416 global->flurry = flurry;
418 flurry = new_flurry_info(global, 3, blueColorMode, 100.0, 0.8, 1.0);
419 flurry->next = global->flurry;
420 global->flurry = flurry;
423 case PRESET_BINARY: {
424 flurry_info_t *flurry;
426 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 0.5, 1.0);
427 flurry->next = global->flurry;
428 global->flurry = flurry;
430 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 1.5, 1.0);
431 flurry->next = global->flurry;
432 global->flurry = flurry;
435 case PRESET_CLASSIC: {
436 flurry_info_t *flurry;
438 flurry = new_flurry_info(global, 5, tiedyeColorMode, 10000.0, 1.0, 1.0);
439 flurry->next = global->flurry;
440 global->flurry = flurry;
443 case PRESET_INSANE: {
444 flurry_info_t *flurry;
446 flurry = new_flurry_info(global, 64, tiedyeColorMode, 1000.0, 0.5, 0.5);
447 flurry->next = global->flurry;
448 global->flurry = flurry;
453 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
458 if ((global->glx_context = init_GL(mi)) != NULL) {
459 reshape_flurry(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
466 global->oldFrameTime = -1;
470 draw_flurry(ModeInfo * mi)
473 double deltaFrameTime = 0;
477 global_info_t *global = flurry_info + MI_SCREEN(mi);
478 flurry_info_t *flurry;
479 Display *display = MI_DISPLAY(mi);
480 Window window = MI_WINDOW(mi);
482 newFrameTime = currentTime();
483 if (global->oldFrameTime == -1) {
484 /* special case the first frame -- clear to black */
488 * this clamps the speed at below 60fps and, here
489 * at least, produces a reasonably accurate 50fps.
490 * (probably part CPU speed and part scheduler).
492 * Flurry is designed to run at this speed; much higher
493 * than that and the blending causes the display to
494 * saturate, which looks really ugly.
496 if (newFrameTime - global->oldFrameTime < 1/60.0) {
497 usleep(MAX_(1,(int)(20000 * (newFrameTime - global->oldFrameTime))));
501 deltaFrameTime = newFrameTime - global->oldFrameTime;
502 alpha = 5.0 * deltaFrameTime;
504 global->oldFrameTime = newFrameTime;
506 if (alpha > 0.2) alpha = 0.2;
508 if (!global->glx_context)
515 glDrawBuffer(GL_BACK);
516 glXMakeCurrent(display, window, *(global->glx_context));
519 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
521 glColor4f(0.0, 0.0, 0.0, alpha);
522 glRectd(0, 0, global->sys_glWidth, global->sys_glHeight);
524 brite = pow(deltaFrameTime,0.75) * 10;
525 for (flurry = global->flurry; flurry; flurry=flurry->next) {
526 GLRenderScene(global, flurry, brite * flurry->briteFactor);
529 if (mi->fps_p) do_fps (mi);
532 glXSwapBuffers(display, window);
536 free_flurry(ModeInfo * mi)
538 global_info_t *global = &flurry_info[MI_SCREEN(mi)];
539 flurry_info_t *flurry;
541 if (global->glx_context) {
542 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
545 for (flurry = global->flurry; flurry; flurry=flurry->next) {
546 delete_flurry_info(flurry);
550 XSCREENSAVER_MODULE ("Flurry", flurry)