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