ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / glx / bubble3d.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* bubble3d.c - 3D bubbles  */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)bubble3d.c  4.11 98/06/16 xlockmore";
6
7 #endif
8
9 /*-
10  * BUBBLE3D (C) 1998 Richard W.M. Jones.
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  * Revision History:
24  * 16-Jun-98: Written.
25  *
26  * bubble.c: This code is responsible for creating and managing
27  * bubbles over their lifetime.
28  * The bubbles may be drawn inside out.
29  */
30
31 #include "bubble3d.h"
32
33 typedef struct bubble {
34         GLfloat    *contributions;      /* List of contributions from each
35                                          * nudge to each vertex. This list has
36                                          * length nr_vertices * nr_nudge_axes.
37                                          */
38         GLfloat     x, y, z;    /* (x,y,z) location of the bubble. */
39         GLfloat     scale;      /* Scaling factor applied to bubble. */
40         GLfloat     y_incr, scale_incr;         /* Change in y and scale each frame. */
41         GLfloat     rotx, roty, rotz;   /* Current rotation. */
42         GLfloat     rotx_incr, roty_incr, rotz_incr;    /* Amount by which we increase
43                                                          * rotation each step.
44                                                          */
45         GLfloat    *nudge_angle;        /* Current angle (radians) of each
46                                          * nudge. This list has length nr_nudge_axes.
47                                          */
48         GLfloat    *nudge_angle_incr;   /* Amount by which we increase each nudge
49                                          * angle in each frame.
50                                          */
51 } bubble;
52
53 /* Should be taken care of already... but just in case */
54 #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
55 #undef inline
56 #define inline                  /* */
57 #endif
58 static inline void
59 normalize(GLfloat v[3])
60 {
61         GLfloat     d = (GLfloat) sqrt((double) (v[0] * v[0] + v[1] * v[1] +
62                                                  v[2] * v[2]));
63
64         if (d != 0) {
65                 v[0] /= d;
66                 v[1] /= d;
67                 v[2] /= d;
68         } else {
69                 v[0] = v[1] = v[2] = 0;
70         }
71 }
72
73 static inline GLfloat
74 dotprod(GLfloat * v1, GLfloat * v2)
75 {
76         return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
77 }
78
79 static inline GLfloat
80 max(GLfloat a, GLfloat b)
81 {
82         return a > b ? a : b;
83 }
84
85 /* Create a new bubble. */
86 void       *
87 glb_bubble_new(GLfloat x, GLfloat y, GLfloat z, GLfloat scale,
88                GLfloat y_incr, GLfloat scale_incr)
89 {
90         int         i, j;
91
92         /* GLfloat axes [glb_config.nr_nudge_axes][3]; */
93         GLfloat     axes[5][3]; /* HARD CODED for SunCC */
94         int         nr_vertices;
95         glb_vertex *vertices = glb_sphere_get_vertices(&nr_vertices);
96
97         bubble     *b = (bubble *) malloc(sizeof *b);
98
99         if (b == 0)
100                 return 0;
101
102         b->contributions = (GLfloat *) malloc(sizeof (GLfloat) * nr_vertices *
103                                               glb_config.nr_nudge_axes);
104         if (b->contributions == 0) {
105                 (void) free((void *) b);
106                 return 0;
107         }
108         b->nudge_angle = (GLfloat *) malloc(sizeof (GLfloat) * glb_config.nr_nudge_axes);
109         if (b->nudge_angle == 0) {
110                 (void) free((void *) b->contributions);
111                 (void) free((void *) b);
112                 return 0;
113         }
114         b->nudge_angle_incr = (GLfloat *) malloc(sizeof (GLfloat) * glb_config.nr_nudge_axes);
115         if (b->nudge_angle_incr == 0) {
116                 (void) free((void *) b->nudge_angle);
117                 (void) free((void *) b->contributions);
118                 (void) free((void *) b);
119                 return 0;
120         }
121         /* Initialize primitive elements. */
122         b->x = x;
123         b->y = y;
124         b->z = z;
125         b->scale = scale;
126         b->y_incr = y_incr;
127         b->scale_incr = scale_incr;
128         b->rotx = b->roty = b->rotz = 0;
129         b->rotx_incr = glb_drand() * glb_config.rotation_factor * 2
130                 - glb_config.rotation_factor;
131         b->roty_incr = glb_drand() * glb_config.rotation_factor * 2
132                 - glb_config.rotation_factor;
133         b->rotz_incr = glb_drand() * glb_config.rotation_factor * 2
134                 - glb_config.rotation_factor;
135
136         /* Initialize the nudge angle arrays. */
137         for (i = 0; i < glb_config.nr_nudge_axes; ++i) {
138                 b->nudge_angle[i] = 0;
139                 b->nudge_angle_incr[i] = glb_drand() * glb_config.nudge_angle_factor;
140         }
141
142         /* Choose some random nudge axes. */
143         for (i = 0; i < glb_config.nr_nudge_axes; ++i) {
144                 axes[i][0] = glb_drand() * 2 - 1;
145                 axes[i][1] = glb_drand() * 2 - 1;
146                 axes[i][2] = glb_drand() * 2 - 1;
147                 normalize(axes[i]);
148         }
149
150         /* Calculate the contribution that each nudge axis has on each vertex. */
151         for (i = 0; i < nr_vertices; ++i)
152                 for (j = 0; j < glb_config.nr_nudge_axes; ++j)
153                         b->contributions[i * glb_config.nr_nudge_axes + j]
154                                 = max(0, dotprod(vertices[i], axes[j]));
155
156         return (void *) b;
157 }
158
159 /* Delete a bubble and free up all memory. */
160 void
161 glb_bubble_delete(void *bb)
162 {
163         bubble     *b = (bubble *) bb;
164
165         if (b != NULL) {
166                 if (b->nudge_angle_incr) {
167                         (void) free((void *) b->nudge_angle_incr);
168                         b->nudge_angle_incr = NULL;
169                 }
170                 if (b->nudge_angle) {
171                         (void) free((void *) b->nudge_angle);
172                         b->nudge_angle = NULL;
173                 }
174                 if (b->contributions) {
175                         (void) free((void *) b->contributions);
176                         b->contributions = NULL;
177                 }
178                 (void) free((void *) b);
179                 b = NULL;
180         }
181 }
182
183 /* Rotate and wobble a bubble by a single step. */
184 void
185 glb_bubble_step(void *bb)
186 {
187         int         i;
188         bubble     *b = (bubble *) bb;
189
190         /* Update the rotation. */
191         b->rotx += b->rotx_incr;
192         b->roty += b->roty_incr;
193         b->rotz += b->rotz_incr;
194
195         /* Update the nudge angles. */
196         for (i = 0; i < glb_config.nr_nudge_axes; ++i)
197                 b->nudge_angle[i] += b->nudge_angle_incr[i];
198
199         /* Move it upwards & outwards. */
200         b->y += b->y_incr;
201         b->scale += b->scale_incr;
202 }
203
204 /* Draw a bubble. */
205 void
206 glb_bubble_draw(void *bb)
207 {
208         int         i, j;
209         bubble     *b = (bubble *) bb;
210         int         nr_vertices;
211         glb_vertex *vertices = glb_sphere_get_vertices(&nr_vertices);
212         int         nr_triangles;
213         glb_triangle *triangles = glb_sphere_get_triangles(&nr_triangles);
214         glb_vertex *new_vertices;
215
216         new_vertices = (glb_vertex *) malloc(sizeof (glb_vertex) * nr_vertices);
217         /* Calculate the vertices of this bubble, factoring in each nudge axis. */
218         for (i = 0; i < nr_vertices; ++i) {
219                 GLfloat     s = 0;
220
221                 for (j = 0; j < glb_config.nr_nudge_axes; ++j)
222                         s += ((GLfloat) cos((double) (b->nudge_angle[j])) *
223                               glb_config.nudge_factor - glb_config.nudge_factor / 2) *
224                                 b->contributions[i * glb_config.nr_nudge_axes + j];
225
226                 new_vertices[i][0] = vertices[i][0] * (s + 1);
227                 new_vertices[i][1] = vertices[i][1] * (s + 1);
228                 new_vertices[i][2] = vertices[i][2] * (s + 1);
229         }
230
231         glPushMatrix();
232
233         /* Apply translation, rotation and scalings. */
234         glTranslatef(b->x, b->y, b->z);
235
236         glRotatef(b->rotx, 1, 0, 0);
237         glRotatef(b->roty, 0, 1, 0);
238         glRotatef(b->rotz, 0, 0, 1);
239
240         glScalef(b->scale, b->scale, b->scale);
241
242         /* Draw the bubble. */
243         glBegin(GL_TRIANGLES);
244         for (i = 0; i < nr_triangles; ++i) {
245                 glNormal3fv(new_vertices[triangles[i][0]]);
246                 glVertex3fv(new_vertices[triangles[i][0]]);
247                 glNormal3fv(new_vertices[triangles[i][1]]);
248                 glVertex3fv(new_vertices[triangles[i][1]]);
249                 glNormal3fv(new_vertices[triangles[i][2]]);
250                 glVertex3fv(new_vertices[triangles[i][2]]);
251         }
252         glEnd();
253         glPopMatrix();
254         (void) free((void *) new_vertices);
255 }
256
257 /* Return y value. */
258 GLfloat
259 glb_bubble_get_y(void *bb)
260 {
261         bubble     *b = (bubble *) bb;
262
263         return b->y;
264 }