From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / hacks / glx / starwars.c
index 0a7f4fd026dd770d93f5caf8cf7e14844404c177..1398c159c9bd28da58ef4664ae64c8e04059d69f 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * starwars, Copyright (c) 1998-2005 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
  *
  * For the fanboys:
  *
- *     starwars -program 'cat starwars.txt' -columns 25 -no-wrap -texture
+ *     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 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 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    "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"
@@ -63,43 +91,24 @@ extern XtAppContext app;
 
 #define MAX_THICK_LINES   25
 #define FONT_WEIGHT       14
-#define KEEP_ASPECT
-
-#define DEFAULTS "*delay:    40000     \n" \
-                "*showFPS:  False     \n" \
-                "*fpsTop:   True      \n" \
-                "*font:   " DEF_FONT "\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;
-
-  FILE *pipe;
-  XtInputId pipe_id;
-  Time subproc_relaunch_delay;
+  text_data *tc;
 
   char *buf;
   int buf_size;
@@ -143,7 +152,7 @@ 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 },*/
   {"-fade",        ".fade",      XrmoptionNoArg,  "True"   },
@@ -157,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" },
@@ -168,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},
@@ -179,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};
 
 
 
@@ -269,104 +279,9 @@ latin1_to_ascii (char *s)
     }
 }
 
-\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)
-{
-  char *oprogram = get_string_resource ("program", "Program");
-  char *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 < 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. */
-          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);
@@ -380,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)
@@ -397,6 +311,21 @@ 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;
@@ -515,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);
@@ -643,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)];
@@ -655,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
     {
@@ -674,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
@@ -697,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);
@@ -727,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);
@@ -752,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 *)
@@ -766,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));
   }
 
@@ -791,16 +737,21 @@ init_sws (ModeInfo *mi)
 
       check_gl_error ("loading font");
 
-# ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
       /* "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)
-        glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16);
-      clear_gl_error();
-# endif
+      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
     {
@@ -846,7 +797,6 @@ init_sws (ModeInfo *mi)
   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)
@@ -868,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));
@@ -894,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);
     }
@@ -903,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;
@@ -914,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));
 
@@ -927,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);
@@ -1029,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);
             }
 
@@ -1055,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 */