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