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" \
32 "*reflections: True \n" \
34 # include "xlockmore.h"
43 #include "gltrackball.h"
44 #include "chessmodels.h"
47 #define countof(x) (sizeof((x))/sizeof((*x)))
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" },
58 int rotate, reflections, smooth;
60 static argtype vars[] = {
61 {&rotate, "rotate", "Rotate", "True", t_Bool},
62 {&reflections, "reflections", "Reflections", "True", t_Bool},
63 {&smooth, "smooth", "Smooth", "True", t_Bool},
66 ModeSpecOpt chess_opts = {countof(opts), opts, countof(vars), vars, NULL};
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, "",
78 GLXContext *glx_context;
80 trackball_state *trackball;
84 static Chesscreen *qs = NULL;
92 #define M_PI 3.14159265
97 /** definition of white/black (orange/gray) colors */
98 GLfloat colors[2][3] =
106 /* i prefer silvertip */
107 GLfloat whites[WHITES][3] =
116 #include "chessgames.h"
121 void build_colors(void) {
124 int newwhite = oldwhite;
125 while(newwhite == oldwhite)
126 newwhite = random()%WHITES;
129 colors[0][0] = whites[oldwhite][0];
130 colors[0][1] = whites[oldwhite][1];
131 colors[0][2] = whites[oldwhite][2];
135 int mpiece = 0, tpiece, steps = 0, done = 1;
136 double from[2], to[2];
138 int moving = 0, take = 0, mc = 0, count = 99, wire = 0;
140 /** handle X event (trackball) */
141 Bool chess_handle_event (ModeInfo *mi, XEvent *event) {
142 Chesscreen *c = &qs[MI_SCREEN(mi)];
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));
151 else if(event->xany.type == ButtonRelease
152 && event->xbutton.button & Button1) {
153 c->button_down_p = False;
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));
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 GLfloat shininess[] = {60.0};
171 GLfloat specular[] = {0.4, 0.4, 0.4, 1.0};
173 /* configure lighting */
174 void setup_lights(void) {
175 glEnable(GL_LIGHTING);
176 glLightfv(GL_LIGHT0, GL_POSITION, position);
177 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse2);
180 /* glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient2); */
182 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
183 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
185 glLightfv(GL_LIGHT1, GL_SPECULAR, diffuse2);
186 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse2);
191 void drawPieces(void) {
194 for(i = 0; i < BOARDSIZE; ++i) {
195 for(j = 0; j < BOARDSIZE; ++j) {
196 if(game.board[i][j]) {
197 int c = game.board[i][j]/PIECES;
198 glColor3fv(colors[c]);
199 glCallList(game.board[i][j]%PIECES);
202 glTranslatef(1.0, 0.0, 0.0);
205 glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
208 glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
211 /** draw a moving piece */
212 void drawMovingPiece(void) {
213 int piece = mpiece % PIECES;
216 glColor3fv(colors[mpiece/PIECES]);
218 /** assume a queening. should be more general */
219 if((mpiece == PAWN && fabs(to[0]) < 0.01) ||
220 (mpiece == BPAWN && fabs(to[0]-7.0) < 0.01)) {
221 glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
222 glColor4f(colors[mpiece/7][0], colors[mpiece/7][1], colors[mpiece/7][2],
223 (fabs(50.0-steps))/50.0);
224 piece = steps < 50 ? PAWN : QUEEN;
228 mpiece = mpiece == PAWN ? QUEEN : BQUEEN;
230 else if(mpiece % PIECES == KNIGHT) {
234 glTranslatef(steps < 50 ? from[1] : to[1], 0.0,
235 steps < 50 ? from[0] : to[0]);
238 ? (1.0 - steps / 10.0)
240 ? specular[0] * (1.0 - (100 - steps) / 10.0)
243 shine[0] = 0.0;/*mult*shininess[0];*/
244 spec[0] = mult*specular[0];
245 spec[1] = mult*specular[1];
246 spec[2] = mult*specular[2];
248 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine);
249 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
251 glColor4f(colors[mpiece/7][0], colors[mpiece/7][1], colors[mpiece/7][2],
252 fabs(49-steps)/49.0);
253 glScalef(fabs(49-steps)/49.0, fabs(49-steps)/49.0, fabs(49-steps)/49.0);
256 glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
263 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
264 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
272 /** code to squish a taken piece */
273 void drawTakePiece(void) {
277 glColor4f(colors[tpiece/7][0], colors[tpiece/7][1], colors[tpiece/7][2],
278 (100-1.6*steps)/100.0);
280 glTranslatef(to[1], 0.0, to[0]);
282 if(mpiece % PIECES == KNIGHT)
283 glScalef(1.0+steps/100.0, 1.0, 1.0+steps/100.0);
285 glScalef(1.0, 1 - steps/50.0 > 0.01 ? 1 - steps/50.0 : 0.01, 1.0);
286 glCallList(tpiece % 7);
293 void drawBoard(void) {
298 for(i = 0; i < BOARDSIZE; ++i)
299 for(j = 0; j < BOARDSIZE; ++j) {
300 /*glColor3fv(colors[(i+j)%2]);*/
301 glColor4f(colors[(i+j)%2][0], colors[(i+j)%2][1],
302 colors[(i+j)%2][2], 0.65);
303 glNormal3f(0.0, 1.0, 0.0);
304 glVertex3f(i, 0.0, j + 1.0);
305 glVertex3f(i + 1.0, 0.0, j + 1.0);
306 glVertex3f(i + 1.0, 0.0, j);
307 glVertex3f(i, 0.0, j);
310 /* chop underneath board */
311 /* glColor3f(0, 0, 0); */
312 /* glNormal3f(0, -1, 0); */
313 /* glVertex3f(0, 0, BOARDSIZE); */
314 /* glVertex3f(0, 0, 0); */
315 /* glVertex3f(BOARDSIZE, 0, 0); */
316 /* glVertex3f(BOARDSIZE, 0, BOARDSIZE); */
322 void draw_pieces(void) {
324 if(moving) drawMovingPiece();
325 if(take) drawTakePiece();
328 /** reflectionboard */
329 void draw_reflections(void) {
332 glEnable(GL_STENCIL_TEST);
333 glStencilFunc(GL_ALWAYS, 1, 1);
334 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
335 glColorMask(0,0,0,0);
336 glDisable(GL_CULL_FACE);
338 glDisable(GL_DEPTH_TEST);
341 /* only draw white squares */
342 for(i = 0; i < BOARDSIZE; ++i) {
343 for(j = (BOARDSIZE+i) % 2; j < BOARDSIZE; j += 2) {
344 glVertex3f(i, 0.0, j + 1.0);
345 glVertex3f(i + 1.0, 0.0, j + 1.0);
346 glVertex3f(i + 1.0, 0.0, j);
347 glVertex3f(i, 0.0, j);
351 glEnable(GL_DEPTH_TEST);
353 glColorMask(1, 1, 1, 1);
354 glStencilFunc(GL_EQUAL, 1, 1);
355 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
358 glScalef(1.0, -1.0, 1.0);
359 glTranslatef(0.5, 0.0, 0.5);
361 glLightfv(GL_LIGHT0, GL_POSITION, position);
365 glDisable(GL_STENCIL_TEST);
366 glLightfv(GL_LIGHT0, GL_POSITION, position);
368 glEnable(GL_CULL_FACE);
370 glColorMask(1,1,1,1);
373 /** draws the scene */
374 void display(Chesscreen *c) {
375 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
377 glMatrixMode(GL_MODELVIEW);
380 /** setup perspectif */
381 glTranslatef(0.0, 0.0, -1.5*BOARDSIZE);
382 glRotatef(30.0, 1.0, 0.0, 0.0);
383 gltrackball_rotate (c->trackball);
384 glRotatef(theta*100, 0.0, 1.0, 0.0);
385 glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
387 position[0] = 4.0 + 1.0*-sin(theta*100*M_PI/180.0);
388 position[2] = 4.0 + 1.0*cos(theta*100*M_PI/180.0);
391 position2[0] = 4.0 + 8.0*-sin(theta*100*M_PI/180.0);
392 position2[2] = 4.0 + 8.0*cos(theta*100*M_PI/180.0);
394 glEnable(GL_LIGHTING);
395 glLightfv(GL_LIGHT0, GL_POSITION, position);
396 glLightfv(GL_LIGHT1, GL_POSITION, position2);
399 /** draw board, pieces */
401 glEnable(GL_LIGHTING);
402 glEnable(GL_COLOR_MATERIAL);
417 glTranslatef(0.5, 0.0, 0.5);
421 glDisable(GL_COLOR_MATERIAL);
422 glDisable(GL_LIGHTING);
425 if (!c->button_down_p)
429 /** reshape handler */
430 void reshape_chess(ModeInfo *mi, int width, int height) {
431 GLfloat h = (GLfloat) height / (GLfloat) width;
432 glViewport(0,0, width, height);
433 glMatrixMode(GL_PROJECTION);
435 gluPerspective(45, 1/h, 2.0, 30.0);
436 glMatrixMode(GL_MODELVIEW);
439 /** initialization handler */
440 void init_chess(ModeInfo *mi) {
442 int screen = MI_SCREEN(mi);
443 wire = MI_IS_WIREFRAME(mi);
446 !(qs = (Chesscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Chesscreen))))
450 c->window = MI_WINDOW(mi);
451 c->trackball = gltrackball_init ();
453 if((c->glx_context = init_GL(mi)))
454 reshape_chess(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
458 glClearColor(0.0, 0.0, 0.0, 0.0);
460 glDepthFunc(GL_LEQUAL);
462 glEnable(GL_CULL_FACE);
469 glColorMaterial(GL_FRONT, GL_DIFFUSE);
470 glShadeModel(smooth ? GL_SMOOTH : GL_FLAT);
471 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
472 glEnable(GL_DEPTH_TEST);
475 glPolygonMode(GL_FRONT, GL_LINE);
480 /** does dirty work drawing scene, moving pieces */
481 void draw_chess(ModeInfo *mi) {
482 Chesscreen *c = &qs[MI_SCREEN(mi)];
483 Window w = MI_WINDOW(mi);
484 Display *disp = MI_DISPLAY(mi);
489 glXMakeCurrent(disp, w, *(c->glx_context));
491 /** code for moving a piece */
492 if(moving && ++steps == 100) {
493 moving = count = steps = take = 0;
494 game.board[game.moves[mc][2]][game.moves[mc][3]] = mpiece;
497 if(mc == game.movecount) {
505 mpiece = game.board[game.moves[mc][0]][game.moves[mc][1]];
506 game.board[game.moves[mc][0]][game.moves[mc][1]] = NONE;
508 if((tpiece = game.board[game.moves[mc][2]][game.moves[mc][3]])) {
509 game.board[game.moves[mc][2]][game.moves[mc][3]] = NONE;
513 from[0] = game.moves[mc][0];
514 from[1] = game.moves[mc][1];
515 to[0] = game.moves[mc][2];
516 to[1] = game.moves[mc][3];
518 dz = (to[0] - from[0]) / 100;
519 dx = (to[1] - from[1]) / 100;
524 int newgame = oldgame;
525 while(newgame == oldgame)
526 newgame = random()%GAMES;
530 game = games[oldgame];
543 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION,
544 done == 1 ? 1.0+0.1*count : 100.0/count);
545 glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION,
546 done == 1 ? 1.0+0.1*count : 100.0/count);
547 glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.15);
548 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.15);
553 if(mi->fps_p) do_fps(mi);
555 glXSwapBuffers(disp, w);
559 void release_chess(ModeInfo *mi) {