140295c1fe22d86cfe3cdb95dc334b3cd1d6f99b
[xscreensaver] / hacks / glx / atlantis.c
1 /* atlantis --- Shows moving 3D sea animals */
2
3 #if !defined( lint ) && !defined( SABER )
4 static const char sccsid[] = "@(#)atlantis.c    1.3 98/06/18 xlockmore";
5
6 #endif
7
8 /* Copyright (c) E. Lassauge, 1998. */
9
10 /*
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * This file is provided AS IS with no warranties of any kind.  The author
18  * shall have no liability with respect to the infringement of copyrights,
19  * trade secrets or any patents by this file or any part thereof.  In no
20  * event will the author be liable for any lost revenue or profits or
21  * other special, indirect and consequential damages.
22  *
23  * The original code for this mode was written by Mark J. Kilgard
24  * as a demo for openGL programming.
25  * 
26  * Porting it to xlock  was possible by comparing the original Mesa's morph3d 
27  * demo with it's ported version to xlock, so thanks for Marcelo F. Vianna 
28  * (look at morph3d.c) for his indirect help.
29  *
30  * Thanks goes also to Brian Paul for making it possible and inexpensive
31  * to use OpenGL at home.
32  *
33  * My e-mail address is lassauge@sagem.fr
34  *
35  * Eric Lassauge  (May-13-1998)
36  *
37  * REVISION HISTORY:
38  * 
39  * David A. Bagley - 98/06/17 : Add whalespeed option. Global options to
40  *                              initialize local variables are now:
41  *                              XLock.atlantis.cycles: 100      ! SharkSpeed
42  *                              XLock.atlantis.batchcount: 4    ! SharkNum
43  *                              XLock.atlantis.whalespeed: 250  ! WhaleSpeed
44  *                              XLock.atlantis.size: 6000       ! SharkSize
45  *                              Add random direction for whales/dolphins
46  * 
47  * E.Lassauge - 98/06/16: Use the following global options to initialize
48  *                        local variables :
49  *                              XLock.atlantis.delay: 100       ! SharkSpeed
50  *                              XLock.atlantis.batchcount: 4    ! SharkNum
51  *                              XLock.atlantis.cycles: 250      ! WhaleSpeed
52  *                              XLock.atlantis.size: 6000       ! SharkSize
53  *                        Add support for -/+ wireframe (t'was so easy to do!)
54  *
55  * TODO : 
56  *        - add a sort of background image or random bg color
57  *        - better handling of sizes and speeds
58  *        - test standalone and module modes
59  *        - purify it (!)
60  */
61
62 /* Copyright (c) Mark J. Kilgard, 1994. */
63
64 /**
65  * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
66  * ALL RIGHTS RESERVED
67  * Permission to use, copy, modify, and distribute this software for
68  * any purpose and without fee is hereby granted, provided that the above
69  * copyright notice appear in all copies and that both the copyright notice
70  * and this permission notice appear in supporting documentation, and that
71  * the name of Silicon Graphics, Inc. not be used in advertising
72  * or publicity pertaining to distribution of the software without specific,
73  * written prior permission.
74  *
75  * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
76  * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
77  * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
78  * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
79  * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
80  * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
81  * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
82  * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
83  * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
84  * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
85  * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
86  * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
87  *
88  * US Government Users Restricted Rights
89  * Use, duplication, or disclosure by the Government is subject to
90  * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
91  * (c)(1)(ii) of the Rights in Technical Data and Computer Software
92  * clause at DFARS 252.227-7013 and/or in similar or successor
93  * clauses in the FAR or the DOD or NASA FAR Supplement.
94  * Unpublished-- rights reserved under the copyright laws of the
95  * United States.  Contractor/manufacturer is Silicon Graphics,
96  * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
97  *
98  * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
99  */
100
101 #ifdef STANDALONE
102 # define PROGCLASS      "Atlantis"
103 # define HACK_INIT      init_atlantis
104 # define HACK_DRAW      draw_atlantis
105 # define atlantis_opts  xlockmore_opts
106 # define DEFAULTS       "*delay:        1000 \n" \
107                          "*count:          4 \n" \
108                          "*cycles:       100 \n" \
109                          "*size:        6000 \n" \
110                          "*whalespeed:   250 \n"
111 # include "xlockmore.h"         /* from the xscreensaver distribution */
112 #else  /* !STANDALONE */
113 # include "xlock.h"             /* from the xlockmore distribution */
114 #include "vis.h"
115 #endif /* !STANDALONE */
116
117 #ifdef USE_GL
118
119 #include "atlantis.h"
120 #include <GL/glu.h>
121
122
123 #define DEF_WHALESPEED  "250"
124 static int  whalespeed;
125 static XrmOptionDescRec opts[] =
126 {
127      {"-whalespeed", ".atlantis.whalespeed", XrmoptionSepArg, (caddr_t) NULL}
128 };
129
130 static argtype vars[] =
131 {
132 {(caddr_t *) & whalespeed, "whalespeed", "WhaleSpeed", DEF_WHALESPEED, t_Int}
133 };
134
135 static OptionStruct desc[] =
136 {
137         {"-whalespeed num", "speed of whales and the dolphin"}
138 };
139
140 ModeSpecOpt atlantis_opts =
141 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
142
143 #ifdef USE_MODULES
144 ModStruct   atlantis_description =
145 {"atlantis", "init_atlantis", "draw_atlantis", "release_atlantis",
146  "refresh_atlantis", "change_atlantis", NULL, &atlantis_opts,
147  1000, NUM_SHARKS, SHARKSPEED, SHARKSIZE, 64, 1.0, "",
148  "Shows moving sharks/whales/dolphin", 0, NULL};
149
150 #endif
151
152 static atlantisstruct *atlantis = NULL;
153
154 static void
155 InitFishs(atlantisstruct * ap)
156 {
157         int         i;
158
159         for (i = 0; i < ap->num_sharks; i++) {
160                 ap->sharks[i].x = 70000.0 + NRAND(ap->sharksize);
161                 ap->sharks[i].y = NRAND(ap->sharksize);
162                 ap->sharks[i].z = NRAND(ap->sharksize);
163                 ap->sharks[i].psi = NRAND(360) - 180.0;
164                 ap->sharks[i].v = 1.0;
165         }
166
167         /* Random whae direction */
168         ap->whaledir = LRAND() & 1;
169
170         ap->dolph.x = 30000.0;
171         ap->dolph.y = 0.0;
172         ap->dolph.z = (float) (ap->sharksize);
173         ap->dolph.psi = (ap->whaledir) ? 90.0 : -90.0;
174         ap->dolph.theta = 0.0;
175         ap->dolph.v = 6.0;
176
177         ap->momWhale.x = 70000.0;
178         ap->momWhale.y = 0.0;
179         ap->momWhale.z = 0.0;
180         ap->momWhale.psi = (ap->whaledir) ? 90.0 : -90.0;
181         ap->momWhale.theta = 0.0;
182         ap->momWhale.v = 3.0;
183
184         ap->babyWhale.x = 60000.0;
185         ap->babyWhale.y = -2000.0;
186         ap->babyWhale.z = -2000.0;
187         ap->babyWhale.psi = (ap->whaledir) ? 90.0 : -90.0;
188         ap->babyWhale.theta = 0.0;
189         ap->babyWhale.v = 3.0;
190 }
191
192 static void
193 Init(atlantisstruct * ap)
194 {
195         static float ambient[] =
196         {0.1, 0.1, 0.1, 1.0};
197         static float diffuse[] =
198         {1.0, 1.0, 1.0, 1.0};
199         static float position[] =
200         {0.0, 1.0, 0.0, 0.0};
201         static float mat_shininess[] =
202         {90.0};
203         static float mat_specular[] =
204         {0.8, 0.8, 0.8, 1.0};
205         static float mat_diffuse[] =
206         {0.46, 0.66, 0.795, 1.0};
207         static float mat_ambient[] =
208         {0.0, 0.1, 0.2, 1.0};
209         static float lmodel_ambient[] =
210         {0.4, 0.4, 0.4, 1.0};
211         static float lmodel_localviewer[] =
212         {0.0};
213         float       fblue = 0.0, fgreen;
214
215         glFrontFace(GL_CW);
216
217         glDepthFunc(GL_LEQUAL);
218         glEnable(GL_DEPTH_TEST);
219
220         glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
221         glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
222         glLightfv(GL_LIGHT0, GL_POSITION, position);
223         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
224         glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
225         glEnable(GL_LIGHTING);
226         glEnable(GL_LIGHT0);
227
228         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
229         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
230         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
231         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
232
233         InitFishs(ap);
234
235         /* Add a little randomness */
236         fblue = ((float) (NRAND(50)) / 100.0) + 0.50;
237         fgreen = fblue * 0.56;
238         glClearColor(0.0, fgreen, fblue, 0.0);
239 }
240
241 static void
242 Reshape(ModeInfo * mi, int width, int height)
243 {
244         atlantisstruct *ap = &atlantis[MI_SCREEN(mi)];
245
246         glViewport(0, 0, ap->WinW = (GLint) width, ap->WinH = (GLint) height);
247
248         glMatrixMode(GL_PROJECTION);
249         glLoadIdentity();
250         gluPerspective(400.0, (GLdouble) width / (GLdouble) height, 1.0, 2000000.0);
251         glMatrixMode(GL_MODELVIEW);
252 }
253
254 static void
255 Animate(atlantisstruct * ap)
256 {
257         int         i;
258
259         for (i = 0; i < ap->num_sharks; i++) {
260                 SharkPilot(&(ap->sharks[i]), ap->sharkspeed);
261                 SharkMiss(ap, i);
262         }
263         WhalePilot(&(ap->dolph), ap->whalespeed, ap->whaledir);
264         ap->dolph.phi++;
265         WhalePilot(&(ap->momWhale), ap->whalespeed, ap->whaledir);
266         ap->momWhale.phi++;
267         WhalePilot(&(ap->babyWhale), ap->whalespeed, ap->whaledir);
268         ap->babyWhale.phi++;
269 }
270
271 static void
272 AllDisplay(atlantisstruct * ap)
273 {
274         int         i;
275
276         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
277
278         for (i = 0; i < ap->num_sharks; i++) {
279                 glPushMatrix();
280                 FishTransform(&(ap->sharks[i]));
281                 DrawShark(&(ap->sharks[i]), ap->wire);
282                 glPopMatrix();
283         }
284
285         glPushMatrix();
286         FishTransform(&(ap->dolph));
287         DrawDolphin(&(ap->dolph), ap->wire);
288         glPopMatrix();
289
290         glPushMatrix();
291         FishTransform(&(ap->momWhale));
292         DrawWhale(&(ap->momWhale), ap->wire);
293         glPopMatrix();
294
295         glPushMatrix();
296         FishTransform(&(ap->babyWhale));
297         glScalef(0.45, 0.45, 0.3);
298         DrawWhale(&(ap->babyWhale), ap->wire);
299         glPopMatrix();
300 }
301
302 /*
303  *-----------------------------------------------------------------------------
304  *-----------------------------------------------------------------------------
305  *    Xlock hooks.
306  *-----------------------------------------------------------------------------
307  *-----------------------------------------------------------------------------
308  */
309
310 /*
311  *-----------------------------------------------------------------------------
312  *    Initialize atlantis.  Called each time the window changes.
313  *-----------------------------------------------------------------------------
314  */
315
316 void
317 init_atlantis(ModeInfo * mi)
318 {
319         int         screen = MI_SCREEN(mi);
320         atlantisstruct *ap;
321         Display    *display = MI_DISPLAY(mi);
322         Window      window = MI_WINDOW(mi);
323
324         if (atlantis == NULL) {
325                 if ((atlantis = (atlantisstruct *) calloc(MI_NUM_SCREENS(mi),
326                                            sizeof (atlantisstruct))) == NULL)
327                         return;
328         }
329         ap = &atlantis[screen];
330         ap->num_sharks = MI_COUNT(mi);
331         if (ap->sharks == NULL) {
332                 if ((ap->sharks = (fishRec *) calloc(ap->num_sharks,
333                                                 sizeof (fishRec))) == NULL) {
334                         /* free everything up to now */
335                         (void) free((void *) atlantis);
336                         atlantis = NULL;
337                         return;
338                 }
339         }
340         ap->sharkspeed = MI_CYCLES(mi);         /* has influence on the "width"
341                                                    of the movement */
342         ap->sharksize = MI_SIZE(mi);    /* has influence on the "distance"
343                                            of the sharks */
344         ap->whalespeed = whalespeed;
345         ap->wire = MI_IS_WIREFRAME(mi);
346
347         if (MI_IS_DEBUG(mi)) {
348                 (void) fprintf(stderr,
349                                "%s:\n\tnum_sharks=%d\n\tsharkspeed=%.1f\n\tsharksize=%d\n\twhalespeed=%.1f\n\twireframe=%s\n",
350                                MI_NAME(mi),
351                                ap->num_sharks,
352                                ap->sharkspeed,
353                                ap->sharksize,
354                                ap->whalespeed,
355                                ap->wire ? "yes" : "no"
356                         );
357         }
358         if ((ap->glx_context = init_GL(mi)) != NULL) {
359
360                 Reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
361                 glDrawBuffer(GL_BACK);
362                 Init(ap);
363                 AllDisplay(ap);
364                 glXSwapBuffers(display, window);
365
366         } else {
367                 MI_CLEARWINDOW(mi);
368         }
369 }
370
371 /*
372  *-----------------------------------------------------------------------------
373  *    Called by the mainline code periodically to update the display.
374  *-----------------------------------------------------------------------------
375  */
376 void
377 draw_atlantis(ModeInfo * mi)
378 {
379         atlantisstruct *ap = &atlantis[MI_SCREEN(mi)];
380
381         Display    *display = MI_DISPLAY(mi);
382         Window      window = MI_WINDOW(mi);
383
384         MI_IS_DRAWN(mi) = True;
385
386         if (!ap->glx_context)
387                 return;
388
389         glXMakeCurrent(display, window, *(ap->glx_context));
390
391         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
392
393         glPushMatrix();
394
395         AllDisplay(ap);
396         Animate(ap);
397
398         glXSwapBuffers(display, window);
399 }
400
401
402 /*
403  *-----------------------------------------------------------------------------
404  *    The display is being taken away from us.  Free up malloc'ed 
405  *      memory and X resources that we've alloc'ed.  Only called
406  *      once, we must zap everything for every screen.
407  *-----------------------------------------------------------------------------
408  */
409
410 void
411 release_atlantis(ModeInfo * mi)
412 {
413         int         screen;
414
415         if (atlantis != NULL) {
416                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
417                         atlantisstruct *ap = &atlantis[screen];
418
419                         if (ap->sharks)
420                                 (void) free((void *) ap->sharks);
421                 }
422                 (void) free((void *) atlantis);
423                 atlantis = NULL;
424         }
425         FreeAllGL(mi);
426 }
427
428 void
429 refresh_atlantis(ModeInfo * mi)
430 {
431 }
432
433 void
434 change_atlantis(ModeInfo * mi)
435 {
436         atlantisstruct *ap = &atlantis[MI_SCREEN(mi)];
437
438         if (!ap->glx_context)
439                 return;
440
441         glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(ap->glx_context));
442         Init(ap);
443 }
444
445 #endif /* USE_GL */