From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / queens.c
index 7b55ac273a17a70e1c0eab4e06e04fcf7859df25..cd3867cf9af87498d8367146ff71aeb490aafef3 100644 (file)
 # include "xlock.h"
 #endif
 
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+#else
+# include <X11/Xlib.h>
+# include <GL/gl.h>
+# include <GL/glu.h>
+#endif
+
+#ifdef HAVE_JWZGLES
+# include "jwzgles.h"
+#endif /* HAVE_JWZGLES */
+
 #ifdef USE_GL
 
 #include "gltrackball.h"
+#include "chessmodels.h"
 
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
@@ -54,7 +67,7 @@ ENTRYPOINT ModeSpecOpt queens_opts = {countof(opts), opts, countof(vars), vars,
 
 #ifdef USE_MODULES
 ModStruct   queens_description =
-{"queens", "init_queens", "draw_queens", "release_queens",
+{"queens", "init_queens", "draw_queens", NULL,
  "draw_queens", "init_queens", NULL, &queens_opts,
  1000, 1, 2, 1, 4, 1.0, "",
  "Queens", 0, NULL};
@@ -62,7 +75,6 @@ ModStruct   queens_description =
 #endif
 
 #define NONE 0
-#define QUEEN 1
 #define MINBOARD 5
 #define MAXBOARD 10
 #define COLORSETS 5
@@ -73,10 +85,12 @@ typedef struct {
   trackball_state *trackball;
   Bool button_down_p;
   GLfloat position[4];
+  int queen_list;
 
   int board[MAXBOARD][MAXBOARD];
   int steps, colorset, BOARDSIZE;
   double theta;
+  int queen_polys;
 
 } Queenscreen;
 
@@ -97,35 +111,13 @@ queens_handle_event (ModeInfo *mi, XEvent *event)
 {
   Queenscreen *qs = &qss[MI_SCREEN(mi)];
 
-  if (event->xany.type == ButtonPress &&
-      event->xbutton.button == Button1)
-    {
-      qs->button_down_p = True;
-      gltrackball_start (qs->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)
-    {
-      qs->button_down_p = False;
-      return True;
-    }
-  else if (event->xany.type == ButtonPress &&
-           (event->xbutton.button == Button4 ||
-            event->xbutton.button == Button5))
-    {
-      gltrackball_mousewheel (qs->trackball, event->xbutton.button, 5,
-                              !event->xbutton.state);
-      return True;
-    }
-  else if (event->xany.type == MotionNotify &&
-           qs->button_down_p)
+  if (gltrackball_event_handler (event, qs->trackball,
+                                 MI_WIDTH (mi), MI_HEIGHT (mi),
+                                 &qs->button_down_p))
+    return True;
+  else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
     {
-      gltrackball_track (qs->trackball,
-                         event->xmotion.x, event->xmotion.y,
-                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      qs->steps = 1024 - 1;
       return True;
     }
 
@@ -242,15 +234,17 @@ static GLfloat findAlpha(Queenscreen *qs)
 }
 
 /* draw pieces */
-static void drawPieces(Queenscreen *qs) 
+static int drawPieces(Queenscreen *qs) 
 {
   int i, j;
+  int polys = 0;
 
   for(i = 0; i < qs->BOARDSIZE; ++i) {
     for(j = 0; j < qs->BOARDSIZE; ++j) {
       if(qs->board[i][j]) {
        glColor3fv(colors[qs->colorset][i%2]);
-       glCallList(QUEEN);
+       glCallList(qs->queen_list);
+        polys += qs->queen_polys;
       }
       
       glTranslatef(1.0, 0.0, 0.0);
@@ -258,12 +252,14 @@ static void drawPieces(Queenscreen *qs)
     
     glTranslatef(-1.0*qs->BOARDSIZE, 0.0, 1.0);
   }
+  return polys;
 }
 
 /** reflectionboard */
-static void draw_reflections(Queenscreen *qs) 
+static int draw_reflections(Queenscreen *qs) 
 {
   int i, j;
+  int polys = 0;
 
   glEnable(GL_STENCIL_TEST);
   glStencilFunc(GL_ALWAYS, 1, 1);
@@ -281,6 +277,7 @@ static void draw_reflections(Queenscreen *qs)
       glVertex3f(i + 1.0, 0.0, j + 1.0);
       glVertex3f(i + 1.0, 0.0, j);
       glVertex3f(i, 0.0, j);
+      polys++;
     }
   }
   glEnd();
@@ -294,7 +291,7 @@ static void draw_reflections(Queenscreen *qs)
   glScalef(1.0, -1.0, 1.0);
   glTranslatef(0.5, 0.001, 0.5);
   glLightfv(GL_LIGHT0, GL_POSITION, qs->position);
-  drawPieces(qs);
+  polys += drawPieces(qs);
   glPopMatrix();
   glDisable(GL_STENCIL_TEST);
 
@@ -304,12 +301,14 @@ static void draw_reflections(Queenscreen *qs)
   glEnable(GL_CULL_FACE);
   glCullFace(GL_BACK);
   glColorMask(1,1,1,1);
+  return polys;
 }
 
 /* draw board */
-static void drawBoard(Queenscreen *qs) 
+static int drawBoard(Queenscreen *qs) 
 {
   int i, j;
+  int polys = 0;
 
   glBegin(GL_QUADS);
 
@@ -325,19 +324,107 @@ static void drawBoard(Queenscreen *qs)
       glVertex3f(i + 1.0, 0.0, j + 1.0);
       glVertex3f(i + 1.0, 0.0, j);
       glVertex3f(i, 0.0, j);
+      polys++;
     }
 
   glEnd();
+
+  {
+    GLfloat off = 0.01;
+    GLfloat w = qs->BOARDSIZE;
+    GLfloat h = 0.1;
+
+    /* Give the board a slight lip. */
+    /* #### oops, normals are wrong here, but you can't tell */
+
+    glColor3f(0.3, 0.3, 0.3);
+    glBegin (GL_QUADS);
+    glVertex3f (0,  0, 0);
+    glVertex3f (0, -h, 0);
+    glVertex3f (0, -h, w);
+    glVertex3f (0,  0, w);
+
+    glVertex3f (0,  0, w);
+    glVertex3f (0, -h, w);
+    glVertex3f (w, -h, w);
+    glVertex3f (w,  0, w);
+
+    glVertex3f (w,  0, w);
+    glVertex3f (w, -h, w);
+    glVertex3f (w, -h, 0);
+    glVertex3f (w,  0, 0);
+
+    glVertex3f (w,  0, 0);
+    glVertex3f (w, -h, 0);
+    glVertex3f (0, -h, 0);
+    glVertex3f (0,  0, 0);
+
+    glVertex3f (0, -h, 0);
+    glVertex3f (w, -h, 0);
+    glVertex3f (w, -h, w);
+    glVertex3f (0, -h, w);
+    glEnd();
+    polys += 4;
+
+    /* Fill in the underside of the board with an invisible black box
+       to hide the reflections that are not on tiles.  Probably there's
+       a way to do this with stencils instead.
+     */
+    w -= off*2;
+    h = 5;
+
+    glPushMatrix();
+    glTranslatef (off, 0, off);
+    glDisable(GL_LIGHTING);
+    glColor3f(0,0,0);
+    glBegin (GL_QUADS);
+    glVertex3f (0,  0, 0);
+    glVertex3f (0, -h, 0);
+    glVertex3f (0, -h, w);
+    glVertex3f (0,  0, w);
+
+    glVertex3f (0,  0, w);
+    glVertex3f (0, -h, w);
+    glVertex3f (w, -h, w);
+    glVertex3f (w,  0, w);
+
+    glVertex3f (w,  0, w);
+    glVertex3f (w, -h, w);
+    glVertex3f (w, -h, 0);
+    glVertex3f (w,  0, 0);
+
+    glVertex3f (w,  0, 0);
+    glVertex3f (w, -h, 0);
+    glVertex3f (0, -h, 0);
+    glVertex3f (0,  0, 0);
+
+    glVertex3f (0, -h, 0);
+    glVertex3f (w, -h, 0);
+    glVertex3f (w, -h, w);
+    glVertex3f (0, -h, w);
+    glEnd();
+    polys += 4;
+    glPopMatrix();
+    if (!wire)
+      glEnable(GL_LIGHTING);
+  }
+
+  return polys;
 }
 
-static void display(Queenscreen *qs) 
+static int display(ModeInfo *mi, Queenscreen *qs) 
 {
+  int max = 1024;
+  int polys = 0;
   glClear(clearbits);
   
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
 
+  glRotatef(current_device_rotation(), 0, 0, 1);
+
   /* setup light attenuation */
+  /* #### apparently this does nothing */
   glEnable(GL_COLOR_MATERIAL);
   glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.8/(0.01+findAlpha(qs)));
   glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.06);
@@ -360,72 +447,74 @@ static void display(Queenscreen *qs)
     glEnable(GL_LIGHT0);
   }
 
