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" \
35 # include "xlockmore.h"
44 #include "gltrackball.h"
45 #include "chessmodels.h"
48 #define countof(x) (sizeof((x))/sizeof((*x)))
50 static XrmOptionDescRec opts[] = {
51 {"+rotate", ".chess.rotate", XrmoptionNoArg, "false" },
52 {"-rotate", ".chess.rotate", XrmoptionNoArg, "true" },
53 {"+reflections", ".chess.reflections", XrmoptionNoArg, "false" },
54 {"-reflections", ".chess.reflections", XrmoptionNoArg, "true" },
55 {"+shadows", ".chess.shadows", XrmoptionNoArg, "false" },
56 {"-shadows", ".chess.shadows", XrmoptionNoArg, "true" },
57 {"+smooth", ".chess.smooth", XrmoptionNoArg, "false" },
58 {"-smooth", ".chess.smooth", XrmoptionNoArg, "true" },
61 int rotate, reflections, smooth, shadows;
63 static argtype vars[] = {
64 {&rotate, "rotate", "Rotate", "True", t_Bool},
65 {&reflections, "reflections", "Reflections", "True", t_Bool},
66 {&shadows, "shadows", "Shadows", "True", t_Bool},
67 {&smooth, "smooth", "Smooth", "True", t_Bool},
70 ModeSpecOpt chess_opts = {countof(opts), opts, countof(vars), vars, NULL};
73 ModStruct chess_description =
74 {"chess", "init_chess", "draw_chess", "release_chess",
75 "draw_chess", "init_chess", NULL, &chess_opts,
76 1000, 1, 2, 1, 4, 1.0, "",
82 GLXContext *glx_context;
84 trackball_state *trackball;
88 static Chesscreen *qs = NULL;
96 #define M_PI 3.14159265
101 static float MaterialShadow[] = {0.0, 0.0, 0.0, 0.3};
105 /** definition of white/black (orange/gray) colors */
106 GLfloat colors[2][3] =
114 /* i prefer silvertip */
115 GLfloat whites[WHITES][3] =
124 #include "chessgames.h"
129 void build_colors(void) {
132 int newwhite = oldwhite;
133 while(newwhite == oldwhite)
134 newwhite = random()%WHITES;
137 colors[0][0] = whites[oldwhite][0];
138 colors[0][1] = whites[oldwhite][1];
139 colors[0][2] = whites[oldwhite][2];
143 #define checkImageWidth 16
144 #define checkImageHeight 16
145 GLubyte checkImage[checkImageWidth][checkImageHeight][3];
146 GLuint piecetexture, boardtexture;
148 /* build piece texture */
149 void make_piece_texture(void) {
152 for (i = 0; i < checkImageWidth; i++) {
153 for (j = 0; j < checkImageHeight; j++) {
154 c = ((j%2) == 0 || i%2 == 0) ? 240 : 180+random()%16;
155 checkImage[i][j][0] = (GLubyte) c;
156 checkImage[i][j][1] = (GLubyte) c;
157 checkImage[i][j][2] = (GLubyte) c;
161 glGenTextures(1, &piecetexture);
162 glBindTexture(GL_TEXTURE_2D, piecetexture);
164 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
165 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
166 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
167 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
168 glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth,
169 checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
173 /* build board texture (uniform noise in [180,180+50]) */
174 void make_board_texture(void) {
177 for (i = 0; i < checkImageWidth; i++) {
178 for (j = 0; j < checkImageHeight; j++) {
179 c = 180 + random()%51;
180 checkImage[i][j][0] = (GLubyte) c;
181 checkImage[i][j][1] = (GLubyte) c;
182 checkImage[i][j][2] = (GLubyte) c;
186 glGenTextures(1, &boardtexture);
187 glBindTexture(GL_TEXTURE_2D, boardtexture);
189 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
190 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
191 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
192 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
193 glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth,
194 checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
199 int mpiece = 0, tpiece, steps = 0, done = 1;
200 double from[2], to[2];
202 int moving = 0, take = 0, mc = 0, count = 99, wire = 0;
205 /** handle X event (trackball) */
206 Bool chess_handle_event (ModeInfo *mi, XEvent *event) {
207 Chesscreen *c = &qs[MI_SCREEN(mi)];
209 if(event->xany.type == ButtonPress && event->xbutton.button & Button1) {
210 c->button_down_p = True;
211 gltrackball_start (c->trackball,
212 event->xbutton.x, event->xbutton.y,
213 MI_WIDTH (mi), MI_HEIGHT (mi));
216 else if(event->xany.type == ButtonRelease
217 && event->xbutton.button & Button1) {
218 c->button_down_p = False;
221 else if(event->xany.type == MotionNotify && c->button_down_p) {
222 gltrackball_track (c->trackball,
223 event->xmotion.x, event->xmotion.y,
224 MI_WIDTH (mi), MI_HEIGHT (mi));
231 GLfloat position[] = { 0.0, 5.0, 5.0, 1.0 };
232 GLfloat position2[] = { 5.0, 5.0, 5.0, 1.0 };
233 GLfloat diffuse2[] = {1.0, 1.0, 1.0, 1.0};
234 GLfloat ambient2[] = {0.7, 0.7, 0.7, 1.0};
235 GLfloat shininess[] = {60.0};
236 GLfloat specular[] = {0.4, 0.4, 0.4, 1.0};
238 /* configure lighting */
239 void setup_lights(void) {
240 glEnable(GL_LIGHTING);
241 glLightfv(GL_LIGHT0, GL_POSITION, position);
242 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse2);
245 /* glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient2); */
247 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
248 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
250 glLightfv(GL_LIGHT1, GL_SPECULAR, diffuse2);
251 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse2);
256 void drawPieces(void) {
259 for(i = 0; i < BOARDSIZE; ++i) {
260 for(j = 0; j < BOARDSIZE; ++j) {
261 if(game.board[i][j]) {
262 int c = game.board[i][j]/PIECES;
263 glColor3fv(colors[c]);
264 glCallList(game.board[i][j]%PIECES);
267 glTranslatef(1.0, 0.0, 0.0);
270 glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
273 glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
277 void drawPiecesShadow(void) {
280 for(i = 0; i < BOARDSIZE; ++i) {
281 for(j = 0; j < BOARDSIZE; ++j) {
282 if(game.board[i][j]) {
283 glColor4f(0.0, 0.0, 0.0, 0.4);
284 glCallList(game.board[i][j]%PIECES);
287 glTranslatef(1.0, 0.0, 0.0);
290 glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
293 glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
296 /* draw a moving piece */
297 void drawMovingPiece(int shadow) {
298 int piece = mpiece % PIECES;
302 if(shadow) glColor4fv(MaterialShadow);
303 else glColor3fv(colors[mpiece/PIECES]);
305 /** assume a queening. should be more general */
306 if((mpiece == PAWN && fabs(to[0]) < 0.01) ||
307 (mpiece == BPAWN && fabs(to[0]-7.0) < 0.01)) {
308 glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
310 glColor4f(shadow ? MaterialShadow[0] : colors[mpiece/7][0],
311 shadow ? MaterialShadow[1] : colors[mpiece/7][1],
312 shadow ? MaterialShadow[2] : colors[mpiece/7][2],
313 (fabs(50.0-steps))/50.0);
315 piece = steps < 50 ? PAWN : QUEEN;
319 mpiece = mpiece == PAWN ? QUEEN : BQUEEN;
321 else if(mpiece % PIECES == KNIGHT) {
325 glTranslatef(steps < 50 ? from[1] : to[1], 0.0,
326 steps < 50 ? from[0] : to[0]);
329 ? (1.0 - steps / 10.0) : 100 - steps < 10
330 ? (1.0 - (100 - steps) / 10.0) : 0.0;
332 shine[0] = mult*shininess[0];
333 spec[0] = mult*specular[0];
334 spec[1] = mult*specular[1];
335 spec[2] = mult*specular[2];
337 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine);
338 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
340 glColor4f(shadow ? MaterialShadow[0] : colors[mpiece/7][0],
341 shadow ? MaterialShadow[1] : colors[mpiece/7][1],
342 shadow ? MaterialShadow[2] : colors[mpiece/7][2],
343 fabs(49-steps)/49.0);
345 glScalef(fabs(49-steps)/49.0, fabs(49-steps)/49.0, fabs(49-steps)/49.0);
348 glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
355 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
356 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
364 /** code to squish a taken piece */
365 void drawTakePiece(int shadow) {
369 glColor4f(shadow ? MaterialShadow[0] : colors[tpiece/7][0],
370 shadow ? MaterialShadow[1] : colors[tpiece/7][1],
371 shadow ? MaterialShadow[0] : colors[tpiece/7][2],
372 (100-1.6*steps)/100.0);
374 glTranslatef(to[1], 0.0, to[0]);
376 if(mpiece % PIECES == KNIGHT)
377 glScalef(1.0+steps/100.0, 1.0, 1.0+steps/100.0);
379 glScalef(1.0, 1 - steps/50.0 > 0.01 ? 1 - steps/50.0 : 0.01, 1.0);
380 glCallList(tpiece % 7);
389 void drawBoard(void) {
394 for(i = 0; i < BOARDSIZE; ++i)
395 for(j = 0; j < BOARDSIZE; ++j) {
396 double ma1 = (i+j)%2 == 0 ? mod*i : 0.0;
397 double mb1 = (i+j)%2 == 0 ? mod*j : 0.0;
398 double ma2 = (i+j)%2 == 0 ? mod*(i+1.0) : 0.01;
399 double mb2 = (i+j)%2 == 0 ? mod*(j+1.0) : 0.01;
401 /*glColor3fv(colors[(i+j)%2]);*/
402 glColor4f(colors[(i+j)%2][0], colors[(i+j)%2][1],
403 colors[(i+j)%2][2], 0.65);
405 glNormal3f(0.0, 1.0, 0.0);
406 /* glTexCoord2f(mod*i, mod*(j+1.0)); */
407 glTexCoord2f(ma1, mb2);
408 glVertex3f(i, 0.0, j + 1.0);
409 /* glTexCoord2f(mod*(i+1.0), mod*(j+1.0)); */
410 glTexCoord2f(ma2, mb2);
411 glVertex3f(i + 1.0, 0.0, j + 1.0);
412 glTexCoord2f(ma2, mb1);
413 /* glTexCoord2f(mod*(i+1.0), mod*j); */
414 glVertex3f(i + 1.0, 0.0, j);
415 glTexCoord2f(ma1, mb1);
416 /* glTexCoord2f(mod*i, mod*j); */
417 glVertex3f(i, 0.0, j);
420 /* chop underneath board */
421 /* glColor3f(0, 0, 0); */
422 /* glNormal3f(0, -1, 0); */
423 /* glVertex3f(0, 0, BOARDSIZE); */
424 /* glVertex3f(0, 0, 0); */
425 /* glVertex3f(BOARDSIZE, 0, 0); */
426 /* glVertex3f(BOARDSIZE, 0, BOARDSIZE); */
430 void draw_pieces(void) {
431 glEnable(GL_TEXTURE_2D);
432 glBindTexture(GL_TEXTURE_2D, piecetexture);
433 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
435 glColor4f(0.5, 0.5, 0.5, 1.0);
436 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
439 if(moving) drawMovingPiece(0);
440 if(take) drawTakePiece(0);
441 glDisable(GL_TEXTURE_2D);
444 void draw_shadow_pieces(void) {
445 glEnable(GL_TEXTURE_2D);
446 glBindTexture(GL_TEXTURE_2D, piecetexture);
447 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
451 if(moving) drawMovingPiece(shadows);
452 if(take) drawTakePiece(shadows);
453 glDisable(GL_TEXTURE_2D);
459 /* create a matrix that will project the desired shadow */
460 void shadowmatrix(GLfloat shadowMat[4][4],
461 GLfloat groundplane[4],
462 GLfloat lightpos[4]) {
465 /* find dot product between light position vector and ground plane normal */
466 dot = groundplane[X] * lightpos[X] +
467 groundplane[Y] * lightpos[Y] +
468 groundplane[Z] * lightpos[Z] +
469 groundplane[W] * lightpos[W];
471 shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
472 shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
473 shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
474 shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];
476 shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
477 shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
478 shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
479 shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];
481 shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
482 shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
483 shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
484 shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];
486 shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
487 shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
488 shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
489 shadowMat[3][3] = dot - lightpos[W] * groundplane[W];
492 GLfloat ground[4] = {0.0, 1.0, 0.0, -0.00001};
494 /** reflectionboard */
495 void draw_reflections(void) {
498 glEnable(GL_STENCIL_TEST);
499 glStencilFunc(GL_ALWAYS, 1, 1);
500 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
501 glColorMask(0,0,0,0);
502 glDisable(GL_CULL_FACE);
504 glDisable(GL_DEPTH_TEST);
507 /* only draw white squares */
508 for(i = 0; i < BOARDSIZE; ++i) {
509 for(j = (BOARDSIZE+i) % 2; j < BOARDSIZE; j += 2) {
510 glVertex3f(i, 0.0, j + 1.0);
511 glVertex3f(i + 1.0, 0.0, j + 1.0);
512 glVertex3f(i + 1.0, 0.0, j);
513 glVertex3f(i, 0.0, j);
517 glEnable(GL_DEPTH_TEST);
519 glColorMask(1, 1, 1, 1);
520 glStencilFunc(GL_EQUAL, 1, 1);
521 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
524 glScalef(1.0, -1.0, 1.0);
525 glTranslatef(0.5, 0.0, 0.5);
527 glLightfv(GL_LIGHT0, GL_POSITION, position);
531 glDisable(GL_STENCIL_TEST);
532 glLightfv(GL_LIGHT0, GL_POSITION, position);
534 glEnable(GL_CULL_FACE);
536 glColorMask(1,1,1,1);
539 /** draws the scene */
540 void display(Chesscreen *c) {
541 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
543 glMatrixMode(GL_MODELVIEW);
546 /** setup perspectif */
547 glTranslatef(0.0, 0.0, -1.5*BOARDSIZE);
548 glRotatef(30.0, 1.0, 0.0, 0.0);
549 gltrackball_rotate (c->trackball);
550 glRotatef(theta*100, 0.0, 1.0, 0.0);
551 glTranslatef(-0.5*BOARDSIZE, 0.0, -0.5*BOARDSIZE);
553 position[0] = 4.0 + 1.0*-sin(theta*100*M_PI/180.0);
554 position[2] = 4.0 + 1.0*cos(theta*100*M_PI/180.0);
557 position2[0] = 4.0 + 8.0*-sin(theta*100*M_PI/180.0);
558 position2[2] = 4.0 + 8.0*cos(theta*100*M_PI/180.0);
560 glEnable(GL_LIGHTING);
561 glLightfv(GL_LIGHT0, GL_POSITION, position);
562 glLightfv(GL_LIGHT1, GL_POSITION, position2);
565 /** draw board, pieces */
567 glEnable(GL_LIGHTING);
568 glEnable(GL_COLOR_MATERIAL);
575 glEnable(GL_TEXTURE_2D);
576 glBindTexture(GL_TEXTURE_2D, boardtexture);
578 glDisable(GL_TEXTURE_2D);
583 shadowmatrix(m, ground, position);
585 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialShadow);
587 glDisable(GL_LIGHTING);
588 glDisable(GL_DEPTH_TEST);
590 /* display ant shadow */
592 glTranslatef(0.0, 0.001, 0.0);
594 glTranslatef(0.5, 0.01, 0.5);
595 draw_shadow_pieces();
598 glEnable(GL_LIGHTING);
600 glEnable(GL_DEPTH_TEST);
609 glTranslatef(0.5, 0.0, 0.5);
613 glDisable(GL_COLOR_MATERIAL);
614 glDisable(GL_LIGHTING);
617 if (!c->button_down_p)
621 /** reshape handler */
622 void reshape_chess(ModeInfo *mi, int width, int height) {
623 GLfloat h = (GLfloat) height / (GLfloat) width;
624 glViewport(0,0, width, height);
625 glMatrixMode(GL_PROJECTION);
627 gluPerspective(45, 1/h, 2.0, 30.0);
628 glMatrixMode(GL_MODELVIEW);
631 /** initialization handler */
632 void init_chess(ModeInfo *mi) {
634 int screen = MI_SCREEN(mi);
635 wire = MI_IS_WIREFRAME(mi);
638 !(qs = (Chesscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Chesscreen))))
642 c->window = MI_WINDOW(mi);
643 c->trackball = gltrackball_init ();
645 if((c->glx_context = init_GL(mi)))
646 reshape_chess(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
650 glClearColor(0.0, 0.0, 0.0, 0.0);
652 glDepthFunc(GL_LEQUAL);
654 glEnable(GL_CULL_FACE);
657 make_piece_texture();
658 make_board_texture();
663 glColorMaterial(GL_FRONT, GL_DIFFUSE);
664 glShadeModel(smooth ? GL_SMOOTH : GL_FLAT);
665 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
666 glEnable(GL_DEPTH_TEST);
669 glPolygonMode(GL_FRONT, GL_LINE);
674 /** does dirty work drawing scene, moving pieces */
675 void draw_chess(ModeInfo *mi) {
676 Chesscreen *c = &qs[MI_SCREEN(mi)];
677 Window w = MI_WINDOW(mi);
678 Display *disp = MI_DISPLAY(mi);
683 glXMakeCurrent(disp, w, *(c->glx_context));
685 /** code for moving a piece */
686 if(moving && ++steps == 100) {
687 moving = count = steps = take = 0;
688 game.board[game.moves[mc][2]][game.moves[mc][3]] = mpiece;
691 if(mc == game.movecount) {
699 mpiece = game.board[game.moves[mc][0]][game.moves[mc][1]];
700 game.board[game.moves[mc][0]][game.moves[mc][1]] = NONE;
702 if((tpiece = game.board[game.moves[mc][2]][game.moves[mc][3]])) {
703 game.board[game.moves[mc][2]][game.moves[mc][3]] = NONE;
707 from[0] = game.moves[mc][0];
708 from[1] = game.moves[mc][1];
709 to[0] = game.moves[mc][2];
710 to[1] = game.moves[mc][3];
712 dz = (to[0] - from[0]) / 100;
713 dx = (to[1] - from[1]) / 100;
718 int newgame = oldgame;
719 while(newgame == oldgame)
720 newgame = random()%GAMES;
723 mod = 0.6 + (random()%20)/10.0;
727 game = games[oldgame];
740 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION,
741 done == 1 ? 1.0+0.1*count : 100.0/count);
742 glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION,
743 done == 1 ? 1.0+0.1*count : 100.0/count);
744 glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.14);
745 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.14);
750 if(mi->fps_p) do_fps(mi);
752 glXSwapBuffers(disp, w);
756 void release_chess(ModeInfo *mi) {