From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / hacks / glx / glplanet.c
index e81199956d56fe22f00d4b17329297fd1ea059e0..1c20b2b996d0dc48f2f63d6368e08a113863a535 100644 (file)
 
 
 #ifdef STANDALONE
-# define PROGCLASS                                             "Planet"
-# define HACK_INIT                                             init_planet
-# define HACK_DRAW                                             draw_planet
-# define HACK_RESHAPE                                  reshape_planet
-# define HACK_HANDLE_EVENT                             planet_handle_event
-# define EVENT_MASK                                            PointerMotionMask
-# define planet_opts                                   xlockmore_opts
 #define DEFAULTS       "*delay:                        20000   \n"     \
                                        "*showFPS:                      False   \n" \
-                    "*rotate:           True    \n" \
-                    "*roll:             True    \n" \
-                    "*wander:           True    \n" \
                                        "*wireframe:            False   \n"     \
-                                       "*light:                        True    \n"     \
-                                       "*texture:                      True    \n" \
-                                       "*stars:                        True    \n" \
-                                       "*image:                        BUILTIN \n" \
                                        "*imageForeground:      Green   \n" \
                                        "*imageBackground:      Blue    \n"
-
+# define refresh_planet 0
 # include "xlockmore.h"                                /* from the xscreensaver distribution */
 #else  /* !STANDALONE */
 # include "xlock.h"                                    /* from the xlockmore distribution */
 # endif /* VMS */
 #endif
 
-
-#include <GL/glu.h>
-
 #define DEF_ROTATE  "True"
 #define DEF_ROLL    "True"
 #define DEF_WANDER  "True"
+#define DEF_SPIN    "0.03"
 #define DEF_TEXTURE "True"
 #define DEF_STARS   "True"
 #define DEF_LIGHT   "True"
@@ -96,6 +80,7 @@ static int do_stars;
 static int do_light;
 static char *which_image;
 static int resolution;