+  /* Since the lighting attenuation trick up there doesn't seem to be working,
+     let's drop the old board down and drop the new board in. */
+  if (qs->steps < (max/8.0)) {
+    GLfloat y = qs->steps / (max/8.0);
+    y = sin (M_PI/2 * y);
+    glTranslatef (0, 10 - (y * 10), 0);
+  } else if (qs->steps > max-(max/8.0)) {
+    GLfloat y = (qs->steps - (max-(max/8.0))) / (GLfloat) (max/8.0);
+    y = 1 - sin (M_PI/2 * (1-y));
+    glTranslatef (0, -y * 15, 0);
+  }
+
   /* draw reflections */
   if(!wire) {
-    draw_reflections(qs);
+    polys += draw_reflections(qs);
     glEnable(GL_BLEND);
   }
-  drawBoard(qs);
+  polys += drawBoard(qs);
   if(!wire)
     glDisable(GL_BLEND);
 
   glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.1);
 
   glTranslatef(0.5, 0.0, 0.5);
-  drawPieces(qs);
+  polys += drawPieces(qs);
 
   /* rotate camera */
   if(!qs->button_down_p)
     qs->theta += .002;
 
   /* zero out board, find new solution of size MINBOARD <= i <= MAXBOARD */
-  if(++qs->steps == 1024) {
+  if(++qs->steps == max) {
     qs->steps = 0;
     blank(qs);
     qs->BOARDSIZE = MINBOARD + (random() % (MAXBOARD - MINBOARD + 1));
     qs->colorset = (qs->colorset+1)%COLORSETS;
     go(qs);
   }
+  return polys;
 }
 
