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