http://ftp.ussg.iu.edu/linux/slackware/slackware-9.0/source/xap/xscreensaver/xscreens...
[xscreensaver] / hacks / glx / flurry.c
1 /* -*- Mode: C; tab-width: 4 c-basic-offset: 4 indent-tabs-mode: t -*- */
2 /*
3  * vim: ts=8 sw=4 noet
4  */
5
6 /*
7
8 Copyright (c) 2002, Calum Robinson
9 All rights reserved.
10
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are met:
13
14 * Redistributions of source code must retain the above copyright notice, this
15   list of conditions and the following disclaimer.
16
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.
20
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.
24
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.
35
36 */
37
38 /* flurry */
39
40 #if !defined( lint ) && !defined( SABER )
41 static const char sccsid[] = "@(#)flurry.c      4.07 97/11/24 xlockmore";
42
43 #endif
44
45 /*-
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
48  */
49
50 #define DEF_PRESET     "classic"
51 #define DEF_BRIGHTNESS "8"
52
53 #include <X11/Intrinsic.h>
54
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"
62
63 # include "xlockmore.h"         /* from the xscreensaver distribution */
64
65 #ifdef USE_GL
66
67 static char *preset_str;
68
69 static XrmOptionDescRec opts[] = {
70     { "-preset",     ".preset",     XrmoptionSepArg, 0 }
71 };
72
73 static argtype vars[] = {
74     {(caddr_t *) &preset_str, "preset",     "Preset",     DEF_PRESET,     t_String},
75 };
76
77 #define countof(x) (sizeof((x))/sizeof((*x)))
78
79 ModeSpecOpt flurry_opts = {countof(opts), opts, countof(vars), vars, NULL};
80
81 #ifdef USE_MODULES
82 ModStruct   flurry_description = {
83     "flurry",
84     "init_flurry",
85     "draw_flurry",
86     "release_flurry",
87     "draw_flurry",
88     "init_flurry",
89     NULL,
90     &flurry_opts,
91     1000, 1, 2, 1, 4, 1.0,
92     "",
93     "Flurry",
94     0,
95     NULL
96 };
97
98 #endif
99
100 #include <sys/time.h>
101
102 #include "flurry.h"
103
104 global_info_t *flurry_info = NULL;
105
106 static double gTimeCounter = 0.0;
107
108 double currentTime(void) {
109   struct timeval tv;
110
111   gettimeofday(&tv, NULL);
112
113   return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
114 }
115
116 void OTSetup (void) {
117     if (gTimeCounter == 0.0) {
118         gTimeCounter = currentTime();
119     }
120 }
121
122 double TimeInSecondsSinceStart (void) {
123     return currentTime() - gTimeCounter;
124 }
125
126 #if 0
127 #ifdef __ppc__
128 static int IsAltiVecAvailable(void)
129 {
130     return 0;
131 }
132 #endif
133 #endif
134
135 void delete_flurry_info(flurry_info_t *flurry)
136 {
137     int i;
138
139     free(flurry->s);
140     free(flurry->star);
141     for (i=0;i<MAX_SPARKS;i++)
142     {
143         free(flurry->spark[i]);
144     }
145     free(flurry);
146 }
147
148 flurry_info_t *new_flurry_info(global_info_t *global, int streams, ColorModes colour, float thickness, float speed, double bf)
149 {
150     int i,k;
151     flurry_info_t *flurry = (flurry_info_t *)malloc(sizeof(flurry_info_t));
152
153     if (!flurry) return NULL;
154
155     flurry->flurryRandomSeed = RandFlt(0.0, 300.0);
156
157         flurry->fOldTime = 0;
158         flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
159         flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
160
161     flurry->numStreams = streams;
162     flurry->streamExpansion = thickness;
163     flurry->currentColorMode = colour;
164     flurry->briteFactor = bf;
165
166     flurry->s = malloc(sizeof(SmokeV));
167     InitSmoke(flurry->s);
168
169     flurry->star = malloc(sizeof(Star));
170     InitStar(flurry->star);
171     flurry->star->rotSpeed = speed;
172
173     for (i = 0;i < MAX_SPARKS; i++)
174     {
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]);
179     }
180
181     for (i=0;i<NUMSMOKEPARTICLES/4;i++) {
182         for(k=0;k<4;k++) {
183             flurry->s->p[i].dead.i[k] = 1;
184         }
185     }
186
187     flurry->next = NULL;
188
189     return flurry;
190 }
191
192 void GLSetupRC(global_info_t *global)
193 {
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);
201     glEnable(GL_BLEND);
202
203     glViewport(0,0,(int) global->sys_glWidth,(int) global->sys_glHeight);
204     glMatrixMode(GL_PROJECTION);
205     glLoadIdentity();
206     gluOrtho2D(0,global->sys_glWidth,0,global->sys_glHeight);
207     glMatrixMode(GL_MODELVIEW);
208     glLoadIdentity();
209
210     glClearColor(0.0,0.0,0.0,1.0);
211     glClear(GL_COLOR_BUFFER_BIT);
212
213     glEnableClientState(GL_COLOR_ARRAY);        
214     glEnableClientState(GL_VERTEX_ARRAY);       
215     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
216     
217 #if 0
218 #ifdef __ppc__
219     global->optMode = OPT_MODE_SCALAR_FRSQRTE;
220
221 #ifdef __VEC__
222     if (IsAltiVecAvailable()) global->optMode = OPT_MODE_VECTOR_UNROLLED;
223 #endif
224
225 #else
226     global->optMode = OPT_MODE_SCALAR_BASE;
227 #endif
228 #endif /* 0 */
229 }
230
231 void GLRenderScene(global_info_t *global, flurry_info_t *flurry, double b)
232 {
233     int i;
234
235     flurry->dframe++;
236
237     flurry->fOldTime = flurry->fTime;
238     flurry->fTime = TimeInSecondsSinceStart() + flurry->flurryRandomSeed;
239     flurry->fDeltaTime = flurry->fTime - flurry->fOldTime;
240
241     flurry->drag = (float) pow(0.9965,flurry->fDeltaTime*85.0);
242
243     UpdateStar(global, flurry, flurry->star);
244
245 #ifdef DRAW_SPARKS
246     glShadeModel(GL_SMOOTH);
247     glEnable(GL_BLEND);
248     glBlendFunc(GL_SRC_ALPHA,GL_ONE);
249 #endif
250
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]);
257 #ifdef DRAW_SPARKS
258         DrawSpark(global, flurry, flurry->spark[i]);
259 #endif
260     }
261
262     switch(global->optMode) {
263         case OPT_MODE_SCALAR_BASE:
264             UpdateSmoke_ScalarBase(global, flurry, flurry->s);
265             break;
266 #if 0
267 #ifdef __ppc__
268         case OPT_MODE_SCALAR_FRSQRTE:
269             UpdateSmoke_ScalarFrsqrte(global, flurry, flurry->s);
270             break;
271 #endif
272 #ifdef __VEC__
273         case OPT_MODE_VECTOR_SIMPLE:
274             UpdateSmoke_VectorBase(global, flurry, flurry->s);
275             break;
276         case OPT_MODE_VECTOR_UNROLLED:
277             UpdateSmoke_VectorUnrolled(global, flurry, flurry->s);
278             break;
279 #endif
280 #endif /* 0 */
281
282         default:
283             break;
284     }
285
286     /* glDisable(GL_BLEND); */
287     glEnable(GL_BLEND);
288     glBlendFunc(GL_SRC_ALPHA,GL_ONE);
289     glEnable(GL_TEXTURE_2D);
290
291     switch(global->optMode) {
292         case OPT_MODE_SCALAR_BASE:
293 #if 0
294 #ifdef __ppc__
295         case OPT_MODE_SCALAR_FRSQRTE:
296 #endif
297 #endif /* 0 */
298             DrawSmoke_Scalar(global, flurry, flurry->s, b);
299             break;
300 #if 0
301 #ifdef __VEC__
302         case OPT_MODE_VECTOR_SIMPLE:
303         case OPT_MODE_VECTOR_UNROLLED:
304             DrawSmoke_Vector(global, flurry, flurry->s, b);
305             break;
306 #endif
307 #endif /* 0 */
308         default:
309             break;
310     }    
311
312     glDisable(GL_TEXTURE_2D);
313 }
314
315 void GLResize(global_info_t *global, float w, float h)
316 {
317     global->sys_glWidth = w;
318     global->sys_glHeight = h;
319 }
320
321 /* new window size or exposure */
322 void reshape_flurry(ModeInfo *mi, int width, int height)
323 {
324     global_info_t *global = flurry_info + MI_SCREEN(mi);
325
326     glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
327
328     glViewport(0.0, 0.0, width, height);
329     glMatrixMode(GL_PROJECTION);
330     glLoadIdentity();
331     gluOrtho2D(0, width, 0, height);
332     glMatrixMode(GL_MODELVIEW);
333
334     glClearColor(0.0, 0.0, 0.0, 1.0);
335     glClear(GL_COLOR_BUFFER_BIT);
336
337     glFlush();
338
339     GLResize(global, (float)width, (float)height);
340 }
341
342 void
343 init_flurry(ModeInfo * mi)
344 {
345     int screen = MI_SCREEN(mi);
346     int i;
347     global_info_t *global;
348     enum {
349         PRESET_INSANE = -1,
350         PRESET_WATER = 0,
351         PRESET_FIRE,
352         PRESET_PSYCHEDELIC,
353         PRESET_RGB,
354         PRESET_BINARY,
355         PRESET_CLASSIC,
356         PRESET_MAX
357     } preset_num;
358
359     if (flurry_info == NULL) {
360         OTSetup();
361         if ((flurry_info = (global_info_t *) calloc(MI_NUM_SCREENS(mi),
362                         sizeof (global_info_t))) == NULL)
363             return;
364     }
365
366     global = &flurry_info[screen];
367
368     global->window = MI_WINDOW(mi);
369
370     global->flurry = NULL;
371
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;
389     } else {
390         fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
391         exit(1);
392     }
393
394     switch (preset_num) {
395     case PRESET_WATER: {
396         for (i = 0; i < 9; i++) {
397             flurry_info_t *flurry;
398
399             flurry = new_flurry_info(global, 1, blueColorMode, 100.0, 2.0, 2.0);
400             flurry->next = global->flurry;
401             global->flurry = flurry;
402         }
403         break;
404     }
405     case PRESET_FIRE: {
406         flurry_info_t *flurry;
407
408         flurry = new_flurry_info(global, 12, slowCyclicColorMode, 10000.0, 0.0, 1.0);
409         flurry->next = global->flurry;
410         global->flurry = flurry;        
411         break;
412     }
413     case PRESET_PSYCHEDELIC: {
414         flurry_info_t *flurry;
415
416         flurry = new_flurry_info(global, 10, rainbowColorMode, 200.0, 2.0, 1.0);
417         flurry->next = global->flurry;
418         global->flurry = flurry;        
419         break;
420     }
421     case PRESET_RGB: {
422         flurry_info_t *flurry;
423
424         flurry = new_flurry_info(global, 3, redColorMode, 100.0, 0.8, 1.0);
425         flurry->next = global->flurry;
426         global->flurry = flurry;        
427
428         flurry = new_flurry_info(global, 3, greenColorMode, 100.0, 0.8, 1.0);
429         flurry->next = global->flurry;
430         global->flurry = flurry;        
431
432         flurry = new_flurry_info(global, 3, blueColorMode, 100.0, 0.8, 1.0);
433         flurry->next = global->flurry;
434         global->flurry = flurry;        
435         break;
436     }
437     case PRESET_BINARY: {
438         flurry_info_t *flurry;
439
440         flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 0.5, 1.0);
441         flurry->next = global->flurry;
442         global->flurry = flurry;
443
444         flurry = new_flurry_info(global, 16, tiedyeColorMode, 1000.0, 1.5, 1.0);
445         flurry->next = global->flurry;
446         global->flurry = flurry;
447         break;
448     }
449     case PRESET_CLASSIC: {
450         flurry_info_t *flurry;
451
452         flurry = new_flurry_info(global, 5, tiedyeColorMode, 10000.0, 1.0, 1.0);
453         flurry->next = global->flurry;
454         global->flurry = flurry;
455         break;
456     }
457     case PRESET_INSANE: {
458         flurry_info_t *flurry;
459
460         flurry = new_flurry_info(global, 64, tiedyeColorMode, 1000.0, 0.5, 0.5);
461         flurry->next = global->flurry;
462         global->flurry = flurry;
463
464         break;
465     }
466     default: {
467         fprintf(stderr, "%s: unknown preset %s\n", progname, preset_str);
468         exit(1);
469     }
470     } 
471
472     if ((global->glx_context = init_GL(mi)) != NULL) {
473         reshape_flurry(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
474         GLSetupRC(global);
475     } else {
476         MI_CLEARWINDOW(mi);
477     }
478 }
479
480 void
481 draw_flurry(ModeInfo * mi)
482 {
483     static int first = 1;
484     static double oldFrameTime = -1;
485     double newFrameTime;
486     double deltaFrameTime = 0;
487     double brite;
488     GLfloat alpha;
489
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);
494
495     newFrameTime = currentTime();
496     if (oldFrameTime == -1) {
497         /* special case the first frame -- clear to black */
498         alpha = 1.0;
499     } else {
500         /* 
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).
504          *
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.
508          */
509         if (newFrameTime - oldFrameTime < 1/60.0) {
510             usleep(MAX_(1,(int)(20000 * (newFrameTime - oldFrameTime))));
511             return;
512
513         }
514         deltaFrameTime = newFrameTime - oldFrameTime;
515         alpha = 5.0 * deltaFrameTime;
516     }
517     oldFrameTime = newFrameTime;
518
519     if (alpha > 0.2) alpha = 0.2;
520
521     if (!global->glx_context)
522         return;
523
524     if (first) {
525         MakeTexture();
526         first = 0;
527     }
528     glDrawBuffer(GL_BACK);
529     glXMakeCurrent(display, window, *(global->glx_context));
530
531     glEnable(GL_BLEND);
532     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
533
534     glColor4f(0.0, 0.0, 0.0, alpha);
535     glRectd(0, 0, global->sys_glWidth, global->sys_glHeight);
536
537     brite = pow(deltaFrameTime,0.75) * 10;
538     for (flurry = global->flurry; flurry; flurry=flurry->next) {
539         GLRenderScene(global, flurry, brite * flurry->briteFactor);
540     }
541
542     if (mi->fps_p) do_fps (mi);
543
544     glFinish();
545     glXSwapBuffers(display, window);
546 }
547
548 void
549 release_flurry(ModeInfo * mi)
550 {
551     if (flurry_info != NULL) {
552         int screen;
553
554         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
555             global_info_t *global = &flurry_info[screen];
556             flurry_info_t *flurry;
557
558             if (global->glx_context) {
559                 glXMakeCurrent(MI_DISPLAY(mi), global->window, *(global->glx_context));
560             }
561
562             for (flurry = global->flurry; flurry; flurry=flurry->next) {
563                 delete_flurry_info(flurry);
564             }
565         }
566         (void) free((void *) flurry_info);
567         flurry_info = NULL;
568     }
569     FreeAllGL(mi);
570 }
571
572 #endif