http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.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 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, spidey, spideydark;
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 /* ugggggggly */
89 #define NONE    0
90 #define KING    1
91 #define QUEEN   2
92 #define BISHOP  3 
93 #define KNIGHT  4 
94 #define ROOK    5
95 #define PAWN    6 
96 #define BKING    8
97 #define BQUEEN   9
98 #define BBISHOP  10 
99 #define BKNIGHT  11
100 #define BROOK    12
101 #define BPAWN    13 
102
103 #define BOARDSIZE 8
104 #define PIECES 7
105
106 /* definition of white/black colors */
107 GLfloat colors[2][3] = { {1.0, 0.5, 0.0},
108                          {0.5, 0.5, 0.5} };
109
110 /* int board[8][8] = */
111 /*   { {ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK}, */
112 /*     {PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN}, */
113 /*     {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE}, */
114 /*     {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE}, */
115 /*     {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE}, */
116 /*     {NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE}, */
117 /*     {BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN}, */
118 /*     {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}}; */
119
120 int board[8][8];
121
122 void buildBoard(void) {
123   board[0][5] = BKING;
124   board[1][4] = BPAWN;
125   board[1][2] = BPAWN;
126   board[1][0] = BPAWN;
127   board[2][2] = BPAWN;
128   board[2][4] = BPAWN;
129   board[2][7] = KNIGHT;
130   board[3][0] = PAWN;
131   board[3][2] = ROOK;
132   board[4][0] = PAWN;
133   board[4][4] = KING;
134   board[4][5] = PAWN;
135   board[6][0] = BPAWN;
136   board[6][7] = PAWN;
137   board[7][0] = BBISHOP;
138 }
139
140 #define MOVES 24
141
142 int moves[MOVES][4] = 
143   { {3, 2, 6, 2},
144     {7, 0, 6, 1},
145     {6, 2, 6, 6},
146     {0, 5, 0, 4},
147     {6, 6, 0, 6},
148     {0, 4, 1, 3},
149     {2, 7, 1, 5},
150     {2, 2, 3, 2},
151     {0, 6, 0, 3}, 
152     {1, 3, 2, 2},
153     {0, 3, 6, 3},
154     {3, 2, 4, 2}, /* pawn to bishop 5 */
155     {1, 5, 0, 3}, /* check */
156     {2, 2, 3, 2},
157     {0, 3, 2, 4}, /* takes pawn */
158     {3, 2, 2, 2},
159     {2, 4, 0, 3},
160     {2, 2, 3, 2},
161     {6, 3, 6, 1}, /* rook takes bishop */
162     {6, 0, 7, 0}, /* hack this in! */
163     {6, 1, 3, 1},
164     {3, 2, 2, 3},
165     {3, 1, 3, 3},
166     {0, 0, 2, 3},
167   };
168
169 /* yay its c */
170 int mpiece = 0, tpiece, steps = 0;
171 double mcount = 0.0;
172 double from[2], to[2];
173 double dx, dz;
174 int moving = 0, take = 0, mc = 0, count = 0;
175
176 Bool chess_handle_event (ModeInfo *mi, XEvent *event) {
177   Chesscreen *c = &qs[MI_SCREEN(mi)];
178
179   if(event->xany.type == ButtonPress && event->xbutton.button & Button1) {
180     c->button_down_p = True;
181     gltrackball_start (c->trackball,
182                        event->xbutton.x, event->xbutton.y,
183                        MI_WIDTH (mi), MI_HEIGHT (mi));
184     return True;
185   }
186   else if(event->xany.type == ButtonRelease 
187           && event->xbutton.button & Button1) {
188     c->button_down_p = False;
189     return True;
190   }
191   else if(event->xany.type == MotionNotify && c->button_down_p) {
192     gltrackball_track (c->trackball,
193                        event->xmotion.x, event->xmotion.y,
194                        MI_WIDTH (mi), MI_HEIGHT (mi));
195     return True;
196   }
197   
198   return False;
199 }
200
201 /* clear board */
202 void blank(void) {
203   int i, j;
204
205   for(i = 0; i < BOARDSIZE; ++i)
206     for(j = 0; j < BOARDSIZE; ++j)
207       board[i][j] = NONE;
208 }
209
210 /* configure lighting */
211 void setup_lights(void) {
212   GLfloat position[] = { 0.0, 8.0, 0.0, 1.0 };
213
214   glEnable(GL_LIGHTING);
215   glLightfv(GL_LIGHT0, GL_POSITION, position);
216   glEnable(GL_LIGHT0);
217 }
218
219 /* draw pieces */
220 void drawPieces(void) {
221   int i, j;
222
223   for(i = 0; i < BOARDSIZE; ++i) {
224     for(j = 0; j < BOARDSIZE; ++j) {
225       if(board[i][j]) { 
226         int c = board[i][j]/PIECES;
227         glColor3fv(colors[c]);
228         glCallList(board[i][j]%7);
229       }
230       
231       glTranslatef(1.0, 0.0, 0.0);
232     }
233     
234     glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
235   }
236
237   glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
238 }
239
240 void drawMovingPiece(int wire) {
241   glTranslatef(from[1], 0.0, from[0]);
242   glColor3fv(colors[mpiece/7]);
243
244   /* assume a queening.  should be more general */
245   if((mpiece == PAWN  && fabs(to[0]) < 0.01) || 
246      (mpiece == BPAWN && fabs(to[0]-7.0) < 0.01)) {
247     if(!wire)
248       glEnable(GL_BLEND);
249
250     glColor4f(colors[mpiece/7][0], colors[mpiece/7][1], colors[mpiece/7][2],
251               (fabs(50.0-steps))/50.0);
252     
253     glCallList(steps < 50 ? PAWN : QUEEN);
254
255     /* what a kludge.  yay for side effects */
256     if(steps == 99)
257       mpiece = mpiece == PAWN ? QUEEN : BQUEEN;
258
259     if(!wire)
260       glDisable(GL_BLEND);
261   }
262   else
263     glCallList(mpiece % 7);
264 }
265
266 void drawTakePiece(int wire) {
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] - from[1], 0.0, to[0] - from[0]);
274   glScalef(1.0, 1 - steps/50.0 > 0.01 ? 1 - steps/50.0 : 0.01, 1.0);
275   glCallList(tpiece % 7);
276   
277   if(!wire)
278     glDisable(GL_BLEND);
279 }
280
281 /* draw board */
282 void drawBoard(void) {
283   int i, j;
284
285   for(i = 0; i < BOARDSIZE; ++i)
286     for(j = 0; j < BOARDSIZE; ++j) {
287       glColor3fv(colors[(i+j)%2]);
288       glNormal3f(0.0, 1.0, 0.0);
289
290       glBegin(GL_QUADS);
291
292       glVertex3f(i - 0.5, 0.0, j + 0.5);
293       glVertex3f(i + 0.5, 0.0, j + 0.5);
294       glVertex3f(i + 0.5, 0.0, j - 0.5);
295       glVertex3f(i - 0.5, 0.0, j - 0.5);
296
297       /* draw the bottom, too */
298       glNormal3f(0.0, -1.0, 0.0);
299
300       glVertex3f(i - 0.5, 0.0, j - 0.5);
301       glVertex3f(i + 0.5, 0.0, j - 0.5);
302       glVertex3f(i + 0.5, 0.0, j + 0.5);
303       glVertex3f(i - 0.5, 0.0, j + 0.5);
304
305       glEnd();
306     }
307 }
308
309 #define SQ 0.5
310
311 double theta = 0.0;
312
313 void display(Chesscreen *c, int wire) {
314   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
315
316   glMatrixMode(GL_MODELVIEW);
317   glLoadIdentity();
318
319   glTranslatef(0.0, -3.0+fabs(sin(theta)), -1.3*BOARDSIZE);
320   gltrackball_rotate (c->trackball);
321   glRotatef(theta*100, 0.0, 1.0, 0.0);
322   glTranslatef(-0.5*(BOARDSIZE-1), 0.0, -0.5*(BOARDSIZE-1));
323
324   if(!wire) {
325     glEnable(GL_LIGHTING);
326     glEnable(GL_COLOR_MATERIAL);
327   }
328
329   drawBoard();
330   glTranslatef(0.0, .02, 0.0);
331   drawPieces();
332   if(moving) drawMovingPiece(wire);
333   if(take) drawTakePiece(wire);
334
335   glDisable(GL_COLOR_MATERIAL);
336   glDisable(GL_LIGHTING);
337   
338   theta += .002;
339 }
340
341 void reshape_chess(ModeInfo *mi, int width, int height) {
342   GLfloat h = (GLfloat) height / (GLfloat) width;
343   glViewport(0,0, width, height);
344   glMatrixMode(GL_PROJECTION);
345   glLoadIdentity();
346   gluPerspective(45, 1/h, 2.0, 30.0);
347   glMatrixMode(GL_MODELVIEW);
348 }
349
350 void init_chess(ModeInfo *mi) {
351   GLfloat mat_shininess[] = { 90.0 };
352   GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
353
354   int screen = MI_SCREEN(mi);
355   int wire = MI_IS_WIREFRAME(mi);
356   Chesscreen *c;
357
358   if(!qs && 
359      !(qs = (Chesscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Chesscreen))))
360     return;
361   
362   c = &qs[screen];
363   c->window = MI_WINDOW(mi);
364   c->trackball = gltrackball_init ();
365   
366   if((c->glx_context = init_GL(mi)))
367     reshape_chess(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
368   else
369     MI_CLEARWINDOW(mi);
370
371   glClearColor(0.0, 0.0, 0.0, 0.0);
372
373   glEnable(GL_CULL_FACE);
374   glCullFace(GL_BACK);
375   glLineWidth(1.0);
376   glDepthFunc(GL_LEQUAL);
377
378   setup_lights();
379
380   gen_model_lists();
381
382   if (!wire) {
383     glColorMaterial(GL_FRONT, GL_DIFFUSE);
384
385     glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
386     glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
387     glShadeModel(GL_SMOOTH);
388     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
389     glEnable(GL_DEPTH_TEST);
390   }
391   else
392     glPolygonMode(GL_FRONT, GL_LINE);
393
394   buildBoard();
395 }
396
397 void draw_chess(ModeInfo *mi) {
398   Chesscreen *c = &qs[MI_SCREEN(mi)];
399   Window w = MI_WINDOW(mi);
400   Display *disp = MI_DISPLAY(mi);
401
402   if(!c->glx_context)
403     return;
404
405   glXMakeCurrent(disp, w, *(c->glx_context));
406
407   /* moving code */
408   if(moving) {
409     ++steps;
410     from[0] += dz;
411     from[1] += dx;
412   }
413   
414   if(steps == 100) {
415     moving = count = steps = take = 0;
416     board[moves[mc][2]][moves[mc][3]] = mpiece;
417     ++mc;
418     
419     if(mc == MOVES) {
420       blank();
421       buildBoard();
422       mc = 0;
423     }
424   }
425
426   if(count++ == 100) {
427     moving = 1;
428     mpiece = board[moves[mc][0]][moves[mc][1]];
429     board[moves[mc][0]][moves[mc][1]] = NONE;
430
431     if((tpiece = board[moves[mc][2]][moves[mc][3]]) != NONE) {
432       board[moves[mc][2]][moves[mc][3]] = NONE;
433       take = 1;
434     }
435     
436     mcount = 0.0;
437     from[0] = moves[mc][0];
438     from[1] = moves[mc][1];
439     to[0] = moves[mc][2];
440     to[1] = moves[mc][3];
441     
442     dz = (to[0] - from[0]) / 100;
443     dx = (to[1] - from[1]) / 100;
444     steps = 0;
445   }
446
447   display(c, MI_IS_WIREFRAME(mi));
448
449   if(mi->fps_p) do_fps(mi);
450   glFinish(); 
451   glXSwapBuffers(disp, w);
452 }
453
454 void release_chess(ModeInfo *mi) {
455   if(qs)
456     free((void *) qs);
457
458   FreeAllGL(MI);
459 }
460
461 #endif