From http://www.jwz.org/xscreensaver/xscreensaver-5.40.tar.gz
[xscreensaver] / hacks / glx / sphere.c
1 /* sphere, Copyright (c) 2002 Paul Bourke <pbourke@swin.edu.au>,
2  *         Copyright (c) 2010-2014 Jamie Zawinski <jwz@jwz.org>
3  * Utility function to create a unit sphere in GL.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation.  No representations are made about the suitability of this
10  * software for any purpose.  It is provided "as is" without express or 
11  * implied warranty.
12  *
13  *  8-Oct-98: dek          Released initial version of "glplanet"
14  * 21-Mar-01: jwz@jwz.org  Broke sphere routine out into its own file.
15  * 28-Feb-02: jwz@jwz.org  New implementation from Paul Bourke:
16  *                         http://astronomy.swin.edu.au/~pbourke/opengl/sphere/
17  * 21-Aug-10  jwz@jwz.org  Converted to use glDrawArrays, for OpenGL ES.
18  */
19
20 #include <math.h>
21 #include <stdlib.h>
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #ifdef HAVE_COCOA
28 #elif defined(HAVE_ANDROID)
29 # include <GLES/gl.h>
30 #else  /* real X11 */
31 # include <GL/gl.h>
32 #endif
33
34 #ifdef HAVE_JWZGLES
35 # include "jwzgles.h"
36 #endif /* HAVE_JWZGLES */
37
38 #include "sphere.h"
39
40 typedef struct { GLfloat x, y, z; } XYZ;
41
42 static int
43 unit_sphere_1 (int stacks, int slices, int wire_p, int half_p)
44 {
45   int polys = 0;
46   int i,j;
47   double theta1, theta2, theta3;
48   XYZ p, n;
49   XYZ la = { 0, -1, 0 }, lb = { 0, -1, 0 };
50   XYZ c = {0, 0, 0};  /* center */
51   double r = 1.0;     /* radius */
52   int stacks2 = stacks * 2;
53   int end = (half_p ? stacks/2 : stacks);
54
55   int mode = (wire_p ? GL_LINE_STRIP : GL_TRIANGLE_STRIP);
56
57   int arraysize, out;
58   struct { XYZ p; XYZ n; GLfloat s, t; } *array;
59
60   if (r < 0)
61     r = -r;
62   if (slices < 0)
63     slices = -slices;
64
65   arraysize = (stacks+1) * (slices+1) * (wire_p ? 4 : 2);
66   array = (void *) calloc (arraysize, sizeof(*array));
67   if (! array) abort();
68   out = 0;
69
70   if (slices < 4 || stacks < 2 || r <= 0)
71     {
72       mode = GL_POINTS;
73       array[out++].p = c;
74       goto END;
75     }
76
77   for (j = 0; j < end; j++)
78     {
79       theta1 = j       * (M_PI+M_PI) / stacks2 - M_PI_2;
80       theta2 = (j + 1) * (M_PI+M_PI) / stacks2 - M_PI_2;
81
82       for (i = slices; i >= 0; i--)
83         {
84           theta3 = i * (M_PI+M_PI) / slices;
85
86           if (wire_p)
87             {
88               array[out++].p = lb;                              /* vertex */
89               array[out++].p = la;                              /* vertex */
90             }
91
92           n.x = cos (theta2) * cos(theta3);
93           n.y = sin (theta2);
94           n.z = cos (theta2) * sin(theta3);
95           p.x = c.x + r * n.x;
96           p.y = c.y + r * n.y;
97           p.z = c.z + r * n.z;
98
99           array[out].p = p;                                     /* vertex */
100           array[out].n = n;                                     /* normal */
101           array[out].s = i       / (GLfloat) slices;            /* texture */
102           array[out].t = 2*(j+1) / (GLfloat) stacks2;
103           out++;
104
105           if (wire_p) la = p;
106
107           n.x = cos(theta1) * cos(theta3);
108           n.y = sin(theta1);
109           n.z = cos(theta1) * sin(theta3);
110           p.x = c.x + r * n.x;
111           p.y = c.y + r * n.y;
112           p.z = c.z + r * n.z;
113
114           array[out].p = p;                                     /* vertex */
115           array[out].n = n;                                     /* normal */
116           array[out].s = i   / (GLfloat) slices;                /* texture */
117           array[out].t = 2*j / (GLfloat) stacks2;
118           out++;
119
120           if (out >= arraysize) abort();
121
122           if (wire_p) lb = p;
123           polys++;
124         }
125     }
126
127  END:
128
129   glEnableClientState (GL_VERTEX_ARRAY);
130   glEnableClientState (GL_NORMAL_ARRAY);
131   glEnableClientState (GL_TEXTURE_COORD_ARRAY);
132
133   glVertexPointer   (3, GL_FLOAT, sizeof(*array), &array[0].p);
134   glNormalPointer   (   GL_FLOAT, sizeof(*array), &array[0].n);
135   glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
136
137   glDrawArrays (mode, 0, out);
138
139   free (array);
140
141   return polys;
142 }
143
144
145 int
146 unit_sphere (int stacks, int slices, int wire_p)
147 {
148   return unit_sphere_1 (stacks, slices, wire_p, 0);
149 }
150
151 int
152 unit_dome (int stacks, int slices, int wire_p)
153 {
154   return unit_sphere_1 (stacks, slices, wire_p, 1);
155 }