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 HACK_HANDLE_EVENT flurry_handle_event
60 # define EVENT_MASK PointerMotionMask
61 # define flurry_opts xlockmore_opts
62 # define DEFAULTS "*showFPS: False \n" \
63 "*preset: " DEF_PRESET " \n"
65 # include "xlockmore.h" /* from the xscreensaver distribution */
70 #include "gltrackball.h"
72 static char *preset_str;
74 static XrmOptionDescRec opts[] = {
75 { "-preset", ".preset", XrmoptionSepArg, 0 }
78 static argtype vars[] = {
79 {(caddr_t *) &preset_str, "preset", "Preset", DEF_PRESET, t_String},
82 #define countof(x) (sizeof((x))/sizeof((*x)))
84 ModeSpecOpt flurry_opts = {countof(opts), opts, countof(vars), vars, NULL};
87 ModStruct flurry_description = {
96 1000, 1, 2, 1, 4, 1.0,
105 #include <sys/time.h>
106 #include <sys/sysctl.h>
110 global_info_t *flurry_info = NULL;
112 static double gTimeCounter = 0.0;
114 double currentTime(void) {
117 gettimeofday(&tv, NULL);
119 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
122 void OTSetup (void) {
123 if (gTimeCounter == 0.0) {
124 gTimeCounter = currentTime();
128 double TimeInSecondsSinceStart (void) {
129 return currentTime() - gTimeCounter;
133 static int IsAltiVecAvailable(void)
139 void delete_flurry_info(flurry_info_t *flurry)
145 for (i=0;i<MAX_SPARKS;i++)
147 free(flurry->spark[i]);
152 flurry_info_t *new_flurry_info(global_info_t *global, int streams, ColorModes colour, float thickness, float speed, double bf)
155 flurry_info_t *flurry = (flurry_info_t *)malloc(sizeof(flurry_info_t));
157 if (!flurry) return NULL;
159 flurry->flurryRandomSeed = RandFlt(0.0, 300.0);
161 flurry->fOldTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
163 flurry->numStreams = streams;
164 flurry->streamExpansion = thickness;
165 flurry->currentColorMode = colour;
166 flurry->briteFactor = bf;
168 flurry->s = malloc(sizeof(SmokeV));
169 InitSmoke(flurry->s);
171 flurry->star = malloc(sizeof(Star));
172 InitStar(flurry->star);
173 flurry->star->rotSpeed = speed;
175 for (i = 0;i < MAX_SPARKS; i++)
177 flurry->spark[i] = malloc(sizeof(Spark));
178 InitSpark(flurry->spark[i]);
179 flurry->spark[i]->mystery = 1800 * (i + 1) / 13; /* 100 * (i + 1) / (flurry->numStreams + 1); */
180 UpdateSpark(global, flurry, flurry->spark[i]);
183 for (i=0;i<NUMSMOKEPARTICLES/4;i++) {
185 flurry->s->p[i].dead.i[k] = 1;
194 void GLSetupRC(global_info_t *global)
196 /* setup the defaults for OpenGL */
197 glDisable(GL_DEPTH_TEST);
198 glAlphaFunc(GL_GREATER,0.0f);
199 glEnable(GL_ALPHA_TEST);
200 glShadeModel(GL_FLAT);
201 glDisable(GL_LIGHTING);
202 glDisable(GL_CULL_FACE);
205 glViewport(0,0,(int) global->sys_glWidth,(int) global->sys_glHeight);
206 glMatrixMode(GL_PROJECTION);
208 gluOrtho2D(0,global->sys_glWidth,0,global->sys_glHeight);
209 glMatrixMode(GL_MODELVIEW);
212 glClearColor(0.0,0.0,0.0,1.0);
213 glClear(GL_COLOR_BUFFER_BIT);
215 glEnableClientState(GL_COLOR_ARRAY);
216 glEnableClientState(GL_VERTEX_ARRAY);
217 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
220 global->optMode = OPT_MODE_SCALAR_FRSQRTE;
223 if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
227 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);
267 case OPT_MODE_SCALAR_FRSQRTE:
268 UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
272 case OPT_MODE_VECTOR_SIMPLE:
273 UpdateSmoke_VectorBase(global, flurry, flurry->s);
275 case OPT_MODE_VECTOR_UNROLLED:
276 UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
283 /* glDisable(GL_BLEND); */
285 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
286 glEnable(GL_TEXTURE_2D);
288 switch(global->optMode) {
289 case OPT_MODE_SCALAR_BASE:
291 case OPT_MODE_SCALAR_FRSQRTE:
293 DrawSmoke_Scalar(global, flurry, flurry->s, b);
296 case OPT_MODE_VECTOR_SIMPLE:
297 case OPT_MODE_VECTOR_UNROLLED:
298 DrawSmoke_Vector(global, flurry, flurry->s, b);
305 glDisable(GL_TEXTURE_2D);
308 void GLResize(global_info_t *global, float w, float h)
310 global->sys_glWidth = w;
311 global->sys_glHeight = h;
314 /* new window size or exposure */
315 void reshape_flurry(ModeInfo *mi, int width, int height)
317 global_info_t *global = flurry_info + MI_SCREEN(mi);
319 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
321 glViewport(0.0, 0.0, width, height);
322 glMatrixMode(GL_PROJECTION);
324 gluOrtho2D(0, width, 0, height);
325 glMatrixMode(GL_MODELVIEW);
327 glClearColor(0.0, 0.0, 0.0, 1.0);
328 glClear(GL_COLOR_BUFFER_BIT);
332 GLResize(global, (float)width, (float)height);
336 flurry_handle_event (ModeInfo *mi, XEvent *event)
338 global_info_t *global = flurry_info + MI_SCREEN(mi);
340 if (event->xany.type == ButtonPress && event->xbutton.button & Button1) {
341 global->button_down_p = True;
342 gltrackball_start (global->trackball,
343 event->xbutton.x, event->xbutton.y,
344 MI_WIDTH (mi), MI_HEIGHT (mi));
347 else if (event->xany.type == ButtonRelease && event->xbutton.button & Button1) {
348 global->button_down_p = False;
351 else if (event->xany.type == MotionNotify && global->button_down_p) {
352 gltrackball_track (global->trackball,
353 event->xmotion.x, event->xmotion.y,
354 MI_WIDTH (mi), MI_HEIGHT (mi));
362 init_flurry(ModeInfo * mi)
364 int screen = MI_SCREEN(mi);
366 global_info_t *global;
378 if (flurry_info == NULL) {
380 if ((flurry_info = (global_info_t *) calloc(MI_NUM_SCREENS(mi),
381 sizeof (global_info_t))) == NULL)
385 global = &flurry_info[screen];
387 global->window = MI_WINDOW(mi);
389 global->rot = make_rotator(1, 1, 1, 1, 0, True);
390 global->trackball = gltrackball_init();
392 global->flurry = NULL;
394 if (!preset_str || !*preset_str) preset_str = DEF_PRESET;
395 if (!strcmp(preset_str, "random")) {
396 preset_num = random() % PRESET_MAX;
397 } else if (!strcmp(preset_str, "water")) {
398 preset_num = PRESET_WATER;
399 } else if (!strcmp(preset_str, "fire")) {
400 preset_num = PRESET_FIRE;
401 } else if (!strcmp(preset_str, "psychedelic")) {
402 preset_num = PRESET_PSYCHEDELIC;
403 } else if (!strcmp(preset_str, "rgb")) {
404 preset_num = PRESET_RGB;
405 } else if (!strcmp(preset_str, "binary")) {
406 preset_num = PRESET_BINARY;
407 } else if (!strcmp(preset_str, "classic")) {
408 preset_num = PRESET_CLASSIC;
409 } else if (!strcmp(preset_str, "insane")) {
410 preset_num = PRESET_INSANE;
412 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
416 switch (preset_num) {
418 for (i = 0; i < 9; i++) {
419 flurry_info_t *flurry;
421 flurry = new_flurry_info(global, 1, blueColorMode, 100.0, 2.0, 2.0);
422 flurry->next = global->flurry;
423 global->flurry = flurry;
428 flurry_info_t *flurry;
430 flurry = new_flurry_info(global, 12, slowCyclicColorMode, 10000.0, 0.0, 1.0);
431 flurry->next = global->flurry;
432 global->flurry = flurry;
435 case PRESET_PSYCHEDELIC: {
436 flurry_info_t *flurry;
438 flurry = new_flurry_info(global, 10, rainbowColorMode, 200.0, 2.0, 1.0);
439 flurry->next = global->flurry;
440 global->flurry = flurry;
444 flurry_info_t *flurry;
446 flurry = new_flurry_info(global, 3, redColorMode, 100.0, 0.8, 1.0);
447 flurry->next = global->flurry;
448 global->flurry = flurry;
450 flurry = new_flurry_info(global, 3, greenColorMode, 100.0, 0.8, 1.0);
451 flurry->next = global->flurry;
452 global->flurry = flurry;
454 flurry = new_flurry_info(global, 3, blueColorMode, 100.0, 0.8, 1.0);
455 flurry->next = global->flurry;
456 global->flurry = flurry;
459 case PRESET_BINARY: {
460 flurry_info_t *flurry;
462 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 0.5, 1.0);
463 flurry->next = global->flurry;
464 global->flurry = flurry;
466 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 1.5, 1.0);
467 flurry->next = global->flurry;
468 global->flurry = flurry;
471 case PRESET_CLASSIC: {
472 flurry_info_t *flurry;
474 flurry = new_flurry_info(global, 5, tiedyeColorMode, 10000.0, 1.0, 1.0);
475 flurry->next = global->flurry;
476 global->flurry = flurry;
479 case PRESET_INSANE: {
480 flurry_info_t *flurry;
482 flurry = new_flurry_info(global, 64, tiedyeColorMode, 1000.0, 0.5, 0.5);
483 flurry->next = global->flurry;
484 global->flurry = flurry;
489 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
494 if ((global->glx_context = init_GL(mi)) != NULL) {
495 reshape_flurry(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
503 draw_flurry(ModeInfo * mi)
505 static int first = 1;
506 static double oldFrameTime = -1;
508 double deltaFrameTime = 0;
512 global_info_t *global = flurry_info + MI_SCREEN(mi);
513 flurry_info_t *flurry;
514 Display *display = MI_DISPLAY(mi);
515 Window window = MI_WINDOW(mi);
517 newFrameTime = currentTime();
518 if (oldFrameTime == -1) {
519 /* special case the first frame -- clear to black */
523 * this clamps the speed at below 60fps and, here
524 * at least, produces a reasonably accurate 50fps.
525 * (probably part CPU speed and part scheduler).
527 * Flurry is designed to run at this speed; much higher
528 * than that and the blending causes the display to
529 * saturate, which looks really ugly.
531 if (newFrameTime - oldFrameTime < 1/60.0) {
532 usleep(MAX_(1,(int)(20000 * (newFrameTime - oldFrameTime))));
536 deltaFrameTime = newFrameTime - oldFrameTime;
537 alpha = 5.0 * deltaFrameTime;
539 oldFrameTime = newFrameTime;
541 if (alpha > 0.2) alpha = 0.2;
543 if (!global->glx_context)
550 glDrawBuffer(GL_BACK);
551 glXMakeCurrent(display, window, *(global->glx_context));
554 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
556 glColor4f(0.0, 0.0, 0.0, alpha);
557 glRectd(0, 0, global->sys_glWidth, global->sys_glHeight);
559 brite = pow(deltaFrameTime,0.75) * 10;
560 for (flurry = global->flurry; flurry; flurry=flurry->next) {
561 GLRenderScene(global, flurry, brite * flurry->briteFactor);
564 if (mi->fps_p) do_fps (mi);
567 glXSwapBuffers(display, window);
571 release_flurry(ModeInfo * mi)
573 if (flurry_info != NULL) {
576 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
577 global_info_t *global = &flurry_info[screen];
578 flurry_info_t *flurry;
580 if (global->glx_context) {
581 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
584 for (flurry = global->flurry; flurry; flurry=flurry->next) {
585 delete_flurry_info(flurry);
588 (void) free((void *) flurry_info);