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