From d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 16 Oct 2018 10:08:48 +0200 Subject: Original 5.40 --- hacks/glx/dnalogo.c | 3639 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3639 insertions(+) create mode 100644 hacks/glx/dnalogo.c (limited to 'hacks/glx/dnalogo.c') diff --git a/hacks/glx/dnalogo.c b/hacks/glx/dnalogo.c new file mode 100644 index 0000000..2b24f83 --- /dev/null +++ b/hacks/glx/dnalogo.c @@ -0,0 +1,3639 @@ +/* DNA Logo, Copyright (c) 2001-2018 Jamie Zawinski + * + * DNA Lounge + * + * Restaurant -- Bar -- Nightclub -- Cafe -- Est. 1985. + * + * 375 Eleventh Street + * San Francisco, CA + * 94103 + * + * https://www.dnalounge.com/ + * http://www.dnapizza.com/ + * + * 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. + */ + +#define DEFAULTS __extension__ \ + "*delay: 25000 \n" \ + "*showFPS: False \n" \ + "*wireframe: False \n" \ + "*doGasket: True \n" \ + "*doHelix: True \n" \ + "*doLadder: True \n" \ + "*doFrame: True \n" \ + "*wallFacets: 360 \n" \ + "*barFacets: 90 \n" \ + "*clockwise: False \n" \ + "*turns: 0.72 \n" \ + "*turnSpacing: 2.3 \n" \ + "*barSpacing: 0.268 \n" \ + "*wallHeight: 0.42 \n" \ + "*wallThickness: 0.12 \n" \ + "*barThickness: 0.058 \n" \ + "*wallTaper: 0.95 \n" \ + "*gasketSize: 2.0 \n" \ + "*gasketDepth: 0.15 \n" \ + "*gasketThickness: 0.4 \n" \ + "*frameSize: 1.28 \n" \ + "*frameDepth: 0.01 \n" \ + "*frameThickness: 0.03 \n" \ + "*triangleSize: 0.045 \n" \ + "*cwFacets: 3 \n" \ + "*cwDiscFacets: 64 \n" \ + "*cwSpread: 0.5 \n" \ + "*cwLineWidth: 0.18 \n" \ + "*cwThickness: 0.15 \n" \ + "*cwCapSize: 0.4 \n" \ + "*text: CODEWORD\n" \ + "*speed: 1.0 \n" \ + "*mode: both" "\n" \ + ".background: #000000\n" \ + ".foreground: #00AA00\n" \ + ".cwForeground: #FCA816\n" \ + ".cwBackground: #943225\n" \ + "*cwFont: " CWFONT "\n" \ + "*geometry: =640x640\n" \ + +# if defined(HAVE_COCOA) || defined(HAVE_ANDROID) +# define CWFONT "Yearling 28, OCR A Std 24" +# else +# define CWFONT "-*-helvetica-medium-r-normal-*-*-240-*-*-*-*-*-*" +# endif + +# define free_logo 0 +# define release_logo 0 +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +#undef DXF_OUTPUT_HACK + +#ifdef DXF_OUTPUT_HACK /* When this is defined, instead of rendering + to the screen, we write a DXF CAD file to stdout. + This is a kludge of shocking magnitude... + Maybe there's some other way to intercept all + glVertex3f calls than with a #define? */ +# define unit_tube dxf_unit_tube +# define unit_cone dxf_unit_cone +# define tube_1 dxf_tube_1 +# define tube dxf_tube +# define cone dxf_cone +#endif /* DXF_OUTPUT_HACK */ + +#include "xlockmore.h" +#include "normals.h" +#include "tube.h" +#include "sphere.h" +#include "rotator.h" +#include "gltrackball.h" +#include "utf8wc.h" +#include "texfont.h" + +#ifdef USE_GL /* whole file */ + +#ifdef HAVE_JWZGLES +# include "dnapizza.h" +#else +# define HAVE_TESS +#endif + +typedef enum { + HELIX_IN, HELIX, HELIX_OUT, + PIZZA_IN, PIZZA, PIZZA_OUT, + HELIX_AND_PIZZA, +# ifdef CW + CODEWORD_IN, CODEWORD, CODEWORD_OUT, CODEWORD_BLANK +# endif +} glyph_mode; + +typedef struct { + Bool spinning_p; + GLfloat position; /* 0.0 - 1.0 */ + GLfloat position_eased; /* 0.0 - 1.0, eased in and out */ + GLfloat easement; /* portion of path that is eased. <= 0.5 */ + GLfloat speed; /* how far along the path (may be negative) */ + GLfloat probability; /* relative likelyhood to start spinning */ +} spinner; + +typedef struct { + GLXContext *glx_context; + + GLuint helix_list, helix_list_wire, helix_list_facetted; + GLuint pizza_list, pizza_list_wire, pizza_list_facetted; + GLuint gasket_list, gasket_list_wire; + GLuint frame_list, frame_list_wire; + int polys[7]; + + int wall_facets; + int bar_facets; + Bool clockwise; + GLfloat color[4]; + + GLfloat turns; + GLfloat turn_spacing; + GLfloat bar_spacing; + GLfloat wall_height; + GLfloat wall_thickness; + GLfloat bar_thickness; + GLfloat wall_taper; + + GLfloat gasket_size; + GLfloat gasket_depth; + GLfloat gasket_thickness; + + GLfloat frame_size; + GLfloat frame_depth; + GLfloat frame_thickness; + GLfloat triangle_size; + +# ifdef CW + int codeword_facets, codeword_disc_facets; + GLfloat codeword_spread, codeword_line_width, codeword_thickness; + GLfloat codeword_cap_size; + const char *codeword_text; + char *codeword_text_out; + int *codeword_text_points; + XYZ *codeword_path; + int codeword_path_npoints; + int codeword_nguides; + XYZ *codeword_guides; + GLfloat codeword_color[4], codeword_bg[4]; + texture_font_data *font; +# endif + +# ifdef DEBUG + GLfloat persp_off, pos_off; + texture_font_data *label_font; +# endif + + GLfloat speed; + glyph_mode mode; + glyph_mode anim_state; + GLfloat anim_ratio; + + spinner gasket_spinnerx, gasket_spinnery, gasket_spinnerz; + spinner scene_spinnerx, scene_spinnery; /* for DNA */ +# ifdef CW + rotator *scene_rot; /* for Codeword */ +# endif + spinner helix_spinnerz; + spinner pizza_spinnery, pizza_spinnerz; + spinner frame_spinner; + + trackball_state *trackball; + Bool button_down_p; + + int wire_overlay; /* frame countdown */ + +} logo_configuration; + +static logo_configuration *dcs = NULL; + +static XrmOptionDescRec opts[] = { + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-pizza", ".mode", XrmoptionNoArg, "pizza" }, + { "-helix", ".mode", XrmoptionNoArg, "helix" }, + { "-both", ".mode", XrmoptionNoArg, "both" }, +# ifdef CW + { "-codeword", ".mode", XrmoptionNoArg, "codeword" }, + { "-cw", ".mode", XrmoptionNoArg, "codeword" }, + { "-text", ".text", XrmoptionSepArg, 0 }, +# endif +}; + +ENTRYPOINT ModeSpecOpt logo_opts = {countof(opts), opts, 0, NULL, NULL}; + +#define PROBABILITY_SCALE 600 + + +#ifdef DXF_OUTPUT_HACK + +# define glBegin dxf_glBegin +# define glVertex3f dxf_glVertex3f +# define glVertex3dv dxf_glVertex3dv +# define glEnd dxf_glEnd +# define glVertexPointer dxf_glVertexPointer +# define glDrawArrays dxf_glDrawArrays + +static int dxf_type, dxf_point, dxf_point_total, dxf_layer, dxf_color; +static GLfloat dxf_quads[4*4]; + +static void +dxf_glBegin (int type) +{ + dxf_type = type; + dxf_point = 0; + dxf_point_total = 0; +} + +static void +dxf_glVertex3f (GLfloat ox, GLfloat oy, GLfloat oz) +{ + int i = 0; + GLfloat m[4*4]; + GLfloat x, y, z; + + /* Transform the point into modelview space. */ + glGetFloatv (GL_MODELVIEW_MATRIX, m); + x = ox * m[0] + oy * m[4] + oz * m[8] + m[12]; + y = ox * m[1] + oy * m[5] + oz * m[9] + m[13]; + z = ox * m[2] + oy * m[6] + oz * m[10] + m[14]; + + dxf_quads[dxf_point*3+0] = x; + dxf_quads[dxf_point*3+1] = y; + dxf_quads[dxf_point*3+2] = z; + dxf_point++; + dxf_point_total++; + + switch (dxf_type) { + case GL_QUADS: + if (dxf_point < 4) return; + + fprintf (stdout, "0\n3DFACE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color); + fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "12\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "22\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "32\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "13\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "23\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "33\n%.6f\n", dxf_quads[i++]); + dxf_point = 0; + break; + + case GL_QUAD_STRIP: + if (dxf_point < 4) return; + + fprintf (stdout, "0\n3DFACE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color); + fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "12\n%.6f\n", dxf_quads[i+3]); /* funky quad strip */ + fprintf (stdout, "22\n%.6f\n", dxf_quads[i+4]); /* vert order: 1243. */ + fprintf (stdout, "32\n%.6f\n", dxf_quads[i+5]); + + fprintf (stdout, "13\n%.6f\n", dxf_quads[i]); + fprintf (stdout, "23\n%.6f\n", dxf_quads[i+1]); + fprintf (stdout, "33\n%.6f\n", dxf_quads[i+2]); + i += 6; + + dxf_quads[0] = dxf_quads[6]; /* copy point 3 to pos 1 */ + dxf_quads[1] = dxf_quads[7]; + dxf_quads[2] = dxf_quads[8]; + dxf_quads[3] = dxf_quads[9]; /* copy point 4 to pos 2 */ + dxf_quads[4] = dxf_quads[10]; + dxf_quads[5] = dxf_quads[11]; + dxf_point = 2; /* leave those two points in queue */ + break; + + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: + if (dxf_point < 3) return; + + fprintf (stdout, "0\n3DFACE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color); + fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "12\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "22\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "32\n%.6f\n", dxf_quads[i++]); + + i -= 3; + fprintf (stdout, "13\n%.6f\n", dxf_quads[i++]); /* dup pt 4 as pt 3. */ + fprintf (stdout, "23\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "33\n%.6f\n", dxf_quads[i++]); + + dxf_point = 0; + if (dxf_type == GL_TRIANGLE_FAN) + { + dxf_quads[3] = dxf_quads[6]; /* copy point 3 to point 2 */ + dxf_quads[4] = dxf_quads[7]; + dxf_quads[5] = dxf_quads[8]; + dxf_point = 2; /* leave two points in queue */ + } + break; + + case GL_TRIANGLE_STRIP: + if (dxf_point < 3) return; + + fprintf (stdout, "0\n3DFACE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color); + + fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "12\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "22\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "32\n%.6f\n", dxf_quads[i++]); + + i -= 3; + fprintf (stdout, "13\n%.6f\n", dxf_quads[i++]); /* dup pt 4 as pt 3. */ + fprintf (stdout, "23\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "33\n%.6f\n", dxf_quads[i++]); + + dxf_quads[0] = dxf_quads[3]; /* copy point 2 to pos 1 */ + dxf_quads[1] = dxf_quads[4]; + dxf_quads[2] = dxf_quads[5]; + dxf_quads[3] = dxf_quads[6]; /* copy point 3 to pos 2 */ + dxf_quads[4] = dxf_quads[7]; + dxf_quads[5] = dxf_quads[8]; + dxf_point = 2; /* leave those two points in queue */ + break; + + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + + if (dxf_point_total == 1) + { + dxf_quads[6] = ox; + dxf_quads[7] = oy; + dxf_quads[8] = oz; + } + + if (dxf_point < 2) return; + + fprintf (stdout, "0\nLINE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color); + + fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]); + + fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]); + fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]); + + dxf_point = 0; + if (dxf_type != GL_LINES) + { + dxf_quads[0] = dxf_quads[3]; + dxf_quads[1] = dxf_quads[4]; + dxf_quads[2] = dxf_quads[5]; + dxf_point = 1; + } + break; + + default: + abort(); + break; + } +} + + +static void +dxf_glVertex3dv (const GLdouble *v) +{ + glVertex3f (v[0], v[1], v[2]); +} + + +static void +dxf_glEnd(void) +{ + if (dxf_type == GL_LINE_LOOP) /* close loop */ + glVertex3f (dxf_quads[6], dxf_quads[7], dxf_quads[8]); + dxf_type = -1; + dxf_point = 0; + dxf_point_total = 0; +} + + +static void +dxf_start (void) +{ + fprintf (stdout, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n"); + fprintf (stdout, "0\nSECTION\n2\nENTITIES\n"); +} + +static void +dxf_end (void) +{ + fprintf (stdout, "0\nENDSEC\n0\nEOF\n"); + exit (0); +} + + +static const GLvoid *dxf_vp; +static GLsizei dxf_vp_size; +static GLsizei dxf_vp_stride; + +static void +dxf_glVertexPointer (GLint size, GLenum type, GLsizei stride, + const GLvoid *pointer) +{ + if (type != GL_FLOAT) abort(); + if (stride <= 0) abort(); + dxf_vp = pointer; + dxf_vp_size = size; + dxf_vp_stride = stride; +} + +static void +dxf_glDrawArrays (GLenum mode, GLint first, GLsizei count) +{ + int i; + unsigned char *a = (unsigned char *) dxf_vp; + dxf_glBegin (mode); + for (i = first; i < first+count; i++) + { + GLfloat *fa = (GLfloat *) a; + dxf_glVertex3f (fa[0], fa[1], fa[2]); + a += dxf_vp_stride; + } + dxf_glEnd(); +} + + +# define XYZ tube_XYZ /* avoid conflict with normals.h */ +# include "tube.c" /* Yes, I really am including a C file. */ +# undef XYZ +# define XYZ sphere_XYZ +# define unit_sphere unit_sphere_dxf +# define unit_dome unit_dome_dxf +# include "sphere.c" +# undef XYZ + +#endif /* DXF_OUTPUT_HACK */ + + + +/* Calculate the angle (in radians) between two vectors. + */ +static GLfloat +vector_angle (double ax, double ay, double az, + double bx, double by, double bz) +{ + double La = sqrt (ax*ax + ay*ay + az*az); + double Lb = sqrt (bx*bx + by*by + bz*bz); + double cc, angle; + + if (La == 0 || Lb == 0) return 0; + if (ax == bx && ay == by && az == bz) return 0; + + /* dot product of two vectors is defined as: + La * Lb * cos(angle between vectors) + and is also defined as: + ax*bx + ay*by + az*bz + so: + La * Lb * cos(angle) = ax*bx + ay*by + az*bz + cos(angle) = (ax*bx + ay*by + az*bz) / (La * Lb) + angle = acos ((ax*bx + ay*by + az*bz) / (La * Lb)); + */ + cc = (ax*bx + ay*by + az*bz) / (La * Lb); + if (cc > 1) cc = 1; /* avoid fp rounding error (1.000001 => sqrt error) */ + angle = acos (cc); + + return (angle); +} + + +# ifdef CW + +static void +normalize (XYZ *p) +{ + GLfloat d = sqrt (p->x*p->x + p->y*p->y + p->z*p->z); + if (d != 0) + { + p->x /= d; + p->y /= d; + p->z /= d; + } + else + { + p->x = p->y = p->z = 0; + } +} + + +static double +dot (const XYZ u, const XYZ v) +{ + return (u.x * v.x) + (u.y * v.y) + (u.z * v.z); +} + +#endif /* CW */ + + +/* Make the helix + */ + +static int +make_helix (logo_configuration *dc, int facetted, int wire) +{ + int polys = 0; + int wall_facets = dc->wall_facets / (facetted ? 10 : 1); + GLfloat th; + GLfloat max_th = M_PI * 2 * dc->turns; + GLfloat th_inc = M_PI * 2 / wall_facets; + + GLfloat x1=0, y1=0, x2=0, y2=0; + GLfloat x1b=0, y1b=0, x2b=0, y2b=0; + GLfloat z1=0, z2=0; + GLfloat h1=0, h2=0; + GLfloat h1off=0, h2off=0; + GLfloat z_inc = dc->turn_spacing / wall_facets; + + th = 0; + x1 = 1; + y1 = 0; + x1b = 1; + y1b = 0; + + z1 = -(dc->turn_spacing * dc->turns / 2); + + h1 = (dc->wall_taper > 0 ? 0 : dc->wall_height / 2); + h1off = (dc->wall_taper > 0 ? -dc->wall_height / 2 : 0); + + if (!dc->clockwise) + z1 = -z1, z_inc = -z_inc, h1off = -h1off; + + /* Leading end-cap + */ + if (!wire && h1 > 0) + { + GLfloat nx, ny; + glFrontFace(GL_CCW); + glBegin(GL_QUADS); + nx = cos (th + M_PI/2); + ny = sin (th + M_PI/2); + glNormal3f(nx, ny, 0); + glVertex3f( x1, y1, z1 - h1 + h1off); + glVertex3f( x1, y1, z1 + h1 + h1off); + glVertex3f(x1b, y1b, z1 + h1 + h1off); + glVertex3f(x1b, y1b, z1 - h1 + h1off); + polys++; + glEnd(); + } + + while (th + th_inc <= max_th) + { + GLfloat thick = dc->wall_thickness; + + th += th_inc; + + x2 = cos (th); + y2 = sin (th); + z2 = z1 + z_inc; + + h2 = h1; + h2off = h1off; + + if (dc->wall_taper > 0) + { + h2off = 0; + if (th < dc->wall_taper) + { + h2 = dc->wall_height/2 * cos (M_PI / 2 + * (1 - (th / dc->wall_taper))); + if (dc->clockwise) + h2off = h2 - dc->wall_height/2; + else + h2off = dc->wall_height/2 - h2; + + if (th + th_inc <= 0) + thick = 0; + else + thick *= cos (M_PI / 2 * (1 - (th / dc->wall_taper))); + } + else if (th >= max_th - dc->wall_taper) + { + if (th + th_inc > max_th) /* edge case: always come to a point */ + h2 = 0; + else + h2 = dc->wall_height/2 * cos (M_PI / 2 + * (1 - ((max_th - th) + / dc->wall_taper))); + if (dc->clockwise) + h2off = dc->wall_height/2 - h2; + else + h2off = h2 - dc->wall_height/2; + + if (th + th_inc > max_th) + thick = 0; + else + thick *= cos(M_PI / 2 * (1 - ((max_th - th)/dc->wall_taper))); + } + } + + x2b = x2 * (1 - thick); + y2b = y2 * (1 - thick); + + /* outer face + */ + glFrontFace(GL_CW); + glBegin(wire ? GL_LINES : GL_QUADS); + glNormal3f(x1, y1, 0); + glVertex3f(x1, y1, z1 - h1 + h1off); + glVertex3f(x1, y1, z1 + h1 + h1off); + glNormal3f(x2, y2, 0); + glVertex3f(x2, y2, z2 + h2 + h2off); + glVertex3f(x2, y2, z2 - h2 + h2off); + polys++; + glEnd(); + + /* inner face + */ + glFrontFace(GL_CCW); + glBegin(wire ? GL_LINES : GL_QUADS); + glNormal3f(-x1b, -y1b, 0); + glVertex3f( x1b, y1b, z1 - h1 + h1off); + glVertex3f( x1b, y1b, z1 + h1 + h1off); + glNormal3f(-x2b, -y2b, 0); + glVertex3f( x2b, y2b, z2 + h2 + h2off); + glVertex3f( x2b, y2b, z2 - h2 + h2off); + polys++; + glEnd(); + + /* top face + */ + glFrontFace(GL_CCW); + /* glNormal3f(0, 0, 1);*/ + do_normal (x2, y2, z2 + h2 + h2off, + x2b, y2b, z2 + h2 + h2off, + x1b, y1b, z1 + h1 + h1off); + glBegin(wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f( x2, y2, z2 + h2 + h2off); + glVertex3f( x2b, y2b, z2 + h2 + h2off); + glVertex3f( x1b, y1b, z1 + h1 + h1off); + glVertex3f( x1, y1, z1 + h1 + h1off); + polys++; + glEnd(); + + /* bottom face + */ + glFrontFace(GL_CCW); + do_normal ( x1, y1, z1 - h1 + h1off, + x1b, y1b, z1 - h1 + h1off, + x2b, y2b, z2 - h2 + h2off); + glBegin(wire ? GL_LINE_LOOP : GL_QUADS); + glNormal3f(0, 0, -1); + glVertex3f( x1, y1, z1 - h1 + h1off); + glVertex3f( x1b, y1b, z1 - h1 + h1off); + glVertex3f( x2b, y2b, z2 - h2 + h2off); + glVertex3f( x2, y2, z2 - h2 + h2off); + polys++; + glEnd(); + + x1 = x2; + y1 = y2; + x1b = x2b; + y1b = y2b; + z1 += z_inc; + h1 = h2; + h1off = h2off; + } + + /* Trailing end-cap + */ + if (!wire && h2 > 0) + { + GLfloat nx, ny; + glFrontFace(GL_CW); + glBegin(GL_QUADS); + nx = cos (th + M_PI/2); + ny = sin (th + M_PI/2); + glNormal3f(nx, ny, 0); + glVertex3f(x2, y2, z1 - h2 + h2off); + glVertex3f(x2, y2, z1 + h2 + h2off); + glVertex3f(x2b, y2b, z1 + h2 + h2off); + glVertex3f(x2b, y2b, z1 - h2 + h2off); + polys++; + glEnd(); + } + return polys; +} + + +static int +make_ladder (logo_configuration *dc, int facetted, int wire) +{ + int polys = 0; + GLfloat th; + GLfloat max_th = dc->turns * M_PI * 2; + GLfloat max_z = dc->turns * dc->turn_spacing; + GLfloat z_inc = dc->bar_spacing; + GLfloat th_inc = M_PI * 2 * (dc->bar_spacing / dc->turn_spacing); + GLfloat x, y, z; + + /* skip forward to center the bars in the helix... */ + int i; + GLfloat usable_th = max_th - dc->wall_taper; + GLfloat usable_z = max_z / (max_th / usable_th); + int nbars = usable_z / dc->bar_spacing; + GLfloat used_z, pad_z, pad_ratio; + + if (! (nbars & 1)) nbars--; /* always an odd number of bars */ + + used_z = (nbars - 1) * dc->bar_spacing; + pad_z = max_z - used_z; + pad_ratio = pad_z / max_z; + + th = (max_th * pad_ratio/2); + z = -(max_z / 2) + (max_z * pad_ratio/2); + + /* ##### WHYYYYYY */ + /* The image is not reflected across line y = -x and I don't know why. */ + th += M_PI * -0.035; + z -= 0.08; + + if (!dc->clockwise) + z = -z, z_inc = -z_inc; + + glFrontFace(GL_CCW); + for (i = 0; i < nbars; i++) + { + int facets = dc->bar_facets / (facetted ? 14 : 1); + if (facets <= 3) facets = 3; + x = cos (th) * (1 - dc->wall_thickness); + y = sin (th) * (1 - dc->wall_thickness); + polys += tube ( x, y, z, + -x, -y, z, + dc->bar_thickness, 0, facets, + True, True, wire); + z += z_inc; + th += th_inc; + } + return polys; +} + + + +/* Make the gasket + */ + + +static int +make_gasket (logo_configuration *dc, int wire) +{ + int polys = 0; + int i; + int points_size; + int npoints = 0; + int nctrls = 0; + int res = 360/8; + GLfloat d2r = M_PI / 180; + + GLfloat thick2 = (dc->gasket_thickness / dc->gasket_size) / 2; + + GLfloat *pointsx0, *pointsy0, *pointsx1, *pointsy1, *normals; + + GLfloat r0 = 0.750; /* 395 */ + GLfloat r1a = 0.825; /* bottom of wall below upper left hole */ + GLfloat r1b = 0.867; /* center of upper left hole */ + GLfloat r1c = 0.909; /* top of wall above hole */ + GLfloat r1 = 0.916; /* 471 */ + GLfloat r2 = 0.963; /* 490 */ + GLfloat r3 = 0.960; /* 499 */ + GLfloat r4 = 1.000; /* 507 */ + GLfloat r5 = 1.080; /* 553 */ + + GLfloat ctrl_r[100], ctrl_th[100]; + + glPushMatrix(); + +# ifdef DXF_OUTPUT_HACK + if (! wire) res *= 8; +# endif + +# define POINT(r,th) \ + ctrl_r [nctrls] = r, \ + ctrl_th[nctrls] = (th * d2r), \ + nctrls++ + + POINT (0.829, 0); /* top indentation, right half */ + POINT (0.831, 0.85); + POINT (0.835, 1.81); + POINT (0.841, 2.65); + POINT (0.851, 3.30); + POINT (0.862, 3.81); + POINT (0.872, 3.95); + + POINT (r4, 4.0); /* moving clockwise... */ + POINT (r4, 47.0); + POINT (r1, 47.0); + POINT (r1, 53.0); + POINT (r2, 55.5); + POINT (r2, 72.3); + POINT (r1, 74.0); + POINT (r1, 100.0); + POINT (r3, 102.5); + POINT (r3, 132.0); + POINT (r1, 133.0); + + POINT (r1, 180.7); + POINT (r2, 183.6); + POINT (r2, 210.0); + POINT (r1, 212.0); + POINT (r1, 223.2); + POINT (r5, 223.2); + POINT (r5, 225.0); + POINT (r4, 225.0); + + POINT (r4, 316.8); /* upper left indentation */ + POINT (0.990, 316.87); + POINT (0.880, 317.21); + POINT (0.872, 317.45); + POINT (0.869, 317.80); + POINT (0.867, 318.10); + + POINT (0.867, 318.85); + POINT (0.869, 319.15); + POINT (0.872, 319.50); + POINT (0.880, 319.74); + POINT (0.990, 320.08); + + POINT (r4, 338.0); + if (! wire) + { + POINT (r1a, 338.0); /* cut-out disc */ + POINT (r1a, 344.0); + } + POINT (r4, 344.0); + POINT (r4, 356.0); + + POINT (0.872, 356.05); /* top indentation, left half */ + POINT (0.862, 356.19); + POINT (0.851, 356.70); + POINT (0.841, 357.35); + POINT (0.835, 358.19); + POINT (0.831, 359.15); + POINT (0.829, 360); +# undef POINT + + points_size = res + (nctrls * 2); + pointsx0 = (GLfloat *) malloc (points_size * sizeof(GLfloat)); + pointsy0 = (GLfloat *) malloc (points_size * sizeof(GLfloat)); + pointsx1 = (GLfloat *) malloc (points_size * sizeof(GLfloat)); + pointsy1 = (GLfloat *) malloc (points_size * sizeof(GLfloat)); + normals = (GLfloat *) malloc (points_size * sizeof(GLfloat) * 2); + + npoints = 0; + for (i = 1; i < nctrls; i++) + { + GLfloat from_r = ctrl_r [i-1]; + GLfloat from_th = ctrl_th[i-1]; + GLfloat to_r = ctrl_r [i]; + GLfloat to_th = ctrl_th[i]; + + GLfloat step = 2*M_PI / res; + int nsteps = 1 + ((to_th - from_th) / step); + int j; + + for (j = 0; j < nsteps + (i == nctrls-1); j++) + { + GLfloat r = from_r + (j * (to_r - from_r) / nsteps); + GLfloat th = from_th + (j * (to_th - from_th) / nsteps); + + GLfloat cth = cos(th) * dc->gasket_size; + GLfloat sth = sin(th) * dc->gasket_size; + + pointsx0[npoints] = r0 * cth; /* inner ring */ + pointsy0[npoints] = r0 * sth; + pointsx1[npoints] = r * cth; /* outer ring */ + pointsy1[npoints] = r * sth; + npoints++; + + if (npoints >= points_size) abort(); + } + } + + /* normals for the outer ring */ + for (i = 1; i < npoints; i++) + { + XYZ a, b, c, n; + a.x = pointsx1[i-1]; + a.y = pointsy1[i-1]; + a.z = 0; + b.x = pointsx1[i]; + b.y = pointsy1[i]; + b.z = 0; + c = b; + c.z = 1; + n = calc_normal (a, b, c); + normals[(i-1)*2 ] = n.x; + normals[(i-1)*2+1] = n.y; + } + + glRotatef(-90, 0, 1, 0); + glRotatef(180, 0, 0, 1); + + if (wire) + { + GLfloat z; + for (z = -thick2; z <= thick2; z += thick2*2) + { +# if 1 + /* inside edge */ + glBegin (GL_LINE_LOOP); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx0[i], pointsy0[i], z); + polys += npoints; + glEnd(); + + /* outside edge */ + glBegin (GL_LINE_LOOP); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx1[i], pointsy1[i], z); + polys += npoints; + glEnd(); +# else + for (i = 1; i < npoints; i++) + { + glBegin (GL_LINE_STRIP); + glVertex3f (pointsx0[i-1], pointsy0[i-1], z); + glVertex3f (pointsx0[i ], pointsy0[i ], z); + glVertex3f (pointsx1[i ], pointsy1[i ], z); + glVertex3f (pointsx1[i-1], pointsy1[i-1], z); + glEnd(); + } + polys += npoints; +# endif + } +#if 1 + glBegin (GL_LINES); + for (i = 0; i < npoints; i++) + { + /* inside rim */ + glVertex3f (pointsx0[i], pointsy0[i], -thick2); + glVertex3f (pointsx0[i], pointsy0[i], thick2); + /* outside rim */ + glVertex3f (pointsx1[i], pointsy1[i], -thick2); + glVertex3f (pointsx1[i], pointsy1[i], thick2); + } + polys += npoints; + glEnd(); +#endif + } + else + { + /* top */ + glFrontFace(GL_CW); + glNormal3f(0, 0, -1); + glBegin (GL_QUAD_STRIP); + for (i = 0; i < npoints; i++) + { + glVertex3f (pointsx0[i], pointsy0[i], -thick2); + glVertex3f (pointsx1[i], pointsy1[i], -thick2); + } + polys += npoints; + glEnd(); + + /* bottom */ + glFrontFace(GL_CCW); + glNormal3f(0, 0, 1); + glBegin (GL_QUAD_STRIP); + for (i = 0; i < npoints; i++) + { + glVertex3f (pointsx0[i], pointsy0[i], thick2); + glVertex3f (pointsx1[i], pointsy1[i], thick2); + } + polys += npoints; + glEnd(); + + /* inside edge */ + glFrontFace(GL_CW); + glBegin (GL_QUAD_STRIP); + for (i = 0; i < npoints; i++) + { + glNormal3f (-pointsx0[i], -pointsy0[i], 0); + glVertex3f ( pointsx0[i], pointsy0[i], thick2); + glVertex3f ( pointsx0[i], pointsy0[i], -thick2); + } + polys += npoints; + glEnd(); + + /* outside edge */ + glFrontFace(GL_CCW); + glBegin (GL_QUADS); + { + for (i = 0; i < npoints-1; i++) + { + int ia = (i == 0 ? npoints-2 : i-1); + int iz = (i == npoints-2 ? 0 : i+1); + GLfloat x = pointsx1[i]; + GLfloat y = pointsy1[i]; + GLfloat xz = pointsx1[iz]; + GLfloat yz = pointsy1[iz]; + + GLfloat nxa = normals[ia*2]; /* normal of [i-1 - i] face */ + GLfloat nya = normals[ia*2+1]; + GLfloat nx = normals[i*2]; /* normal of [i - i+1] face */ + GLfloat ny = normals[i*2+1]; + GLfloat nxz = normals[iz*2]; /* normal of [i+1 - i+2] face */ + GLfloat nyz = normals[iz*2+1]; + + GLfloat anglea = vector_angle (nx, ny, 0, nxa, nya, 0); + GLfloat anglez = vector_angle (nx, ny, 0, nxz, nyz, 0); + GLfloat pointy = 0.6; + + if (anglea > pointy) + { + glNormal3f (nx, ny, 0); + glVertex3f (x, y, thick2); + glVertex3f (x, y, -thick2); + } + else + { + glNormal3f ((nxa + nx) / 2, (nya + ny) / 2, 0); + glVertex3f (x, y, thick2); + glVertex3f (x, y, -thick2); + } + + if (anglez > pointy) + { + glNormal3f (nx, ny, 0); + glVertex3f (xz, yz, -thick2); + glVertex3f (xz, yz, thick2); + } + else + { + glNormal3f ((nx + nxz) / 2, (ny + nyz) / 2, 0); + glVertex3f (xz, yz, -thick2); + glVertex3f (xz, yz, thick2); + } + } + polys += npoints; + } + glEnd(); + } + + /* Fill in the upper left hole... + */ + { + GLfloat th; + npoints = 0; + + th = 338.0 * d2r; + pointsx0[npoints] = r1c * cos(th) * dc->gasket_size; + pointsy0[npoints] = r1c * sin(th) * dc->gasket_size; + npoints++; + pointsx0[npoints] = r4 * cos(th) * dc->gasket_size; + pointsy0[npoints] = r4 * sin(th) * dc->gasket_size; + npoints++; + + th = 344.0 * d2r; + pointsx0[npoints] = r1c * cos(th) * dc->gasket_size; + pointsy0[npoints] = r1c * sin(th) * dc->gasket_size; + npoints++; + pointsx0[npoints] = r4 * cos(th) * dc->gasket_size; + pointsy0[npoints] = r4 * sin(th) * dc->gasket_size; + + if (! wire) + { + /* front wall */ + glNormal3f (0, 0, -1); + glFrontFace(GL_CW); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f (pointsx0[0], pointsy0[0], -thick2); + glVertex3f (pointsx0[1], pointsy0[1], -thick2); + glVertex3f (pointsx0[3], pointsy0[3], -thick2); + glVertex3f (pointsx0[2], pointsy0[2], -thick2); + glEnd(); + polys++; + + /* back wall */ + glNormal3f (0, 0, 1); + glFrontFace(GL_CCW); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f (pointsx0[0], pointsy0[0], thick2); + glVertex3f (pointsx0[1], pointsy0[1], thick2); + glVertex3f (pointsx0[3], pointsy0[3], thick2); + glVertex3f (pointsx0[2], pointsy0[2], thick2); + glEnd(); + polys++; + } + + /* top wall */ + glFrontFace(GL_CW); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glNormal3f (pointsx0[1], pointsy0[1], 0); + glVertex3f (pointsx0[1], pointsy0[1], thick2); + glNormal3f (pointsx0[3], pointsy0[3], 0); + glVertex3f (pointsx0[3], pointsy0[3], thick2); + glVertex3f (pointsx0[3], pointsy0[3], -thick2); + glNormal3f (pointsx0[1], pointsy0[1], 0); + glVertex3f (pointsx0[1], pointsy0[1], -thick2); + glEnd(); + polys++; + + + /* Now make a donut. + */ + { + int nsteps = (wire ? 12 : 64); + GLfloat r0 = 0.04; + GLfloat r1 = 0.070; + GLfloat th, cth, sth; + + glPushMatrix (); + + th = ((339.0 + 343.0) / 2) * d2r; + + glTranslatef (r1b * cos(th) * dc->gasket_size, + r1b * sin(th) * dc->gasket_size, + 0); + + npoints = 0; + for (i = 0; i < nsteps; i++) + { + th = 2 * M_PI * i / nsteps; + cth = cos (th) * dc->gasket_size; + sth = sin (th) * dc->gasket_size; + pointsx0[npoints] = r0 * cth; + pointsy0[npoints] = r0 * sth; + pointsx1[npoints] = r1 * cth; + pointsy1[npoints] = r1 * sth; + npoints++; + polys++; + } + + pointsx0[npoints] = pointsx0[0]; + pointsy0[npoints] = pointsy0[0]; + pointsx1[npoints] = pointsx1[0]; + pointsy1[npoints] = pointsy1[0]; + npoints++; + + if (wire) + { + glBegin (GL_LINE_LOOP); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx0[i], pointsy0[i], -thick2); + polys += npoints; + glEnd(); + glBegin (GL_LINE_LOOP); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx0[i], pointsy0[i], thick2); + polys += npoints; + glEnd(); +# if 0 + glBegin (GL_LINE_LOOP); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx1[i], pointsy1[i], -thick2); + polys += npoints; + glEnd(); + glBegin (GL_LINE_LOOP); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx1[i], pointsy1[i], thick2); + polys += npoints; + glEnd(); +# endif + } + else + { + /* top */ + glFrontFace(GL_CW); + glNormal3f(0, 0, -1); + glBegin (GL_QUAD_STRIP); + for (i = 0; i < npoints; i++) + { + glVertex3f (pointsx0[i], pointsy0[i], -thick2); + glVertex3f (pointsx1[i], pointsy1[i], -thick2); + } + polys += npoints; + glEnd(); + + /* bottom */ + glFrontFace(GL_CCW); + glNormal3f(0, 0, 1); + glBegin (GL_QUAD_STRIP); + for (i = 0; i < npoints; i++) + { + glVertex3f (pointsx0[i], pointsy0[i], thick2); + glVertex3f (pointsx1[i], pointsy1[i], thick2); + } + polys += npoints; + glEnd(); + } + + /* inside edge */ + glFrontFace(GL_CW); + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + for (i = 0; i < npoints; i++) + { + glNormal3f (-pointsx0[i], -pointsy0[i], 0); + glVertex3f ( pointsx0[i], pointsy0[i], thick2); + glVertex3f ( pointsx0[i], pointsy0[i], -thick2); + } + polys += npoints; + glEnd(); + + glPopMatrix(); + } + } + + + /* Attach the bottom-right dingus... + */ + { + GLfloat w = 0.05; + GLfloat h = 0.19; + GLfloat th; + + glRotatef (49.5, 0, 0, 1); + glScalef (dc->gasket_size, dc->gasket_size, 1); + glTranslatef (0, (r0+r1)/2, 0); + + /* buried box */ + if (! wire) + { + glFrontFace(GL_CCW); + glBegin (wire ? GL_LINE_STRIP : GL_QUADS); + glNormal3f (0, 0, -1); + glVertex3f (-w/2, -h/2, -thick2); glVertex3f (-w/2, h/2, -thick2); + glVertex3f ( w/2, h/2, -thick2); glVertex3f ( w/2, -h/2, -thick2); + glNormal3f (1, 0, 0); + glVertex3f ( w/2, -h/2, -thick2); glVertex3f ( w/2, h/2, -thick2); + glVertex3f ( w/2, h/2, thick2); glVertex3f ( w/2, -h/2, thick2); + glNormal3f (0, 0, 1); + glVertex3f ( w/2, -h/2, thick2); glVertex3f ( w/2, h/2, thick2); + glVertex3f (-w/2, h/2, thick2); glVertex3f (-w/2, -h/2, thick2); + glNormal3f (-1, 0, 0); + glVertex3f (-w/2, -h/2, thick2); glVertex3f (-w/2, h/2, thick2); + glVertex3f (-w/2, h/2, -thick2); glVertex3f (-w/2, -h/2, -thick2); + polys++; + glEnd(); + } + + npoints = 0; + for (th = (wire ? 0 : -0.1); + th <= M_PI + 0.1; + th += (M_PI / (wire ? 5 : 32))) + { + pointsx0[npoints] = w/2 * cos(th); + pointsy0[npoints] = w/2 * sin(th); + npoints++; + polys++; + } + + /* front inside curve */ + glNormal3f (0, 0, -1); + glFrontFace(GL_CW); + glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN); + if (! wire) glVertex3f (0, h/2, -thick2); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx0[i], h/2 + pointsy0[i], -thick2); + polys += npoints; + glEnd(); + + /* front outside curve */ + glFrontFace(GL_CCW); + glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN); + if (! wire) glVertex3f (0, -h/2, -thick2); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx0[i], -h/2 - pointsy0[i], -thick2); + polys += npoints; + glEnd(); + + /* back inside curve */ + glNormal3f (0, 0, 1); + glFrontFace(GL_CCW); + glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN); + if (! wire) glVertex3f (0, h/2, thick2); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx0[i], h/2 + pointsy0[i], thick2); + polys += npoints; + glEnd(); + + /* back outside curve */ + glFrontFace(GL_CW); + glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN); + if (! wire) glVertex3f (0, -h/2, thick2); + for (i = 0; i < npoints; i++) + glVertex3f (pointsx0[i], -h/2 - pointsy0[i], thick2); + polys += npoints; + glEnd(); + + /* inside curve */ + glFrontFace(GL_CCW); + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + for (i = 0; i < npoints; i++) + { + glNormal3f (pointsx0[i], pointsy0[i], 0); + glVertex3f (pointsx0[i], h/2 + pointsy0[i], thick2); + glVertex3f (pointsx0[i], h/2 + pointsy0[i], -thick2); + } + polys += npoints; + glEnd(); + + /* outside curve */ + glFrontFace(GL_CW); + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + for (i = 0; i < npoints; i++) + { + glNormal3f (pointsx0[i], -pointsy0[i], 0); + glVertex3f (pointsx0[i], -h/2 - pointsy0[i], thick2); + glVertex3f (pointsx0[i], -h/2 - pointsy0[i], -thick2); + } + polys += npoints; + glEnd(); + } + + free (pointsx0); + free (pointsy0); + free (pointsx1); + free (pointsy1); + free (normals); + + glPopMatrix(); + return polys; +} + +static int +make_frame (logo_configuration *dc, int wire) +{ + int polys = 0; + int i, j; + GLfloat x[20], y[20]; + GLfloat corner_cut = 0.5; + + glPushMatrix(); + glRotatef (90, 0, 1, 0); + glScalef (4 * dc->frame_size, + 4 * dc->frame_size, + 4 * dc->frame_size); + + x[0] = -dc->frame_thickness; + x[1] = -dc->frame_thickness * corner_cut; + x[2] = 0; + x[3] = 0.5 - dc->triangle_size; + x[4] = 0.5; + x[5] = 0.5 + dc->triangle_size; + x[6] = 1; + x[7] = 1 + dc->frame_thickness * corner_cut; + x[8] = 1 + dc->frame_thickness; + + y[0] = -dc->frame_thickness; + y[1] = -dc->frame_thickness * corner_cut; + y[2] = 0; + y[3] = dc->triangle_size; + + /* front and back + */ + glTranslatef (-0.5, -0.5, dc->frame_depth / 4); + if (! wire) + for (j = 0; j <= 1; j++) + { + if (j) glTranslatef (0, 0, -dc->frame_depth / 2); + glFrontFace (j ? GL_CCW : GL_CW); + for (i = 0; i < 4; i++) + { + glNormal3f (0, 0, (j ? -1 : 1)); + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + glVertex3f (x[0], y[1], 0); glVertex3f (x[0], y[2], 0); + glVertex3f (x[1], y[0], 0); glVertex3f (x[1], y[2], 0); + glVertex3f (x[3], y[0], 0); glVertex3f (x[3], y[2], 0); + glVertex3f (x[4], y[0], 0); glVertex3f (x[4], y[3], 0); + glVertex3f (x[5], y[0], 0); glVertex3f (x[5], y[2], 0); + glVertex3f (x[7], y[0], 0); glVertex3f (x[7], y[2], 0); + glVertex3f (x[8], y[1], 0); glVertex3f (x[8], y[2], 0); + polys += 6; + glEnd (); + glTranslatef (0.5, 0.5, 0); + glRotatef (90, 0, 0, 1); + glTranslatef (-0.5, -0.5, 0); + } + } + + /* ledges + */ + glFrontFace (GL_CCW); + for (i = 0; i < 4; i++) + { + glNormal3f (0, 1, 0); + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + glVertex3f (x[2], y[2], 0); glVertex3f (x[2], y[2], dc->frame_depth/2); + glVertex3f (x[3], y[2], 0); glVertex3f (x[3], y[2], dc->frame_depth/2); + glVertex3f (x[4], y[3], 0); glVertex3f (x[4], y[3], dc->frame_depth/2); + glVertex3f (x[5], y[2], 0); glVertex3f (x[5], y[2], dc->frame_depth/2); + glVertex3f (x[6], y[2], 0); glVertex3f (x[6], y[2], dc->frame_depth/2); + polys += 4; + glEnd (); + + glNormal3f (0, -1, 0); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f (x[7], y[0], 0); + glVertex3f (x[7], y[0], dc->frame_depth/2); + glVertex3f (x[1], y[0], dc->frame_depth/2); + glVertex3f (x[1], y[0], 0); + polys++; + glEnd (); + + glNormal3f (1, -1, 0); + glBegin (wire ? GL_LINE_LOOP : GL_QUADS); + glVertex3f (x[8], y[1], 0); + glVertex3f (x[8], y[1], dc->frame_depth/2); + glVertex3f (x[7], y[0], dc->frame_depth/2); + glVertex3f (x[7], y[0], 0); + polys++; + glEnd (); + + if (wire) + { + glNormal3f (0, 1, 0); + for (j = 0; j <= 1; j++) + { + glBegin (GL_LINE_STRIP); + glVertex3f (x[2], y[2], j*dc->frame_depth/2); + glVertex3f (x[3], y[2], j*dc->frame_depth/2); + glVertex3f (x[4], y[3], j*dc->frame_depth/2); + glVertex3f (x[5], y[2], j*dc->frame_depth/2); + glVertex3f (x[6], y[2], j*dc->frame_depth/2); + polys += 4; + glEnd (); + } + } + + glTranslatef (0.5, 0.5, 0); + glRotatef (90, 0, 0, 1); + glTranslatef (-0.5, -0.5, 0); + } + + glPopMatrix(); + return polys; +} + + +/* Make some pizza. + */ + +#ifdef HAVE_TESS + +typedef struct { + GLdouble *points; + int i; +} tess_out; + + +static void +tess_error_cb (GLenum errorCode) +{ + fprintf (stderr, "%s: tesselation error: %s\n", + progname, gluErrorString(errorCode)); + exit (0); +} + +static void +tess_combine_cb (GLdouble coords[3], GLdouble *d[4], GLfloat w[4], + GLdouble **data_out) +{ + GLdouble *new = (GLdouble *) malloc (3 * sizeof(*new)); + new[0] = coords[0]; + new[1] = coords[1]; + new[2] = coords[2]; + *data_out = new; +} + + +#if 0 +static void +tess_vertex_cb (void *vertex_data, void *closure) +{ + tess_out *to = (tess_out *) closure; + GLdouble *v = (GLdouble *) vertex_data; + to->points[to->i++] = v[0]; + to->points[to->i++] = v[1]; + to->points[to->i++] = v[2]; +} +#endif + +static void +tess_begin_cb (GLenum which) +{ + glBegin(which); +} + +static void +tess_end_cb (void) +{ + glEnd(); +} + +#endif /* HAVE_TESS */ + + +static int +make_pizza (logo_configuration *dc, int facetted, int wire) +{ + int polys = 0; + int topfaces = (facetted ? 48 : 120); + int discfaces = (facetted ? 12 : 120); + int npoints = topfaces * 2 + 100; + GLdouble *points = (GLdouble *) calloc (npoints * 3, sizeof(GLdouble)); + int nholes = 3; + GLdouble *holes = (GLdouble *) calloc (topfaces*nholes*3, sizeof(GLdouble)); + + GLfloat step = M_PI * 2 / 6 / topfaces; + GLfloat thick2 = (dc->gasket_thickness / dc->gasket_size) / 4; + GLfloat th, x, y, s; + int i, j, k; + int endpoints; + +# ifdef HAVE_TESS + tess_out TO, *to = &TO; + GLUtesselator *tess = gluNewTess(); + + to->points = (GLdouble *) calloc (topfaces * 20, sizeof(GLdouble)); + to->i = 0; + +# ifndef _GLUfuncptr +# define _GLUfuncptr void(*)(void) +# endif + + gluTessCallback(tess,GLU_TESS_BEGIN, (_GLUfuncptr)tess_begin_cb); + gluTessCallback(tess,GLU_TESS_VERTEX, (_GLUfuncptr)glVertex3dv); + gluTessCallback(tess,GLU_TESS_END, (_GLUfuncptr)tess_end_cb); + gluTessCallback(tess,GLU_TESS_COMBINE, (_GLUfuncptr)tess_combine_cb); + gluTessCallback(tess,GLU_TESS_ERROR, (_GLUfuncptr)tess_error_cb); + + gluTessProperty (tess, GLU_TESS_BOUNDARY_ONLY, wire); + gluTessProperty (tess,GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); + +# endif /* HAVE_TESS */ + + glPushMatrix(); + + s = 1.9; + glRotatef (180, 0, 0, 1); + glScalef (s, s, s); + glRotatef (90, 0, 1, 0); + glTranslatef (-0.53, 0, 0); + glRotatef (-30, 0, 0, 1); + + /* Compute the wedge */ + th = 0; + j = 0; + + /* Edge 1 */ + { + GLfloat edge[] = { + 0.000, 0.000, + 0.000, 0.210, + 0.042, 0.230, + 0.042, 0.616, + 0.000, 0.641, + }; + for (i = 0; i < countof(edge)/2; i++) + { + points[j++] = edge[i*2+1]; + points[j++] = edge[i*2]; + points[j++] = 0; + } + } + + s = 0.798; /* radius of end of slice, before crust gap */ + for (i = 0; i < topfaces; i++) + { + points[j++] = cos(th) * s; + points[j++] = sin(th) * s; + points[j++] = 0; + th += step; + } + + /* Edge 2 */ + { + GLfloat edge[] = { + 0.613, 0.353, + 0.572, 0.376, + 0.455, 0.309, + 0.452, 0.260, + 0.332, 0.192, + 0.293, 0.216, + 0.178, 0.149, + 0.178, 0.102, + }; + for (i = 0; i < countof(edge)/2; i++) + { + points[j++] = edge[i*2+1]; + points[j++] = edge[i*2]; + points[j++] = 0; + } + endpoints = j/3; + } + + + /* Draw the rim of the slice */ + glBegin (wire ? GL_LINES : GL_QUADS); + x = points[0]; + y = points[1]; + for (i = (wire ? 0 : 1); i < endpoints; i++) + { + GLdouble *p = points + (i*3); + + do_normal (p[0], p[1], -thick2, + p[0], p[1], thick2, + x, y, thick2); + if (!wire) + { + glVertex3f (x, y, -thick2); + glVertex3f (x, y, thick2); + } + glVertex3f (p[0], p[1], thick2); + glVertex3f (p[0], p[1], -thick2); + x = p[0]; + y = p[1]; + polys++; + } + + do_normal (points[0], points[1], -thick2, + points[0], points[1], thick2, + x, y, thick2); + glVertex3f (x, y, -thick2); + glVertex3f (x, y, thick2); + glVertex3f (points[0], points[1], thick2); + glVertex3f (points[0], points[1], -thick2); + polys++; + glEnd(); + +# ifndef HAVE_TESS + if (wire) + { + /* Outline of slice */ + glBegin (GL_LINE_LOOP); + for (i = 0; i < endpoints; i++) + glVertex3f (points[i*3], points[i*3+1], -thick2); + glEnd(); + glBegin (GL_LINE_LOOP); + for (i = 0; i < endpoints; i++) + glVertex3f (points[i*3], points[i*3+1], thick2); + glEnd(); + } +# endif /* HAVE_TESS */ + + /* Compute the holes */ + step = M_PI * 2 / discfaces; + for (k = 0; k < nholes; k++) + { + GLdouble *p = holes + (discfaces * 3 * k); + th = 0; + j = 0; + switch (k) { + case 0: x = 0.34; y = 0.17; s = 0.05; break; + case 1: x = 0.54; y = 0.17; s = 0.06; break; + case 2: x = 0.55; y = 0.36; s = 0.06; break; + default: abort(); break; + } + for (i = 0; i < discfaces; i++) + { + p[j++] = x + cos(M_PI*2 - th) * s; + p[j++] = y + sin(M_PI*2 - th) * s; + p[j++] = 0; + th += step; + } + } + + + /* Draw the inside rim of the holes */ + for (k = 0; k < nholes; k++) + { + GLdouble *p = holes + (discfaces * 3 * k); + + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + for (i = 0; i < discfaces; i++) + { + GLdouble *p2 = p + (i*3); + if (i > 0) + do_normal (p2[0], p2[1], -thick2, + p2[0], p2[1], thick2, + p2[-3], p2[-2], thick2); + glVertex3f (p2[0], p2[1], -thick2); + glVertex3f (p2[0], p2[1], thick2); + polys++; + } + glVertex3f (p[0], p[1], -thick2); + glVertex3f (p[0], p[1], thick2); + polys++; + glEnd(); +# ifndef HAVE_TESS + if (wire) + { + /* Outline of holes */ + glBegin (GL_LINE_LOOP); + for (i = 0; i < discfaces; i++) + glVertex3f (p[i*3], p[i*3+1], -thick2); + glEnd(); + glBegin (GL_LINE_LOOP); + for (i = 0; i < discfaces; i++) + glVertex3f (p[i*3], p[i*3+1], thick2); + glEnd(); + } +# endif /* !HAVE_TESS */ + } + +# ifdef HAVE_TESS + glTranslatef (0, 0, -thick2); + for (y = 0; y <= 1; y++) + { + if (y) glTranslatef (0, 0, thick2*2); + + /* A non-convex polygon */ + gluTessBeginPolygon (tess, to); + + glNormal3f (0, 0, (y > 0 ? 1 : -1)); + gluTessNormal (tess, 0, 0, (y > 0 ? 1 : -1)); + glFrontFace (GL_CCW); + + /* Tess the wedge */ + gluTessBeginContour (tess); + for (i = 0; i < endpoints; i++) + { + GLdouble *p = points + (i*3); + gluTessVertex (tess, p, p); + polys++; + } + gluTessVertex (tess, points, points); + gluTessEndContour (tess); + + /* Tess the holes */ + for (k = 0; k < nholes; k++) + { + GLdouble *p = holes + (discfaces * 3 * k); + gluTessBeginContour (tess); + for (i = 0; i < discfaces; i++) + { + GLdouble *p2 = p + (i*3); + gluTessVertex (tess, p2, p2); + polys++; + } + gluTessEndContour (tess); + } + + gluTessEndPolygon (tess); + } + + glTranslatef (0, 0, -thick2); + +# else /* !HAVE_TESS */ + if (! wire) + { + glTranslatef(0, 0, thick2); + glNormal3f (0, 0, 1); + glFrontFace (GL_CW); + + /* Sadly, jwzgl's glVertexPointer seems not to be recordable inside + display lists. */ +# if 0 + glDisableClientState (GL_COLOR_ARRAY); + glDisableClientState (GL_NORMAL_ARRAY); + glDisableClientState (GL_TEXTURE_COORD_ARRAY); + glEnableClientState (GL_VERTEX_ARRAY); + glVertexPointer (3, GL_FLOAT, 0, dnapizza_triangles); + glDrawArrays (GL_TRIANGLES, 0, countof (dnapizza_triangles) / 3); +# else + glBegin (GL_TRIANGLES); + for (i = 0; i < countof (dnapizza_triangles); i += 3) + glVertex3fv (dnapizza_triangles + i); + glEnd(); +# endif + + glTranslatef(0, 0, -thick2*2); + glNormal3f (0, 0, -1); + glFrontFace (GL_CCW); + +# if 0 + glDrawArrays (GL_TRIANGLES, 0, countof (dnapizza_triangles) / 3); +# else + int i; + glBegin (GL_TRIANGLES); + for (i = 0; i < countof (dnapizza_triangles); i += 3) + glVertex3fv (dnapizza_triangles + i); + glEnd(); +# endif + + glTranslatef(0, 0, thick2); + } +# endif /* !HAVE_TESS */ + + + /* Compute the crust */ + + s = 0.861; /* radius of inside of crust */ + step = M_PI * 2 / 6 / topfaces; + th = 0; + j = 0; + for (i = 0; i < topfaces; i++) + { + points[j++] = cos(th) * s; + points[j++] = sin(th) * s; + points[j++] = 0; + th += step; + } + + s = 1; + for (i = 0; i < topfaces; i++) + { + points[j++] = cos(th) * s; + points[j++] = sin(th) * s; + points[j++] = 0; + th -= step; + } + + /* Draw the rim of the crust */ + glFrontFace (GL_CCW); + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + for (i = 0; i < topfaces * 2; i++) + { + GLdouble *p = points + (i*3); + if (i == 0 || i == (topfaces*2)-1) + glNormal3f (0, -1, 0); + else if (i == topfaces-1 || i == topfaces) + glNormal3f (0, 1, 0); + else + do_normal (p[-3], p[-2], thick2, + p[0], p[1], thick2, + p[0], p[1], -thick2); + glVertex3f (p[0], p[1], -thick2); + glVertex3f (p[0], p[1], thick2); + polys++; + } + glVertex3f (points[0], points[1], -thick2); + glVertex3f (points[0], points[1], thick2); + polys++; + glEnd(); + + if (wire) + { + glBegin (GL_LINE_STRIP); + for (i = 0; i < topfaces * 2; i++) + { + GLdouble *p = points + (i*3); + glVertex3f (p[0], p[1], -thick2); + polys++; + } + glVertex3f (points[0], points[1], -thick2); + glEnd(); + + glBegin (GL_LINE_STRIP); + for (i = 0; i < topfaces * 2; i++) + { + GLdouble *p = points + (i*3); + glVertex3f (p[0], p[1], thick2); + polys++; + } + glVertex3f (points[0], points[1], thick2); + glEnd(); + } + + /* Draw the top of the crust */ + if (! wire) + { + glFrontFace (GL_CW); + glBegin (wire ? GL_LINE_STRIP : GL_QUAD_STRIP); + glNormal3f (0, 0, -1); + if (!wire) + for (i = 0; i < topfaces; i++) + { + int ii = topfaces + (topfaces - i - 1); + GLdouble *p1 = points + (i*3); + GLdouble *p2 = points + (ii*3); + glVertex3f (p1[0], p1[1], -thick2); + glVertex3f (p2[0], p2[1], -thick2); + polys++; + } + polys++; + glEnd(); + + /* Draw the bottom of the crust */ + glFrontFace (GL_CCW); + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + glNormal3f (0, 0, 1); + for (i = 0; i < topfaces; i++) + { + int ii = topfaces + (topfaces - i - 1); + GLdouble *p1 = points + (i*3); + GLdouble *p2 = points + (ii*3); + glVertex3f (p1[0], p1[1], thick2); + glVertex3f (p2[0], p2[1], thick2); + polys++; + } + polys++; + glEnd(); + } + +# ifdef HAVE_TESS + gluDeleteTess (tess); + free (to->points); +# endif /* HAVE_TESS */ + + free (points); + free (holes); + + glPopMatrix(); + + return polys; +} + + +# ifdef CW + +/* Upcase string, convert Unicrud to ASCII, remove any non-letters. + */ +static char * +codeword_simplify_text (const char *s0) +{ + char *s1 = utf8_to_latin1 ((s0 ? s0 : ""), True); + int L = strlen(s1); + char *s2 = (char *) malloc (L + 10); + char *s3 = s2; + int i; + for (i = 0; i < L; i++) + { + char c = s1[i]; + if (c >= 'a' && c <= 'z') + c -= 'a'-'A'; + if (c >= 'A' && c <= 'Z') + *s3++ = c; + } + *s3 = 0; + if (! *s2) + strcpy (s2, "CODEWORD"); + return s2; +} + + +static void +make_codeword_path (ModeInfo *mi) +{ + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; + int letters = strlen (dc->codeword_text); + + GLfloat rtick = dc->codeword_spread; + GLfloat iradius = rtick * dc->codeword_cap_size; + + int dial = 0; + int letter; + GLfloat last_r = 0; + + GLfloat inner_circum = M_PI * 2 * (iradius + rtick * 2); + GLfloat outer_circum = M_PI * 2 * (iradius + rtick * (letters + 1)); + GLfloat facet_length = inner_circum / (26 * dc->codeword_facets); + int outer_facets = ceil (outer_circum / facet_length); + + int *histo = (int *) calloc (letters * 26, sizeof(*histo)); + XYZ *points = (XYZ *) calloc (letters * outer_facets, sizeof (*points)); + int npoints = 0; + + for (letter = -1; letter < letters; letter++) + { + if (letter == -1) /* Inner starting point */ + { + points[npoints].x = iradius; + points[npoints].y = 0; + last_r = iradius; + npoints++; + } + else /* Add arc for this letter */ + { + int direction = (letter & 1 ? -1 : 1); + int v = (dc->codeword_text[letter] - 'A' + 1); + int dial1 = dial + v * direction; + + GLfloat th; + GLfloat th0 = M_PI * 2 / 26 * dial; + GLfloat th1 = M_PI * 2 / 26 * dial1; + GLfloat r = iradius + rtick * (letter + 2); + GLfloat circum = M_PI * 2 * r; + GLfloat arc_length = circum * v / 26; + int arc_facets = ceil (fabs (arc_length / facet_length)); + GLfloat facet_th = (th1 - th0) / arc_facets; + + if (arc_facets > outer_facets) abort(); + + /* Let's put some intermediate facets on the crossbars too, + so that the animation doesn't speed up on those. */ + { + GLfloat rr; + for (rr = last_r + facet_length; + rr <= r - facet_length; + rr += facet_length) + { + points[npoints].x = rr * cos (th0); + points[npoints].y = rr * sin (th0); + npoints++; + } + last_r = r; + } + + + for (th = th0; + (th0 < th1 + ? th <= th1 + facet_th + : th >= th1 + facet_th); + th += facet_th) + { + GLfloat th2 = th; + if (th0 < th1 && th > th1) + th2 = th1; + if (th0 > th1 && th < th1) + th2 = th1; + points[npoints].x = r * cos (th2); + points[npoints].y = r * sin (th2); + + /* Ugh, add point only if it differs from prev. + Not sure how this happens. */ + if (npoints == 0 || + points[npoints-1].x != points[npoints].x || + points[npoints-1].y != points[npoints].y) + npoints++; + } + + /* Mark up the histo array to find the outer border. */ + { + int i; + for (i = dial; + (direction > 0 + ? i <= dial1 + : i >= dial1); + i += direction) + { + int x = (i + 26) % 26; + int y; + for (y = 0; y <= letter; y++) + histo[y * 26 + x]++; + } + } + + dc->codeword_text_points[letter] = npoints; + + dial = dial1; + } + } + + if (npoints >= letters * outer_facets) abort(); + +# if 0 + { /* Print histo */ + int x, y; + for (y = 0; y < letters; y++) + { + fprintf (stderr, "%2d: ", y); + for (x = 0; x < 26; x++) + fprintf (stderr, "%x", histo[y * 26 + x]); + fprintf (stderr, "\n"); + } + fprintf (stderr, "\n"); + } +# endif + + + /* Find a gap in the outer edge, to draw guide dots. */ + { + int x, y; + int last_row = letters; + int start_dial = -1, end_dial = -1; + + for (y = letters-1; y >= 0; y--) + { + for (x = 0; x < 26; x++) + { + if (histo[y * 26 + x] == 0) + { + if (last_row != y) + start_dial = end_dial = -1; + last_row = y; + if (start_dial == -1) + start_dial = x; + end_dial = x; + } + } + } + + if (last_row < letters-1 && start_dial >= 0) + { + GLfloat r = iradius + rtick * (last_row + 2); + int i; + + dc->codeword_nguides = 0; + dc->codeword_guides = (XYZ *) + calloc (end_dial - start_dial + 1, sizeof (*dc->codeword_guides)); + for (i = start_dial; i <= end_dial; i++) + { + GLfloat th = i * M_PI * 2 / 26; + GLfloat x = r * cos (th); + GLfloat y = r * sin (th); + dc->codeword_guides[dc->codeword_nguides].x = x; + dc->codeword_guides[dc->codeword_nguides].y = y; + dc->codeword_nguides++; + } + } + free (histo); + histo = 0; + } + + dc->codeword_path_npoints = npoints; + dc->codeword_path = points; +} + + +static int +draw_codeword_cap (ModeInfo *mi) +{ + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; + int wire = MI_IS_WIREFRAME(mi); + int polys = 0; + + int segments = dc->codeword_disc_facets; + GLfloat size = dc->codeword_spread * dc->codeword_cap_size; + GLfloat width = dc->codeword_line_width / 2; + GLfloat thick = dc->codeword_thickness / 2; + GLfloat r1 = size + width/2; + GLfloat r2 = size - width/2; + GLfloat facet, th, z; + + if (wire) segments = 12; + facet = M_PI * 2 / segments; + + glPushMatrix(); + + /* Top and bottom */ + + for (z = -thick; z <= thick; z += thick*2) + { + glNormal3f (0, 0, (z < 0 ? -1 : 1)); + glFrontFace (z < 0 ? GL_CCW : GL_CW); + + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + for (th = 0; th <= M_PI*2; th += facet) + { + GLfloat x = cos (th); + GLfloat y = sin (th); + glVertex3f (r1 * x, r1 * y, z); + glVertex3f (r2 * x, r2 * y, z); + } + glEnd(); + + if (wire) + { + glBegin (GL_LINE_LOOP); + for (th = 0; th <= M_PI*2; th += facet) + { + GLfloat x = cos (th); + GLfloat y = sin (th); + glVertex3f (r1 * x, r1 * y, z); + } + glEnd(); + glBegin (GL_LINE_LOOP); + for (th = 0; th <= M_PI*2; th += facet) + { + GLfloat x = cos (th); + GLfloat y = sin (th); + glVertex3f (r2 * x, r2 * y, z); + } + glEnd(); + } + } + + /* Inside and outside */ + + for (z = -1; z <= 1; z += 2) + { + glFrontFace (z < 0 ? GL_CCW : GL_CW); + + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + for (th = 0; th <= M_PI*2; th += facet) + { + GLfloat th1 = th + facet; + GLfloat x0 = cos (th); + GLfloat y0 = sin (th); + GLfloat x1 = cos (th1); + GLfloat y1 = sin (th1); + GLfloat r = z < 0 ? r1 : r2; + + if (z < 0) + do_normal (r * x0, r * y0, thick, + r * x0, r * y0, -thick, + r * x1, r * y1, -thick); + else + do_normal (r * x1, r * y1, thick, + r * x1, r * y1, -thick, + r * x0, r * y0, -thick); + + glVertex3f (r * x0, r * y0, thick); + glVertex3f (r * x0, r * y0, -thick); + } + glEnd(); + } + + glPopMatrix(); + + return polys; +} + + +static int +draw_codeword_guides (ModeInfo *mi, GLfloat anim_ratio) +{ + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; + int wire = MI_IS_WIREFRAME(mi); + int polys = 0; + + int segments = dc->codeword_disc_facets; + GLfloat s = dc->codeword_line_width / 2; + GLfloat each = 1.0 / dc->codeword_nguides; + int i; + + if (wire) segments = 6; + + for (i = 0; i < dc->codeword_nguides; i++) + { + GLfloat ratio; + if (anim_ratio < i*each) ratio = 0; + else if (anim_ratio >= (i+1)*each) ratio = 1; + else ratio = (anim_ratio - i*each) / each; + + if (ratio <= 0) continue; + if (ratio == 0) ratio = 0.001; + + glPushMatrix(); + glTranslatef (dc->codeword_guides[i].x, + dc->codeword_guides[i].y, + dc->codeword_guides[i].z); + + glScalef (ratio, ratio, ratio); + + /* If the line width and thickness are pretty close to each other, + use spheres. Otherwise use tubes. + */ + if (dc->codeword_thickness < dc->codeword_line_width * 1.3 && + dc->codeword_thickness > dc->codeword_line_width / 1.3) + { + glScalef (s, s, s); + glFrontFace (GL_CCW); + polys += unit_sphere (segments, segments, wire); + } + else + { + polys += tube (0, 0, -dc->codeword_thickness / 2, + 0, 0, dc->codeword_thickness / 2, + s, 0, segments, True, True, wire); + } + + glPopMatrix(); + } + + return polys; +} + + +/* Compute the characters at which the cursor is currently pointing, + and render it on the logo. + */ +static void +codeword_text_output (ModeInfo *mi, GLfloat anim_ratio) +{ + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; + int i; + int L = strlen (dc->codeword_text); + int point = dc->codeword_path_npoints * anim_ratio; + Bool hit = False; + + if (dc->anim_state == CODEWORD_BLANK) + point = 0; + + for (i = 0; i < L; i++) + { + if (point >= dc->codeword_text_points[i]) + dc->codeword_text_out[i] = dc->codeword_text[i]; + else if (hit) + dc->codeword_text_out[i] = 0; + else + { + int steps = dc->codeword_text[i] - 'A' + 1; + int last = (i > 0 ? dc->codeword_text_points[i-1] : 0); + double ratio = ((point - last) / + (double) (dc->codeword_text_points[i] - last)); + char chr = 'A' + (ratio * steps); + if (ratio < 0.1) chr = 0; + dc->codeword_text_out[i] = chr; + hit = True; + } + } + dc->codeword_text_out[i] = 0; + + if (*dc->codeword_text_out && + !strcmp (dc->codeword_text, "CODEWORD")) + { + int i; + int L2 = strlen (dc->codeword_text_out); + GLfloat ss = 0.01; + int ascent, descent; + + glPushMatrix(); + glColor4fv (dc->codeword_color); + glRotatef (90, 0, 1, 0); + glRotatef (-90, 0, 0, 1); + + for (i = 0; i < L2; i++) + { + XCharStruct e; + char buf[2]; + glPushMatrix(); + glRotatef ((i + 0.5) * 360 / 26.0, 0, 0, 1); + +# if 0 + { + GLfloat th; + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + glVertex3f(0,0,0); + glVertex3f(0,-4,0); + glEnd(); + glBegin(GL_LINE_STRIP); + for (th = M_PI * 1.45; th < M_PI * 1.55; th += 0.1) + { + GLfloat r = 3.85; + glVertex3f (r * cos(th), r * sin(th), 0); + } + glEnd(); + if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING); + } +# endif + + glTranslatef (0, -dc->codeword_spread * (L - 1), 0); + glScalef (ss, ss, ss); + buf[0] = dc->codeword_text_out[i] + ('a' - 'A'); + buf[1] = 0; + texture_string_metrics (dc->font, buf, &e, &ascent, &descent); + +# ifdef HAVE_MOBILE + /* #### Magic magic magic WTF... */ + glScalef (0.5, 0.5, 0.5); +# endif + + glTranslatef (-e.width * 1.0, + -(ascent + descent + e.descent * 2.4), /* #### WTF */ + 0); + + glScalef (2, 2, 2); + +# if 0 + glDisable(GL_LIGHTING); + glBegin(GL_LINE_LOOP); + glVertex3f(0, 0, 0); + glVertex3f(e.width, 0, 0); + glVertex3f(e.width, e.ascent + e.descent, 0); + glVertex3f(0, e.ascent + e.descent, 0); + glEnd(); + if (!MI_IS_WIREFRAME(mi)) glEnable(GL_LIGHTING); +# endif + + glDisable(GL_CULL_FACE); /* tell texfont.c to draw both sides */ + print_texture_string (dc->font, buf); + glEnable(GL_CULL_FACE); + + glPopMatrix(); + } + glPopMatrix(); + } +} + + +/* Convert the precomputed path to a thick line of polygons. + We could actually precompute all of these polygons too, + but it's fast enough. + */ +static int +draw_codeword_path (ModeInfo *mi) +{ + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; + int wire = MI_IS_WIREFRAME(mi); + int polys = 0; + + GLfloat anim_ratio = (dc->anim_state == CODEWORD_IN ? dc->anim_ratio : + dc->anim_state == CODEWORD_OUT ? 1 - dc->anim_ratio : + dc->anim_state == CODEWORD_BLANK ? 0 : + 1); + int last_anim_point = 0; + + GLfloat width = dc->codeword_line_width / 2; + GLfloat thick = dc->codeword_thickness / 2; + int i, k; + GLfloat j; + + int quad_size = (dc->codeword_path_npoints + 1) * 2; + XYZ *quads = (XYZ *) calloc (quad_size, sizeof(*quads)); + XYZ *norms = (XYZ *) calloc (quad_size, sizeof(*norms)); + int nquads = 0; + + for (i = 0; i < dc->codeword_path_npoints; i++) + { + XYZ p1 = dc->codeword_path[i]; + XYZ p2 = (i < dc->codeword_path_npoints-1 + ? dc->codeword_path[i+1] + : dc->codeword_path[i-1]); + XYZ p1a, p1b; + + XYZ n; /* normal of the first line segment */ + n.x = -(p2.y - p1.y); + n.y = (p2.x - p1.x); + n.z = 0; + normalize (&n); + + if (i == 0) + { + p1a.x = p1.x - width / 2 * n.x; + p1a.y = p1.y - width / 2 * n.y; + p1a.z = 0; + + p1b.x = p1.x + width / 2 * n.x; + p1b.y = p1.y + width / 2 * n.y; + p1b.z = 0; + } + else if (i == dc->codeword_path_npoints - 1) + { + p1b.x = p1.x - width / 2 * n.x; + p1b.y = p1.y - width / 2 * n.y; + p1b.z = 0; + + p1a.x = p1.x + width / 2 * n.x; + p1a.y = p1.y + width / 2 * n.y; + p1a.z = 0; + } + else + { + XYZ p0 = dc->codeword_path[i-1]; + + XYZ t, t0, t1; /* tangent of corner between two line segments */ + XYZ m; /* miter line: normal of tangent */ + GLfloat d; /* length of miter */ + + t0.x = p2.x - p1.x; + t0.y = p2.y - p1.y; + t0.z = p2.z - p1.z; + normalize (&t0); + + t1.x = p1.x - p0.x; + t1.y = p1.y - p0.y; + t1.z = p1.z - p0.z; + normalize (&t1); + + t.x = t0.x + t1.x; + t.y = t0.y + t1.y; + t.z = t0.z + t1.z; + normalize (&t); + + m.x = -t.y; + m.y = t.x; + m.z = 0; + + /* find length of miter by projecting it on one of the normals */ + d = width / 2 / dot (m, n); + + p1a.x = p1.x - d * m.x; + p1a.y = p1.y - d * m.y; + p1a.z = 0; + + p1b.x = p1.x + d * m.x; + p1b.y = p1.y + d * m.y; + p1b.z = 0; + } + + quads[nquads++] = p1a; + quads[nquads++] = p1b; + + if (nquads >= quad_size) abort(); + + if (i / (double) dc->codeword_path_npoints > anim_ratio) + break; + + last_anim_point = i; + } + + + /* Compute normals for each point along the interior edge */ + for (k = 0; k <= 1; k++) + { + for (i = k; i < nquads-2; i += 2) + { + XYZ p1a = quads[i]; + XYZ p2a = quads[i+2]; + XYZ p1b = p1a; + XYZ p2b = p2a; + p1a.z = thick; /* a: top */ + p1b.z = -thick; /* b: bottom */ + p2a.z = thick; + p2b.z = -thick; + + norms[i] = (k == 0 + ? calc_normal (p1a, p1b, p2b) + : calc_normal (p2a, p2b, p1a)); + } + } + + glPushMatrix(); + glColor4fv (dc->codeword_color); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dc->codeword_color); + +# ifdef HAVE_MOBILE /* Make the whole thing fit on the phone screen */ + { + GLfloat size = MI_WIDTH(mi) < MI_HEIGHT(mi) ? MI_WIDTH(mi) : MI_HEIGHT(mi); + glScalef (0.9, 0.9, 0.9); + if (size <= 768) /* iPad retina / iPhone 6 */ + glScalef (0.7, 0.7, 0.7); + } +# endif + + codeword_text_output (mi, anim_ratio); + + glRotatef (90, 1, 0, 0); + glRotatef (90, 0, 1, 0); + glRotatef (-90, 0, 0, 1); + glScalef (0.8, 0.8, 0.8); + + glNormal3f (0, 0, -1); + + if (anim_ratio <= 0) + { + polys += draw_codeword_cap (mi); + goto DONE; + } + +# if 0 + glColor3f (1, 0, 0); + glBegin(GL_LINE_STRIP); + for (i = 0; i < dc->codeword_path_npoints; i++) + { + glVertex3f (dc->codeword_path[i].x, + dc->codeword_path[i].y, + dc->codeword_path[i].z); + polys++; + } + glEnd(); + glColor4fv (dc->codeword_color); +# endif + + if (wire) + { + int k; + GLfloat j; + for (i = 0; i <= 1; i++) + for (j = -thick; j <= thick; j += thick*2) + { + glBegin (GL_LINE_STRIP); + for (k = i; k < nquads; k += 2) + { + glVertex3f (quads[k].x, quads[k].y, j); + polys++; + } + glEnd(); + } + } + + /* Top and bottom */ + + for (j = -thick; j <= thick; j += thick*2) + { + if (j < 0) + { + glNormal3f (0, 0, -1); + glFrontFace (GL_CW); + } + else + { + glNormal3f (0, 0, 1); + glFrontFace (GL_CCW); + } + glBegin (wire ? GL_LINES : GL_QUAD_STRIP); + for (i = 0; i < nquads; i += 2) + { + glVertex3f (quads[i+1].x, quads[i+1].y, j); + glVertex3f (quads[i].x, quads[i].y, j); + polys++; + } + glEnd(); + } + + /* Edges */ + + for (k = 0; k <= 1; k++) + { + if (k > 0) + { + glNormal3f (0, 0, -1); + glFrontFace (GL_CW); + } + else + { + glNormal3f (0, 0, 1); + glFrontFace (GL_CCW); + } + + glBegin (wire ? GL_LINES : GL_QUADS); + for (i = k; i < nquads; i += 2) + { + XYZ p1a = quads[i]; + XYZ p2a = (i < nquads-2) ? quads[i+2] : p1a; + XYZ p1b = p1a; + XYZ p2b = p2a; + + XYZ n1 = norms[i]; + XYZ n2 = (i < nquads-2) ? norms[i+2] : n1; + + /* If the two normals are very similar, smooth the face. + If they are different, it's a sharp turn, and use the + same normal for both edges (not quite right, but close). + */ + GLfloat angle = vector_angle (n1.x, n1.y, n1.z, + n2.x, n2.y, n2.z); + GLfloat pointy = 0.8; + + p1a.z = thick; + p1b.z = -thick; + p2a.z = thick; + p2b.z = -thick; + + glNormal3f (n1.x, n1.y, n1.z); + glVertex3f (p1a.x, p1a.y, p1a.z); + glVertex3f (p1b.x, p1b.y, p1b.z); + + if (angle < pointy) + glNormal3f (n2.x, n2.y, n2.z); + glVertex3f (p2b.x, p2b.y, p2b.z); + glVertex3f (p2a.x, p2a.y, p2a.z); + polys++; + } + glEnd(); + } + + + /* Only draw the guides when the path is almost complete; + fade them in and out based on completeness. */ + { + GLfloat size = 0.95; + GLfloat r = (anim_ratio > size + ? (anim_ratio - size) / (1 - size) + : 0); + polys += draw_codeword_guides (mi, r); + } + + + /* Draw the start and end caps */ + { + int i; + GLfloat x, y, z, x2, y2, z2, X, Y, Z; + GLfloat r = dc->codeword_spread * dc->codeword_cap_size; + + i = 0; + x = dc->codeword_path[i].x; + y = dc->codeword_path[i].y; + z = dc->codeword_path[i].z; + + x -= r; + + glPushMatrix(); + glTranslatef (x, y, z); + polys += draw_codeword_cap (mi); + glPopMatrix(); + + /* end cap */ + + i = last_anim_point + 1; + if (i > dc->codeword_path_npoints - 1) + i = dc->codeword_path_npoints - 1; + + x = dc->codeword_path[i].x; + y = dc->codeword_path[i].y; + z = dc->codeword_path[i].z; + + i--; + x2 = dc->codeword_path[i].x; + y2 = dc->codeword_path[i].y; + z2 = dc->codeword_path[i].z; + + X = (x2 - x); + Y = (y2 - y); + Z = (z2 - z); + + glPushMatrix(); + glTranslatef (x, y, z); + glRotatef (-atan2 (X, Y) * (180 / M_PI), 0, 0, 1); + glRotatef ( atan2 (Z, sqrt(X*X + Y*Y)) * (180 / M_PI), 1, 0, 0); + glTranslatef (0, -r, 0); + polys += draw_codeword_cap (mi); + glPopMatrix(); + } + + DONE: + + glPopMatrix(); + + free (quads); + free (norms); + + return polys; +} + +#endif /* CW */ + + +ENTRYPOINT void +reshape_logo (ModeInfo *mi, int width, int height) +{ +# ifdef DEBUG + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; +# endif + GLfloat h = (GLfloat) height / (GLfloat) width; + GLfloat persp = 64; /* 30 */ + GLfloat pos = 13; /* 30 */ + +# ifdef DEBUG + persp += dc->persp_off; + pos += dc->pos_off; +# endif + + glViewport (0, 0, (GLint) width, (GLint) height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective (persp, 1/h, 1, 100); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt( 0, 0, pos, + 0, 0, 0, + 0, 1, 0); + +# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */ + { + int o = (int) current_device_rotation(); + if (o != 0 && o != 180 && o != -180) + glScalef (1/h, 1/h, 1/h); /* #### Why does this change the lighting? */ + } +# endif + + glClear(GL_COLOR_BUFFER_BIT); +} + + +static void +gl_init (ModeInfo *mi) +{ +/* logo_configuration *dc = &dcs[MI_SCREEN(mi)]; */ + int wire = MI_IS_WIREFRAME(mi); + + GLfloat position[] = {0, 0, 0, 0}; + GLfloat direction[] = {3, -1, -3}; + + position[0] = -direction[0]; + position[1] = -direction[1]; + position[2] = -direction[2]; + + if (!wire) + { + glLightfv(GL_LIGHT0, GL_POSITION, position); + glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direction); + glShadeModel(GL_SMOOTH); + glEnable(GL_NORMALIZE); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + } +} + + +ENTRYPOINT void +init_logo (ModeInfo *mi) +{ + logo_configuration *dc; + int do_gasket = get_boolean_resource(mi->dpy, "doGasket", "Boolean"); + int do_helix = get_boolean_resource(mi->dpy, "doHelix", "Boolean"); + int do_ladder = (do_helix && + get_boolean_resource(mi->dpy, "doLadder", "Boolean")); + int do_frame = get_boolean_resource(mi->dpy, "doFrame", "Boolean"); + GLfloat helix_rot = 147.0; + + if (!do_gasket && !do_helix) + { + fprintf (stderr, "%s: no helix or gasket?\n", progname); + exit (1); + } + + MI_INIT (mi, dcs); + + dc = &dcs[MI_SCREEN(mi)]; + + if ((dc->glx_context = init_GL(mi)) != NULL) { + gl_init(mi); + reshape_logo (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + } + + dc->wall_facets = get_integer_resource(mi->dpy, "wallFacets", "Integer"); + dc->bar_facets = get_integer_resource(mi->dpy, "barFacets", "Integer"); + dc->clockwise = get_boolean_resource(mi->dpy, "clockwise", "Boolean"); + dc->turns = get_float_resource(mi->dpy, "turns", "Float"); + dc->turn_spacing = get_float_resource(mi->dpy, "turnSpacing", "Float"); + dc->bar_spacing = get_float_resource(mi->dpy, "barSpacing", "Float"); + dc->wall_height = get_float_resource(mi->dpy, "wallHeight", "Float"); + dc->wall_thickness = get_float_resource(mi->dpy, "wallThickness", "Float"); + dc->bar_thickness = get_float_resource(mi->dpy, "barThickness", "Float"); + dc->wall_taper = get_float_resource(mi->dpy, "wallTaper", "Float"); + + dc->gasket_size = get_float_resource(mi->dpy,"gasketSize", "Float"); + dc->gasket_depth = get_float_resource(mi->dpy,"gasketDepth", "Float"); + dc->gasket_thickness = get_float_resource(mi->dpy,"gasketThickness","Float"); + + dc->frame_size = get_float_resource(mi->dpy, "frameSize", "Float"); + dc->frame_depth = get_float_resource(mi->dpy, "frameDepth", "Float"); + dc->frame_thickness = get_float_resource(mi->dpy, "frameThickness", "Float"); + dc->triangle_size = get_float_resource(mi->dpy, "triangleSize", "Float"); + + dc->speed = get_float_resource(mi->dpy, "speed", "Float"); +# ifdef CW + dc->codeword_text = get_string_resource(mi->dpy, "text", "String"); + dc->codeword_text = codeword_simplify_text (dc->codeword_text); + dc->codeword_text_out = + calloc (strlen(dc->codeword_text) + 1, sizeof(*dc->codeword_text_out)); + dc->codeword_text_points = + (int *) calloc (strlen(dc->codeword_text) + 1, + sizeof(*dc->codeword_text_points)); + + dc->codeword_facets = get_integer_resource(mi->dpy, "cwFacets", "Integer"); + dc->codeword_disc_facets = get_integer_resource(mi->dpy, + "cwDiscFacets", "Integer"); + dc->codeword_spread = get_float_resource(mi->dpy, "cwSpread", "Float"); + dc->codeword_line_width = get_float_resource(mi->dpy, "cwLineWidth", "Float"); + dc->codeword_thickness = get_float_resource(mi->dpy, "cwThickness", "Float"); + dc->codeword_cap_size = get_float_resource(mi->dpy, "cwCapSize", "Float"); +# endif + + { + char *s = get_string_resource (MI_DISPLAY (mi), "mode", "String"); + if (!s || !*s || !strcasecmp (s, "helix")) + dc->mode = HELIX; + else if (!strcasecmp (s, "pizza")) + dc->mode = PIZZA; + else if (!strcasecmp (s, "both")) + dc->mode = HELIX_AND_PIZZA; +# ifdef CW + else if (!strcasecmp (s, "codeword")) + dc->mode = CODEWORD_IN; +# endif + else + { + fprintf (stderr, + "%s: mode must be helix, pizza or both, not \"%s\"\n", + progname, s); + exit (1); + } + if (s) free (s); + + dc->anim_state = (dc->mode == HELIX_AND_PIZZA + ? ((random() & 1) ? HELIX : PIZZA) + : dc->mode); + dc->anim_ratio = 0; + } + +# ifdef CW + if (dc->mode == CODEWORD_IN) + dc->font = load_texture_font (MI_DISPLAY(mi), "cwFont"); +# endif + +# ifdef DEBUG + dc->label_font = load_texture_font (MI_DISPLAY(mi), "fpsFont"); +# endif + + { + XColor xcolor; + + char *color_name = + get_string_resource (mi->dpy, "foreground", "Foreground"); + char *s2; + for (s2 = color_name + strlen(color_name) - 1; s2 > color_name; s2--) + if (*s2 == ' ' || *s2 == '\t') + *s2 = 0; + else + break; + + if (! XParseColor (MI_DISPLAY(mi), mi->xgwa.colormap, color_name, &xcolor)) + { + fprintf (stderr, "%s: can't parse color %s\n", progname, color_name); + exit (1); + } + + dc->color[0] = xcolor.red / 65535.0; + dc->color[1] = xcolor.green / 65535.0; + dc->color[2] = xcolor.blue / 65535.0; + dc->color[3] = 1.0; + + color_name = get_string_resource (mi->dpy, "cwForeground", "Foreground"); + for (s2 = color_name + strlen(color_name) - 1; s2 > color_name; s2--) + if (*s2 == ' ' || *s2 == '\t') + *s2 = 0; + else + break; + + if (! XParseColor (MI_DISPLAY(mi), mi->xgwa.colormap, color_name, &xcolor)) + { + fprintf (stderr, "%s: can't parse color %s\n", progname, color_name); + exit (1); + } + +# ifdef CW + dc->codeword_color[0] = xcolor.red / 65535.0; + dc->codeword_color[1] = xcolor.green / 65535.0; + dc->codeword_color[2] = xcolor.blue / 65535.0; + dc->codeword_color[3] = 1.0; + + color_name = get_string_resource (mi->dpy, "cwBackground", "Background"); + for (s2 = color_name + strlen(color_name) - 1; s2 > color_name; s2--) + if (*s2 == ' ' || *s2 == '\t') + *s2 = 0; + else + break; + + if (! XParseColor (MI_DISPLAY(mi), mi->xgwa.colormap, color_name, &xcolor)) + { + fprintf (stderr, "%s: can't parse color %s\n", progname, color_name); + exit (1); + } + + dc->codeword_bg[0] = xcolor.red / 65535.0; + dc->codeword_bg[1] = xcolor.green / 65535.0; + dc->codeword_bg[2] = xcolor.blue / 65535.0; + dc->codeword_bg[3] = 1.0; +# endif /* CW */ + } + + dc->trackball = gltrackball_init (False); + + dc->gasket_spinnerx.probability = 0.1; + dc->gasket_spinnery.probability = 0.1; + dc->gasket_spinnerz.probability = 1.0; + dc->gasket_spinnerx.easement = 0.08; + dc->gasket_spinnery.easement = 0.08; + dc->gasket_spinnerz.easement = 0.08; + + dc->helix_spinnerz.probability = 0.6; + dc->helix_spinnerz.easement = 0.2; + + dc->pizza_spinnerz.probability = 0.6; + dc->pizza_spinnery.probability = 0.6; + dc->pizza_spinnerz.easement = 0.2; + dc->pizza_spinnery.easement = 0.2; + + dc->frame_spinner.probability = 5.0; + dc->frame_spinner.easement = 0.2; + + dc->scene_spinnerx.probability = 0.1; + dc->scene_spinnery.probability = 0.0; + dc->scene_spinnerx.easement = 0.1; + dc->scene_spinnery.easement = 0.1; + +# ifdef CW + if (dc->mode == CODEWORD_IN) + { + double tilt_speed = 0.003; + dc->scene_rot = make_rotator (0, 0, 0, 0, tilt_speed, True); + } +# endif + + /* start the frame off-screen */ + dc->frame_spinner.spinning_p = True; + dc->frame_spinner.position = 0.3; + dc->frame_spinner.speed = 0.001; + + if (dc->speed > 0) /* start off with the gasket in motion */ + { + dc->gasket_spinnerz.spinning_p = True; + dc->gasket_spinnerz.speed = (0.002 + * ((random() & 1) ? 1 : -1) + * dc->speed); + } + +# ifdef DXF_OUTPUT_HACK + { +# if 0 + dc->frame_depth = dc->gasket_depth; + dxf_layer = 1; + dxf_color = 3; + dxf_start(); + glPushMatrix(); + glRotatef(90, 1, 0, 0); + glRotatef(90, 0, 0, 1); + make_pizza (dc, 0, 0); + + glPushMatrix(); + glRotatef(helix_rot, 0, 0, 1); + make_ladder (dc, 0, 0); + make_helix (dc, 0, 0); + glRotatef (180, 0, 0, 1); + make_helix (dc, 0, 0); + glPopMatrix(); + + dxf_layer++; + make_gasket (dc, 0); + dxf_layer++; + make_frame (dc, 0); + glPopMatrix(); + dxf_end(); +# else + dxf_start(); + glPushMatrix(); + glRotatef(90, 1, 0, 0); + glRotatef(90, 0, 0, 1); + dc->anim_state = CODEWORD; + make_codeword_path (mi); + draw_codeword_path (mi); + glPopMatrix(); + dxf_end(); +# endif + } +# endif + + glPushMatrix(); + dc->helix_list = glGenLists (1); + glNewList (dc->helix_list, GL_COMPILE); + glRotatef(helix_rot, 0, 0, 1); + if (do_ladder) dc->polys[0] += make_ladder (dc, 0, 0); + if (do_helix) dc->polys[0] += make_helix (dc, 0, 0); + glRotatef(180, 0, 0, 1); + if (do_helix) dc->polys[0] += make_helix (dc, 0, 0); + glEndList (); + glPopMatrix(); + + glPushMatrix(); + dc->helix_list_wire = glGenLists (1); + glNewList (dc->helix_list_wire, GL_COMPILE); +/* glRotatef(helix_rot, 0, 0, 1); wtf? */ + if (do_ladder) dc->polys[1] += make_ladder (dc, 1, 1); + if (do_helix) dc->polys[1] += make_helix (dc, 1, 1); + glRotatef(180, 0, 0, 1); + if (do_helix) dc->polys[1] += make_helix (dc, 1, 1); + glEndList (); + glPopMatrix(); + + glPushMatrix(); + dc->helix_list_facetted = glGenLists (1); + glNewList (dc->helix_list_facetted, GL_COMPILE); + glRotatef(helix_rot, 0, 0, 1); + if (do_ladder) dc->polys[2] += make_ladder (dc, 1, 0); + if (do_helix) dc->polys[2] += make_helix (dc, 1, 0); + glRotatef(180, 0, 0, 1); + if (do_helix) dc->polys[2] += make_helix (dc, 1, 0); + glEndList (); + glPopMatrix(); + + dc->pizza_list = glGenLists (1); + glNewList (dc->pizza_list, GL_COMPILE); + if (do_frame) dc->polys[5] += make_pizza (dc, 0, 0); + glEndList (); + + dc->pizza_list_wire = glGenLists (1); + glNewList (dc->pizza_list_wire, GL_COMPILE); + if (do_frame) dc->polys[6] += make_pizza (dc, 1, 1); + glEndList (); + + dc->pizza_list_facetted = glGenLists (1); + glNewList (dc->pizza_list_facetted, GL_COMPILE); + if (do_frame) dc->polys[6] += make_pizza (dc, 1, 0); + glEndList (); + + dc->gasket_list = glGenLists (1); + glNewList (dc->gasket_list, GL_COMPILE); + if (do_gasket) dc->polys[3] += make_gasket (dc, 0); + glEndList (); + + dc->gasket_list_wire = glGenLists (1); + glNewList (dc->gasket_list_wire, GL_COMPILE); + if (do_gasket) dc->polys[4] += make_gasket (dc, 1); + glEndList (); + + dc->frame_list = glGenLists (1); + glNewList (dc->frame_list, GL_COMPILE); + if (do_frame) dc->polys[5] += make_frame (dc, 0); + glEndList (); + + dc->frame_list_wire = glGenLists (1); + glNewList (dc->frame_list_wire, GL_COMPILE); + if (do_frame) dc->polys[6] += make_frame (dc, 1); + glEndList (); + +# ifdef CW + make_codeword_path (mi); +# endif + + /* When drawing both solid and wireframe objects, + make sure the wireframe actually shows up! */ + glEnable (GL_POLYGON_OFFSET_FILL); + glPolygonOffset (1.0, 1.0); +} + + +ENTRYPOINT Bool +logo_handle_event (ModeInfo *mi, XEvent *event) +{ + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; + + if (gltrackball_event_handler (event, dc->trackball, + MI_WIDTH (mi), MI_HEIGHT (mi), + &dc->button_down_p)) + return True; + else if (event->xany.type == KeyPress) + { + KeySym keysym; + char c = 0; + XLookupString (&event->xkey, &c, 1, &keysym, 0); + +# ifdef DEBUG + { + GLfloat step = 0.1; + if (c == 'a') dc->persp_off += step; + else if (c == 'z') dc->persp_off -= step; + else if (c == 's') dc->pos_off += step; + else if (c == 'x') dc->pos_off -= step; + else return False; + + /* dc->pos_off = -dc->persp_off; */ + reshape_logo (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + return True; + } +# endif + + if (c == ' ' || c == '\t') + { + switch (dc->anim_state) { + case HELIX: + dc->anim_state = HELIX_OUT; + dc->anim_ratio = 0.0; + return True; + case PIZZA: + dc->anim_state = PIZZA_OUT; + dc->anim_ratio = 0.0; + return True; +# ifdef CW + case CODEWORD: + dc->anim_state = CODEWORD_OUT; + dc->anim_ratio = 0.0; + return True; +# endif + default: + break; + } + } + } + + return False; +} + + +static GLfloat +spinner_ease (GLfloat x) +{ + /* Smooth curve up, ending at slope = 1. */ + return cos ((x/2 + 1) * M_PI) + 1; +} + + +static void +tick_spinner (ModeInfo *mi, spinner *s) +{ + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; + + if (dc->speed == 0) return; + if (dc->button_down_p) return; + + if (s->spinning_p) + { + s->position += s->speed; + if (s->position >= 1.0 || s->position <= 0.0) + { + s->position = 0; + s->position_eased = 0; + s->spinning_p = False; + } + else if (s->easement > 0 && s->position <= s->easement) + s->position_eased = (s->easement * + spinner_ease (s->position / s->easement)); + else if (s->easement > 0 && s->position >= 1-s->easement) + s->position_eased = (1 - s->easement * + spinner_ease ((1 - s->position) / s->easement)); + else + s->position_eased = s->position; + } + else if (s->probability && + (random() % (int) (PROBABILITY_SCALE / s->probability)) == 0) + { + GLfloat ss = 0.004; + s->spinning_p = True; + s->position = 0; + do { + s->speed = dc->speed * (frand(ss/3) + frand(ss/3) + frand(ss/3)); + } while (s->speed <= 0); + if (random() & 1) + { + s->speed = -s->speed; + s->position = 1.0; + } + } +} + + +static void +link_spinners (ModeInfo *mi, spinner *s0, spinner *s1) +{ + if (s0->spinning_p && !s1->spinning_p) + { + GLfloat op = s1->probability; + s1->probability = PROBABILITY_SCALE; + tick_spinner (mi, s1); + s1->probability = op; + } +} + + +ENTRYPOINT void +draw_logo (ModeInfo *mi) +{ + logo_configuration *dc = &dcs[MI_SCREEN(mi)]; + Display *dpy = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + int wire = MI_IS_WIREFRAME(mi); + GLfloat gcolor[4]; + GLfloat specular[] = {0.8, 0.8, 0.8, 1.0}; + GLfloat shininess = 50.0; + Bool pizza_p; +# ifdef CW + Bool codeword_p; +# endif + + if (!dc->glx_context) + return; + + mi->polygon_count = 0; + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(dc->glx_context)); + + if (!wire && + dc->wire_overlay == 0 && + (random() % (int) (PROBABILITY_SCALE / 0.2)) == 0) + dc->wire_overlay = ((random() % 200) + + (random() % 200) + + (random() % 200)); + +# ifndef DEBUG + tick_spinner (mi, &dc->gasket_spinnerx); + tick_spinner (mi, &dc->gasket_spinnery); + tick_spinner (mi, &dc->gasket_spinnerz); + tick_spinner (mi, &dc->helix_spinnerz); + tick_spinner (mi, &dc->pizza_spinnery); + tick_spinner (mi, &dc->pizza_spinnerz); + tick_spinner (mi, &dc->scene_spinnerx); + tick_spinner (mi, &dc->scene_spinnery); + tick_spinner (mi, &dc->frame_spinner); + link_spinners (mi, &dc->scene_spinnerx, &dc->scene_spinnery); +# endif /* DEBUG */ + + switch (dc->anim_state) + { + case HELIX: + if (dc->mode == HELIX_AND_PIZZA && + (random() % (int) (PROBABILITY_SCALE / 0.2)) == 0) + dc->anim_state = HELIX_OUT; + break; + + case HELIX_OUT: + dc->anim_ratio += 0.1 * dc->speed; + if (dc->anim_ratio >= 1.0) + { + dc->anim_ratio = 0.0; + dc->anim_state = PIZZA_IN; + } + break; + + case PIZZA_IN: + dc->anim_ratio += 0.1 * dc->speed; + if (dc->anim_ratio >= 1.0) + { + dc->anim_ratio = 0.0; + dc->anim_state = PIZZA; + } + break; + + case PIZZA: + if (dc->mode == HELIX_AND_PIZZA && + (random() % (int) (PROBABILITY_SCALE / 0.2)) == 0) + dc->anim_state = PIZZA_OUT; + break; + + case PIZZA_OUT: + dc->anim_ratio += 0.1 * dc->speed; + if (dc->anim_ratio >= 1.0) + { + dc->anim_ratio = 0.0; + dc->anim_state = HELIX_IN; + } + break; + + case HELIX_IN: + dc->anim_ratio += 0.1 * dc->speed; + if (dc->anim_ratio >= 1.0) + { + dc->anim_ratio = 0.0; + dc->anim_state = HELIX; + } + break; + + +# ifdef CW + case CODEWORD_IN: + dc->scene_spinnerx.probability = 0.2; + dc->scene_spinnery.probability = 0.05; + if (! dc->button_down_p) + dc->anim_ratio += 0.004 * dc->speed; + if (dc->anim_ratio >= 1.0) + { + dc->anim_state = CODEWORD; + dc->anim_ratio = frand (0.5); + } + break; + + case CODEWORD: + dc->scene_spinnerx.probability = 0.5; + dc->scene_spinnery.probability = 0.2; + if (! dc->button_down_p) + dc->anim_ratio += (0.0005 + frand(0.002)) * dc->speed; + if (dc->anim_ratio >= 1.0) + { + dc->anim_ratio = 0.0; + dc->anim_state = CODEWORD_OUT; + } + break; + + case CODEWORD_OUT: + dc->scene_spinnerx.probability = 0; + dc->scene_spinnery.probability = 0; + if (! dc->button_down_p) + dc->anim_ratio += 0.02 * dc->speed; + if (dc->anim_ratio >= 1.0) + { + dc->anim_ratio = 0.0; + dc->anim_state = CODEWORD_BLANK; + } + break; + + case CODEWORD_BLANK: + dc->scene_spinnerx.probability = 0; + dc->scene_spinnery.probability = 0; + if (! dc->button_down_p) + dc->anim_ratio += 0.01 * dc->speed; + if (dc->anim_ratio >= 1.0) + { + dc->anim_ratio = 0.0; + dc->anim_state = CODEWORD_IN; + } + break; +# endif /* CW */ + + default: + abort(); + break; + } + +# ifdef DEBUG + dc->anim_state = HELIX; + dc->wire_overlay = 0; +# endif + + pizza_p = (dc->anim_state == PIZZA || + dc->anim_state == PIZZA_IN || + dc->anim_state == PIZZA_OUT); + +# ifdef CW + codeword_p = (dc->anim_state == CODEWORD || + dc->anim_state == CODEWORD_IN || + dc->anim_state == CODEWORD_OUT || + dc->anim_state == CODEWORD_BLANK); +# endif + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix (); + glRotatef(current_device_rotation(), 0, 0, 1); + { + GLfloat scale = 1.8; + glScalef(scale, scale, scale); + + glColor3f(dc->color[0], dc->color[1], dc->color[2]); + + + /* Draw frame before trackball rotation */ +# ifdef CW + if (! codeword_p) +# endif + { + GLfloat p = (dc->frame_spinner.position_eased >= 0 + ? dc->frame_spinner.position_eased + : -dc->frame_spinner.position_eased); + GLfloat size = (p > 0.5 ? 1-p : p); + scale = 1 + (size * 10); + glPushMatrix(); + /* gltrackball_rotate (dc->trackball); */ + glRotatef(90, 1, 0, 0); + glRotatef(90, 0, 0, 1); + + glScalef (1, scale, scale); + if (wire) + { + glDisable (GL_LIGHTING); + glCallList (dc->frame_list_wire); + mi->polygon_count += dc->polys[6]; + } + else if (dc->wire_overlay != 0) + { + glCallList (dc->frame_list); + glDisable (GL_LIGHTING); + glColor3fv (dc->color); + glCallList (dc->frame_list_wire); + mi->polygon_count += dc->polys[6]; + if (!wire) glEnable (GL_LIGHTING); + } + else + { + glCallList (dc->frame_list); + mi->polygon_count += dc->polys[5]; + } + glPopMatrix(); + } + + gltrackball_rotate (dc->trackball); + + glRotatef(90, 1, 0, 0); + glRotatef(90, 0, 0, 1); + +# ifdef CW + if (! codeword_p) +# endif + { + glRotatef (360 * dc->scene_spinnerx.position_eased, 0, 1, 0); + glRotatef (360 * dc->scene_spinnery.position_eased, 0, 0, 1); + + glPushMatrix(); + + glRotatef (360 * dc->gasket_spinnerx.position_eased, 0, 1, 0); + glRotatef (360 * dc->gasket_spinnery.position_eased, 0, 0, 1); + glRotatef (360 * dc->gasket_spinnerz.position_eased, 1, 0, 0); + + memcpy (gcolor, dc->color, sizeof (dc->color)); + if (dc->wire_overlay != 0) + { + gcolor[0] = gcolor[1] = gcolor[2] = 0; + specular[0] = specular[1] = specular[2] = 0; + shininess = 0; + } + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gcolor); + glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, specular); + glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shininess); + + if (wire) + { + glDisable (GL_LIGHTING); + glCallList (dc->gasket_list_wire); + mi->polygon_count += dc->polys[4]; + } + else if (dc->wire_overlay != 0) + { + glCallList (dc->gasket_list); + glDisable (GL_LIGHTING); + glColor3fv (dc->color); + glCallList (dc->gasket_list_wire); + mi->polygon_count += dc->polys[4]; + if (!wire) glEnable (GL_LIGHTING); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gcolor); + } + else + { + glCallList (dc->gasket_list); + mi->polygon_count += dc->polys[3]; + } + glPopMatrix(); + + if (pizza_p) + { + glRotatef (360 * dc->pizza_spinnery.position_eased, 1, 0, 0); + glRotatef (360 * dc->pizza_spinnerz.position_eased, 0, 0, 1); + } + else + { + glRotatef (360 * dc->helix_spinnerz.position_eased, 0, 0, 1); + } + + scale = ((dc->anim_state == PIZZA_IN || dc->anim_state == HELIX_IN) + ? dc->anim_ratio + : ((dc->anim_state == PIZZA_OUT || dc->anim_state == HELIX_OUT) + ? 1.0 - dc->anim_ratio + : 1.0)); + if (scale <= 0) scale = 0.001; + glScalef (scale, scale, scale); + + if (wire) + { + glDisable (GL_LIGHTING); + if (pizza_p) + glCallList (dc->pizza_list_wire); + else + glCallList (dc->helix_list_wire); + mi->polygon_count += dc->polys[1]; + } + else if (dc->wire_overlay != 0) + { + if (pizza_p) + glCallList (dc->pizza_list_facetted); + else + glCallList (dc->helix_list_facetted); + + glDisable (GL_LIGHTING); + glColor3fv (dc->color); + + if (pizza_p) + glCallList (dc->pizza_list_wire); + else + glCallList (dc->helix_list_wire); + + mi->polygon_count += dc->polys[2]; + if (!wire) glEnable (GL_LIGHTING); + } + else + { + if (pizza_p) + glCallList (dc->pizza_list); + else + glCallList (dc->helix_list); + mi->polygon_count += dc->polys[0]; + } + } +# ifdef CW + else /* codeword_p */ + { +# if 0 + double max = 70; /* face front */ + double x, y, z; + get_position (dc->scene_rot, &x, &y, &z, !dc->button_down_p); + glRotatef (max/2 - x*max, 0, 0, 1); + glRotatef (max/2 - y*max, 0, 1, 0); + /* glRotatef (max/2 - z*max, 1, 0, 0); */ +# else + glRotatef (360 * dc->scene_spinnerx.position_eased, 0, 1, 0); + glRotatef (360 * dc->scene_spinnery.position_eased, 0, 0, 1); +# endif + + glClearColor (dc->codeword_bg[0], + dc->codeword_bg[1], + dc->codeword_bg[2], + dc->codeword_bg[3]); + mi->polygon_count += draw_codeword_path (mi); + } +# endif /* CW */ + } + glPopMatrix(); + + if (dc->wire_overlay > 0) + dc->wire_overlay--; + +# ifdef DEBUG + { + char s[1024]; + sprintf (s, "a/z, s/x; per = %0.2f pos = %0.2f", + dc->persp_off, dc->pos_off); + glColor3f (1,1,1); + print_texture_label (dpy, dc->label_font, MI_WIDTH(mi), MI_HEIGHT(mi), + 1, s); + } +# endif + + if (mi->fps_p) do_fps (mi); + glFinish(); + + glXSwapBuffers(dpy, window); +} + +XSCREENSAVER_MODULE_2 ("DNALogo", dnalogo, logo) + +#endif /* USE_GL */ -- cgit v1.2.3-55-g7522