From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / hacks / glx / sphere.c
index d11eb9f10f79f9e83a8034793094ae89841a71c8..ff456cd4316b3ce9a1b5d8ec08d97e62e7614e9e 100644 (file)
@@ -1,4 +1,5 @@
-/* sphere, Copyright (c) 1998 David Konerding <dek@cgl.ucsf.edu>
+/* sphere, Copyright (c) 2002 Paul Bourke <pbourke@swin.edu.au>,
+ *         Copyright (c) 2010-2014 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
  * software for any purpose.  It is provided "as is" without express or 
  * implied warranty.
  *
- *  8-Oct-98: dek           Released initial version of "glplanet"
- * 21-Mar-01: jwz@jwz.org   Broke sphere routine out into its own file.
+ *  8-Oct-98: dek          Released initial version of "glplanet"
+ * 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 "config.h"
-#include <stdlib.h>
 #include <math.h>
-#include <GL/glx.h>
-#include "tube.h"
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef HAVE_COCOA
+# include <GL/gl.h>
+#endif
+
+#ifdef HAVE_JWZGLES
+# include "jwzgles.h"
+#endif /* HAVE_JWZGLES */
 
-/* Function for determining points on the surface of the sphere */
-static void
-parametric_sphere (float theta, float rho, GLfloat *vector)
+#include "sphere.h"
+
+typedef struct { GLfloat x, y, z; } XYZ;
+
+static int
+unit_sphere_1 (int stacks, int slices, int wire_p, int half_p)
 {
-  vector[0] = -sin(theta) * sin(rho);
-  vector[1] = cos(theta) * sin(rho);
-  vector[2] = cos(rho);
+  int polys = 0;
+  int i,j;
+  double theta1, theta2, theta3;
+  XYZ p, n;
+  XYZ la = { 0, -1, 0 }, lb = { 0, -1, 0 };
+  XYZ c = {0, 0, 0};  /* center */
+  double r = 1.0;     /* radius */
+  int stacks2 = stacks * 2;
+  int end = (half_p ? stacks/2 : stacks);
+
+  int mode = (wire_p ? GL_LINE_STRIP : 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)
+    {
+      mode = GL_POINTS;
+      array[out++].p = c;
+      goto END;
+    }
+
+  for (j = 0; j < end; j++)
+    {
+      theta1 = j       * (M_PI+M_PI) / stacks2 - M_PI_2;
+      theta2 = (j + 1) * (M_PI+M_PI) / stacks2 - M_PI_2;
+
+      for (i = slices; i >= 0; i--)
+        {
+          theta3 = i * (M_PI+M_PI) / slices;
+
+          if (wire_p)
+            {
+              array[out++].p = lb;                             /* vertex */
+              array[out++].p = la;                             /* vertex */
+            }
+
+          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;
+
+          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++;
+        }
+    }
+
+ 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;
 }
 
 
-void
-unit_sphere (int stacks, int slices, Bool wire)
+int
+unit_sphere (int stacks, int slices, int wire_p)
 {
-  int i, j;
-  float drho, dtheta;
-  float rho, theta;
-  GLfloat vector[3];
-  GLfloat ds, dt, t, s;
-
-  if (!wire)
-    glShadeModel(GL_SMOOTH);
-
-  /* Generate a sphere with quadrilaterals.
-   * Quad vertices are determined using a parametric sphere function.
-   * For fun, you could generate practically any parameteric surface and
-   * map an image onto it. 
-   */
-  drho = M_PI / stacks;
-  dtheta = 2.0 * M_PI / slices;
-  ds = 1.0 / slices;
-  dt = 1.0 / stacks;
-
-  glFrontFace(GL_CCW);
-  glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
-
-  t = 0.0;
-  for (i=0; i < stacks; i++) {
-    rho = i * drho;
-    s = 0.0;
-    for (j=0; j < slices; j++) {
-      theta = j * dtheta;
-
-      glTexCoord2f (s,t);
-      parametric_sphere (theta, rho, vector);
-      glNormal3fv (vector);
-      parametric_sphere (theta, rho, vector);
-      glVertex3f (vector[0], vector[1], vector[2]);
-
-      glTexCoord2f (s,t+dt);
-      parametric_sphere (theta, rho+drho, vector);
-      glNormal3fv (vector);
-      parametric_sphere (theta, rho+drho, vector);
-      glVertex3f (vector[0], vector[1], vector[2]);
-
-      glTexCoord2f (s+ds,t+dt);
-      parametric_sphere (theta + dtheta, rho+drho, vector);
-      glNormal3fv (vector);
-      parametric_sphere (theta + dtheta, rho+drho, vector);
-      glVertex3f (vector[0], vector[1], vector[2]);
-
-      glTexCoord2f (s+ds, t);
-      parametric_sphere (theta + dtheta, rho, vector);
-      glNormal3fv (vector);
-      parametric_sphere (theta + dtheta, rho, vector);
-      glVertex3f (vector[0], vector[1], vector[2]);
-
-      s = s + ds;
-    }
-    t = t + dt;
-  }
-  glEnd();
+  return unit_sphere_1 (stacks, slices, wire_p, 0);
+}
+
+int
+unit_dome (int stacks, int slices, int wire_p)
+{
+  return unit_sphere_1 (stacks, slices, wire_p, 1);
 }