http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.06.tar.gz
[xscreensaver] / hacks / glx / sphere.c
1 /* sphere, Copyright (c) 2002, 2008 Paul Bourke <pbourke@swin.edu.au>
2  * Utility function to create a unit sphere in GL.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  *
12  *  8-Oct-98: dek          Released initial version of "glplanet"
13  * 21-Mar-01: jwz@jwz.org  Broke sphere routine out into its own file.
14  * 28-Feb-02: jwz@jwz.org  New implementation from Paul Bourke:
15  *                         http://astronomy.swin.edu.au/~pbourke/opengl/sphere/
16  */
17
18 #include <math.h>
19 #include <stdlib.h>
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #ifdef HAVE_COCOA
26 # include <OpenGL/gl.h>
27 #else
28 # include <GL/gl.h>
29 #endif
30
31 #include "sphere.h"
32
33 typedef struct { GLfloat x, y, z; } XYZ;
34
35 int
36 unit_sphere (int stacks, int slices, int wire_p)
37 {
38   int polys = 0;
39   int i,j;
40   double theta1, theta2, theta3;
41   XYZ e, p;
42   XYZ la = { 0, 0, 0 }, lb = { 0, 0, 0 };
43   XYZ c = {0, 0, 0};  /* center */
44   double r = 1.0;     /* radius */
45   int stacks2 = stacks * 2;
46
47   if (r < 0)
48     r = -r;
49   if (slices < 0)
50     slices = -slices;
51
52   if (slices < 4 || stacks < 2 || r <= 0)
53     {
54       glBegin (GL_POINTS);
55       glVertex3f (c.x, c.y, c.z);
56       glEnd();
57       return 1;
58     }
59
60   glFrontFace(GL_CW);
61
62   for (j = 0; j < stacks; j++)
63     {
64       theta1 = j       * (M_PI+M_PI) / stacks2 - M_PI_2;
65       theta2 = (j + 1) * (M_PI+M_PI) / stacks2 - M_PI_2;
66
67       glBegin (wire_p ? GL_LINE_LOOP : GL_TRIANGLE_STRIP);
68       for (i = 0; i <= slices; i++)
69         {
70           theta3 = i * (M_PI+M_PI) / slices;
71
72           if (wire_p && i != 0)
73             {
74               glVertex3f (lb.x, lb.y, lb.z);
75               glVertex3f (la.x, la.y, la.z);
76             }
77
78           e.x = cos (theta2) * cos(theta3);
79           e.y = sin (theta2);
80           e.z = cos (theta2) * sin(theta3);
81           p.x = c.x + r * e.x;
82           p.y = c.y + r * e.y;
83           p.z = c.z + r * e.z;
84
85           glNormal3f (e.x, e.y, e.z);
86           glTexCoord2f (i       / (double)slices,
87                         2*(j+1) / (double)stacks2);
88           glVertex3f (p.x, p.y, p.z);
89           if (wire_p) la = p;
90
91           e.x = cos(theta1) * cos(theta3);
92           e.y = sin(theta1);
93           e.z = cos(theta1) * sin(theta3);
94           p.x = c.x + r * e.x;
95           p.y = c.y + r * e.y;
96           p.z = c.z + r * e.z;
97
98           glNormal3f (e.x, e.y, e.z);
99           glTexCoord2f (i   / (double)slices,
100                         2*j / (double)stacks2);
101           glVertex3f (p.x, p.y, p.z);
102           if (wire_p) lb = p;
103           polys++;
104         }
105       glEnd();
106     }
107   return polys;
108 }