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  * Original water.c code by Dennis Kasprzyk.
30  */
31 
32 /*
33  * Water amplitude calculation, ripple effect, deformation
34  * code, and some other modifications by David Mikos.
35  */
36 
37 
38 #include "atlantis-internal.h"
39 #include "math.h"
40 #include "atlantis_options.h"
41 
42 static void
genTriMesh(Vertex * vertices,int size,unsigned int * indices,int subdiv,float r,Vertex a)43 genTriMesh (Vertex       *vertices,
44             int		 size,
45 	    unsigned int *indices,
46 	    int		 subdiv,
47 	    float	 r,
48 	    Vertex	 a)
49 {
50     int          nRow;
51     Vertex       *v;
52     unsigned int *idx;
53     int          i, j, k;
54 
55     float ang, d, dy, dx, y, x;
56 
57     float angStep = 2 * PI / size;
58 
59     int c  = 1; /* counter for how many points already indexed */
60     int c2 = 0; /* similar to c but for indices add one for each layer */
61     int oc = 1;
62     int t;
63 
64     if (subdiv < 0)
65 	return;
66     if (!vertices || !indices)
67 	return;
68 
69     nRow = (subdiv) ? (2 << (subdiv - 1)) : 1;
70 
71     v =   vertices;
72     idx = indices;
73 
74     v[0] = a;
75 
76 
77     /* initialize coordinates, spiralling around from centre */
78     for (i = 1; i <= nRow; i++)
79     {
80 	ang = PI / size;
81 	d   = i * r/nRow;
82 
83 	for (j = 0; j < size; j++)
84 	{
85 	    x = d * cosf (ang);
86 	    y = d * sinf (ang);
87 
88 	    ang -= angStep;
89 
90 	    dx = (d * cosf (ang) - x) / i;
91 	    dy = (d * sinf (ang) - y) / i;
92 
93 	    c2 = i * j + c;
94 	    for (k = 0; k < i; k++, c2++)
95 	    {
96 		v[c2].v[0] = y + k * dy + a.v[0];
97 		v[c2].v[1] = a.v[1];
98 		v[c2].v[2] = x + k*dx + a.v[2];
99 	    }
100 	}
101 
102 	c += i * size;
103     }
104 
105     c = 1;
106     c2 = 0;
107 
108     int out = 1; /* outer */
109     int inn = 0; /* inner */
110 
111     for (i = 1; i <= nRow; i++)
112     {
113 	for (j = 0; j < size; j++)
114 	{
115 	    t = (2 * i - 1) * j + c2;
116 	    for (k = 0; k < 2 * i - 1; k++)
117 	    {
118 		idx[3 * (t + k) + 0] = out;
119 		idx[3 * (t + k) + 1] = inn;
120 
121 		if (k % 2 == 0)
122 		{
123 		    out++;
124 		    if (out >= c + i * size)
125 			out -= i * size;
126 
127 		    idx[3 * (t + k) + 2] = out;
128 		}
129 		else
130 		{
131 		    inn++;
132 		    if (inn >= c)
133 			inn -= (i - 1) * size;
134 
135 		    idx[3 * (t + k) + 2] = inn;
136 		}
137 	    }
138 	}
139 
140 	oc = c;
141 
142 	c += i * size;
143 	c2 += (2 * i - 1) * size;
144 
145 	inn = oc;
146 	out = c;
147     }
148 
149 }
150 
151 static void
genTriWall(Vertex * lVer,Vertex * hVer,unsigned int * indices,unsigned int idxBaseL,unsigned int idxBaseH,int subdiv,float ang,Vertex a,Vertex b,Vertex c,Vertex d)152 genTriWall (Vertex       *lVer,
153 	    Vertex       *hVer,
154 	    unsigned int *indices,
155 	    unsigned int idxBaseL,
156 	    unsigned int idxBaseH,
157 	    int          subdiv,
158 	    float        ang,
159 	    Vertex       a,
160 	    Vertex       b,
161 	    Vertex       c,
162 	    Vertex       d)
163 {
164     int   nRow;
165     int   i, k;
166     float vab[3], vcd[3];
167 
168     if (subdiv < 0)
169 	return;
170     if (!lVer || !hVer || !indices)
171 	return;
172 
173     nRow = pow (2, subdiv);
174 
175     for (i = 0; i < 3; i++)
176     {
177 	vab[i] = b.v[i] - a.v[i];
178 	vab[i] /= nRow;
179 	vcd[i] = d.v[i] - c.v[i];
180 	vcd[i] /= nRow;
181     }
182 
183     for (i = 0; i <= nRow; i++)
184     {
185 	for (k = 0; k < 3; k++)
186 	{
187 	    lVer[i].v[k] = a.v[k] + (i * vab[k]);
188 	    hVer[i].v[k] = c.v[k] + (i * vcd[k]);
189 	}
190 
191 	lVer[i].n[0] = sinf (ang);
192 	lVer[i].n[1] = 0;
193 	lVer[i].n[2] = cosf (ang);
194 
195 	hVer[i].n[0] = lVer[i].n[0];
196 	hVer[i].n[1] = lVer[i].n[1];
197 	hVer[i].n[2] = lVer[i].n[2];
198     }
199 
200     for (i = 0; i < nRow; i++)
201     {
202 	indices[(i * 6)]     = idxBaseL + i;
203 	indices[(i * 6) + 1] = idxBaseH + i;
204 	indices[(i * 6) + 2] = idxBaseH + i + 1;
205 	indices[(i * 6) + 3] = idxBaseL + i + 1;
206 	indices[(i * 6) + 4] = idxBaseL + i;
207 	indices[(i * 6) + 5] = idxBaseH + i + 1;
208     }
209 }
210 
211 static void
updateRipple(Water * w,int size)212 updateRipple (Water *w,
213               int size)
214 {
215     int i;
216 
217     if (!w->rippleFactor)
218 	return;
219 
220     for (i = 0; i < w->nSVer; i++)
221 	w->rippleFactor[i] = NRAND (1001) - 500;
222 }
223 
224 static Water *
genWater(int size,int sDiv,float distance,float bottom,Bool initRipple)225 genWater (int size,
226           int sDiv,
227           float distance,
228           float bottom,
229           Bool initRipple)
230 {
231     Water  *w;
232     int    i, j;
233 
234     float  ang, r, aStep;
235     int    nVer, nRow, nIdx, nWVer, nWIdx;;
236     Vertex a = {{ 0.0, 0.0, 0.0 }};
237     Vertex b = {{ 0.0, 0.0, 0.0 }};
238     Vertex c = {{ 0.0, 0.0, 0.0 }};
239     Vertex d = {{ 0.0, bottom, 0.0 }};
240     Vertex e = {{ 0.0, bottom, 0.0 }};
241 
242     Vertex       *wv;
243     unsigned int *wi;
244 
245     if (sDiv < 0)
246 	return NULL;
247 
248     if (size < 3)
249 	return NULL;
250 
251     w = malloc (sizeof (Water));
252     if (!w)
253 	return NULL;
254 
255     nRow = (sDiv) ? (2 << (sDiv - 1)) : 1;
256     nVer = size * ((nRow * (nRow + 1)) / 2) + 1;
257 
258     nIdx = 3 * size * (nRow * nRow);
259 
260     nWIdx = pow (2, sDiv + 1) * 3;
261     nWVer = pow (2, sDiv + 1) + 2;
262 
263     w->nBIdx = nRow * size;
264 
265     w->nVertices  = nVer + (nWVer) * size;
266     w->nIndices   = nIdx + (nWIdx) * size + w->nBIdx;
267 
268     w->nSVer = nVer;
269     w->nSIdx = nIdx;
270     w->nWVer = nWVer * size;
271     w->nWIdx = nWIdx * size;
272 
273     w->size     = size;
274     w->distance = distance;
275     w->sDiv     = sDiv;
276 
277     w->wave1 = 0.0;
278     w->wave2 = 0.0;
279 
280     w->vertices = calloc (1, sizeof (Vertex) * w->nVertices);
281     if (!w->vertices)
282     {
283 	free (w);
284 	return NULL;
285     }
286 
287     w->indices = calloc (1, sizeof (int) * w->nIndices);
288     if (!w->indices)
289     {
290 	free (w->vertices);
291 	free (w);
292 	return NULL;
293     }
294 
295     w->vertices2 = NULL;
296     w->indices2  = NULL;
297 
298     r = distance / cosf (M_PI / size);
299     ang = M_PI / size;
300     aStep = 2 * M_PI / size;
301 
302     wv = w->vertices + nVer;
303     wi = w->indices  + nIdx;
304 
305     for (i = 0; i < size; i++)
306     {
307 	d.v[0] = b.v[0] = sinf (ang - aStep) * r;
308 	d.v[2] = b.v[2] = cosf (ang - aStep) * r;
309 
310 	e.v[0] = c.v[0] = sinf (ang) * r;
311 	e.v[2] = c.v[2] = cosf (ang) * r;
312 
313 	genTriWall (wv + (i * nWVer / 2), wv + ((i + size) * nWVer / 2),
314 		    wi + (i * nWIdx), nVer + (i * nWVer / 2),
315 		    nVer + ((i + size) * nWVer / 2), sDiv,
316 		    ang - aStep / 2, b, c, d, e);
317 
318 	ang += aStep;
319     }
320     genTriMesh (w->vertices, size, w->indices, sDiv, r, a);
321 
322 
323     /* bottom face indices for cylinder deformation */
324     for (i = 0; i < size; i++)
325     {
326 	wi = w->indices + w->nSIdx + w->nWIdx + i * nRow;
327 
328 	for (j = 0; j < nRow; j++)
329 	    wi[j] = w->nSVer + ((size - 1 - i + size) * nWVer / 2) +
330 		    nRow - 1 - j;
331     }
332 
333 
334     w->rippleTimer = 0;
335 
336     if (initRipple)
337     {
338 	w->rippleFactor = calloc (1, sizeof (int *) * w->nSVer);
339 
340 	if (!w->rippleFactor)
341 	{
342 	    free (w->vertices);
343 	    free (w->indices);
344 	    free (w);
345 	    return NULL;
346 	}
347 	updateRipple(w, size);
348     }
349     else
350 	w->rippleFactor = NULL;
351 
352     return w;
353 }
354 
355 void
freeWater(Water * w)356 freeWater (Water *w)
357 {
358     if (!w)
359 	return;
360 
361     if (w->vertices)
362 	free (w->vertices);
363     if (w->indices)
364 	free (w->indices);
365     if (w->vertices2)
366 	free (w->vertices2);
367     if (w->indices2)
368 	free (w->indices2);
369     if (w->rippleFactor)
370 	free(w->rippleFactor);
371 
372     w->vertices     = NULL;
373     w->vertices2    = NULL;
374     w->indices      = NULL;
375     w->indices2     = NULL;
376     w->rippleFactor = NULL;
377 }
378 
379 static void
setAmplitude(Vertex * v,float bh,float wt,float swt,float wa,float swa,float wf,float swf,int ripple,int ripple2)380 setAmplitude (Vertex *v,
381 	      float  bh,
382 	      float  wt,
383 	      float  swt,
384 	      float  wa,
385 	      float  swa,
386 	      float  wf,
387 	      float  swf,
388 	      int ripple,
389 	      int ripple2)
390 {
391     float  dx, dz, d, c;
392 
393     v->v[1] = bh + (wa  * sinf (wt  + wf  * v->v[0] * v->v[2])) +
394 		   (swa * sinf (swt + swf * v->v[0] * v->v[2]));
395 
396     v->v[1] = MIN (0.5, MAX (-0.5, v->v[1]));
397 
398     c =  wa  * cosf (wt  + wf  * v->v[0] * v->v[2]) * wf;
399     c += swa * cosf (swt + swf * v->v[0] * v->v[2]) * swf;
400 
401     dx = c * v->v[2];
402     dz = c * v->v[0];
403 
404     /* actual normal
405     v->n[0] = -dx;
406     v->n[1] = 1;
407     v->n[2] = -dz;
408     */
409 
410     v->n[0] = -0.2 * (v->v[1] - bh);
411     v->n[1] = 5;
412     v->n[2] = -0.2 * (v->v[1] - bh);
413 
414     if (ripple)
415     {
416 	float sum;
417 	float rFactor = (ripple / 1000.0f);
418 
419 	v->n[0] -= (2 * dx + 3) * rFactor + 3 * dx;
420 	rFactor = (ripple2 / 1000.0f);
421 	v->n[2] -= (2 * dz + 3) * rFactor + 3 * dz;
422 
423 	if (ripple & 1)
424 	    rFactor = (ripple / 1000.0f);
425 
426 	/* for more equal normal vector lengths */
427 	sum = (abs (ripple) + abs (ripple2)) / 2000.0f;
428 
429 	v->n[1] *= 0.8 + 0.2 * (1 - sum) * 2 * fabsf (rFactor);
430     }
431     else
432     {
433 	 v->n[0] -= (5 * dx);
434 	 v->n[2] -= (5 * dz);
435     }
436 
437     d = sqrtf ((v->n[0] * v->n[0]) + (v->n[1] * v->n[1]) +
438                (v->n[2] * v->n[2]));
439 
440     if (d == 0.0f)
441 	return;
442 
443     v->n[0] /= d;
444     v->n[1] /= d;
445     v->n[2] /= d;
446 }
447 
448 
449 static void
deformCylinder(CompScreen * s,Water * w,float progress)450 deformCylinder(CompScreen *s,
451                Water  *w,
452                float progress)
453 {
454     ATLANTIS_SCREEN (s);
455     CUBE_SCREEN (s);
456 
457     int          nVer, nWVer, nRow, nRowS, subdiv;
458     Vertex       *v;
459     int          i, j, k, l;
460 
461     float  ang, r, aStep;
462 
463     Vertex       *wv;
464 
465     int size = as->hsize;
466 
467     float ratioRadiusToSideDist;
468 
469     //Vertex a = {{ 0.0, 0.0, 0.0 }};
470     Vertex b = {{ 0.0, 0.0, 0.0 }};
471     Vertex c = {{ 0.0, 0.0, 0.0 }};
472 
473     float    vab[3];
474 
475     int c1 = 1; /* counter for how many points already indexed */
476     int c2 = 1; /* similar to c but for indices add one for each layer */
477 
478     float dist, x, y, dx, dy;
479 
480 
481     if (!w)
482 	return;
483     if (w->sDiv < 0)
484 	return;
485     if (!w->vertices)
486 	return;
487     if (w->size != size)
488 	return;
489 
490     subdiv = w->sDiv;
491     nRow = (subdiv)?(2 << (subdiv - 1)) : 1;
492     nVer = size * ((nRow * (nRow + 1)) / 2) + 1;
493 
494     nWVer = pow (2, subdiv + 1) + 2;
495 
496     ratioRadiusToSideDist = as->radius * as->ratio / as->sideDistance;
497 
498     r = cs->distance / cosf (M_PI / size);
499     ang = M_PI / size;
500     aStep = 2 * M_PI / size;
501 
502     wv = w->vertices + w->nSVer;
503     v =  w->vertices;
504 
505     //v[0] = a;
506 
507     /* new coordinates, spiralling around from centre */
508     for (i = 1; i <= nRow; i++)
509     {
510 	ang = PI / size;
511 	dist = i * r / nRow;
512 
513 	for (j = 0; j < size; j++)
514 	{
515 	    x = cosf (ang);
516 	    y = sinf (ang);
517 
518 	    ang -= aStep;
519 	    dx = (cosf (ang) - x) / i;
520 	    dy = (sinf (ang) - y) / i;
521 
522 	    c2 = i * j + c1;
523 	    for (k = 0; k < i; k++, c2++)
524 	    {
525 		v[c2].v[0] = y + k * dy;
526 		v[c2].v[2] = x + k * dx;
527 
528 		v[c2].v[0] += progress * (sinf (ang + aStep -
529 		                                (k * aStep) / i) - v[c2].v[0]);
530 		v[c2].v[0] *= dist;
531 
532 		v[c2].v[2] += progress * (cosf (ang + aStep -
533 		                                (k * aStep) / i) - v[c2].v[2]);
534 		v[c2].v[2] *= dist;
535 
536 		/* translation not needed*/
537 		/*
538 		v[c2].v[0] += a[0];
539 		v[c2].v[2] += a[2];
540 		*/
541 	    }
542 	}
543 
544 	c1 += i * size;
545     }
546 
547     ang = M_PI / size;
548 
549     for (l = 0; l < size; l++)
550     {
551 	v = w->vertices + (l * nVer);
552 
553 	b.v[0] = sinf (ang - aStep);
554 	b.v[2] = cosf (ang - aStep);
555 
556 	c.v[0] = sinf (ang);
557 	c.v[2] = cosf (ang);
558 
559 	for (i = 0; i < 3; i++)
560 	{
561 	    vab[i] = b.v[i];// - a.v[i];
562 	    vab[i] /= nRow - 1.0;
563 	}
564 
565 
566 	Vertex *lVer = wv + (l * nWVer / 2);
567 	Vertex *hVer = wv + ((l + size) * nWVer / 2);
568 
569 	/*side walls */
570 	    nRowS = pow (2, subdiv);
571 
572 	    for (i = 0; i < 3; i++)
573 	    {
574 		vab[i] = c.v[i] - b.v[i];
575 		vab[i] /= nRowS;
576 	    }
577 
578 	    for (i = 0; i <= nRowS; i++)
579 	    {
580 		for (k = 0; k < 3; k += 2)
581 		{
582 		    lVer[i].v[k] = b.v[k] + (i * vab[k]);
583 		}
584 
585 		float th = atan2f(lVer[i].v[0], lVer[i].v[2]);
586 
587 
588 		lVer[i].v[0] += progress * (sinf (ang - aStep + i * aStep /
589 		                                  nRowS) - lVer[i].v[0]);
590 		lVer[i].v[2] += progress * (cosf (ang - aStep + i * aStep /
591 		                                  nRowS) - lVer[i].v[2]);
592 		lVer[i].v[0] *= r;
593 		lVer[i].v[2] *= r;
594 
595 		for (k = 0; k < 3; k += 2)
596 		    hVer[i].v[k] = lVer[i].v[k];
597 
598 
599 		lVer[i].n[0] = (1 - progress) * sinf (ang) +
600 			       progress * sinf (th);
601 		lVer[i].n[1] = 0;
602 		lVer[i].n[2] = (1-progress)*cosf(ang) +
603 			       progress*cosf(th);
604 
605 		hVer[i].n[0] = lVer[i].n[0];
606 		hVer[i].n[1] = lVer[i].n[1];
607 		hVer[i].n[2] = lVer[i].n[2];
608 	    }
609 
610 	ang += aStep;
611     }
612 }
613 
614 static void
deformSphere(CompScreen * s,Water * w,float progress,float waterBottom,Bool groundNormals)615 deformSphere(CompScreen *s,
616              Water  *w,
617              float progress,
618              float waterBottom,
619              Bool groundNormals)
620 {
621     ATLANTIS_SCREEN (s);
622     CUBE_SCREEN (s);
623 
624     int          nWVer, nWIdx, nWVer2, nWIdx2, nRow, nRowS, subdiv;
625     Vertex       *v;
626     int          i, j, k, l;
627 
628     float        ang, r, aStep;
629 
630     Vertex       *wv;
631 
632     int size = as->hsize;
633 
634     float ratioRadiusToSideDist, sphereRadiusFactor, sphereRadiusFactor2;
635 
636     //Vertex a = {{ 0.0, 0.0, 0.0 }};
637     Vertex b = {{ 0.0, 0.0, 0.0 }};
638     Vertex c = {{ 0.0, 0.0, 0.0 }};
639 
640     float    vab[3];
641 
642     int c1 = 1; /* counter for how many points already indexed */
643     int c2 = 1; /* similar to c but for indices add one for each layer */
644 
645     float dist, factor, x, y, dx, dy;
646 
647     if (!w)
648 	return;
649     if (w->sDiv < 0)
650 	return;
651     if (!w->vertices)
652 	return;
653     if (w->size != size)
654 	return;
655 
656     subdiv = w->sDiv;
657     nRow = (subdiv)?(2 << (subdiv - 1)) : 1;
658 
659     nWIdx = pow (2, subdiv + 1) * 3;
660     nWVer = pow (2, subdiv + 1) + 2;
661 
662     nWIdx2 = nWIdx * nRow * 2;
663     nWVer2 = nWVer * (nRow + 1) / 2;
664 
665     ratioRadiusToSideDist = as->radius * as->ratio / as->sideDistance;
666 
667     sphereRadiusFactor  = as->radius / 100000;
668     sphereRadiusFactor  = progress * (hypotf (sphereRadiusFactor, 0.5f) /
669 			  sphereRadiusFactor - 1);
670     sphereRadiusFactor2 = sphereRadiusFactor * cosf (w->bh*PI)+1;
671 
672     r = cs->distance / cosf (M_PI / size);
673     ang = M_PI / size;
674     aStep = 2 * M_PI / size;
675 
676     wv = w->vertices + w->nSVer;
677 
678     if (nWVer2 * size != w->nWVer2 && w->vertices2)
679     {
680 	free (w->vertices2);
681 	w->vertices2 = NULL;
682     }
683     if (nWIdx2 * size != w->nWIdx2 && w->indices2)
684     {
685 	free (w->indices2);
686 	w->indices2 = NULL;
687     }
688 
689     w->nWVer2 = nWVer2 * size;
690     w->nWIdx2 = nWIdx2 * size;
691 
692     w->nBIdx2 = nRow * size;
693 
694     if (!w->vertices2)
695     {
696 	w->vertices2 = calloc (1, sizeof (Vertex) * w->nWVer2);
697 	if (!w->vertices2)
698 	    return;
699     }
700 
701     if (!w->indices2)
702     {
703 	w->indices2 = calloc (1, sizeof (int) * (w->nWIdx2 + w->nBIdx2));
704     	if (!w->indices2)
705     	    return;
706     }
707 
708     v = w->vertices;
709 
710     //v[0] = a;
711 
712     /* new coordinates, spiralling around from centre */
713     for (i = 1; i <= nRow; i++)
714     {
715 	ang = PI / size;
716 	dist = i * r / nRow;
717 	factor = dist * sphereRadiusFactor2;
718 
719 	for (j = 0; j < size; j++)
720 	{
721 	    x = cosf (ang);
722 	    y = sinf (ang);
723 
724 	    ang -= aStep;
725 	    dx = (cosf (ang) - x) / i;
726 	    dy = (sinf (ang) - y) / i;
727 
728 	    c2 = i * j + c1;
729 	    for (k = 0; k < i; k++, c2++)
730 	    {
731 		v[c2].v[0] = y + k * dy;
732 		v[c2].v[2] = x + k * dx;
733 
734 		v[c2].v[0] += progress * (sinf (ang + aStep -
735 		                                (k * aStep) / i) - v[c2].v[0]);
736 		v[c2].v[2] += progress * (cosf (ang + aStep -
737 		                                (k * aStep) / i) - v[c2].v[2]);
738 		v[c2].v[0] *= factor;
739 		v[c2].v[2] *= factor;
740 
741 		/* translation not needed*/
742 		/*
743 		v[c2].v[0] += a[0];
744 		v[c2].v[2] += a[2];
745 		*/
746 	    }
747 	}
748 
749 	c1 += i * size;
750     }
751 
752     ang = M_PI / size;
753 
754     for (l = 0; l < size; l++)
755     {
756 	unsigned int * indices = w->indices2 + (l * nWIdx);
757 	unsigned int idxBaseL = (l * nWVer / 2);
758 
759 	b.v[0] = sinf (ang - aStep);
760 	b.v[2] = cosf (ang - aStep);
761 
762 	c.v[0] = sinf (ang);
763 	c.v[2] = cosf (ang);
764 
765 	Vertex *lVer = w->vertices2 + (l * nWVer2 / (nRow + 1));
766 
767 	/*side walls */
768 	nRowS = pow (2, subdiv);
769 
770 	for (i = 0; i < 3; i++)
771 	{
772 	    vab[i] = c.v[i] - b.v[i];
773 	    vab[i] /= nRowS;
774 	}
775 
776 	for (i = 0; i <= nRowS; i++)
777 	{
778 	    float th;
779 
780 	    for (k = 0; k < 3; k++)
781 		lVer[i].v[k] = b.v[k] + (i * vab[k]);
782 
783 	    lVer[i].v[0] += progress * (sinf (ang - aStep + i * aStep /
784 	                                      nRowS) - lVer[i].v[0]);
785 	    lVer[i].v[2] += progress * (cosf (ang - aStep + i * aStep /
786 	                                      nRowS) - lVer[i].v[2]);
787 
788 	    th = atan2f (lVer[i].v[0], lVer[i].v[2]);
789 
790 	    lVer[i].n[0] = (1 - progress) * sinf (ang - aStep / 2) +
791 			   progress * sinf (th);
792 	    lVer[i].n[1] = 0;
793 	    lVer[i].n[2] = (1 - progress) * cosf (ang - aStep / 2) +
794 			   progress * cosf (th);
795 
796 	    for (j = nRow; j >= 0; j--)
797 	    {
798 		Vertex *hVer = lVer + j * (size * nWVer2 / (nRow + 1));
799 
800 		float hFactor;
801 		float p = ((float) j) / nRow;
802 
803 		for (k = 0; k < 3; k++)
804 		{
805 		    hVer[i].v[k] = lVer[i].v[k];
806 		    hVer[i].n[k] = lVer[i].n[k];
807 		}
808 
809 		hVer[i].n[0] = p * ((1 - progress) * sinf (ang - aStep / 2) +
810 			       progress * sinf (th));
811 		hVer[i].n[1] = 1 - p;
812 		hVer[i].n[2] = p * ((1 - progress) * cosf (ang - aStep / 2) +
813 			       progress * cosf(th));
814 
815 		hFactor = r * (sphereRadiusFactor * cosf ((w->bh - j *
816 			  (w->bh - waterBottom) / nRow) * PI)+1);
817 
818 		for (k = 0; k < 3; k += 2)
819 		    hVer[i].v[k] *= hFactor;
820 	    }
821 	}
822 
823 	for (j = 0; j < nRow; j++)
824 	{
825 	    unsigned int idxBaseH = idxBaseL + size * nWVer / 2;
826 
827 	    for (i = 0; i < nRowS; i++)
828 	    {
829 		indices[(i * 6)]     = idxBaseL + i;
830 		indices[(i * 6) + 1] = idxBaseH + i;
831 		indices[(i * 6) + 2] = idxBaseH + i + 1;
832 		indices[(i * 6) + 3] = idxBaseL + i + 1;
833 		indices[(i * 6) + 4] = idxBaseL + i;
834 		indices[(i * 6) + 5] = idxBaseH + i + 1;
835 	    }
836 	    idxBaseL = idxBaseH;
837 	    indices += 2 * nWIdx2 / nRow;
838 	}
839 
840 	/* bottom face indices */
841 	idxBaseL = (nRow - 1) * size * nWVer / 2;
842 	indices = w->indices2 + w->nWIdx2 + (l * nRow);
843 
844 	for (j = 0; j < nRow; j++)
845 	    indices[j] = idxBaseL + ((size - 1 - l + size) * nWVer / 2) +
846 			 nRow - 1 - j;
847 
848 	ang += aStep;
849     }
850 }
851 
852 void
updateHeight(Water * w,Water * w2,Bool rippleEffect,int currentDeformation)853 updateHeight (Water *w,
854               Water *w2,
855               Bool rippleEffect,
856               int currentDeformation)
857 {
858     int offset;
859 
860     Bool useOtherWallVertices;
861     Vertex * vertices;
862 
863     int i, j;
864 
865     if (!w)
866 	return;
867 
868     offset = w->nSVer / 2 + 1;
869     rippleEffect = (rippleEffect && w->rippleFactor);
870 
871     useOtherWallVertices = (currentDeformation == DeformationSphere &&
872 	    		    w->vertices2);
873     vertices = (useOtherWallVertices ? w->vertices2 - w->nSVer : w->vertices);
874 
875     for (i = 0; i < w->nSVer; i++)
876 	setAmplitude(&w->vertices[i], w->bh, w->wave1, w->wave2, w->wa,
877 	             w->swa, w->wf, w->swf,
878 	             (rippleEffect ? w->rippleFactor[i] : 0),
879 	             (rippleEffect ? w->rippleFactor[(i + offset) % w->nSVer] :
880 	             		     0));
881 
882     for (i = w->nSVer; i < w->nSVer + (w->nWVer / 2); i++)
883         setAmplitude(&vertices[i], w->bh, w->wave1, w->wave2, w->wa,
884 		     w->swa, w->wf, w->swf, 0, 0);
885 
886     if (useOtherWallVertices)
887     {
888 	int nRow = (w->sDiv)?(2 << (w->sDiv - 1)) + 1 : 2;
889 
890 	Vertex * verticesL = vertices;
891 
892 	for (j = 1; j < nRow - 1; j++ )
893 	{
894 	    vertices += w->nWVer / 2;
895 
896 	    for (i=w->nSVer; i < w->nSVer + (w->nWVer / 2); i++)
897 		vertices[i].v[1] = verticesL[i].v[1] - j *
898 				   (verticesL[i].v[1] + 0.5) / (nRow - 1);
899 	}
900 
901 	vertices += w->nWVer / 2;
902 
903 	 /* set bottom ground to base of deformed cube */
904 	 /* this is okay because ground and water have same grid size */
905 	    for (i = w->nSVer; i < w->nSVer + (w->nWVer / 2); i++)
906 	        vertices[i].v[1] = -0.5;
907     }
908 }
909 
910 void
updateDeformation(CompScreen * s,int currentDeformation)911 updateDeformation (CompScreen *s,
912                    int currentDeformation)
913 {
914     ATLANTIS_SCREEN (s);
915     CUBE_SCREEN (s);
916 
917     static const float floatErr = 0.0001f;
918 
919     Bool deform = FALSE;
920 
921     float progress, dummy;
922     (*cs->getRotation) (s, &dummy, &dummy, &progress);
923 
924     if (currentDeformation == DeformationNone)
925     {
926 	if (as->oldProgress == 0.0f)
927 	    return;
928 
929 	as->oldProgress = 0.0f;
930 	progress = 0.0f;
931     }
932     else
933     {
934 	if (fabsf (progress) < floatErr)
935 	    progress = 0.0f;
936 	else if (fabsf (1.0f - progress) < floatErr)
937 	    progress = 1.0f;
938 
939 	if ((as->oldProgress != 0.0f || progress != 0.0f) &&
940 		(as->oldProgress != 1.0f || progress != 1.0f))
941 	{
942 	    if (progress == 0.0f || progress == 1.0f)
943 	    {
944 		if (as->oldProgress != progress)
945 		{
946 		    deform = TRUE;
947 		    as->oldProgress = progress;
948 		}
949 	    }
950 	    else if (fabsf (as->oldProgress - progress) >= floatErr)
951 	    {
952 		deform = TRUE;
953 		as->oldProgress = progress;
954 	    }
955 	}
956     }
957 
958     if (deform)
959     {
960 	if (atlantisGetShowWater (s) || atlantisGetShowWaterWire (s))
961 	{
962 	    switch (currentDeformation)
963 	    {
964 	    case DeformationNone :
965 	    case DeformationCylinder :
966 		deformCylinder(s, as->water, progress);
967 		break;
968 
969 	    case DeformationSphere :
970 		deformSphere(s, as->water, progress, -0.5, FALSE);
971 	    }
972 	}
973 
974 	if (atlantisGetShowGround (s))
975 	{
976 	    switch (currentDeformation)
977 	    {
978 	    case DeformationNone :
979 		progress = 0.0f;
980 	    case DeformationCylinder :
981 		deformCylinder (s, as->ground, progress);
982 		break;
983 
984 	    case DeformationSphere :
985 		deformSphere (s, as->ground, progress, -0.5, TRUE);
986 	    }
987 
988 	    updateHeight (as->ground, NULL, FALSE, currentDeformation);
989 	}
990     }
991 }
992 
993 void
updateWater(CompScreen * s,float time)994 updateWater (CompScreen *s,
995              float time)
996 {
997     ATLANTIS_SCREEN (s);
998     CUBE_SCREEN (s);
999 
1000     int sDiv = (atlantisGetRenderWaves (s))?
1001 	       atlantisGetGridQuality (s) : 0;
1002     int size = as->hsize;
1003 
1004     if (!as->water)
1005 	as->water = genWater (size, sDiv, cs->distance, -0.5, atlantisGetWaveRipple (s));
1006 
1007     if (!as->water)
1008 	return;
1009 
1010     if (as->water->size != size || as->water->sDiv != sDiv ||
1011 	as->water->distance != cs->distance || (atlantisGetWaveRipple (s) && !as->water->rippleFactor))
1012     {
1013 	freeWater (as->water);
1014 	as->water = genWater (size, sDiv, cs->distance, -0.5, atlantisGetWaveRipple (s));
1015 
1016 	if (!as->water)
1017 	    return;
1018     }
1019 
1020     if (atlantisGetWaveRipple (s))
1021     {
1022 	as->water->rippleTimer -= (int) (time * 1000);
1023 	if (as->water->rippleTimer <= 0)
1024 	{
1025 	    as->water->rippleTimer += 170;
1026 	    updateRipple (as->water, size);
1027 	}
1028     }
1029 
1030     as->water->wave1 += time * as->speedFactor;
1031     as->water->wave2 += time * as->speedFactor;
1032 
1033     as->water->wave1 = fmodf (as->water->wave1, 2 * M_PI);
1034     as->water->wave2 = fmodf (as->water->wave2, 2 * M_PI);
1035 
1036     if (atlantisGetRenderWaves (s))
1037     {
1038 	as->water->wa  = atlantisGetWaveAmplitude (s);
1039 	as->water->swa = atlantisGetSmallWaveAmplitude (s);
1040  	as->water->wf  = atlantisGetWaveFrequency (s);
1041 	as->water->swf = atlantisGetSmallWaveFrequency (s);
1042     }
1043     else
1044     {
1045 	as->water->wa  = 0.0;
1046 	as->water->swa = 0.0;
1047  	as->water->wf  = 0.0;
1048 	as->water->swf = 0.0;
1049     }
1050 
1051     as->water->bh  = -0.5 + atlantisGetWaterHeight (s);
1052 }
1053 
1054 void
updateGround(CompScreen * s,float time)1055 updateGround (CompScreen *s,
1056               float time)
1057 {
1058     ATLANTIS_SCREEN (s);
1059     CUBE_SCREEN (s);
1060 
1061     int sDiv = atlantisGetGridQuality (s);
1062     int size = as->hsize;
1063 
1064     Bool update = FALSE;
1065 
1066     if (!as->ground)
1067     {
1068 	as->ground = genWater (size, sDiv, cs->distance, -0.5, FALSE);
1069 	update = TRUE;
1070     }
1071 
1072     if (!as->ground)
1073 	return;
1074 
1075     if (as->ground->size != size || as->ground->sDiv != sDiv ||
1076 	as->ground->distance != cs->distance)
1077     {
1078 	freeWater (as->ground);
1079 	as->ground = genWater (size, sDiv, cs->distance, -0.5, FALSE);
1080 
1081 	update = TRUE;
1082 	if (!as->ground)
1083 	    return;
1084     }
1085 
1086     if (!update)
1087 	return;
1088 
1089     as->ground->wave1 = (float)(rand () & 15) / 15.0;
1090     as->ground->wave2 = (float)(rand () & 15) / 15.0;
1091 
1092     as->ground->bh  = -0.45;
1093     as->ground->wa  = 0.1;
1094     as->ground->swa = 0.02;
1095     as->ground->wf  = 2.0;
1096     as->ground->swf = 10.0;
1097 
1098     updateHeight (as->ground, NULL, FALSE, DeformationNone);
1099 }
1100 
1101 void
drawWater(Water * w,Bool full,Bool wire,int currentDeformation)1102 drawWater (Water *w, Bool full, Bool wire, int currentDeformation)
1103 {
1104     float *v;
1105     if (!w)
1106 	return;
1107 
1108     glDisable (GL_DEPTH_TEST);
1109 
1110     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1111 
1112     if (full)
1113     {
1114 	glEnable  (GL_LIGHTING);
1115 	glEnable  (GL_LIGHT1);
1116 	glDisable (GL_LIGHT0);
1117 
1118 	glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1119 	glEnableClientState  (GL_NORMAL_ARRAY);
1120 
1121 	v = (float *) w->vertices;
1122 
1123 	glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1124 	glNormalPointer (GL_FLOAT,    6 * sizeof (float), v + 3);
1125 
1126 	glDrawElements (GL_TRIANGLES, w->nSIdx, GL_UNSIGNED_INT, w->indices);
1127 
1128 	glDisableClientState (GL_NORMAL_ARRAY);
1129 	glDisable (GL_LIGHTING);
1130 
1131 	glEnable (GL_COLOR_MATERIAL);
1132 	if (currentDeformation == DeformationSphere &&
1133 	    w->vertices2 && w->indices2)
1134 	{
1135 	    v = (float *) w->vertices2;
1136 
1137 	    glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1138 	    glNormalPointer (GL_FLOAT,    6 * sizeof (float), v + 3);
1139 
1140 	    glDrawElements (GL_TRIANGLES, w->nWIdx2,
1141 	                    GL_UNSIGNED_INT, w->indices2);
1142 	}
1143 	else
1144 	    glDrawElements (GL_TRIANGLES, w->nWIdx,
1145 	                    GL_UNSIGNED_INT, w->indices + w->nSIdx);
1146     }
1147 
1148     glDisableClientState (GL_NORMAL_ARRAY);
1149 
1150     glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1151 
1152     glColor4usv (defaultColor);
1153 
1154     if (wire)
1155     {
1156 	glDisable (GL_LIGHTING);
1157 
1158 	glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1159 
1160 	v = (float *) w->vertices;
1161 
1162 	glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1163 
1164 	glDisableClientState (GL_NORMAL_ARRAY);
1165 
1166 	glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1167 	glDrawElements  (GL_LINE_STRIP, w->nSIdx, GL_UNSIGNED_INT, w->indices);
1168 
1169 	if (currentDeformation == DeformationSphere)
1170 	{
1171 	    v = (float *) w->vertices2;
1172 
1173 	    glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1174 	    glDrawElements  (GL_LINE_STRIP, w->nWIdx2,
1175 	                     GL_UNSIGNED_INT, w->indices2);
1176 	}
1177 	else
1178 	    glDrawElements  (GL_LINE_STRIP, w->nWIdx,
1179 	                     GL_UNSIGNED_INT, w->indices + w->nSIdx);
1180     }
1181 }
1182 
1183 void
drawGround(Water * w,Water * g,int currentDeformation)1184 drawGround (Water *w,
1185             Water *g,
1186             int currentDeformation)
1187 {
1188     float *v;
1189     float *n;
1190 
1191     if (!g)
1192 	return;
1193 
1194     glEnable  (GL_DEPTH_TEST);
1195 
1196     glEnable  (GL_LIGHTING);
1197     glEnable  (GL_LIGHT1);
1198     glDisable (GL_LIGHT0);
1199 
1200     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1201 
1202     v = (float *) g->vertices;
1203     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1204 
1205     glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1206 
1207     glEnableClientState (GL_NORMAL_ARRAY);
1208 
1209     if (w)
1210 	n = (float *) w->vertices;
1211     else
1212 	n = (float *) g->vertices;
1213     glNormalPointer (GL_FLOAT, 6 * sizeof (float), n + 3);
1214 
1215     glDrawElements (GL_TRIANGLES, g->nSIdx, GL_UNSIGNED_INT, g->indices);
1216 
1217     if (currentDeformation == DeformationSphere && g->vertices2 && g->indices2)
1218     {
1219 	v = (float *) g->vertices2;
1220 	n = (float *) g->vertices2;
1221 
1222 	glNormalPointer (GL_FLOAT, 6 * sizeof (float), n + 3);
1223 	glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1224 
1225 	glDrawElements (GL_TRIANGLES, g->nWIdx2,
1226 	                GL_UNSIGNED_INT, g->indices2);
1227     }
1228     else
1229 	glDrawElements (GL_TRIANGLES, g->nWIdx,
1230 	                GL_UNSIGNED_INT, g->indices + g->nSIdx);
1231 
1232     glDisableClientState (GL_NORMAL_ARRAY);
1233     glDisable (GL_LIGHTING);
1234 
1235     glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1236 }
1237 
fillBottom(Water * w,float distance,float bottom,int currentDeformation)1238 static void fillBottom (Water *w,
1239                         float distance,
1240                         float bottom,
1241                         int currentDeformation)
1242 {
1243     int   i;
1244     float *v;
1245     int	  size = w->size;
1246 
1247     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
1248 
1249     if (currentDeformation == DeformationCylinder)
1250     {
1251 	v = (float *) w->vertices;
1252 
1253 	glNormal3f (0, -1, 0);
1254 
1255 	glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1256 	glDisableClientState (GL_NORMAL_ARRAY);
1257 
1258 	glDrawElements (GL_TRIANGLE_FAN, w->nBIdx,
1259 	                GL_UNSIGNED_INT, w->indices + w->nSIdx + w->nWIdx);
1260     }
1261     else if (currentDeformation == DeformationSphere &&
1262 	     w->vertices2 && w->indices2)
1263     {
1264 	v = (float *) w->vertices2;
1265 
1266 	glVertexPointer (3, GL_FLOAT, 6 * sizeof (float), v);
1267 
1268 	glDisableClientState (GL_NORMAL_ARRAY);
1269 
1270 	glNormal3f (0, -1, 0);
1271 
1272 	glDrawElements (GL_TRIANGLE_FAN, w->nBIdx2,
1273 	                GL_UNSIGNED_INT, w->indices2 + w->nWIdx2);
1274     }
1275     else
1276     {
1277 	float r = distance / cosf (M_PI / size);
1278 	float ang = M_PI / size;
1279 	float aStep = 2 * M_PI / size;
1280 
1281 	glBegin (GL_TRIANGLE_FAN);
1282 	glNormal3f (0, -1, 0);
1283 	glVertex3f (0.0, bottom, 0.0);
1284 
1285 	for (i = 0; i <= size; i++)
1286 	{
1287 	    glVertex3f (sinf (ang) * r, bottom, cosf (ang) * r);
1288 	    ang -= aStep;
1289 	}
1290 	glEnd ();
1291     }
1292 
1293     glEnableClientState (GL_TEXTURE_COORD_ARRAY);
1294 }
1295 
1296 void
drawBottomGround(Water * w,float distance,float bottom,int currentDeformation)1297 drawBottomGround (Water *w,
1298                   float distance,
1299                   float bottom,
1300                   int currentDeformation)
1301 {
1302     glDisable (GL_DEPTH_TEST);
1303 
1304     glEnable  (GL_LIGHTING);
1305     glEnable  (GL_LIGHT1);
1306     glDisable (GL_LIGHT0);
1307 
1308     fillBottom (w, distance, bottom, currentDeformation);
1309 
1310     glDisable (GL_LIGHTING);
1311 }
1312 
1313 void
drawBottomWater(Water * w,float distance,float bottom,int currentDeformation)1314 drawBottomWater (Water *w,
1315                  float distance,
1316                  float bottom,
1317                  int currentDeformation)
1318 {
1319     glDisable (GL_DEPTH_TEST);
1320 
1321     glDisable (GL_LIGHTING);
1322 
1323     glEnable (GL_COLOR_MATERIAL);
1324     fillBottom (w, distance, bottom, currentDeformation);
1325 }
1326 
1327 void
setWaterMaterial(unsigned short * waterColor)1328 setWaterMaterial (unsigned short * waterColor)
1329 {
1330     static const float mat_shininess[]  = { 140.0 };
1331     static const float mat_specular[]   = { 1.0, 1.0, 1.0, 1.0 };
1332 
1333     glDisable (GL_COLOR_MATERIAL);
1334     setMaterialAmbientDiffuse4us (waterColor, 2.0, 0.8);
1335 
1336     glColor4usv (waterColor);
1337 
1338     glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
1339     glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
1340 }
1341 
1342 void
setGroundMaterial(unsigned short * groundColor)1343 setGroundMaterial (unsigned short * groundColor)
1344 {
1345     static const float mat_shininess[]  = { 40.0 };
1346     static const float mat_specular[]   = { 0.0, 0.0, 0.0, 1.0 };
1347 
1348     glDisable (GL_COLOR_MATERIAL);
1349     setMaterialAmbientDiffuse4us (groundColor, 1.5, 0.8);
1350 
1351     glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
1352     glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
1353 }
1354 
1355 float
getHeight(Water * w,float x,float z)1356 getHeight (Water *w,
1357            float x,
1358            float z)
1359 {
1360     if (!w)
1361 	return 0.0;
1362     return w->bh + (w->wa * sinf (w->wave1 + w->wf * x * z)) +
1363 	   (w->swa * sinf (w->wave2 + w->swf * x * z));
1364 }
1365 
1366 /* use other scale for creatures inside cube */
1367 float
getGroundHeight(CompScreen * s,float x,float z)1368 getGroundHeight (CompScreen *s,
1369                  float x,
1370                  float z)
1371 {
1372     ATLANTIS_SCREEN (s);
1373 
1374     Water *g = as->ground;
1375 
1376     if (atlantisGetShowGround(s))
1377 	return getHeight(g, x / (100000 * as->ratio),
1378 	                 z / (100000 * as->ratio)) * 100000;
1379     return -0.5*100000;
1380 }
1381