http://www.uw-madison.lkams.kernel.org/pub/mirrors/fink/distfiles/xscreensaver-4...
[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 "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 caps_p, 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=0, y0=0;
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   if (caps_p)
74     for (z = 0; z <= 1; z++)
75       {
76         glFrontFace(z == 0 ? GL_CCW : GL_CW);
77         glNormal3f(0, (z == 0 ? -1 : 1), 0);
78         glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
79         if (! wire) glVertex3f(0, z, 0);
80         for (i = 0, th = 0; i <= faces; i++)
81           {
82             GLfloat x = cos (th);
83             GLfloat y = sin (th);
84             glVertex3f(x, z, y);
85             th += step;
86           }
87         glEnd();
88       }
89 }
90
91
92 static void
93 unit_cone (int faces, Bool smooth, Bool cap_p, Bool wire)
94 {
95   int i;
96   GLfloat step = M_PI * 2 / faces;
97   GLfloat s2 = step/2;
98   GLfloat th;
99   GLfloat x, y, x0, y0;
100
101   /* side walls
102    */
103   glFrontFace(GL_CW);
104   glBegin(wire ? GL_LINES : GL_TRIANGLES);
105
106   th = 0;
107   x = 1;
108   y = 0;
109   x0 = cos (s2);
110   y0 = sin (s2);
111
112   for (i = 0; i < faces; i++)
113     {
114       glNormal3f(x0, 0, y0);
115       glVertex3f(0,  1, 0);
116
117       if (smooth) glNormal3f(x, 0, y);
118       glVertex3f(x, 0, y);
119
120       th += step;
121       x0 = cos (th + s2);
122       y0 = sin (th + s2);
123       x  = cos (th);
124       y  = sin (th);
125
126       if (smooth) glNormal3f(x, 0, y);
127       glVertex3f(x, 0, y);
128     }
129   glEnd();
130
131   /* End cap
132    */
133   if (cap_p)
134     {
135       glFrontFace(GL_CCW);
136       glNormal3f(0, -1, 0);
137       glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
138       if (! wire) glVertex3f(0, 0, 0);
139       for (i = 0, th = 0; i <= faces; i++)
140         {
141           GLfloat x = cos (th);
142           GLfloat y = sin (th);
143           glVertex3f(x, 0, y);
144           th += step;
145         }
146       glEnd();
147     }
148 }
149
150
151 static void
152 tube_1 (GLfloat x1, GLfloat y1, GLfloat z1,
153         GLfloat x2, GLfloat y2, GLfloat z2,
154         GLfloat diameter, GLfloat cap_size,
155         int faces, Bool smooth, Bool caps_p, Bool wire,
156         Bool cone_p)
157 {
158   GLfloat length, X, Y, Z;
159
160   if (diameter <= 0) abort();
161
162   X = (x2 - x1);
163   Y = (y2 - y1);
164   Z = (z2 - z1);
165
166   if (X == 0 && Y == 0 && Z == 0)
167     return;
168
169   length = sqrt (X*X + Y*Y + Z*Z);
170
171   glPushMatrix();
172
173   glTranslatef(x1, y1, z1);
174   glRotatef (-atan2 (X, Y)               * (180 / M_PI), 0, 0, 1);
175   glRotatef ( atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI), 1, 0, 0);
176   glScalef (diameter, length, diameter);
177
178   /* extend the endpoints of the tube by the cap size in both directions */
179   if (cap_size != 0)
180     {
181       GLfloat c = cap_size/length;
182       glTranslatef (0, -c, 0);
183       glScalef (1, 1+c+c, 1);
184     }
185
186   if (cone_p)
187     unit_cone (faces, smooth, caps_p, wire);
188   else
189     unit_tube (faces, smooth, caps_p, wire);
190
191   glPopMatrix();
192 }
193
194
195 void
196 tube (GLfloat x1, GLfloat y1, GLfloat z1,
197       GLfloat x2, GLfloat y2, GLfloat z2,
198       GLfloat diameter, GLfloat cap_size,
199       int faces, Bool smooth, Bool caps_p, Bool wire)
200 {
201   tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size,
202           faces, smooth, caps_p, wire,
203           False);
204 }
205
206
207 void
208 cone (GLfloat x1, GLfloat y1, GLfloat z1,
209       GLfloat x2, GLfloat y2, GLfloat z2,
210       GLfloat diameter, GLfloat cap_size,
211       int faces, Bool smooth, Bool cap_p, Bool wire)
212 {
213   tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size,
214           faces, smooth, cap_p, wire,
215           True);
216 }