1 /* a 3D chess display for KnightCap
2 
3    Andrew.Tridgell@anu.edu.au January 1997 */
4 
5 #include "includes.h"
6 #include "knightcap.h"
7 
8 extern struct state *state;
9 int need_redraw=1;
10 
11 #if RENDERED_DISPLAY
12 #include <GL/glut.h>
13 #include "trackball.h"
14 
15 static int window_size = 500;
16 
17 #define SLEEP_TIME 100000 /* microseconds */
18 
19 
20 static int do_scaling;
21 static int do_motion;
22 static int mouse_moved;
23 extern int demo_mode;
24 static int downx, downy;
25 
26 /* the pieces don't sit quite on the board - there is a
27    small gap */
28 #define BOARDGAP 0.05
29 
30 #define BOARD1(p) (state->position.board[p])
31 #define BOARD(x,y) BOARD1(POSN(x,y))
32 
33 static float a_color[4] =      {0.75, 0.75, 0.55};
34 static float b_color[4] =      {0.4, 0.4, 0.6};
35 
36 /* traditional white and black squares */
37 static float square_color_1[4] =      {0.7, 0.7, 0.7};
38 /* static float square_color_2[4] =      {0, 0, 0}; */
39 
40 enum {MENU_RESET, MENU_QUIT, MENU_FLIP, MENU_RESET_VIEW, MENU_DEMO,
41       MENU_COMPUTER_WHITE, MENU_COMPUTER_BLACK, MENU_SAVE, MENU_RESTORE,
42       MENU_EVAL};
43 
44 
45 enum {EDIT_NONE, EDIT_RECREATE, EDIT_CLEAR, EDIT_WHITES_MOVE,
46       EDIT_BLACKS_MOVE,
47       EDIT_BPAWN, EDIT_BKNIGHT, EDIT_BBISHOP,
48       EDIT_BROOK, EDIT_BQUEEN, EDIT_BKING,
49       EDIT_WPAWN, EDIT_WKNIGHT, EDIT_WBISHOP,
50       EDIT_WROOK, EDIT_WQUEEN, EDIT_WKING};
51 
52 
53 
54 #define NUM_SLICES 10
55 #define NUM_STACKS 8
56 
57 static int menu_ics_robot, menu_always_think, menu_demo_mode;
58 
redraw(void)59 void redraw(void)
60 {
61 	need_redraw = 1;
62 }
63 
set_cursor(int c)64 static void set_cursor(int c)
65 {
66 	static int last_c;
67 	if (last_c == c) return;
68 	glutSetCursor(c);
69 	last_c = c;
70 }
71 
72 /* this is taken from the glut library */
drawBox(GLfloat x0,GLfloat x1,GLfloat y0,GLfloat y1,GLfloat z0,GLfloat z1)73 static void drawBox(GLfloat x0, GLfloat x1, GLfloat y0, GLfloat y1,
74 		    GLfloat z0, GLfloat z1)
75 {
76 	static GLfloat n[6][3] =
77 	{
78 		{-1.0, 0.0, 0.0},
79 		{0.0, 1.0, 0.0},
80 		{1.0, 0.0, 0.0},
81 		{0.0, -1.0, 0.0},
82 		{0.0, 0.0, 1.0},
83 		{0.0, 0.0, -1.0}
84 	};
85 	static GLint faces[6][4] =
86 	{
87 		{0, 1, 2, 3},
88 		{3, 2, 6, 7},
89 		{7, 6, 5, 4},
90 		{4, 5, 1, 0},
91 		{5, 6, 2, 1},
92 		{7, 4, 0, 3}
93 	};
94 	GLfloat v[8][3];
95 	GLint i;
96 
97 	v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
98 	v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
99 	v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
100 	v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
101 	v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
102 	v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
103 
104 	for (i = 0; i < 6; i++) {
105 		glBegin(GL_QUADS);
106 		glNormal3fv(&n[i][0]);
107 		glVertex3fv(&v[faces[i][0]][0]);
108 		glVertex3fv(&v[faces[i][1]][0]);
109 		glVertex3fv(&v[faces[i][2]][0]);
110 		glVertex3fv(&v[faces[i][3]][0]);
111 		glEnd();
112 	}
113 }
114 
draw_pawn(void)115 static void draw_pawn(void)
116 {
117 	GLUquadricObj *q;
118 	q = gluNewQuadric();
119 	gluCylinder(q, 0.22, 0.1, 0.65, NUM_SLICES, NUM_STACKS);
120 	glTranslatef(0,0,0.6);
121 	glutSolidSphere(0.14,NUM_SLICES,NUM_STACKS);
122 }
123 
draw_rook(void)124 static void draw_rook(void)
125 {
126 	GLUquadricObj *q;
127 
128 	/* the base */
129 	drawBox(-0.25, 0.25, -0.25, 0.25, 0, 0.1);
130 	glTranslatef(0,0,0.1);
131 
132 	/* the torso */
133 	q = gluNewQuadric();
134 	gluCylinder(q, 0.22, 0.16, 0.5, NUM_SLICES, NUM_STACKS);
135 	glTranslatef(0, 0, 0.5);
136 
137 	/* the top */
138 	drawBox(-0.2, 0.2, -0.2, 0.2, 0, 0.1);
139 	glTranslatef(0,0,0.1);
140 
141 	glTranslatef(-0.15, -0.15, 0.05);
142 	glutSolidCube(0.1);
143 	glTranslatef(0.3, 0, 0);
144 	glutSolidCube(0.1);
145 	glTranslatef(0, 0.3, 0);
146 	glutSolidCube(0.1);
147 	glTranslatef(-0.3, 0, 0);
148 	glutSolidCube(0.1);
149 }
150 
draw_bishop(void)151 static void draw_bishop(void)
152 {
153 	GLUquadricObj *q;
154 
155 	glScalef(1.2, 1.2, 1);
156 
157 	/* the torso */
158 	q = gluNewQuadric();
159 	gluCylinder(q, 0.22, 0.12, 0.9, NUM_SLICES, NUM_STACKS);
160 	glTranslatef(0, 0, 0.85);
161 
162 	/* the sash */
163 	glPushMatrix();
164 	glRotatef(-45, 1, 0, 0);
165 	glScalef(1, 1.5, 1);
166 	glutSolidTorus(0.05, 0.12, NUM_SLICES, NUM_STACKS);
167 	glPopMatrix();
168 
169 	/* the shoulders? */
170 	glTranslatef(0, 0, 0.2);
171 	glScalef(1,1,1.5);
172 	glutSolidSphere(0.1, NUM_SLICES, NUM_STACKS);
173 }
174 
draw_queen(void)175 static void draw_queen(void)
176 {
177 	GLUquadricObj *q;
178 	glScalef(1,1,1.15);
179 
180 	/* the base */
181 	glTranslatef(0, 0, 0.07);
182 	glutSolidTorus(0.06, 0.23, NUM_SLICES, NUM_STACKS);
183 
184 	/* the torso */
185 	q = gluNewQuadric();
186 	gluCylinder(q, 0.25, 0.15, 1.0, NUM_SLICES, NUM_STACKS);
187 	glTranslatef(0,0, 0.9);
188 
189 	/* the ruff */
190 	glutSolidTorus(0.08, 0.16, NUM_SLICES, NUM_STACKS);
191 	glTranslatef(0,0, 0.15);
192 
193 	/* the head */
194 	glutSolidSphere(0.15, NUM_SLICES, NUM_STACKS);
195 
196 	/* the crown */
197 	glTranslatef(0,0,0.08);
198 	glutSolidTorus(0.03, 0.13, NUM_SLICES, NUM_SLICES);
199 
200 	/* and a knob on top */
201 	glTranslatef(0,0, 0.07);
202 	glutSolidSphere(0.07, NUM_SLICES/2, NUM_STACKS/2);
203 }
204 
draw_king(void)205 static void draw_king(void)
206 {
207 	GLUquadricObj *q;
208 	q = gluNewQuadric();
209 
210 	/* the base */
211 	drawBox(-0.27, 0.27, -0.27, 0.27, 0, 0.1);
212 	glTranslatef(0,0,0.1);
213 
214 	/* torso and shoulders */
215 	gluCylinder(q, 0.25, 0.15, 1.0, NUM_SLICES, NUM_STACKS);
216 	glTranslatef(0,0,1);
217 	glutSolidTorus(0.07, 0.14, NUM_SLICES, NUM_STACKS);
218 
219 	/* the cross */
220 	drawBox(-0.075, 0.075, -0.075, 0.075, 0, 0.4);
221 	glTranslatef(0,0,0.2);
222 
223 	drawBox(-0.2, 0.2, -0.075, 0.075, -0.07, 0.07);
224 }
225 
226 
draw_knight(void)227 static void draw_knight(void)
228 {
229 	GLUquadricObj *q;
230 	q = gluNewQuadric();
231 
232 
233 	glRotatef(-90,0,0,1);
234 
235 	/* base */
236 	glTranslatef(0,0,0.05);
237 	glutSolidTorus(0.1,0.2,NUM_SLICES,NUM_STACKS);
238 	glTranslatef(0,0,0.1);
239 	glutSolidTorus(0.1,0.2,NUM_SLICES,NUM_STACKS);
240 	glTranslatef(0,0,0.05);
241 
242 	/* torso */
243 	glRotatef(10, 0, 1, 0);
244 	gluCylinder(q, 0.2, 0.15, 0.7, NUM_SLICES, NUM_STACKS);
245 	glTranslatef(0,0, 0.65);
246 
247 	/* head */
248 	glutSolidSphere(0.16, NUM_SLICES, NUM_STACKS);
249 
250 	/* ears */
251 	glPushMatrix();
252 	glRotatef(10, 0, 1, 0);
253 	glRotatef(25, 1, 0, 0);
254 	glTranslatef(0.05,0,0.13);
255 	gluCylinder(q, 0.08, 0.0, 0.15, NUM_SLICES/2, NUM_STACKS/2);
256 	glPopMatrix();
257 
258 	glPushMatrix();
259 	glRotatef(10, 0, 1, 0);
260 	glRotatef(-25, 1, 0, 0);
261 	glTranslatef(0.05,0,0.13);
262 	gluCylinder(q, 0.08, 0, 0.15, NUM_SLICES/2, NUM_STACKS/2);
263 	glPopMatrix();
264 
265 	/* nose */
266 	glRotatef(-110, 0, 1, 0);
267 	gluCylinder(q, 0.17, 0.1, 0.3, NUM_SLICES, NUM_STACKS);
268 	glTranslatef(0,0, 0.3);
269 	glutSolidSphere(0.1, NUM_SLICES, NUM_STACKS);
270 }
271 
272 
273 /* its cute to make the bishops and knights face the opponents king */
face_king(int p,int x,int y)274 static void face_king(int p, int x, int y)
275 {
276 	Square kpos = PIECES(&state->position, -p)[IKING].pos;
277 	double dx, dy, theta;
278 
279 	dx = XPOS(kpos) - x;
280 	dy = YPOS(kpos) - y;
281 
282 	theta = 360*atan(dx/(dy+0.01))/(2*M_PI);
283 
284 	if (dy < 0) theta += 180;
285 
286 	glRotatef(-theta,0,0,1);
287 }
288 
draw_piece(int p,int x,int y)289 static void draw_piece(int p, int x, int y)
290 {
291 	glPushMatrix();
292 	glTranslatef(0.5, 0.5, BOARDGAP);
293 	if (p > 0) {
294 		glColor3fv(a_color);
295 	} else {
296 		glColor3fv(b_color);
297 	}
298 
299 	switch (abs(p)) {
300 	case PAWN:
301 		draw_pawn();
302 		break;
303 	case KNIGHT:
304 		face_king(p, x, y);
305 		draw_knight();
306 		break;
307 	case BISHOP:
308 		face_king(p, x, y);
309 		draw_bishop();
310 		break;
311 	case ROOK:
312 		draw_rook();
313 		break;
314 	case QUEEN:
315 		draw_queen();
316 		break;
317 	case KING:
318 		draw_king();
319 		break;
320 	}
321 
322 	glPopMatrix();
323 }
324 
325 
draw_pieces(void)326 static void draw_pieces(void)
327 {
328 	int i,j;
329 	int p;
330 
331 	for (i=0;i<8;i++)
332 		for (j=0;j<8;j++) {
333 			if (!(p=BOARD(i,j))) continue;
334 			glPushMatrix();
335 			glTranslatef(i,j,0);
336 			draw_piece(p, i, j);
337 			glPopMatrix();
338 		}
339 }
340 
341 /* this draws the board itself - must be called with lighting
342    off (otherwise we'd need to give the squares some depth) */
draw_board(void)343 static void draw_board(void)
344 {
345 	int i, j;
346 
347 	glPushAttrib(GL_ENABLE_BIT);
348 	glDisable(GL_LIGHTING);
349 	glDisable(GL_DITHER);
350 	for (i=0;i<8;i++)
351 		for (j=0;j<8;j++) {
352 			if (!((i+j)&1)) continue;
353 
354 			glPushMatrix();
355 			glTranslatef(i, j, 0);
356 			glColor3fv(square_color_1);
357 			glRectf(0,0,1,1);
358 			glPopMatrix();
359 		}
360 	glEnable(GL_DITHER);
361 	glPopAttrib();
362 }
363 
setup_lighting(void)364 static void setup_lighting(void)
365 {
366 	GLfloat light_position[] = {2, -1, 20.0, 0.0};
367 
368 	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
369 	glEnable(GL_LIGHTING);
370 	glEnable(GL_LIGHT0);
371 
372 	glEnable(GL_COLOR_MATERIAL);
373 	glShadeModel(GL_SMOOTH);
374 }
375 
position_board(void)376 static void position_board(void)
377 {
378 	GLfloat m[4][4];
379 
380 	glScalef(state->scale, state->scale, state->scale);
381 
382 	setup_lighting();
383 
384 	gluPerspective(26, 1, 10, 100);
385 
386 	glMatrixMode(GL_MODELVIEW);
387 
388 	glTranslatef(0, 0, -20);
389 
390 	build_rotmatrix(m, state->curquat);
391 	glMultMatrixf(&m[0][0]);
392 
393 	if (state->flip_view) {
394 		/* its easier to flip the view than to use the trackball */
395 		glRotatef(180, 0, 0, 1);
396 	}
397 
398 	glTranslatef(-4, -4, 0);
399 }
400 
401 /* this starts us at a reasonable viewing angle */
reset_view(void)402 static void reset_view(void)
403 {
404 	state->scale = 1;
405 	state->curquat[0] = 0.28;
406 	state->curquat[1] = 0;
407 	state->curquat[2] = 0;
408 	state->curquat[3] = 0.90;
409 }
410 
411 
draw_all(void)412 void draw_all(void)
413 {
414 	need_redraw = 0;
415 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
416 
417 	glPushMatrix();
418 	glMatrixMode(GL_PROJECTION);
419 	glLoadIdentity();
420 	position_board();
421 	draw_pieces();
422 	draw_board();
423         glPopMatrix();
424 
425 	glutSwapBuffers();
426 }
427 
428 
429 /* check if mouse click at (px,py) is in a square, returning the
430    square in (*rx,*ry) if it is */
in_square(int px,int py,Square * p)431 static int in_square(int px,int py, Square *p)
432 {
433 	int x, y;
434 	int ret;
435 	GLint vp[4];
436 	int squares_only=1;
437 
438 	glGetIntegerv(GL_VIEWPORT, vp);
439 
440         glPushMatrix();
441 
442 again:
443 
444 	for (x=0;x<8;x++)
445 		for (y=0;y<8;y++) {
446 			glFeedbackBuffer(0, GL_2D, NULL);
447 			glRenderMode(GL_FEEDBACK);
448 			glInitNames();
449 			glPushName(~0);
450 			glPushMatrix();
451 			glMatrixMode(GL_PROJECTION);
452 			glLoadIdentity();
453 			gluPickMatrix(px, vp[3] - py, 1, 1, vp);
454 			position_board();
455 			glTranslatef(x, y, 0);
456 			if (!squares_only && BOARD(x,y)) {
457 				draw_piece(BOARD(x,y), x, y);
458 			} else {
459 				glRectf(0, 0, 1, 1);
460 			}
461 			glPopMatrix();
462 
463 			ret = glRenderMode(GL_RENDER);
464 
465 			if (ret != 0) {
466 				(*p) = POSN(x,y);
467 				glPopMatrix();
468 				return 1;
469 			}
470 		}
471 
472 	if (!squares_only) {
473 		squares_only = 1;
474 		goto again;
475 	}
476 
477 	glPopMatrix();
478 
479 	return 0;
480 }
481 
482 
mouse_func(int button,int bstate,int x,int y)483 static void mouse_func(int button, int bstate, int x, int y)
484 {
485 	static Square from, to;
486 	static int do_movement;
487 
488 	if (bstate == GLUT_DOWN && button == GLUT_MIDDLE_BUTTON) {
489 		downx = x;
490 		downy = y;
491 	}
492 
493 	if (bstate == GLUT_DOWN && button == GLUT_LEFT_BUTTON) {
494 		mouse_moved = 0;
495 		downx = x;
496 		downy = y;
497 		if(glutGetModifiers() & GLUT_ACTIVE_SHIFT) {
498 			do_scaling = 1;
499 		} else if (in_square(x,y,&from) && BOARD1(from)) {
500 			do_movement = 1;
501 		} else {
502 			do_motion = 1;
503 		}
504 	}
505 
506 	if (bstate == GLUT_UP && button == GLUT_LEFT_BUTTON) {
507 		do_motion = 0;
508 		do_scaling = 0;
509 		if (do_movement && in_square(x,y,&to) && to != from &&
510 		    next_to_play(&state->position) != state->computer) {
511 			Move move;
512 			move.from = from;
513 			move.to = to;
514 			prog_tell_move(&state->position,&move);
515 			player_moved(from, to);
516 		}
517 		do_movement = 0;
518 	}
519 }
520 
motion_func(int x,int y)521 static void motion_func(int x, int y)
522 {
523 	float lastquat[4];
524 	GLint vp[4];
525 
526 	if (x == downx && y == downy) return;
527 
528 	mouse_moved = 1;
529 
530 	if (!do_motion && !do_scaling) return;
531 
532 	glGetIntegerv(GL_VIEWPORT, vp);
533 
534 	if (do_motion) {
535 		trackball(lastquat,
536 			  (2.0*downx - vp[2]) / vp[2],
537 			  (vp[3] - 2.0*downy) / vp[3],
538 			  (2.0*x - vp[2]) / vp[2],
539 			  (vp[3] - 2.0*y) / vp[3]
540 			  );
541 
542 		add_quats(lastquat, state->curquat, state->curquat);
543 	}
544 
545 	if (do_scaling) {
546 		state->scale *= (1.0 + (((float) (downy - y)) / vp[3]));
547 	}
548 
549 	downx = x;
550 	downy = y;
551 	redraw();
552 }
553 
554 
edit_menu(int v)555 static void edit_menu(int v)
556 {
557 	Square sq;
558 
559 	if (!in_square(downx, downy, &sq))
560 		return;
561 
562 	switch (v) {
563 	case EDIT_NONE:
564 		lprintf(0,"remove at %d %d\n", downx, downy);
565 		state->position.board[sq] = 0;
566 		break;
567 	case EDIT_RECREATE:
568 		lprintf(0,"recreate\n");
569 		create_pboard(&state->position);
570 		break;
571 
572 	case EDIT_CLEAR:
573 		memset(state->position.board, 0,
574 		       sizeof(state->position.board));
575 		break;
576 
577 	case EDIT_WHITES_MOVE:
578 		state->position.move_num &= ~1;
579 		break;
580 
581 	case EDIT_BLACKS_MOVE:
582 		state->position.move_num |= 1;
583 		break;
584 
585 	case EDIT_BPAWN:
586 	case EDIT_BKNIGHT:
587 	case EDIT_BBISHOP:
588 	case EDIT_BROOK:
589 	case EDIT_BQUEEN:
590 	case EDIT_BKING:
591 		lprintf(0,"set black %d at %d %d\n",
592 			v - EDIT_BPAWN, downx, downy);
593 
594 		state->position.board[sq] = -(PAWN + (v - EDIT_BPAWN));
595 		break;
596 
597 	case EDIT_WPAWN:
598 	case EDIT_WKNIGHT:
599 	case EDIT_WBISHOP:
600 	case EDIT_WROOK:
601 	case EDIT_WQUEEN:
602 	case EDIT_WKING:
603 		lprintf(0,"set black %d at %d %d\n",
604 			v - EDIT_WPAWN, downx, downy);
605 
606 		state->position.board[sq] = PAWN + (v - EDIT_WPAWN);
607 		break;
608 	}
609 
610 	redraw();
611 }
612 
613 
main_menu(int v)614 static void main_menu(int v)
615 {
616 	switch (v) {
617 	case MENU_EVAL:
618 		eval_debug(&state->position);
619 		break;
620 
621 	case MENU_SAVE:
622 		save_game("knightcap.save");
623 		break;
624 
625 	case MENU_RESTORE:
626 		restore_game("knightcap.save");
627 		break;
628 
629 	case MENU_DEMO:
630 		demo_mode = !demo_mode;
631 		if (!demo_mode)
632 			state->stop_search = 1;
633 		if (demo_mode) {
634 			glutChangeToMenuEntry(menu_demo_mode,
635 					    "disable demo mode", MENU_DEMO);
636 		} else {
637 			glutChangeToMenuEntry(menu_demo_mode,
638 					    "demo mode", MENU_DEMO);
639 		}
640 		break;
641 
642 	case MENU_QUIT:
643 		state->stop_search = 1;
644 		state->quit = 1;
645 		prog_exit();
646 		exit(0);
647 		break;
648 
649 	case MENU_RESET:
650 		reset_board();
651 		break;
652 
653 	case MENU_RESET_VIEW:
654 		reset_view();
655 		break;
656 
657 	case MENU_FLIP:
658 		state->flip_view = !state->flip_view;
659 		break;
660 	}
661 
662 	redraw();
663 }
664 
665 
computer_menu(int v)666 static void computer_menu(int v)
667 {
668 	if (v == 2) {
669 		state->always_think = !state->always_think;
670 		if (state->always_think) {
671 			glutChangeToMenuEntry(menu_always_think,
672 					    "disable always think",v);
673 		} else {
674 			glutChangeToMenuEntry(menu_always_think,
675 					    "always think", v);
676 		}
677 		return;
678 	}
679 	if (v == 3) {
680 		state->ics_robot = !state->ics_robot;
681 		if (state->ics_robot) {
682 			glutChangeToMenuEntry(menu_ics_robot,
683 					    "disable ICS robot",v);
684 		} else {
685 			glutChangeToMenuEntry(menu_ics_robot,
686 					    "enable ICS robot", v);
687 		}
688 		return;
689 	}
690 	state->stop_search = 1;
691 	state->computer = v;
692 }
693 
move_time_menu(int v)694 static void move_time_menu(int v)
695 {
696 	state->move_time = v;
697 }
698 
create_menus(void)699 static void create_menus(void)
700 {
701 	int comp, undo, redo, move;
702 
703 	comp = glutCreateMenu(computer_menu);
704 	glutAddMenuEntry("computer plays white", PIECE_WHITE);
705 	glutAddMenuEntry("computer plays black", PIECE_BLACK);
706 	glutAddMenuEntry("disable computer", 0);
707 	menu_always_think = 4;
708 	glutAddMenuEntry("always think", 2);
709 	menu_ics_robot = 5;
710 	glutAddMenuEntry("enable ICS robot", 3);
711 
712 	undo = glutCreateMenu(undo_menu);
713 	glutAddMenuEntry("1 move", 1);
714 	glutAddMenuEntry("2 moves", 2);
715 	glutAddMenuEntry("4 moves", 4);
716 	glutAddMenuEntry("8 moves", 8);
717 
718 	redo = glutCreateMenu(undo_menu);
719 	glutAddMenuEntry("1 move", -1);
720 	glutAddMenuEntry("2 moves",-2);
721 	glutAddMenuEntry("4 moves",-4);
722 	glutAddMenuEntry("8 moves",-8);
723 
724 	move = glutCreateMenu(move_time_menu);
725 	glutAddMenuEntry("2  seconds", 2);
726 	glutAddMenuEntry("5  seconds", 5);
727 	glutAddMenuEntry("9  seconds", 9);
728 	glutAddMenuEntry("10 seconds", 10);
729 	glutAddMenuEntry("30 seconds", 30);
730 	glutAddMenuEntry("60 seconds", 60);
731 	glutAddMenuEntry("5  minutes", 300);
732 
733 	glutCreateMenu(main_menu);
734 	glutAddMenuEntry("reset game", MENU_RESET);
735 	glutAddMenuEntry("reset view", MENU_RESET_VIEW);
736 	glutAddMenuEntry("flip view", MENU_FLIP);
737 	menu_demo_mode = 4;
738 	glutAddMenuEntry("demo mode", MENU_DEMO);
739 	glutAddMenuEntry("eval debug", MENU_EVAL);
740 	glutAddSubMenu("computer",comp);
741 	glutAddSubMenu("undo",undo);
742 	glutAddSubMenu("redo",redo);
743 	glutAddSubMenu("move time",move);
744 	glutAddMenuEntry("save game", MENU_SAVE);
745 	glutAddMenuEntry("restore game", MENU_RESTORE);
746 	glutAddMenuEntry("quit", MENU_QUIT);
747 	glutAttachMenu(GLUT_RIGHT_BUTTON);
748 
749 	glutCreateMenu(edit_menu);
750 	glutAddMenuEntry("delete", EDIT_NONE);
751 	glutAddMenuEntry("recreate", EDIT_RECREATE);
752 	glutAddMenuEntry("clear board", EDIT_CLEAR);
753 	glutAddMenuEntry("whites move", EDIT_WHITES_MOVE);
754 	glutAddMenuEntry("blacks move", EDIT_BLACKS_MOVE);
755 	glutAddMenuEntry("black pawn", EDIT_BPAWN);
756 	glutAddMenuEntry("black knight", EDIT_BKNIGHT);
757 	glutAddMenuEntry("black bishop", EDIT_BBISHOP);
758 	glutAddMenuEntry("black rook", EDIT_BROOK);
759 	glutAddMenuEntry("black queen", EDIT_BQUEEN);
760 	glutAddMenuEntry("black king", EDIT_BKING);
761 	glutAddMenuEntry("white pawn", EDIT_WPAWN);
762 	glutAddMenuEntry("white knight", EDIT_WKNIGHT);
763 	glutAddMenuEntry("white bishop", EDIT_WBISHOP);
764 	glutAddMenuEntry("white rook", EDIT_WROOK);
765 	glutAddMenuEntry("white queen", EDIT_WQUEEN);
766 	glutAddMenuEntry("white king", EDIT_WKING);
767 	glutAttachMenu(GLUT_MIDDLE_BUTTON);
768 }
769 
start_display(int argc,char * argv[])770 void start_display(int argc,char *argv[])
771 {
772 	glutInit(&argc, argv);
773 	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
774 
775 	reset_view();
776 
777 	glutCreateWindow("KnightCap");
778 	glutReshapeWindow(window_size, window_size);
779 	glutDisplayFunc(draw_all);
780 	glutMouseFunc(mouse_func);
781 	glutMotionFunc(motion_func);
782 	glutIdleFunc(idle_func);
783 
784 	/* set other relevant state information */
785 	glEnable(GL_DEPTH_TEST);
786 	glEnable(GL_LINE_SMOOTH);
787 
788 	set_cursor(GLUT_CURSOR_CROSSHAIR);
789 	create_menus();
790 
791 	glutMainLoop();
792 }
793 
794 #else
795 
redraw(void)796 void redraw(void)
797 {
798 
799 }
800 
draw_all(void)801 void draw_all(void)
802 {
803 	need_redraw = 0;
804 	print_board(state->position.board);
805 }
806 #endif
807