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.
40 #if !defined( lint ) && !defined( SABER )
41 static const char sccsid[] = "@(#)flurry.c 4.07 97/11/24 xlockmore";
46 * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
47 * otherwise caddr_t is not defined correctly
50 #define DEF_PRESET "classic"
51 #define DEF_BRIGHTNESS "8"
53 #include <X11/Intrinsic.h>
55 # define PROGCLASS "Flurry"
56 # define HACK_INIT init_flurry
57 # define HACK_DRAW draw_flurry
58 # define HACK_RESHAPE reshape_flurry
59 # define flurry_opts xlockmore_opts
60 # define DEFAULTS "*showFPS: False \n" \
61 "*preset: " DEF_PRESET " \n"
63 # include "xlockmore.h" /* from the xscreensaver distribution */
67 static char *preset_str;
69 static XrmOptionDescRec opts[] = {
70 { "-preset", ".preset", XrmoptionSepArg, 0 }
73 static argtype vars[] = {
74 {(caddr_t *) &preset_str, "preset", "Preset", DEF_PRESET, t_String},
77 #define countof(x) (sizeof((x))/sizeof((*x)))
79 ModeSpecOpt flurry_opts = {countof(opts), opts, countof(vars), vars, NULL};
82 ModStruct flurry_description = {
91 1000, 1, 2, 1, 4, 1.0,
100 #include <sys/time.h>
104 global_info_t *flurry_info = NULL;
106 static double gTimeCounter = 0.0;
108 double currentTime(void) {
111 gettimeofday(&tv, NULL);
113 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
116 void OTSetup (void) {
117 if (gTimeCounter == 0.0) {
118 gTimeCounter = currentTime();
122 double TimeInSecondsSinceStart (void) {
123 return currentTime() - gTimeCounter;
128 static int IsAltiVecAvailable(void)
135 void delete_flurry_info(flurry_info_t *flurry)
141 for (i=0;i<MAX_SPARKS;i++)
143 free(flurry->spark[i]);
148 flurry_info_t *new_flurry_info(global_info_t *global, int streams, ColorModes colour, float thickness, float speed, double bf)
151 flurry_info_t *flurry = (flurry_info_t *)malloc(sizeof(flurry_info_t));
153 if (!flurry) return NULL;
155 flurry->flurryRandomSeed = RandFlt(0.0, 300.0);
157 flurry->fOldTime = 0;
158 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
159 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
161 flurry->numStreams = streams;
162 flurry->streamExpansion = thickness;
163 flurry->currentColorMode = colour;
164 flurry->briteFactor = bf;
166 flurry->s = malloc(sizeof(SmokeV));
167 InitSmoke(flurry->s);
169 flurry->star = malloc(sizeof(Star));
170 InitStar(flurry->star);
171 flurry->star->rotSpeed = speed;
173 for (i = 0;i < MAX_SPARKS; i++)
175 flurry->spark[i] = malloc(sizeof(Spark));
176 InitSpark(flurry->spark[i]);
177 flurry->spark[i]->mystery = 1800 * (i + 1) / 13; /* 100 * (i + 1) / (flurry->numStreams + 1); */
178 UpdateSpark(global, flurry, flurry->spark[i]);
181 for (i=0;i<NUMSMOKEPARTICLES/4;i++) {
183 flurry->s->p[i].dead.i[k] = 1;
192 void GLSetupRC(global_info_t *global)
194 /* setup the defaults for OpenGL */
195 glDisable(GL_DEPTH_TEST);
196 glAlphaFunc(GL_GREATER,0.0f);
197 glEnable(GL_ALPHA_TEST);
198 glShadeModel(GL_FLAT);
199 glDisable(GL_LIGHTING);
200 glDisable(GL_CULL_FACE);
203 glViewport(0,0,(int) global->sys_glWidth,(int) global->sys_glHeight);
204 glMatrixMode(GL_PROJECTION);
206 gluOrtho2D(0,global->sys_glWidth,0,global->sys_glHeight);
207 glMatrixMode(GL_MODELVIEW);
210 glClearColor(0.0,0.0,0.0,1.0);
211 glClear(GL_COLOR_BUFFER_BIT);
213 glEnableClientState(GL_COLOR_ARRAY);
214 glEnableClientState(GL_VERTEX_ARRAY);
215 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
219 global->optMode = OPT_MODE_SCALAR_FRSQRTE;
222 if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
226 global->optMode = OPT_MODE_SCALAR_BASE;
231 void GLRenderScene(global_info_t *global, flurry_info_t *flurry, double b)
237 flurry->fOldTime = flurry->fTime;
238 flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
239 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
241 flurry->drag = (float) pow(0.9965,flurry->fDeltaTime*85.0);
243 UpdateStar(global, flurry, flurry->star);
246 glShadeModel(GL_SMOOTH);
248 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
251 for (i=0;i<flurry->numStreams;i++) {
252 flurry->spark[i]->color[0]=1.0;
253 flurry->spark[i]->color[1]=1.0;
254 flurry->spark[i]->color[2]=1.0;
255 flurry->spark[i]->color[2]=1.0;
256 UpdateSpark(global, flurry, flurry->spark[i]);
258 DrawSpark(global, flurry, flurry->spark[i]);
262 switch(global->optMode) {
263 case OPT_MODE_SCALAR_BASE:
264 UpdateSmoke_ScalarBase(global, flurry, flurry->s);
268 case OPT_MODE_SCALAR_FRSQRTE:
269 UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
273 case OPT_MODE_VECTOR_SIMPLE:
274 UpdateSmoke_VectorBase(global, flurry, flurry->s);
276 case OPT_MODE_VECTOR_UNROLLED:
277 UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
286 /* glDisable(GL_BLEND); */
288 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
289 glEnable(GL_TEXTURE_2D);
291 switch(global->optMode) {
292 case OPT_MODE_SCALAR_BASE:
295 case OPT_MODE_SCALAR_FRSQRTE:
298 DrawSmoke_Scalar(global, flurry, flurry->s, b);
302 case OPT_MODE_VECTOR_SIMPLE:
303 case OPT_MODE_VECTOR_UNROLLED:
304 DrawSmoke_Vector(global, flurry, flurry->s, b);
312 glDisable(GL_TEXTURE_2D);
315 void GLResize(global_info_t *global, float w, float h)
317 global->sys_glWidth = w;
318 global->sys_glHeight = h;
321 /* new window size or exposure */
322 void reshape_flurry(ModeInfo *mi, int width, int height)
324 global_info_t *global = flurry_info + MI_SCREEN(mi);
326 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
328 glViewport(0.0, 0.0, width, height);
329 glMatrixMode(GL_PROJECTION);
331 gluOrtho2D(0, width, 0, height);
332 glMatrixMode(GL_MODELVIEW);
334 glClearColor(0.0, 0.0, 0.0, 1.0);
335 glClear(GL_COLOR_BUFFER_BIT);
339 GLResize(global, (float)width, (float)height);
343 init_flurry(ModeInfo * mi)
345 int screen = MI_SCREEN(mi);
347 global_info_t *global;
359 if (flurry_info == NULL) {
361 if ((flurry_info = (global_info_t *) calloc(MI_NUM_SCREENS(mi),
362 sizeof (global_info_t))) == NULL)
366 global = &flurry_info[screen];
368 global->window = MI_WINDOW(mi);
370 global->flurry = NULL;
372 if (!preset_str || !*preset_str) preset_str = DEF_PRESET;
373 if (!strcmp(preset_str, "random")) {
374 preset_num = random() % PRESET_MAX;
375 } else if (!strcmp(preset_str, "water")) {
376 preset_num = PRESET_WATER;
377 } else if (!strcmp(preset_str, "fire")) {
378 preset_num = PRESET_FIRE;
379 } else if (!strcmp(preset_str, "psychedelic")) {
380 preset_num = PRESET_PSYCHEDELIC;
381 } else if (!strcmp(preset_str, "rgb")) {
382 preset_num = PRESET_RGB;
383 } else if (!strcmp(preset_str, "binary")) {
384 preset_num = PRESET_BINARY;
385 } else if (!strcmp(preset_str, "classic")) {
386 preset_num = PRESET_CLASSIC;
387 } else if (!strcmp(preset_str, "insane")) {
388 preset_num = PRESET_INSANE;
390 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
394 switch (preset_num) {
396 for (i = 0; i < 9; i++) {
397 flurry_info_t *flurry;
399 flurry = new_flurry_info(global, 1, blueColorMode, 100.0, 2.0, 2.0);
400 flurry->next = global->flurry;
401 global->flurry = flurry;
406 flurry_info_t *flurry;
408 flurry = new_flurry_info(global, 12, slowCyclicColorMode, 10000.0, 0.0, 1.0);
409 flurry->next = global->flurry;
410 global->flurry = flurry;
413 case PRESET_PSYCHEDELIC: {
414 flurry_info_t *flurry;
416 flurry = new_flurry_info(global, 10, rainbowColorMode, 200.0, 2.0, 1.0);
417 flurry->next = global->flurry;
418 global->flurry = flurry;
422 flurry_info_t *flurry;
424 flurry = new_flurry_info(global, 3, redColorMode, 100.0, 0.8, 1.0);
425 flurry->next = global->flurry;
426 global->flurry = flurry;
428 flurry = new_flurry_info(global, 3, greenColorMode, 100.0, 0.8, 1.0);
429 flurry->next = global->flurry;
430 global->flurry = flurry;
432 flurry = new_flurry_info(global, 3, blueColorMode, 100.0, 0.8, 1.0);
433 flurry->next = global->flurry;
434 global->flurry = flurry;
437 case PRESET_BINARY: {
438 flurry_info_t *flurry;
440 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 0.5, 1.0);
441 flurry->next = global->flurry;
442 global->flurry = flurry;
444 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 1.5, 1.0);
445 flurry->next = global->flurry;
446 global->flurry = flurry;
449 case PRESET_CLASSIC: {
450 flurry_info_t *flurry;
452 flurry = new_flurry_info(global, 5, tiedyeColorMode, 10000.0, 1.0, 1.0);
453 flurry->next = global->flurry;
454 global->flurry = flurry;
457 case PRESET_INSANE: {
458 flurry_info_t *flurry;
460 flurry = new_flurry_info(global, 64, tiedyeColorMode, 1000.0, 0.5, 0.5);
461 flurry->next = global->flurry;
462 global->flurry = flurry;
467 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
472 if ((global->glx_context = init_GL(mi)) != NULL) {
473 reshape_flurry(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
481 draw_flurry(ModeInfo * mi)
483 static int first = 1;
484 static double oldFrameTime = -1;
486 double deltaFrameTime = 0;
490 global_info_t *global = flurry_info + MI_SCREEN(mi);
491 flurry_info_t *flurry;
492 Display *display = MI_DISPLAY(mi);
493 Window window = MI_WINDOW(mi);
495 newFrameTime = currentTime();
496 if (oldFrameTime == -1) {
497 /* special case the first frame -- clear to black */
501 * this clamps the speed at below 60fps and, here
502 * at least, produces a reasonably accurate 50fps.
503 * (probably part CPU speed and part scheduler).
505 * Flurry is designed to run at this speed; much higher
506 * than that and the blending causes the display to
507 * saturate, which looks really ugly.
509 if (newFrameTime - oldFrameTime < 1/60.0) {
510 usleep(MAX_(1,(int)(20000 * (newFrameTime - oldFrameTime))));
514 deltaFrameTime = newFrameTime - oldFrameTime;
515 alpha = 5.0 * deltaFrameTime;
517 oldFrameTime = newFrameTime;
519 if (alpha > 0.2) alpha = 0.2;
521 if (!global->glx_context)
528 glDrawBuffer(GL_BACK);
529 glXMakeCurrent(display, window, *(global->glx_context));
532 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
534 glColor4f(0.0, 0.0, 0.0, alpha);
535 glRectd(0, 0, global->sys_glWidth, global->sys_glHeight);
537 brite = pow(deltaFrameTime,0.75) * 10;
538 for (flurry = global->flurry; flurry; flurry=flurry->next) {
539 GLRenderScene(global, flurry, brite * flurry->briteFactor);
542 if (mi->fps_p) do_fps (mi);
545 glXSwapBuffers(display, window);
549 release_flurry(ModeInfo * mi)
551 if (flurry_info != NULL) {
554 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
555 global_info_t *global = &flurry_info[screen];
556 flurry_info_t *flurry;
558 if (global->glx_context) {
559 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
562 for (flurry = global->flurry; flurry; flurry=flurry->next) {
563 delete_flurry_info(flurry);
566 (void) free((void *) flurry_info);