6632c29d6882ec641a2e565f507b195974e3b5b4
[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, angle, a, b, c;
155
156   if (diameter <= 0) abort();
157
158   a = (x2 - x1);
159   b = (y2 - y1);
160   c = (z2 - z1);
161
162   length = sqrt (a*a + b*b + c*c);
163   angle = acos (a / length);
164
165   glPushMatrix();
166   glTranslatef(x1, y1, z1);
167   glScalef (length, length, length);
168
169   if (c == 0 && b == 0)
170     glRotatef (angle / (M_PI / 180), 0, 1, 0);
171   else
172     glRotatef (angle / (M_PI / 180), 0, -c, b);
173
174   glRotatef (-90, 0, 0, 1);
175   glScalef (diameter/length, 1, diameter/length);
176
177   /* extend the endpoints of the tube by the cap size in both directions */
178   if (cap_size != 0)
179     {
180       GLfloat c = cap_size/length;
181       glTranslatef (0, -c, 0);
182       glScalef (1, 1+c+c, 1);
183     }
184
185   if (cone_p)
186     unit_cone (faces, smooth, wire);
187   else
188     unit_tube (faces, smooth, wire);
189   glPopMatrix();
190 }
191
192
193 void
194 tube (GLfloat x1, GLfloat y1, GLfloat z1,
195       GLfloat x2, GLfloat y2, GLfloat z2,
196       GLfloat diameter, GLfloat cap_size,
197       int faces, Bool smooth, Bool wire)
198 {
199   tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size, faces, smooth, wire,
200           False);
201 }
202
203
204 void
205 cone (GLfloat x1, GLfloat y1, GLfloat z1,
206       GLfloat x2, GLfloat y2, GLfloat z2,
207       GLfloat diameter, GLfloat cap_size,
208       int faces, Bool smooth, Bool wire)
209 {
210   tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size, faces, smooth, wire,
211           True);
212 }