http://www.jwz.org/xscreensaver/xscreensaver-5.12.tar.gz
[xscreensaver] / hacks / glx / blocktube.c
index f32c7b1e4a0d56241beebc06351f5f02eef381c3..f3e71c81b7b2dc952aeeaf93c5750f640727b90d 100644 (file)
  * implied warranty.
  */
 
-#include <X11/Intrinsic.h>
-
 #define DEBUG 1
 
-extern XtAppContext app;
-
-#define PROGCLASS       "Blocktube"
-#define HACK_INIT       init_blocktube
-#define HACK_DRAW       draw_blocktube
-#define HACK_RESHAPE    reshape_blocktube
-#define EVENT_MASK      PointerMotionMask
-#define blocktube_opts  xlockmore_opts
-
-#define DEF_HOLDTIME    "1000"
-#define DEF_CHANGETIME  "200"
-#define MAX_ENTITIES     1000
-#define DEF_TEXTURE     "True"
-#define DEF_FOG         "True"
-
-#define DEFAULTS        "*delay:       10000           \n" \
-                        "*holdtime:   " DEF_HOLDTIME   "\n" \
-                        "*changetime: " DEF_CHANGETIME "\n" \
-                       "*wireframe:    False           \n" \
-                       "*texture:    " DEF_TEXTURE    "\n" \
-                       "*fog:        " DEF_FOG        "\n" \
+#define DEFAULTS        "*delay:       40000           \n" \
+                        "*wireframe:    False           \n" \
                        "*showFPS:      False           \n" \
 
+# define refresh_blocktube 0
+# define blocktube_handle_event 0
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
@@ -48,9 +29,13 @@ extern XtAppContext app;
 
 #ifdef USE_GL /* whole file */
 
-#include <GL/glu.h>
+#define DEF_HOLDTIME    "1000"
+#define DEF_CHANGETIME  "200"
+#define MAX_ENTITIES     1000
+#define DEF_TEXTURE     "True"
+#define DEF_FOG         "True"
 
-#if defined( USE_XPM ) || defined( USE_XPMINC ) || defined( HAVE_XPM )
+#if defined(USE_XPM) || defined(USE_XPMINC) || defined(STANDALONE)
 /* USE_XPM & USE_XPMINC in xlock mode ; HAVE_XPM in xscreensaver mode */
 #include "xpm-ximage.h"
 #define I_HAVE_XPM
@@ -58,14 +43,6 @@ extern XtAppContext app;
 #include "../images/blocktube.xpm"
 #endif /* HAVE_XPM */
 
