diff options
Diffstat (limited to 'hacks/glx/tube.c')
-rw-r--r-- | hacks/glx/tube.c | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/hacks/glx/tube.c b/hacks/glx/tube.c new file mode 100644 index 0000000..a5c0c96 --- /dev/null +++ b/hacks/glx/tube.c @@ -0,0 +1,403 @@ +/* tube, Copyright (c) 2001-2012 Jamie Zawinski <jwz@jwz.org> + * Utility functions to create tubes and cones in GL. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#include <math.h> + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> + +#ifdef HAVE_COCOA +#elif defined(HAVE_ANDROID) +# include <GLES/gl.h> +#else +# include <GL/gl.h> +#endif + +#ifdef HAVE_JWZGLES +# include "jwzgles.h" +#endif /* HAVE_JWZGLES */ + +#include "tube.h" + +typedef struct { GLfloat x, y, z; } XYZ; + + +static int +unit_tube (int faces, int smooth, int caps_p, int wire_p) +{ + int i; + int polys = 0; + GLfloat step = M_PI * 2 / faces; + GLfloat s2 = step/2; + GLfloat th; + GLfloat x, y, x0=0, y0=0; + int z = 0; + + int arraysize, out; + struct { XYZ p; XYZ n; GLfloat s, t; } *array; + + arraysize = (faces+1) * 6; + array = (void *) calloc (arraysize, sizeof(*array)); + if (! array) abort(); + out = 0; + + + /* #### texture coords are currently not being computed */ + + + /* side walls + */ + th = 0; + x = 1; + y = 0; + + if (!smooth) + { + x0 = cos (s2); + y0 = sin (s2); + } + + if (smooth) faces++; + + for (i = 0; i < faces; i++) + { + array[out].p.x = x; /* bottom point A */ + array[out].p.y = 0; + array[out].p.z = y; + + if (smooth) + array[out].n = array[out].p; /* its own normal */ + else + { + array[out].n.x = x0; /* mid-plane normal */ + array[out].n.y = 0; + array[out].n.z = y0; + } + out++; + + + array[out].p.x = x; /* top point A */ + array[out].p.y = 1; + array[out].p.z = y; + array[out].n = array[out-1].n; /* same normal */ + out++; + + + th += step; + x = cos (th); + y = sin (th); + + if (!smooth) + { + x0 = cos (th + s2); + y0 = sin (th + s2); + + array[out].p.x = x; /* top point B */ + array[out].p.y = 1; + array[out].p.z = y; + array[out].n = array[out-1].n; /* same normal */ + out++; + + + array[out] = array[out-3]; /* bottom point A */ + out++; + + array[out] = array[out-2]; /* top point B */ + out++; + + array[out].p.x = x; /* bottom point B */ + array[out].p.y = 0; + array[out].p.z = y; + array[out].n = array[out-1].n; /* same normal */ + out++; + + polys++; + } + + polys++; + if (out >= arraysize) abort(); + } + + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_NORMAL_ARRAY); + glEnableClientState (GL_TEXTURE_COORD_ARRAY); + + glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p); + glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n); + glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s); + + glFrontFace(GL_CCW); + glDrawArrays ((wire_p ? GL_LINES : + (smooth ? GL_TRIANGLE_STRIP : GL_TRIANGLES)), + 0, out); + + + /* End caps + */ + if (caps_p) + for (z = 0; z <= 1; z++) + { + out = 0; + if (! wire_p) + { + array[out].p.x = 0; + array[out].p.y = z; + array[out].p.z = 0; + + array[out].n.x = 0; + array[out].n.y = (z == 0 ? -1 : 1); + array[out].n.z = 0; + out++; + } + + th = 0; + for (i = (z == 0 ? 0 : faces); + (z == 0 ? i <= faces : i >= 0); + i += (z == 0 ? 1 : -1)) { + GLfloat x = cos (th); + GLfloat y = sin (th); + + array[out] = array[0]; /* same normal and texture */ + array[out].p.x = x; + array[out].p.y = z; + array[out].p.z = y; + out++; + + th += (z == 0 ? step : -step); + + polys++; + if (out >= arraysize) abort(); + } + + glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p); + glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n); + glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s); + + glFrontFace(GL_CCW); + glDrawArrays ((wire_p ? GL_LINE_LOOP : GL_TRIANGLE_FAN), 0, out); + } + + free(array); + + return polys; +} + + +static int +unit_cone (int faces, int smooth, int cap_p, int wire_p) +{ + int i; + int polys = 0; + GLfloat step = M_PI * 2 / faces; + GLfloat s2 = step/2; + GLfloat th; + GLfloat x, y, x0, y0; + + int arraysize, out; + struct { XYZ p; XYZ n; GLfloat s, t; } *array; + + arraysize = (faces+1) * 3; + array = (void *) calloc (arraysize, sizeof(*array)); + if (! array) abort(); + out = 0; + + + /* #### texture coords are currently not being computed */ + + + /* side walls + */ + + th = 0; + x = 1; + y = 0; + x0 = cos (s2); + y0 = sin (s2); + + for (i = 0; i < faces; i++) + { + array[out].p.x = x; /* bottom point A */ + array[out].p.y = 0; + array[out].p.z = y; + + if (smooth) + array[out].n = array[out].p; /* its own normal */ + else + { + array[out].n.x = x0; /* mid-plane normal */ + array[out].n.y = 0; + array[out].n.z = y0; + } + out++; + + + array[out].p.x = 0; /* tip point */ + array[out].p.y = 1; + array[out].p.z = 0; + + array[out].n.x = x0; /* mid-plane normal */ + array[out].n.y = 0; + array[out].n.z = y0; + out++; + + + th += step; + x0 = cos (th + s2); + y0 = sin (th + s2); + x = cos (th); + y = sin (th); + + array[out].p.x = x; /* bottom point B */ + array[out].p.y = 0; + array[out].p.z = y; + + if (smooth) + array[out].n = array[out].p; /* its own normal */ + else + array[out].n = array[out-1].n; /* same normal as other two */ + out++; + + + if (out >= arraysize) abort(); + polys++; + } + + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_NORMAL_ARRAY); + glEnableClientState (GL_TEXTURE_COORD_ARRAY); + + glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p); + glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n); + glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s); + + glFrontFace(GL_CCW); + glDrawArrays ((wire_p ? GL_LINES : GL_TRIANGLES), 0, out); + + + /* End cap + */ + if (cap_p) + { + out = 0; + + if (! wire_p) + { + array[out].p.x = 0; + array[out].p.y = 0; + array[out].p.z = 0; + + array[out].n.x = 0; + array[out].n.y = -1; + array[out].n.z = 0; + out++; + } + + for (i = 0, th = 0; i <= faces; i++) + { + GLfloat x = cos (th); + GLfloat y = sin (th); + + array[out] = array[0]; /* same normal and texture */ + array[out].p.x = x; + array[out].p.y = 0; + array[out].p.z = y; + out++; + th += step; + polys++; + if (out >= arraysize) abort(); + } + + glVertexPointer (3, GL_FLOAT, sizeof(*array), &array[0].p); + glNormalPointer ( GL_FLOAT, sizeof(*array), &array[0].n); + glTexCoordPointer (2, GL_FLOAT, sizeof(*array), &array[0].s); + + glFrontFace(GL_CCW); + glDrawArrays ((wire_p ? GL_LINE_LOOP : GL_TRIANGLE_FAN), 0, out); + } + + free (array); + + return polys; +} + + +static int +tube_1 (GLfloat x1, GLfloat y1, GLfloat z1, + GLfloat x2, GLfloat y2, GLfloat z2, + GLfloat diameter, GLfloat cap_size, + int faces, int smooth, int caps_p, int wire_p, + int cone_p) +{ + GLfloat length, X, Y, Z; + int polys = 0; + + if (diameter <= 0) abort(); + + X = (x2 - x1); + Y = (y2 - y1); + Z = (z2 - z1); + + if (X == 0 && Y == 0 && Z == 0) + return 0; + + length = sqrt (X*X + Y*Y + Z*Z); + + glPushMatrix(); + + glTranslatef(x1, y1, z1); + glRotatef (-atan2 (X, Y) * (180 / M_PI), 0, 0, 1); + glRotatef ( atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI), 1, 0, 0); + glScalef (diameter, length, diameter); + + /* extend the endpoints of the tube by the cap size in both directions */ + if (cap_size != 0) + { + GLfloat c = cap_size/length; + glTranslatef (0, -c, 0); + glScalef (1, 1+c+c, 1); + } + + if (cone_p) + polys = unit_cone (faces, smooth, caps_p, wire_p); + else + polys = unit_tube (faces, smooth, caps_p, wire_p); + + glPopMatrix(); + return polys; +} + + +int +tube (GLfloat x1, GLfloat y1, GLfloat z1, + GLfloat x2, GLfloat y2, GLfloat z2, + GLfloat diameter, GLfloat cap_size, + int faces, int smooth, int caps_p, int wire_p) +{ + return tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size, + faces, smooth, caps_p, wire_p, + 0); +} + + +int +cone (GLfloat x1, GLfloat y1, GLfloat z1, + GLfloat x2, GLfloat y2, GLfloat z2, + GLfloat diameter, GLfloat cap_size, + int faces, int smooth, int cap_p, int wire_p) +{ + return tube_1 (x1, y1, z1, x2, y2, z2, diameter, cap_size, + faces, smooth, cap_p, wire_p, + 1); +} |