static void init_textures (ModeInfo *mi) { splitflap_configuration *bp = &bps[MI_SCREEN(mi)]; int i; const char * const *spool = latin1_spool; int max = countof(latin1_spool); bp->texinfo = (texinfo *) calloc (max+1, sizeof(*bp->texinfo)); texture_string_metrics (bp->font_data, "", 0, &bp->ascent, &bp->descent); for (i = 0; i < max; i++) { texinfo *ti = &bp->texinfo[i]; glGenTextures (1, &ti->texid); glBindTexture (GL_TEXTURE_2D, ti->texid); ti->text = spool[i]; /* fprintf(stderr, "%d \\%03o\\%03o %s\n", i, (unsigned char) ti->text[0], (unsigned char) ti->text[1], ti->text); */ string_to_texture (bp->font_data, ti->text, &ti->metrics, &ti->tex_width, &ti->tex_height); } bp->texinfo_size = i; glBindTexture (GL_TEXTURE_2D, 0); }
static int char_width (fliptext_configuration *sc, char c) { XCharStruct e; char s[2]; s[0] = c; s[1] = 0; texture_string_metrics (sc->texfont, s, &e, 0, 0); return e.width; }
static int draw_colon (ModeInfo *mi) { splitflap_configuration *bp = &bps[MI_SCREEN(mi)]; GLfloat s = 1.0 / (bp->ascent + bp->descent); GLfloat z = 0.01; int count = 0; XCharStruct m; texture_string_metrics (bp->font_data, ":", &m, 0, 0); s *= 2; glPushMatrix(); glTranslatef (-(1 + COLON_WIDTH), 0, 0); glScalef (s, s, 1); glTranslatef (-m.lbearing - (m.rbearing - m.lbearing)/2, -(m.ascent + m.descent) / 2, 0); glEnable (GL_TEXTURE_2D); /* draw the text five times, to give it a border. */ { const XPoint offsets[] = {{ -1, -1 }, { -1, 1 }, { 1, 1 }, { 1, -1 }, { 0, 0 }}; int i; GLfloat n = 1.5; glColor3f (0, 0, 0); for (i = 0; i < countof(offsets); i++) { glPushMatrix(); if (offsets[i].x == 0) { glColor4fv (bp->text_color); glTranslatef (0, 0, z * 2); } glTranslatef (n * offsets[i].x, n * offsets[i].y, 0); print_texture_string (bp->font_data, ":"); count++; glPopMatrix(); } } glPopMatrix(); return count; }
static void draw_unichar (ModeInfo *mi) { unicrud_configuration *bp = &bps[MI_SCREEN(mi)]; char text[10]; char title[400]; XCharStruct e; int w, h, i, j; GLfloat s; i = utf8_encode (bp->unichar, text, sizeof(text) - 1); text[i] = 0; *title = 0; sprintf (title + strlen(title), "Plane:\t%s\n", bp->charplane); sprintf (title + strlen(title), "Block:\t%s\n", bp->charblock); # ifdef HAVE_JWXYZ sprintf (title + strlen(title), "Name:\t%s\n", (bp->charname ? bp->charname : "")); #endif sprintf (title + strlen(title), "Unicode:\t%04lX\n", bp->unichar); sprintf (title + strlen(title), "UTF-8:\t"); for (j = 0; j < i; j++) sprintf (title + strlen(title), "%02X ", ((unsigned char *)text)[j]); texture_string_metrics (bp->char_font, text, &e, 0, 0); w = e.width; h = e.ascent; s = 9; glScalef (s, s, s); s = 1.0 / (h > w ? h : w); /* Scale to unit */ glScalef (s, s, s); glTranslatef (-w/2, -h/2, 0); glColor4fv (bp->color); print_texture_string (bp->char_font, text); glColor3f (1, 1, 0); if (do_titles) print_texture_label (mi->dpy, bp->title_font, mi->xgwa.width, mi->xgwa.height, 1, title); }
static void loading_msg (ModeInfo *mi) { photopile_state *ss = &sss[MI_SCREEN(mi)]; int wire = MI_IS_WIREFRAME(mi); const char text[] = "Loading..."; if (wire) return; if (ss->loading_sw == 0) /* only do this once */ { XCharStruct e; texture_string_metrics (ss->texfont, text, &e, 0, 0); ss->loading_sw = e.width; ss->loading_sh = e.ascent + e.descent; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glOrtho(0, MI_WIDTH(mi), 0, MI_HEIGHT(mi), -1, 1); glTranslatef ((MI_WIDTH(mi) - ss->loading_sw) / 2, (MI_HEIGHT(mi) - ss->loading_sh) / 2, 0); glColor3f (1, 1, 0); glEnable (GL_TEXTURE_2D); glDisable (GL_DEPTH_TEST); print_texture_string (ss->texfont, text); glEnable (GL_DEPTH_TEST); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glFinish(); glXSwapBuffers (MI_DISPLAY (mi), MI_WINDOW(mi)); }
/* Reads some text from the subprocess, and creates and returns a `line' object. Adds that object to the lines list. Returns 0 if no text available yet. If skip_blanks_p, then keep trying for new lines of text until we get one that is not empty. */ static line * make_line (fliptext_configuration *sc, Bool skip_blanks_p) { XCharStruct e; line *ln; char *s; AGAIN: s = get_one_line (sc); if (s && skip_blanks_p && blank_p (s)) { free (s); goto AGAIN; } if (!s) return 0; ln = (line *) calloc (1, sizeof(*ln)); ln->text = s; ln->state = NEW; texture_string_metrics (sc->texfont, s, &e, 0, 0); ln->width = sc->font_scale * e.width; ln->height = sc->font_scale * sc->line_height; memcpy (ln->color, sc->color, sizeof(ln->color)); sc->nlines++; if (sc->lines_size <= sc->nlines) { sc->lines_size = (sc->lines_size * 1.2) + sc->nlines; sc->lines = (line **) realloc (sc->lines, sc->lines_size * sizeof(*sc->lines)); if (! sc->lines) { fprintf (stderr, "%s: out of memory (%d lines)\n", progname, sc->lines_size); exit (1); } } sc->lines[sc->nlines-1] = ln; return ln; }
static void pick_unichar (ModeInfo *mi) { unicrud_configuration *bp = &bps[MI_SCREEN(mi)]; int i; unsigned long min = 0; unsigned long max = 0x2F800; unsigned long last = 0; int retries = 0; AGAIN: bp->unichar = min + (random() % (max - min)); if (++retries > 0xF0000 / 2) { fprintf (stderr, "%s: internal error: too many retries\n", progname); exit (1); } /* bp->unichar = 0x1F4A9; */ last = 0; bp->charplane = "Unassigned"; bp->charblock = "Unassigned"; for (i = 0; i < countof(unicode_block_names); i++) { if (unicode_block_names[i].start < last) { fprintf (stderr, "%s: progname: internal error: misordered: 0x%lX\n", progname, unicode_block_names[i].start); exit (1); } last = unicode_block_names[i].start; if (bp->unichar >= unicode_block_names[i].start) { if (unicode_block_names[i].name[0] == '*') { bp->charplane = unicode_block_names[i].name + 1; bp->charblock = "Unassigned"; } else bp->charblock = unicode_block_names[i].name; } else break; } if (!strncmp (bp->charblock, "Unassigned", 10) || !strncmp (bp->charblock, "Combining", 9)) goto AGAIN; if (*do_block && !matches (do_block, bp->charblock)) goto AGAIN; /* Skip blank characters */ { XCharStruct e; char text[10]; i = utf8_encode (bp->unichar, text, sizeof(text) - 1); text[i] = 0; texture_string_metrics (bp->char_font, text, &e, 0, 0); if (e.width < 2 || e.ascent + e.descent < 2) goto AGAIN; } # ifdef HAVE_JWXYZ bp->charname = texfont_unicode_character_name (bp->char_font, bp->unichar); # endif bp->color[0] = 0.5 + frand(0.5); bp->color[1] = 0.5 + frand(0.5); bp->color[2] = 0.5 + frand(0.5); bp->color[3] = 1; }
static void draw_frame (ModeInfo *mi, image_frame *frame, time_t now, Bool body_p) { carousel_state *ss = &sss[MI_SCREEN(mi)]; int wire = MI_IS_WIREFRAME(mi); GLfloat texw = frame->current.geom.width / (GLfloat) frame->current.tw; GLfloat texh = frame->current.geom.height / (GLfloat) frame->current.th; GLfloat texx1 = frame->current.geom.x / (GLfloat) frame->current.tw; GLfloat texy1 = frame->current.geom.y / (GLfloat) frame->current.th; GLfloat texx2 = texx1 + texw; GLfloat texy2 = texy1 + texh; GLfloat aspect = ((GLfloat) frame->current.geom.height / (GLfloat) frame->current.geom.width); glBindTexture (GL_TEXTURE_2D, frame->current.texid); glPushMatrix(); /* Position this image on the wheel. */ glRotatef (frame->theta, 0, 1, 0); glTranslatef (0, 0, frame->r); /* Scale down the image so that all N frames fit on the wheel without bumping in to each other. */ { GLfloat t, s; switch (ss->nframes) { case 1: t = -1.0; s = 1.7; break; case 2: t = -0.8; s = 1.6; break; case 3: t = -0.4; s = 1.5; break; case 4: t = -0.2; s = 1.3; break; default: t = 0.0; s = 6.0 / ss->nframes; break; } glTranslatef (0, 0, t); glScalef (s, s, s); } /* Center this image on the wheel plane. */ glTranslatef (-0.5, -(aspect/2), 0); /* Move as per the "zoom in and out" setting. */ if (zoom_p) { double x, y, z; /* Only use the Z component of the rotator for in/out position. */ get_position (frame->rot, &x, &y, &z, !ss->button_down_p); glTranslatef (0, 0, z/2); } /* Compute the "drop in and out" state. */ switch (frame->mode) { case EARLY: abort(); break; case NORMAL: if (!ss->button_down_p && now >= frame->expires && ss->loads_in_progress == 0) /* only load one at a time */ load_image (mi, frame); break; case LOADING: break; case OUT: if (--frame->mode_tick <= 0) { image swap = frame->current; frame->current = frame->loading; frame->loading = swap; frame->mode = IN; frame->mode_tick = fade_ticks / speed; } break; case IN: if (--frame->mode_tick <= 0) frame->mode = NORMAL; break; default: abort(); } /* Now translate for current in/out state. */ if (frame->mode == OUT || frame->mode == IN) { GLfloat t = (frame->mode == OUT ? frame->mode_tick / (fade_ticks / speed) : (((fade_ticks / speed) - frame->mode_tick + 1) / (fade_ticks / speed))); t = 5 * (1 - t); if (frame->from_top_p) t = -t; glTranslatef (0, t, 0); } if (body_p) /* Draw the image quad. */ { if (! wire) { glColor3f (1, 1, 1); glNormal3f (0, 0, 1); glEnable (GL_TEXTURE_2D); glBegin (GL_QUADS); glNormal3f (0, 0, 1); glTexCoord2f (texx1, texy2); glVertex3f (0, 0, 0); glTexCoord2f (texx2, texy2); glVertex3f (1, 0, 0); glTexCoord2f (texx2, texy1); glVertex3f (1, aspect, 0); glTexCoord2f (texx1, texy1); glVertex3f (0, aspect, 0); glEnd(); } /* Draw a box around it. */ glLineWidth (2.0); glColor3f (0.5, 0.5, 0.5); glDisable (GL_TEXTURE_2D); glBegin (GL_LINE_LOOP); glVertex3f (0, 0, 0); glVertex3f (1, 0, 0); glVertex3f (1, aspect, 0); glVertex3f (0, aspect, 0); glEnd(); } else /* Draw a title under the image. */ { XCharStruct e; int sw, sh; GLfloat scale = 0.05; char *title = frame->current.title ? frame->current.title : "(untitled)"; texture_string_metrics (ss->texfont, title, &e, 0, 0); sw = e.width; sh = e.ascent + e.descent; glTranslatef (0, -scale, 0); scale /= sh; glScalef (scale, scale, scale); glTranslatef (((1/scale) - sw) / 2, 0, 0); glColor3f (1, 1, 1); if (!wire) { glEnable (GL_TEXTURE_2D); print_texture_string (ss->texfont, title); } else { glBegin (GL_LINE_LOOP); glVertex3f (0, 0, 0); glVertex3f (sw, 0, 0); glVertex3f (sw, sh, 0); glVertex3f (0, sh, 0); glEnd(); } } glPopMatrix(); }
static void loading_msg (ModeInfo *mi, int n) { carousel_state *ss = &sss[MI_SCREEN(mi)]; int wire = MI_IS_WIREFRAME(mi); char text[100]; if (wire) return; if (n == 0) sprintf (text, "Loading images..."); else sprintf (text, "Loading images... (%d%%)", (int) (n * 100 / MI_COUNT(mi))); if (ss->loading_sw == 0) { /* only do this once, so that the string doesn't move. */ XCharStruct e; texture_string_metrics (ss->texfont, text, &e, 0, 0); ss->loading_sw = e.width; ss->loading_sh = e.ascent + e.descent; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); /* { double rot = current_device_rotation(); glRotatef(rot, 0, 0, 1); if ((rot > 45 && rot < 135) || (rot < -45 && rot > -135)) { GLfloat s = MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi); glScalef (s, 1/s, 1); } } */ # ifdef HAVE_MOBILE if (MI_WIDTH(mi) < MI_HEIGHT(mi)) /* portrait orientation */ { GLfloat s = (MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi)); glScalef (s, s, s); glTranslatef(-s/2, 0, 0); } # endif glOrtho(0, MI_WIDTH(mi), 0, MI_HEIGHT(mi), -1, 1); glTranslatef ((MI_WIDTH(mi) - ss->loading_sw) / 2, (MI_HEIGHT(mi) - ss->loading_sh) / 2, 0); glColor3f (1, 1, 0); glEnable (GL_TEXTURE_2D); glDisable (GL_DEPTH_TEST); print_texture_string (ss->texfont, text); glEnable (GL_DEPTH_TEST); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glFinish(); glXSwapBuffers (MI_DISPLAY (mi), MI_WINDOW(mi)); }
ENTRYPOINT void init_fliptext (ModeInfo *mi) { int wire = MI_IS_WIREFRAME(mi); fliptext_configuration *sc; MI_INIT(mi, scs); sc = &scs[MI_SCREEN(mi)]; sc->lines = (line **) calloc (max_lines+1, sizeof(char *)); sc->dpy = MI_DISPLAY(mi); if ((sc->glx_context = init_GL(mi)) != NULL) { reshape_fliptext (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); clear_gl_error(); /* WTF? sometimes "invalid op" from glViewport! */ } { XCharStruct e; int cw, lh, ascent, descent; sc->texfont = load_texture_font (MI_DISPLAY(mi), "font"); check_gl_error ("loading font"); texture_string_metrics (sc->texfont, "n", &e, &ascent, &descent); cw = e.width; lh = ascent + descent; sc->char_width = cw; sc->line_height = lh; } if (!wire) { glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable (GL_BLEND); glEnable (GL_ALPHA_TEST); glEnable (GL_TEXTURE_2D); /* "Anistropic filtering helps for quadrilateral-angled textures. A sharper image is accomplished by interpolating and filtering multiple samples from one or more mipmaps to better approximate very distorted textures. This is the next level of filtering after trilinear filtering." */ if (strstr ((char *) glGetString(GL_EXTENSIONS), "GL_EXT_texture_filter_anisotropic")) { GLfloat anisotropic = 0.0; glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic); if (anisotropic >= 1.0) glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropic); } } /* The default font is (by fiat) "18 points". Interpret the user's font size request relative to that. */ sc->font_scale = 3 * (font_size / 18.0); if (target_columns <= 2) target_columns = 2; /* Figure out what the wrap column should be, in font-coordinate pixels. Compute it from the given -columns value, but don't let it be wider than the screen. */ { GLfloat maxw = 110 * sc->line_height / sc->font_scale; /* magic... */ sc->font_wrap_pixels = target_columns * sc->char_width; if (sc->font_wrap_pixels > maxw || sc->font_wrap_pixels <= 0) sc->font_wrap_pixels = maxw; } sc->buf_size = target_columns * max_lines; sc->buf = (char *) calloc (1, sc->buf_size); alignment_random_p = False; if (!alignment_str || !*alignment_str || !strcasecmp(alignment_str, "left")) sc->alignment = -1; else if (!strcasecmp(alignment_str, "center") || !strcasecmp(alignment_str, "middle")) sc->alignment = 0; else if (!strcasecmp(alignment_str, "right")) sc->alignment = 1; else if (!strcasecmp(alignment_str, "random")) sc->alignment = -1, alignment_random_p = True; else { fprintf (stderr, "%s: alignment must be left/center/right/random, not \"%s\"\n", progname, alignment_str); exit (1); } sc->tc = textclient_open (sc->dpy); if (max_lines < 1) max_lines = 1; min_lines = max_lines * 0.66; if (min_lines > max_lines - 3) min_lines = max_lines - 4; if (min_lines < 1) min_lines = 1; parse_color (mi, "foreground", get_string_resource(mi->dpy, "foreground", "Foreground"), sc->color); sc->top_margin = (sc->char_width * 100); sc->bottom_margin = -sc->top_margin; reshape_fliptext (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); /* compute left/right */ }
static void draw_line (ModeInfo *mi, line *line) { int wire = MI_IS_WIREFRAME(mi); fliptext_configuration *sc = &scs[MI_SCREEN(mi)]; if (! line->text || !*line->text || line->state == NEW || line->state == HESITATE || line->state == DEAD) return; glPushMatrix(); glTranslatef (line->current.x, line->current.y, line->current.z); glRotatef (line->cth, 0, 1, 0); if (sc->alignment == 1) glTranslatef (-line->width, 0, 0); else if (sc->alignment == 0) glTranslatef (-line->width/2, 0, 0); glScalef (sc->font_scale, sc->font_scale, sc->font_scale); glColor4f (line->color[0], line->color[1], line->color[2], line->color[3]); if (!wire) print_texture_string (sc->texfont, line->text); else { int w, h; char *s = line->text; char c[2]; c[1]=0; glDisable (GL_TEXTURE_2D); glColor3f (0.4, 0.4, 0.4); while (*s) { XCharStruct e; *c = *s++; texture_string_metrics (sc->texfont, c, &e, 0, 0); w = e.width; h = e.ascent + e.descent; glBegin (GL_LINE_LOOP); glVertex3f (0, 0, 0); glVertex3f (w, 0, 0); glVertex3f (w, h, 0); glVertex3f (0, h, 0); glEnd(); glTranslatef (w, 0, 0); } } #if 0 glDisable (GL_TEXTURE_2D); glColor3f (0.4, 0.4, 0.4); glBegin (GL_LINE_LOOP); glVertex3f (0, 0, 0); glVertex3f (line->width/sc->font_scale, 0, 0); glVertex3f (line->width/sc->font_scale, line->height/sc->font_scale, 0); glVertex3f (0, line->height/sc->font_scale, 0); glEnd(); if (!wire) glEnable (GL_TEXTURE_2D); #endif glPopMatrix(); mi->polygon_count += strlen (line->text); }
static void draw_image (ModeInfo *mi, int i, GLfloat t, GLfloat s, GLfloat z) { int wire = MI_IS_WIREFRAME(mi); photopile_state *ss = &sss[MI_SCREEN(mi)]; image *frame = ss->frames + i; position pos = interpolate(t, frame->pos); GLfloat w = frame->geom.width * 0.5; GLfloat h = frame->geom.height * 0.5; GLfloat z1 = z - 0.25 / (MI_COUNT(mi) + 1); GLfloat z2 = z - 0.5 / (MI_COUNT(mi) + 1); GLfloat w1 = w; GLfloat h1 = h; GLfloat h2 = h; if (polaroid_p) { GLfloat minSize = MIN(w, h); GLfloat maxSize = MAX(w, h); /* Clip or scale image to fit in the frame. */ if (clip_p) { w = h = minSize; } else { GLfloat scale = minSize / maxSize; w *= scale; h *= scale; } w1 = minSize * 1.16; /* enlarge frame border */ h1 = minSize * 1.5; h2 = w1; s /= 1.5; /* compensate for border size */ } glPushMatrix(); /* Position and scale this image. */ glTranslatef (pos.x, pos.y, 0); glRotatef (pos.angle, 0, 0, 1); glScalef (s, s, 1); /* Draw the drop shadow. */ if (shadows_p && !wire) { glColor3f (0, 0, 0); draw_drop_shadow(ss->shadow, -w1, -h1, z2, 2.0 * w1, h1 + h2, 20.0); glDisable (GL_BLEND); } glDisable (GL_LIGHTING); glEnable (GL_DEPTH_TEST); glDisable (GL_CULL_FACE); /* Draw the retro instant-film frame. */ if (polaroid_p) { if (! wire) { glShadeModel (GL_SMOOTH); glEnable (GL_LINE_SMOOTH); glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); glColor3f (1, 1, 1); glBegin (GL_QUADS); glVertex3f (-w1, -h1, z2); glVertex3f ( w1, -h1, z2); glVertex3f ( w1, h2, z2); glVertex3f (-w1, h2, z2); glEnd(); } glLineWidth (1.0); glColor3f (0.5, 0.5, 0.5); glBegin (GL_LINE_LOOP); glVertex3f (-w1, -h1, z); glVertex3f ( w1, -h1, z); glVertex3f ( w1, h2, z); glVertex3f (-w1, h2, z); glEnd(); } /* Draw the image quad. */ if (! wire) { GLfloat texw = w / frame->tw; GLfloat texh = h / frame->th; GLfloat texx = (frame->geom.x + 0.5 * frame->geom.width) / frame->tw; GLfloat texy = (frame->geom.y + 0.5 * frame->geom.height) / frame->th; glBindTexture (GL_TEXTURE_2D, frame->texid); glEnable (GL_TEXTURE_2D); glColor3f (1, 1, 1); glBegin (GL_QUADS); glTexCoord2f (texx - texw, texy + texh); glVertex3f (-w, -h, z1); glTexCoord2f (texx + texw, texy + texh); glVertex3f ( w, -h, z1); glTexCoord2f (texx + texw, texy - texh); glVertex3f ( w, h, z1); glTexCoord2f (texx - texw, texy - texh); glVertex3f (-w, h, z1); glEnd(); glDisable (GL_TEXTURE_2D); } /* Draw a box around it. */ if (! wire) { glShadeModel (GL_SMOOTH); glEnable (GL_LINE_SMOOTH); glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); } glLineWidth (1.0); glColor3f (0.5, 0.5, 0.5); glBegin (GL_LINE_LOOP); glVertex3f (-w, -h, z); glVertex3f ( w, -h, z); glVertex3f ( w, h, z); glVertex3f (-w, h, z); glEnd(); /* Draw a title under the image. */ if (titles_p) { int sw, sh, ascent, descent; GLfloat scale = 1; const char *title = frame->title ? frame->title : "(untitled)"; XCharStruct e; /* #### Highly approximate, but doing real clipping is harder... */ int max = 35; if (strlen(title) > max) title += strlen(title) - max; texture_string_metrics (ss->texfont, title, &e, &ascent, &descent); sw = e.width; sh = ascent + descent; /* Scale the text to match the pixel size of the photo */ scale *= w / 300.0; /* Move to below photo */ glTranslatef (0, -h - sh * (polaroid_p ? 2.2 : 0.5), 0); glTranslatef (-sw*scale/2, sh*scale/2, z); glScalef (scale, scale, 1); if (wire || !polaroid_p) { glColor3f (1, 1, 1); } else { glColor3f (0, 0, 0); } if (!wire) { glEnable (GL_TEXTURE_2D); glEnable (GL_BLEND); print_texture_string (ss->texfont, title); } else { glBegin (GL_LINE_LOOP); glVertex3f (0, 0, 0); glVertex3f (sw, 0, 0); glVertex3f (sw, sh, 0); glVertex3f (0, sh, 0); glEnd(); } } glPopMatrix(); }