-typedef struct {
-    GLXContext *glx_context;
-    GLuint  block_dlist;
-} blocktube_configuration;
-
-static int nextID = 1;
-static blocktube_configuration *lps = NULL;
-
 typedef struct {
     int id, r, g, b;
     GLfloat tVal;
@@ -76,40 +53,50 @@ typedef struct {
     GLfloat angularVelocity;
 } entity;
 
-static entity entities[MAX_ENTITIES];
-static float targetR, targetG, targetB,
-             currentR, currentG, currentB,
-             deltaR, deltaG, deltaB;
+typedef struct {
+  GLXContext *glx_context;
+  GLuint  block_dlist;
+  int nextID;
+
+  entity entities[MAX_ENTITIES];
+  float targetR, targetG, targetB,
+    currentR, currentG, currentB,
+    deltaR, deltaG, deltaB;
+  int counter;
+  int changing;
+  GLfloat zoom;
+  GLfloat tilt;
+  GLuint envTexture;
+  XImage *texti;
+
+  GLfloat tunnelLength;
+  GLfloat tunnelWidth;
+  int polys;
+
+} blocktube_configuration;
+
+static blocktube_configuration *lps = NULL;
+
 static GLint holdtime;
 static GLint changetime;
-static int counter = 0;
-static int changing = 0;
-static GLfloat zoom = 30.0f;
-static GLfloat tilt = 4.5f;
-static GLuint loop;
-static GLuint envTexture;
-static XImage *texti;
 static int do_texture;
 static int do_fog;
 
-GLfloat tunnelLength=200;
-GLfloat tunnelWidth=5;
-
 static XrmOptionDescRec opts[] = {
     { "-holdtime",  ".holdtime",  XrmoptionSepArg, 0 },
     { "-changetime",  ".changetime",  XrmoptionSepArg, 0 },
-    {"-texture",     ".texture",   XrmoptionNoArg, (caddr_t) "True" },
-    {"+texture",     ".texture",   XrmoptionNoArg, (caddr_t) "False" },
-    {"-fog",         ".fog",       XrmoptionNoArg, (caddr_t) "True" },
-    {"+fog",         ".fog",       XrmoptionNoArg, (caddr_t) "False" },
+    {"-texture",     ".texture",   XrmoptionNoArg, "True" },
+    {"+texture",     ".texture",   XrmoptionNoArg, "False" },
+    {"-fog",         ".fog",       XrmoptionNoArg, "True" },
+    {"+fog",         ".fog",       XrmoptionNoArg, "False" },
 };
 
 static argtype vars[] = {
-    {(caddr_t *) &holdtime, "holdtime",  "Hold Time",  DEF_HOLDTIME,  t_Int},
-    {(caddr_t *) &changetime, "changetime",  "Change Time",  DEF_CHANGETIME, \
+    {&holdtime, "holdtime",  "Hold Time",  DEF_HOLDTIME,  t_Int},
+    {&changetime, "changetime",  "Change Time",  DEF_CHANGETIME, \
      t_Int},
-    {(caddr_t *) &do_texture, "texture",    "Texture", DEF_TEXTURE,   t_Bool},
-    {(caddr_t *) &do_fog,     "fog",        "Fog",     DEF_FOG,       t_Bool},
+    {&do_texture, "texture",    "Texture", DEF_TEXTURE,   t_Bool},
+    {&do_fog,     "fog",        "Fog",     DEF_FOG,       t_Bool},
 };
 
 static OptionStruct desc[] = {
@@ -117,32 +104,33 @@ static OptionStruct desc[] = {
     {"-changetime", "how long it takes to fade to a new color"},
 };
 
-ModeSpecOpt blocktube_opts = {countof(opts), opts, countof(vars), vars, desc};
+ENTRYPOINT ModeSpecOpt blocktube_opts = {countof(opts), opts, countof(vars), vars, desc};
 
 #ifdef USE_MODULES
 ModStruct blocktube_description =
     {"blocktube", "init_blocktube", "draw_blocktube", "release_blocktube",
      "draw_blocktube", "init_blocktube", (char *)NULL, &blocktube_opts,
-     10000, 30, 1, 1, 64, 1.0, "",
+     40000, 30, 1, 1, 64, 1.0, "",
      "A shifting tunnel of reflective blocks", 0, NULL};
 #endif /* USE_MODULES */
 
 #if defined( I_HAVE_XPM )
 static Bool LoadGLTextures(ModeInfo *mi)
 {
+    blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
     Bool status;
 
     status = True;
-    glGenTextures(1, &envTexture);
-    glBindTexture(GL_TEXTURE_2D, envTexture);
-    texti = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi), MI_COLORMAP(mi),
+    glGenTextures(1, &lp->envTexture);
+    glBindTexture(GL_TEXTURE_2D, lp->envTexture);
+    lp->texti = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi), MI_COLORMAP(mi),
                           blocktube_xpm);
-    if (!texti) {
+    if (!lp->texti) {
         status = False;
     } else {
         glPixelStorei(GL_UNPACK_ALIGNMENT,1);
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texti->width, texti->height, 0,
-            GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, texti->data);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lp->texti->width, lp->texti->height, 0,
+            GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, lp->texti->data);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
@@ -152,63 +140,71 @@ static Bool LoadGLTextures(ModeInfo *mi)
 }
 #endif
 
