http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / glx / b_sphere.c
1 #if 0
2 static const char sccsid[] = "@(#)b_sphere.c  4.11 98/06/16 xlockmore";
3 #endif
4
5 /*-
6  * BUBBLE3D (C) 1998 Richard W.M. Jones.
7  * b_sphere.c: Create a list of vertices and triangles in a
8  * normalized sphere, which is then later used as the basic shape
9  * for all bubbles. This code is run once when the program starts
10  * up.
11  */
12
13 #include "bubble3d.h"
14
15 /* The list of vertices created. */
16 typedef glb_vertex vertex;
17 static vertex *vertices = 0;
18 static int  nr_vertices = 0, nr_vertices_allocated = 0;
19
20 /* The list of triangles created. */
21 typedef glb_triangle triangle;
22 static triangle *triangles = 0;
23 static int  nr_triangles = 0, nr_triangles_allocated = 0;
24
25 /* Have we initialized the lists yet? */
26 static int  initialized = 0;
27
28 #define EPSILON GLB_VERTICES_EPSILON
29
30 /* Should be taken care of already... but just in case */
31 #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
32 #undef inline
33 #define inline                  /* */
34 #endif
35 static inline int
36 close_enough(GLfloat * v1, GLfloat * v2)
37 {
38         return fabs((double) (v1[0] - v2[0])) <= EPSILON &&
39                 fabs((double) (v1[1] - v2[1])) <= EPSILON &&
40                 fabs((double) (v1[2] - v2[2])) <= EPSILON;
41 }
42
43 #define INCR(n) ((n == 0) ? (n = 1) : (n *= 2))
44 #define INCR_ALLOCATION(a, n, t) (a = (t *) realloc (a, INCR (n) * sizeof (t)))
45
46 static inline GLuint
47 save_vertex(GLfloat * v)
48 {
49         int         i;
50
51         /* Inefficient, but we only do this a few times. Check to see if there's
52          * an existing vertex which is `close enough' to this one.
53          */
54         for (i = 0; i < nr_vertices; ++i)
55                 if (close_enough(v, vertices[i]))
56                         return i;
57
58         if (nr_vertices_allocated <= nr_vertices) {
59                 if (vertices == 0) {
60                         vertices = (vertex *) malloc(INCR(nr_vertices_allocated) * sizeof (vertex));
61                 } else {
62                         INCR_ALLOCATION(vertices, nr_vertices_allocated, vertex);
63                 }
64         }
65         vertices[nr_vertices][0] = v[0];
66         vertices[nr_vertices][1] = v[1];
67         vertices[nr_vertices][2] = v[2];
68         return nr_vertices++;
69 }
70
71 static inline GLuint
72 save_triangle(GLuint v1, GLuint v2, GLuint v3)
73 {
74         if (nr_triangles_allocated <= nr_triangles) {
75                 if (triangles == 0) {
76                         triangles = (triangle *) malloc(INCR(nr_triangles_allocated) * sizeof (triangle));
77                 } else {
78                         INCR_ALLOCATION(triangles, nr_triangles_allocated, triangle);
79                 }
80         }
81         triangles[nr_triangles][0] = v1;
82         triangles[nr_triangles][1] = v2;
83         triangles[nr_triangles][2] = v3;
84         return nr_triangles++;
85 }
86
87 static inline void
88 normalize(GLfloat v[3])
89 {
90         GLfloat     d = (GLfloat) sqrt((double) (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
91
92         if (d != 0) {
93                 v[0] /= d;
94                 v[1] /= d;
95                 v[2] /= d;
96         } else {
97                 v[0] = v[1] = v[2] = 0;
98         }
99 }
100
101 static void
102 subdivide(GLfloat * v1, GLuint vi1,
103           GLfloat * v2, GLuint vi2,
104           GLfloat * v3, GLuint vi3,
105           int depth)
106 {
107         int         i;
108
109         if (depth == 0) {
110                 save_triangle(vi1, vi2, vi3);
111         } else {
112                 GLuint      vi12, vi23, vi31;
113                 GLfloat     v12[3], v23[3], v31[3];
114
115                 for (i = 0; i < 3; ++i) {
116                         v12[i] = v1[i] + v2[i];
117                         v23[i] = v2[i] + v3[i];
118                         v31[i] = v3[i] + v1[i];
119                 }
120                 normalize(v12);
121                 vi12 = save_vertex(v12);
122                 normalize(v23);
123                 vi23 = save_vertex(v23);
124                 normalize(v31);
125                 vi31 = save_vertex(v31);
126                 subdivide(v1, vi1, v12, vi12, v31, vi31, depth - 1);
127                 subdivide(v2, vi2, v23, vi23, v12, vi12, depth - 1);
128                 subdivide(v3, vi3, v31, vi31, v23, vi23, depth - 1);
129                 subdivide(v12, vi12, v23, vi23, v31, vi31, depth - 1);
130         }
131 }
132
133 #define ICO_X 0.525731112119133606
134 #define ICO_Z 0.850650808352039932
135
136 static GLfloat vdata[12][3] =
137 {
138         {-ICO_X, 0, ICO_Z},
139         {ICO_X, 0, ICO_Z},
140         {-ICO_X, 0, -ICO_Z},
141         {ICO_X, 0, -ICO_Z},
142         {0, ICO_Z, ICO_X},
143         {0, ICO_Z, -ICO_X},
144         {0, -ICO_Z, ICO_X},
145         {0, -ICO_Z, -ICO_X},
146         {ICO_Z, ICO_X, 0},
147         {-ICO_Z, ICO_X, 0},
148         {ICO_Z, -ICO_X, 0},
149         {-ICO_Z, -ICO_X, 0}
150 };
151
152 static GLuint tindices[20][3] =
153 {
154         {0, 4, 1},
155         {0, 9, 4},
156         {9, 5, 4},
157         {4, 5, 8},
158         {4, 8, 1},
159         {8, 10, 1},
160         {8, 3, 10},
161         {5, 3, 8},
162         {5, 2, 3},
163         {2, 7, 3},
164         {7, 10, 3},
165         {7, 6, 10},
166         {7, 11, 6},
167         {11, 0, 6},
168         {0, 1, 6},
169         {6, 1, 10},
170         {9, 0, 11},
171         {9, 11, 2},
172         {9, 2, 5},
173         {7, 2, 11}
174 };
175
176 /* Public interface: Create the sphere. */
177 void
178 glb_sphere_init(void)
179 {
180         int         i;
181
182         if (initialized)
183                 return;
184
185         for (i = 0; i < 20; ++i) {
186                 subdivide(vdata[tindices[i][0]], save_vertex(vdata[tindices[i][0]]),
187                    vdata[tindices[i][1]], save_vertex(vdata[tindices[i][1]]),
188                    vdata[tindices[i][2]], save_vertex(vdata[tindices[i][2]]),
189                           glb_config.subdivision_depth);
190         }
191
192         initialized = 1;
193 }
194
195 /* Return the vertices list. */
196 glb_vertex *
197 glb_sphere_get_vertices(int *nr_vertices_ptr)
198 {
199         glb_sphere_init();
200         *nr_vertices_ptr = nr_vertices;
201         return vertices;
202 }
203
204 /* Return the triangles list. */
205 glb_triangle *
206 glb_sphere_get_triangles(int *nr_triangles_ptr)
207 {
208         glb_sphere_init();
209         *nr_triangles_ptr = nr_triangles;
210         return triangles;
211 }
212
213 /* Free up memory. */
214 #if 0
215 void
216 glb_sphere_end(void)
217 {
218         initialized = 0;
219
220         (void) free((void *) vertices);
221         (void) free((void *) triangles);
222
223         vertices = 0;
224         nr_vertices = nr_vertices_allocated = 0;
225
226         triangles = 0;
227         nr_triangles = nr_triangles_allocated = 0;
228 }
229
230 #endif