http://www.jwz.org/xscreensaver/xscreensaver-5.12.tar.gz
[xscreensaver] / hacks / glx / sphere.c
index 10e86d7698e1fd6b81229034067a9f5ae39deb73..eb004b11814a14075f3603cf4fd07e38b3db52dc 100644 (file)
@@ -1,4 +1,5 @@
-/* sphere, Copyright (c) 2002, 2008 Paul Bourke <pbourke@swin.edu.au>
+/* sphere, Copyright (c) 2002 Paul Bourke <pbourke@swin.edu.au>,
+ *         Copyright (c) 2010 Jamie Zawinski <jwz@jwz.org>
  * Utility function to create a unit sphere in GL.
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
@@ -13,6 +14,7 @@
  * 21-Mar-01: jwz@jwz.org  Broke sphere routine out into its own file.
  * 28-Feb-02: jwz@jwz.org  New implementation from Paul Bourke:
  *                         http://astronomy.swin.edu.au/~pbourke/opengl/sphere/
+ * 21-Aug-10  jwz@jwz.org  Converted to use glDrawArrays, for OpenGL ES.
  */
 
 #include <math.h>
@@ -38,71 +40,98 @@ unit_sphere (int stacks, int slices, int wire_p)
   int polys = 0;
   int i,j;
   double theta1, theta2, theta3;
-  XYZ e, p;
+  XYZ p, n;
   XYZ la = { 0, 0, 0 }, lb = { 0, 0, 0 };
   XYZ c = {0, 0, 0};  /* center */
   double r = 1.0;     /* radius */
   int stacks2 = stacks * 2;
 
+  int mode = (wire_p ? GL_LINE_LOOP : GL_TRIANGLE_STRIP);
+
+  int arraysize, out;
+  struct { XYZ p; XYZ n; GLfloat s, t; } *array;
+
   if (r < 0)
     r = -r;
   if (slices < 0)
     slices = -slices;
 
+  arraysize = (stacks+1) * (slices+1) * (wire_p ? 4 : 2);
+  array = (void *) calloc (arraysize, sizeof(*array));
+  if (! array) abort();
+  out = 0;
+
+
   if (slices < 4 || stacks < 2 || r <= 0)
     {
-      glBegin (GL_POINTS);
-      glVertex3f (c.x, c.y, c.z);
-      glEnd();
-      return 1;
+      mode = GL_POINTS;
+      array[out++].p = c;
+      goto END;
     }
 
-  glFrontFace(GL_CW);
-
   for (j = 0; j < stacks; j++)
     {
       theta1 = j       * (M_PI+M_PI) / stacks2 - M_PI_2;
       theta2 = (j + 1) * (M_PI+M_PI) / stacks2 - M_PI_2;
 
-      glBegin (wire_p ? GL_LINE_LOOP : GL_TRIANGLE_STRIP);
-      for (i = 0; i <= slices; i++)
+      for (i = slices; i >= 0; i--)
         {
           theta3 = i * (M_PI+M_PI) / slices;
 
           if (wire_p && i != 0)
             {
-              glVertex3f (lb.x, lb.y, lb.z);
-              glVertex3f (la.x, la.y, la.z);
+              array[out++].p = lb;                             /* vertex */
+              array[out++].p = la;                             /* vertex */
             }
 
-          e.x = cos (theta2) * cos(theta3);
-          e.y = sin (theta2);
-          e.z = cos (theta2) * sin(theta3);
-          p.x = c.x + r * e.x;
-          p.y = c.y + r * e.y;
-          p.z = c.z + r * e.z;
-
-          glNormal3f (e.x, e.y, e.z);
-          glTexCoord2f (i       / (double)slices,
-                        2*(j+1) / (double)stacks2);
-          glVertex3f (p.x, p.y, p.z);
+          n.x = cos (theta2) * cos(theta3);
+          n.y = sin (theta2);
+          n.z = cos (theta2) * sin(theta3);
+          p.x = c.x + r * n.x;
+          p.y = c.y + r * n.y;
+          p.z = c.z + r * n.z;
+
+          array[out].p = p;                                    /* vertex */
+          array[out].n = n;                                    /* normal */
+          array[out].s = i       / (GLfloat) slices;           /* texture */
+          array[out].t = 2*(j+1) / (GLfloat) stacks2;
+          out++;
+
           if (wire_p) la = p;
 
-          e.x = cos(theta1) * cos(theta3);
-          e.y = sin(theta1);
-          e.z = cos(theta1) * sin(theta3);
-          p.x = c.x + r * e.x;
-          p.y = c.y + r * e.y;
-          p.z = c.z + r * e.z;
-
-          glNormal3f (e.x, e.y, e.z);
-          glTexCoord2f (i   / (double)slices,
-                        2*j / (double)stacks2);
-          glVertex3f (p.x, p.y, p.z);
+          n.x = cos(theta1) * cos(theta3);
+          n.y = sin(theta1);
+          n.z = cos(theta1) * sin(theta3);
+          p.x = c.x + r * n.x;
+          p.y = c.y + r * n.y;
+          p.z = c.z + r * n.z;
+
+          array[out].p = p;                                    /* vertex */
+          array[out].n = n;                                    /* normal */
+          array[out].s = i   / (GLfloat) slices;               /* texture */
+          array[out].t = 2*j / (GLfloat) stacks2;
+          out++;
+
+          if (out >= arraysize) abort();
+
           if (wire_p) lb = p;
           polys++;
         }
-      glEnd();
     }
+
+ END:
+
+  glEnableClientState (GL_VERTEX_ARRAY);
+  glEnableClientState (GL_NORMAL_ARRAY);
+  glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+  glVertexPointer   (3, GL_FLOAT, sizeof(*array), &array[0].p);
+  glNormalPointer   (   GL_FLOAT, sizeof(*array), &array[0].n);
+  glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
+
+  glDrawArrays (mode, 0, out);
+
+  free (array);
+
   return polys;
 }