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