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