-static void newTargetColor(void)
+static void newTargetColor(blocktube_configuration *lp)
 {
-    targetR = random() % 256;
-    targetG = random() % 256;
-    targetB = random() % 256;
-    deltaR = (targetR - currentR) / changetime;
-    deltaG = (targetG - currentG) / changetime;
-    deltaB = (targetB - currentB) / changetime;
+    int luminance = 0;
+
+    while (luminance <= 150) {
+        lp->targetR = random() % 256;
+        lp->targetG = random() % 256;
+        lp->targetB = random() % 256;
+        lp->deltaR = (lp->targetR - lp->currentR) / changetime;
+        lp->deltaG = (lp->targetG - lp->currentG) / changetime;
+        lp->deltaB = (lp->targetB - lp->currentB) / changetime;
+        luminance = 0.3 * lp->targetR + 0.59 * lp->targetG + 0.11 * lp->targetB;
+    }
 }
 
-static void randomize_entity (entity *ent)
+static void randomize_entity (blocktube_configuration *lp, entity *ent)
 {
-    ent->id = nextID++;
+    ent->id = lp->nextID++;
     ent->tVal = 1 - ((float)random() / RAND_MAX / 1.5);
     ent->age = 0;
     ent->lifetime = 100;
     ent->angle = random() % 360;
     ent->angularVelocity = 0.5-((float)(random()) / RAND_MAX);
-    ent->position[0] = (float)(random()) / RAND_MAX + tunnelWidth;
+    ent->position[0] = (float)(random()) / RAND_MAX + lp->tunnelWidth;
     ent->position[1] = (float)(random()) / RAND_MAX * 2;
-    ent->position[2] = -(float)(random()) / RAND_MAX * tunnelLength;
+    ent->position[2] = -(float)(random()) / RAND_MAX * lp->tunnelLength;
 }
 
