/* 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 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; free (color_name); 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); } free (color_name); # 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); } free (color_name); 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); } ENTRYPOINT void free_logo (ModeInfo *mi) { logo_configuration *dc = &dcs[MI_SCREEN(mi)]; if (!dc->glx_context) return; glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *dc->glx_context); if (dc->trackball) gltrackball_free (dc->trackball); # ifdef CW if (dc->codeword_text) free (dc->codeword_text); if (dc->codeword_text_out) free (dc->codeword_text_out); if (dc->scene_rot) free_rotator (dc->scene_rot); if (dc->font) free_texture_font (dc->font); # endif # ifdef DEBUG if (dc->label_font) free_texture_font (dc->label_font); # endif glDeleteLists(dc->helix_list, 1); glDeleteLists(dc->helix_list_wire, 1); glDeleteLists(dc->helix_list_facetted, 1); glDeleteLists(dc->pizza_list, 1); glDeleteLists(dc->pizza_list_wire, 1); glDeleteLists(dc->pizza_list_facetted, 1); glDeleteLists(dc->gasket_list, 1); glDeleteLists(dc->gasket_list_wire, 1); glDeleteLists(dc->frame_list, 1); glDeleteLists(dc->frame_list_wire, 1); } XSCREENSAVER_MODULE_2 ("DNALogo", dnalogo, logo) #endif /* USE_GL */