X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fstarwars.c;h=9ee8cc3f05ed11e00cdb993ae1beeac83c0842d7;hp=69b1cf9cd073c83569e92a2081cc5a0c95c727df;hb=4361b69d3178d7fc98d0388f9a223af6c2651aba;hpb=5f9c47ca98dd43d8f59b7c27d3fde6edfde4fe21 diff --git a/hacks/glx/starwars.c b/hacks/glx/starwars.c index 69b1cf9c..9ee8cc3f 100644 --- a/hacks/glx/starwars.c +++ b/hacks/glx/starwars.c @@ -1,4 +1,4 @@ -/* starwars, Copyright (c) 1998-2011 Jamie Zawinski and +/* starwars, Copyright (c) 1998-2015 Jamie Zawinski and * Claudio Matsuoka * * Permission to use, copy, modify, distribute, and sell this software and its @@ -22,7 +22,7 @@ * * For the fanboys: * - * starwars -program 'cat starwars.txt' -columns 25 -no-wrap -texture + * starwars -program 'cat starwars.txt' -columns 25 -no-wrap */ #ifdef HAVE_CONFIG_H @@ -36,22 +36,25 @@ # include #endif -#ifndef HAVE_COCOA -# include -#endif - - +#include "starwars.h" #define DEFAULTS "*delay: 40000 \n" \ "*showFPS: False \n" \ "*fpsTop: True \n" \ - "*font: " DEF_FONT "\n" + "*usePty: False \n" \ + "*texFontCacheSize: 300\n" \ + "*font: " DEF_FONT "\n" \ + "*textLiteral: " DEF_TEXT "\n" \ + "*program: xscreensaver-text --cols 0" /* don't wrap */ # define refresh_sws 0 +# define release_sws 0 # define sws_handle_event 0 #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) #include "xlockmore.h" +#include "textclient.h" +#include "utf8wc.h" #ifdef USE_GL /* whole file */ @@ -64,7 +67,6 @@ # endif -#define DEF_PROGRAM "xscreensaver-text --cols 0" /* don't wrap */ #define DEF_LINES "125" #define DEF_STEPS "35" #define DEF_SPIN "0.03" @@ -78,20 +80,16 @@ #define DEF_TEXTURES "True" #define DEF_DEBUG "False" -/* Utopia 800 needs 64 512x512 textures (4096x4096 bitmap). - Utopia 720 needs 16 512x512 textures (2048x2048 bitmap). - Utopia 480 needs 16 512x512 textures (2048x2048 bitmap). - Utopia 400 needs 4 512x512 textures (1024x1024 bitmap). - Utopia 180 needs 1 512x512 texture. - Times 240 needs 1 512x512 texture. - */ -#define DEF_FONT "-*-utopia-bold-r-normal-*-*-720-*-*-*-*-iso8859-1" +#define DEF_FONT "-*-utopia-bold-r-normal-*-*-360-*-*-*-*-*-*" #define TAB_WIDTH 8 #define MAX_THICK_LINES 25 #define FONT_WEIGHT 14 -#define KEEP_ASPECT + +#ifndef HAVE_MOBILE +# define KEEP_ASPECT /* Letterboxing looks dumb on iPhone. */ +#endif #include "texfont.h" #include "glutstroke.h" @@ -104,23 +102,20 @@ typedef struct { GLuint text_list, star_list; texture_font_data *texfont; - int polygon_count; - - FILE *pipe; - XtInputId pipe_id; - XtIntervalId pipe_timer; - Time subproc_relaunch_delay; + text_data *tc; char *buf; int buf_size; int buf_tail; char **lines; + int *line_widths; int total_lines; double star_theta; double char_width; double line_height; + double descent; double font_scale; double intra_line_scroll; @@ -133,7 +128,6 @@ typedef struct { static sws_configuration *scs = NULL; -static char *program; static int max_lines; static int scroll_steps; static float star_spin; @@ -149,7 +143,6 @@ static char *alignment_str; static int alignment; static XrmOptionDescRec opts[] = { - {"-program", ".program", XrmoptionSepArg, 0 }, {"-lines", ".lines", XrmoptionSepArg, 0 }, {"-steps", ".steps", XrmoptionSepArg, 0 }, {"-spin", ".spin", XrmoptionSepArg, 0 }, @@ -175,7 +168,6 @@ static XrmOptionDescRec opts[] = { }; static argtype vars[] = { - {&program, "program", "Program", DEF_PROGRAM, t_String}, {&max_lines, "lines", "Integer", DEF_LINES, t_Int}, {&scroll_steps, "steps", "Integer", DEF_STEPS, t_Int}, {&star_spin, "spin", "Float", DEF_SPIN, t_Float}, @@ -255,246 +247,176 @@ strip (char *s, Bool leading, Bool trailing) } -/* The GLUT font only has ASCII characters in them, so do what we can to - convert Latin1 characters to the nearest ASCII equivalent... - */ -static void -latin1_to_ascii (char *s) -{ - unsigned char *us = (unsigned char *) s; - const unsigned char ascii[95] = { - '!', 'C', '#', '#', 'Y', '|', 'S', '_', 'C', '?', '<', '=', '-', 'R', '_', - '?', '?', '2', '3', '\'','u', 'P', '.', ',', '1', 'o', '>', '?', '?', '?', - '?', 'A', 'A', 'A', 'A', 'A', 'A', 'E', 'C', 'E', 'E', 'E', 'E', 'I', 'I', - 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'x', '0', 'U', 'U', 'U', 'U', - 'Y', 'p', 'S', 'a', 'a', 'a', 'a', 'a', 'a', 'e', 'c', 'e', 'e', 'e', 'e', - 'i', 'i', 'i', 'i', 'o', 'n', 'o', 'o', 'o', 'o', 'o', '/', 'o', 'u', 'u', - 'u', 'u', 'y', 'p', 'y' }; - while (*us) - { - if (*us >= 161) - *us = ascii[*us - 161]; - else if (*us > 127) - *us = '?'; - us++; - } -} - - -/* Subprocess. - (This bit mostly cribbed from phosphor.c) - */ - -static void drain_input (sws_configuration *sc); - -static void -subproc_cb (XtPointer closure, int *source, XtInputId *id) -{ - sws_configuration *sc = (sws_configuration *) closure; - drain_input (sc); -} - - -static void -launch_text_generator (sws_configuration *sc) +static int +sw_string_width (sws_configuration *sc, const char *s) { - XtAppContext app = XtDisplayToApplicationContext (sc->dpy); - char *oprogram = get_string_resource (sc->dpy, "program", "Program"); - char *program = (char *) malloc (strlen (oprogram) + 10); - strcpy (program, "( "); - strcat (program, oprogram); - strcat (program, " ) 2>&1"); - - if ((sc->pipe = popen (program, "r"))) + if (textures_p) { - sc->pipe_id = - XtAppAddInput (app, fileno (sc->pipe), - (XtPointer) (XtInputReadMask | XtInputExceptMask), - subproc_cb, (XtPointer) sc); + XCharStruct e; + texture_string_metrics (sc->texfont, s, &e, 0, 0); + return e.width; } else - { - perror (program); - } + return glutStrokeLength (GLUT_FONT, (unsigned char *) s); } -static void -relaunch_generator_timer (XtPointer closure, XtIntervalId *id) +static int +sw_string_width2 (sws_configuration *sc, const char *s, size_t size) { - sws_configuration *sc = (sws_configuration *) closure; - if (!sc->pipe_timer) abort(); - sc->pipe_timer = 0; - launch_text_generator (sc); -} - + char *s2 = (char *) malloc (size + 1); + int result; -/* When the subprocess has generated some output, this reads as much as it - can into sc->buf at sc->buf_tail. - */ -static void -drain_input (sws_configuration *sc) -{ - XtAppContext app = XtDisplayToApplicationContext (sc->dpy); - if (sc->buf_tail < sc->buf_size - 2) - { - int target = sc->buf_size - sc->buf_tail - 2; - int n = (sc->pipe - ? read (fileno (sc->pipe), - (void *) (sc->buf + sc->buf_tail), - target) - : 0); - if (n > 0) - { - sc->buf_tail += n; - sc->buf[sc->buf_tail] = 0; - } - else - { - if (sc->pipe) - { - XtRemoveInput (sc->pipe_id); - sc->pipe_id = 0; - pclose (sc->pipe); - sc->pipe = 0; - } - - /* If the process didn't print a terminating newline, add one. */ - if (sc->buf_tail > 1 && - sc->buf[sc->buf_tail-1] != '\n') - { - sc->buf[sc->buf_tail++] = '\n'; - sc->buf[sc->buf_tail] = 0; - } - - /* Then add one more, just for giggles. */ - sc->buf[sc->buf_tail++] = '\n'; - sc->buf[sc->buf_tail] = 0; - - /* Set up a timer to re-launch the subproc in a bit. */ - sc->pipe_timer = XtAppAddTimeOut (app, sc->subproc_relaunch_delay, - relaunch_generator_timer, - (XtPointer) sc); - } - } -} + strncpy (s2, s, size); + s2[size] = 0; + result = sw_string_width (sc, s2); -static int -string_width (sws_configuration *sc, const char *s) -{ - if (textures_p) - return texture_string_width (sc->texfont, s, 0); - else - return glutStrokeLength (GLUT_FONT, (unsigned char *) s); -} - -static int -char_width (sws_configuration *sc, char c) -{ - char s[2]; - s[0] = c; - s[1] = 0; - return string_width (sc, s); + free (s2); + return result; } -/* Populates the sc->lines list with as many lines as are currently in - sc->buf (which was filled by drain_input(). +/* Populates the sc->lines list with as many lines as possible. */ static void get_more_lines (sws_configuration *sc) { /* wrap anyway, if it's absurdly long. */ int wrap_pix = (wrap_p ? sc->line_pixel_width : 10000); - - int col = 0; - int col_pix = 0; char *s = sc->buf; - while (sc->total_lines < max_lines) + + int target = sc->buf_size - sc->buf_tail - 2; + + /* Fill as much as we can into sc->buf. + */ + while (target > 0) { - int cw; + int c = textclient_getc (sc->tc); + if (c <= 0) + break; + sc->buf[sc->buf_tail++] = (char) c; + sc->buf[sc->buf_tail] = 0; + target--; + } - if (s >= sc->buf + sc->buf_tail) - /* Reached end of buffer before end of line. Bail. */ - return; + while (sc->total_lines < max_lines) + { + char *next_s = s; + unsigned counter = 0; - cw = char_width (sc, *s); + /* OS X is really slow to calcuate the bounds for a line of text, + so skip ahead a bit. - if (*s == '\r' || *s == '\n' || - col_pix + cw >= wrap_pix) + Really though, the right thing to do is probably to wrap + CTLineCreateTruncatedLine, one way or another. */ + for (;;) { - int L = s - sc->buf; + if (next_s >= sc->buf + sc->buf_tail) + break; - if (*s == '\r' || *s == '\n') + if (!counter) { - if (*s == '\r' && s[1] == '\n') /* swallow CRLF too */ - *s++ = 0; + if (s > sc->buf && + sw_string_width2 (sc, sc->buf, next_s - sc->buf) >= wrap_pix) + break; - *s++ = 0; + counter = 12; /* <-- Adjust to taste. */ + s = next_s; } - else + + if (*next_s == '\r' || *next_s == '\n') + break; + + --counter; + ++next_s; + } + + for (;;) + { + if (s >= sc->buf + sc->buf_tail) + /* Reached end of buffer before end of line. Bail. */ + return; + + /* When checking pixel width, always measure the line from the + beginning, or else multi-byte UTF-8 characters, particularly + combining diacriticals, aren't measured right. */ + + if (*s == '\r' || *s == '\n' || + (s > sc->buf && sw_string_width2 (sc, sc->buf, s - sc->buf) >= wrap_pix)) { - /* We wrapped -- try to back up to the previous word boundary. */ - char *s2 = s; - int n = 0; - while (s2 > sc->buf && *s2 != ' ' && *s2 != '\t') - s2--, n++; - if (s2 > sc->buf) + int L = s - sc->buf; + + if (*s == '\r' || *s == '\n') { - s = s2; + if (*s == '\r' && s[1] == '\n') /* swallow CRLF too */ + *s++ = 0; + *s++ = 0; - L = s - sc->buf; } - } + else + { + /* We wrapped -- try to back up to the previous word boundary. */ + char *s2 = s; + int n = 0; + while (s2 > sc->buf && *s2 != ' ' && *s2 != '\t') + s2--, n++; + if (s2 > sc->buf) + { + s = s2; + *s++ = 0; + L = s - sc->buf; + } + } - sc->lines[sc->total_lines] = (char *) malloc (L+1); - memcpy (sc->lines[sc->total_lines], sc->buf, L); - sc->lines[sc->total_lines][L] = 0; + sc->lines[sc->total_lines] = (char *) malloc (L+1); + memcpy (sc->lines[sc->total_lines], sc->buf, L); + sc->lines[sc->total_lines][L] = 0; - if (!textures_p) - latin1_to_ascii (sc->lines[sc->total_lines]); + if (!textures_p) + { + /* The GLUT font only has ASCII characters. */ + char *s1 = utf8_to_latin1 (sc->lines[sc->total_lines], True); + free (sc->lines[sc->total_lines]); + sc->lines[sc->total_lines] = s1; + } - { - char *t = sc->lines[sc->total_lines]; - char *ut = untabify (t); - strip (ut, (alignment == 0), 1); /* if centering, strip - leading whitespace too */ - sc->lines[sc->total_lines] = ut; - free (t); - } + { + char *t = sc->lines[sc->total_lines]; + char *ut = untabify (t); + strip (ut, (alignment == 0), 1); /* if centering, strip + leading whitespace too */ + sc->lines[sc->total_lines] = ut; + free (t); + } - sc->total_lines++; + sc->line_widths[sc->total_lines] = + sw_string_width(sc, sc->lines[sc->total_lines]); + + sc->total_lines++; + + if (sc->buf_tail > (s - sc->buf)) + { + int i = sc->buf_tail - (s - sc->buf); + memmove (sc->buf, s, i); + sc->buf_tail = i; + sc->buf[sc->buf_tail] = 0; + } + else + { + sc->buf_tail = 0; + } - if (sc->buf_tail > (s - sc->buf)) - { - int i = sc->buf_tail - (s - sc->buf); - memmove (sc->buf, s, i); - sc->buf_tail = i; sc->buf[sc->buf_tail] = 0; + s = sc->buf; + + break; } else { - sc->buf_tail = 0; + s++; } - - sc->buf[sc->buf_tail] = 0; - s = sc->buf; - col = 0; - col_pix = 0; - } - else - { - col++; - col_pix += cw; - if (*s == '\t') - { - int tab_pix = TAB_WIDTH * sc->char_width; - col = TAB_WIDTH * ((col / TAB_WIDTH) + 1); - col_pix = tab_pix * ((col / tab_pix) + 1); - } - s++; } } } @@ -517,29 +439,45 @@ draw_string (sws_configuration *sc, GLfloat x, GLfloat y, const char *s) if (debug_p) { - GLfloat w; GLfloat h = sc->line_height / sc->font_scale; - char c[2]; - c[1]=0; - s = os; + char **chars = utf8_split (os, 0); + int i, w = 0; + char *s2 = (char *) malloc (strlen(s) + 1); + *s2 = 0; + if (textures_p) glDisable (GL_TEXTURE_2D); glLineWidth (1); - glColor3f (0.4, 0.4, 0.4); - glPushMatrix (); - glTranslatef (x, y, 0); - while (*s) + + glColor3f (0.2, 0.2, 0.5); + + glBegin (GL_LINES); + + for (i = 0; chars[i]; i++) { - *c = *s++; - w = string_width (sc, c); - 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); + glVertex3f (x + w, y - sc->descent, 0); /* char left */ + glVertex3f (x + w, y - sc->descent + h, 0); + strcat (s2, chars[i]); + w = sw_string_width (sc, s2); + free (chars[i]); } - glPopMatrix (); + + glVertex3f (x + w, y - sc->descent, 0); /* char right */ + glVertex3f (x + w, y - sc->descent + h, 0); + + glVertex3f (x, y - sc->descent + h, 0); /* ascent */ + glVertex3f (x + w, y - sc->descent + h, 0); + + glVertex3f (x - sc->char_width, y, 0); /* baseline */ + glVertex3f (x + sc->char_width + w, y, 0); + + glVertex3f (x, y - sc->descent, 0); /* descent */ + glVertex3f (x + w, y - sc->descent, 0); + + glEnd(); + + free (s2); + free (chars); + if (textures_p) glEnable (GL_TEXTURE_2D); } } @@ -670,6 +608,7 @@ reshape_sws (ModeInfo *mi, int width, int height) int w = mi->xgwa.width; int h = mi->xgwa.height; int yoff = 0; + GLfloat rot = current_device_rotation(); #ifdef KEEP_ASPECT { @@ -680,15 +619,28 @@ reshape_sws (ModeInfo *mi, int width, int height) } #endif - glMatrixMode (GL_PROJECTION); glViewport (0, yoff, w, h); + glMatrixMode (GL_PROJECTION); + glLoadIdentity(); + glMatrixMode (GL_MODELVIEW); glLoadIdentity (); gluPerspective (80.0, 1/desired_aspect, 1000, 55000); gluLookAt (0.0, 0.0, 4600.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); + + /* Horrible kludge to prevent the text from materializing already + on screen on iPhone in landscape mode. + */ + if ((rot > 45 && rot < 135) || + (rot < -45 && rot > -135)) + { + GLfloat s = 1.1; + glScalef (s, s, s); + } + glRotatef (-60.0, 1.0, 0.0, 0.0); #if 0 @@ -712,8 +664,8 @@ reshape_sws (ModeInfo *mi, int width, int height) { GLdouble mm[17], pm[17]; GLint vp[5]; - GLfloat x = 0.5, y1 = 0, z = 0; - GLfloat y2 = sc->line_height; + GLdouble x = 0.5, y1 = 0, z = 0; + GLdouble y2 = sc->line_height; GLdouble wx=-1, wy1=-1, wy2=-1, wz=-1; glGetDoublev (GL_MODELVIEW_MATRIX, mm); @@ -742,8 +694,6 @@ gl_init (ModeInfo *mi) { sws_configuration *sc = &scs[MI_SCREEN(mi)]; - program = get_string_resource (mi->dpy, "program", "Program"); - glDisable (GL_LIGHTING); glDisable (GL_DEPTH_TEST); @@ -767,6 +717,9 @@ gl_init (ModeInfo *mi) } +static void free_sws (ModeInfo *mi); + + ENTRYPOINT void init_sws (ModeInfo *mi) { @@ -774,20 +727,15 @@ init_sws (ModeInfo *mi) sws_configuration *sc = 0; - if (!scs) { - scs = (sws_configuration *) - calloc (MI_NUM_SCREENS(mi), sizeof (sws_configuration)); - if (!scs) { - fprintf(stderr, "%s: out of memory\n", progname); - exit(1); - } - } + MI_INIT (mi, scs, free_sws); sc = &scs[MI_SCREEN(mi)]; sc->dpy = MI_DISPLAY(mi); sc = &scs[MI_SCREEN(mi)]; + /* Unchecked malloc. :( */ sc->lines = (char **) calloc (max_lines+1, sizeof(char *)); + sc->line_widths = (int *) calloc (max_lines+1, sizeof(int)); if ((sc->glx_context = init_GL(mi)) != NULL) { gl_init(mi); @@ -799,11 +747,14 @@ init_sws (ModeInfo *mi) if (textures_p) { - int cw, lh; + XCharStruct e; + int cw, ascent, descent; sc->texfont = load_texture_font (MI_DISPLAY(mi), "font"); - cw = texture_string_width (sc->texfont, "n", &lh); + texture_string_metrics (sc->texfont, "n", &e, &ascent, &descent); + cw = e.width; sc->char_width = cw; - font_height = lh; + font_height = ascent + descent; + sc->descent = descent; glEnable(GL_ALPHA_TEST); glEnable (GL_TEXTURE_2D); @@ -829,6 +780,7 @@ init_sws (ModeInfo *mi) { font_height = GLUT_FONT->top - GLUT_FONT->bottom; sc->char_width = glutStrokeWidth (GLUT_FONT, 'z'); /* 'n' seems wide */ + sc->descent = 0; } sc->font_scale = 1.0 / sc->char_width; @@ -859,17 +811,19 @@ init_sws (ModeInfo *mi) sc->font_scale /= target_columns; sc->line_height = font_height * sc->font_scale; - - /* Buffer only two lines of text. + /* Buffer only a few lines of text. If the buffer is too big, there's a significant delay between when the program launches and when the text appears, which can be irritating for time-sensitive output (clock, current music, etc.) + + I'd like to buffer only 2 lines, but we need to assume that we + could get a whole line of N-byte Unicrud, and if we fill the buffer + before hitting the end of the line, we stall. */ - sc->buf_size = target_columns * 2; + sc->buf_size = target_columns * 2 * 4; if (sc->buf_size < 80) sc->buf_size = 80; sc->buf = (char *) calloc (1, sc->buf_size); - sc->subproc_relaunch_delay = 2 * 1000; /* 2 seconds */ sc->total_lines = max_lines-1; if (random() & 1) @@ -891,7 +845,7 @@ init_sws (ModeInfo *mi) exit (1); } - launch_text_generator (sc); + sc->tc = textclient_open (sc->dpy); /* one more reshape, after line_height has been computed */ reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); @@ -917,6 +871,7 @@ draw_stars (ModeInfo *mi) -100.0, 100.0); glRotatef (sc->star_theta, 0.0, 0.0, 1.0); if (textures_p) glDisable (GL_TEXTURE_2D); + glCallList (sc->star_list); if (textures_p) glEnable (GL_TEXTURE_2D); } @@ -938,11 +893,6 @@ draw_sws (ModeInfo *mi) if (!sc->glx_context) return; -#if 0 - if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput)) - XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput); -#endif - glDrawBuffer (GL_BACK); glXMakeCurrent (dpy, window, *(sc->glx_context)); @@ -953,14 +903,33 @@ draw_sws (ModeInfo *mi) glMatrixMode (GL_MODELVIEW); glPushMatrix (); +# ifdef HAVE_MOBILE + /* Need to do this every time to get device rotation right */ + reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); +# endif + if (debug_p) { int i; glPushMatrix (); if (textures_p) glDisable (GL_TEXTURE_2D); glLineWidth (1); - glColor3f (0.4, 0.4, 0.4); glTranslatef (0,-1, 0); + + glColor3f(1, 0, 0); /* Red line is where text appears */ + glPushMatrix(); + glTranslatef(0, -0.028, 0); + glLineWidth (4); + glBegin(GL_LINES); + glVertex3f(-0.5, 1, 0); + glVertex3f( 0.5, 1, 0); + glVertex3f(-0.5, -1, 0); + glVertex3f( 0.5, -1, 0); + glEnd(); + glLineWidth (1); + glPopMatrix(); + + glColor3f (0.2, 0.2, 0.2); for (i = 0; i < 16; i++) { box (1, 1, 1); @@ -969,14 +938,79 @@ draw_sws (ModeInfo *mi) } if (textures_p) glEnable (GL_TEXTURE_2D); glPopMatrix (); + check_gl_error ("debug render"); } /* Scroll to current position */ glTranslatef (0.0, sc->intra_line_scroll, 0.0); glColor3f (1.0, 1.0, 0.4); - glCallList (sc->text_list); - mi->polygon_count = sc->polygon_count; + + mi->polygon_count = 0; + + glPushMatrix (); + glScalef (sc->font_scale, sc->font_scale, sc->font_scale); + for (i = 0; i < sc->total_lines; i++) + { + double fade = (fade_p ? 1.0 * i / sc->total_lines : 1.0); + int offscreen_lines = 2; + + double x = -0.5; + double y = ((sc->total_lines - (i + offscreen_lines) - 1) + * sc->line_height); + double xoff = 0; + char *line = sc->lines[i]; + + if (debug_p) + { + double xx = x * 1.4; /* a little more to the left */ + char n[20]; + sprintf(n, "%d:", i); + glColor3f (1.0, 1.0, 1.0); + draw_string (sc, xx / sc->font_scale, y / sc->font_scale, n); + } + + if (!line || !*line) + continue; + + if (sc->line_thickness != 1 && !textures_p) + { + int max_thick_lines = MAX_THICK_LINES; + GLfloat thinnest_line = 1.0; + GLfloat thickest_line = sc->line_thickness; + GLfloat range = thickest_line - thinnest_line; + GLfloat thickness; + + int j = sc->total_lines - i - 1; + + if (j > max_thick_lines) + thickness = thinnest_line; + else + thickness = (thinnest_line + + (range * ((max_thick_lines - j) / + (GLfloat) max_thick_lines))); + + glLineWidth (thickness); + } + + if (alignment >= 0) + { + int n = sc->line_widths[i]; + xoff = 1.0 - (n * sc->font_scale); + } + + if (alignment == 0) + xoff /= 2; + + glColor3f (fade, fade, 0.5 * fade); + draw_string (sc, (x + xoff) / sc->font_scale, y / sc->font_scale, + line); + if (textures_p) + mi->polygon_count += strlen (line); + } + glPopMatrix (); + + sc->intra_line_scroll += sc->line_height / scroll_steps; @@ -991,8 +1025,10 @@ draw_sws (ModeInfo *mi) /* Scroll the contents of the lines array toward 0. */ if (sc->total_lines > 0) { - for (i = 1; i < sc->total_lines; i++) + for (i = 1; i < sc->total_lines; i++) { sc->lines[i-1] = sc->lines[i]; + sc->line_widths[i-1] = sc->line_widths[i]; + } sc->lines[--sc->total_lines] = 0; } @@ -1004,72 +1040,6 @@ draw_sws (ModeInfo *mi) here so that new text still pulls in from the bottom of the screen, isntead of just appearing. */ sc->total_lines = max_lines; - - glDeleteLists (sc->text_list, 1); - sc->text_list = glGenLists (1); - glNewList (sc->text_list, GL_COMPILE); - sc->polygon_count = 0; - glPushMatrix (); - glScalef (sc->font_scale, sc->font_scale, sc->font_scale); - for (i = 0; i < sc->total_lines; i++) - { - double fade = (fade_p ? 1.0 * i / sc->total_lines : 1.0); - int offscreen_lines = 2; - - double x = -0.5; - double y = ((sc->total_lines - (i + offscreen_lines) - 1) - * sc->line_height); - double xoff = 0; - char *line = sc->lines[i]; - - if (debug_p) - { - double xx = x * 1.4; /* a little more to the left */ - char n[20]; - sprintf(n, "%d:", i); - draw_string (sc, xx / sc->font_scale, y / sc->font_scale, n); - } - - if (!line || !*line) - continue; - - if (sc->line_thickness != 1 && !textures_p) - { - int max_thick_lines = MAX_THICK_LINES; - GLfloat thinnest_line = 1.0; - GLfloat thickest_line = sc->line_thickness; - GLfloat range = thickest_line - thinnest_line; - GLfloat thickness; - - int j = sc->total_lines - i - 1; - - if (j > max_thick_lines) - thickness = thinnest_line; - else - thickness = (thinnest_line + - (range * ((max_thick_lines - j) / - (GLfloat) max_thick_lines))); - - glLineWidth (thickness); - } - - if (alignment >= 0) - { - int n = string_width (sc, line); - xoff = 1.0 - (n * sc->font_scale); - } - - if (alignment == 0) - xoff /= 2; - - glColor3f (fade, fade, 0.5 * fade); - draw_string (sc, (x + xoff) / sc->font_scale, y / sc->font_scale, - line); - if (textures_p) - sc->polygon_count += strlen (line); - } - glPopMatrix (); - glEndList (); } glPopMatrix (); @@ -1081,29 +1051,23 @@ draw_sws (ModeInfo *mi) sc->star_theta += star_spin; } -ENTRYPOINT void -release_sws (ModeInfo *mi) +static void +free_sws (ModeInfo *mi) { - if (scs) { - int screen; - for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { - sws_configuration *sc = &scs[screen]; - if (sc->pipe_id) - XtRemoveInput (sc->pipe_id); - if (sc->pipe) - pclose (sc->pipe); - if (sc->pipe_timer) - XtRemoveTimeOut (sc->pipe_timer); - - /* #### there's more to free here */ - } - free (scs); - scs = 0; - } - FreeAllGL(mi); + sws_configuration *sc = &scs[MI_SCREEN(mi)]; + if (sc->tc) + textclient_close (sc->tc); + + /* #### there's more to free here */ } +#ifdef __GNUC__ + __extension__ /* don't warn about "string length is greater than the length + ISO C89 compilers are required to support" when including + "starwars.txt" in the defaults... */ +#endif + XSCREENSAVER_MODULE_2 ("StarWars", starwars, sws) #endif /* USE_GL */