http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[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, "false" },
52   {"-rotate", ".chess.rotate", XrmoptionNoArg, "true" },
53   {"+reflections", ".chess.reflections", XrmoptionNoArg, "false" },
54   {"-reflections", ".chess.reflections", XrmoptionNoArg, "true" },
55   {"+shadows", ".chess.shadows", XrmoptionNoArg, "false" },
56   {"-shadows", ".chess.shadows", XrmoptionNoArg, "true" },
57   {"+smooth", ".chess.smooth", XrmoptionNoArg, "false" },
58   {"-smooth", ".chess.smooth", XrmoptionNoArg, "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 == ButtonPress &&
222            (event->xbutton.button == Button4 ||
223             event->xbutton.button == Button5))
224     {
225       gltrackball_mousewheel (c->trackball, event->xbutton.button, 5,
226                               !event->xbutton.state);
227       return True;
228     }
229   else if(event->xany.type == MotionNotify && c->button_down_p) {
230     gltrackball_track (c->trackball,
231                        event->xmotion.x, event->xmotion.y,
232                        MI_WIDTH (mi), MI_HEIGHT (mi));
233     return True;
234   }
235   
236   return False;
237 }
238
239 GLfloat position[] = { 0.0, 5.0, 5.0, 1.0 };
240 GLfloat position2[] = { 5.0, 5.0, 5.0, 1.0 };
241 GLfloat diffuse2[] = {1.0, 1.0, 1.0, 1.0};
242 GLfloat ambient2[] = {0.7, 0.7, 0.7, 1.0};
243 GLfloat shininess[] = {60.0};
244 GLfloat specular[] = {0.4, 0.4, 0.4, 1.0};
245
246 /* configure lighting */
247 void setup_lights(void) {
248   glEnable(GL_LIGHTING);
249   glLightfv(GL_LIGHT0, GL_POSITION, position);
250   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse2);
251   glEnable(GL_LIGHT0);
252
253 /*   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient2); */
254
255   glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
256   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
257
258   glLightfv(GL_LIGHT1, GL_SPECULAR, diffuse2);
259   glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse2);
260   glEnable(GL_LIGHT1);
261 }
262
263 /* draw pieces */
264 void drawPieces(void) {
265   int i, j;
266
267   for(i = 0; i < BOARDSIZE; ++i) {
268     for(j = 0; j < BOARDSIZE; ++j) {
269       if(game.board[i][j]) {    
270         int c = game.board[i][j]/PIECES;
271         glColor3fv(colors[c]);
272         glCallList(game.board[i][j]%PIECES);
273       }
274       
275       glTranslatef(1.0, 0.0, 0.0);
276     }
277     
278     glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
279   }
280
281   glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
282 }
283
284 /* draw pieces */
285 void drawPiecesShadow(void) {
286   int i, j;
287
288   for(i = 0; i < BOARDSIZE; ++i) {
289     for(j = 0; j < BOARDSIZE; ++j) {
290       if(game.board[i][j]) {    
291         glColor4f(0.0, 0.0, 0.0, 0.4);
292         glCallList(game.board[i][j]%PIECES);
293       }
294       
295       glTranslatef(1.0, 0.0, 0.0);
296     }
297     
298     glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
299   }
300
301   glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
302 }
303
304 /* draw a moving piece */
305 void drawMovingPiece(int shadow) {
306   int piece = mpiece % PIECES;
307
308   glPushMatrix();
309
310   if(shadow) glColor4fv(MaterialShadow);
311   else glColor3fv(colors[mpiece/PIECES]);
312
313   /** assume a queening.  should be more general */
314   if((mpiece == PAWN  && fabs(to[0]) < 0.01) || 
315      (mpiece == BPAWN && fabs(to[0]-7.0) < 0.01)) {
316     glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
317
318     glColor4f(shadow ? MaterialShadow[0] : colors[mpiece/7][0], 
319               shadow ? MaterialShadow[1] : colors[mpiece/7][1], 
320               shadow ? MaterialShadow[2] : colors[mpiece/7][2],
321               (fabs(50.0-steps))/50.0);
322
323     piece = steps < 50 ? PAWN : QUEEN;
324
325     /* what a kludge */
326     if(steps == 99)
327       mpiece = mpiece == PAWN ? QUEEN : BQUEEN;
328   }
329   else if(mpiece % PIECES == KNIGHT) {
330     GLfloat shine[1];
331     GLfloat spec[4];
332     GLfloat mult;
333     glTranslatef(steps < 50 ? from[1] : to[1], 0.0, 
334                  steps < 50 ? from[0] : to[0]);
335
336     mult = steps < 10 
337       ? (1.0 - steps / 10.0) : 100 - steps < 10 
338       ? (1.0 - (100 - steps) / 10.0) : 0.0;
339
340     shine[0] = mult*shininess[0];
341     spec[0] = mult*specular[0];
342     spec[1] = mult*specular[1];
343     spec[2] = mult*specular[2];
344     spec[3] = 1.0;
345     glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine);
346     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
347
348     glColor4f(shadow ? MaterialShadow[0] : colors[mpiece/7][0], 
349               shadow ? MaterialShadow[1] : colors[mpiece/7][1], 
350               shadow ? MaterialShadow[2] : colors[mpiece/7][2],
351               fabs(49-steps)/49.0);
352
353     glScalef(fabs(49-steps)/49.0, fabs(49-steps)/49.0, fabs(49-steps)/49.0);
354   }
355   else
356     glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
357
358   if(!wire)
359     glEnable(GL_BLEND);
360   
361   glCallList(piece);
362
363   glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
364   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
365
366   glPopMatrix();
367
368   if(!wire)
369     glDisable(GL_BLEND);
370 }
371
372 /** code to squish a taken piece */
373 void drawTakePiece(int shadow) {
374   if(!wire)
375     glEnable(GL_BLEND);
376
377   glColor4f(shadow ? MaterialShadow[0] : colors[tpiece/7][0], 
378             shadow ? MaterialShadow[1] : colors[tpiece/7][1], 
379             shadow ? MaterialShadow[0] : colors[tpiece/7][2],
380             (100-1.6*steps)/100.0);
381
382   glTranslatef(to[1], 0.0, to[0]);
383   
384   if(mpiece % PIECES == KNIGHT)
385     glScalef(1.0+steps/100.0, 1.0, 1.0+steps/100.0);
386   else
387     glScalef(1.0, 1 - steps/50.0 > 0.01 ? 1 - steps/50.0 : 0.01, 1.0);
388   glCallList(tpiece % 7);
389   
390   if(!wire)
391     glDisable(GL_BLEND);
392 }
393
394 double mod = 1.4;
395
396 /** draw board */
397 void drawBoard(void) {
398   int i, j;
399
400   glBegin(GL_QUADS);
401
402   for(i = 0; i < BOARDSIZE; ++i)
403     for(j = 0; j < BOARDSIZE; ++j) {
404       double ma1 = (i+j)%2 == 0 ? mod*i : 0.0;
405       double mb1 = (i+j)%2 == 0 ? mod*j : 0.0;
406       double ma2 = (i+j)%2 == 0 ? mod*(i+1.0) : 0.01;
407       double mb2 = (i+j)%2 == 0 ? mod*(j+1.0) : 0.01;
408
409       /*glColor3fv(colors[(i+j)%2]);*/
410       glColor4f(colors[(i+j)%2][0], colors[(i+j)%2][1],
411                 colors[(i+j)%2][2], 0.65);
412       
413       glNormal3f(0.0, 1.0, 0.0);
414 /*       glTexCoord2f(mod*i, mod*(j+1.0)); */
415       glTexCoord2f(ma1, mb2);
416       glVertex3f(i, 0.0, j + 1.0);
417 /*       glTexCoord2f(mod*(i+1.0), mod*(j+1.0)); */
418       glTexCoord2f(ma2, mb2);
419       glVertex3f(i + 1.0, 0.0, j + 1.0);
420       glTexCoord2f(ma2, mb1);
421 /*       glTexCoord2f(mod*(i+1.0), mod*j); */
422       glVertex3f(i + 1.0, 0.0, j);
423       glTexCoord2f(ma1, mb1);
424 /*       glTexCoord2f(mod*i, mod*j); */
425       glVertex3f(i, 0.0, j);
426     }
427
428   /* chop underneath board */
429 /*   glColor3f(0, 0, 0); */
430 /*   glNormal3f(0, -1, 0); */
431 /*   glVertex3f(0,         0,  BOARDSIZE); */
432 /*   glVertex3f(0,         0,  0); */
433 /*   glVertex3f(BOARDSIZE, 0,  0); */
434 /*   glVertex3f(BOARDSIZE, 0,  BOARDSIZE); */
435   glEnd();
436 }
437
438 void draw_pieces(void) {
439   glEnable(GL_TEXTURE_2D);
440   glBindTexture(GL_TEXTURE_2D, piecetexture);
441   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
442
443   glColor4f(0.5, 0.5, 0.5, 1.0);
444   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
445
446   drawPieces();
447   if(moving) drawMovingPiece(0);
448   if(take) drawTakePiece(0);
449   glDisable(GL_TEXTURE_2D);
450 }
451
452 void draw_shadow_pieces(void) {
453   glEnable(GL_TEXTURE_2D);
454   glBindTexture(GL_TEXTURE_2D, piecetexture);
455   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
456
457   
458   drawPiecesShadow();
459   if(moving) drawMovingPiece(shadows);
460   if(take) drawTakePiece(shadows);
461   glDisable(GL_TEXTURE_2D);
462 }
463
464 enum {X, Y, Z, W};
465 enum {A, B, C, D};
466
467 /* create a matrix that will project the desired shadow */
468 void shadowmatrix(GLfloat shadowMat[4][4],
469                   GLfloat groundplane[4],
470                   GLfloat lightpos[4]) {
471   GLfloat dot;
472
473   /* find dot product between light position vector and ground plane normal */
474   dot = groundplane[X] * lightpos[X] +
475         groundplane[Y] * lightpos[Y] +
476         groundplane[Z] * lightpos[Z] +
477         groundplane[W] * lightpos[W];
478
479   shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
480   shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
481   shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
482   shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
483
484   shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
485   shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
486   shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
487   shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
488
489   shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
490   shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
491   shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
492   shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
493
494   shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
495   shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
496   shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
497   shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
498 }
499
500 GLfloat ground[4] = {0.0, 1.0, 0.0, -0.00001};
501
502 /** reflectionboard */
503 void draw_reflections(void) {
504   int i, j;
505
506   glEnable(GL_STENCIL_TEST);
507   glStencilFunc(GL_ALWAYS, 1, 1);
508   glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
509   glColorMask(0,0,0,0);
510   glDisable(GL_CULL_FACE);
511
512   glDisable(GL_DEPTH_TEST);
513   glBegin(GL_QUADS);
514
515   /* only draw white squares */
516   for(i = 0; i < BOARDSIZE; ++i) {
517     for(j = (BOARDSIZE+i) % 2; j < BOARDSIZE; j += 2) {
518       glVertex3f(i, 0.0, j + 1.0);
519       glVertex3f(i + 1.0, 0.0, j + 1.0);
520       glVertex3f(i + 1.0, 0.0, j);
521       glVertex3f(i, 0.0, j);
522     }
523   }
524   glEnd();
525   glEnable(GL_DEPTH_TEST);
526
527   glColorMask(1, 1, 1, 1);
528   glStencilFunc(GL_EQUAL, 1, 1);
529   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
530   
531   glPushMatrix(); 
532   glScalef(1.0, -1.0, 1.0);
533   glTranslatef(0.5, 0.0, 0.5);
534
535   glLightfv(GL_LIGHT0, GL_POSITION, position);
536   draw_pieces();
537   glPopMatrix();
538   
539   glDisable(GL_STENCIL_TEST);
540   glLightfv(GL_LIGHT0, GL_POSITION, position);
541
542   glEnable(GL_CULL_FACE);
543   glCullFace(GL_BACK);
544   glColorMask(1,1,1,1);
545 }
546
547 /** draws the scene */
548 void display(Chesscreen *c) {
549   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
550
551   glMatrixMode(GL_MODELVIEW);
552   glLoadIdentity();
553
554   /** setup perspectif */
555   glTranslatef(0.0, 0.0, -1.5*BOARDSIZE);
556   glRotatef(30.0, 1.0, 0.0, 0.0);
557   gltrackball_rotate (c->trackball);
558   glRotatef(theta*100, 0.0, 1.0, 0.0);
559   glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
560
561   position[0] = 4.0 + 1.0*-sin(theta*100*M_PI/180.0);
562   position[2] = 4.0 + 1.0*cos(theta*100*M_PI/180.0);
563   position[1] = 5.0;
564
565   position2[0] = 4.0 + 8.0*-sin(theta*100*M_PI/180.0);
566   position2[2] = 4.0 + 8.0*cos(theta*100*M_PI/180.0);
567
568   glEnable(GL_LIGHTING);
569   glLightfv(GL_LIGHT0, GL_POSITION, position);
570   glLightfv(GL_LIGHT1, GL_POSITION, position2);
571   glEnable(GL_LIGHT0);
572
573   /** draw board, pieces */
574   if(!wire) {
575     glEnable(GL_LIGHTING);
576     glEnable(GL_COLOR_MATERIAL);
577
578     if(reflections) {
579       draw_reflections();
580       glEnable(GL_BLEND);
581     }
582
583     glEnable(GL_TEXTURE_2D);
584     glBindTexture(GL_TEXTURE_2D, boardtexture);
585     drawBoard();
586     glDisable(GL_TEXTURE_2D);
587
588     if(shadows) {
589       /* render shadows */
590       GLfloat m[4][4];
591       shadowmatrix(m, ground, position);
592
593       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
594       glEnable(GL_BLEND);
595       glDisable(GL_LIGHTING);
596       glDisable(GL_DEPTH_TEST);
597       
598       /* display ant shadow */
599       glPushMatrix();
600       glTranslatef(0.0, 0.001, 0.0);
601       glMultMatrixf(m[0]);
602       glTranslatef(0.5, 0.01, 0.5);
603       draw_shadow_pieces();
604       glPopMatrix();      
605
606       glEnable(GL_LIGHTING);
607       glDisable(GL_BLEND);
608       glEnable(GL_DEPTH_TEST);
609     }
610
611     if(reflections)
612       glDisable(GL_BLEND);
613   }
614   else
615     drawBoard();
616  
617   glTranslatef(0.5, 0.0, 0.5);
618   draw_pieces();
619
620   if(!wire) {
621     glDisable(GL_COLOR_MATERIAL);
622     glDisable(GL_LIGHTING);
623   }
624
625   if (!c->button_down_p)
626     theta += .002;
627 }
628
629 /** reshape handler */
630 void reshape_chess(ModeInfo *mi, int width, int height) {
631   GLfloat h = (GLfloat) height / (GLfloat) width;
632   glViewport(0,0, width, height);
633   glMatrixMode(GL_PROJECTION);
634   glLoadIdentity();
635   gluPerspective(45, 1/h, 2.0, 30.0);
636   glMatrixMode(GL_MODELVIEW);
637 }
638
639 /** initialization handler */
640 void init_chess(ModeInfo *mi) {
641   Chesscreen *c;
642   int screen = MI_SCREEN(mi);
643   wire = MI_IS_WIREFRAME(mi);
644
645   if(!qs && 
646      !(qs = (Chesscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Chesscreen))))
647     return;
648   
649   c = &qs[screen];
650   c->window = MI_WINDOW(mi);
651   c->trackball = gltrackball_init ();
652   
653   if((c->glx_context = init_GL(mi)))
654     reshape_chess(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
655   else
656     MI_CLEARWINDOW(mi);
657
658   glClearColor(0.0, 0.0, 0.0, 0.0);
659
660   glDepthFunc(GL_LEQUAL);
661   glClearStencil(0);
662   glEnable(GL_CULL_FACE);
663   glCullFace(GL_BACK);
664
665   make_piece_texture();
666   make_board_texture();
667   gen_model_lists();
668
669   if(!wire) {
670     setup_lights();
671     glColorMaterial(GL_FRONT, GL_DIFFUSE);
672     glShadeModel(smooth ? GL_SMOOTH : GL_FLAT);
673     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
674     glEnable(GL_DEPTH_TEST);
675   }
676   else
677     glPolygonMode(GL_FRONT, GL_LINE);
678 }
679
680 int oldgame = -1;
681
682 /** does dirty work drawing scene, moving pieces */
683 void draw_chess(ModeInfo *mi) {
684   Chesscreen *c = &qs[MI_SCREEN(mi)];
685   Window w = MI_WINDOW(mi);
686   Display *disp = MI_DISPLAY(mi);
687
688   if(!c->glx_context)
689     return;
690
691   glXMakeCurrent(disp, w, *(c->glx_context));
692
693   /** code for moving a piece */
694   if(moving && ++steps == 100) {
695     moving = count = steps = take = 0;
696     game.board[game.moves[mc][2]][game.moves[mc][3]] = mpiece;
697     ++mc;
698     
699     if(mc == game.movecount) {
700       done = 1;
701       mc = 0;
702     }
703   }
704
705   if(++count == 100) {
706     if(!done) {
707       mpiece = game.board[game.moves[mc][0]][game.moves[mc][1]];
708       game.board[game.moves[mc][0]][game.moves[mc][1]] = NONE;
709       
710       if((tpiece = game.board[game.moves[mc][2]][game.moves[mc][3]])) {
711         game.board[game.moves[mc][2]][game.moves[mc][3]] = NONE;
712         take = 1;
713       }
714       
715       from[0] = game.moves[mc][0];
716       from[1] = game.moves[mc][1];
717       to[0] = game.moves[mc][2];
718       to[1] = game.moves[mc][3];
719       
720       dz = (to[0] - from[0]) / 100;
721       dx = (to[1] - from[1]) / 100;
722       steps = 0;
723       moving = 1;
724     }
725     else if(done == 1) {
726       int newgame = oldgame;
727       while(newgame == oldgame)
728         newgame = random()%GAMES;
729
730       /* mod the mod */
731       mod = 0.6 + (random()%20)/10.0;
732
733       /* same old game */
734       oldgame = newgame;
735       game = games[oldgame];
736       build_colors();
737       done = 2;
738       count = 0;
739     }
740     else {
741       done = 0;
742       count = 0;
743     }
744   }
745
746   /* set lighting */
747   if(done) {
748     glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 
749              done == 1 ? 1.0+0.1*count : 100.0/count);
750     glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 
751              done == 1 ? 1.0+0.1*count : 100.0/count);
752     glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.14);
753     glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.14);
754   }
755
756   display(c);
757
758   if(mi->fps_p) do_fps(mi);
759   glFinish(); 
760   glXSwapBuffers(disp, w);
761 }
762
763 /** bust it */
764 void release_chess(ModeInfo *mi) {
765   if(qs)
766     free((void *) qs);
767
768   FreeAllGL(MI);
769 }
770
771 #endif