-static void entityTick(entity *ent)
+static void entityTick(blocktube_configuration *lp, entity *ent)
 {
     ent->angle += ent->angularVelocity;
     ent->position[2] += 0.1;
-    if (ent->position[2] > zoom) {
-        ent->position[2] = -tunnelLength + ((float)(random()) / RAND_MAX) * 20;
+    if (ent->position[2] > lp->zoom) {
+        ent->position[2] = -lp->tunnelLength + ((float)(random()) / RAND_MAX) * 20;
     }
     ent->age += 0.1;
 }
 
-static void tick(void)
+static void tick(blocktube_configuration *lp)
 {
-    counter--;
-    if (!counter) {
-        if (!changing) {
-            newTargetColor();
-            counter = changetime;
+    lp->counter--;
+    if (!lp->counter) {
+        if (!lp->changing) {
+            newTargetColor(lp);
+            lp->counter = changetime;
         } else {
-            counter = holdtime;
+            lp->counter = holdtime;
         }
-        changing = (!changing);
+        lp->changing = (!lp->changing);
     } else {
-        if (changing) {
-            currentR += deltaR;
-            currentG += deltaG;
-            currentB += deltaB;
+        if (lp->changing) {
+            lp->currentR += lp->deltaR;
+            lp->currentG += lp->deltaG;
+            lp->currentB += lp->deltaB;
         }
     }
 }
 
-static void cube_vertices(float x, float y, float z, int wire);
+static int cube_vertices(float x, float y, float z, int wire);
+
+ENTRYPOINT void reshape_blocktube (ModeInfo *mi, int width, int height);
 
-void init_blocktube (ModeInfo *mi)
+ENTRYPOINT void init_blocktube (ModeInfo *mi)
 {
+    int loop;
     GLfloat fogColor[4] = {0,0,0,1};
     blocktube_configuration *lp;
     int wire = MI_IS_WIREFRAME(mi);
@@ -220,12 +216,16 @@ void init_blocktube (ModeInfo *mi)
         fprintf(stderr, "%s: out of memory\n", progname);
         exit(1);
       }
-      lp = &lps[MI_SCREEN(mi)];
     }
 
     lp = &lps[MI_SCREEN(mi)];
     lp->glx_context = init_GL(mi);
 
+    lp->zoom = 30;
+    lp->tilt = 4.5;
+    lp->tunnelLength = 200;
+    lp->tunnelWidth = 5;
+
     if (wire) {
       do_fog = False;
       do_texture = False;
@@ -234,7 +234,7 @@ void init_blocktube (ModeInfo *mi)
 
     lp->block_dlist = glGenLists (1);
     glNewList (lp->block_dlist, GL_COMPILE);
-    cube_vertices(0.15, 1.2, 5.25, wire);
+    lp->polys = cube_vertices(0.15, 1.2, 5.25, wire);
     glEndList ();
 
 #if defined( I_HAVE_XPM )
@@ -253,7 +253,7 @@ void init_blocktube (ModeInfo *mi)
       glFogi(GL_FOG_MODE, GL_LINEAR);
       glHint(GL_FOG_HINT, GL_NICEST);
       glFogf(GL_FOG_START, 0);
-      glFogf(GL_FOG_END, tunnelLength/1.8);
+      glFogf(GL_FOG_END, lp->tunnelLength/1.8);
       glFogfv(GL_FOG_COLOR, fogColor);
       glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
     }
@@ -279,28 +279,39 @@ void init_blocktube (ModeInfo *mi)
       glEnable(GL_LIGHT0);
     }
 
-    counter = holdtime;
-    currentR = random() % 256;
-    currentG = random() % 256;
-    currentB = random() % 256;
-    newTargetColor();
+    lp->counter = holdtime;
+    lp->currentR = random() % 256;
+    lp->currentG = random() % 256;
+    lp->currentB = random() % 256;
+    newTargetColor(lp);
     for (loop = 0; loop < MAX_ENTITIES; loop++)
     {
-        randomize_entity(&entities[loop]);
+        randomize_entity(lp, &lp->entities[loop]);
     }
     reshape_blocktube(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
     glFlush();
 }
 
-void release_blocktube (ModeInfo *mi)
+ENTRYPOINT void release_blocktube (ModeInfo *mi)
 {
-#if defined ( I_HAVE_XPM )
-    glDeleteTextures(1, &envTexture);
-    XDestroyImage(texti);
-#endif
+  if (lps) {
+    int screen;
+    for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
+      blocktube_configuration *lp = &lps[screen];
+# if defined ( I_HAVE_XPM )
+      if (lp->envTexture)
+        glDeleteTextures(1, &lp->envTexture);
+      if (lp->texti)
+        XDestroyImage(lp->texti);
+# endif
+    }
+    free (lps);
+    lps = 0;
+  }
+  FreeAllGL(mi);
 }
 
-void reshape_blocktube (ModeInfo *mi, int width, int height)
+ENTRYPOINT void reshape_blocktube (ModeInfo *mi, int width, int height)
 {
     GLfloat h = (GLfloat) height / (GLfloat) width;
 
@@ -311,8 +322,9 @@ void reshape_blocktube (ModeInfo *mi, int width, int height)
     glMatrixMode(GL_MODELVIEW);
 }
 
-static void cube_vertices(float x, float y, float z, int wire)
+static int cube_vertices(float x, float y, float z, int wire)
 {
+    int polygon_count = 0;
     float x2, y2, z2, nv = 0.7;
     x2 = x/2;
     y2 = y/2;
@@ -326,6 +338,7 @@ static void cube_vertices(float x, float y, float z, int wire)
     glTexCoord2f(1.0, 0.0); glVertex3f( x2,  y2,  z2);
     glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2,  z2);
     glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2,  z2);
+    polygon_count++;
     glEnd();
 
     glNormal3f(0, 0, -nv);
@@ -334,6 +347,7 @@ static void cube_vertices(float x, float y, float z, int wire)
     glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2, -z2);
     glTexCoord2f(0.0, 1.0); glVertex3f( x2,  y2, -z2);
     glTexCoord2f(0.0, 0.0); glVertex3f(-x2,  y2, -z2);
+    polygon_count++;
     glEnd();
 
     glNormal3f(0, nv, 0);
