41131c28d325c032fa3879becbd0c04127e5fc8b
[xscreensaver] / hacks / glx / endgame.c
1 /*
2  * endgame.c
3  * plays through a chess game ending.  enjoy.
4  *
5  * version 1.0 - June 6, 2002
6  *
7  * Copyright (C) 2002 Blair Tennessy (tennessb@unbc.ca)
8  *
9  * Permission to use, copy, modify, distribute, and sell this software and its
10  * documentation for any purpose is hereby granted without fee, provided that
11  * the above copyright notice appear in all copies and that both that
12  * copyright notice and this permission notice appear in supporting
13  * documentation.  No representations are made about the suitability of this
14  * software for any purpose.  It is provided "as is" without express or
15  * implied warranty.
16  */
17
18 #include <X11/Intrinsic.h>
19
20 #ifdef STANDALONE
21 # define PROGCLASS        "Endgame"
22 # define HACK_INIT        init_chess
23 # define HACK_DRAW        draw_chess
24 # define HACK_RESHAPE     reshape_chess
25 # define HACK_HANDLE_EVENT chess_handle_event
26 # define EVENT_MASK       PointerMotionMask
27 # define chess_opts  xlockmore_opts
28
29 #define DEFAULTS       "*delay:       20000       \n" \
30                        "*showFPS:       False       \n" \
31                        "*wireframe:     False     \n"   \
32                        "*reflections:   True     \n"    \
33                        "*shadows:       True     \n"    \
34
35 # include "xlockmore.h"
36
37 #else
38 # include "xlock.h"
39 #endif
40
41 #ifdef USE_GL
42
43 #include <GL/glu.h>
44 #include "gltrackball.h"
45 #include "chessmodels.h"
46
47 #undef countof
48 #define countof(x) (sizeof((x))/sizeof((*x)))
49
50 static XrmOptionDescRec opts[] = {
51   {"+rotate", ".chess.rotate", XrmoptionNoArg, (caddr_t) "false" },
52   {"-rotate", ".chess.rotate", XrmoptionNoArg, (caddr_t) "true" },
53   {"+reflections", ".chess.reflections", XrmoptionNoArg, (caddr_t) "false" },
54   {"-reflections", ".chess.reflections", XrmoptionNoArg, (caddr_t) "true" },
55   {"+shadows", ".chess.shadows", XrmoptionNoArg, (caddr_t) "false" },
56   {"-shadows", ".chess.shadows", XrmoptionNoArg, (caddr_t) "true" },
57   {"+smooth", ".chess.smooth", XrmoptionNoArg, (caddr_t) "false" },
58   {"-smooth", ".chess.smooth", XrmoptionNoArg, (caddr_t) "true" },
59 };
60
61 int rotate, reflections, smooth, shadows;
62
63 static argtype vars[] = {
64   {&rotate,      "rotate",      "Rotate",      "True", t_Bool},
65   {&reflections, "reflections", "Reflections", "True", t_Bool},
66   {&shadows, "shadows", "Shadows", "True", t_Bool},
67   {&smooth,      "smooth",      "Smooth",      "True", t_Bool},
68 };
69
70 ModeSpecOpt chess_opts = {countof(opts), opts, countof(vars), vars, NULL};
71
72 #ifdef USE_MODULES
73 ModStruct   chess_description =
74 {"chess", "init_chess", "draw_chess", "release_chess",
75  "draw_chess", "init_chess", NULL, &chess_opts,
76  1000, 1, 2, 1, 4, 1.0, "",
77  "Chess", 0, NULL};
78
79 #endif
80
81 typedef struct {
82   GLXContext *glx_context;
83   Window window;
84   trackball_state *trackball;
85   Bool button_down_p;
86 } Chesscreen;
87
88 static Chesscreen *qs = NULL;
89
90 #include <math.h>
91 #include <sys/time.h>
92 #include <stdio.h>
93 #include <stdlib.h>
94
95 #ifndef M_PI
96 #define M_PI 3.14159265
97 #endif
98
99 #define BOARDSIZE 8
100
101 static float MaterialShadow[] =   {0.0, 0.0, 0.0, 0.3};
102
103
104
105 /** definition of white/black (orange/gray) colors */
106 GLfloat colors[2][3] = 
107   { 
108     {1.0, 0.5, 0.0},
109     {0.6, 0.6, 0.6},
110   };
111
112 #define WHITES 5
113
114 /* i prefer silvertip */
115 GLfloat whites[WHITES][3] = 
116   {
117     {1.0, 0.55, 0.1},
118     {0.8, 0.52, 0.8},
119     {0.43, 0.54, 0.76},
120     {0.8, 0.8, 0.8},
121     {0.35, 0.60, 0.35},
122   };
123
124 #include "chessgames.h"
125
126 ChessGame game;
127 int oldwhite = -1;
128
129 void build_colors(void) {
130
131   /* find new white */
132   int newwhite = oldwhite;
133   while(newwhite == oldwhite)
134     newwhite = random()%WHITES;
135   oldwhite = newwhite;
136
137   colors[0][0] = whites[oldwhite][0];
138   colors[0][1] = whites[oldwhite][1];
139   colors[0][2] = whites[oldwhite][2];
140 }
141
142 /* road texture */
143 #define checkImageWidth 16
144 #define checkImageHeight 16
145 GLubyte checkImage[checkImageWidth][checkImageHeight][3];
146 GLuint piecetexture, boardtexture;
147
148 /* build piece texture */
149 void make_piece_texture(void) {
150   int i, j, c;
151
152   for (i = 0; i < checkImageWidth; i++) {
153     for (j = 0; j < checkImageHeight; j++) {
154       c = ((j%2) == 0 || i%2 == 0) ? 240 : 180+random()%16;
155       checkImage[i][j][0] = (GLubyte) c;
156       checkImage[i][j][1] = (GLubyte) c;
157       checkImage[i][j][2] = (GLubyte) c;
158     }
159   }
160
161   glGenTextures(1, &piecetexture);
162   glBindTexture(GL_TEXTURE_2D, piecetexture);
163
164   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
165   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
166   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
167   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
168   glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth, 
169                checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 
170                &checkImage[0][0]);
171 }
172
173 /* build board texture (uniform noise in [180,180+50]) */
174 void make_board_texture(void) {
175   int i, j, c;
176
177   for (i = 0; i < checkImageWidth; i++) {
178     for (j = 0; j < checkImageHeight; j++) {
179       c = 180 + random()%51;
180       checkImage[i][j][0] = (GLubyte) c;
181       checkImage[i][j][1] = (GLubyte) c;
182       checkImage[i][j][2] = (GLubyte) c;
183     }
184   }
185
186   glGenTextures(1, &boardtexture);
187   glBindTexture(GL_TEXTURE_2D, boardtexture);
188
189   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
190   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
191   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
192   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
193   glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth, 
194                checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 
195                &checkImage[0][0]);
196 }
197
198 /* yay its c */
199 int mpiece = 0, tpiece, steps = 0, done = 1;
200 double from[2], to[2];
201 double dx, dz;
202 int moving = 0, take = 0, mc = 0, count = 99, wire = 0;
203 double theta = 0.0;
204
205 /** handle X event (trackball) */
206 Bool chess_handle_event (ModeInfo *mi, XEvent *event) {
207   Chesscreen *c = &qs[MI_SCREEN(mi)];
208
209   if(event->xany.type == ButtonPress && event->xbutton.button & Button1) {
210     c->button_down_p = True;
211     gltrackball_start (c->trackball,
212                        event->xbutton.x, event->xbutton.y,
213                        MI_WIDTH (mi), MI_HEIGHT (mi));
214     return True;
215   }
216   else if(event->xany.type == ButtonRelease 
217           && event->xbutton.button & Button1) {
218     c->button_down_p = False;
219     return True;
220   }
221   else if(event->xany.type == MotionNotify && c->button_down_p) {
222     gltrackball_track (c->trackball,
223                        event->xmotion.x, event->xmotion.y,
224                        MI_WIDTH (mi), MI_HEIGHT (mi));
225     return True;
226   }
227   
228   return False;
229 }
230
231 GLfloat position[] = { 0.0, 5.0, 5.0, 1.0 };
232 GLfloat position2[] = { 5.0, 5.0, 5.0, 1.0 };
233 GLfloat diffuse2[] = {1.0, 1.0, 1.0, 1.0};
234 GLfloat ambient2[] = {0.7, 0.7, 0.7, 1.0};
235 GLfloat shininess[] = {60.0};
236 GLfloat specular[] = {0.4, 0.4, 0.4, 1.0};
237
238 /* configure lighting */
239 void setup_lights(void) {
240   glEnable(GL_LIGHTING);
241   glLightfv(GL_LIGHT0, GL_POSITION, position);
242   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse2);
243   glEnable(GL_LIGHT0);
244
245 /*   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient2); */
246
247   glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
248   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
249
250   glLightfv(GL_LIGHT1, GL_SPECULAR, diffuse2);
251   glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse2);
252   glEnable(GL_LIGHT1);
253 }
254
255 /* draw pieces */
256 void drawPieces(void) {
257   int i, j;
258
259   for(i = 0; i < BOARDSIZE; ++i) {
260     for(j = 0; j < BOARDSIZE; ++j) {
261       if(game.board[i][j]) {    
262         int c = game.board[i][j]/PIECES;
263         glColor3fv(colors[c]);
264         glCallList(game.board[i][j]%PIECES);
265       }
266       
267       glTranslatef(1.0, 0.0, 0.0);
268     }
269     
270     glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
271   }
272
273   glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
274 }
275
276 /* draw pieces */
277 void drawPiecesShadow(void) {
278   int i, j;
279
280   for(i = 0; i < BOARDSIZE; ++i) {
281     for(j = 0; j < BOARDSIZE; ++j) {
282       if(game.board[i][j]) {    
283         glColor4f(0.0, 0.0, 0.0, 0.4);
284         glCallList(game.board[i][j]%PIECES);
285       }
286       
287       glTranslatef(1.0, 0.0, 0.0);
288     }
289     
290     glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
291   }
292
293   glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
294 }
295
296 /* draw a moving piece */
297 void drawMovingPiece(int shadow) {
298   int piece = mpiece % PIECES;
299
300   glPushMatrix();
301
302   if(shadow) glColor4fv(MaterialShadow);
303   else glColor3fv(colors[mpiece/PIECES]);
304
305   /** assume a queening.  should be more general */
306   if((mpiece == PAWN  && fabs(to[0]) < 0.01) || 
307      (mpiece == BPAWN && fabs(to[0]-7.0) < 0.01)) {
308     glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
309
310     glColor4f(shadow ? MaterialShadow[0] : colors[mpiece/7][0], 
311               shadow ? MaterialShadow[1] : colors[mpiece/7][1], 
312               shadow ? MaterialShadow[2] : colors[mpiece/7][2],
313               (fabs(50.0-steps))/50.0);
314
315     piece = steps < 50 ? PAWN : QUEEN;
316
317     /* what a kludge */
318     if(steps == 99)
319       mpiece = mpiece == PAWN ? QUEEN : BQUEEN;
320   }
321   else if(mpiece % PIECES == KNIGHT) {
322     GLfloat shine[1];
323     GLfloat spec[4];
324     GLfloat mult;
325     glTranslatef(steps < 50 ? from[1] : to[1], 0.0, 
326                  steps < 50 ? from[0] : to[0]);
327
328     mult = steps < 10 
329       ? (1.0 - steps / 10.0) : 100 - steps < 10 
330       ? (1.0 - (100 - steps) / 10.0) : 0.0;
331
332     shine[0] = mult*shininess[0];
333     spec[0] = mult*specular[0];
334     spec[1] = mult*specular[1];
335     spec[2] = mult*specular[2];
336     spec[3] = 1.0;
337     glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine);
338     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
339
340     glColor4f(shadow ? MaterialShadow[0] : colors[mpiece/7][0], 
341               shadow ? MaterialShadow[1] : colors[mpiece/7][1], 
342               shadow ? MaterialShadow[2] : colors[mpiece/7][2],
343               fabs(49-steps)/49.0);
344
345     glScalef(fabs(49-steps)/49.0, fabs(49-steps)/49.0, fabs(49-steps)/49.0);
346   }
347   else
348     glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
349
350   if(!wire)
351     glEnable(GL_BLEND);
352   
353   glCallList(piece);
354
355   glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
356   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
357
358   glPopMatrix();
359
360   if(!wire)
361     glDisable(GL_BLEND);
362 }
363
364 /** code to squish a taken piece */
365 void drawTakePiece(int shadow) {
366   if(!wire)
367     glEnable(GL_BLEND);
368
369   glColor4f(shadow ? MaterialShadow[0] : colors[tpiece/7][0], 
370             shadow ? MaterialShadow[1] : colors[tpiece/7][1], 
371             shadow ? MaterialShadow[0] : colors[tpiece/7][2],
372             (100-1.6*steps)/100.0);
373
374   glTranslatef(to[1], 0.0, to[0]);
375   
376   if(mpiece % PIECES == KNIGHT)
377     glScalef(1.0+steps/100.0, 1.0, 1.0+steps/100.0);
378   else
379     glScalef(1.0, 1 - steps/50.0 > 0.01 ? 1 - steps/50.0 : 0.01, 1.0);
380   glCallList(tpiece % 7);
381   
382   if(!wire)
383     glDisable(GL_BLEND);
384 }
385
386 double mod = 1.4;
387
388 /** draw board */
389 void drawBoard(void) {
390   int i, j;
391
392   glBegin(GL_QUADS);
393
394   for(i = 0; i < BOARDSIZE; ++i)
395     for(j = 0; j < BOARDSIZE; ++j) {
396       double ma1 = (i+j)%2 == 0 ? mod*i : 0.0;
397       double mb1 = (i+j)%2 == 0 ? mod*j : 0.0;
398       double ma2 = (i+j)%2 == 0 ? mod*(i+1.0) : 0.01;
399       double mb2 = (i+j)%2 == 0 ? mod*(j+1.0) : 0.01;
400
401       /*glColor3fv(colors[(i+j)%2]);*/
402       glColor4f(colors[(i+j)%2][0], colors[(i+j)%2][1],
403                 colors[(i+j)%2][2], 0.65);
404       
405       glNormal3f(0.0, 1.0, 0.0);
406 /*       glTexCoord2f(mod*i, mod*(j+1.0)); */
407       glTexCoord2f(ma1, mb2);
408       glVertex3f(i, 0.0, j + 1.0);
409 /*       glTexCoord2f(mod*(i+1.0), mod*(j+1.0)); */
410       glTexCoord2f(ma2, mb2);
411       glVertex3f(i + 1.0, 0.0, j + 1.0);
412       glTexCoord2f(ma2, mb1);
413 /*       glTexCoord2f(mod*(i+1.0), mod*j); */
414       glVertex3f(i + 1.0, 0.0, j);
415       glTexCoord2f(ma1, mb1);
416 /*       glTexCoord2f(mod*i, mod*j); */
417       glVertex3f(i, 0.0, j);
418     }
419
420   /* chop underneath board */
421 /*   glColor3f(0, 0, 0); */
422 /*   glNormal3f(0, -1, 0); */
423 /*   glVertex3f(0,         0,  BOARDSIZE); */
424 /*   glVertex3f(0,         0,  0); */
425 /*   glVertex3f(BOARDSIZE, 0,  0); */
426 /*   glVertex3f(BOARDSIZE, 0,  BOARDSIZE); */
427   glEnd();
428 }
429
430 void draw_pieces(void) {
431   glEnable(GL_TEXTURE_2D);
432   glBindTexture(GL_TEXTURE_2D, piecetexture);
433   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
434
435   glColor4f(0.5, 0.5, 0.5, 1.0);
436   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
437
438   drawPieces();
439   if(moving) drawMovingPiece(0);
440   if(take) drawTakePiece(0);
441   glDisable(GL_TEXTURE_2D);
442 }
443
444 void draw_shadow_pieces(void) {
445   glEnable(GL_TEXTURE_2D);
446   glBindTexture(GL_TEXTURE_2D, piecetexture);
447   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
448
449   
450   drawPiecesShadow();
451   if(moving) drawMovingPiece(shadows);
452   if(take) drawTakePiece(shadows);
453   glDisable(GL_TEXTURE_2D);
454 }
455
456 enum {X, Y, Z, W};
457 enum {A, B, C, D};
458
459 /* create a matrix that will project the desired shadow */
460 void shadowmatrix(GLfloat shadowMat[4][4],
461                   GLfloat groundplane[4],
462                   GLfloat lightpos[4]) {
463   GLfloat dot;
464
465   /* find dot product between light position vector and ground plane normal */
466   dot = groundplane[X] * lightpos[X] +
467         groundplane[Y] * lightpos[Y] +
468         groundplane[Z] * lightpos[Z] +
469         groundplane[W] * lightpos[W];
470
471   shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
472   shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
473   shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
474   shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
475
476   shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
477   shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
478   shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
479   shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
480
481   shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
482   shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
483   shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
484   shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
485
486   shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
487   shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
488   shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
489   shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
490 }
491
492 GLfloat ground[4] = {0.0, 1.0, 0.0, -0.00001};
493
494 /** reflectionboard */
495 void draw_reflections(void) {
496   int i, j;
497
498   glEnable(GL_STENCIL_TEST);
499   glStencilFunc(GL_ALWAYS, 1, 1);
500   glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
501   glColorMask(0,0,0,0);
502   glDisable(GL_CULL_FACE);
503
504   glDisable(GL_DEPTH_TEST);
505   glBegin(GL_QUADS);
506
507   /* only draw white squares */
508   for(i = 0; i < BOARDSIZE; ++i) {
509     for(j = (BOARDSIZE+i) % 2; j < BOARDSIZE; j += 2) {
510       glVertex3f(i, 0.0, j + 1.0);
511       glVertex3f(i + 1.0, 0.0, j + 1.0);
512       glVertex3f(i + 1.0, 0.0, j);
513       glVertex3f(i, 0.0, j);
514     }
515   }
516   glEnd();
517   glEnable(GL_DEPTH_TEST);
518
519   glColorMask(1, 1, 1, 1);
520   glStencilFunc(GL_EQUAL, 1, 1);
521   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
522   
523   glPushMatrix(); 
524   glScalef(1.0, -1.0, 1.0);
525   glTranslatef(0.5, 0.0, 0.5);
526
527   glLightfv(GL_LIGHT0, GL_POSITION, position);
528   draw_pieces();
529   glPopMatrix();
530   
531   glDisable(GL_STENCIL_TEST);
532   glLightfv(GL_LIGHT0, GL_POSITION, position);
533
534   glEnable(GL_CULL_FACE);
535   glCullFace(GL_BACK);
536   glColorMask(1,1,1,1);
537 }
538
539 /** draws the scene */
540 void display(Chesscreen *c) {
541   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
542
543   glMatrixMode(GL_MODELVIEW);
544   glLoadIdentity();
545
546   /** setup perspectif */
547   glTranslatef(0.0, 0.0, -1.5*BOARDSIZE);
548   glRotatef(30.0, 1.0, 0.0, 0.0);
549   gltrackball_rotate (c->trackball);
550   glRotatef(theta*100, 0.0, 1.0, 0.0);
551   glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
552
553   position[0] = 4.0 + 1.0*-sin(theta*100*M_PI/180.0);
554   position[2] = 4.0 + 1.0*cos(theta*100*M_PI/180.0);
555   position[1] = 5.0;
556
557   position2[0] = 4.0 + 8.0*-sin(theta*100*M_PI/180.0);
558   position2[2] = 4.0 + 8.0*cos(theta*100*M_PI/180.0);
559
560   glEnable(GL_LIGHTING);
561   glLightfv(GL_LIGHT0, GL_POSITION, position);
562   glLightfv(GL_LIGHT1, GL_POSITION, position2);
563   glEnable(GL_LIGHT0);
564
565   /** draw board, pieces */
566   if(!wire) {
567     glEnable(GL_LIGHTING);
568     glEnable(GL_COLOR_MATERIAL);
569
570     if(reflections) {
571       draw_reflections();
572       glEnable(GL_BLEND);
573     }
574
575     glEnable(GL_TEXTURE_2D);
576     glBindTexture(GL_TEXTURE_2D, boardtexture);
577     drawBoard();
578     glDisable(GL_TEXTURE_2D);
579
580     if(shadows) {
581       /* render shadows */
582       GLfloat m[4][4];
583       shadowmatrix(m, ground, position);
584
585       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
586       glEnable(GL_BLEND);
587       glDisable(GL_LIGHTING);
588       glDisable(GL_DEPTH_TEST);
589       
590       /* display ant shadow */
591       glPushMatrix();
592       glTranslatef(0.0, 0.001, 0.0);
593       glMultMatrixf(m[0]);
594       glTranslatef(0.5, 0.01, 0.5);
595       draw_shadow_pieces();
596       glPopMatrix();      
597
598       glEnable(GL_LIGHTING);
599       glDisable(GL_BLEND);
600       glEnable(GL_DEPTH_TEST);
601     }
602
603     if(reflections)
604       glDisable(GL_BLEND);
605   }
606   else
607     drawBoard();
608  
609   glTranslatef(0.5, 0.0, 0.5);
610   draw_pieces();
611
612   if(!wire) {
613     glDisable(GL_COLOR_MATERIAL);
614     glDisable(GL_LIGHTING);
615   }
616
617   if (!c->button_down_p)
618     theta += .002;
619 }
620
621 /** reshape handler */
622 void reshape_chess(ModeInfo *mi, int width, int height) {
623   GLfloat h = (GLfloat) height / (GLfloat) width;
624   glViewport(0,0, width, height);
625   glMatrixMode(GL_PROJECTION);
626   glLoadIdentity();
627   gluPerspective(45, 1/h, 2.0, 30.0);
628   glMatrixMode(GL_MODELVIEW);
629 }
630
631 /** initialization handler */
632 void init_chess(ModeInfo *mi) {
633   Chesscreen *c;
634   int screen = MI_SCREEN(mi);
635   wire = MI_IS_WIREFRAME(mi);
636
637   if(!qs && 
638      !(qs = (Chesscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Chesscreen))))
639     return;
640   
641   c = &qs[screen];
642   c->window = MI_WINDOW(mi);
643   c->trackball = gltrackball_init ();
644   
645   if((c->glx_context = init_GL(mi)))
646     reshape_chess(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
647   else
648     MI_CLEARWINDOW(mi);
649
650   glClearColor(0.0, 0.0, 0.0, 0.0);
651
652   glDepthFunc(GL_LEQUAL);
653   glClearStencil(0);
654   glEnable(GL_CULL_FACE);
655   glCullFace(GL_BACK);
656
657   make_piece_texture();
658   make_board_texture();
659   gen_model_lists();
660
661   if(!wire) {
662     setup_lights();
663     glColorMaterial(GL_FRONT, GL_DIFFUSE);
664     glShadeModel(smooth ? GL_SMOOTH : GL_FLAT);
665     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
666     glEnable(GL_DEPTH_TEST);
667   }
668   else
669     glPolygonMode(GL_FRONT, GL_LINE);
670 }
671
672 int oldgame = -1;
673
674 /** does dirty work drawing scene, moving pieces */
675 void draw_chess(ModeInfo *mi) {
676   Chesscreen *c = &qs[MI_SCREEN(mi)];
677   Window w = MI_WINDOW(mi);
678   Display *disp = MI_DISPLAY(mi);
679
680   if(!c->glx_context)
681     return;
682
683   glXMakeCurrent(disp, w, *(c->glx_context));
684
685   /** code for moving a piece */
686   if(moving && ++steps == 100) {
687     moving = count = steps = take = 0;
688     game.board[game.moves[mc][2]][game.moves[mc][3]] = mpiece;
689     ++mc;
690     
691     if(mc == game.movecount) {
692       done = 1;
693       mc = 0;
694     }
695   }
696
697   if(++count == 100) {
698     if(!done) {
699       mpiece = game.board[game.moves[mc][0]][game.moves[mc][1]];
700       game.board[game.moves[mc][0]][game.moves[mc][1]] = NONE;
701       
702       if((tpiece = game.board[game.moves[mc][2]][game.moves[mc][3]])) {
703         game.board[game.moves[mc][2]][game.moves[mc][3]] = NONE;
704         take = 1;
705       }
706       
707       from[0] = game.moves[mc][0];
708       from[1] = game.moves[mc][1];
709       to[0] = game.moves[mc][2];
710       to[1] = game.moves[mc][3];
711       
712       dz = (to[0] - from[0]) / 100;
713       dx = (to[1] - from[1]) / 100;
714       steps = 0;
715       moving = 1;
716     }
717     else if(done == 1) {
718       int newgame = oldgame;
719       while(newgame == oldgame)
720         newgame = random()%GAMES;
721
722       /* mod the mod */
723       mod = 0.6 + (random()%20)/10.0;
724
725       /* same old game */
726       oldgame = newgame;
727       game = games[oldgame];
728       build_colors();
729       done = 2;
730       count = 0;
731     }
732     else {
733       done = 0;
734       count = 0;
735     }
736   }
737
738   /* set lighting */
739   if(done) {
740     glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 
741              done == 1 ? 1.0+0.1*count : 100.0/count);
742     glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 
743              done == 1 ? 1.0+0.1*count : 100.0/count);
744     glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.14);
745     glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.14);
746   }
747
748   display(c);
749
750   if(mi->fps_p) do_fps(mi);
751   glFinish(); 
752   glXSwapBuffers(disp, w);
753 }
754
755 /** bust it */
756 void release_chess(ModeInfo *mi) {
757   if(qs)
758     free((void *) qs);
759
760   FreeAllGL(MI);
761 }
762
763 #endif