232 lines
4.9 KiB
C
232 lines
4.9 KiB
C
#if !defined( lint ) && !defined( SABER )
|
|
static const char sccsid[] = "@(#)b_sphere.c 4.11 98/06/16 xlockmore";
|
|
|
|
#endif
|
|
|
|
/*-
|
|
* BUBBLE3D (C) 1998 Richard W.M. Jones.
|
|
* b_sphere.c: Create a list of vertices and triangles in a
|
|
* normalized sphere, which is then later used as the basic shape
|
|
* for all bubbles. This code is run once when the program starts
|
|
* up.
|
|
*/
|
|
|
|
#include "bubble3d.h"
|
|
|
|
/* The list of vertices created. */
|
|
typedef glb_vertex vertex;
|
|
static vertex *vertices = 0;
|
|
static int nr_vertices = 0, nr_vertices_allocated = 0;
|
|
|
|
/* The list of triangles created. */
|
|
typedef glb_triangle triangle;
|
|
static triangle *triangles = 0;
|
|
static int nr_triangles = 0, nr_triangles_allocated = 0;
|
|
|
|
/* Have we initialized the lists yet? */
|
|
static int initialized = 0;
|
|
|
|
#define EPSILON GLB_VERTICES_EPSILON
|
|
|
|
/* Should be taken care of already... but just in case */
|
|
#if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
|
|
#undef inline
|
|
#define inline /* */
|
|
#endif
|
|
static inline int
|
|
close_enough(GLfloat * v1, GLfloat * v2)
|
|
{
|
|
return fabs((double) (v1[0] - v2[0])) <= EPSILON &&
|
|
fabs((double) (v1[1] - v2[1])) <= EPSILON &&
|
|
fabs((double) (v1[2] - v2[2])) <= EPSILON;
|
|
}
|
|
|
|
#define INCR(n) ((n == 0) ? (n = 1) : (n *= 2))
|
|
#define INCR_ALLOCATION(a, n, t) (a = (t *) realloc (a, INCR (n) * sizeof (t)))
|
|
|
|
static inline GLuint
|
|
save_vertex(GLfloat * v)
|
|
{
|
|
int i;
|
|
|
|
/* Inefficient, but we only do this a few times. Check to see if there's
|
|
* an existing vertex which is `close enough' to this one.
|
|
*/
|
|
for (i = 0; i < nr_vertices; ++i)
|
|
if (close_enough(v, vertices[i]))
|
|
return i;
|
|
|
|
if (nr_vertices_allocated <= nr_vertices) {
|
|
if (vertices == 0) {
|
|
vertices = (vertex *) malloc(INCR(nr_vertices_allocated) * sizeof (vertex));
|
|
} else {
|
|
INCR_ALLOCATION(vertices, nr_vertices_allocated, vertex);
|
|
}
|
|
}
|
|
vertices[nr_vertices][0] = v[0];
|
|
vertices[nr_vertices][1] = v[1];
|
|
vertices[nr_vertices][2] = v[2];
|
|
return nr_vertices++;
|
|
}
|
|
|
|
static inline GLuint
|
|
save_triangle(GLuint v1, GLuint v2, GLuint v3)
|
|
{
|
|
if (nr_triangles_allocated <= nr_triangles) {
|
|
if (triangles == 0) {
|
|
triangles = (triangle *) malloc(INCR(nr_triangles_allocated) * sizeof (triangle));
|
|
} else {
|
|
INCR_ALLOCATION(triangles, nr_triangles_allocated, triangle);
|
|
}
|
|
}
|
|
triangles[nr_triangles][0] = v1;
|
|
triangles[nr_triangles][1] = v2;
|
|
triangles[nr_triangles][2] = v3;
|
|
return nr_triangles++;
|
|
}
|
|
|
|
static inline void
|
|
normalize(GLfloat v[3])
|
|
{
|
|
GLfloat d = (GLfloat) sqrt((double) (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
|
|
|
|
if (d != 0) {
|
|
v[0] /= d;
|
|
v[1] /= d;
|
|
v[2] /= d;
|
|
} else {
|
|
v[0] = v[1] = v[2] = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
subdivide(GLfloat * v1, GLuint vi1,
|
|
GLfloat * v2, GLuint vi2,
|
|
GLfloat * v3, GLuint vi3,
|
|
int depth)
|
|
{
|
|
int i;
|
|
|
|
if (depth == 0) {
|
|
(void) save_triangle(vi1, vi2, vi3);
|
|
} else {
|
|
GLuint vi12, vi23, vi31;
|
|
GLfloat v12[3], v23[3], v31[3];
|
|
|
|
for (i = 0; i < 3; ++i) {
|
|
v12[i] = v1[i] + v2[i];
|
|
v23[i] = v2[i] + v3[i];
|
|
v31[i] = v3[i] + v1[i];
|
|
}
|
|
normalize(v12);
|
|
vi12 = save_vertex(v12);
|
|
normalize(v23);
|
|
vi23 = save_vertex(v23);
|
|
normalize(v31);
|
|
vi31 = save_vertex(v31);
|
|
subdivide(v1, vi1, v12, vi12, v31, vi31, depth - 1);
|
|
subdivide(v2, vi2, v23, vi23, v12, vi12, depth - 1);
|
|
subdivide(v3, vi3, v31, vi31, v23, vi23, depth - 1);
|
|
subdivide(v12, vi12, v23, vi23, v31, vi31, depth - 1);
|
|
}
|
|
}
|
|
|
|
#define ICO_X 0.525731112119133606
|
|
#define ICO_Z 0.850650808352039932
|
|
|
|
static GLfloat vdata[12][3] =
|
|
{
|
|
{-ICO_X, 0, ICO_Z},
|
|
{ICO_X, 0, ICO_Z},
|
|
{-ICO_X, 0, -ICO_Z},
|
|
{ICO_X, 0, -ICO_Z},
|
|
{0, ICO_Z, ICO_X},
|
|
{0, ICO_Z, -ICO_X},
|
|
{0, -ICO_Z, ICO_X},
|
|
{0, -ICO_Z, -ICO_X},
|
|
{ICO_Z, ICO_X, 0},
|
|
{-ICO_Z, ICO_X, 0},
|
|
{ICO_Z, -ICO_X, 0},
|
|
{-ICO_Z, -ICO_X, 0}
|
|
};
|
|
|
|
static GLuint tindices[20][3] =
|
|
{
|
|
{0, 4, 1},
|
|
{0, 9, 4},
|
|
{9, 5, 4},
|
|
{4, 5, 8},
|
|
{4, 8, 1},
|
|
{8, 10, 1},
|
|
{8, 3, 10},
|
|
{5, 3, 8},
|
|
{5, 2, 3},
|
|
{2, 7, 3},
|
|
{7, 10, 3},
|
|
{7, 6, 10},
|
|
{7, 11, 6},
|
|
{11, 0, 6},
|
|
{0, 1, 6},
|
|
{6, 1, 10},
|
|
{9, 0, 11},
|
|
{9, 11, 2},
|
|
{9, 2, 5},
|
|
{7, 2, 11}
|
|
};
|
|
|
|
/* Public interface: Create the sphere. */
|
|
void
|
|
glb_sphere_init(void)
|
|
{
|
|
int i;
|
|
|
|
if (initialized)
|
|
return;
|
|
|
|
for (i = 0; i < 20; ++i) {
|
|
subdivide(vdata[tindices[i][0]], save_vertex(vdata[tindices[i][0]]),
|
|
vdata[tindices[i][1]], save_vertex(vdata[tindices[i][1]]),
|
|
vdata[tindices[i][2]], save_vertex(vdata[tindices[i][2]]),
|
|
glb_config.subdivision_depth);
|
|
}
|
|
|
|
initialized = 1;
|
|
}
|
|
|
|
/* Return the vertices list. */
|
|
glb_vertex *
|
|
glb_sphere_get_vertices(int *nr_vertices_ptr)
|
|
{
|
|
glb_sphere_init();
|
|
*nr_vertices_ptr = nr_vertices;
|
|
return vertices;
|
|
}
|
|
|
|
/* Return the triangles list. */
|
|
glb_triangle *
|
|
glb_sphere_get_triangles(int *nr_triangles_ptr)
|
|
{
|
|
glb_sphere_init();
|
|
*nr_triangles_ptr = nr_triangles;
|
|
return triangles;
|
|
}
|
|
|
|
/* Free up memory. */
|
|
#if 0
|
|
void
|
|
glb_sphere_end(void)
|
|
{
|
|
initialized = 0;
|
|
|
|
free(vertices);
|
|
free(triangles);
|
|
|
|
vertices = 0;
|
|
nr_vertices = nr_vertices_allocated = 0;
|
|
|
|
triangles = 0;
|
|
nr_triangles = nr_triangles_allocated = 0;
|
|
}
|
|
|
|
#endif
|