-/* starwars, Copyright (c) 1998-2008 Jamie Zawinski <jwz@jwz.org> and
+/* starwars, Copyright (c) 1998-2018 Jamie Zawinski <jwz@jwz.org> and
* Claudio Matsuoka <claudio@helllabs.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
*
* 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
# include <unistd.h>
#endif
-#ifdef HAVE_UNAME
-# include <sys/utsname.h>
-#endif /* HAVE_UNAME */
-
-#ifndef HAVE_COCOA
-# include <X11/Intrinsic.h>
-#endif
-
-
+#include "starwars.h"
#define DEFAULTS "*delay: 40000 \n" \
"*showFPS: False \n" \
"*fpsTop: True \n" \
- "*font: " DEF_FONT "\n"
-
-# define refresh_sws 0
-# define sws_handle_event 0
+ "*usePty: False \n" \
+ "*texFontCacheSize: 300\n" \
+ "*font: " DEF_FONT "\n" \
+ "*textLiteral: " DEF_TEXT "\n" \
+ "*program: xscreensaver-text --cols 0" /* don't wrap */
+
+# define release_sws 0
+# define sws_handle_event xlockmore_no_events
#undef countof
#define countof(x) (sizeof((x))/sizeof((*x)))
#include "xlockmore.h"
+#include "textclient.h"
+#include "utf8wc.h"
#ifdef USE_GL /* whole file */
# endif
-#define DEF_PROGRAM "xscreensaver-text --cols 0" /* don't wrap */
#define DEF_LINES "125"
#define DEF_STEPS "35"
#define DEF_SPIN "0.03"
#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"
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;
static sws_configuration *scs = NULL;
-static char *program;
static int max_lines;
static int scroll_steps;
static float star_spin;
static int alignment;
static XrmOptionDescRec opts[] = {
- {"-program", ".program", XrmoptionSepArg, 0 },
{"-lines", ".lines", XrmoptionSepArg, 0 },
{"-steps", ".steps", XrmoptionSepArg, 0 },
{"-spin", ".spin", XrmoptionSepArg, 0 },
};
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},
}
-/* 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++;
- }
-}
-
-\f
-/* 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;
+ strncpy (s2, s, size);
+ s2[size] = 0;
-/* 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;
+ result = sw_string_width (sc, s2);
- /* 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);
- }
- }
-}
-
-
-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;
- }
-
- 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++;
}
- 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);
}
}
int max_size = 3;
GLfloat inc = 0.5;
int steps = max_size / inc;
+ GLfloat scale = 1;
+
+ if (MI_WIDTH(mi) > 2560) { /* Retina displays */
+ scale *= 2;
+ nstars = (size/scale) * (size/scale) / 320;
+ }
glDeleteLists (sc->star_list, 1);
sc->star_list = glGenLists (1);
for (j = 1; j <= steps; j++)
{
- glPointSize(inc * j);
+ glPointSize(inc * j * scale);
glBegin (GL_POINTS);
for (i = 0; i < nstars / steps; i++)
{
int w = mi->xgwa.width;
int h = mi->xgwa.height;
int yoff = 0;
+ GLfloat rot = current_device_rotation();
#ifdef KEEP_ASPECT
{
}
#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
{
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);
{
sws_configuration *sc = &scs[MI_SCREEN(mi)];
- program = get_string_resource (mi->dpy, "program", "Program");
-
glDisable (GL_LIGHTING);
glDisable (GL_DEPTH_TEST);
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);
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);
reshape_sws (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+ clear_gl_error(); /* WTF? sometimes "invalid op" from glViewport! */
+
init_stars (mi, MI_WIDTH(mi), MI_HEIGHT(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);
{
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;
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)
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));
-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);
}
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));
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);
}
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;
/* 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;
}
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 ();
}
ENTRYPOINT void
-release_sws (ModeInfo *mi)
+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 */