-/*
- * starwars, Copyright (c) 1998-2001, 2004 Jamie Zawinski <jwz@jwz.org> and
+/* starwars, Copyright (c) 1998-2014 Jamie Zawinski <jwz@jwz.org> and
* Claudio Matsuoka <claudio@helllabs.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* implied warranty.
*
* Star Wars -- Phosphor meets a well-known scroller from a galaxy far,
- * far away. Hacked by Claudio Matsuoka. Includes portions of
- * mjk's GLUT library, Copyright (c) 1994, 1995, 1996 by Mark J.
- * Kilgard. Roman simplex stroke font Copyright (c) 1989, 1990,
- * 1991 by Sun Microsystems, Inc. and the X Consortium.
+ * far away.
*
- * Notes:
- * - I tried texturized fonts but the roman simplex stroke font
- * was the most readable for the 80-column text from fortune.
- * - The proportional font is bad for text from ps(1) or w(1).
- * - Apparently the RIVA TNT cards for PCs don't like the stars to
- * be drawn in orthogonal perspective, causing unnecessary system
- * load.
- *
- * History:
- * 20000221 claudio First version
- * 20010124 jwz Rewrote large sections to add the ability to
+ * Feb 2000 Claudio Matsuoka First version.
+ * Jan 2001 Jamie Zawinski Rewrote large sections to add the ability to
* run a subprocess, customization of the font
* size and other parameters, etc.
- * 20010224 jepler@mail.inetnebr.com made the lines be anti-aliased,
- * made the text fade to black at the end.
+ * Feb 2001 jepler@inetnebr.com Added anti-aliased lines, and fade-to-black.
+ * Feb 2005 Jamie Zawinski Added texture fonts.
+ *
+ *
+ * For the fanboys:
+ *
+ * starwars -program 'cat starwars.txt' -columns 25 -no-wrap
*/
-#include <X11/Intrinsic.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
-extern XtAppContext app;
+#include <ctype.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "starwars.h"
+#define DEFAULTS "*delay: 40000 \n" \
+ "*showFPS: False \n" \
+ "*fpsTop: True \n" \
+ "*usePty: False \n" \
+ "*font: " DEF_FONT "\n" \
+ "*textLiteral: " DEF_TEXT "\n"
-#define PROGCLASS "StarWars"
-#define HACK_INIT init_sws
-#define HACK_DRAW draw_sws
-#define HACK_RESHAPE reshape_sws
-#define sws_opts xlockmore_opts
-#define DEF_PROGRAM "(default)"
+# define refresh_sws 0
+# define sws_handle_event 0
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
+
+#include "xlockmore.h"
+#include "textclient.h"
+
+#ifdef USE_GL /* whole file */
+
+/* Should be in <GL/glext.h> */
+# ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
+# define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+# endif
+# ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
+# define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+# 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_FONT_SIZE "-1"
+#define DEF_SIZE "-1"
#define DEF_COLUMNS "-1"
-#define DEF_WRAP "True"
-#define DEF_ALIGN "Center"
+#define DEF_LINE_WRAP "True"
+#define DEF_ALIGNMENT "Center"
#define DEF_SMOOTH "True"
#define DEF_THICK "True"
#define DEF_FADE "True"
+#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 TAB_WIDTH 8
-#define BASE_FONT_SIZE 18 /* magic */
-#define BASE_FONT_COLUMNS 80 /* magic */
-
#define MAX_THICK_LINES 25
#define FONT_WEIGHT 14
-#define KEEP_ASPECT
-#undef DEBUG
-
-#define DEFAULTS "*delay: 40000 \n" \
- "*showFPS: False \n" \
- "*fpsTop: True \n" \
- "*program: " DEF_PROGRAM "\n" \
- "*lines: " DEF_LINES "\n" \
- "*spin: " DEF_SPIN "\n" \
- "*steps: " DEF_STEPS "\n" \
- "*smooth: " DEF_SMOOTH "\n" \
- "*thick: " DEF_THICK "\n" \
- "*fade: " DEF_FADE "\n" \
- "*starwars.fontSize: " DEF_FONT_SIZE "\n" \
- "*starwars.columns: " DEF_COLUMNS "\n" \
- "*starwars.lineWrap: " DEF_WRAP "\n" \
- "*starwars.alignment:" DEF_ALIGN "\n"
-#undef countof
-#define countof(x) (sizeof((x))/sizeof((*x)))
-
-#include "xlockmore.h"
-
-#ifdef USE_GL /* whole file */
+#ifndef USE_IPHONE
+# define KEEP_ASPECT /* Letterboxing looks dumb on iPhone. */
+#endif
-#include <ctype.h>
-#include <GL/glu.h>
-#include <sys/stat.h>
+#include "texfont.h"
#include "glutstroke.h"
#include "glut_roman.h"
#define GLUT_FONT (&glutStrokeRoman)
-#ifdef HAVE_UNAME
-# include <sys/utsname.h>
-#endif /* HAVE_UNAME */
-
-
typedef struct {
+ Display *dpy;
GLXContext *glx_context;
GLuint text_list, star_list;
+ texture_font_data *texfont;
+ int polygon_count;
+ text_data *tc;
- FILE *pipe;
- XtInputId pipe_id;
- Time subproc_relaunch_delay;
-
- char buf [1024];
+ char *buf;
+ int buf_size;
int buf_tail;
+
char **lines;
int total_lines;
- int columns;
double star_theta;
+ double char_width;
double line_height;
double font_scale;
double intra_line_scroll;
- int line_pixel_height;
+ int line_pixel_width; /* in font units (for wrapping text) */
+ int line_pixel_height; /* in screen units (for computing line thickness) */
GLfloat line_thickness;
} sws_configuration;
static int smooth_p;
static int thick_p;
static int fade_p;
+static int textures_p;
+static int debug_p;
static char *alignment_str;
static int alignment;
static XrmOptionDescRec opts[] = {
- {"-program", ".starwars.program", XrmoptionSepArg, (caddr_t) 0 },
- {"-lines", ".starwars.lines", XrmoptionSepArg, (caddr_t) 0 },
- {"-steps", ".starwars.steps", XrmoptionSepArg, (caddr_t) 0 },
- {"-spin", ".starwars.spin", XrmoptionSepArg, (caddr_t) 0 },
- {"-size", ".starwars.fontSize", XrmoptionSepArg, (caddr_t) 0 },
- {"-columns", ".starwars.columns", XrmoptionSepArg, (caddr_t) 0 },
- {"-smooth", ".starwars.smooth", XrmoptionNoArg, (caddr_t) "True" },
- {"-no-smooth", ".starwars.smooth", XrmoptionNoArg, (caddr_t) "False" },
- {"-thick", ".starwars.thick", XrmoptionNoArg, (caddr_t) "True" },
- {"-no-thick", ".starwars.thick", XrmoptionNoArg, (caddr_t) "False" },
- {"-fade", ".starwars.fade", XrmoptionNoArg, (caddr_t) "True" },
- {"-no-fade", ".starwars.fade", XrmoptionNoArg, (caddr_t) "False" },
- {"-wrap", ".starwars.lineWrap", XrmoptionNoArg, (caddr_t) "True" },
- {"-no-wrap", ".starwars.lineWrap", XrmoptionNoArg, (caddr_t) "False" },
- {"-nowrap", ".starwars.lineWrap", XrmoptionNoArg, (caddr_t) "False" },
- {"-left", ".starwars.alignment",XrmoptionNoArg, (caddr_t) "Left" },
- {"-right", ".starwars.alignment",XrmoptionNoArg, (caddr_t) "Right" },
- {"-center", ".starwars.alignment",XrmoptionNoArg, (caddr_t) "Center" },
+ {"-program", ".program", XrmoptionSepArg, 0 },
+ {"-lines", ".lines", XrmoptionSepArg, 0 },
+ {"-steps", ".steps", XrmoptionSepArg, 0 },
+ {"-spin", ".spin", XrmoptionSepArg, 0 },
+ {"-size", ".size", XrmoptionSepArg, 0 },
+ {"-columns", ".columns", XrmoptionSepArg, 0 },
+/*{"-font", ".font", XrmoptionSepArg, 0 },*/
+ {"-fade", ".fade", XrmoptionNoArg, "True" },
+ {"-no-fade", ".fade", XrmoptionNoArg, "False" },
+ {"-textures", ".textures", XrmoptionNoArg, "True" },
+ {"-smooth", ".smooth", XrmoptionNoArg, "True" },
+ {"-no-smooth", ".smooth", XrmoptionNoArg, "False" },
+ {"-thick", ".thick", XrmoptionNoArg, "True" },
+ {"-no-thick", ".thick", XrmoptionNoArg, "False" },
+ {"-no-textures", ".textures", XrmoptionNoArg, "False" },
+ {"-wrap", ".lineWrap", XrmoptionNoArg, "True" },
+ {"-no-wrap", ".lineWrap", XrmoptionNoArg, "False" },
+ {"-nowrap", ".lineWrap", XrmoptionNoArg, "False" },
+ {"-alignment", ".alignment", XrmoptionSepArg, 0 },
+ {"-left", ".alignment", XrmoptionNoArg, "Left" },
+ {"-right", ".alignment", XrmoptionNoArg, "Right" },
+ {"-center", ".alignment", XrmoptionNoArg, "Center" },
+ {"-debug", ".debug", XrmoptionNoArg, "True" },
};
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},
- {&font_size, "fontSize", "Float", DEF_STEPS, t_Float},
- {&target_columns, "columns", "Integer", DEF_COLUMNS, t_Int},
- {&wrap_p, "lineWrap", "Boolean", DEF_COLUMNS, t_Bool},
- {&alignment_str, "alignment", "Alignment", DEF_ALIGN, t_String},
- {&smooth_p, "smooth", "Boolean", DEF_SMOOTH, t_Bool},
- {&thick_p, "thick", "Boolean", DEF_THICK, t_Bool},
- {&fade_p, "fade", "Boolean", DEF_FADE, t_Bool},
+ {&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},
+ {&font_size, "size", "Float", DEF_SIZE, t_Float},
+ {&target_columns, "columns", "Integer", DEF_COLUMNS, t_Int},
+ {&wrap_p, "lineWrap", "Boolean", DEF_LINE_WRAP, t_Bool},
+ {&alignment_str, "alignment", "Alignment", DEF_ALIGNMENT, t_String},
+ {&smooth_p, "smooth", "Boolean", DEF_SMOOTH, t_Bool},
+ {&thick_p, "thick", "Boolean", DEF_THICK, t_Bool},
+ {&fade_p, "fade", "Boolean", DEF_FADE, t_Bool},
+ {&textures_p, "textures", "Boolean", DEF_TEXTURES, t_Bool},
+ {&debug_p, "debug", "Boolean", DEF_DEBUG, t_Bool},
};
-ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
+ENTRYPOINT ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
}
-\f
-/* Subprocess.
- (This bit mostly cribbed from phosphor.c)
+/* 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 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)
+latin1_to_ascii (char *s)
{
- char *oprogram = get_string_resource ("program", "Program");
- char *program;
-
- if (!strcasecmp(oprogram, "(default)"))
+ 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)
{
- oprogram = FORTUNE_PROGRAM;
-
-#if defined(__linux__) && defined(HAVE_UNAME)
- {
- static int done_once = 0;
- if (!done_once)
- {
- struct utsname uts;
- struct stat st;
- done_once = 1;
- if (uname (&uts) == 0)
- {
- static char cmd[200];
- char *s;
- /* strip version at the first non-digit-dash-dot, to
- lose any "SMP" crap at the end. */
- for (s = uts.release; *s; s++)
- if (!isdigit(*s) && *s != '.' && *s != '-')
- *s = 0;
- sprintf (cmd, "cat /usr/src/linux-%s/README", uts.release);
- if (!stat (cmd+4, &st))
- oprogram = cmd;
- else
- {
- /* kernel source not installed? try X... */
- strcpy (cmd, "cat /usr/X11R6/lib/X11/doc/README");
- if (!stat (cmd+4, &st))
- oprogram = cmd;
- }
- }
- }
- }
-#endif /* __linux__ && HAVE_UNAME */
-
-#ifdef __APPLE__ /* MacOS X + XDarwin */
- {
- static int done_once = 0;
- if (!done_once)
- {
- struct stat st;
- static char *cmd = "cat /usr/X11R6/README";
- if (!stat (cmd+4, &st))
- oprogram = cmd;
- }
- }
-#endif /* __APPLE__ */
- }
-
- program = (char *) malloc (strlen (oprogram) + 10);
- strcpy (program, "( ");
- strcat (program, oprogram);
- strcat (program, " ) 2>&1");
-
- if ((sc->pipe = popen (program, "r")))
- {
- sc->pipe_id =
- XtAppAddInput (app, fileno (sc->pipe),
- (XtPointer) (XtInputReadMask | XtInputExceptMask),
- subproc_cb, (XtPointer) sc);
- }
- else
- {
- perror (program);
+ if (*us >= 161)
+ *us = ascii[*us - 161];
+ else if (*us > 127)
+ *us = '?';
+ us++;
}
}
-static void
-relaunch_generator_timer (XtPointer closure, XtIntervalId *id)
+static int
+string_width (sws_configuration *sc, const char *s)
{
- sws_configuration *sc = (sws_configuration *) closure;
- launch_text_generator (sc);
+ if (textures_p)
+ return texture_string_width (sc->texfont, s, 0);
+ else
+ return glutStrokeLength (GLUT_FONT, (unsigned char *) s);
}
-
-/* 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)
+static int
+char_width (sws_configuration *sc, char c)
{
- if (sc->buf_tail < sizeof(sc->buf) - 2)
- {
- int target = sizeof(sc->buf) - sc->buf_tail - 2;
- int n = read (fileno (sc->pipe),
- (void *) (sc->buf + sc->buf_tail),
- target);
- if (n > 0)
- {
- sc->buf_tail += n;
- sc->buf[sc->buf_tail] = 0;
- }
- else
- {
- 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. */
- XtAppAddTimeOut (app, sc->subproc_relaunch_delay,
- relaunch_generator_timer,
- (XtPointer) sc);
- }
- }
+ char s[2];
+ s[0] = c;
+ s[1] = 0;
+ return string_width (sc, s);
}
-/* 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;
+
+ int target = sc->buf_size - sc->buf_tail - 2;
+
+ /* Fill as much as we can into sc->buf.
+ */
+ while (target > 0)
+ {
+ int c = textclient_getc (sc->tc);
+ if (c <= 0)
+ break;
+ sc->buf[sc->buf_tail++] = (char) c;
+ sc->buf[sc->buf_tail] = 0;
+ target--;
+ }
+
while (sc->total_lines < max_lines)
{
+ int cw;
+
if (s >= sc->buf + sc->buf_tail)
- {
- /* Reached end of buffer before end of line. Bail. */
- return;
- }
+ /* Reached end of buffer before end of line. Bail. */
+ return;
+
+ cw = char_width (sc, *s);
- if (*s == '\r' || *s == '\n' || col > sc->columns)
+ if (*s == '\r' || *s == '\n' ||
+ col_pix + cw >= wrap_pix)
{
int L = s - sc->buf;
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]);
+
{
char *t = sc->lines[sc->total_lines];
char *ut = untabify (t);
sc->buf[sc->buf_tail] = 0;
s = sc->buf;
col = 0;
+ col_pix = 0;
}
else
{
col++;
+ col_pix += cw;
if (*s == '\t')
- col = TAB_WIDTH * ((col / TAB_WIDTH) + 1);
+ {
+ int tab_pix = TAB_WIDTH * sc->char_width;
+ col = TAB_WIDTH * ((col / TAB_WIDTH) + 1);
+ col_pix = tab_pix * ((col / tab_pix) + 1);
+ }
s++;
}
}
static void
-draw_string (int x, int y, const char *s)
+draw_string (sws_configuration *sc, GLfloat x, GLfloat y, const char *s)
{
+ const char *os = s;
if (!s || !*s) return;
glPushMatrix ();
glTranslatef (x, y, 0);
- while (*s)
- glutStrokeCharacter (GLUT_FONT, *s++);
+ if (textures_p)
+ print_texture_string (sc->texfont, s);
+ else
+ while (*s)
+ glutStrokeCharacter (GLUT_FONT, *s++);
glPopMatrix ();
+
+ if (debug_p)
+ {
+ GLfloat w;
+ GLfloat h = sc->line_height / sc->font_scale;
+ char c[2];
+ c[1]=0;
+ s = os;
+ if (textures_p) glDisable (GL_TEXTURE_2D);
+ glLineWidth (1);
+ glColor3f (0.4, 0.4, 0.4);
+ glPushMatrix ();
+ glTranslatef (x, y, 0);
+ while (*s)
+ {
+ *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);
+ }
+ glPopMatrix ();
+ if (textures_p) glEnable (GL_TEXTURE_2D);
+ }
}
-#ifdef DEBUG
static void
-grid (double width, double height, double spacing, double z)
+grid (double width, double height, double xspacing, double yspacing, double z)
{
double x, y;
- for (y = 0; y <= height/2; y += spacing)
+ for (y = 0; y <= height/2; y += yspacing)
{
glBegin(GL_LINES);
glVertex3f(-width/2, y, z);
glVertex3f( width/2, -y, z);
glEnd();
}
- for (x = 0; x <= width/2; x += spacing)
+ for (x = 0; x <= width/2; x += xspacing)
{
glBegin(GL_LINES);
glVertex3f( x, -height/2, z);
glVertex3f( width/2, height/2, -depth/2);
glEnd();
- glEnd();
glBegin(GL_LINES);
glVertex3f(-width/2, height/2, depth/2);
glVertex3f(-width/2, -height/2, -depth/2);
glVertex3f( width/2, height/2, -depth/2);
glEnd();
}
-#endif /* DEBUG */
/* Construct stars (number of stars is dependent on size of screen) */
{
sws_configuration *sc = &scs[MI_SCREEN(mi)];
int i, j;
- int nstars = width * height / 320;
+ int size = (width > height ? width : height);
+ int nstars = size * size / 320;
int max_size = 3;
GLfloat inc = 0.5;
int steps = max_size / inc;
glColor3f (0.6 + frand(0.3),
0.6 + frand(0.3),
0.6 + frand(0.3));
- glVertex2f (2 * width * (0.5 - frand(1.0)),
- 2 * height * (0.5 - frand(1.0)));
+ glVertex2f (2 * size * (0.5 - frand(1.0)),
+ 2 * size * (0.5 - frand(1.0)));
}
glEnd ();
}
/* Window management, etc
*/
-void
+ENTRYPOINT void
reshape_sws (ModeInfo *mi, int width, int height)
{
sws_configuration *sc = &scs[MI_SCREEN(mi)];
GLfloat desired_aspect = (GLfloat) 3/4;
int w = mi->xgwa.width;
int h = mi->xgwa.height;
+ int yoff = 0;
+ GLfloat rot = current_device_rotation();
#ifdef KEEP_ASPECT
- h = w * desired_aspect;
+ {
+ int h2 = w * desired_aspect;
+ yoff = (h - h2) / 2; /* Wide window: letterbox at top and bottom. */
+ if (yoff < 0) yoff = 0; /* Tall window: clip off the top. */
+ h = h2;
+ }
#endif
glMatrixMode (GL_PROJECTION);
- glViewport (0, 0, w, h);
+ glViewport (0, yoff, w, h);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
- gluPerspective (80.0, 1/desired_aspect, 10, 500000);
+ 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);
+
+ glRotatef(rot, 0, 0, 1);
+
+ /* 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
+ glRotatef (60.0, 1.0, 0.0, 0.0);
+ glTranslatef (260, 3200, 0);
+ glScalef (1.85, 1.85, 1);
+#endif
+
/* The above gives us an arena where the bottom edge of the screen is
represented by the line (-2100,-3140,0) - ( 2100,-3140,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 ("program", "Program");
+ program = get_string_resource (mi->dpy, "program", "Program");
glDisable (GL_LIGHTING);
glDisable (GL_DEPTH_TEST);
- if (smooth_p)
+ if (smooth_p)
{
glEnable (GL_LINE_SMOOTH);
glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
}
-void
+ENTRYPOINT void
init_sws (ModeInfo *mi)
{
double font_height;
- sws_configuration *sc;
+ sws_configuration *sc = 0;
if (!scs) {
scs = (sws_configuration *)
fprintf(stderr, "%s: out of memory\n", progname);
exit(1);
}
-
- sc = &scs[MI_SCREEN(mi)];
- sc->lines = (char **) calloc (max_lines+1, sizeof(char *));
}
sc = &scs[MI_SCREEN(mi)];
+ sc->dpy = MI_DISPLAY(mi);
+ sc = &scs[MI_SCREEN(mi)];
+ sc->lines = (char **) calloc (max_lines+1, sizeof(char *));
+
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));
}
-
- font_height = GLUT_FONT->top - GLUT_FONT->bottom;
- sc->font_scale = 1.0 / glutStrokeWidth (GLUT_FONT, 'z'); /* 'n' seems
- too wide */
- if (target_columns > 0)
+ if (textures_p)
{
- sc->columns = target_columns;
+ int cw, lh;
+ sc->texfont = load_texture_font (MI_DISPLAY(mi), "font");
+ cw = texture_string_width (sc->texfont, "n", &lh);
+ sc->char_width = cw;
+ font_height = lh;
+ glEnable(GL_ALPHA_TEST);
+ glEnable (GL_TEXTURE_2D);
+
+ check_gl_error ("loading font");
+
+ /* "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 (smooth_p &&
+ 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);
+ }
}
else
{
- if (font_size <= 0)
- font_size = BASE_FONT_SIZE;
- sc->columns = BASE_FONT_COLUMNS * ((double) BASE_FONT_SIZE / font_size);
+ font_height = GLUT_FONT->top - GLUT_FONT->bottom;
+ sc->char_width = glutStrokeWidth (GLUT_FONT, 'z'); /* 'n' seems wide */
}
+
+ sc->font_scale = 1.0 / sc->char_width;
+
+
+ /* We consider a font that consumes 80 columns to be "18 points".
+
+ If neither -size nor -columns was specified, default to 60 columns
+ (which is 24 points.)
+
+ If both were specified, -columns has priority.
+ */
+ {
+ int base_col = 80;
+ int base_size = 18;
+
+ if (target_columns <= 0 && font_size <= 0)
+ target_columns = 60;
+
+ if (target_columns > 0)
+ font_size = base_size * (base_col / (double) target_columns);
+ else if (font_size > 0)
+ target_columns = base_col * (base_size / (double) font_size);
+ }
- sc->font_scale /= sc->columns;
+ sc->line_pixel_width = target_columns * sc->char_width;
+
+ sc->font_scale /= target_columns;
sc->line_height = font_height * sc->font_scale;
- if (!wrap_p) sc->columns = 1000; /* wrap anyway, if it's absurdly long. */
+ /* Buffer only two 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.)
+ */
+ sc->buf_size = target_columns * 2;
+ if (sc->buf_size < 80) sc->buf_size = 80;
+ sc->buf = (char *) calloc (1, sc->buf_size);
- sc->subproc_relaunch_delay = 2 * 1000;
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));
-0.5 * MI_HEIGHT(mi), 0.5 * MI_HEIGHT(mi),
-100.0, 100.0);
glRotatef (sc->star_theta, 0.0, 0.0, 1.0);
+ if (textures_p) glDisable (GL_TEXTURE_2D);
+
+ /* Keep the stars pointing in the same direction after rotation */
+ glRotatef(current_device_rotation(), 0, 0, 1);
+
glCallList (sc->star_list);
+ if (textures_p) glEnable (GL_TEXTURE_2D);
}
glPopMatrix ();
}
glPopMatrix ();
}
-void
+ENTRYPOINT void
draw_sws (ModeInfo *mi)
{
sws_configuration *sc = &scs[MI_SCREEN(mi)];
+/* XtAppContext app = XtDisplayToApplicationContext (sc->dpy);*/
Display *dpy = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
int i;
if (!sc->glx_context)
return;
- if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
- XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
-
glDrawBuffer (GL_BACK);
glXMakeCurrent (dpy, window, *(sc->glx_context));
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
-#ifdef DEBUG
- glColor3f (0.4, 0.4, 0.4);
- glLineWidth (1);
- glTranslatef(0, 1, 0);
- box (1, 1, 1);
- glTranslatef(0, -1, 0);
- box (1, 1, 1);
- grid (1, 1, sc->line_height, 0);
-#endif /* DEBUG */
+# ifdef USE_IPHONE
+ /* 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);
+ 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.4, 0.4, 0.4);
+ for (i = 0; i < 16; i++)
+ {
+ box (1, 1, 1);
+ grid (1, 1, sc->char_width * sc->font_scale, sc->line_height, 0);
+ glTranslatef(0, 1, 0);
+ }
+ if (textures_p) glEnable (GL_TEXTURE_2D);
+ glPopMatrix ();
+ }
/* 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;
sc->intra_line_scroll += sc->line_height / scroll_steps;
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++)
{
- int offscreen_lines = 3;
+ 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];
-#ifdef DEBUG
- char n[20];
- sprintf(n, "%d:", i);
- draw_string (x / sc->font_scale, y / sc->font_scale, n);
-#endif /* DEBUG */
+
+ 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)
+ if (sc->line_thickness != 1 && !textures_p)
{
int max_thick_lines = MAX_THICK_LINES;
GLfloat thinnest_line = 1.0;
}
if (alignment >= 0)
- xoff = 1.0 - (glutStrokeLength(GLUT_FONT,
- (unsigned char *) line)
- * sc->font_scale);
- if (alignment == 0)
- xoff /= 2;
-
- if (fade_p)
{
- double factor = 1.0 * i / sc->total_lines;
- glColor3f (factor, factor, 0.5 * factor);
+ int n = string_width (sc, line);
+ xoff = 1.0 - (n * sc->font_scale);
}
- draw_string ((x + xoff) / sc->font_scale, y / sc->font_scale, line);
+ 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 ();
sc->star_theta += star_spin;
}
+ENTRYPOINT void
+release_sws (ModeInfo *mi)
+{
+ if (scs) {
+ int screen;
+ for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
+ sws_configuration *sc = &scs[screen];
+ if (sc->tc)
+ textclient_close (sc->tc);
+
+ /* #### there's more to free here */
+ }
+ free (scs);
+ scs = 0;
+ }
+ FreeAllGL(mi);
+}
+
+
+#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 */