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 release_flurry 0
51 # define flurry_handle_event xlockmore_no_events
52 # include "xlockmore.h" /* from the xscreensaver distribution */
56 static char *preset_str;
58 static XrmOptionDescRec opts[] = {
59 { "-preset", ".preset", XrmoptionSepArg, 0 }
62 static argtype vars[] = {
63 {&preset_str, "preset", "Preset", DEF_PRESET, t_String},
66 #define countof(x) (sizeof((x))/sizeof((*x)))
68 ENTRYPOINT ModeSpecOpt flurry_opts = {countof(opts), opts, countof(vars), vars, NULL};
71 ModStruct flurry_description = {
80 1000, 1, 2, 1, 4, 1.0,
91 global_info_t *flurry_info = NULL;
94 double currentTime(void) {
96 # ifdef GETTIMEOFDAY_TWO_ARGS
98 gettimeofday(&tv, &tzp);
103 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
106 double TimeInSecondsSinceStart (const global_info_t *global) {
107 return currentTime() - global->gTimeCounter;
112 static int IsAltiVecAvailable(void)
121 void delete_flurry_info(flurry_info_t *flurry)
127 for (i=0;i<MAX_SPARKS;i++)
129 free(flurry->spark[i]);
135 flurry_info_t *new_flurry_info(global_info_t *global, int streams, ColorModes colour, float thickness, float speed, double bf)
138 flurry_info_t *flurry = (flurry_info_t *)malloc(sizeof(flurry_info_t));
140 if (!flurry) return NULL;
142 flurry->flurryRandomSeed = RandFlt(0.0, 300.0);
144 flurry->fOldTime = 0;
146 flurry->fTime = TimeInSecondsSinceStart(global) + flurry->flurryRandomSeed;
147 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
149 flurry->numStreams = streams;
150 flurry->streamExpansion = thickness;
151 flurry->currentColorMode = colour;
152 flurry->briteFactor = bf;
154 flurry->s = malloc(sizeof(SmokeV));
155 InitSmoke(flurry->s);
157 flurry->star = malloc(sizeof(Star));
158 InitStar(flurry->star);
159 flurry->star->rotSpeed = speed;
161 for (i = 0;i < MAX_SPARKS; i++)
163 flurry->spark[i] = malloc(sizeof(Spark));
164 InitSpark(flurry->spark[i]);
165 flurry->spark[i]->mystery = 1800 * (i + 1) / 13; /* 100 * (i + 1) / (flurry->numStreams + 1); */
166 UpdateSpark(global, flurry, flurry->spark[i]);
169 for (i=0;i<NUMSMOKEPARTICLES/4;i++) {
171 flurry->s->p[i].dead.i[k] = 1;
181 void GLSetupRC(global_info_t *global)
183 /* setup the defaults for OpenGL */
184 glDisable(GL_DEPTH_TEST);
185 glAlphaFunc(GL_GREATER,0.0f);
186 glEnable(GL_ALPHA_TEST);
187 glShadeModel(GL_FLAT);
188 glDisable(GL_LIGHTING);
189 glDisable(GL_CULL_FACE);
192 glViewport(0,0,(int) global->sys_glWidth,(int) global->sys_glHeight);
193 glMatrixMode(GL_PROJECTION);
195 glOrtho(0,global->sys_glWidth,0,global->sys_glHeight,-1,1);
196 glMatrixMode(GL_MODELVIEW);
199 glClear(GL_COLOR_BUFFER_BIT);
201 glEnableClientState(GL_COLOR_ARRAY);
202 glEnableClientState(GL_VERTEX_ARRAY);
203 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
207 global->optMode = OPT_MODE_SCALAR_FRSQRTE;
210 if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
214 global->optMode = OPT_MODE_SCALAR_BASE;
220 void GLRenderScene(global_info_t *global, flurry_info_t *flurry, double b)
226 flurry->fOldTime = flurry->fTime;
227 flurry->fTime = TimeInSecondsSinceStart(global) + flurry->flurryRandomSeed;
228 flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
230 flurry->drag = (float) pow(0.9965,flurry->fDeltaTime*85.0);
232 UpdateStar(global, flurry, flurry->star);
235 glShadeModel(GL_SMOOTH);
237 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
240 for (i=0;i<flurry->numStreams;i++) {
241 flurry->spark[i]->color[0]=1.0;
242 flurry->spark[i]->color[1]=1.0;
243 flurry->spark[i]->color[2]=1.0;
244 flurry->spark[i]->color[2]=1.0;
245 UpdateSpark(global, flurry, flurry->spark[i]);
247 DrawSpark(global, flurry, flurry->spark[i]);
251 switch(global->optMode) {
252 case OPT_MODE_SCALAR_BASE:
253 UpdateSmoke_ScalarBase(global, flurry, flurry->s);
257 case OPT_MODE_SCALAR_FRSQRTE:
258 UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
262 case OPT_MODE_VECTOR_SIMPLE:
263 UpdateSmoke_VectorBase(global, flurry, flurry->s);
265 case OPT_MODE_VECTOR_UNROLLED:
266 UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
275 /* glDisable(GL_BLEND); */
277 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
278 glEnable(GL_TEXTURE_2D);
280 switch(global->optMode) {
281 case OPT_MODE_SCALAR_BASE:
284 case OPT_MODE_SCALAR_FRSQRTE:
287 DrawSmoke_Scalar(global, flurry, flurry->s, b);
291 case OPT_MODE_VECTOR_SIMPLE:
292 case OPT_MODE_VECTOR_UNROLLED:
293 DrawSmoke_Vector(global, flurry, flurry->s, b);
301 glDisable(GL_TEXTURE_2D);
305 void GLResize(global_info_t *global, float w, float h)
307 global->sys_glWidth = w;
308 global->sys_glHeight = h;
311 /* new window size or exposure */
312 ENTRYPOINT void reshape_flurry(ModeInfo *mi, int width, int height)
314 global_info_t *global = flurry_info + MI_SCREEN(mi);
316 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
318 glViewport(0.0, 0.0, width, height);
319 glMatrixMode(GL_PROJECTION);
321 glOrtho(0, width, 0, height,-1,1);
322 glMatrixMode(GL_MODELVIEW);
323 glClear(GL_COLOR_BUFFER_BIT);
325 GLResize(global, (float)width, (float)height);
329 init_flurry(ModeInfo * mi)
331 int screen = MI_SCREEN(mi);
333 global_info_t *global;
345 MI_INIT (mi, flurry_info);
347 global = &flurry_info[screen];
349 global->gTimeCounter = currentTime();
351 global->window = MI_WINDOW(mi);
353 global->flurry = NULL;
355 if (!preset_str || !*preset_str) preset_str = DEF_PRESET;
356 if (!strcmp(preset_str, "random")) {
357 preset_num = random() % PRESET_MAX;
358 } else if (!strcmp(preset_str, "water")) {
359 preset_num = PRESET_WATER;
360 } else if (!strcmp(preset_str, "fire")) {
361 preset_num = PRESET_FIRE;
362 } else if (!strcmp(preset_str, "psychedelic")) {
363 preset_num = PRESET_PSYCHEDELIC;
364 } else if (!strcmp(preset_str, "rgb")) {
365 preset_num = PRESET_RGB;
366 } else if (!strcmp(preset_str, "binary")) {
367 preset_num = PRESET_BINARY;
368 } else if (!strcmp(preset_str, "classic")) {
369 preset_num = PRESET_CLASSIC;
370 } else if (!strcmp(preset_str, "insane")) {
371 preset_num = PRESET_INSANE;
373 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
377 switch (preset_num) {
379 for (i = 0; i < 9; i++) {
380 flurry_info_t *flurry;
382 flurry = new_flurry_info(global, 1, blueColorMode, 100.0, 2.0, 2.0);
383 flurry->next = global->flurry;
384 global->flurry = flurry;
389 flurry_info_t *flurry;
391 flurry = new_flurry_info(global, 12, slowCyclicColorMode, 10000.0, 0.2, 1.0);
392 flurry->next = global->flurry;
393 global->flurry = flurry;
396 case PRESET_PSYCHEDELIC: {
397 flurry_info_t *flurry;
399 flurry = new_flurry_info(global, 10, rainbowColorMode, 200.0, 2.0, 1.0);
400 flurry->next = global->flurry;
401 global->flurry = flurry;
405 flurry_info_t *flurry;
407 flurry = new_flurry_info(global, 3, redColorMode, 100.0, 0.8, 1.0);
408 flurry->next = global->flurry;
409 global->flurry = flurry;
411 flurry = new_flurry_info(global, 3, greenColorMode, 100.0, 0.8, 1.0);
412 flurry->next = global->flurry;
413 global->flurry = flurry;
415 flurry = new_flurry_info(global, 3, blueColorMode, 100.0, 0.8, 1.0);
416 flurry->next = global->flurry;
417 global->flurry = flurry;
420 case PRESET_BINARY: {
421 flurry_info_t *flurry;
423 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 0.5, 1.0);
424 flurry->next = global->flurry;
425 global->flurry = flurry;
427 flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 1.5, 1.0);
428 flurry->next = global->flurry;
429 global->flurry = flurry;
432 case PRESET_CLASSIC: {
433 flurry_info_t *flurry;
435 flurry = new_flurry_info(global, 5, tiedyeColorMode, 10000.0, 1.0, 1.0);
436 flurry->next = global->flurry;
437 global->flurry = flurry;
440 case PRESET_INSANE: {
441 flurry_info_t *flurry;
443 flurry = new_flurry_info(global, 64, tiedyeColorMode, 1000.0, 0.5, 0.5);
444 flurry->next = global->flurry;
445 global->flurry = flurry;
450 fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
455 if ((global->glx_context = init_GL(mi)) != NULL) {
456 reshape_flurry(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
463 global->oldFrameTime = -1;
467 draw_flurry(ModeInfo * mi)
470 double deltaFrameTime = 0;
474 global_info_t *global = flurry_info + MI_SCREEN(mi);
475 flurry_info_t *flurry;
476 Display *display = MI_DISPLAY(mi);
477 Window window = MI_WINDOW(mi);
479 newFrameTime = currentTime();
480 if (global->oldFrameTime == -1) {
481 /* special case the first frame -- clear to black */
485 * this clamps the speed at below 60fps and, here
486 * at least, produces a reasonably accurate 50fps.
487 * (probably part CPU speed and part scheduler).
489 * Flurry is designed to run at this speed; much higher
490 * than that and the blending causes the display to
491 * saturate, which looks really ugly.
493 if (newFrameTime - global->oldFrameTime < 1/60.0) {
494 usleep(MAX_(1,(int)(20000 * (newFrameTime - global->oldFrameTime))));
498 deltaFrameTime = newFrameTime - global->oldFrameTime;
499 alpha = 5.0 * deltaFrameTime;
501 global->oldFrameTime = newFrameTime;
503 if (alpha > 0.2) alpha = 0.2;
505 if (!global->glx_context)
512 glDrawBuffer(GL_BACK);
513 glXMakeCurrent(display, window, *(global->glx_context));
516 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
518 glColor4f(0.0, 0.0, 0.0, alpha);
519 glRectd(0, 0, global->sys_glWidth, global->sys_glHeight);
521 brite = pow(deltaFrameTime,0.75) * 10;
522 for (flurry = global->flurry; flurry; flurry=flurry->next) {
523 GLRenderScene(global, flurry, brite * flurry->briteFactor);
526 if (mi->fps_p) do_fps (mi);
529 glXSwapBuffers(display, window);
533 free_flurry(ModeInfo * mi)
535 global_info_t *global = &flurry_info[MI_SCREEN(mi)];
536 flurry_info_t *flurry;
538 if (global->glx_context) {
539 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
542 for (flurry = global->flurry; flurry; flurry=flurry->next) {
543 delete_flurry_info(flurry);
547 XSCREENSAVER_MODULE ("Flurry", flurry)