@@ -342,6 +356,7 @@ static void cube_vertices(float x, float y, float z, int wire)
     glTexCoord2f(0.0, 0.0); glVertex3f( x2,  y2, -z2);
     glTexCoord2f(1.0, 0.0); glVertex3f( x2,  y2,  z2);
     glTexCoord2f(1.0, 1.0); glVertex3f(-x2,  y2,  z2);
+    polygon_count++;
     glEnd();
 
     glNormal3f(0, -nv, 0);
@@ -350,9 +365,10 @@ static void cube_vertices(float x, float y, float z, int wire)
     glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2,  z2);
     glTexCoord2f(0.0, 0.0); glVertex3f( x2, -y2,  z2);
     glTexCoord2f(1.0, 0.0); glVertex3f( x2, -y2, -z2);
+    polygon_count++;
     glEnd();
 
-    if (wire) return;
+    if (wire) return polygon_count;
 
     glNormal3f(nv, 0, 0);
     glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
@@ -360,6 +376,7 @@ static void cube_vertices(float x, float y, float z, int wire)
     glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2,  z2);
     glTexCoord2f(0.0, 1.0); glVertex3f( x2,  y2,  z2);
     glTexCoord2f(0.0, 0.0); glVertex3f( x2,  y2, -z2);
+    polygon_count++;
     glEnd();
 
     glNormal3f(-nv, 0, 0);
@@ -368,16 +385,20 @@ static void cube_vertices(float x, float y, float z, int wire)
     glTexCoord2f(1.0, 0.0); glVertex3f(-x2,  y2, -z2);
     glTexCoord2f(1.0, 1.0); glVertex3f(-x2,  y2,  z2);
     glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2,  z2);
+    polygon_count++;
     glEnd();
+
+    return polygon_count;
 }
 
 static void draw_block(ModeInfo *mi, entity *ent)
 {
     blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
     glCallList (lp->block_dlist);
+    mi->polygon_count += lp->polys;
 }
 
-void
+ENTRYPOINT void
 draw_blocktube (ModeInfo *mi)
 {
     blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
@@ -389,33 +410,39 @@ draw_blocktube (ModeInfo *mi)
     if (!lp->glx_context)
       return;
 
+    mi->polygon_count = 0;
+
+    glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(lp->glx_context));
+
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
     if (do_texture) {
       glEnable(GL_TEXTURE_GEN_S);
       glEnable(GL_TEXTURE_GEN_T);
-      glBindTexture(GL_TEXTURE_2D, envTexture);
+      glBindTexture(GL_TEXTURE_2D, lp->envTexture);
     }
 
     for (loop = 0; loop < MAX_ENTITIES; loop++) {
-        cEnt = &entities[loop];
+        cEnt = &lp->entities[loop];
 
         glLoadIdentity();
-        glTranslatef(0.0f, 0.0f, zoom);
-        glRotatef(tilt, 1.0f, 0.0f, 0.0f);
+        glTranslatef(0.0f, 0.0f, lp->zoom);
+        glRotatef(lp->tilt, 1.0f, 0.0f, 0.0f);
         glRotatef(cEnt->angle, 0.0f, 0.0f, 1.0f);
         glTranslatef(cEnt->position[0], cEnt->position[1], cEnt->position[2]);
-        glColor4ub((int)(currentR * cEnt->tVal),
-                   (int)(currentG * cEnt->tVal),
-                   (int)(currentB * cEnt->tVal), 255);
+        glColor4ub((int)(lp->currentR * cEnt->tVal),
+                   (int)(lp->currentG * cEnt->tVal),
+                   (int)(lp->currentB * cEnt->tVal), 255);
         draw_block(mi, cEnt);
-        entityTick(cEnt);
+        entityTick(lp, cEnt);
     }
-    tick();
+    tick(lp);
 
     if (mi->fps_p) do_fps (mi);
     glFinish();
     glXSwapBuffers(dpy, window);
 }
 
+XSCREENSAVER_MODULE ("BlockTube", blocktube)
+
 #endif /* USE_GL */