3 * plays through a chess game ending. enjoy.
5 * version 1.0 - June 6, 2002
7 * Copyright (C) 2002 Blair Tennessy (tennessb@unbc.ca)
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
18 #include <X11/Intrinsic.h>
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
29 #define DEFAULTS "*delay: 20000 \n" \
30 "*showFPS: False \n" \
31 "*wireframe: False \n" \
33 # include "xlockmore.h"
42 #include "gltrackball.h"
43 #include "chessmodels.h"
46 #define countof(x) (sizeof((x))/sizeof((*x)))
48 static XrmOptionDescRec opts[] = {
49 {"+rotate", ".chess.rotate", XrmoptionNoArg, (caddr_t) "false" },
50 {"-rotate", ".chess.rotate", XrmoptionNoArg, (caddr_t) "true" },
55 static argtype vars[] = {
56 {(caddr_t *) &rotate, "rotate", "Rotate", "True", t_Bool},
59 ModeSpecOpt chess_opts = {countof(opts), opts, countof(vars), vars, NULL};
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, "",
71 GLXContext *glx_context;
73 trackball_state *trackball;
77 static Chesscreen *qs = NULL;
85 #define M_PI 3.14159265
90 /** definition of white/black (orange/gray) colors */
91 GLfloat colors[2][3] =
97 /* well, i prefer silver tip */
98 GLfloat whites[3][3] =
105 /* int board[BOARDSIZE][BOARDSIZE]; */
107 #include "chessgames.h"
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; */
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];
136 /* int moves[MOVES][4] = */
137 /* { {3, 2, 6, 2}, */
148 /* {3, 2, 4, 2}, /\* pawn to bishop 5 *\/ */
149 /* {1, 5, 0, 3}, /\* check *\/ */
151 /* {0, 3, 2, 4}, /\* takes pawn *\/ */
155 /* {6, 3, 6, 1}, /\* rook takes bishop *\/ */
164 int mpiece = 0, tpiece, steps = 0, done = 1;
165 double from[2], to[2];
167 int moving = 0, take = 0, mc = 0, count = 99, wire = 0;
169 /** handle X event (trackball) */
170 Bool chess_handle_event (ModeInfo *mi, XEvent *event) {
171 Chesscreen *c = &qs[MI_SCREEN(mi)];
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));
180 else if(event->xany.type == ButtonRelease
181 && event->xbutton.button & Button1) {
182 c->button_down_p = False;
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));
195 GLfloat position[] = { 3.0, 7.0, 3.0, 1.0 };
197 /* configure lighting */
198 void setup_lights(void) {
199 glEnable(GL_LIGHTING);
200 glLightfv(GL_LIGHT0, GL_POSITION, position);
205 void drawPieces(void) {
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);
216 glTranslatef(1.0, 0.0, 0.0);
219 glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
222 glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
225 /** draw a moving piece */
226 void drawMovingPiece(void) {
227 int piece = mpiece % PIECES;
230 glColor3fv(colors[mpiece/PIECES]);
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;
242 mpiece = mpiece == PAWN ? QUEEN : BQUEEN;
244 else if(mpiece % PIECES == KNIGHT) {
245 glTranslatef(steps < 50 ? from[1] : to[1], 0.0,
246 steps < 50 ? from[0] : to[0]);
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);
253 glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
265 /** code to squish a taken piece */
266 void drawTakePiece(void) {
270 glColor4f(colors[tpiece/7][0], colors[tpiece/7][1], colors[tpiece/7][2],
271 (100-1.6*steps)/100.0);
273 glTranslatef(to[1], 0.0, to[0]);
275 if(mpiece % PIECES == KNIGHT)
276 glScalef(1.0+steps/100.0, 1.0, 1.0+steps/100.0);
278 glScalef(1.0, 1 - steps/50.0 > 0.01 ? 1 - steps/50.0 : 0.01, 1.0);
279 glCallList(tpiece % 7);
286 void drawBoard(void) {
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);
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); */
315 void draw_pieces(void) {
317 if(moving) drawMovingPiece();
318 if(take) drawTakePiece();
321 /** reflectionboard */
322 void draw_reflections(void) {
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);
331 glDisable(GL_DEPTH_TEST);
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);
344 glEnable(GL_DEPTH_TEST);
346 glColorMask(1, 1, 1, 1);
347 glStencilFunc(GL_EQUAL, 1, 1);
348 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
351 glScalef(1.0, -1.0, 1.0);
352 glTranslatef(0.5, 0.0, 0.5);
354 glLightfv(GL_LIGHT0, GL_POSITION, position);
358 glDisable(GL_STENCIL_TEST);
359 glLightfv(GL_LIGHT0, GL_POSITION, position);
361 glEnable(GL_CULL_FACE);
363 glColorMask(1,1,1,1);
366 /** draws the scene */
367 void display(Chesscreen *c) {
368 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
370 glMatrixMode(GL_MODELVIEW);
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);
380 /** draw board, pieces */
382 glEnable(GL_LIGHTING);
383 glEnable(GL_COLOR_MATERIAL);
392 glTranslatef(0.5, 0.0, 0.5);
396 glDisable(GL_COLOR_MATERIAL);
397 glDisable(GL_LIGHTING);
400 if (!c->button_down_p)
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);
410 gluPerspective(45, 1/h, 2.0, 30.0);
411 glMatrixMode(GL_MODELVIEW);
414 /** initialization handler */
415 void init_chess(ModeInfo *mi) {
417 int screen = MI_SCREEN(mi);
418 wire = MI_IS_WIREFRAME(mi);
421 !(qs = (Chesscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Chesscreen))))
425 c->window = MI_WINDOW(mi);
426 c->trackball = gltrackball_init ();
428 if((c->glx_context = init_GL(mi)))
429 reshape_chess(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
433 glClearColor(0.0, 0.0, 0.0, 0.0);
435 glDepthFunc(GL_LEQUAL);
437 glEnable(GL_CULL_FACE);
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);
450 glPolygonMode(GL_FRONT, GL_LINE);
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);
462 glXMakeCurrent(disp, w, *(c->glx_context));
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;
470 if(mc == game.movecount) {
478 mpiece = game.board[game.moves[mc][0]][game.moves[mc][1]];
479 game.board[game.moves[mc][0]][game.moves[mc][1]] = NONE;
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;
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];
491 dz = (to[0] - from[0]) / 100;
492 dx = (to[1] - from[1]) / 100;
497 /* copy over new game */
498 game = games[random()%GAMES];
511 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION,
512 done == 1 ? 1.0+0.1*count : 100.0/count);
516 if(mi->fps_p) do_fps(mi);
518 glXSwapBuffers(disp, w);
522 void release_chess(ModeInfo *mi) {