+static float star_spin;
 
 static XrmOptionDescRec opts[] = {
   {"-rotate",  ".glplanet.rotate",  XrmoptionNoArg, "true" },
@@ -108,6 +93,7 @@ static XrmOptionDescRec opts[] = {
   {"+texture", ".glplanet.texture", XrmoptionNoArg, "false" },
   {"-stars",   ".glplanet.stars",   XrmoptionNoArg, "true" },
   {"+stars",   ".glplanet.stars",   XrmoptionNoArg, "false" },
+  {"-spin",    ".glplanet.spin",    XrmoptionSepArg, 0 },
   {"-light",   ".glplanet.light",   XrmoptionNoArg, "true" },
   {"+light",   ".glplanet.light",   XrmoptionNoArg, "false" },
   {"-image",   ".glplanet.image",  XrmoptionSepArg, 0 },
@@ -123,9 +109,10 @@ static argtype vars[] = {
   {&do_light,    "light",   "Light",   DEF_LIGHT,   t_Bool},
   {&which_image, "image",   "Image",   DEF_IMAGE,   t_String},
   {&resolution,  "resolution","Resolution", DEF_RESOLUTION, t_Int},
+  {&star_spin,   "spin",    "Float",   DEF_SPIN,    t_Float},
 };
 
-ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
+ENTRYPOINT ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
 
 #ifdef USE_MODULES
 ModStruct   planet_description =
@@ -176,6 +163,7 @@ typedef struct {
   double z;
   rotator *rot;
   trackball_state *trackball;
+  double star_theta;
   Bool button_down_p;
 } planetstruct;
 
@@ -183,25 +171,6 @@ typedef struct {
 static planetstruct *planets = NULL;
 
 
-static inline void
-normalize(GLfloat v[3])
-{
-  GLfloat d = (GLfloat) sqrt((double) (v[0] * v[0] +
-                                       v[1] * v[1] +
-                                       v[2] * v[2]));
-  if (d != 0)
-    {
-      v[0] /= d;
-      v[1] /= d;
-      v[2] /= d;
-       }
-  else
-    {
-      v[0] = v[1] = v[2] = 0;
-       }
-}
-
-
 /* Set up and enable texturing on our object */
 static void
 setup_xpm_texture (ModeInfo *mi, char **xpm_data)
@@ -285,109 +254,74 @@ setup_texture(ModeInfo * mi)
 }
 
 
-void
+static void
 init_stars (ModeInfo *mi)
 {
+  planetstruct *gp = &planets[MI_SCREEN(mi)];
   int i, j;
-  GLfloat max_size = 3;
-  GLfloat inc = 0.5;
-  int steps = max_size / inc;
   int width  = MI_WIDTH(mi);
   int height = MI_HEIGHT(mi);
-
-  planetstruct *gp = &planets[MI_SCREEN(mi)];
-  Bool wire = MI_IS_WIREFRAME(mi);
-  
-  if (!wire)
-    glEnable (GL_POINT_SMOOTH);
+  int size = (width > height ? width : height);
+  int nstars = size * size / 320;
+  int max_size = 3;
+  GLfloat inc = 0.5;
+  int steps = max_size / inc;
 
   gp->starlist = glGenLists(1);
   glNewList(gp->starlist, GL_COMPILE);
 
-  glScalef (1.0/width, 1.0/height, 1);
+  glEnable(GL_POINT_SMOOTH);
 
   for (j = 1; j <= steps; j++)
     {
       glPointSize(inc * j);
-      glBegin(GL_POINTS);
-      for (i = 0 ; i < NUM_STARS / steps; i++)
+      glBegin (GL_POINTS);
+      for (i = 0; i < nstars / steps; i++)
         {
           glColor3f (0.6 + frand(0.3),
                      0.6 + frand(0.3),
                      0.6 + frand(0.3));
-          glVertex2f ((GLfloat) (random() % width),
-                      (GLfloat) (random() % height));
+          glVertex2f (2 * size * (0.5 - frand(1.0)),
+                      2 * size * (0.5 - frand(1.0)));
         }
-      glEnd();
+      glEnd ();
     }
-  glEndList();
+  glEndList ();
 
   check_gl_error("stars initialization");
 }
 
 
-void
-draw_stars (ModeInfo * mi)
+static void
+draw_stars (ModeInfo *mi)
 {
-  int width  = MI_WIDTH(mi);
-  int height = MI_HEIGHT(mi);
-
   planetstruct *gp = &planets[MI_SCREEN(mi)];
   
-  /* Sadly, this causes a stall of the graphics pipeline (as would the
-     equivalent calls to glGet*.)  But there's no way around this, short
-     of having each caller set up the specific display matrix we need
-     here, which would kind of defeat the purpose of centralizing this
-     code in one file.
-   */
-  glPushAttrib(GL_TRANSFORM_BIT |  /* for matrix contents */
-               GL_ENABLE_BIT |     /* for various glDisable calls */
-               GL_CURRENT_BIT |    /* for glColor3f() */
-               GL_LIST_BIT);       /* for glListBase() */
-  {
-    check_gl_error ("glPushAttrib");
-
-    /* disable lighting and texturing when drawing stars!
-       (glPopAttrib() restores these.)
-     */
-    glDisable(GL_TEXTURE_2D);
-    glDisable(GL_LIGHTING);
-    glDisable(GL_DEPTH_TEST);
-
-    /* glPopAttrib() does not restore matrix changes, so we must
-       push/pop the matrix stacks to be non-intrusive there.
-     */
-    glMatrixMode(GL_PROJECTION);
-    glPushMatrix();
-    {
-      check_gl_error ("glPushMatrix");
-      glLoadIdentity();
-
-      /* Each matrix mode has its own stack, so we need to push/pop
-         them separately. */
-      glMatrixMode(GL_MODELVIEW);
-      glPushMatrix();
-      {
-        check_gl_error ("glPushMatrix");
-        glLoadIdentity();
+  glDisable(GL_TEXTURE_2D);
+  glDisable(GL_LIGHTING);
+  glDisable(GL_DEPTH_TEST);
 
-        gluOrtho2D (0, width, 0, height);
-        check_gl_error ("gluOrtho2D");
+  glMatrixMode (GL_PROJECTION);
+  glPushMatrix ();
+  {
+    glLoadIdentity ();
 
-        /* Draw the stars */
-        glScalef (width, height, 1);
-        glCallList(gp->starlist);
-        check_gl_error ("drawing stars");
-      }
-      glPopMatrix();
+    glMatrixMode (GL_MODELVIEW);
+    glPushMatrix ();
+    {
+      glLoadIdentity ();
+      glOrtho (-0.5 * MI_WIDTH(mi),  0.5 * MI_WIDTH(mi),
+               -0.5 * MI_HEIGHT(mi), 0.5 * MI_HEIGHT(mi),
+               -100.0, 100.0);
+      glRotatef (gp->star_theta, 0.0, 0.0, 1.0);
+      glCallList (gp->starlist);
     }
-    glMatrixMode(GL_PROJECTION);
-    glPopMatrix();
-
+    glPopMatrix ();
   }
-  /* clean up after our state changes */
-  glPopAttrib();
-  check_gl_error ("glPopAttrib");
+  glMatrixMode (GL_PROJECTION);
+  glPopMatrix ();
+
+  glMatrixMode (GL_MODELVIEW);
 }
 
 
@@ -428,14 +362,15 @@ init_sun (ModeInfo * mi)
   glLightfv (GL_LIGHT0, GL_DIFFUSE,  ldif);
   glLightfv (GL_LIGHT0, GL_SPECULAR, spec);
 
+  check_gl_error("sun");
   glMaterialfv (GL_FRONT, GL_AMBIENT,  mamb);
   glMaterialfv (GL_FRONT, GL_DIFFUSE,  mdif);
   glMaterialfv (GL_FRONT, GL_SPECULAR, mpec);
   glMaterialf  (GL_FRONT, GL_SHININESS, shiny);
 
 
-  glEnable(GL_BLEND);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+/*  glEnable(GL_BLEND);*/
+/*  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);*/
   glShadeModel(GL_SMOOTH);
 
   check_gl_error("lighting");
@@ -444,7 +379,7 @@ init_sun (ModeInfo * mi)
 
 #define RANDSIGN() ((random() & 1) ? 1 : -1)
 
-void
+ENTRYPOINT void
 reshape_planet (ModeInfo *mi, int width, int height)
 {
   GLfloat h = (GLfloat) height / (GLfloat) width;
@@ -461,40 +396,21 @@ reshape_planet (ModeInfo *mi, int width, int height)
 }
 
 
-Bool
+ENTRYPOINT Bool
 planet_handle_event (ModeInfo *mi, XEvent *event)
 {
   planetstruct *gp = &planets[MI_SCREEN(mi)];
 
-  if (event->xany.type == ButtonPress &&
-      event->xbutton.button & Button1)
-    {
-      gp->button_down_p = True;
-      gltrackball_start (gp->trackball,
-                         event->xbutton.x, event->xbutton.y,
-                         MI_WIDTH (mi), MI_HEIGHT (mi));
-      return True;
-    }
-  else if (event->xany.type == ButtonRelease &&
-           event->xbutton.button & Button1)
-    {
-      gp->button_down_p = False;
-      return True;
-    }
-  else if (event->xany.type == MotionNotify &&
-           gp->button_down_p)
-    {
-      gltrackball_track (gp->trackball,
-                         event->xmotion.x, event->xmotion.y,
-                         MI_WIDTH (mi), MI_HEIGHT (mi));
-      return True;
-    }
+  if (gltrackball_event_handler (event, gp->trackball,
+                                 MI_WIDTH (mi), MI_HEIGHT (mi),
+                                 &gp->button_down_p))
+    return True;
 
   return False;
 }
 
 
-void
+ENTRYPOINT void
 init_planet (ModeInfo * mi)
 {
   planetstruct *gp;
@@ -513,8 +429,8 @@ init_planet (ModeInfo * mi)
   }
 
   {
-       char *f = get_string_resource("imageForeground", "Foreground");
-       char *b = get_string_resource("imageBackground", "Background");
+       char *f = get_string_resource(mi->dpy, "imageForeground", "Foreground");
+       char *b = get_string_resource(mi->dpy, "imageBackground", "Background");
        char *s;
        if (!f) f = strdup("white");
        if (!b) b = strdup("black");
@@ -550,14 +466,13 @@ init_planet (ModeInfo * mi)
                             do_wander ? wander_speed : 0,
                             True);
     gp->z = frand (1.0);
-    gp->trackball = gltrackball_init ();
+    gp->trackball = gltrackball_init (True);
   }
 
   if (wire)
     {
       do_texture = False;
       do_light = False;
-      glEnable (GL_LINE_SMOOTH);
     }
 
   if (do_texture)
@@ -569,9 +484,8 @@ init_planet (ModeInfo * mi)
   if (do_stars)
     init_stars (mi);
 
-  glEnable(GL_DEPTH_TEST);
-  glEnable(GL_CULL_FACE);
-  glCullFace(GL_BACK); 
+  if (random() & 1)
+    star_spin = -star_spin;
 
   /* construct the polygons of the planet
    */
@@ -581,8 +495,8 @@ init_planet (ModeInfo * mi)
   glPushMatrix ();
   glScalef (RADIUS, RADIUS, RADIUS);
   glRotatef (90, 1, 0, 0);
+  glFrontFace(GL_CCW);
   unit_sphere (resolution, resolution, wire);
-  mi->polygon_count += resolution*resolution;
   glPopMatrix ();
   glEndList();
 
@@ -591,8 +505,9 @@ init_planet (ModeInfo * mi)
   gp->latlonglist = glGenLists(1);
   glNewList (gp->latlonglist, GL_COMPILE);
   glPushMatrix ();
-  if (do_texture) glDisable (GL_TEXTURE_2D);
-  if (do_light)   glDisable (GL_LIGHTING);
+  glDisable (GL_TEXTURE_2D);
+  glDisable (GL_LIGHTING);
+  glDisable (GL_LINE_SMOOTH);
   glColor3f (0.1, 0.3, 0.1);
   glScalef (RADIUS, RADIUS, RADIUS);
   glScalef (1.01, 1.01, 1.01);
@@ -602,13 +517,11 @@ init_planet (ModeInfo * mi)
   glVertex3f(0, -2, 0);
   glVertex3f(0,  2, 0);
   glEnd();
-  if (do_light)   glEnable(GL_LIGHTING);
-  if (do_texture) glEnable(GL_TEXTURE_2D);
   glPopMatrix ();
   glEndList();
 }
 
-void
+ENTRYPOINT void
 draw_planet (ModeInfo * mi)
 {
   planetstruct *gp = &planets[MI_SCREEN(mi)];
@@ -624,8 +537,21 @@ draw_planet (ModeInfo * mi)
 
   glXMakeCurrent (display, window, *(gp->glx_context));
 
+  mi->polygon_count = 0;
+
   if (do_stars)
-    draw_stars (mi);
+    {
+      draw_stars (mi);
+      mi->polygon_count += NUM_STARS;
+    }
+
+  if (do_light)   glEnable(GL_LIGHTING);
+  if (do_texture) glEnable(GL_TEXTURE_2D);
+
+  glEnable (GL_LINE_SMOOTH);
+  glEnable(GL_DEPTH_TEST);
+  glEnable(GL_CULL_FACE);
+  glCullFace(GL_BACK); 
 
   glPushMatrix();
 
@@ -655,17 +581,24 @@ draw_planet (ModeInfo * mi)
     }
 
   glCallList (gp->platelist);
+  mi->polygon_count += resolution*resolution;
+
   if (gp->button_down_p)
-    glCallList (gp->latlonglist);
+    {
+      glCallList (gp->latlonglist);
+      mi->polygon_count += 24*24;
+    }
   glPopMatrix();
 
   if (mi->fps_p) do_fps (mi);
   glFinish();
   glXSwapBuffers(display, window);
+
+  gp->star_theta += star_spin;
 }
 
 
-void
+ENTRYPOINT void
 release_planet (ModeInfo * mi)
 {
   if (planets != NULL) {
@@ -676,7 +609,8 @@ release_planet (ModeInfo * mi)
 
          if (gp->glx_context) {
                /* Display lists MUST be freed while their glXContext is current. */
-               glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
+        /* but this gets a BadMatch error. -jwz */
+               /*glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));*/
 
                if (glIsList(gp->platelist))
                  glDeleteLists(gp->platelist, 1);
@@ -691,5 +625,6 @@ release_planet (ModeInfo * mi)
 }
 
 
-#endif
+XSCREENSAVER_MODULE_2 ("GLPlanet", glplanet, planet)
 
+#endif