1 /* tube, Copyright (c) 2001-2010 Jamie Zawinski <jwz@jwz.org>
2 * Utility functions to create tubes and cones in GL.
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
22 # include <OpenGL/gl.h>
29 typedef struct { GLfloat x, y, z; } XYZ;
32 unit_tube (int faces, int smooth, int caps_p, int wire_p)
36 GLfloat step = M_PI * 2 / faces;
39 GLfloat x, y, x0=0, y0=0;
43 struct { XYZ p; XYZ n; GLfloat s, t; } *array;
45 arraysize = (faces+1) * 6;
46 array = (void *) calloc (arraysize, sizeof(*array));
51 /* #### texture coords are currently not being computed */
68 for (i = 0; i < faces; i++)
70 array[out].p.x = x; /* bottom point A */
75 array[out].n = array[out].p; /* its own normal */
78 array[out].n.x = x0; /* mid-plane normal */
85 array[out].p.x = x; /* top point A */
88 array[out].n = array[out-1].n; /* same normal */
101 array[out].p.x = x; /* top point B */
104 array[out].n = array[out-1].n; /* same normal */
108 array[out] = array[out-3]; /* bottom point A */
111 array[out] = array[out-2]; /* top point B */
114 array[out].p.x = x; /* bottom point B */
117 array[out].n = array[out-1].n; /* same normal */
124 if (out >= arraysize) abort();
127 glEnableClientState (GL_VERTEX_ARRAY);
128 glEnableClientState (GL_NORMAL_ARRAY);
129 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
131 glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p);
132 glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n);
133 glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
135 glDrawArrays ((wire_p ? GL_LINES :
136 (smooth ? GL_TRIANGLE_STRIP : GL_TRIANGLES)),
143 for (z = 0; z <= 1; z++)
153 array[out].n.y = (z == 0 ? -1 : 1);
159 for (i = (z == 0 ? 0 : faces);
160 (z == 0 ? i <= faces : i >= 0);
161 i += (z == 0 ? 1 : -1)) {
162 GLfloat x = cos (th);
163 GLfloat y = sin (th);
165 array[out] = array[0]; /* same normal and texture */
171 th += (z == 0 ? step : -step);
174 if (out >= arraysize) abort();
177 glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p);
178 glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n);
179 glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
181 glDrawArrays ((wire_p ? GL_LINE_LOOP : GL_TRIANGLE_FAN), 0, out);
189 unit_cone (int faces, int smooth, int cap_p, int wire_p)
193 GLfloat step = M_PI * 2 / faces;
196 GLfloat x, y, x0, y0;
199 struct { XYZ p; XYZ n; GLfloat s, t; } *array;
201 arraysize = (faces+1) * 3;
202 array = (void *) calloc (arraysize, sizeof(*array));
203 if (! array) abort();
207 /* #### texture coords are currently not being computed */
219 for (i = 0; i < faces; i++)
221 array[out].p.x = x; /* bottom point A */
226 array[out].n = array[out].p; /* its own normal */
229 array[out].n.x = x0; /* mid-plane normal */
236 array[out].p.x = 0; /* tip point */
240 array[out].n.x = x0; /* mid-plane normal */
252 array[out].p.x = x; /* bottom point B */
257 array[out].n = array[out].p; /* its own normal */
259 array[out].n = array[out-1].n; /* same normal as other two */
263 if (out >= arraysize) abort();
267 glEnableClientState (GL_VERTEX_ARRAY);
268 glEnableClientState (GL_NORMAL_ARRAY);
269 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
271 glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p);
272 glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n);
273 glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
275 glDrawArrays ((wire_p ? GL_LINES : GL_TRIANGLES), 0, out);
296 for (i = 0, th = 0; i <= faces; i++)
298 GLfloat x = cos (th);
299 GLfloat y = sin (th);
301 array[out] = array[0]; /* same normal and texture */
308 if (out >= arraysize) abort();
311 glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p);
312 glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n);
313 glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
315 glDrawArrays ((wire_p ? GL_LINE_LOOP : GL_TRIANGLE_FAN), 0, out);
325 tube_1 (GLfloat x1, GLfloat y1, GLfloat z1,
326 GLfloat x2, GLfloat y2, GLfloat z2,
327 GLfloat diameter, GLfloat cap_size,
328 int faces, int smooth, int caps_p, int wire_p,
331 GLfloat length, X, Y, Z;
334 if (diameter <= 0) abort();
340 if (X == 0 && Y == 0 && Z == 0)
343 length = sqrt (X*X + Y*Y + Z*Z);
347 glTranslatef(x1, y1, z1);
348 glRotatef (-atan2 (X, Y) * (180 / M_PI), 0, 0, 1);
349 glRotatef ( atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI), 1, 0, 0);
350 glScalef (diameter, length, diameter);
352 /* extend the endpoints of the tube by the cap size in both directions */
355 GLfloat c = cap_size/length;
356 glTranslatef (0, -c, 0);
357 glScalef (1, 1+c+c, 1);
361 polys = unit_cone (faces, smooth, caps_p, wire_p);
363 polys = unit_tube (faces, smooth, caps_p, wire_p);
371 tube (GLfloat x1, GLfloat y1, GLfloat z1,
372 GLfloat x2, GLfloat y2, GLfloat z2,
373 GLfloat diameter, GLfloat cap_size,
374 int faces, int smooth, int caps_p, int wire_p)
376 return tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size,
377 faces, smooth, caps_p, wire_p,
383 cone (GLfloat x1, GLfloat y1, GLfloat z1,
384 GLfloat x2, GLfloat y2, GLfloat z2,
385 GLfloat diameter, GLfloat cap_size,
386 int faces, int smooth, int cap_p, int wire_p)
388 return tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size,
389 faces, smooth, cap_p, wire_p,