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 {(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},
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};
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);
178 /* glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient2); */
180 glLightfv(GL_LIGHT1, GL_SPECULAR, diffuse2);
181 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse2);
186 void drawPieces(void) {
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);
197 glTranslatef(1.0, 0.0, 0.0);
200 glTranslatef(-1.0*BOARDSIZE, 0.0, 1.0);
203 glTranslatef(0.0, 0.0, -1.0*BOARDSIZE);
206 /** draw a moving piece */
207 void drawMovingPiece(void) {
208 int piece = mpiece % PIECES;
211 glColor3fv(colors[mpiece/PIECES]);
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;
223 mpiece = mpiece == PAWN ? QUEEN : BQUEEN;
225 else if(mpiece % PIECES == KNIGHT) {
226 glTranslatef(steps < 50 ? from[1] : to[1], 0.0,
227 steps < 50 ? from[0] : to[0]);
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);
234 glTranslatef(from[1]+steps*dx, 0.0, from[0]+steps*dz);
246 /** code to squish a taken piece */
247 void drawTakePiece(void) {
251 glColor4f(colors[tpiece/7][0], colors[tpiece/7][1], colors[tpiece/7][2],
252 (100-1.6*steps)/100.0);
254 glTranslatef(to[1], 0.0, to[0]);
256 if(mpiece % PIECES == KNIGHT)
257 glScalef(1.0+steps/100.0, 1.0, 1.0+steps/100.0);
259 glScalef(1.0, 1 - steps/50.0 > 0.01 ? 1 - steps/50.0 : 0.01, 1.0);
260 glCallList(tpiece % 7);
267 void drawBoard(void) {
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);
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); */
296 void draw_pieces(void) {
298 if(moving) drawMovingPiece();
299 if(take) drawTakePiece();
302 /** reflectionboard */
303 void draw_reflections(void) {
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);
312 glDisable(GL_DEPTH_TEST);
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);
325 glEnable(GL_DEPTH_TEST);
327 glColorMask(1, 1, 1, 1);
328 glStencilFunc(GL_EQUAL, 1, 1);
329 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
332 glScalef(1.0, -1.0, 1.0);
333 glTranslatef(0.5, 0.0, 0.5);
335 glLightfv(GL_LIGHT0, GL_POSITION, position);
339 glDisable(GL_STENCIL_TEST);
340 glLightfv(GL_LIGHT0, GL_POSITION, position);
342 glEnable(GL_CULL_FACE);
344 glColorMask(1,1,1,1);
347 /** draws the scene */
348 void display(Chesscreen *c) {
349 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
351 glMatrixMode(GL_MODELVIEW);
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);
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);
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);
368 glEnable(GL_LIGHTING);
369 glLightfv(GL_LIGHT0, GL_POSITION, position);
370 glLightfv(GL_LIGHT1, GL_POSITION, position2);
373 /** draw board, pieces */
375 glEnable(GL_LIGHTING);
376 glEnable(GL_COLOR_MATERIAL);
391 glTranslatef(0.5, 0.0, 0.5);
395 glDisable(GL_COLOR_MATERIAL);
396 glDisable(GL_LIGHTING);
399 if (!c->button_down_p)
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);
409 gluPerspective(45, 1/h, 2.0, 30.0);
410 glMatrixMode(GL_MODELVIEW);
413 /** initialization handler */
414 void init_chess(ModeInfo *mi) {
416 int screen = MI_SCREEN(mi);
417 wire = MI_IS_WIREFRAME(mi);
420 !(qs = (Chesscreen *) calloc(MI_NUM_SCREENS(mi), sizeof(Chesscreen))))
424 c->window = MI_WINDOW(mi);
425 c->trackball = gltrackball_init ();
427 if((c->glx_context = init_GL(mi)))
428 reshape_chess(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
432 glClearColor(0.0, 0.0, 0.0, 0.0);
434 glDepthFunc(GL_LEQUAL);
436 glEnable(GL_CULL_FACE);
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);
449 glPolygonMode(GL_FRONT, GL_LINE);
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);
463 glXMakeCurrent(disp, w, *(c->glx_context));
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;
471 if(mc == game.movecount) {
479 mpiece = game.board[game.moves[mc][0]][game.moves[mc][1]];
480 game.board[game.moves[mc][0]][game.moves[mc][1]] = NONE;
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;
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];
492 dz = (to[0] - from[0]) / 100;
493 dx = (to[1] - from[1]) / 100;
498 int newgame = oldgame;
499 while(newgame == oldgame)
500 newgame = random()%GAMES;
504 game = games[oldgame];
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);
527 if(mi->fps_p) do_fps(mi);
529 glXSwapBuffers(disp, w);
533 void release_chess(ModeInfo *mi) {