http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / glx / tube.c
1 /* tube, Copyright (c) 2001, 2003 Jamie Zawinski <jwz@jwz.org>
2  * Utility functions to create tubes and cones 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
13 #include <math.h>
14
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18
19 #include <stdlib.h>
20
21 #ifdef HAVE_COCOA
22 # include <OpenGL/gl.h>
23 #else
24 # include <GL/gl.h>
25 #endif
26
27 #include "tube.h"
28
29 static void
30 unit_tube (int faces, int smooth, int caps_p, int wire_p)
31 {
32   int i;
33   GLfloat step = M_PI * 2 / faces;
34   GLfloat s2 = step/2;
35   GLfloat th;
36   GLfloat x, y, x0=0, y0=0;
37   int z = 0;
38
39   /* side walls
40    */
41   glFrontFace(GL_CCW);
42   glBegin (wire_p ? GL_LINES : (smooth ? GL_QUAD_STRIP : GL_QUADS));
43
44   th = 0;
45   x = 1;
46   y = 0;
47
48   if (!smooth)
49     {
50       x0 = cos (s2);
51       y0 = sin (s2);
52     }
53
54   if (smooth) faces++;
55
56   for (i = 0; i < faces; i++)
57     {
58       if (smooth)
59         glNormal3f(x, 0, y);
60       else
61         glNormal3f(x0, 0, y0);
62
63       glVertex3f(x, 0, y);
64       glVertex3f(x, 1, y);
65
66       th += step;
67       x  = cos (th);
68       y  = sin (th);
69
70       if (!smooth)
71         {
72           x0 = cos (th + s2);
73           y0 = sin (th + s2);
74
75           glVertex3f(x, 1, y);
76           glVertex3f(x, 0, y);
77         }
78     }
79   glEnd();
80
81   /* End caps
82    */
83   if (caps_p)
84     for (z = 0; z <= 1; z++)
85       {
86         glFrontFace(z == 0 ? GL_CCW : GL_CW);
87         glNormal3f(0, (z == 0 ? -1 : 1), 0);
88         glBegin(wire_p ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
89         if (! wire_p) glVertex3f(0, z, 0);
90         for (i = 0, th = 0; i <= faces; i++)
91           {
92             GLfloat x = cos (th);
93             GLfloat y = sin (th);
94             glVertex3f(x, z, y);
95             th += step;
96           }
97         glEnd();
98       }
99 }
100
101
102 static void
103 unit_cone (int faces, int smooth, int cap_p, int wire_p)
104 {
105   int i;
106   GLfloat step = M_PI * 2 / faces;
107   GLfloat s2 = step/2;
108   GLfloat th;
109   GLfloat x, y, x0, y0;
110
111   /* side walls
112    */
113   glFrontFace(GL_CW);
114   glBegin(wire_p ? GL_LINES : GL_TRIANGLES);
115
116   th = 0;
117   x = 1;
118   y = 0;
119   x0 = cos (s2);
120   y0 = sin (s2);
121
122   for (i = 0; i < faces; i++)
123     {
124       glNormal3f(x0, 0, y0);
125       glVertex3f(0,  1, 0);
126
127       if (smooth) glNormal3f(x, 0, y);
128       glVertex3f(x, 0, y);
129
130       th += step;
131       x0 = cos (th + s2);
132       y0 = sin (th + s2);
133       x  = cos (th);
134       y  = sin (th);
135
136       if (smooth) glNormal3f(x, 0, y);
137       glVertex3f(x, 0, y);
138     }
139   glEnd();
140
141   /* End cap
142    */
143   if (cap_p)
144     {
145       glFrontFace(GL_CCW);
146       glNormal3f(0, -1, 0);
147       glBegin(wire_p ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
148       if (! wire_p) glVertex3f(0, 0, 0);
149       for (i = 0, th = 0; i <= faces; i++)
150         {
151           GLfloat x = cos (th);
152           GLfloat y = sin (th);
153           glVertex3f(x, 0, y);
154           th += step;
155         }
156       glEnd();
157     }
158 }
159
160
161 static void
162 tube_1 (GLfloat x1, GLfloat y1, GLfloat z1,
163         GLfloat x2, GLfloat y2, GLfloat z2,
164         GLfloat diameter, GLfloat cap_size,
165         int faces, int smooth, int caps_p, int wire_p,
166         int cone_p)
167 {
168   GLfloat length, X, Y, Z;
169
170   if (diameter <= 0) abort();
171
172   X = (x2 - x1);
173   Y = (y2 - y1);
174   Z = (z2 - z1);
175
176   if (X == 0 && Y == 0 && Z == 0)
177     return;
178
179   length = sqrt (X*X + Y*Y + Z*Z);
180
181   glPushMatrix();
182
183   glTranslatef(x1, y1, z1);
184   glRotatef (-atan2 (X, Y)               * (180 / M_PI), 0, 0, 1);
185   glRotatef ( atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI), 1, 0, 0);
186   glScalef (diameter, length, diameter);
187
188   /* extend the endpoints of the tube by the cap size in both directions */
189   if (cap_size != 0)
190     {
191       GLfloat c = cap_size/length;
192       glTranslatef (0, -c, 0);
193       glScalef (1, 1+c+c, 1);
194     }
195
196   if (cone_p)
197     unit_cone (faces, smooth, caps_p, wire_p);
198   else
199     unit_tube (faces, smooth, caps_p, wire_p);
200
201   glPopMatrix();
202 }
203
204
205 void
206 tube (GLfloat x1, GLfloat y1, GLfloat z1,
207       GLfloat x2, GLfloat y2, GLfloat z2,
208       GLfloat diameter, GLfloat cap_size,
209       int faces, int smooth, int caps_p, int wire_p)
210 {
211   tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size,
212           faces, smooth, caps_p, wire_p,
213           0);
214 }
215
216
217 void
218 cone (GLfloat x1, GLfloat y1, GLfloat z1,
219       GLfloat x2, GLfloat y2, GLfloat z2,
220       GLfloat diameter, GLfloat cap_size,
221       int faces, int smooth, int cap_p, int wire_p)
222 {
223   tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size,
224           faces, smooth, cap_p, wire_p,
225           1);
226 }