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