+ 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;
+}
+
+
+\f
+/* Window management, etc
+ */
+ENTRYPOINT void
+reshape_logo (ModeInfo *mi, int width, int height)
+{
+ GLfloat h = (GLfloat) height / (GLfloat) width;
+
+ glViewport (0, 0, (GLint) width, (GLint) height);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective (30.0, 1/h, 1.0, 100.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ gluLookAt( 0.0, 0.0, 30.0,
+ 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.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, NULL);
+
+ 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");
+ 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");
+
+ {
+ 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;
+ else if (!strcasecmp (s, "codeword"))
+ dc->mode = CODEWORD_IN;
+ else
+ {
+ fprintf (stderr,
+ "%s: mode must be helix, pizza, both or codeword, 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;
+ }
+
+ if (dc->mode == CODEWORD_IN)
+ dc->font = load_texture_font (MI_DISPLAY(mi), "cwFont");
+
+ {
+ 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);
+ }
+
+ 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;
+ }
+
+ 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;
+
+ if (dc->mode == CODEWORD_IN)
+ {
+ double tilt_speed = 0.003;
+ dc->scene_rot = make_rotator (0, 0, 0, 0, tilt_speed, True);
+ }
+
+ /* 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);