You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1487 lines
31KB

  1. //
  2. // "$Id: glpuzzle.cxx 8033 2010-12-15 12:11:16Z AlbrechtS $"
  3. //
  4. // OpenGL puzzle demo for the Fast Light Tool Kit (FLTK).
  5. //
  6. // This is a GLUT demo program to demonstrate fltk's GLUT emulation.
  7. // Search for "fltk" to find all the changes
  8. //
  9. // Copyright 1998-2010 by Bill Spitzak and others.
  10. //
  11. // This library is free software; you can redistribute it and/or
  12. // modify it under the terms of the GNU Library General Public
  13. // License as published by the Free Software Foundation; either
  14. // version 2 of the License, or (at your option) any later version.
  15. //
  16. // This library is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. // Library General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU Library General Public
  22. // License along with this library; if not, write to the Free Software
  23. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  24. // USA.
  25. //
  26. // Please report all bugs and problems on the following page:
  27. //
  28. // http://www.fltk.org/str.php
  29. //
  30. // this block added for fltk's distribtion so it will compile w/o OpenGL:
  31. #include <config.h>
  32. #if !HAVE_GL || !HAVE_GL_GLU_H
  33. #include <FL/Fl.H>
  34. #include <FL/fl_message.H>
  35. int main(int, char**) {
  36. fl_alert("This demo does not work without GL and GLU");
  37. return 1;
  38. }
  39. #else
  40. // end of added block
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <sys/types.h>
  45. #include <time.h>
  46. #include <math.h>
  47. #include <FL/glut.H> // changed for fltk
  48. #include <FL/glu.h> // added for fltk
  49. #include "trackball.c" // changed from trackball.h for fltk
  50. #define WIDTH 4
  51. #define HEIGHT 5
  52. #define PIECES 10
  53. #define OFFSETX -2
  54. #define OFFSETY -2.5
  55. #define OFFSETZ -0.5
  56. typedef char Config[HEIGHT][WIDTH];
  57. struct puzzle {
  58. struct puzzle *backptr;
  59. struct puzzle *solnptr;
  60. Config pieces;
  61. struct puzzle *next;
  62. unsigned hashvalue;
  63. };
  64. #define HASHSIZE 10691
  65. struct puzzlelist {
  66. struct puzzle *puzzle;
  67. struct puzzlelist *next;
  68. };
  69. static char convert[PIECES + 1] =
  70. {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4};
  71. static unsigned char colors[PIECES + 1][3] =
  72. {
  73. {0, 0, 0},
  74. {255, 255, 127},
  75. {255, 255, 127},
  76. {255, 255, 127},
  77. {255, 255, 127},
  78. {255, 127, 255},
  79. {255, 127, 255},
  80. {255, 127, 255},
  81. {255, 127, 255},
  82. {255, 127, 127},
  83. {255, 255, 255},
  84. };
  85. void changeState(void);
  86. static struct puzzle *hashtable[HASHSIZE];
  87. static struct puzzle *startPuzzle;
  88. static struct puzzlelist *puzzles;
  89. static struct puzzlelist *lastentry;
  90. int curX, curY, visible;
  91. #define MOVE_SPEED 0.2
  92. static unsigned char movingPiece;
  93. static float move_x, move_y;
  94. static float curquat[4];
  95. static int doubleBuffer = 1;
  96. static int depth = 1;
  97. static char xsize[PIECES + 1] =
  98. {0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2};
  99. static char ysize[PIECES + 1] =
  100. {0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 2};
  101. static float zsize[PIECES + 1] =
  102. {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.6};
  103. static Config startConfig =
  104. {
  105. {8, 10, 10, 7},
  106. {8, 10, 10, 7},
  107. {6, 9, 9, 5},
  108. {6, 4, 3, 5},
  109. {2, 0, 0, 1}
  110. };
  111. static Config thePuzzle =
  112. {
  113. {8, 10, 10, 7},
  114. {8, 10, 10, 7},
  115. {6, 9, 9, 5},
  116. {6, 4, 3, 5},
  117. {2, 0, 0, 1}
  118. };
  119. static int xadds[4] =
  120. {-1, 0, 1, 0};
  121. static int yadds[4] =
  122. {0, -1, 0, 1};
  123. static long W = 400, H = 300;
  124. static GLint viewport[4];
  125. #define srandom srand
  126. #define random() (rand() >> 2)
  127. unsigned
  128. hash(Config config)
  129. {
  130. int i, j, value;
  131. value = 0;
  132. for (i = 0; i < HEIGHT; i++) {
  133. for (j = 0; j < WIDTH; j++) {
  134. value = value + convert[(int)config[i][j]];
  135. value *= 6;
  136. }
  137. }
  138. return (value);
  139. }
  140. int
  141. solution(Config config)
  142. {
  143. if (config[4][1] == 10 && config[4][2] == 10)
  144. return (1);
  145. return (0);
  146. }
  147. float boxcoords[][3] =
  148. {
  149. {0.2, 0.2, 0.9},
  150. {0.8, 0.2, 0.9},
  151. {0.8, 0.8, 0.9},
  152. {0.2, 0.8, 0.9},
  153. {0.2, 0.1, 0.8},
  154. {0.8, 0.1, 0.8},
  155. {0.9, 0.2, 0.8},
  156. {0.9, 0.8, 0.8},
  157. {0.8, 0.9, 0.8},
  158. {0.2, 0.9, 0.8},
  159. {0.1, 0.8, 0.8},
  160. {0.1, 0.2, 0.8},
  161. {0.2, 0.1, 0.2},
  162. {0.8, 0.1, 0.2},
  163. {0.9, 0.2, 0.2},
  164. {0.9, 0.8, 0.2},
  165. {0.8, 0.9, 0.2},
  166. {0.2, 0.9, 0.2},
  167. {0.1, 0.8, 0.2},
  168. {0.1, 0.2, 0.2},
  169. {0.2, 0.2, 0.1},
  170. {0.8, 0.2, 0.1},
  171. {0.8, 0.8, 0.1},
  172. {0.2, 0.8, 0.1},
  173. };
  174. float boxnormals[][3] =
  175. {
  176. {0, 0, 1}, /* 0 */
  177. {0, 1, 0},
  178. {1, 0, 0},
  179. {0, 0, -1},
  180. {0, -1, 0},
  181. {-1, 0, 0},
  182. {0.7071, 0.7071, 0.0000}, /* 6 */
  183. {0.7071, -0.7071, 0.0000},
  184. {-0.7071, 0.7071, 0.0000},
  185. {-0.7071, -0.7071, 0.0000},
  186. {0.7071, 0.0000, 0.7071}, /* 10 */
  187. {0.7071, 0.0000, -0.7071},
  188. {-0.7071, 0.0000, 0.7071},
  189. {-0.7071, 0.0000, -0.7071},
  190. {0.0000, 0.7071, 0.7071}, /* 14 */
  191. {0.0000, 0.7071, -0.7071},
  192. {0.0000, -0.7071, 0.7071},
  193. {0.0000, -0.7071, -0.7071},
  194. {0.5774, 0.5774, 0.5774}, /* 18 */
  195. {0.5774, 0.5774, -0.5774},
  196. {0.5774, -0.5774, 0.5774},
  197. {0.5774, -0.5774, -0.5774},
  198. {-0.5774, 0.5774, 0.5774},
  199. {-0.5774, 0.5774, -0.5774},
  200. {-0.5774, -0.5774, 0.5774},
  201. {-0.5774, -0.5774, -0.5774},
  202. };
  203. int boxfaces[][4] =
  204. {
  205. {0, 1, 2, 3}, /* 0 */
  206. {9, 8, 16, 17},
  207. {6, 14, 15, 7},
  208. {20, 23, 22, 21},
  209. {12, 13, 5, 4},
  210. {19, 11, 10, 18},
  211. {7, 15, 16, 8}, /* 6 */
  212. {13, 14, 6, 5},
  213. {18, 10, 9, 17},
  214. {19, 12, 4, 11},
  215. {1, 6, 7, 2}, /* 10 */
  216. {14, 21, 22, 15},
  217. {11, 0, 3, 10},
  218. {20, 19, 18, 23},
  219. {3, 2, 8, 9}, /* 14 */
  220. {17, 16, 22, 23},
  221. {4, 5, 1, 0},
  222. {20, 21, 13, 12},
  223. {2, 7, 8, -1}, /* 18 */
  224. {16, 15, 22, -1},
  225. {5, 6, 1, -1},
  226. {13, 21, 14, -1},
  227. {10, 3, 9, -1},
  228. {18, 17, 23, -1},
  229. {11, 4, 0, -1},
  230. {20, 12, 19, -1},
  231. };
  232. #define NBOXFACES (sizeof(boxfaces)/sizeof(boxfaces[0]))
  233. /* Draw a box. Bevel as desired. */
  234. void
  235. drawBox(int piece, float xoff, float yoff)
  236. {
  237. int xlen, ylen;
  238. int i, k;
  239. float x, y, z;
  240. float zlen;
  241. float *v;
  242. xlen = xsize[piece];
  243. ylen = ysize[piece];
  244. zlen = zsize[piece];
  245. glColor3ubv(colors[piece]);
  246. glBegin(GL_QUADS);
  247. for (i = 0; i < 18; i++) {
  248. glNormal3fv(boxnormals[i]);
  249. for (k = 0; k < 4; k++) {
  250. if (boxfaces[i][k] == -1)
  251. continue;
  252. v = boxcoords[boxfaces[i][k]];
  253. x = v[0] + OFFSETX;
  254. if (v[0] > 0.5)
  255. x += xlen - 1;
  256. y = v[1] + OFFSETY;
  257. if (v[1] > 0.5)
  258. y += ylen - 1;
  259. z = v[2] + OFFSETZ;
  260. if (v[2] > 0.5)
  261. z += zlen - 1;
  262. glVertex3f(xoff + x, yoff + y, z);
  263. }
  264. }
  265. glEnd();
  266. glBegin(GL_TRIANGLES);
  267. for (i = 18; i < int(NBOXFACES); i++) {
  268. glNormal3fv(boxnormals[i]);
  269. for (k = 0; k < 3; k++) {
  270. if (boxfaces[i][k] == -1)
  271. continue;
  272. v = boxcoords[boxfaces[i][k]];
  273. x = v[0] + OFFSETX;
  274. if (v[0] > 0.5)
  275. x += xlen - 1;
  276. y = v[1] + OFFSETY;
  277. if (v[1] > 0.5)
  278. y += ylen - 1;
  279. z = v[2] + OFFSETZ;
  280. if (v[2] > 0.5)
  281. z += zlen - 1;
  282. glVertex3f(xoff + x, yoff + y, z);
  283. }
  284. }
  285. glEnd();
  286. }
  287. float containercoords[][3] =
  288. {
  289. {-0.1, -0.1, 1.0},
  290. {-0.1, -0.1, -0.1},
  291. {4.1, -0.1, -0.1},
  292. {4.1, -0.1, 1.0},
  293. {1.0, -0.1, 0.6}, /* 4 */
  294. {3.0, -0.1, 0.6},
  295. {1.0, -0.1, 0.0},
  296. {3.0, -0.1, 0.0},
  297. {1.0, 0.0, 0.0}, /* 8 */
  298. {3.0, 0.0, 0.0},
  299. {3.0, 0.0, 0.6},
  300. {1.0, 0.0, 0.6},
  301. {0.0, 0.0, 1.0}, /* 12 */
  302. {4.0, 0.0, 1.0},
  303. {4.0, 0.0, 0.0},
  304. {0.0, 0.0, 0.0},
  305. {0.0, 5.0, 0.0}, /* 16 */
  306. {0.0, 5.0, 1.0},
  307. {4.0, 5.0, 1.0},
  308. {4.0, 5.0, 0.0},
  309. {-0.1, 5.1, -0.1}, /* 20 */
  310. {4.1, 5.1, -0.1},
  311. {4.1, 5.1, 1.0},
  312. {-0.1, 5.1, 1.0},
  313. };
  314. float containernormals[][3] =
  315. {
  316. {0, -1, 0},
  317. {0, -1, 0},
  318. {0, -1, 0},
  319. {0, -1, 0},
  320. {0, -1, 0},
  321. {0, 1, 0},
  322. {0, 1, 0},
  323. {0, 1, 0},
  324. {1, 0, 0},
  325. {1, 0, 0},
  326. {1, 0, 0},
  327. {-1, 0, 0},
  328. {-1, 0, 0},
  329. {-1, 0, 0},
  330. {0, 1, 0},
  331. {0, 0, -1},
  332. {0, 0, -1},
  333. {0, 0, 1},
  334. {0, 0, 1},
  335. {0, 0, 1},
  336. {0, 0, 1},
  337. {0, 0, 1},
  338. {0, 0, 1},
  339. {0, 0, 1},
  340. };
  341. int containerfaces[][4] =
  342. {
  343. {1, 6, 4, 0},
  344. {0, 4, 5, 3},
  345. {1, 2, 7, 6},
  346. {7, 2, 3, 5},
  347. {16, 19, 18, 17},
  348. {23, 22, 21, 20},
  349. {12, 11, 8, 15},
  350. {10, 13, 14, 9},
  351. {15, 16, 17, 12},
  352. {2, 21, 22, 3},
  353. {6, 8, 11, 4},
  354. {1, 0, 23, 20},
  355. {14, 13, 18, 19},
  356. {9, 7, 5, 10},
  357. {12, 13, 10, 11},
  358. {1, 20, 21, 2},
  359. {4, 11, 10, 5},
  360. {15, 8, 19, 16},
  361. {19, 8, 9, 14},
  362. {8, 6, 7, 9},
  363. {0, 3, 13, 12},
  364. {13, 3, 22, 18},
  365. {18, 22, 23, 17},
  366. {17, 23, 0, 12},
  367. };
  368. #define NCONTFACES (sizeof(containerfaces)/sizeof(containerfaces[0]))
  369. /* Draw the container */
  370. void
  371. drawContainer(void)
  372. {
  373. int i, k;
  374. float *v;
  375. /* Y is reversed here because the model has it reversed */
  376. /* Arbitrary bright wood-like color */
  377. glColor3ub(209, 103, 23);
  378. glBegin(GL_QUADS);
  379. for (i = 0; i < int(NCONTFACES); i++) {
  380. v = containernormals[i];
  381. glNormal3f(v[0], -v[1], v[2]);
  382. for (k = 3; k >= 0; k--) {
  383. v = containercoords[containerfaces[i][k]];
  384. glVertex3f(v[0] + OFFSETX, -(v[1] + OFFSETY), v[2] + OFFSETZ);
  385. }
  386. }
  387. glEnd();
  388. }
  389. void
  390. drawAll(void)
  391. {
  392. int i, j;
  393. int piece;
  394. char done[PIECES + 1];
  395. float m[4][4];
  396. build_rotmatrix(m, curquat);
  397. glMatrixMode(GL_MODELVIEW);
  398. glLoadIdentity();
  399. glTranslatef(0, 0, -10);
  400. glMultMatrixf(&(m[0][0]));
  401. glRotatef(180, 0, 0, 1);
  402. if (depth) {
  403. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  404. } else {
  405. glClear(GL_COLOR_BUFFER_BIT);
  406. }
  407. for (i = 1; i <= PIECES; i++) {
  408. done[i] = 0;
  409. }
  410. glLoadName(0);
  411. drawContainer();
  412. for (i = 0; i < HEIGHT; i++) {
  413. for (j = 0; j < WIDTH; j++) {
  414. piece = thePuzzle[i][j];
  415. if (piece == 0)
  416. continue;
  417. if (done[piece])
  418. continue;
  419. done[piece] = 1;
  420. glLoadName(piece);
  421. if (piece == movingPiece) {
  422. drawBox(piece, move_x, move_y);
  423. } else {
  424. drawBox(piece, j, i);
  425. }
  426. }
  427. }
  428. }
  429. void
  430. redraw(void)
  431. {
  432. glMatrixMode(GL_PROJECTION);
  433. glLoadIdentity();
  434. gluPerspective(45, viewport[2]*1.0/viewport[3], 0.1, 100.0);
  435. drawAll();
  436. if (doubleBuffer)
  437. glutSwapBuffers();
  438. else
  439. glFinish();
  440. }
  441. void
  442. solidifyChain(struct puzzle *puzzle)
  443. {
  444. int i;
  445. char buf[256];
  446. i = 0;
  447. while (puzzle->backptr) {
  448. i++;
  449. puzzle->backptr->solnptr = puzzle;
  450. puzzle = puzzle->backptr;
  451. }
  452. sprintf(buf, "%d moves to complete!", i);
  453. glutSetWindowTitle(buf);
  454. }
  455. int
  456. addConfig(Config config, struct puzzle *back)
  457. {
  458. unsigned hashvalue;
  459. struct puzzle *newpiece;
  460. struct puzzlelist *newlistentry;
  461. hashvalue = hash(config);
  462. newpiece = hashtable[hashvalue % HASHSIZE];
  463. while (newpiece != NULL) {
  464. if (newpiece->hashvalue == hashvalue) {
  465. int i, j;
  466. for (i = 0; i < WIDTH; i++) {
  467. for (j = 0; j < HEIGHT; j++) {
  468. if (convert[(int)config[j][i]] !=
  469. convert[(int)newpiece->pieces[j][i]])
  470. goto nomatch;
  471. }
  472. }
  473. return 0;
  474. }
  475. nomatch:
  476. newpiece = newpiece->next;
  477. }
  478. newpiece = (struct puzzle *) malloc(sizeof(struct puzzle));
  479. newpiece->next = hashtable[hashvalue % HASHSIZE];
  480. newpiece->hashvalue = hashvalue;
  481. memcpy(newpiece->pieces, config, HEIGHT * WIDTH);
  482. newpiece->backptr = back;
  483. newpiece->solnptr = NULL;
  484. hashtable[hashvalue % HASHSIZE] = newpiece;
  485. newlistentry = (struct puzzlelist *) malloc(sizeof(struct puzzlelist));
  486. newlistentry->puzzle = newpiece;
  487. newlistentry->next = NULL;
  488. if (lastentry) {
  489. lastentry->next = newlistentry;
  490. } else {
  491. puzzles = newlistentry;
  492. }
  493. lastentry = newlistentry;
  494. if (back == NULL) {
  495. startPuzzle = newpiece;
  496. }
  497. if (solution(config)) {
  498. solidifyChain(newpiece);
  499. return 1;
  500. }
  501. return 0;
  502. }
  503. /* Checks if a space can move */
  504. int
  505. canmove0(Config pieces, int x, int y, int dir, Config newpieces)
  506. {
  507. char piece;
  508. int xadd, yadd;
  509. int l, m;
  510. xadd = xadds[dir];
  511. yadd = yadds[dir];
  512. if (x + xadd < 0 || x + xadd >= WIDTH ||
  513. y + yadd < 0 || y + yadd >= HEIGHT)
  514. return 0;
  515. piece = pieces[y + yadd][x + xadd];
  516. if (piece == 0)
  517. return 0;
  518. memcpy(newpieces, pieces, HEIGHT * WIDTH);
  519. for (l = 0; l < WIDTH; l++) {
  520. for (m = 0; m < HEIGHT; m++) {
  521. if (newpieces[m][l] == piece)
  522. newpieces[m][l] = 0;
  523. }
  524. }
  525. xadd = -xadd;
  526. yadd = -yadd;
  527. for (l = 0; l < WIDTH; l++) {
  528. for (m = 0; m < HEIGHT; m++) {
  529. if (pieces[m][l] == piece) {
  530. int newx, newy;
  531. newx = l + xadd;
  532. newy = m + yadd;
  533. if (newx < 0 || newx >= WIDTH ||
  534. newy < 0 || newy >= HEIGHT)
  535. return 0;
  536. if (newpieces[newy][newx] != 0)
  537. return 0;
  538. newpieces[newy][newx] = piece;
  539. }
  540. }
  541. }
  542. return 1;
  543. }
  544. /* Checks if a piece can move */
  545. int
  546. canmove(Config pieces, int x, int y, int dir, Config newpieces)
  547. {
  548. int xadd, yadd;
  549. xadd = xadds[dir];
  550. yadd = yadds[dir];
  551. if (x + xadd < 0 || x + xadd >= WIDTH ||
  552. y + yadd < 0 || y + yadd >= HEIGHT)
  553. return 0;
  554. if (pieces[y + yadd][x + xadd] == pieces[y][x]) {
  555. return canmove(pieces, x + xadd, y + yadd, dir, newpieces);
  556. }
  557. if (pieces[y + yadd][x + xadd] != 0)
  558. return 0;
  559. return canmove0(pieces, x + xadd, y + yadd, (dir + 2) % 4, newpieces);
  560. }
  561. int
  562. generateNewConfigs(struct puzzle *puzzle)
  563. {
  564. int i, j, k;
  565. Config pieces;
  566. Config newpieces;
  567. memcpy(pieces, puzzle->pieces, HEIGHT * WIDTH);
  568. for (i = 0; i < WIDTH; i++) {
  569. for (j = 0; j < HEIGHT; j++) {
  570. if (pieces[j][i] == 0) {
  571. for (k = 0; k < 4; k++) {
  572. if (canmove0(pieces, i, j, k, newpieces)) {
  573. if (addConfig(newpieces, puzzle))
  574. return 1;
  575. }
  576. }
  577. }
  578. }
  579. }
  580. return 0;
  581. }
  582. void
  583. freeSolutions(void)
  584. {
  585. struct puzzlelist *nextpuz;
  586. struct puzzle *puzzle, *next;
  587. int i;
  588. while (puzzles) {
  589. nextpuz = puzzles->next;
  590. free((char *) puzzles);
  591. puzzles = nextpuz;
  592. }
  593. lastentry = NULL;
  594. for (i = 0; i < HASHSIZE; i++) {
  595. puzzle = hashtable[i];
  596. hashtable[i] = NULL;
  597. while (puzzle) {
  598. next = puzzle->next;
  599. free((char *) puzzle);
  600. puzzle = next;
  601. }
  602. }
  603. startPuzzle = NULL;
  604. }
  605. int
  606. continueSolving(void)
  607. {
  608. struct puzzle *nextpuz;
  609. int i, j;
  610. int movedPiece;
  611. int movedir;
  612. int fromx, fromy;
  613. int tox, toy;
  614. if (startPuzzle == NULL)
  615. return 0;
  616. if (startPuzzle->solnptr == NULL) {
  617. freeSolutions();
  618. return 0;
  619. }
  620. nextpuz = startPuzzle->solnptr;
  621. movedPiece = 0;
  622. movedir = 0;
  623. for (i = 0; i < HEIGHT; i++) {
  624. for (j = 0; j < WIDTH; j++) {
  625. if (startPuzzle->pieces[i][j] != nextpuz->pieces[i][j]) {
  626. if (startPuzzle->pieces[i][j]) {
  627. movedPiece = startPuzzle->pieces[i][j];
  628. fromx = j;
  629. fromy = i;
  630. if (i < HEIGHT - 1 && nextpuz->pieces[i + 1][j] == movedPiece) {
  631. movedir = 3;
  632. } else {
  633. movedir = 2;
  634. }
  635. goto found_piece;
  636. } else {
  637. movedPiece = nextpuz->pieces[i][j];
  638. if (i < HEIGHT - 1 &&
  639. startPuzzle->pieces[i + 1][j] == movedPiece) {
  640. fromx = j;
  641. fromy = i + 1;
  642. movedir = 1;
  643. } else {
  644. fromx = j + 1;
  645. fromy = i;
  646. movedir = 0;
  647. }
  648. goto found_piece;
  649. }
  650. }
  651. }
  652. }
  653. glutSetWindowTitle((char *)"What! No change?");
  654. freeSolutions();
  655. return 0;
  656. found_piece:
  657. if (!movingPiece) {
  658. movingPiece = movedPiece;
  659. move_x = fromx;
  660. move_y = fromy;
  661. }
  662. move_x += xadds[movedir] * MOVE_SPEED;
  663. move_y += yadds[movedir] * MOVE_SPEED;
  664. tox = fromx + xadds[movedir];
  665. toy = fromy + yadds[movedir];
  666. if (move_x > tox - MOVE_SPEED / 2 && move_x < tox + MOVE_SPEED / 2 &&
  667. move_y > toy - MOVE_SPEED / 2 && move_y < toy + MOVE_SPEED / 2) {
  668. startPuzzle = nextpuz;
  669. movingPiece = 0;
  670. }
  671. memcpy(thePuzzle, startPuzzle->pieces, HEIGHT * WIDTH);
  672. changeState();
  673. return 1;
  674. }
  675. int
  676. solvePuzzle(void)
  677. {
  678. struct puzzlelist *nextpuz;
  679. char buf[256];
  680. int i;
  681. if (solution(thePuzzle)) {
  682. glutSetWindowTitle((char *)"Puzzle already solved!");
  683. return 0;
  684. }
  685. addConfig(thePuzzle, NULL);
  686. i = 0;
  687. while (puzzles) {
  688. i++;
  689. if (generateNewConfigs(puzzles->puzzle))
  690. break;
  691. nextpuz = puzzles->next;
  692. free((char *) puzzles);
  693. puzzles = nextpuz;
  694. }
  695. if (puzzles == NULL) {
  696. freeSolutions();
  697. sprintf(buf, "I can't solve it! (%d positions examined)", i);
  698. glutSetWindowTitle(buf);
  699. return 1;
  700. }
  701. return 1;
  702. }
  703. int
  704. selectPiece(int mousex, int mousey)
  705. {
  706. long hits;
  707. GLuint selectBuf[1024];
  708. GLuint closest;
  709. GLuint dist;
  710. glSelectBuffer(1024, selectBuf);
  711. (void) glRenderMode(GL_SELECT);
  712. glInitNames();
  713. /* Because LoadName() won't work with no names on the stack */
  714. glPushName(0);
  715. glMatrixMode(GL_PROJECTION);
  716. glLoadIdentity();
  717. gluPickMatrix(mousex, H - mousey, 4, 4, viewport);
  718. gluPerspective(45, viewport[2]*1.0/viewport[3], 0.1, 100.0);
  719. drawAll();
  720. hits = glRenderMode(GL_RENDER);
  721. if (hits <= 0) {
  722. return 0;
  723. }
  724. closest = 0;
  725. dist = 0xFFFFFFFFU; //2147483647;
  726. while (hits) {
  727. if (selectBuf[(hits - 1) * 4 + 1] < dist) {
  728. dist = selectBuf[(hits - 1) * 4 + 1];
  729. closest = selectBuf[(hits - 1) * 4 + 3];
  730. }
  731. hits--;
  732. }
  733. return closest;
  734. }
  735. void
  736. nukePiece(int piece)
  737. {
  738. int i, j;
  739. for (i = 0; i < HEIGHT; i++) {
  740. for (j = 0; j < WIDTH; j++) {
  741. if (thePuzzle[i][j] == piece) {
  742. thePuzzle[i][j] = 0;
  743. }
  744. }
  745. }
  746. }
  747. void
  748. multMatrices(const GLfloat a[16], const GLfloat b[16], GLfloat r[16])
  749. {
  750. int i, j;
  751. for (i = 0; i < 4; i++) {
  752. for (j = 0; j < 4; j++) {
  753. r[i * 4 + j] =
  754. a[i * 4 + 0] * b[0 * 4 + j] +
  755. a[i * 4 + 1] * b[1 * 4 + j] +
  756. a[i * 4 + 2] * b[2 * 4 + j] +
  757. a[i * 4 + 3] * b[3 * 4 + j];
  758. }
  759. }
  760. }
  761. void
  762. makeIdentity(GLfloat m[16])
  763. {
  764. m[0 + 4 * 0] = 1;
  765. m[0 + 4 * 1] = 0;
  766. m[0 + 4 * 2] = 0;
  767. m[0 + 4 * 3] = 0;
  768. m[1 + 4 * 0] = 0;
  769. m[1 + 4 * 1] = 1;
  770. m[1 + 4 * 2] = 0;
  771. m[1 + 4 * 3] = 0;
  772. m[2 + 4 * 0] = 0;
  773. m[2 + 4 * 1] = 0;
  774. m[2 + 4 * 2] = 1;
  775. m[2 + 4 * 3] = 0;
  776. m[3 + 4 * 0] = 0;
  777. m[3 + 4 * 1] = 0;
  778. m[3 + 4 * 2] = 0;
  779. m[3 + 4 * 3] = 1;
  780. }
  781. /*
  782. ** inverse = invert(src)
  783. */
  784. int
  785. invertMatrix(const GLfloat src[16], GLfloat inverse[16])
  786. {
  787. int i, j, k, swap;
  788. double t;
  789. GLfloat temp[4][4];
  790. for (i = 0; i < 4; i++) {
  791. for (j = 0; j < 4; j++) {
  792. temp[i][j] = src[i * 4 + j];
  793. }
  794. }
  795. makeIdentity(inverse);
  796. for (i = 0; i < 4; i++) {
  797. /*
  798. ** Look for largest element in column */
  799. swap = i;
  800. for (j = i + 1; j < 4; j++) {
  801. if (fabs(temp[j][i]) > fabs(temp[i][i])) {
  802. swap = j;
  803. }
  804. }
  805. if (swap != i) {
  806. /*
  807. ** Swap rows. */
  808. for (k = 0; k < 4; k++) {
  809. t = temp[i][k];
  810. temp[i][k] = temp[swap][k];
  811. temp[swap][k] = t;
  812. t = inverse[i * 4 + k];
  813. inverse[i * 4 + k] = inverse[swap * 4 + k];
  814. inverse[swap * 4 + k] = t;
  815. }
  816. }
  817. if (temp[i][i] == 0) {
  818. /*
  819. ** No non-zero pivot. The matrix is singular, which
  820. shouldn't ** happen. This means the user gave us a
  821. bad matrix. */
  822. return 0;
  823. }
  824. t = temp[i][i];
  825. for (k = 0; k < 4; k++) {
  826. temp[i][k] /= t;
  827. inverse[i * 4 + k] /= t;
  828. }
  829. for (j = 0; j < 4; j++) {
  830. if (j != i) {
  831. t = temp[j][i];
  832. for (k = 0; k < 4; k++) {
  833. temp[j][k] -= temp[i][k] * t;
  834. inverse[j * 4 + k] -= inverse[i * 4 + k] * t;
  835. }
  836. }
  837. }
  838. }
  839. return 1;
  840. }
  841. /*
  842. ** This is a screwball function. What it does is the following:
  843. ** Given screen x and y coordinates, compute the corresponding object space
  844. ** x and y coordinates given that the object space z is 0.9 + OFFSETZ.
  845. ** Since the tops of (most) pieces are at z = 0.9 + OFFSETZ, we use that
  846. ** number.
  847. */
  848. int
  849. computeCoords(int piece, int mousex, int mousey,
  850. GLfloat * selx, GLfloat * sely)
  851. {
  852. GLfloat modelMatrix[16];
  853. GLfloat projMatrix[16];
  854. GLfloat finalMatrix[16];
  855. GLfloat in[4];
  856. GLfloat a, b, c, d;
  857. GLfloat top, bot;
  858. GLfloat z;
  859. GLfloat w;
  860. GLfloat height;
  861. if (piece == 0)
  862. return 0;
  863. height = zsize[piece] - 0.1 + OFFSETZ;
  864. glGetFloatv(GL_PROJECTION_MATRIX, projMatrix);
  865. glGetFloatv(GL_MODELVIEW_MATRIX, modelMatrix);
  866. multMatrices(modelMatrix, projMatrix, finalMatrix);
  867. if (!invertMatrix(finalMatrix, finalMatrix))
  868. return 0;
  869. in[0] = (2.0 * (mousex - viewport[0]) / viewport[2]) - 1;
  870. in[1] = (2.0 * ((H - mousey) - viewport[1]) / viewport[3]) - 1;
  871. a = in[0] * finalMatrix[0 * 4 + 2] +
  872. in[1] * finalMatrix[1 * 4 + 2] +
  873. finalMatrix[3 * 4 + 2];
  874. b = finalMatrix[2 * 4 + 2];
  875. c = in[0] * finalMatrix[0 * 4 + 3] +
  876. in[1] * finalMatrix[1 * 4 + 3] +
  877. finalMatrix[3 * 4 + 3];
  878. d = finalMatrix[2 * 4 + 3];
  879. /*
  880. ** Ok, now we need to solve for z: ** (a + b z) / (c + d
  881. z) = height. ** ("height" is the height in object space we
  882. want to solve z for) ** ** ==> a + b z = height c +
  883. height d z ** bz - height d z = height c - a ** z =
  884. (height c - a) / (b - height d) */
  885. top = height * c - a;
  886. bot = b - height * d;
  887. if (bot == 0.0)
  888. return 0;
  889. z = top / bot;
  890. /*
  891. ** Ok, no problem. ** Now we solve for x and y. We know
  892. that w = c + d z, so we compute it. */
  893. w = c + d * z;
  894. /*
  895. ** Now for x and y: */
  896. *selx = (in[0] * finalMatrix[0 * 4 + 0] +
  897. in[1] * finalMatrix[1 * 4 + 0] +
  898. z * finalMatrix[2 * 4 + 0] +
  899. finalMatrix[3 * 4 + 0]) / w - OFFSETX;
  900. *sely = (in[0] * finalMatrix[0 * 4 + 1] +
  901. in[1] * finalMatrix[1 * 4 + 1] +
  902. z * finalMatrix[2 * 4 + 1] +
  903. finalMatrix[3 * 4 + 1]) / w - OFFSETY;
  904. return 1;
  905. }
  906. static int selected;
  907. static int selectx, selecty;
  908. static float selstartx, selstarty;
  909. void
  910. grabPiece(int piece, float selx, float sely)
  911. {
  912. int hit;
  913. selectx = int(selx);
  914. selecty = int(sely);
  915. if (selectx < 0 || selecty < 0 || selectx >= WIDTH || selecty >= HEIGHT) {
  916. return;
  917. }
  918. hit = thePuzzle[selecty][selectx];
  919. if (hit != piece)
  920. return;
  921. if (hit) {
  922. movingPiece = hit;
  923. while (selectx > 0 && thePuzzle[selecty][selectx - 1] == movingPiece) {
  924. selectx--;
  925. }
  926. while (selecty > 0 && thePuzzle[selecty - 1][selectx] == movingPiece) {
  927. selecty--;
  928. }
  929. move_x = selectx;
  930. move_y = selecty;
  931. selected = 1;
  932. selstartx = selx;
  933. selstarty = sely;
  934. } else {
  935. selected = 0;
  936. }
  937. changeState();
  938. }
  939. void
  940. moveSelection(float selx, float sely)
  941. {
  942. float deltax, deltay;
  943. int dir;
  944. Config newpieces;
  945. if (!selected)
  946. return;
  947. deltax = selx - selstartx;
  948. deltay = sely - selstarty;
  949. if (fabs(deltax) > fabs(deltay)) {
  950. deltay = 0;
  951. if (deltax > 0) {
  952. if (deltax > 1)
  953. deltax = 1;
  954. dir = 2;
  955. } else {
  956. if (deltax < -1)
  957. deltax = -1;
  958. dir = 0;
  959. }
  960. } else {
  961. deltax = 0;
  962. if (deltay > 0) {
  963. if (deltay > 1)
  964. deltay = 1;
  965. dir = 3;
  966. } else {
  967. if (deltay < -1)
  968. deltay = -1;
  969. dir = 1;
  970. }
  971. }
  972. if (canmove(thePuzzle, selectx, selecty, dir, newpieces)) {
  973. move_x = deltax + selectx;
  974. move_y = deltay + selecty;
  975. if (deltax > 0.5) {
  976. memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  977. selectx++;
  978. selstartx++;
  979. } else if (deltax < -0.5) {
  980. memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  981. selectx--;
  982. selstartx--;
  983. } else if (deltay > 0.5) {
  984. memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  985. selecty++;
  986. selstarty++;
  987. } else if (deltay < -0.5) {
  988. memcpy(thePuzzle, newpieces, HEIGHT * WIDTH);
  989. selecty--;
  990. selstarty--;
  991. }
  992. } else {
  993. if (deltay > 0 && thePuzzle[selecty][selectx] == 10 &&
  994. selectx == 1 && selecty == 3) {
  995. /* Allow visual movement of solution piece outside of the
  996. box */
  997. move_x = selectx;
  998. move_y = sely - selstarty + selecty;
  999. } else {
  1000. move_x = selectx;
  1001. move_y = selecty;
  1002. }
  1003. }
  1004. }
  1005. void
  1006. dropSelection(void)
  1007. {
  1008. if (!selected)
  1009. return;
  1010. movingPiece = 0;
  1011. selected = 0;
  1012. changeState();
  1013. }
  1014. static int left_mouse, middle_mouse;
  1015. static int mousex, mousey;
  1016. static int solving;
  1017. static int spinning;
  1018. static float lastquat[4];
  1019. static int sel_piece;
  1020. static void
  1021. Reshape(int width, int height)
  1022. {
  1023. W = width;
  1024. H = height;
  1025. glViewport(0, 0, W, H);
  1026. glGetIntegerv(GL_VIEWPORT, viewport);
  1027. }
  1028. void
  1029. toggleSolve(void)
  1030. {
  1031. if (solving) {
  1032. freeSolutions();
  1033. solving = 0;
  1034. glutChangeToMenuEntry(1, (char *)"Solving", 1);
  1035. glutSetWindowTitle((char *)"glpuzzle");
  1036. movingPiece = 0;
  1037. } else {
  1038. glutChangeToMenuEntry(1, (char *)"Stop solving", 1);
  1039. glutSetWindowTitle((char *)"Solving...");
  1040. if (solvePuzzle()) {
  1041. solving = 1;
  1042. }
  1043. }
  1044. changeState();
  1045. glutPostRedisplay();
  1046. }
  1047. void reset(void)
  1048. {
  1049. if (solving) {
  1050. freeSolutions();
  1051. solving = 0;
  1052. glutChangeToMenuEntry(1, (char *)"Solving", 1);
  1053. glutSetWindowTitle((char *)"glpuzzle");
  1054. movingPiece = 0;
  1055. changeState();
  1056. }
  1057. memcpy(thePuzzle, startConfig, HEIGHT * WIDTH);
  1058. glutPostRedisplay();
  1059. }
  1060. void
  1061. keyboard(unsigned char c, int x, int y)
  1062. {
  1063. int piece;
  1064. switch (c) {
  1065. case 27:
  1066. exit(0);
  1067. break;
  1068. case 'D':
  1069. case 'd':
  1070. if (solving) {
  1071. freeSolutions();
  1072. solving = 0;
  1073. glutChangeToMenuEntry(1, (char *)"Solving", 1);
  1074. glutSetWindowTitle((char *)"glpuzzle");
  1075. movingPiece = 0;
  1076. changeState();
  1077. }
  1078. piece = selectPiece(x, y);
  1079. if (piece) {
  1080. nukePiece(piece);
  1081. }
  1082. glutPostRedisplay();
  1083. break;
  1084. case 'R':
  1085. case 'r':
  1086. reset();
  1087. break;
  1088. case 'S':
  1089. case 's':
  1090. toggleSolve();
  1091. break;
  1092. case 'b':
  1093. case 'B':
  1094. depth = 1 - depth;
  1095. if (depth) {
  1096. glEnable(GL_DEPTH_TEST);
  1097. } else {
  1098. glDisable(GL_DEPTH_TEST);
  1099. }
  1100. glutPostRedisplay();
  1101. break;
  1102. default:
  1103. break;
  1104. }
  1105. }
  1106. void
  1107. motion(int x, int y)
  1108. {
  1109. float selx, sely;
  1110. if (middle_mouse && !left_mouse) {
  1111. if (mousex != x || mousey != y) {
  1112. trackball(lastquat,
  1113. (2.0*mousex - W) / W,
  1114. (H - 2.0*mousey) / H,
  1115. (2.0*x - W) / W,
  1116. (H - 2.0*y) / H);
  1117. spinning = 1;
  1118. } else {
  1119. spinning = 0;
  1120. }
  1121. changeState();
  1122. } else {
  1123. computeCoords(sel_piece, x, y, &selx, &sely);
  1124. moveSelection(selx, sely);
  1125. }
  1126. mousex = x;
  1127. mousey = y;
  1128. glutPostRedisplay();
  1129. }
  1130. void
  1131. mouse(int b, int s, int x, int y)
  1132. {
  1133. float selx, sely;
  1134. mousex = x;
  1135. mousey = y;
  1136. curX = x;
  1137. curY = y;
  1138. if (s == GLUT_DOWN) {
  1139. switch (b) {
  1140. case GLUT_LEFT_BUTTON:
  1141. if (solving) {
  1142. freeSolutions();
  1143. solving = 0;
  1144. glutChangeToMenuEntry(1, (char *)"Solving", 1);
  1145. glutSetWindowTitle((char *)"glpuzzle");
  1146. movingPiece = 0;
  1147. }
  1148. left_mouse = GL_TRUE;
  1149. sel_piece = selectPiece(mousex, mousey);
  1150. if (!sel_piece) {
  1151. left_mouse = GL_FALSE;
  1152. middle_mouse = GL_TRUE; // let it rotate object
  1153. } else if (computeCoords(sel_piece, mousex, mousey, &selx, &sely)) {
  1154. grabPiece(sel_piece, selx, sely);
  1155. }
  1156. glutPostRedisplay();
  1157. break;
  1158. case GLUT_MIDDLE_BUTTON:
  1159. middle_mouse = GL_TRUE;
  1160. glutPostRedisplay();
  1161. break;
  1162. }
  1163. } else {
  1164. if (left_mouse) {
  1165. left_mouse = GL_FALSE;
  1166. dropSelection();
  1167. glutPostRedisplay();
  1168. } else if (middle_mouse) {
  1169. middle_mouse = GL_FALSE;
  1170. glutPostRedisplay();
  1171. }
  1172. }
  1173. motion(x, y);
  1174. }
  1175. void
  1176. animate(void)
  1177. {
  1178. if (spinning) {
  1179. add_quats(lastquat, curquat, curquat);
  1180. }
  1181. glutPostRedisplay();
  1182. if (solving) {
  1183. if (!continueSolving()) {
  1184. solving = 0;
  1185. glutChangeToMenuEntry(1, (char *)"Solving", 1);
  1186. glutSetWindowTitle((char *)"glpuzzle");
  1187. }
  1188. }
  1189. if ((!solving && !spinning) || !visible) {
  1190. glutIdleFunc(NULL);
  1191. }
  1192. }
  1193. void
  1194. changeState(void)
  1195. {
  1196. if (visible) {
  1197. if (!solving && !spinning) {
  1198. glutIdleFunc(NULL);
  1199. } else {
  1200. glutIdleFunc(animate);
  1201. }
  1202. } else {
  1203. glutIdleFunc(NULL);
  1204. }
  1205. }
  1206. void
  1207. init(void)
  1208. {
  1209. static float lmodel_ambient[] =
  1210. {0.0, 0.0, 0.0, 0.0};
  1211. static float lmodel_twoside[] =
  1212. {GL_FALSE};
  1213. static float lmodel_local[] =
  1214. {GL_FALSE};
  1215. static float light0_ambient[] =
  1216. {0.1, 0.1, 0.1, 1.0};
  1217. static float light0_diffuse[] =
  1218. {1.0, 1.0, 1.0, 0.0};
  1219. static float light0_position[] =
  1220. {0.8660254, 0.5, 1, 0};
  1221. static float light0_specular[] =
  1222. {0.0, 0.0, 0.0, 0.0};
  1223. static float bevel_mat_ambient[] =
  1224. {0.0, 0.0, 0.0, 1.0};
  1225. static float bevel_mat_shininess[] =
  1226. {40.0};
  1227. static float bevel_mat_specular[] =
  1228. {0.0, 0.0, 0.0, 0.0};
  1229. static float bevel_mat_diffuse[] =
  1230. {1.0, 0.0, 0.0, 0.0};
  1231. glEnable(GL_CULL_FACE);
  1232. glCullFace(GL_BACK);
  1233. glEnable(GL_DEPTH_TEST);
  1234. glClearDepth(1.0);
  1235. glClearColor(0.5, 0.5, 0.5, 0.0);
  1236. glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
  1237. glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  1238. glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
  1239. glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
  1240. glEnable(GL_LIGHT0);
  1241. glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, lmodel_local);
  1242. glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
  1243. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
  1244. glEnable(GL_LIGHTING);
  1245. glMaterialfv(GL_FRONT, GL_AMBIENT, bevel_mat_ambient);
  1246. glMaterialfv(GL_FRONT, GL_SHININESS, bevel_mat_shininess);
  1247. glMaterialfv(GL_FRONT, GL_SPECULAR, bevel_mat_specular);
  1248. glMaterialfv(GL_FRONT, GL_DIFFUSE, bevel_mat_diffuse);
  1249. glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  1250. glEnable(GL_COLOR_MATERIAL);
  1251. glShadeModel(GL_FLAT);
  1252. trackball(curquat, 0.0, 0.0, 0.0, 0.0);
  1253. srandom(time(NULL));
  1254. }
  1255. static void
  1256. Usage(void)
  1257. {
  1258. puts("Usage: puzzle [-s]");
  1259. puts(" -s: Run in single buffered mode");
  1260. exit(-1);
  1261. }
  1262. void
  1263. visibility(int v)
  1264. {
  1265. if (v == GLUT_VISIBLE) {
  1266. visible = 1;
  1267. } else {
  1268. visible = 0;
  1269. }
  1270. changeState();
  1271. }
  1272. void
  1273. menu(int choice)
  1274. {
  1275. switch(choice) {
  1276. case 1:
  1277. toggleSolve();
  1278. break;
  1279. case 2:
  1280. reset();
  1281. break;
  1282. case 3:
  1283. exit(0);
  1284. break;
  1285. }
  1286. }
  1287. int
  1288. main(int argc, char **argv)
  1289. {
  1290. long i;
  1291. glutInit(&argc, argv);
  1292. for (i = 1; i < argc; i++) {
  1293. if (argv[i][0] == '-') {
  1294. switch (argv[i][1]) {
  1295. case 's':
  1296. doubleBuffer = 0;
  1297. break;
  1298. default:
  1299. Usage();
  1300. }
  1301. } else {
  1302. Usage();
  1303. }
  1304. }
  1305. glutInitWindowSize(W, H);
  1306. if (doubleBuffer) {
  1307. glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE);
  1308. } else {
  1309. glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_SINGLE | GLUT_MULTISAMPLE);
  1310. }
  1311. glutCreateWindow("glpuzzle");
  1312. visible = 1; // added for fltk, bug in original program?
  1313. init();
  1314. glGetIntegerv(GL_VIEWPORT, viewport);
  1315. puts("");
  1316. puts("r Reset puzzle");
  1317. puts("s Solve puzzle (may take a few seconds to compute)");
  1318. puts("d Destroy a piece - makes the puzzle easier");
  1319. puts("b Toggles the depth buffer on and off");
  1320. puts("");
  1321. puts("Left mouse moves pieces");
  1322. puts("Middle mouse spins the puzzle");
  1323. puts("Right mouse has menu");
  1324. glutReshapeFunc(Reshape);
  1325. glutDisplayFunc(redraw);
  1326. glutKeyboardFunc(keyboard);
  1327. glutMotionFunc(motion);
  1328. glutMouseFunc(mouse);
  1329. glutVisibilityFunc(visibility);
  1330. glutCreateMenu(menu);
  1331. glutAddMenuEntry((char *)"Solve", 1);
  1332. glutAddMenuEntry((char *)"Reset", 2);
  1333. glutAddMenuEntry((char *)"Quit", 3);
  1334. glutAttachMenu(GLUT_RIGHT_BUTTON);
  1335. glutMainLoop();
  1336. return 0; /* ANSI C requires main to return int. */
  1337. }
  1338. #endif // added for fltk's distribution
  1339. //
  1340. // End of "$Id: glpuzzle.cxx 8033 2010-12-15 12:11:16Z AlbrechtS $".
  1341. //