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