X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fglx%2Fstarwars.c;h=1398c159c9bd28da58ef4664ae64c8e04059d69f;hb=6afd6db0ae9396cd7ff897ade597cd5483f49b0e;hp=3277df5e08108e318c2ebe43c3acf3eeb1a47d73;hpb=2d04c4f22466851aedb6ed0f2919d148f726b889;p=xscreensaver diff --git a/hacks/glx/starwars.c b/hacks/glx/starwars.c index 3277df5e..1398c159 100644 --- a/hacks/glx/starwars.c +++ b/hacks/glx/starwars.c @@ -1,5 +1,4 @@ -/* - * starwars, Copyright (c) 1998-2005 Jamie Zawinski and +/* starwars, Copyright (c) 1998-2014 Jamie Zawinski and * Claudio Matsuoka * * Permission to use, copy, modify, distribute, and sell this software and its @@ -23,97 +22,98 @@ * * For the fanboys: * - * starwars -program 'cat starwars.txt' -columns 25 -no-wrap -texture + * starwars -program 'cat starwars.txt' -columns 25 -no-wrap */ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ -extern XtAppContext app; +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#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 */ +# 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 480 needs a 2048x2048 texture. - Utopia 400 needs a 1024x1024 texture. - Utopia 180 needs a 512x512 texture. - Times 240 needs a 512x512 texture. +/* 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-*-*-400-*-*-*-*-iso8859-1" +#define DEF_FONT "-*-utopia-bold-r-normal-*-*-720-*-*-*-*-iso8859-1" #define TAB_WIDTH 8 #define MAX_THICK_LINES 25 #define FONT_WEIGHT 14 -#define KEEP_ASPECT - -#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" \ - "*textures: " DEF_TEXTURES "\n" \ - "*fontSize: " DEF_FONT_SIZE "\n" \ - "*columns: " DEF_COLUMNS "\n" \ - "*lineWrap: " DEF_WRAP "\n" \ - "*alignment: " DEF_ALIGN "\n" \ - "*font: " DEF_FONT "\n" \ - "*debug: " DEF_DEBUG "\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 -#include -#include #include "texfont.h" #include "glutstroke.h" #include "glut_roman.h" #define GLUT_FONT (&glutStrokeRoman) -#ifdef HAVE_UNAME -# include -#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; @@ -152,9 +152,9 @@ static XrmOptionDescRec opts[] = { {"-lines", ".lines", XrmoptionSepArg, 0 }, {"-steps", ".steps", XrmoptionSepArg, 0 }, {"-spin", ".spin", XrmoptionSepArg, 0 }, - {"-size", ".fontSize", XrmoptionSepArg, 0 }, + {"-size", ".size", XrmoptionSepArg, 0 }, {"-columns", ".columns", XrmoptionSepArg, 0 }, - {"-font", ".font", XrmoptionSepArg, 0 }, +/*{"-font", ".font", XrmoptionSepArg, 0 },*/ {"-fade", ".fade", XrmoptionNoArg, "True" }, {"-no-fade", ".fade", XrmoptionNoArg, "False" }, {"-textures", ".textures", XrmoptionNoArg, "True" }, @@ -166,6 +166,7 @@ static XrmOptionDescRec opts[] = { {"-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" }, @@ -177,10 +178,10 @@ static argtype vars[] = { {&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_FONT_SIZE, t_Float}, + {&font_size, "size", "Float", DEF_SIZE, t_Float}, {&target_columns, "columns", "Integer", DEF_COLUMNS, t_Int}, - {&wrap_p, "lineWrap", "Boolean", DEF_WRAP, t_Bool}, - {&alignment_str, "alignment", "Alignment", DEF_ALIGN, t_String}, + {&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}, @@ -188,7 +189,7 @@ static argtype vars[] = { {&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}; @@ -278,151 +279,9 @@ latin1_to_ascii (char *s) } } - -/* 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) -{ - char *oprogram = get_string_resource ("program", "Program"); - char *program; - - if (!strcasecmp(oprogram, "(default)")) - { - 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); - } -} - - -static void -relaunch_generator_timer (XtPointer closure, XtIntervalId *id) -{ - sws_configuration *sc = (sws_configuration *) closure; - launch_text_generator (sc); -} - - -/* 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) -{ - 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); - } - } -} - static int -string_width (sws_configuration *sc, const char *s) +sw_string_width (sws_configuration *sc, const char *s) { if (textures_p) return texture_string_width (sc->texfont, s, 0); @@ -436,12 +295,11 @@ char_width (sws_configuration *sc, char c) char s[2]; s[0] = c; s[1] = 0; - return string_width (sc, s); + return sw_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) @@ -453,15 +311,28 @@ get_more_lines (sws_configuration *sc) 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); @@ -573,7 +444,7 @@ draw_string (sws_configuration *sc, GLfloat x, GLfloat y, const char *s) while (*s) { *c = *s++; - w = string_width (sc, c); + w = sw_string_width (sc, c); glBegin (GL_LINE_LOOP); glVertex3f (0, 0, 0); glVertex3f (w, 0, 0); @@ -647,7 +518,6 @@ box (double width, double height, double depth) 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); @@ -702,7 +572,7 @@ init_stars (ModeInfo *mi, int width, int height) /* Window management, etc */ -void +ENTRYPOINT void reshape_sws (ModeInfo *mi, int width, int height) { sws_configuration *sc = &scs[MI_SCREEN(mi)]; @@ -714,6 +584,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 { @@ -733,6 +604,19 @@ reshape_sws (ModeInfo *mi, int width, int height) 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 @@ -756,8 +640,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); @@ -786,7 +670,7 @@ gl_init (ModeInfo *mi) { 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); @@ -811,12 +695,12 @@ gl_init (ModeInfo *mi) } -void +ENTRYPOINT void init_sws (ModeInfo *mi) { double font_height; - sws_configuration *sc; + sws_configuration *sc = 0; if (!scs) { scs = (sws_configuration *) @@ -825,16 +709,19 @@ init_sws (ModeInfo *mi) 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)); } @@ -847,6 +734,24 @@ init_sws (ModeInfo *mi) 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 { @@ -883,7 +788,15 @@ init_sws (ModeInfo *mi) sc->line_height = font_height * sc->font_scale; - sc->subproc_relaunch_delay = 2 * 1000; + /* 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->total_lines = max_lines-1; if (random() & 1) @@ -905,7 +818,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)); @@ -931,6 +844,10 @@ 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); + + /* 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); } @@ -940,10 +857,11 @@ draw_stars (ModeInfo *mi) 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; @@ -951,9 +869,6 @@ draw_sws (ModeInfo *mi) if (!sc->glx_context) return; - if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput)) - XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput); - glDrawBuffer (GL_BACK); glXMakeCurrent (dpy, window, *(sc->glx_context)); @@ -964,14 +879,33 @@ draw_sws (ModeInfo *mi) glMatrixMode (GL_MODELVIEW); glPushMatrix (); +# 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); - 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.4, 0.4, 0.4); for (i = 0; i < 16; i++) { box (1, 1, 1); @@ -1025,7 +959,7 @@ draw_sws (ModeInfo *mi) for (i = 0; i < sc->total_lines; i++) { double fade = (fade_p ? 1.0 * i / sc->total_lines : 1.0); - int offscreen_lines = 3; + int offscreen_lines = 2; double x = -0.5; double y = ((sc->total_lines - (i + offscreen_lines) - 1) @@ -1066,7 +1000,7 @@ draw_sws (ModeInfo *mi) if (alignment >= 0) { - int n = string_width (sc, line); + int n = sw_string_width (sc, line); xoff = 1.0 - (n * sc->font_scale); } @@ -1092,4 +1026,31 @@ draw_sws (ModeInfo *mi) 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 */