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";
45 * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
46 * otherwise caddr_t is not defined correctly
49 #define DEF_PRESET "classic"
50 #define DEF_BRIGHTNESS "8"
52 #include <X11/Intrinsic.h>
54 # define PROGCLASS "Flurry"
55 # define HACK_INIT init_flurry
56 # define HACK_DRAW draw_flurry
57 # define HACK_RESHAPE reshape_flurry
58 # define flurry_opts xlockmore_opts
59 # define DEFAULTS "*showFPS: False \n" \
60 "*preset: " DEF_PRESET " \n"
62 # include "xlockmore.h" /* from the xscreensaver distribution */
66 static char *preset_str;
68 static XrmOptionDescRec opts[] = {
69 { "-preset", ".preset", XrmoptionSepArg, 0 }
72 static argtype vars[] = {
73 {(caddr_t *) &preset_str, "preset", "Preset", DEF_PRESET, t_String},
76 #define countof(x) (sizeof((x))/sizeof((*x)))
78 ModeSpecOpt flurry_opts = {countof(opts), opts, countof(vars), vars, NULL};
81 ModStruct flurry_description = {
90 1000, 1, 2, 1, 4, 1.0,
103 global_info_t *flurry_info = NULL;
105 static double gTimeCounter = 0.0;
107 double currentTime(void) {
109 # ifdef GETTIMEOFDAY_TWO_ARGS
111 gettimeofday(&tv, &tzp);
116 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
119 void OTSetup (void) {
120 if (gTimeCounter == 0.0) {
121 gTimeCounter = currentTime();
125 double TimeInSecondsSinceStart (void) {
126 return currentTime() - gTimeCounter;
131 static int IsAltiVecAvailable(void)
138 void delete_flurry_info(flurry_info_t *flurry)
144 for (i=0;i<MAX_SPARKS;i++)
146 free(flurry->spark[i]);
151 flurry_info_t *new_flurry_info(global_info_t *global, int streams, ColorModes colour, float thickness, float speed, double bf)
154 flurry_info_t *flurry = (flurry_info_t *)malloc(sizeof(flurry_info_t));
156 if (!flurry) return NULL;
158 flurry->flurryRandomSeed = RandFlt(0.0, 300.0);
160 flurry->fOldTime = 0;
161 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
162 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
164 flurry->numStreams = streams;
165 flurry->streamExpansion = thickness;
166 flurry->currentColorMode = colour;
167 flurry->briteFactor = bf;
169 flurry->s = malloc(sizeof(SmokeV));
170 InitSmoke(flurry->s);
172 flurry->star = malloc(sizeof(Star));
173 InitStar(flurry->star);
174 flurry->star->rotSpeed = speed;
176 for (i = 0;i < MAX_SPARKS; i++)
178 flurry->spark[i] = malloc(sizeof(Spark));
179 InitSpark(flurry->spark[i]);
180 flurry->spark[i]->mystery = 1800 * (i + 1) / 13; /* 100 * (i + 1) / (flurry->numStreams + 1); */
181 UpdateSpark(global, flurry, flurry->spark[i]);
184 for (i=0;i<NUMSMOKEPARTICLES/4;i++) {
186 flurry->s->p[i].dead.i[k] = 1;
195 void GLSetupRC(global_info_t *global)
197 /* setup the defaults for OpenGL */
198 glDisable(GL_DEPTH_TEST);
199 glAlphaFunc(GL_GREATER,0.0f);
200 glEnable(GL_ALPHA_TEST);
201 glShadeModel(GL_FLAT);
202 glDisable(GL_LIGHTING);
203 glDisable(GL_CULL_FACE);
206 glViewport(0,0,(int) global->sys_glWidth,(int) global->sys_glHeight);
207 glMatrixMode(GL_PROJECTION);
209 gluOrtho2D(0,global->sys_glWidth,0,global->sys_glHeight);
210 glMatrixMode(GL_MODELVIEW);
213 glClearColor(0.0,0.0,0.0,1.0);
214 glClear(GL_COLOR_BUFFER_BIT);
216 glEnableClientState(GL_COLOR_ARRAY);
217 glEnableClientState(GL_VERTEX_ARRAY);
218 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
222 global->optMode = OPT_MODE_SCALAR_FRSQRTE;
225 if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
229 global->optMode = OPT_MODE_SCALAR_BASE;
234 void GLRenderScene(global_info_t *global, flurry_info_t *flurry, double b)
240 flurry->fOldTime = flurry->fTime;
241 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
242 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
244 flurry->drag = (float) pow(0.9965,flurry->fDeltaTime*85.0);
246 UpdateStar(global, flurry, flurry->star);
249 glShadeModel(GL_SMOOTH);
251 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
254 for (i=0;i<flurry->numStreams;i++) {
255 flurry->spark[i]->color[0]=1.0;
256 flurry->spark[i]->color[1]=1.0;
257 flurry->spark[i]->color[2]=1.0;
258 flurry->spark[i]->color[2]=1.0;
259 UpdateSpark(global, flurry, flurry->spark[i]);
261 DrawSpark(global, flurry, flurry->spark[i]);
265 switch(global->optMode) {
266 case OPT_MODE_SCALAR_BASE:
267 UpdateSmoke_ScalarBase(global, flurry, flurry->s);
271 case OPT_MODE_SCALAR_FRSQRTE:
272 UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
276 case OPT_MODE_VECTOR_SIMPLE:
277 UpdateSmoke_VectorBase(global, flurry, flurry->s);
279 case OPT_MODE_VECTOR_UNROLLED:
280 UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
289 /* glDisable(GL_BLEND); */
291 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
292 glEnable(GL_TEXTURE_2D);
294 switch(global->optMode) {
295 case OPT_MODE_SCALAR_BASE:
298 case OPT_MODE_SCALAR_FRSQRTE:
301 DrawSmoke_Scalar(global, flurry, flurry->s, b);
305 case OPT_MODE_VECTOR_SIMPLE:
306 case OPT_MODE_VECTOR_UNROLLED:
307 DrawSmoke_Vector(global, flurry, flurry->s, b);
315 glDisable(GL_TEXTURE_2D);
318 void GLResize(global_info_t *global, float w, float h)
320 global->sys_glWidth = w;
321 global->sys_glHeight = h;
324 /* new window size or exposure */
325 void reshape_flurry(ModeInfo *mi, int width, int height)
327 global_info_t *global = flurry_info + MI_SCREEN(mi);
329 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
331 glViewport(0.0, 0.0, width, height);
332 glMatrixMode(GL_PROJECTION);
334 gluOrtho2D(0, width, 0, height);
335 glMatrixMode(GL_MODELVIEW);
337 glClearColor(0.0, 0.0, 0.0, 1.0);
338 glClear(GL_COLOR_BUFFER_BIT);
342 GLResize(global, (float)width, (float)height);
346 init_flurry(ModeInfo * mi)
348 int screen = MI_SCREEN(mi);
350 global_info_t *global;
362 if (flurry_info == NULL) {
364 if ((flurry_info = (global_info_t *) calloc(MI_NUM_SCREENS(mi),
365 sizeof (global_info_t))) == NULL)
369 global = &flurry_info[screen];
371 global->window = MI_WINDOW(mi);
373 global->flurry = NULL;
375 if (!preset_str || !*preset_str) preset_str = DEF_PRESET;
376 if (!strcmp(preset_str, "random")) {
377 preset_num = random() % PRESET_MAX;
378 } else if (!strcmp(preset_str, "water")) {
379 preset_num = PRESET_WATER;
380 } else if (!strcmp(preset_str, "fire")) {
381 preset_num = PRESET_FIRE;
382 } else if (!strcmp(preset_str, "psychedelic")) {
383 preset_num = PRESET_PSYCHEDELIC;
384 } else if (!strcmp(preset_str, "rgb")) {
385 preset_num = PRESET_RGB;
386 } else if (!strcmp(preset_str, "binary")) {
387 preset_num = PRESET_BINARY;
388 } else if (!strcmp(preset_str, "classic")) {
389 preset_num = PRESET_CLASSIC;
390 } else if (!strcmp(preset_str, "insane")) {
391 preset_num = PRESET_INSANE;
393 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
397 switch (preset_num) {
399 for (i = 0; i < 9; i++) {
400 flurry_info_t *flurry;
402 flurry = new_flurry_info(global, 1, blueColorMode, 100.0, 2.0, 2.0);
403 flurry->next = global->flurry;
404 global->flurry = flurry;
409 flurry_info_t *flurry;
411 flurry = new_flurry_info(global, 12, slowCyclicColorMode, 10000.0, 0.0, 1.0);
412 flurry->next = global->flurry;
413 global->flurry = flurry;
416 case PRESET_PSYCHEDELIC: {
417 flurry_info_t *flurry;
419 flurry = new_flurry_info(global, 10, rainbowColorMode, 200.0, 2.0, 1.0);
420 flurry->next = global->flurry;
421 global->flurry = flurry;
425 flurry_info_t *flurry;
427 flurry = new_flurry_info(global, 3, redColorMode, 100.0, 0.8, 1.0);
428 flurry->next = global->flurry;
429 global->flurry = flurry;
431 flurry = new_flurry_info(global, 3, greenColorMode, 100.0, 0.8, 1.0);
432 flurry->next = global->flurry;
433 global->flurry = flurry;
435 flurry = new_flurry_info(global, 3, blueColorMode, 100.0, 0.8, 1.0);
436 flurry->next = global->flurry;
437 global->flurry = flurry;
440 case PRESET_BINARY: {
441 flurry_info_t *flurry;
443 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 0.5, 1.0);
444 flurry->next = global->flurry;
445 global->flurry = flurry;
447 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 1.5, 1.0);
448 flurry->next = global->flurry;
449 global->flurry = flurry;
452 case PRESET_CLASSIC: {
453 flurry_info_t *flurry;
455 flurry = new_flurry_info(global, 5, tiedyeColorMode, 10000.0, 1.0, 1.0);
456 flurry->next = global->flurry;
457 global->flurry = flurry;
460 case PRESET_INSANE: {
461 flurry_info_t *flurry;
463 flurry = new_flurry_info(global, 64, tiedyeColorMode, 1000.0, 0.5, 0.5);
464 flurry->next = global->flurry;
465 global->flurry = flurry;
470 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
475 if ((global->glx_context = init_GL(mi)) != NULL) {
476 reshape_flurry(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
484 draw_flurry(ModeInfo * mi)
486 static int first = 1;
487 static double oldFrameTime = -1;
489 double deltaFrameTime = 0;
493 global_info_t *global = flurry_info + MI_SCREEN(mi);
494 flurry_info_t *flurry;
495 Display *display = MI_DISPLAY(mi);
496 Window window = MI_WINDOW(mi);
498 newFrameTime = currentTime();
499 if (oldFrameTime == -1) {
500 /* special case the first frame -- clear to black */
504 * this clamps the speed at below 60fps and, here
505 * at least, produces a reasonably accurate 50fps.
506 * (probably part CPU speed and part scheduler).
508 * Flurry is designed to run at this speed; much higher
509 * than that and the blending causes the display to
510 * saturate, which looks really ugly.
512 if (newFrameTime - oldFrameTime < 1/60.0) {
513 usleep(MAX_(1,(int)(20000 * (newFrameTime - oldFrameTime))));
517 deltaFrameTime = newFrameTime - oldFrameTime;
518 alpha = 5.0 * deltaFrameTime;
520 oldFrameTime = newFrameTime;
522 if (alpha > 0.2) alpha = 0.2;
524 if (!global->glx_context)
531 glDrawBuffer(GL_BACK);
532 glXMakeCurrent(display, window, *(global->glx_context));
535 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
537 glColor4f(0.0, 0.0, 0.0, alpha);
538 glRectd(0, 0, global->sys_glWidth, global->sys_glHeight);
540 brite = pow(deltaFrameTime,0.75) * 10;
541 for (flurry = global->flurry; flurry; flurry=flurry->next) {
542 GLRenderScene(global, flurry, brite * flurry->briteFactor);
545 if (mi->fps_p) do_fps (mi);
548 glXSwapBuffers(display, window);
552 release_flurry(ModeInfo * mi)
554 if (flurry_info != NULL) {
557 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
558 global_info_t *global = &flurry_info[screen];
559 flurry_info_t *flurry;
561 if (global->glx_context) {
562 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
565 for (flurry = global->flurry; flurry; flurry=flurry->next) {
566 delete_flurry_info(flurry);
569 (void) free((void *) flurry_info);