1 /* tube, Copyright (c) 2001-2011 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;
33 unit_tube (int faces, int smooth, int caps_p, int wire_p)
37 GLfloat step = M_PI * 2 / faces;
40 GLfloat x, y, x0=0, y0=0;
44 struct { XYZ p; XYZ n; GLfloat s, t; } *array;
46 arraysize = (faces+1) * 6;
47 array = (void *) calloc (arraysize, sizeof(*array));
52 /* #### texture coords are currently not being computed */
69 for (i = 0; i < faces; i++)
71 array[out].p.x = x; /* bottom point A */
76 array[out].n = array[out].p; /* its own normal */
79 array[out].n.x = x0; /* mid-plane normal */
86 array[out].p.x = x; /* top point A */
89 array[out].n = array[out-1].n; /* same normal */
102 array[out].p.x = x; /* top point B */
105 array[out].n = array[out-1].n; /* same normal */
109 array[out] = array[out-3]; /* bottom point A */
112 array[out] = array[out-2]; /* top point B */
115 array[out].p.x = x; /* bottom point B */
118 array[out].n = array[out-1].n; /* same normal */
125 if (out >= arraysize) abort();
128 glEnableClientState (GL_VERTEX_ARRAY);
129 glEnableClientState (GL_NORMAL_ARRAY);
130 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
132 glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p);
133 glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n);
134 glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
136 glDrawArrays ((wire_p ? GL_LINES :
137 (smooth ? GL_TRIANGLE_STRIP : GL_TRIANGLES)),
144 for (z = 0; z <= 1; z++)
154 array[out].n.y = (z == 0 ? -1 : 1);
160 for (i = (z == 0 ? 0 : faces);
161 (z == 0 ? i <= faces : i >= 0);
162 i += (z == 0 ? 1 : -1)) {
163 GLfloat x = cos (th);
164 GLfloat y = sin (th);
166 array[out] = array[0]; /* same normal and texture */
172 th += (z == 0 ? step : -step);
175 if (out >= arraysize) abort();
178 glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p);
179 glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n);
180 glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
182 glDrawArrays ((wire_p ? GL_LINE_LOOP : GL_TRIANGLE_FAN), 0, out);
192 unit_cone (int faces, int smooth, int cap_p, int wire_p)
196 GLfloat step = M_PI * 2 / faces;
199 GLfloat x, y, x0, y0;
202 struct { XYZ p; XYZ n; GLfloat s, t; } *array;
204 arraysize = (faces+1) * 3;
205 array = (void *) calloc (arraysize, sizeof(*array));
206 if (! array) abort();
210 /* #### texture coords are currently not being computed */
222 for (i = 0; i < faces; i++)
224 array[out].p.x = x; /* bottom point A */
229 array[out].n = array[out].p; /* its own normal */
232 array[out].n.x = x0; /* mid-plane normal */
239 array[out].p.x = 0; /* tip point */
243 array[out].n.x = x0; /* mid-plane normal */
255 array[out].p.x = x; /* bottom point B */
260 array[out].n = array[out].p; /* its own normal */
262 array[out].n = array[out-1].n; /* same normal as other two */
266 if (out >= arraysize) abort();
270 glEnableClientState (GL_VERTEX_ARRAY);
271 glEnableClientState (GL_NORMAL_ARRAY);
272 glEnableClientState (GL_TEXTURE_COORD_ARRAY);
274 glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p);
275 glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n);
276 glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
278 glDrawArrays ((wire_p ? GL_LINES : GL_TRIANGLES), 0, out);
299 for (i = 0, th = 0; i <= faces; i++)
301 GLfloat x = cos (th);
302 GLfloat y = sin (th);
304 array[out] = array[0]; /* same normal and texture */
311 if (out >= arraysize) abort();
314 glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p);
315 glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n);
316 glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s);
318 glDrawArrays ((wire_p ? GL_LINE_LOOP : GL_TRIANGLE_FAN), 0, out);
328 tube_1 (GLfloat x1, GLfloat y1, GLfloat z1,
329 GLfloat x2, GLfloat y2, GLfloat z2,
330 GLfloat diameter, GLfloat cap_size,
331 int faces, int smooth, int caps_p, int wire_p,
334 GLfloat length, X, Y, Z;
337 if (diameter <= 0) abort();
343 if (X == 0 && Y == 0 && Z == 0)
346 length = sqrt (X*X + Y*Y + Z*Z);
350 glTranslatef(x1, y1, z1);
351 glRotatef (-atan2 (X, Y) * (180 / M_PI), 0, 0, 1);
352 glRotatef ( atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI), 1, 0, 0);
353 glScalef (diameter, length, diameter);
355 /* extend the endpoints of the tube by the cap size in both directions */
358 GLfloat c = cap_size/length;
359 glTranslatef (0, -c, 0);
360 glScalef (1, 1+c+c, 1);
364 polys = unit_cone (faces, smooth, caps_p, wire_p);
366 polys = unit_tube (faces, smooth, caps_p, wire_p);
374 tube (GLfloat x1, GLfloat y1, GLfloat z1,
375 GLfloat x2, GLfloat y2, GLfloat z2,
376 GLfloat diameter, GLfloat cap_size,
377 int faces, int smooth, int caps_p, int wire_p)
379 return tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size,
380 faces, smooth, caps_p, wire_p,
386 cone (GLfloat x1, GLfloat y1, GLfloat z1,
387 GLfloat x2, GLfloat y2, GLfloat z2,
388 GLfloat diameter, GLfloat cap_size,
389 int faces, int smooth, int cap_p, int wire_p)
391 return tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size,
392 faces, smooth, cap_p, wire_p,