1 /*
2  * Compiz cube atlantis plugin
3  *
4  * atlantis.c
5  *
6  * This plugin renders a fish tank inside of the transparent cube,
7  * replete with fish, crabs, sand, bubbles, and coral.
8  *
9  * Copyright : (C) 2007-2008 by David Mikos
10  * Email     : infiniteloopcounter@gmail.com
11  *
12  * Copyright : (C) 2007 by Dennis Kasprzyk
13  * E-mail    : onestone@opencompositing.org
14  *
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  */
27 
28 /*
29  * Detailed fish/fish2 and coral 3D models made by Biswajyoti Mahanta.
30  *
31  * Butterflyfish and Chromis 3D models/auto-generated code by "unpush"
32  */
33 
34 /*
35  * Based on atlantis xscreensaver http://www.jwz.org/xscreensaver/
36  */
37 
38 /* atlantis --- Shows moving 3D sea animals */
39 
40 /* Copyright (c) E. Lassauge, 1998. */
41 
42 /*
43  * Permission to use, copy, modify, and distribute this software and its
44  * documentation for any purpose and without fee is hereby granted,
45  * provided that the above copyright notice appear in all copies and that
46  * both that copyright notice and this permission notice appear in
47  * supporting documentation.
48  *
49  * This file is provided AS IS with no warranties of any kind.  The author
50  * shall have no liability with respect to the infringement of copyrights,
51  * trade secrets or any patents by this file or any part thereof.  In no
52  * event will the author be liable for any lost revenue or profits or
53  * other special, indirect and consequential damages.
54  *
55  * The original code for this mode was written by Mark J. Kilgard
56  * as a demo for openGL programming.
57  *
58  * Porting it to xlock  was possible by comparing the original Mesa's morph3d
59  * demo with it's ported version to xlock, so thanks for Marcelo F. Vianna
60  * (look at morph3d.c) for his indirect help.
61  *
62  * Thanks goes also to Brian Paul for making it possible and inexpensive
63  * to use OpenGL at home.
64  *
65  * My e-mail address is lassauge@users.sourceforge.net
66  *
67  * Eric Lassauge  (May-13-1998)
68  *
69  */
70 
71 /**
72  * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
73  * ALL RIGHTS RESERVED
74  * Permission to use, copy, modify, and distribute this software for
75  * any purpose and without fee is hereby granted, provided that the above
76  * copyright notice appear in all copies and that both the copyright notice
77  * and this permission notice appear in supporting documentation, and that
78  * the name of Silicon Graphics, Inc. not be used in advertising
79  * or publicity pertaining to distribution of the software without specific,
80  * written prior permission.
81  *
82  * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
83  * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
84  * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
85  * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
86  * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
87  * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
88  * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
89  * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
90  * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
91  * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
92  * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
93  * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
94  *
95  * US Government Users Restricted Rights
96  * Use, duplication, or disclosure by the Government is subject to
97  * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
98  * (c)(1)(ii) of the Rights in Technical Data and Computer Software
99  * clause at DFARS 252.227-7013 and/or in similar or successor
100  * clauses in the FAR or the DOD or NASA FAR Supplement.
101  * Unpublished-- rights reserved under the copyright laws of the
102  * United States.  Contractor/manufacturer is Silicon Graphics,
103  * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
104  *
105  * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
106  */
107 
108 
109 /*
110  * Coordinate system:
111  * clockwise from top
112  * with x=radius, y=0 the "top" (towards 1st desktop from above view)
113  * and the z coordinate as height.
114 */
115 
116 #include <stdlib.h>
117 #include <string.h>
118 #include <stdio.h>
119 #include <signal.h>
120 #include <unistd.h>
121 #include <math.h>
122 
123 #include "atlantis-internal.h"
124 #include "atlantis_options.h"
125 
126 
127 static void initWorldVariables (CompScreen *);
128 static void loadModels (CompScreen *);
129 static void freeModels (CompScreen *s);
130 static void setLightPosition (CompScreen *, GLenum light);
131 static void atlantisInitLightPosition (CompScreen *);
132 
133 int atlantisDisplayPrivateIndex;
134 
135 int cubeDisplayPrivateIndex;
136 
137 
138 static void
initAtlantis(CompScreen * s)139 initAtlantis (CompScreen *s)
140 {
141     ATLANTIS_SCREEN (s);
142 
143     int i = 0, i2 = 0;
144     int j, k;
145     int num;
146 
147     CompListValue * cType   = atlantisGetCreatureType (s);
148     CompListValue * cNumber = atlantisGetCreatureNumber (s);
149     CompListValue * cSize   = atlantisGetCreatureSize (s);
150     CompListValue * cColor  = atlantisGetCreatureColor (s);
151 
152     num = MIN (cType->nValue, cNumber->nValue);
153     num = MIN (num, cSize->nValue);
154     num = MIN (num, cColor->nValue);
155 
156     as->water = NULL;
157     as->ground = NULL;
158 
159     as->numFish = 0;
160     as->numCrabs = 0;
161 
162     for (k = 0; k < num; k++)
163     {
164 	if (cSize->value[k].i == 0)
165 	    continue;
166 
167 	if (cType->value[k].i != CRAB)
168 	    as->numFish += cNumber->value[k].i;
169 	else
170 	    as->numCrabs += cNumber->value[k].i;
171     }
172 
173     as->fish = calloc (as->numFish,  sizeof(fishRec));
174     as->crab = calloc (as->numCrabs, sizeof(crabRec));
175 
176     if (atlantisGetShowWater (s))
177 	as->waterHeight = atlantisGetWaterHeight (s) * 100000 - 50000;
178     else
179 	as->waterHeight = 50000;
180 
181     as->oldProgress = 0;
182 
183     for (k = 0; k < num; k++)
184     {
185 	for (j = 0; j < cNumber->value[k].i; j++)
186 	{
187 	    int size = cSize->value[k].i;
188 	    int type = cType->value[k].i;
189 
190 	    if (size==0)
191 		break;
192 
193 	    if (type != CRAB)
194 	    {
195 		fishRec * fish = &(as->fish[i]);
196 
197 		fish->type = type;
198 
199 		if (type == WHALE)
200 		    size /= 2;
201 		if (type == DOLPHIN)
202 		    size *= 2;
203 		if (type == SHARK)
204 		    size *= 3;
205 
206 		fish->size = randf (sqrtf (size) ) + size;
207 		fish->speed = randf (150) + 50;
208 
209 		if (j == 0)
210 		    setSimilarColor4us (fish->color, cColor->value[k].c,
211 		                        0.2, 0.1);
212 		else
213 		    setSimilarColor (fish->color, as->fish[i-j].color,
214 		                     0.2, 0.1);
215 
216 		fish->x = randf (size);
217 		fish->y = randf (size);
218 		fish->z = (as->waterHeight - 50000) / 2 +
219 			  randf (size * 0.02) - size * 0.01;
220 		fish->psi = randf (360) - 180.0;
221 		fish->theta = randf (100) - 50;
222 		fish->v = 1.0;
223 
224 		fish->group = k;
225 
226 		fish->boidsCounter = i % NUM_GROUPS;
227 		fish->boidsPsi = fish->psi;
228 		fish->boidsTheta = fish->theta;
229 
230 		fish->smoothTurnCounter = NRAND (3);
231 		fish->smoothTurnAmount = NRAND (3) - 1;
232 
233 		fish->prevRandPsi = 0;
234 		fish->prevRandTh = 0;
235 
236 		i++;
237 	    }
238 	    else
239 	    {
240 		crabRec * crab = &(as->crab[i2]);
241 
242 		crab->size = randf (sqrtf (size)) + size;
243 		crab->speed = randf (100) + 50;
244 
245 		if (j == 0)
246 		    setSimilarColor4us (crab->color, cColor->value[k].c,
247 		                        0.2, 0.1);
248 		else
249 		    setSimilarColor (crab->color, as->crab[i2 - j].color,
250 		                     0.2, 0.1);
251 
252 		crab->x = randf (2 * size) - size;
253 		crab->y = randf (2 * size) - size;
254 
255 		if (atlantisGetStartCrabsBottom (s))
256 		{
257 		    crab->z = 50000;
258 		    crab->isFalling = FALSE;
259 		}
260 		else
261 		{
262 		    crab->z = (as->waterHeight - 50000)/2;
263 		    crab->isFalling = TRUE;
264 		}
265 
266 		crab->psi = randf (360);
267 		crab->theta= 0;
268 
269 		crab->scuttlePsi = 0;
270 		crab->scuttleAmount = NRAND (3) - 1;
271 
272 		i2++;
273 	    }
274 	}
275     }
276 
277     as->numCorals = 0;
278     as->numAerators = 0;
279 
280     cType = atlantisGetPlantType (s);
281     cNumber = atlantisGetPlantNumber (s);
282     cSize = atlantisGetPlantSize (s);
283     cColor = atlantisGetPlantColor (s);
284 
285     num = MIN (cType->nValue, cNumber->nValue);
286     num = MIN (num, cSize->nValue);
287     num = MIN (num, cColor->nValue);
288 
289     for (k = 0; k < num; k++)
290     {
291 	switch (cType->value[k].i) {
292 	case 0:
293 	case 1:
294 	    as->numCorals += cNumber->value[k].i;
295 	    break;
296 
297 	case 2:
298 	    as->numAerators += cNumber->value[k].i;
299 	    break;
300 	}
301     }
302 
303     as->coral   = calloc (as->numCorals,   sizeof(coralRec));
304     as->aerator = calloc (as->numAerators, sizeof(aeratorRec));
305 
306     for (k = 0; k < as->numAerators; k++)
307     {
308 	as->aerator[k].numBubbles = 20;
309 	as->aerator[k].bubbles = calloc (as->aerator[k].numBubbles,
310 		sizeof (Bubble));
311     }
312 
313     initWorldVariables(s);
314 
315     updateWater (s, 0); /* make sure normals are initialized */
316     updateGround (s, 0);
317 
318     loadModels(s);
319 }
320 
321 static void
loadModels(CompScreen * s)322 loadModels (CompScreen *s)
323 {
324     ATLANTIS_SCREEN (s);
325 
326     as->crabDisplayList = glGenLists (1);
327     glNewList (as->crabDisplayList, GL_COMPILE);
328     DrawCrab (0);
329     glEndList ();
330 
331     as->coralDisplayList = glGenLists (1);
332     glNewList (as->coralDisplayList, GL_COMPILE);
333     atlantisGetLowPoly (s) ? DrawCoralLow (0) : DrawCoral (0);
334     glEndList ();
335 
336     as->coral2DisplayList = glGenLists (1);
337     glNewList (as->coral2DisplayList, GL_COMPILE);
338     atlantisGetLowPoly (s) ? DrawCoral2Low (0) : DrawCoral2 (0);
339     glEndList ();
340 
341     as->bubbleDisplayList = glGenLists (1);
342     glNewList (as->bubbleDisplayList, GL_COMPILE);
343     atlantisGetLowPoly (s) ? DrawBubble (0, 6) : DrawBubble (0, 9);
344     glEndList ();
345 }
346 
347 static void
freeModels(CompScreen * s)348 freeModels (CompScreen *s)
349 {
350     ATLANTIS_SCREEN (s);
351 
352     glDeleteLists (as->crabDisplayList, 1);
353     glDeleteLists (as->coralDisplayList, 1);
354     glDeleteLists (as->coral2DisplayList, 1);
355     glDeleteLists (as->bubbleDisplayList, 1);
356 }
357 
calculateScreenRatio(CompScreen * s)358 static float calculateScreenRatio (CompScreen *s)
359 {
360     CUBE_SCREEN (s);
361 
362     float temp, ratio;
363     int i;
364 
365     if (!atlantisGetRescaleWidth (s))
366 	return 1.0f;
367 
368     ratio = (float) s->width / (float) s->height;
369 
370     if (s->nOutputDev <= 1)
371 	return ratio;
372 
373     temp = 0;
374 
375     if (cs->moMode == CUBE_MOMODE_AUTO && cs->nOutput < s->nOutputDev)
376     {
377 	return ratio;
378     }
379     else if (cs->moMode == CUBE_MOMODE_ONE)
380     {
381 	/* this doesn't seem right, but it works */
382 	for (i = 0; i < s->nOutputDev; i++)
383 	    temp += (float) s->width / (float) s->outputDev->height;;
384 
385 	if (temp != 0)
386 	    ratio = temp / s->nOutputDev;
387     }
388     else
389     {
390 	for (i = 0; i < s->nOutputDev; i++)
391 	    temp += (float) s->outputDev->width / (float) s->outputDev->height;
392 
393 	if (temp != 0)
394 	    ratio = temp / s->nOutputDev;
395     }
396 
397     return ratio;
398 }
399 
400 static void
initWorldVariables(CompScreen * s)401 initWorldVariables (CompScreen *s)
402 {
403     ATLANTIS_SCREEN (s);
404     CUBE_SCREEN (s);
405 
406     int i = 0, i2 = 0;
407     int j, k;
408     int bi, num;
409 
410     coralRec * coral;
411     aeratorRec * aerator;
412 
413     CompListValue * cType = atlantisGetPlantType (s);
414     CompListValue * cNumber = atlantisGetPlantNumber (s);
415     CompListValue * cSize = atlantisGetPlantSize (s);
416     CompListValue * cColor = atlantisGetPlantColor (s);
417 
418     as->speedFactor = atlantisGetSpeedFactor (s);
419 
420     as->hsize = s->hsize * cs->nOutput;
421 
422     as->arcAngle = 360.0f / as->hsize;
423     as->radius = (100000 - 1) * cs->distance /
424 		 cosf (0.5 * (as->arcAngle * toRadians));
425     as->topDistance = (100000 - 1) * cs->distance;
426 
427     as->ratio = calculateScreenRatio (s);
428 
429     as->sideDistance = as->topDistance * as->ratio;
430     /* the 100000 comes from scaling by 0.00001 ( = (1/0.00001) ) */
431 
432     num = MIN (cType->nValue, cNumber->nValue);
433     num = MIN (num, cSize->nValue);
434     num = MIN (num, cColor->nValue);
435 
436     for (k = 0; k < num; k++)
437     {
438 	for (j = 0; j < cNumber->value[k].i; j++)
439 	{
440 	    int size = cSize->value[k].i;
441 
442 	    switch (cType->value[k].i) {
443 	    case 0:
444 	    case 1:
445 		coral = &(as->coral[i]);
446 
447 		coral->size = (randf (sqrtf(size)) + size);
448 		coral->type = cType->value[k].i;
449 
450 		if (j == 0)
451 		    setSimilarColor4us (coral->color, cColor->value[k].c,
452 		                        0.2, 0.2);
453 		else
454 		    setSimilarColor (coral->color, as->coral[i - j].color,
455 		                     0.2, 0.2);
456 
457 		coral->psi = randf (360);
458 
459 		setRandomLocation (s, &(coral->x), &(coral->y), 3 * size);
460 		coral->z = -50000;
461 		i++;
462 		break;
463 
464 	    case 2:
465 		aerator = &(as->aerator[i2]);
466 
467 		aerator->size = randf (sqrtf (size)) + size;
468 		aerator->type = cType->value[k].i;
469 
470 		if (j == 0)
471 		    setSimilarColor4us (aerator->color, cColor->value[k].c,
472 		                        0, 0);
473 		else
474 		    setSimilarColor (aerator->color, as->aerator[i2-j].color,
475 		                     0.0, 0.0);
476 
477 		setRandomLocation (s, &(aerator->x), &(aerator->y), size);
478 		aerator->z = -50000;
479 
480 		for (bi = 0; bi < aerator->numBubbles; bi++)
481 		{
482 		    aerator->bubbles[bi].size = size;
483 		    aerator->bubbles[bi].x = aerator->x;
484 		    aerator->bubbles[bi].y = aerator->y;
485 		    aerator->bubbles[bi].z = aerator->z;
486 		    aerator->bubbles[bi].speed = 100 + randf (150);
487 		    aerator->bubbles[bi].offset = randf (2 * PI);
488 		    aerator->bubbles[bi].counter = 0;
489 		}
490 
491 		i2++;
492 		break;
493 	    }
494 	}
495     }
496 
497 }
498 
499 static void
freeAtlantis(CompScreen * s)500 freeAtlantis (CompScreen *s)
501 {
502     ATLANTIS_SCREEN (s);
503 
504     int i;
505 
506     if (as->fish)
507 	free (as->fish);
508     if (as->crab)
509 	free (as->crab);
510     if (as->coral)
511 	free (as->coral);
512 
513     if (as->aerator)
514     {
515 	for (i = 0; i < as->numAerators; i++)
516 	{
517 	    if (as->aerator[i].bubbles)
518 		free (as->aerator[i].bubbles);
519 	}
520 
521 	free (as->aerator);
522     }
523 
524     freeWater (as->water);
525     freeWater (as->ground);
526 
527     as->fish = NULL;
528     as->crab = NULL;
529     as->coral= NULL;
530     as->aerator = NULL;
531 
532     freeModels(s);
533 }
534 
535 static void
updateAtlantis(CompScreen * s)536 updateAtlantis (CompScreen *s)
537 {
538     freeAtlantis (s);
539     initAtlantis (s);
540 }
541 static void
atlantisScreenOptionChange(CompScreen * s,CompOption * opt,AtlantisScreenOptions num)542 atlantisScreenOptionChange (CompScreen *s,
543                             CompOption *opt,
544                             AtlantisScreenOptions num)
545 {
546     updateAtlantis (s);
547 }
548 static void
atlantisSpeedFactorOptionChange(CompScreen * s,CompOption * opt,AtlantisScreenOptions num)549 atlantisSpeedFactorOptionChange (CompScreen *s,
550                                  CompOption *opt,
551                                  AtlantisScreenOptions num)
552 {
553     ATLANTIS_SCREEN (s);
554     as->speedFactor = atlantisGetSpeedFactor (s);
555 }
556 
557 static void
atlantisLightingOptionChange(CompScreen * s,CompOption * opt,AtlantisScreenOptions num)558 atlantisLightingOptionChange (CompScreen *s,
559                               CompOption *opt,
560                               AtlantisScreenOptions num)
561 {
562     atlantisInitLightPosition (s);
563 }
564 
565 static void
atlantisLowPolyOptionChange(CompScreen * s,CompOption * opt,AtlantisScreenOptions num)566 atlantisLowPolyOptionChange (CompScreen *s,
567                              CompOption *opt,
568                              AtlantisScreenOptions num)
569 {
570     freeModels (s);
571     loadModels (s);
572 }
573 
574 static void
atlantisClearTargetOutput(CompScreen * s,float xRotate,float vRotate)575 atlantisClearTargetOutput (CompScreen *s,
576                            float xRotate,
577                            float vRotate)
578 {
579     ATLANTIS_SCREEN (s);
580     CUBE_SCREEN (s);
581 
582     UNWRAP (as, cs, clearTargetOutput);
583     (*cs->clearTargetOutput)(s, xRotate, vRotate);
584     WRAP (as, cs, clearTargetOutput, atlantisClearTargetOutput);
585 
586     glClear (GL_DEPTH_BUFFER_BIT);
587 }
588 
589 static void
setLightPosition(CompScreen * s,GLenum light)590 setLightPosition (CompScreen *s,
591                   GLenum light)
592 {
593     float position[] = { 0.0, 0.0, 1.0, 0.0 };
594     float angle = atlantisGetLightInclination(s) * toRadians;
595 
596     if (atlantisGetRotateLighting (s))
597 	angle = 0;
598 
599     position[1] = sinf (angle);
600     position[2] = cosf (angle);
601 
602     glLightfv (light, GL_POSITION, position);
603 }
604 
605 static void
atlantisInitLightPosition(CompScreen * s)606 atlantisInitLightPosition(CompScreen *s)
607 {
608     glPushMatrix ();
609     glLoadIdentity ();
610     setLightPosition (s, GL_LIGHT1);
611     glPopMatrix();
612 }
613 
614 static void
atlantisPaintInside(CompScreen * s,const ScreenPaintAttrib * sAttrib,const CompTransform * transform,CompOutput * output,int size)615 atlantisPaintInside(CompScreen *s,
616 		    const ScreenPaintAttrib *sAttrib,
617 		    const CompTransform *transform,
618 		    CompOutput *output,
619 		    int size)
620 {
621     ATLANTIS_SCREEN (s);
622     CUBE_SCREEN (s);
623 
624     int i, j;
625 
626     float scale, ratio;
627 
628     static const float mat_shininess[] = { 60.0 };
629     static const float mat_specular[] = { 0.6, 0.6, 0.6, 1.0 };
630     static const float mat_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
631     static const float mat_ambient[] = { 0.8, 0.8, 0.9, 1.0 };
632 
633     static const float lmodel_localviewer[] = { 0.0 };
634     static const float lmodel_twoside[] = { 0.0 };
635     static       float lmodel_ambient[] = { 0.4, 0.4, 0.4, 0.4 };
636 
637     ScreenPaintAttrib sA = *sAttrib;
638     CompTransform mT = *transform;
639 
640     int new_hsize = s->hsize * cs->nOutput;
641 
642     int drawDeformation = (as->oldProgress == 0.0f ? getCurrentDeformation(s) :
643 						     getDeformationMode (s));
644 
645     if (atlantisGetShowWater(s))
646 	as->waterHeight = atlantisGetWaterHeight(s) * 100000 - 50000;
647     else
648 	as->waterHeight = 50000;
649 
650     ratio = calculateScreenRatio (s);
651 
652     if (new_hsize < as->hsize || fabsf (ratio - as->ratio) > 0.0001)
653 	updateAtlantis (s);
654     else if (new_hsize > as->hsize)
655     { /* let fish swim in their expanded enclosure without fully resetting */
656 	initWorldVariables (s);
657     }
658 
659     if (atlantisGetShowWater (s) || atlantisGetShowWaterWire (s) ||
660 	atlantisGetShowGround (s))
661     {
662 	updateDeformation (s, drawDeformation);
663 	updateHeight (as->water, atlantisGetShowGround (s) ? as->ground : NULL,
664 	              atlantisGetWaveRipple(s), drawDeformation);
665     }
666 
667     sA.yRotate += cs->invert * (360.0f / size) * (cs->xRotations -
668 	          (s->x * cs->nOutput));
669 
670     (*s->applyScreenTransform)(s, &sA, output, &mT);
671 
672     glPushMatrix();
673 
674     glLoadMatrixf (mT.m);
675 
676     if (!atlantisGetRotateLighting (s))
677 	setLightPosition(s, GL_LIGHT1);
678 
679     glTranslatef (cs->outputXOffset, -cs->outputYOffset, 0.0f);
680 
681     glScalef (cs->outputXScale, cs->outputYScale, 1.0f);
682 
683     Bool enabledCull = FALSE;
684 
685     glPushAttrib (GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT | GL_LIGHTING_BIT);
686 
687     glEnable (GL_BLEND);
688     glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
689 
690     for (i=0; i<4; i++)
691 	lmodel_ambient[i] = atlantisGetLightAmbient(s);
692 
693     glLightModelfv (GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_localviewer);
694     glLightModelfv (GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
695     glLightModelfv (GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
696 
697     if (glIsEnabled (GL_CULL_FACE))
698     {
699 	enabledCull = TRUE;
700     }
701 
702     if (atlantisGetShowWater (s))
703     {
704 	int cull;
705 
706 	glGetIntegerv (GL_CULL_FACE_MODE, &cull);
707 	glEnable (GL_CULL_FACE);
708 
709 	glCullFace (~cull & (GL_FRONT | GL_BACK));
710 	setWaterMaterial (atlantisGetWaterColor (s));
711 	drawWater (as->water, TRUE, FALSE, drawDeformation);
712 	glCullFace (cull);
713     }
714 
715     if (atlantisGetShowGround (s))
716     {
717 	setGroundMaterial (atlantisGetGroundColor (s));
718 
719 	if (atlantisGetRenderWaves (s) && atlantisGetShowWater (s) &&
720 	    !atlantisGetWaveRipple (s))
721 	    drawGround (as->water, as->ground, drawDeformation);
722 	else
723 	    drawGround (NULL, as->ground, drawDeformation);
724     }
725 
726     glPushMatrix();
727 
728     glColor4usv (defaultColor);
729 
730     glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
731     glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
732     glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
733     glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
734 
735     glEnable  (GL_NORMALIZE);
736     glEnable  (GL_DEPTH_TEST);
737     glEnable  (GL_COLOR_MATERIAL);
738     glEnable  (GL_LIGHTING);
739     glEnable  (GL_LIGHT1);
740     glDisable (GL_LIGHT0);
741 
742     glShadeModel(GL_SMOOTH);
743 
744     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
745 
746     glScalef (0.00001f / as->ratio, 0.00001f, 0.00001f / as->ratio);
747 
748     for (i = 0; i < as->numCrabs; i++)
749     {
750 	glPushMatrix ();
751 
752 	CrabTransform (& (as->crab[i]));
753 
754 	scale = as->crab[i].size;
755 	scale /= 6000.0f;
756 	glScalef (scale, scale, scale);
757 	glColor4fv (as->crab[i].color);
758 
759 	initDrawCrab ();
760 	glCallList (as->crabDisplayList);
761 	finDrawCrab ();
762 
763 	glPopMatrix ();
764     }
765 
766     for (i = 0; i < as->numCorals; i++)
767     {
768 	glPushMatrix ();
769 
770 	glTranslatef (as->coral[i].y, as->coral[i].z, as->coral[i].x);
771 	glRotatef (-as->coral[i].psi, 0.0, 1.0, 0.0);
772 
773 	scale = as->coral[i].size;
774 	scale /= 6000.0f;
775 	glScalef (scale, scale, scale);
776 	glColor4fv (as->coral[i].color);
777 
778 	switch (as->coral[i].type) {
779 	case 0:
780 	    initDrawCoral ();
781 	    glCallList (as->coralDisplayList);
782 	    finDrawCoral ();
783 	    break;
784 	case 1:
785 	    initDrawCoral2 ();
786 	    glCallList (as->coral2DisplayList);
787 	    finDrawCoral2 ();
788 	    break;
789 	}
790 
791 	glPopMatrix ();
792     }
793 
794     for (i = 0; i < as->numFish; i++)
795     {
796 	glPushMatrix ();
797 	FishTransform (& (as->fish[i]));
798 	scale = as->fish[i].size;
799 	scale /= 6000.0f;
800 	glScalef (scale, scale, scale);
801 	glColor4fv (as->fish[i].color);
802 
803 	switch (as->fish[i].type)
804 	{
805 	case SHARK:
806 	    DrawShark (& (as->fish[i]), 0);
807 	    break;
808 
809 	case WHALE:
810 	    DrawWhale (& (as->fish[i]), 0);
811 	    break;
812 
813 	case DOLPHIN:
814 	    DrawDolphin (& (as->fish[i]), 0);
815 	    break;
816 
817 	case BUTTERFLYFISH:
818 	    initDrawBFish (as->fish[i].color);
819 	    AnimateBFish  (as->fish[i].htail);
820 	    DrawAnimatedBFish ();
821 	    finDrawBFish ();
822 	    break;
823 
824 	case CHROMIS:
825 	    initDrawChromis (as->fish[i].color);
826 	    AnimateChromis (as->fish[i].htail);
827 	    DrawAnimatedChromis ();
828 	    finDrawChromis ();
829 	    break;
830 
831 	case CHROMIS2:
832 	    initDrawChromis2 (as->fish[i].color);
833 	    AnimateChromis   (as->fish[i].htail);
834 	    DrawAnimatedChromis ();
835 	    finDrawChromis ();
836 	    break;
837 
838 	case CHROMIS3:
839 	    initDrawChromis3 (as->fish[i].color);
840 	    AnimateChromis   (as->fish[i].htail);
841 	    DrawAnimatedChromis ();
842 	    finDrawChromis ();
843 	    break;
844 
845 	case FISH:
846 	    initDrawFish (as->fish[i].color);
847 	    AnimateFish  (as->fish[i].htail);
848 	    DrawAnimatedFish ();
849 	    finDrawFish ();
850 	    break;
851 
852 	case FISH2:
853 	    initDrawFish2 (as->fish[i].color);
854 	    AnimateFish2  (as->fish[i].htail);
855 	    DrawAnimatedFish2 ();
856 	    finDrawFish2 ();
857 	    break;
858 
859 	default:
860 	    break;
861 	}
862 
863 	glPopMatrix();
864     }
865 
866     glEnable(GL_CULL_FACE);
867 
868     for (i = 0; i < as->numAerators; i++)
869     {
870 	for (j = 0; j < as->aerator[i].numBubbles; j++)
871 	{
872 	    glPushMatrix ();
873 
874 	    BubbleTransform (&(as->aerator[i].bubbles[j]));
875 	    scale = as->aerator[i].bubbles[j].size;
876 
877 	    glScalef (scale, scale, scale);
878 	    glColor4fv (as->aerator[i].color);
879 
880 	    glCallList (as->bubbleDisplayList);
881 
882 	    glPopMatrix ();
883 	}
884     }
885 
886     glPopMatrix ();
887 
888     if (atlantisGetShowWater (s) || atlantisGetShowWaterWire (s))
889     {
890 	glEnable (GL_CULL_FACE);
891 	setWaterMaterial (atlantisGetWaterColor (s));
892 	drawWater (as->water, atlantisGetShowWater (s),
893 		atlantisGetShowWaterWire (s), drawDeformation);
894     }
895 
896 
897     if (atlantisGetShowGround (s))
898     {
899 	setGroundMaterial (atlantisGetGroundColor (s));
900 	drawBottomGround (as->ground, cs->distance, -0.5, drawDeformation);
901     }
902     else if (atlantisGetShowWater (s))
903     {
904 	setWaterMaterial (atlantisGetWaterColor (s));
905 	drawBottomWater (as->water, cs->distance, -0.5, drawDeformation);
906     }
907 
908 
909     glDisable (GL_LIGHT1);
910     glDisable (GL_NORMALIZE);
911 
912     if (!s->lighting)
913 	glDisable (GL_LIGHTING);
914 
915     glDisable (GL_DEPTH_TEST);
916 
917     if (enabledCull)
918 	glDisable (GL_CULL_FACE);
919 
920     glPopMatrix ();
921 
922     glPopAttrib ();
923 
924     as->damage = TRUE;
925 
926     UNWRAP (as, cs, paintInside);
927     (*cs->paintInside)(s, sAttrib, transform, output, size);
928     WRAP (as, cs, paintInside, atlantisPaintInside);
929 }
930 
931 static void
atlantisPreparePaintScreen(CompScreen * s,int ms)932 atlantisPreparePaintScreen (CompScreen *s,
933                             int ms)
934 {
935     ATLANTIS_SCREEN (s);
936 
937     int i, j;
938 
939     Bool currentDeformation = getCurrentDeformation (s);
940     int oldhsize = as->hsize;
941 
942     updateWater (s, (float) ms / 1000.0f);
943     updateGround (s, (float) ms / 1000.0f);
944 
945     /* temporary change for animals inside */
946     if (currentDeformation == DeformationCylinder && as->oldProgress > 0.9)
947     {
948 	as->hsize *= 32 / as->hsize;
949 	as->arcAngle = 360.0f / as->hsize;
950 	as->sideDistance = as->radius * as->ratio;
951     }
952     else if (currentDeformation == DeformationSphere)
953     {
954 	/* treat enclosure as a cylinder */
955 	as->hsize *= 32 / as->hsize;
956 	as->arcAngle = 360.0f / as->hsize;
957 	as->sideDistance = as->radius * as->ratio;
958 
959     }
960 
961     for (i = 0; i < as->numFish; i++)
962     {
963 	FishPilot (s, i);
964 
965 	/* animate fish tails */
966 	if (as->fish[i].type <= FISH2)
967 	{
968 	    as->fish[i].htail = fmodf (as->fish[i].htail + 0.00025 *
969 	                               as->fish[i].speed * as->speedFactor, 1);
970 	}
971     }
972 
973     for (i = 0; i < as->numCrabs; i++)
974     {
975 	CrabPilot (s, i);
976     }
977 
978     for (i = 0; i < as->numCorals; i++)
979     {
980 	as->coral[i].z = getGroundHeight (s, as->coral[i].x, as->coral[i].y);
981     }
982 
983     for (i = 0; i < as->numAerators; i++)
984     {
985 	aeratorRec * aerator = &(as->aerator[i]);
986 	float bottom = getGroundHeight (s, aerator->x, aerator->y);
987 
988 	if (aerator->z < bottom)
989 	{
990 	    for (j = 0; j < aerator->numBubbles; j++)
991 	    {
992 		if (aerator->bubbles[j].counter == 0)
993 		    aerator->bubbles[j].z = bottom;
994 	    }
995 	}
996 	aerator->z = bottom;
997 	for (j = 0; j < aerator->numBubbles; j++)
998 	{
999 	    BubblePilot(s, i, j);
1000 	}
1001     }
1002 
1003     as->hsize = oldhsize;
1004     as->arcAngle = 360.0f / as->hsize;
1005     as->sideDistance = as->topDistance * as->ratio;
1006 
1007     UNWRAP (as, s, preparePaintScreen);
1008     (*s->preparePaintScreen)(s, ms);
1009     WRAP (as, s, preparePaintScreen, atlantisPreparePaintScreen);
1010 }
1011 
1012 static void
atlantisDonePaintScreen(CompScreen * s)1013 atlantisDonePaintScreen (CompScreen * s)
1014 {
1015     ATLANTIS_SCREEN (s);
1016 
1017     if (as->damage)
1018     {
1019 	damageScreen (s);
1020 	as->damage = FALSE;
1021     }
1022 
1023     UNWRAP (as, s, donePaintScreen);
1024     (*s->donePaintScreen)(s);
1025     WRAP (as, s, donePaintScreen, atlantisDonePaintScreen);
1026 }
1027 
1028 static Bool
atlantisInitDisplay(CompPlugin * p,CompDisplay * d)1029 atlantisInitDisplay (CompPlugin *p,
1030                      CompDisplay *d)
1031 {
1032     AtlantisDisplay *ad;
1033 
1034     if (!checkPluginABI ("core", CORE_ABIVERSION) ||!checkPluginABI ("cube",
1035 	    CUBE_ABIVERSION))
1036 	return FALSE;
1037 
1038     if (!getPluginDisplayIndex (d, "cube", &cubeDisplayPrivateIndex))
1039 	return FALSE;
1040 
1041     ad = malloc (sizeof(AtlantisDisplay));
1042 
1043     if (!ad)
1044 	return FALSE;
1045 
1046     ad->screenPrivateIndex = allocateScreenPrivateIndex (d);
1047 
1048     if (ad->screenPrivateIndex < 0)
1049     {
1050 	free (ad);
1051 	return FALSE;
1052     }
1053 
1054     d->base.privates[atlantisDisplayPrivateIndex].ptr = ad;
1055 
1056     return TRUE;
1057 }
1058 
1059 static void
atlantisFiniDisplay(CompPlugin * p,CompDisplay * d)1060 atlantisFiniDisplay (CompPlugin *p,
1061                      CompDisplay *d)
1062 {
1063     ATLANTIS_DISPLAY (d);
1064 
1065     freeScreenPrivateIndex (d, ad->screenPrivateIndex);
1066     free (ad);
1067 }
1068 
1069 static Bool
atlantisInitScreen(CompPlugin * p,CompScreen * s)1070 atlantisInitScreen (CompPlugin *p,
1071                     CompScreen *s)
1072 {
1073     static const float ambient[]  = { 0.0, 0.0, 0.0, 0.0 };
1074     static const float diffuse[]  = { 1.0, 1.0, 1.0, 1.0 };
1075     static const float specular[] = { 0.6, 0.6, 0.6, 1.0 };
1076 
1077     AtlantisScreen *as;
1078 
1079     ATLANTIS_DISPLAY (s->display);
1080     CUBE_SCREEN (s);
1081 
1082     as = malloc (sizeof (AtlantisScreen));
1083 
1084     if (!as)
1085 	return FALSE;
1086 
1087     s->base.privates[ad->screenPrivateIndex].ptr = as;
1088 
1089     as->damage = FALSE;
1090 
1091     glLightfv (GL_LIGHT1, GL_AMBIENT, ambient);
1092     glLightfv (GL_LIGHT1, GL_DIFFUSE, diffuse);
1093     glLightfv (GL_LIGHT1, GL_SPECULAR, specular);
1094     atlantisInitLightPosition (s);
1095 
1096     initAtlantis (s);
1097 
1098     atlantisSetSpeedFactorNotify  (s, atlantisSpeedFactorOptionChange);
1099 
1100     atlantisSetLowPolyNotify (s, atlantisLowPolyOptionChange);
1101 
1102     atlantisSetCreatureNumberNotify (s, atlantisScreenOptionChange);
1103     atlantisSetCreatureSizeNotify   (s, atlantisScreenOptionChange);
1104     atlantisSetCreatureColorNotify  (s, atlantisScreenOptionChange);
1105     atlantisSetCreatureTypeNotify   (s, atlantisScreenOptionChange);
1106 
1107     atlantisSetPlantNumberNotify (s, atlantisScreenOptionChange);
1108     atlantisSetPlantSizeNotify   (s, atlantisScreenOptionChange);
1109     atlantisSetPlantColorNotify  (s, atlantisScreenOptionChange);
1110     atlantisSetPlantTypeNotify   (s, atlantisScreenOptionChange);
1111 
1112     atlantisSetRescaleWidthNotify (s, atlantisScreenOptionChange);
1113 
1114     atlantisSetRotateLightingNotify   (s, atlantisLightingOptionChange);
1115     atlantisSetLightInclinationNotify (s, atlantisLightingOptionChange);
1116 
1117 
1118     WRAP (as, s, donePaintScreen, atlantisDonePaintScreen);
1119     WRAP (as, s, preparePaintScreen, atlantisPreparePaintScreen);
1120     WRAP (as, cs, clearTargetOutput, atlantisClearTargetOutput);
1121     WRAP (as, cs, paintInside, atlantisPaintInside);
1122 
1123     return TRUE;
1124 }
1125 
1126 static void
atlantisFiniScreen(CompPlugin * p,CompScreen * s)1127 atlantisFiniScreen (CompPlugin *p,
1128                     CompScreen *s)
1129 {
1130     ATLANTIS_SCREEN (s);
1131     CUBE_SCREEN (s);
1132 
1133     freeAtlantis (s);
1134 
1135     UNWRAP (as, s, donePaintScreen);
1136     UNWRAP (as, s, preparePaintScreen);
1137     UNWRAP (as, cs, clearTargetOutput);
1138     UNWRAP (as, cs, paintInside);
1139 
1140     free (as);
1141 }
1142 
1143 static Bool
atlantisInit(CompPlugin * p)1144 atlantisInit (CompPlugin * p)
1145 {
1146     atlantisDisplayPrivateIndex = allocateDisplayPrivateIndex ();
1147 
1148     if (atlantisDisplayPrivateIndex < 0)
1149 	return FALSE;
1150 
1151     return TRUE;
1152 }
1153 
1154 static void
atlantisFini(CompPlugin * p)1155 atlantisFini (CompPlugin * p)
1156 {
1157     if (atlantisDisplayPrivateIndex >= 0)
1158 	freeDisplayPrivateIndex (atlantisDisplayPrivateIndex);
1159 }
1160 
1161 static CompBool
atlantisInitObject(CompPlugin * p,CompObject * o)1162 atlantisInitObject (CompPlugin *p,
1163                     CompObject *o)
1164 {
1165     static InitPluginObjectProc dispTab[] = {
1166 	(InitPluginObjectProc) 0, /* InitCore */
1167 	(InitPluginObjectProc) atlantisInitDisplay,
1168 	(InitPluginObjectProc) atlantisInitScreen
1169     };
1170 
1171     RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
1172 }
1173 
1174 static void
atlantisFiniObject(CompPlugin * p,CompObject * o)1175 atlantisFiniObject (CompPlugin *p,
1176                     CompObject *o)
1177 {
1178     static FiniPluginObjectProc dispTab[] = {
1179 	(FiniPluginObjectProc) 0, /* FiniCore */
1180 	(FiniPluginObjectProc) atlantisFiniDisplay,
1181 	(FiniPluginObjectProc) atlantisFiniScreen
1182     };
1183 
1184     DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
1185 }
1186 
1187 CompPluginVTable atlantisVTable = {
1188 
1189     "atlantis",
1190     0,
1191     atlantisInit,
1192     atlantisFini,
1193     atlantisInitObject,
1194     atlantisFiniObject,
1195     0,
1196     0
1197 };
1198 
1199 CompPluginVTable *
getCompPluginInfo(void)1200 getCompPluginInfo (void)
1201 {
1202     return &atlantisVTable;
1203 }
1204