http://www.archive.org/download/tucows_10294_XScreenSaver/xscreensaver-4.10.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, (caddr_t) "false" },
50   {"-rotate", ".chess.rotate", XrmoptionNoArg, (caddr_t) "true" },
51 };
52
53 int rotate;
54
55 static argtype vars[] = {
56   {(caddr_t *) &rotate, "rotate", "Rotate", "True", t_Bool},
57 };
58
59 ModeSpecOpt chess_opts = {countof(opts), opts, countof(vars), vars, NULL};
60
61 #ifdef USE_MODULES
62 ModStruct   chess_description =
63 {"chess", "init_chess", "draw_chess", "release_chess",
64  "draw_chess", "init_chess", NULL, &chess_opts,
65  1000, 1, 2, 1, 4, 1.0, "",
66  "Chess", 0, NULL};
67
68 #endif
69
70 typedef struct {
71   GLXContext *glx_context;
72   Window window;
73   trackball_state *trackball;
74   Bool button_down_p;
75 } Chesscreen;
76
77 static Chesscreen *qs = NULL;
78
79 #include <math.h>
80 #include <sys/time.h>
81 #include <stdio.h>
82 #include <stdlib.h>
83
84 #ifndef M_PI
85 #define M_PI 3.14159265
86 #endif
87
88 #define BOARDSIZE 8
89
90 /** definition of white/black (orange/gray) colors */
91 GLfloat colors[2][3] = 
92   { 
93     {1.0, 0.5, 0.0},
94     {0.5, 0.5, 0.5},
95   };
96
97 /* well, i prefer silver tip */
98 GLfloat whites[3][3] = 
99   {
100     {1.0, 0.5, 0.0},
101     {0.8, 0.45, 1.0},
102     {0.37, 0.56, 0.87},   
103   };
104
105 /* int board[BOARDSIZE][BOARDSIZE]; */
106
107 #include "chessgames.h"
108
109 ChessGame game;
110
111 /* void buildBoard(void) { */
112 /*   board[0][5] = BKING; */
113 /*   board[1][4] = BPAWN; */
114 /*   board[1][2] = BPAWN; */
115 /*   board[1][0] = BPAWN; */
116 /*   board[2][2] = BPAWN; */
117 /*   board[2][4] = BPAWN; */
118 /*   board[2][7] = KNIGHT; */
119 /*   board[3][0] = PAWN; */
120 /*   board[3][2] = ROOK; */
121 /*   board[4][0] = PAWN; */
122 /*   board[4][4] = KING; */
123 /*   board[4][5] = PAWN; */
124 /*   board[6][0] = BPAWN; */
125 /*   board[6][7] = PAWN; */
126 /*   board[7][0] = BBISHOP; */
127 /* } */
128
129 void build_colors(void) {
130   int white = random()%3;
131   colors[0][0] = whites[white][0];
132   colors[0][1] = whites[white][1];
133   colors[0][2] = whites[white][2];
134 }
135
136 /* int moves[MOVES][4] =  */
137 /*   { {3, 2, 6, 2}, */
138 /*     {7, 0, 6, 1}, */
139 /*     {6, 2, 6, 6}, */
140 /*     {0, 5, 0, 4}, */
141 /*     {6, 6, 0, 6}, */
142 /*     {0, 4, 1, 3}, */
143 /*     {2, 7, 1, 5}, */
144 /*     {2, 2, 3, 2}, */
145 /*     {0, 6, 0, 3},  */
146 /*     {1, 3, 2, 2}, */
147 /*     {0, 3, 6, 3}, */
148 /*     {3, 2, 4, 2}, /\* pawn to bishop 5 *\/ */
149 /*     {1, 5, 0, 3}, /\* check *\/ */
150 /*     {2, 2, 3, 2}, */
151 /*     {0, 3, 2, 4}, /\* takes pawn *\/ */
152 /*     {3, 2, 2, 2}, */
153 /*     {2, 4, 0, 3}, */
154 /*     {2, 2, 3, 2}, */
155 /*     {6, 3, 6, 1}, /\* rook takes bishop *\/ */
156 /*     {6, 0, 7, 0}, */
157 /*     {6, 1, 3, 1}, */
158 /*     {3, 2, 2, 3}, */
159 /*     {3, 1, 3, 3}, */
160 /*     {0, 0, 2, 3}, */
161 /*   }; */
162
163 /* yay its c */
164 int mpiece = 0, tpiece, steps = 0, done = 1;
165 double from[2], to[2];
166 double dx, dz;
167 int moving = 0, take = 0, mc = 0, count = 99, wire = 0;
168
169 /** handle X event (trackball) */
170 Bool chess_handle_event (ModeInfo *mi, XEvent *event) {
171   Chesscreen *c = &qs[MI_SCREEN(mi)];
172
173   if(event->xany.type == ButtonPress && event->xbutton.button & Button1) {
174     c->button_down_p = True;
175     gltrackball_start (c->trackball,
176                        event->xbutton.x, event->xbutton.y,
177                        MI_WIDTH (mi), MI_HEIGHT (mi));
178     return True;
179   }
180   else if(event->xany.type == ButtonRelease 
181           && event->xbutton.button & Button1) {
182     c->button_down_p = False;
183     return True;
184   }
185   else if(event->xany.type == MotionNotify && c->button_down_p) {
186     gltrackball_track (c->trackball,
187                        event->xmotion.x, event->xmotion.y,
188                        MI_WIDTH (mi), MI_HEIGHT (mi));
189     return True;
190   }
191   
192   return False;
193 }
194
195 GLfloat position[] = { 3.0, 7.0, 3.0, 1.0 };
196
197 /* configure lighting */
198 void setup_lights(void) {
199   glEnable(GL_LIGHTING);
200   glLightfv(GL_LIGHT0, GL_POSITION, position);
201   glEnable(GL_LIGHT0);
202 }
203
204 /** draw pieces */
205 void drawPieces(void) {
206   int i, j;
207
208   for(i = 0; i < BOARDSIZE; ++i) {
209     for(j = 0; j < BOARDSIZE; ++j) {
210       if(game.board[i][j]) {    
211         int c = game.board[i][j]/PIECES;
212         glColor3fv(colors[c]);
213         glCallList(game.board[i][j]%PIECES);
214       }
215       
216       glTranslatef(1.0, 0.0, 0.0);
217     }
218     
219     glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
220   }
221
222   glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
223 }
224
225 /** draw a moving piece */
226 void drawMovingPiece(void) {
227   int piece = mpiece % PIECES;
228
229   glPushMatrix();
230   glColor3fv(colors[mpiece/PIECES]);
231
232   /** assume a queening.  should be more general */
233   if((mpiece == PAWN  && fabs(to[0]) < 0.01) || 
234      (mpiece == BPAWN && fabs(to[0]-7.0) < 0.01)) {
235     glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
236     glColor4f(colors[mpiece/7][0], colors[mpiece/7][1], colors[mpiece/7][2],
237               (fabs(50.0-steps))/50.0);
238     piece = steps < 50 ? PAWN : QUEEN;
239
240     /* what a kludge */
241     if(steps == 99)
242       mpiece = mpiece == PAWN ? QUEEN : BQUEEN;
243   }
244   else if(mpiece % PIECES == KNIGHT) {
245     glTranslatef(steps < 50 ? from[1] : to[1], 0.0, 
246                  steps < 50 ? from[0] : to[0]);
247
248     glColor4f(colors[mpiece/7][0], colors[mpiece/7][1], colors[mpiece/7][2],
249               fabs(49-steps)/49.0);
250     glScalef(fabs(49-steps)/49.0, fabs(49-steps)/49.0, fabs(49-steps)/49.0);
251   }
252   else
253     glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
254
255   if(!wire)
256     glEnable(GL_BLEND);
257   
258   glCallList(piece);
259   glPopMatrix();
260
261   if(!wire)
262     glDisable(GL_BLEND);
263 }
264
265 /** code to squish a taken piece */
266 void drawTakePiece(void) {
267   if(!wire)
268     glEnable(GL_BLEND);
269
270   glColor4f(colors[tpiece/7][0], colors[tpiece/7][1], colors[tpiece/7][2],
271             (100-1.6*steps)/100.0);
272
273   glTranslatef(to[1], 0.0, to[0]);
274   
275   if(mpiece % PIECES == KNIGHT)
276     glScalef(1.0+steps/100.0, 1.0, 1.0+steps/100.0);
277   else
278     glScalef(1.0, 1 - steps/50.0 > 0.01 ? 1 - steps/50.0 : 0.01, 1.0);
279   glCallList(tpiece % 7);
280   
281   if(!wire)
282     glDisable(GL_BLEND);
283 }
284
285 /** draw board */
286 void drawBoard(void) {
287   int i, j;
288
289   glBegin(GL_QUADS);
290
291   for(i = 0; i < BOARDSIZE; ++i)
292     for(j = 0; j < BOARDSIZE; ++j) {
293       /*glColor3fv(colors[(i+j)%2]);*/
294       glColor4f(colors[(i+j)%2][0], colors[(i+j)%2][1],
295                 colors[(i+j)%2][2], 0.65);
296       glNormal3f(0.0, 1.0, 0.0);
297       glVertex3f(i, 0.0, j + 1.0);
298       glVertex3f(i + 1.0, 0.0, j + 1.0);
299       glVertex3f(i + 1.0, 0.0, j);
300       glVertex3f(i, 0.0, j);
301     }
302
303   /* chop underneath board */
304 /*   glColor3f(0, 0, 0); */
305 /*   glNormal3f(0, -1, 0); */
306 /*   glVertex3f(0,         0,  BOARDSIZE); */
307 /*   glVertex3f(0,         0,  0); */
308 /*   glVertex3f(BOARDSIZE, 0,  0); */
309 /*   glVertex3f(BOARDSIZE, 0,  BOARDSIZE); */
310   glEnd();
311 }
312
313 double theta = 0.0;
314
315 void draw_pieces(void) {
316   drawPieces();
317   if(moving) drawMovingPiece();
318   if(take) drawTakePiece();
319 }
320
321 /** reflectionboard */
322 void draw_reflections(void) {
323   int i, j;
324
325   glEnable(GL_STENCIL_TEST);
326   glStencilFunc(GL_ALWAYS, 1, 1);
327   glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
328   glColorMask(0,0,0,0);
329   glDisable(GL_CULL_FACE);
330
331   glDisable(GL_DEPTH_TEST);
332   glBegin(GL_QUADS);
333
334   /* only draw white squares */
335   for(i = 0; i < BOARDSIZE; ++i) {
336     for(j = (BOARDSIZE+i) % 2; j < BOARDSIZE; j += 2) {
337       glVertex3f(i, 0.0, j + 1.0);
338       glVertex3f(i + 1.0, 0.0, j + 1.0);
339       glVertex3f(i + 1.0, 0.0, j);
340       glVertex3f(i, 0.0, j);
341     }
342   }
343   glEnd();
344   glEnable(GL_DEPTH_TEST);
345
346   glColorMask(1, 1, 1, 1);
347   glStencilFunc(GL_EQUAL, 1, 1);
348   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
349   
350   glPushMatrix(); 
351   glScalef(1.0, -1.0, 1.0);
352   glTranslatef(0.5, 0.0, 0.5);
353
354   glLightfv(GL_LIGHT0, GL_POSITION, position);
355   draw_pieces();
356   glPopMatrix();
357   
358   glDisable(GL_STENCIL_TEST);
359   glLightfv(GL_LIGHT0, GL_POSITION, position);
360
361   glEnable(GL_CULL_FACE);
362   glCullFace(GL_BACK);
363   glColorMask(1,1,1,1);
364 }
365
366 /** draws the scene */
367 void display(Chesscreen *c) {
368   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
369
370   glMatrixMode(GL_MODELVIEW);
371   glLoadIdentity();
372
373   /** setup perspectif */
374   glTranslatef(0.0, 0.0, -1.5*BOARDSIZE);
375   glRotatef(30.0, 1.0, 0.0, 0.0);
376   gltrackball_rotate (c->trackball);
377   glRotatef(theta*100, 0.0, 1.0, 0.0);
378   glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
379
380   /** draw board, pieces */
381   if(!wire) {
382     glEnable(GL_LIGHTING);
383     glEnable(GL_COLOR_MATERIAL);
384     draw_reflections();
385     glEnable(GL_BLEND);
386     drawBoard();
387     glDisable(GL_BLEND);
388   }
389   else
390     drawBoard();
391  
392   glTranslatef(0.5, 0.0, 0.5);
393   draw_pieces();
394
395   if(!wire) {
396     glDisable(GL_COLOR_MATERIAL);
397     glDisable(GL_LIGHTING);
398   }
399
400   if (!c->button_down_p)
401     theta += .002;
402 }
403
404 /** reshape handler */
405 void reshape_chess(ModeInfo *mi, int width, int height) {
406   GLfloat h = (GLfloat) height / (GLfloat) width;
407   glViewport(0,0, width, height);
408   glMatrixMode(GL_PROJECTION);
409   glLoadIdentity();
410   gluPerspective(45, 1/h, 2.0, 30.0);
411   glMatrixMode(GL_MODELVIEW);
412 }
413
414 /** initialization handler */
415 void init_chess(ModeInfo *mi) {
416   Chesscreen *c;
417   int screen = MI_SCREEN(mi);
418   wire = MI_IS_WIREFRAME(mi);
419
420   if(!qs && 
421      !(qs = (Chesscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Chesscreen))))
422     return;
423   
424   c = &qs[screen];
425   c->window = MI_WINDOW(mi);
426   c->trackball = gltrackball_init ();
427   
428   if((c->glx_context = init_GL(mi)))
429     reshape_chess(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
430   else
431     MI_CLEARWINDOW(mi);
432
433   glClearColor(0.0, 0.0, 0.0, 0.0);
434
435   glDepthFunc(GL_LEQUAL);
436   glClearStencil(0);
437   glEnable(GL_CULL_FACE);
438   glCullFace(GL_BACK);
439
440   gen_model_lists();
441
442   if(!wire) {
443     setup_lights();
444     glColorMaterial(GL_FRONT, GL_DIFFUSE);
445     glShadeModel(GL_SMOOTH);
446     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
447     glEnable(GL_DEPTH_TEST);
448   }
449   else
450     glPolygonMode(GL_FRONT, GL_LINE);
451 }
452
453 /** does dirty work drawing scene, moving pieces */
454 void draw_chess(ModeInfo *mi) {
455   Chesscreen *c = &qs[MI_SCREEN(mi)];
456   Window w = MI_WINDOW(mi);
457   Display *disp = MI_DISPLAY(mi);
458
459   if(!c->glx_context)
460     return;
461
462   glXMakeCurrent(disp, w, *(c->glx_context));
463
464   /** code for moving a piece */
465   if(moving && ++steps == 100) {
466     moving = count = steps = take = 0;
467     game.board[game.moves[mc][2]][game.moves[mc][3]] = mpiece;
468     ++mc;
469     
470     if(mc == game.movecount) {
471       done = 1;
472       mc = 0;
473     }
474   }
475
476   if(++count == 100) {
477     if(!done) {
478       mpiece = game.board[game.moves[mc][0]][game.moves[mc][1]];
479       game.board[game.moves[mc][0]][game.moves[mc][1]] = NONE;
480       
481       if((tpiece = game.board[game.moves[mc][2]][game.moves[mc][3]])) {
482         game.board[game.moves[mc][2]][game.moves[mc][3]] = NONE;
483         take = 1;
484       }
485       
486       from[0] = game.moves[mc][0];
487       from[1] = game.moves[mc][1];
488       to[0] = game.moves[mc][2];
489       to[1] = game.moves[mc][3];
490       
491       dz = (to[0] - from[0]) / 100;
492       dx = (to[1] - from[1]) / 100;
493       steps = 0;
494       moving = 1;
495     }
496     else if(done == 1) {
497       /* copy over new game */
498       game = games[random()%GAMES];
499       build_colors();
500       done = 2;
501       count = 0;
502     }
503     else {
504       done = 0;
505       count = 0;
506     }
507   }
508
509   /* set lighting */
510   if(done)
511     glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 
512              done == 1 ? 1.0+0.1*count : 100.0/count);
513
514   display(c);
515
516   if(mi->fps_p) do_fps(mi);
517   glFinish(); 
518   glXSwapBuffers(disp, w);
519 }
520
521 /** bust it */
522 void release_chess(ModeInfo *mi) {
523   if(qs)
524     free((void *) qs);
525
526   FreeAllGL(MI);
527 }
528
529 #endif