-static const GLfloat spidermodel[][3] =
-  {
-    {0.48, 0.48, 0.22},
-    {0.48, 0.34, 0.18},
-    {0.34, 0.34, 0.10},
-    {0.34, 0.18, 0.30},
-    {0.18, 0.14, 0.38},
-    {0.14, 0.29, 0.01},
-    {0.29, 0.18, 0.18},
-    {0.18, 0.18, 0.16},
-    {0.18, 0.20, 0.26},
-    {0.20, 0.27, 0.14},
-    {0.27, 0.24, 0.08},
-    {0.24, 0.17, 0.00},
-    {0.17, 0.095, 0.08},
-    {0.095, 0.07, 0.00},
-    {0.07, 0.00, 0.12},
-  };
-
-
 #define EPSILON 0.001
 
+#if 0
 /** draws cylindermodel */
-static void draw_model(int chunks, const GLfloat model[][3], int r) 
+static int draw_model(int chunks, const GLfloat model[][3], int r) 
 {
   int i = 0;
-  GLUquadricObj *quadric = gluNewQuadric();
+  int polys = 0;
   glPushMatrix();
   glRotatef(-90.0, 1.0, 0.0, 0.0);
   
   for(i = 0; i < chunks; ++i) {
-    if(model[i][0] > EPSILON || model[i][1] > EPSILON)
-      gluCylinder(quadric, model[i][0], model[i][1], model[i][2], r, 1);
+    if(model[i][0] > EPSILON || model[i][1] > EPSILON) {
+      polys += tube (0, 0, 0,
+                     0, 0, model[i][1],
+                     model[i][0], 0,
+                     r, False, False, False);
+/*      gluCylinder(quadric, model[i][0], model[i][1], model[i][2], r, 1);
+      polys += r;*/
+    }
     glTranslatef(0.0, 0.0, model[i][2]);
   }
   
   glPopMatrix();
+  return polys;
 }
+#endif
 
 ENTRYPOINT void reshape_queens(ModeInfo *mi, int width, int height) 
 {
@@ -441,27 +530,45 @@ ENTRYPOINT void init_queens(ModeInfo *mi)
 {
   int screen = MI_SCREEN(mi);
   Queenscreen *qs;
+  int poly_counts[PIECES];
   wire = MI_IS_WIREFRAME(mi);
 
-  if(!qss && 
-     !(qss = (Queenscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Queenscreen))))
-    return;
+# ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
+  wire = 0;
+# endif
+
+  MI_INIT (mi, qss, NULL);
   
   qs = &qss[screen];
   qs->window = MI_WINDOW(mi);
-  qs->trackball = gltrackball_init ();
-
-  qs->BOARDSIZE = 8; /* 8 cuz its classic */
   
   if((qs->glx_context = init_GL(mi)))
     reshape_queens(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
   else
     MI_CLEARWINDOW(mi);
 
-  glClearColor(0.0, 0.0, 0.0, 0.0);
-  glNewList(QUEEN, GL_COMPILE);
-  draw_model(countof(spidermodel), spidermodel, 24);
-  glEndList();
+  qs->trackball = gltrackball_init (False);
+
+  qs->BOARDSIZE = 8; /* 8 cuz its classic */
+
+  chessmodels_gen_lists(-1, poly_counts);
+  qs->queen_list = QUEEN;
+  qs->queen_polys = poly_counts[QUEEN];
+
+  /* find a solution */
+  go(qs);
+}
+
+ENTRYPOINT void draw_queens(ModeInfo *mi) 
+{
+  Queenscreen *qs = &qss[MI_SCREEN(mi)];
+  Window w = MI_WINDOW(mi);
+  Display *disp = MI_DISPLAY(mi);
+
+  if(!qs->glx_context)
+    return;
+
+  glXMakeCurrent(disp, w, *(qs->glx_context));
 
   if(flat)
     glShadeModel(GL_FLAT);
@@ -482,22 +589,8 @@ ENTRYPOINT void init_queens(ModeInfo *mi)
   else
     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
-  /* find a solution */
-  go(qs);
-}
-
-ENTRYPOINT void draw_queens(ModeInfo *mi) 
-{
-  Queenscreen *qs = &qss[MI_SCREEN(mi)];
-  Window w = MI_WINDOW(mi);
-  Display *disp = MI_DISPLAY(mi);
-
-  if(!qs->glx_context)
-    return;
-
-  glXMakeCurrent(disp, w, *(qs->glx_context));
-
-  display(qs);
+  mi->polygon_count = display(mi, qs);
+  mi->recursion_depth = qs->BOARDSIZE;
 
   if(mi->fps_p) do_fps(mi);
   glFinish();